]>
Commit | Line | Data |
---|---|---|
6527f429 DM |
1 | // @tag class\r |
2 | /**\r | |
3 | * @class Ext.Inventory\r | |
4 | * @private\r | |
5 | */\r | |
6 | Ext.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 | |
21 | Ext.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 |