]> git.proxmox.com Git - extjs.git/blame - extjs/packages/core/src/class/Inventory.js
add extjs 6.0.1 sources
[extjs.git] / extjs / packages / core / src / class / Inventory.js
CommitLineData
6527f429
DM
1 // @tag class\r
2/**\r
3 * @class Ext.Inventory\r
4 * @private\r
5 */\r
6Ext.Inventory = function () {\r
7// @define Ext.Script\r
8// @define Ext.Inventory\r
9// @require Ext.Function\r
10 var me = this;\r
11\r
12 me.names = [];\r
13 me.paths = {};\r
14\r
15 me.alternateToName = {};\r
16 me.aliasToName = {};\r
17 me.nameToAliases = {};\r
18 me.nameToAlternates = {};\r
19};\r
20\r
21Ext.Inventory.prototype = {\r
22 _array1: [0],\r
23\r
24 prefixes: null,\r
25\r
26 dotRe: /\./g,\r
27 wildcardRe: /\*/g,\r
28\r
29 addAlias: function (className, alias, update) {\r
30 return this.addMapping(className, alias, this.aliasToName, this.nameToAliases, update);\r
31 },\r
32\r
33 addAlternate: function (className, alternate) {\r
34 return this.addMapping(className, alternate, this.alternateToName, this.nameToAlternates);\r
35 },\r
36\r
37 addMapping: function (className, alternate, toName, nameTo, update) {\r
38 var name = className.$className || className,\r
39 mappings = name,\r
40 array = this._array1,\r
41 a, aliases, cls, i, length,\r
42 nameMapping;\r
43\r
44 if (Ext.isString(name)) {\r
45 mappings = {};\r
46 mappings[name] = alternate;\r
47 }\r
48\r
49 for (cls in mappings) {\r
50 aliases = mappings[cls];\r
51 if (Ext.isString(aliases)) {\r
52 array[0] = aliases;\r
53 aliases = array;\r
54 }\r
55\r
56 length = aliases.length;\r
57 nameMapping = nameTo[cls] || (nameTo[cls] = []);\r
58 for (i = 0; i < length; ++i) {\r
59 if (!(a = aliases[i])) {\r
60 continue;\r
61 }\r
62\r
63 if (toName[a] !== cls) {\r
64 //<debug>\r
65 if (!update && toName[a]) {\r
66 Ext.log.warn("Overriding existing mapping: '" + a + "' From '" +\r
67 toName[a] + "' to '" + cls + "'. Is this intentional?");\r
68 }\r
69 //</debug>\r
70\r
71 toName[a] = cls;\r
72 nameMapping.push(a);\r
73 }\r
74 }\r
75 }\r
76 },\r
77\r
78 /**\r
79 * Get the aliases of a class by the class name\r
80 *\r
81 * @param {String} name\r
82 * @return {Array} aliases\r
83 */\r
84 getAliasesByName: function (name) {\r
85 return this.nameToAliases[name] || null;\r
86 },\r
87\r
88 getAlternatesByName: function (name) {\r
89 return this.nameToAlternates[name] || null;\r
90 },\r
91\r
92 /**\r
93 * Get the name of a class by its alias.\r
94 *\r
95 * @param {String} alias\r
96 * @return {String} className\r
97 */\r
98 getNameByAlias: function(alias) {\r
99 return this.aliasToName[alias] || '';\r
100 },\r
101\r
102 /**\r
103 * Get the name of a class by its alternate name.\r
104 *\r
105 * @param {String} alternate\r
106 * @return {String} className\r
107 */\r
108 getNameByAlternate: function (alternate) {\r
109 return this.alternateToName[alternate] || '';\r
110 },\r
111\r
112 /**\r
113 * Converts a string expression to an array of matching class names. An expression can\r
114 * either refers to class aliases or class names. Expressions support wildcards:\r
115 *\r
116 * // returns ['Ext.window.Window']\r
117 * var window = Ext.ClassManager.getNamesByExpression('widget.window');\r
118 *\r
119 * // returns ['widget.panel', 'widget.window', ...]\r
120 * var allWidgets = Ext.ClassManager.getNamesByExpression('widget.*');\r
121 *\r
122 * // returns ['Ext.data.Store', 'Ext.data.ArrayProxy', ...]\r
123 * var allData = Ext.ClassManager.getNamesByExpression('Ext.data.*');\r
124 *\r
125 * @param {String/String[]} expression\r
126 * @param {Object} [exclude=null] An object keyed by class name containing classes to\r
127 * exclude from the returned classes. This must be provided if `accumulate` is set to\r
128 * `true`.\r
129 * @param {Boolean} [accumulate=false] Pass `true` to add matching classes to the\r
130 * specified `exclude` object.\r
131 * @return {String[]} An array of class names.\r
132 */\r
133 getNamesByExpression: function (expression, exclude, accumulate) {\r
134 var me = this,\r
135 aliasToName = me.aliasToName,\r
136 alternateToName = me.alternateToName,\r
137 nameToAliases = me.nameToAliases,\r
138 nameToAlternates = me.nameToAlternates,\r
139 map = accumulate ? exclude : {},\r
140 names = [],\r
141 expressions = Ext.isString(expression) ? [expression] : expression,\r
142 length = expressions.length,\r
143 wildcardRe = me.wildcardRe,\r
144 expr, i, list, match, n, name, regex;\r
145\r
146 for (i = 0; i < length; ++i) {\r
147 if ((expr = expressions[i]).indexOf('*') < 0) {\r
148 // No wildcard\r
149 if (!(name = aliasToName[expr])) {\r
150 if (!(name = alternateToName[expr])) {\r
151 name = expr;\r
152 }\r
153 }\r
154\r
155 if (!(name in map) && !(exclude && (name in exclude))) {\r
156 map[name] = 1;\r
157 names.push(name);\r
158 }\r
159 } else {\r
160 regex = new RegExp('^' + expr.replace(wildcardRe, '(.*?)') + '$');\r
161\r
162 for (name in nameToAliases) {\r
163 if (!(name in map) && !(exclude && (name in exclude))) {\r
164 if (!(match = regex.test(name))) {\r
165 n = (list = nameToAliases[name]).length;\r
166 while (!match && n-- > 0) {\r
167 match = regex.test(list[n]);\r
168 }\r
169\r
170 list = nameToAlternates[name];\r
171 if (list && !match) {\r
172 n = list.length;\r
173 while (!match && n-- > 0) {\r
174 match = regex.test(list[n]);\r
175 }\r
176 }\r
177 }\r
178\r
179 if (match) {\r
180 map[name] = 1;\r
181 names.push(name);\r
182 }\r
183 }\r
184 }\r
185 }\r
186 }\r
187\r
188 return names;\r
189 },\r
190\r
191 getPath: function (className) {\r
192 var me = this,\r
193 paths = me.paths,\r
194 ret = '',\r
195 prefix;\r
196\r
197 if (className in paths) {\r
198 ret = paths[className];\r
199 } else {\r
200 prefix = me.getPrefix(className);\r
201 if (prefix) {\r
202 className = className.substring(prefix.length + 1);\r
203 ret = paths[prefix];\r
204 if (ret) {\r
205 ret += '/';\r
206 }\r
207 }\r
208\r
209 ret += className.replace(me.dotRe, '/') + '.js';\r
210 }\r
211\r
212 return ret;\r
213 },\r
214\r
215 getPrefix: function (className) {\r
216 if (className in this.paths) {\r
217 return className;\r
218 }\r
219\r
220 var prefixes = this.getPrefixes(),\r
221 i = prefixes.length,\r
222 length, prefix;\r
223\r
224 // Walk the prefixes backwards so we consider the longest ones first.\r
225 while (i-- > 0) {\r
226 length = (prefix = prefixes[i]).length;\r
227 if (length < className.length && className.charAt(length) === '.'\r
228 && prefix === className.substring(0, length)) {\r
229 return prefix;\r
230 }\r
231 }\r
232\r
233 return '';\r
234 },\r
235\r
236 getPrefixes: function () {\r
237 var me = this,\r
238 prefixes = me.prefixes;\r
239\r
240 if (!prefixes) {\r
241 me.prefixes = prefixes = me.names.slice(0);\r
242 prefixes.sort(me._compareNames);\r
243 }\r
244\r
245 return prefixes;\r
246 },\r
247\r
248 removeName: function (name) {\r
249 var me = this,\r
250 aliasToName = me.aliasToName,\r
251 alternateToName = me.alternateToName,\r
252 nameToAliases = me.nameToAliases,\r
253 nameToAlternates = me.nameToAlternates,\r
254 aliases = nameToAliases[name],\r
255 alternates = nameToAlternates[name],\r
256 i, a;\r
257\r
258 delete nameToAliases[name];\r
259 delete nameToAlternates[name];\r
260\r
261 if (aliases) {\r
262 for (i = aliases.length; i--;) {\r
263 // Aliases can be reassigned so if this class is the current mapping of\r
264 // the alias, remove it. Since there is no chain to restore what was\r
265 // removed this is not perfect.\r
266 if (name === (a = aliases[i])) {\r
267 delete aliasToName[a];\r
268 }\r
269 }\r
270 }\r
271\r
272 if (alternates) {\r
273 for (i = alternates.length; i--; ) {\r
274 // Like aliases, alternate class names can also be remapped.\r
275 if (name === (a = alternates[i])) {\r
276 delete alternateToName[a];\r
277 }\r
278 }\r
279 }\r
280 },\r
281\r
282 resolveName: function (name) {\r
283 var me = this,\r
284 trueName;\r
285\r
286 // If the name has a registered alias, it is a true className (not an alternate)\r
287 // so we can stop now.\r
288 if (!(name in me.nameToAliases)) {\r
289 // The name is not a known class name, so check to see if it is a known alias:\r
290 if (!(trueName = me.aliasToName[name])) {\r
291 // The name does not correspond to a known alias, so check if it is a known\r
292 // alternateClassName:\r
293 trueName = me.alternateToName[name];\r
294 }\r
295 }\r
296\r
297 return trueName || name;\r
298 },\r
299\r
300 /**\r
301 * This method returns a selector object that produces a selection of classes and\r
302 * delivers them to the desired `receiver`.\r
303 * \r
304 * The returned selector object has the same methods as the given `receiver` object\r
305 * but these methods on the selector accept a first argument that expects a pattern\r
306 * or array of patterns. The actual method on the `receiver` will be called with an\r
307 * array of classes that match these patterns but with any patterns passed to an\r
308 * `exclude` call removed.\r
309 * \r
310 * For example:\r
311 * \r
312 * var sel = inventory.select({\r
313 * require: function (classes) {\r
314 * console.log('Classes: ' + classes.join(','));\r
315 * }\r
316 * });\r
317 * \r
318 * sel.exclude('Ext.chart.*').exclude('Ext.draw.*').require('*');\r
319 * \r
320 * // Logs all classes except those in the Ext.chart and Ext.draw namespaces.\r
321 * \r
322 * @param {Object} receiver\r
323 * @param {Object} [scope] Optional scope to use when calling `receiver` methods.\r
324 * @return {Object} An object with the same methods as `receiver` plus `exclude`.\r
325 */\r
326 select: function (receiver, scope) {\r
327 var me = this,\r
328 excludes = {},\r
329 ret = {\r
330 excludes: excludes,\r
331\r
332 exclude: function () {\r
333 me.getNamesByExpression(arguments, excludes, true);\r
334 return this;\r
335 }\r
336 },\r
337 name;\r
338\r
339 for (name in receiver) {\r
340 ret[name] = me.selectMethod(excludes, receiver[name], scope || receiver);\r
341 }\r
342\r
343 return ret;\r
344 },\r
345\r
346 selectMethod: function (excludes, fn, scope) {\r
347 var me = this;\r
348\r
349 return function (include) {\r
350 var args = Ext.Array.slice(arguments, 1);\r
351 \r
352 args.unshift(me.getNamesByExpression(include, excludes));\r
353\r
354 return fn.apply(scope, args);\r
355 };\r
356 },\r
357\r
358 /**\r
359 * Sets the path of a namespace.\r
360 * For Example:\r
361 *\r
362 * inventory.setPath('Ext', '.');\r
363 * inventory.setPath({\r
364 * Ext: '.'\r
365 * });\r
366 *\r
367 * @param {String/Object} name The name of a single mapping or an object of mappings.\r
368 * @param {String} [path] If `name` is a String, then this is the path for that name.\r
369 * Otherwise this parameter is ignored.\r
370 * @return {Ext.Inventory} this\r
371 * @method\r
372 */\r
373 setPath: Ext.Function.flexSetter(function (name, path) {\r
374 var me = this;\r
375\r
376 me.paths[name] = path;\r
377 me.names.push(name);\r
378\r
379 me.prefixes = null;\r
380\r
381 return me;\r
382 }),\r
383\r
384 _compareNames: function (lhs, rhs) {\r
385 var cmp = lhs.length - rhs.length;\r
386 if (!cmp) {\r
387 cmp = (lhs < rhs) ? -1 : 1;\r
388 }\r
389 return cmp;\r
390 }\r
391};\r