|
1 /** |
|
2 * Tools.js |
|
3 * |
|
4 * Copyright, Moxiecode Systems AB |
|
5 * Released under LGPL License. |
|
6 * |
|
7 * License: http://www.tinymce.com/license |
|
8 * Contributing: http://www.tinymce.com/contributing |
|
9 */ |
|
10 |
|
11 /** |
|
12 * This class contains various utlity functions. These are also exposed |
|
13 * directly on the tinymce namespace. |
|
14 * |
|
15 * @class tinymce.util.Tools |
|
16 */ |
|
17 define("tinymce/util/Tools", [ |
|
18 "tinymce/Env" |
|
19 ], function(Env) { |
|
20 /** |
|
21 * Removes whitespace from the beginning and end of a string. |
|
22 * |
|
23 * @method trim |
|
24 * @param {String} s String to remove whitespace from. |
|
25 * @return {String} New string with removed whitespace. |
|
26 */ |
|
27 var whiteSpaceRegExp = /^\s*|\s*$/g; |
|
28 |
|
29 function trim(str) { |
|
30 return (str === null || str === undefined) ? '' : ("" + str).replace(whiteSpaceRegExp, ''); |
|
31 } |
|
32 |
|
33 /** |
|
34 * Returns true/false if the object is an array or not. |
|
35 * |
|
36 * @method isArray |
|
37 * @param {Object} obj Object to check. |
|
38 * @return {boolean} true/false state if the object is an array or not. |
|
39 */ |
|
40 var isArray = Array.isArray || function(obj) { |
|
41 return Object.prototype.toString.call(obj) === "[object Array]"; |
|
42 }; |
|
43 |
|
44 /** |
|
45 * Checks if a object is of a specific type for example an array. |
|
46 * |
|
47 * @method is |
|
48 * @param {Object} obj Object to check type of. |
|
49 * @param {string} type Optional type to check for. |
|
50 * @return {Boolean} true/false if the object is of the specified type. |
|
51 */ |
|
52 function is(obj, type) { |
|
53 if (!type) { |
|
54 return obj !== undefined; |
|
55 } |
|
56 |
|
57 if (type == 'array' && isArray(obj)) { |
|
58 return true; |
|
59 } |
|
60 |
|
61 return typeof obj == type; |
|
62 } |
|
63 |
|
64 /** |
|
65 * Converts the specified object into a real JavaScript array. |
|
66 * |
|
67 * @method toArray |
|
68 * @param {Object} obj Object to convert into array. |
|
69 * @return {Array} Array object based in input. |
|
70 */ |
|
71 function toArray(obj) { |
|
72 var array = obj, i, l; |
|
73 |
|
74 if (!isArray(obj)) { |
|
75 array = []; |
|
76 for (i = 0, l = obj.length; i < l; i++) { |
|
77 array[i] = obj[i]; |
|
78 } |
|
79 } |
|
80 |
|
81 return array; |
|
82 } |
|
83 |
|
84 /** |
|
85 * Makes a name/object map out of an array with names. |
|
86 * |
|
87 * @method makeMap |
|
88 * @param {Array/String} items Items to make map out of. |
|
89 * @param {String} delim Optional delimiter to split string by. |
|
90 * @param {Object} map Optional map to add items to. |
|
91 * @return {Object} Name/value map of items. |
|
92 */ |
|
93 function makeMap(items, delim, map) { |
|
94 var i; |
|
95 |
|
96 items = items || []; |
|
97 delim = delim || ','; |
|
98 |
|
99 if (typeof items == "string") { |
|
100 items = items.split(delim); |
|
101 } |
|
102 |
|
103 map = map || {}; |
|
104 |
|
105 i = items.length; |
|
106 while (i--) { |
|
107 map[items[i]] = {}; |
|
108 } |
|
109 |
|
110 return map; |
|
111 } |
|
112 |
|
113 /** |
|
114 * Performs an iteration of all items in a collection such as an object or array. This method will execure the |
|
115 * callback function for each item in the collection, if the callback returns false the iteration will terminate. |
|
116 * The callback has the following format: cb(value, key_or_index). |
|
117 * |
|
118 * @method each |
|
119 * @param {Object} o Collection to iterate. |
|
120 * @param {function} cb Callback function to execute for each item. |
|
121 * @param {Object} s Optional scope to execute the callback in. |
|
122 * @example |
|
123 * // Iterate an array |
|
124 * tinymce.each([1,2,3], function(v, i) { |
|
125 * console.debug("Value: " + v + ", Index: " + i); |
|
126 * }); |
|
127 * |
|
128 * // Iterate an object |
|
129 * tinymce.each({a: 1, b: 2, c: 3], function(v, k) { |
|
130 * console.debug("Value: " + v + ", Key: " + k); |
|
131 * }); |
|
132 */ |
|
133 function each(o, cb, s) { |
|
134 var n, l; |
|
135 |
|
136 if (!o) { |
|
137 return 0; |
|
138 } |
|
139 |
|
140 s = s || o; |
|
141 |
|
142 if (o.length !== undefined) { |
|
143 // Indexed arrays, needed for Safari |
|
144 for (n = 0, l = o.length; n < l; n++) { |
|
145 if (cb.call(s, o[n], n, o) === false) { |
|
146 return 0; |
|
147 } |
|
148 } |
|
149 } else { |
|
150 // Hashtables |
|
151 for (n in o) { |
|
152 if (o.hasOwnProperty(n)) { |
|
153 if (cb.call(s, o[n], n, o) === false) { |
|
154 return 0; |
|
155 } |
|
156 } |
|
157 } |
|
158 } |
|
159 |
|
160 return 1; |
|
161 } |
|
162 |
|
163 /** |
|
164 * Creates a new array by the return value of each iteration function call. This enables you to convert |
|
165 * one array list into another. |
|
166 * |
|
167 * @method map |
|
168 * @param {Array} array Array of items to iterate. |
|
169 * @param {function} callback Function to call for each item. It's return value will be the new value. |
|
170 * @return {Array} Array with new values based on function return values. |
|
171 */ |
|
172 function map(array, callback) { |
|
173 var out = []; |
|
174 |
|
175 each(array, function(item) { |
|
176 out.push(callback(item)); |
|
177 }); |
|
178 |
|
179 return out; |
|
180 } |
|
181 |
|
182 /** |
|
183 * Filters out items from the input array by calling the specified function for each item. |
|
184 * If the function returns false the item will be excluded if it returns true it will be included. |
|
185 * |
|
186 * @method grep |
|
187 * @param {Array} a Array of items to loop though. |
|
188 * @param {function} f Function to call for each item. Include/exclude depends on it's return value. |
|
189 * @return {Array} New array with values imported and filtered based in input. |
|
190 * @example |
|
191 * // Filter out some items, this will return an array with 4 and 5 |
|
192 * var items = tinymce.grep([1,2,3,4,5], function(v) {return v > 3;}); |
|
193 */ |
|
194 function grep(a, f) { |
|
195 var o = []; |
|
196 |
|
197 each(a, function(v) { |
|
198 if (!f || f(v)) { |
|
199 o.push(v); |
|
200 } |
|
201 }); |
|
202 |
|
203 return o; |
|
204 } |
|
205 |
|
206 /** |
|
207 * Creates a class, subclass or static singleton. |
|
208 * More details on this method can be found in the Wiki. |
|
209 * |
|
210 * @method create |
|
211 * @param {String} s Class name, inheritage and prefix. |
|
212 * @param {Object} p Collection of methods to add to the class. |
|
213 * @param {Object} root Optional root object defaults to the global window object. |
|
214 * @example |
|
215 * // Creates a basic class |
|
216 * tinymce.create('tinymce.somepackage.SomeClass', { |
|
217 * SomeClass: function() { |
|
218 * // Class constructor |
|
219 * }, |
|
220 * |
|
221 * method: function() { |
|
222 * // Some method |
|
223 * } |
|
224 * }); |
|
225 * |
|
226 * // Creates a basic subclass class |
|
227 * tinymce.create('tinymce.somepackage.SomeSubClass:tinymce.somepackage.SomeClass', { |
|
228 * SomeSubClass: function() { |
|
229 * // Class constructor |
|
230 * this.parent(); // Call parent constructor |
|
231 * }, |
|
232 * |
|
233 * method: function() { |
|
234 * // Some method |
|
235 * this.parent(); // Call parent method |
|
236 * }, |
|
237 * |
|
238 * 'static': { |
|
239 * staticMethod: function() { |
|
240 * // Static method |
|
241 * } |
|
242 * } |
|
243 * }); |
|
244 * |
|
245 * // Creates a singleton/static class |
|
246 * tinymce.create('static tinymce.somepackage.SomeSingletonClass', { |
|
247 * method: function() { |
|
248 * // Some method |
|
249 * } |
|
250 * }); |
|
251 */ |
|
252 function create(s, p, root) { |
|
253 var self = this, sp, ns, cn, scn, c, de = 0; |
|
254 |
|
255 // Parse : <prefix> <class>:<super class> |
|
256 s = /^((static) )?([\w.]+)(:([\w.]+))?/.exec(s); |
|
257 cn = s[3].match(/(^|\.)(\w+)$/i)[2]; // Class name |
|
258 |
|
259 // Create namespace for new class |
|
260 ns = self.createNS(s[3].replace(/\.\w+$/, ''), root); |
|
261 |
|
262 // Class already exists |
|
263 if (ns[cn]) { |
|
264 return; |
|
265 } |
|
266 |
|
267 // Make pure static class |
|
268 if (s[2] == 'static') { |
|
269 ns[cn] = p; |
|
270 |
|
271 if (this.onCreate) { |
|
272 this.onCreate(s[2], s[3], ns[cn]); |
|
273 } |
|
274 |
|
275 return; |
|
276 } |
|
277 |
|
278 // Create default constructor |
|
279 if (!p[cn]) { |
|
280 p[cn] = function() {}; |
|
281 de = 1; |
|
282 } |
|
283 |
|
284 // Add constructor and methods |
|
285 ns[cn] = p[cn]; |
|
286 self.extend(ns[cn].prototype, p); |
|
287 |
|
288 // Extend |
|
289 if (s[5]) { |
|
290 sp = self.resolve(s[5]).prototype; |
|
291 scn = s[5].match(/\.(\w+)$/i)[1]; // Class name |
|
292 |
|
293 // Extend constructor |
|
294 c = ns[cn]; |
|
295 if (de) { |
|
296 // Add passthrough constructor |
|
297 ns[cn] = function() { |
|
298 return sp[scn].apply(this, arguments); |
|
299 }; |
|
300 } else { |
|
301 // Add inherit constructor |
|
302 ns[cn] = function() { |
|
303 this.parent = sp[scn]; |
|
304 return c.apply(this, arguments); |
|
305 }; |
|
306 } |
|
307 ns[cn].prototype[cn] = ns[cn]; |
|
308 |
|
309 // Add super methods |
|
310 self.each(sp, function(f, n) { |
|
311 ns[cn].prototype[n] = sp[n]; |
|
312 }); |
|
313 |
|
314 // Add overridden methods |
|
315 self.each(p, function(f, n) { |
|
316 // Extend methods if needed |
|
317 if (sp[n]) { |
|
318 ns[cn].prototype[n] = function() { |
|
319 this.parent = sp[n]; |
|
320 return f.apply(this, arguments); |
|
321 }; |
|
322 } else { |
|
323 if (n != cn) { |
|
324 ns[cn].prototype[n] = f; |
|
325 } |
|
326 } |
|
327 }); |
|
328 } |
|
329 |
|
330 // Add static methods |
|
331 /*jshint sub:true*/ |
|
332 /*eslint dot-notation:0*/ |
|
333 self.each(p['static'], function(f, n) { |
|
334 ns[cn][n] = f; |
|
335 }); |
|
336 } |
|
337 |
|
338 /** |
|
339 * Returns the index of a value in an array, this method will return -1 if the item wasn't found. |
|
340 * |
|
341 * @method inArray |
|
342 * @param {Array} a Array/Object to search for value in. |
|
343 * @param {Object} v Value to check for inside the array. |
|
344 * @return {Number/String} Index of item inside the array inside an object. Or -1 if it wasn't found. |
|
345 * @example |
|
346 * // Get index of value in array this will alert 1 since 2 is at that index |
|
347 * alert(tinymce.inArray([1,2,3], 2)); |
|
348 */ |
|
349 function inArray(a, v) { |
|
350 var i, l; |
|
351 |
|
352 if (a) { |
|
353 for (i = 0, l = a.length; i < l; i++) { |
|
354 if (a[i] === v) { |
|
355 return i; |
|
356 } |
|
357 } |
|
358 } |
|
359 |
|
360 return -1; |
|
361 } |
|
362 |
|
363 function extend(obj, ext) { |
|
364 var i, l, name, args = arguments, value; |
|
365 |
|
366 for (i = 1, l = args.length; i < l; i++) { |
|
367 ext = args[i]; |
|
368 for (name in ext) { |
|
369 if (ext.hasOwnProperty(name)) { |
|
370 value = ext[name]; |
|
371 |
|
372 if (value !== undefined) { |
|
373 obj[name] = value; |
|
374 } |
|
375 } |
|
376 } |
|
377 } |
|
378 |
|
379 return obj; |
|
380 } |
|
381 |
|
382 /** |
|
383 * Executed the specified function for each item in a object tree. |
|
384 * |
|
385 * @method walk |
|
386 * @param {Object} o Object tree to walk though. |
|
387 * @param {function} f Function to call for each item. |
|
388 * @param {String} n Optional name of collection inside the objects to walk for example childNodes. |
|
389 * @param {String} s Optional scope to execute the function in. |
|
390 */ |
|
391 function walk(o, f, n, s) { |
|
392 s = s || this; |
|
393 |
|
394 if (o) { |
|
395 if (n) { |
|
396 o = o[n]; |
|
397 } |
|
398 |
|
399 each(o, function(o, i) { |
|
400 if (f.call(s, o, i, n) === false) { |
|
401 return false; |
|
402 } |
|
403 |
|
404 walk(o, f, n, s); |
|
405 }); |
|
406 } |
|
407 } |
|
408 |
|
409 /** |
|
410 * Creates a namespace on a specific object. |
|
411 * |
|
412 * @method createNS |
|
413 * @param {String} n Namespace to create for example a.b.c.d. |
|
414 * @param {Object} o Optional object to add namespace to, defaults to window. |
|
415 * @return {Object} New namespace object the last item in path. |
|
416 * @example |
|
417 * // Create some namespace |
|
418 * tinymce.createNS('tinymce.somepackage.subpackage'); |
|
419 * |
|
420 * // Add a singleton |
|
421 * var tinymce.somepackage.subpackage.SomeSingleton = { |
|
422 * method: function() { |
|
423 * // Some method |
|
424 * } |
|
425 * }; |
|
426 */ |
|
427 function createNS(n, o) { |
|
428 var i, v; |
|
429 |
|
430 o = o || window; |
|
431 |
|
432 n = n.split('.'); |
|
433 for (i = 0; i < n.length; i++) { |
|
434 v = n[i]; |
|
435 |
|
436 if (!o[v]) { |
|
437 o[v] = {}; |
|
438 } |
|
439 |
|
440 o = o[v]; |
|
441 } |
|
442 |
|
443 return o; |
|
444 } |
|
445 |
|
446 /** |
|
447 * Resolves a string and returns the object from a specific structure. |
|
448 * |
|
449 * @method resolve |
|
450 * @param {String} n Path to resolve for example a.b.c.d. |
|
451 * @param {Object} o Optional object to search though, defaults to window. |
|
452 * @return {Object} Last object in path or null if it couldn't be resolved. |
|
453 * @example |
|
454 * // Resolve a path into an object reference |
|
455 * var obj = tinymce.resolve('a.b.c.d'); |
|
456 */ |
|
457 function resolve(n, o) { |
|
458 var i, l; |
|
459 |
|
460 o = o || window; |
|
461 |
|
462 n = n.split('.'); |
|
463 for (i = 0, l = n.length; i < l; i++) { |
|
464 o = o[n[i]]; |
|
465 |
|
466 if (!o) { |
|
467 break; |
|
468 } |
|
469 } |
|
470 |
|
471 return o; |
|
472 } |
|
473 |
|
474 /** |
|
475 * Splits a string but removes the whitespace before and after each value. |
|
476 * |
|
477 * @method explode |
|
478 * @param {string} s String to split. |
|
479 * @param {string} d Delimiter to split by. |
|
480 * @example |
|
481 * // Split a string into an array with a,b,c |
|
482 * var arr = tinymce.explode('a, b, c'); |
|
483 */ |
|
484 function explode(s, d) { |
|
485 if (!s || is(s, 'array')) { |
|
486 return s; |
|
487 } |
|
488 |
|
489 return map(s.split(d || ','), trim); |
|
490 } |
|
491 |
|
492 function _addCacheSuffix(url) { |
|
493 var cacheSuffix = Env.cacheSuffix; |
|
494 |
|
495 if (cacheSuffix) { |
|
496 url += (url.indexOf('?') === -1 ? '?' : '&') + cacheSuffix; |
|
497 } |
|
498 |
|
499 return url; |
|
500 } |
|
501 |
|
502 return { |
|
503 trim: trim, |
|
504 isArray: isArray, |
|
505 is: is, |
|
506 toArray: toArray, |
|
507 makeMap: makeMap, |
|
508 each: each, |
|
509 map: map, |
|
510 grep: grep, |
|
511 inArray: inArray, |
|
512 extend: extend, |
|
513 create: create, |
|
514 walk: walk, |
|
515 createNS: createNS, |
|
516 resolve: resolve, |
|
517 explode: explode, |
|
518 _addCacheSuffix: _addCacheSuffix |
|
519 }; |
|
520 }); |