/ext-4.1.0_b3/src/core/src/Ext.js

https://bitbucket.org/srogerf/javascript · JavaScript · 656 lines · 340 code · 87 blank · 229 comment · 79 complexity · c0bafa206e26aa97c2ea39efa3048a99 MD5 · raw file

  1. /**
  2. * @class Ext
  3. * @singleton
  4. */
  5. var Ext = Ext || {};
  6. Ext._startTime = new Date().getTime();
  7. (function() {
  8. var global = this,
  9. objectPrototype = Object.prototype,
  10. toString = objectPrototype.toString,
  11. enumerables = true,
  12. enumerablesTest = { toString: 1 },
  13. emptyFn = function(){},
  14. i;
  15. Ext.global = global;
  16. for (i in enumerablesTest) {
  17. enumerables = null;
  18. }
  19. if (enumerables) {
  20. enumerables = ['hasOwnProperty', 'valueOf', 'isPrototypeOf', 'propertyIsEnumerable',
  21. 'toLocaleString', 'toString', 'constructor'];
  22. }
  23. /**
  24. * An array containing extra enumerables for old browsers
  25. * @property {String[]}
  26. */
  27. Ext.enumerables = enumerables;
  28. /**
  29. * Copies all the properties of config to the specified object.
  30. * Note that if recursive merging and cloning without referencing the original objects / arrays is needed, use
  31. * {@link Ext.Object#merge} instead.
  32. * @param {Object} object The receiver of the properties
  33. * @param {Object} config The source of the properties
  34. * @param {Object} defaults A different object that will also be applied for default values
  35. * @return {Object} returns obj
  36. */
  37. Ext.apply = function(object, config, defaults) {
  38. if (defaults) {
  39. Ext.apply(object, defaults);
  40. }
  41. if (object && config && typeof config === 'object') {
  42. var i, j, k;
  43. for (i in config) {
  44. object[i] = config[i];
  45. }
  46. if (enumerables) {
  47. for (j = enumerables.length; j--;) {
  48. k = enumerables[j];
  49. if (config.hasOwnProperty(k)) {
  50. object[k] = config[k];
  51. }
  52. }
  53. }
  54. }
  55. return object;
  56. };
  57. Ext.buildSettings = Ext.apply({
  58. baseCSSPrefix: 'x-',
  59. scopeResetCSS: false
  60. }, Ext.buildSettings || {});
  61. Ext.apply(Ext, {
  62. /**
  63. * @property {String} [name='Ext']
  64. * <p>The name of the property in the global namespace (The <code>window</code> in browser environments) which refers to the current instance of Ext.</p>
  65. * <p>This is usually <code>"Ext"</code>, but if a sandboxed build of ExtJS is being used, this will be an alternative name.</p>
  66. * <p>If code is being generated for use by <code>eval</code> or to create a <code>new Function</code>, and the global instance
  67. * of Ext must be referenced, this is the name that should be built into the code.</p>
  68. */
  69. name: Ext.sandboxName || 'Ext',
  70. /**
  71. * A reusable empty function
  72. */
  73. emptyFn: emptyFn,
  74. /**
  75. * A zero length string which will pass a truth test. Useful for passing to methods
  76. * which use a truth test to reject <i>falsy</i> values where a string value must be cleared.
  77. */
  78. emptyString: new String(),
  79. baseCSSPrefix: Ext.buildSettings.baseCSSPrefix,
  80. /**
  81. * Copies all the properties of config to object if they don't already exist.
  82. * @param {Object} object The receiver of the properties
  83. * @param {Object} config The source of the properties
  84. * @return {Object} returns obj
  85. */
  86. applyIf: function(object, config) {
  87. var property;
  88. if (object) {
  89. for (property in config) {
  90. if (object[property] === undefined) {
  91. object[property] = config[property];
  92. }
  93. }
  94. }
  95. return object;
  96. },
  97. /**
  98. * Iterates either an array or an object. This method delegates to
  99. * {@link Ext.Array#each Ext.Array.each} if the given value is iterable, and {@link Ext.Object#each Ext.Object.each} otherwise.
  100. *
  101. * @param {Object/Array} object The object or array to be iterated.
  102. * @param {Function} fn The function to be called for each iteration. See and {@link Ext.Array#each Ext.Array.each} and
  103. * {@link Ext.Object#each Ext.Object.each} for detailed lists of arguments passed to this function depending on the given object
  104. * type that is being iterated.
  105. * @param {Object} scope (Optional) The scope (`this` reference) in which the specified function is executed.
  106. * Defaults to the object being iterated itself.
  107. * @markdown
  108. */
  109. iterate: function(object, fn, scope) {
  110. if (Ext.isEmpty(object)) {
  111. return;
  112. }
  113. if (scope === undefined) {
  114. scope = object;
  115. }
  116. if (Ext.isIterable(object)) {
  117. Ext.Array.each.call(Ext.Array, object, fn, scope);
  118. }
  119. else {
  120. Ext.Object.each.call(Ext.Object, object, fn, scope);
  121. }
  122. }
  123. });
  124. Ext.apply(Ext, {
  125. /**
  126. * This method deprecated. Use {@link Ext#define Ext.define} instead.
  127. * @method
  128. * @param {Function} superclass
  129. * @param {Object} overrides
  130. * @return {Function} The subclass constructor from the <tt>overrides</tt> parameter, or a generated one if not provided.
  131. * @deprecated 4.0.0 Use {@link Ext#define Ext.define} instead
  132. */
  133. extend: function() {
  134. // inline overrides
  135. var objectConstructor = objectPrototype.constructor,
  136. inlineOverrides = function(o) {
  137. for (var m in o) {
  138. if (!o.hasOwnProperty(m)) {
  139. continue;
  140. }
  141. this[m] = o[m];
  142. }
  143. };
  144. return function(subclass, superclass, overrides) {
  145. // First we check if the user passed in just the superClass with overrides
  146. if (Ext.isObject(superclass)) {
  147. overrides = superclass;
  148. superclass = subclass;
  149. subclass = overrides.constructor !== objectConstructor ? overrides.constructor : function() {
  150. superclass.apply(this, arguments);
  151. };
  152. }
  153. //<debug>
  154. if (!superclass) {
  155. Ext.Error.raise({
  156. sourceClass: 'Ext',
  157. sourceMethod: 'extend',
  158. msg: 'Attempting to extend from a class which has not been loaded on the page.'
  159. });
  160. }
  161. //</debug>
  162. // We create a new temporary class
  163. var F = function() {},
  164. subclassProto, superclassProto = superclass.prototype;
  165. F.prototype = superclassProto;
  166. subclassProto = subclass.prototype = new F();
  167. subclassProto.constructor = subclass;
  168. subclass.superclass = superclassProto;
  169. if (superclassProto.constructor === objectConstructor) {
  170. superclassProto.constructor = superclass;
  171. }
  172. subclass.override = function(overrides) {
  173. Ext.override(subclass, overrides);
  174. };
  175. subclassProto.override = inlineOverrides;
  176. subclassProto.proto = subclassProto;
  177. subclass.override(overrides);
  178. subclass.extend = function(o) {
  179. return Ext.extend(subclass, o);
  180. };
  181. return subclass;
  182. };
  183. }(),
  184. /**
  185. * Proxy to {@link Ext.Base#override}. Please refer {@link Ext.Base#override} for further details.
  186. *
  187. * @param {Object} cls The class to override
  188. * @param {Object} overrides The properties to add to origClass. This should be specified as an object literal
  189. * containing one or more properties.
  190. * @method override
  191. * @markdown
  192. * @deprecated 4.1.0 Use {@link Ext#define Ext.define} instead
  193. */
  194. override: function(cls, overrides) {
  195. if (cls.$isClass) {
  196. return cls.override(overrides);
  197. }
  198. else {
  199. Ext.apply(cls.prototype, overrides);
  200. }
  201. }
  202. });
  203. // A full set of static methods to do type checking
  204. Ext.apply(Ext, {
  205. /**
  206. * Returns the given value itself if it's not empty, as described in {@link Ext#isEmpty}; returns the default
  207. * value (second argument) otherwise.
  208. *
  209. * @param {Object} value The value to test
  210. * @param {Object} defaultValue The value to return if the original value is empty
  211. * @param {Boolean} allowBlank (optional) true to allow zero length strings to qualify as non-empty (defaults to false)
  212. * @return {Object} value, if non-empty, else defaultValue
  213. */
  214. valueFrom: function(value, defaultValue, allowBlank){
  215. return Ext.isEmpty(value, allowBlank) ? defaultValue : value;
  216. },
  217. /**
  218. * Returns the type of the given variable in string format. List of possible values are:
  219. *
  220. * - `undefined`: If the given value is `undefined`
  221. * - `null`: If the given value is `null`
  222. * - `string`: If the given value is a string
  223. * - `number`: If the given value is a number
  224. * - `boolean`: If the given value is a boolean value
  225. * - `date`: If the given value is a `Date` object
  226. * - `function`: If the given value is a function reference
  227. * - `object`: If the given value is an object
  228. * - `array`: If the given value is an array
  229. * - `regexp`: If the given value is a regular expression
  230. * - `element`: If the given value is a DOM Element
  231. * - `textnode`: If the given value is a DOM text node and contains something other than whitespace
  232. * - `whitespace`: If the given value is a DOM text node and contains only whitespace
  233. *
  234. * @param {Object} value
  235. * @return {String}
  236. * @markdown
  237. */
  238. typeOf: function(value) {
  239. if (value === null) {
  240. return 'null';
  241. }
  242. var type = typeof value;
  243. if (type === 'undefined' || type === 'string' || type === 'number' || type === 'boolean') {
  244. return type;
  245. }
  246. var typeToString = toString.call(value);
  247. switch(typeToString) {
  248. case '[object Array]':
  249. return 'array';
  250. case '[object Date]':
  251. return 'date';
  252. case '[object Boolean]':
  253. return 'boolean';
  254. case '[object Number]':
  255. return 'number';
  256. case '[object RegExp]':
  257. return 'regexp';
  258. }
  259. if (type === 'function') {
  260. return 'function';
  261. }
  262. if (type === 'object') {
  263. if (value.nodeType !== undefined) {
  264. if (value.nodeType === 3) {
  265. return (/\S/).test(value.nodeValue) ? 'textnode' : 'whitespace';
  266. }
  267. else {
  268. return 'element';
  269. }
  270. }
  271. return 'object';
  272. }
  273. //<debug error>
  274. Ext.Error.raise({
  275. sourceClass: 'Ext',
  276. sourceMethod: 'typeOf',
  277. msg: 'Failed to determine the type of the specified value "' + value + '". This is most likely a bug.'
  278. });
  279. //</debug>
  280. },
  281. /**
  282. * Returns true if the passed value is empty, false otherwise. The value is deemed to be empty if it is either:
  283. *
  284. * - `null`
  285. * - `undefined`
  286. * - a zero-length array
  287. * - a zero-length string (Unless the `allowEmptyString` parameter is set to `true`)
  288. *
  289. * @param {Object} value The value to test
  290. * @param {Boolean} allowEmptyString (optional) true to allow empty strings (defaults to false)
  291. * @return {Boolean}
  292. * @markdown
  293. */
  294. isEmpty: function(value, allowEmptyString) {
  295. return (value === null) || (value === undefined) || (!allowEmptyString ? value === '' : false) || (Ext.isArray(value) && value.length === 0);
  296. },
  297. /**
  298. * Returns true if the passed value is a JavaScript Array, false otherwise.
  299. *
  300. * @param {Object} target The target to test
  301. * @return {Boolean}
  302. * @method
  303. */
  304. isArray: ('isArray' in Array) ? Array.isArray : function(value) {
  305. return toString.call(value) === '[object Array]';
  306. },
  307. /**
  308. * Returns true if the passed value is a JavaScript Date object, false otherwise.
  309. * @param {Object} object The object to test
  310. * @return {Boolean}
  311. */
  312. isDate: function(value) {
  313. return toString.call(value) === '[object Date]';
  314. },
  315. /**
  316. * Returns true if the passed value is a JavaScript Object, false otherwise.
  317. * @param {Object} value The value to test
  318. * @return {Boolean}
  319. * @method
  320. */
  321. isObject: (toString.call(null) === '[object Object]') ?
  322. function(value) {
  323. // check ownerDocument here as well to exclude DOM nodes
  324. return value !== null && value !== undefined && toString.call(value) === '[object Object]' && value.ownerDocument === undefined;
  325. } :
  326. function(value) {
  327. return toString.call(value) === '[object Object]';
  328. },
  329. /**
  330. * @private
  331. */
  332. isSimpleObject: function(value) {
  333. return value instanceof Object && value.constructor === Object;
  334. },
  335. /**
  336. * Returns true if the passed value is a JavaScript 'primitive', a string, number or boolean.
  337. * @param {Object} value The value to test
  338. * @return {Boolean}
  339. */
  340. isPrimitive: function(value) {
  341. var type = typeof value;
  342. return type === 'string' || type === 'number' || type === 'boolean';
  343. },
  344. /**
  345. * Returns true if the passed value is a JavaScript Function, false otherwise.
  346. * @param {Object} value The value to test
  347. * @return {Boolean}
  348. * @method
  349. */
  350. isFunction:
  351. // Safari 3.x and 4.x returns 'function' for typeof <NodeList>, hence we need to fall back to using
  352. // Object.prototype.toString (slower)
  353. (typeof document !== 'undefined' && typeof document.getElementsByTagName('body') === 'function') ? function(value) {
  354. return toString.call(value) === '[object Function]';
  355. } : function(value) {
  356. return typeof value === 'function';
  357. },
  358. /**
  359. * Returns true if the passed value is a number. Returns false for non-finite numbers.
  360. * @param {Object} value The value to test
  361. * @return {Boolean}
  362. */
  363. isNumber: function(value) {
  364. return typeof value === 'number' && isFinite(value);
  365. },
  366. /**
  367. * Validates that a value is numeric.
  368. * @param {Object} value Examples: 1, '1', '2.34'
  369. * @return {Boolean} True if numeric, false otherwise
  370. */
  371. isNumeric: function(value) {
  372. return !isNaN(parseFloat(value)) && isFinite(value);
  373. },
  374. /**
  375. * Returns true if the passed value is a string.
  376. * @param {Object} value The value to test
  377. * @return {Boolean}
  378. */
  379. isString: function(value) {
  380. return typeof value === 'string';
  381. },
  382. /**
  383. * Returns true if the passed value is a boolean.
  384. *
  385. * @param {Object} value The value to test
  386. * @return {Boolean}
  387. */
  388. isBoolean: function(value) {
  389. return typeof value === 'boolean';
  390. },
  391. /**
  392. * Returns true if the passed value is an HTMLElement
  393. * @param {Object} value The value to test
  394. * @return {Boolean}
  395. */
  396. isElement: function(value) {
  397. return value ? value.nodeType === 1 : false;
  398. },
  399. /**
  400. * Returns true if the passed value is a TextNode
  401. * @param {Object} value The value to test
  402. * @return {Boolean}
  403. */
  404. isTextNode: function(value) {
  405. return value ? value.nodeName === "#text" : false;
  406. },
  407. /**
  408. * Returns true if the passed value is defined.
  409. * @param {Object} value The value to test
  410. * @return {Boolean}
  411. */
  412. isDefined: function(value) {
  413. return typeof value !== 'undefined';
  414. },
  415. /**
  416. * Returns true if the passed value is iterable, false otherwise
  417. * @param {Object} value The value to test
  418. * @return {Boolean}
  419. */
  420. isIterable: function(value) {
  421. var type = typeof value,
  422. checkLength = false;
  423. if (value && type != 'string') {
  424. // Functions have a length property, so we need to filter them out
  425. if (type == 'function') {
  426. // In Safari, NodeList/HTMLCollection both return "function" when using typeof, so we need
  427. // to explicitly check them here.
  428. if (Ext.isSafari) {
  429. checkLength = value instanceof NodeList || value instanceof HTMLCollection;
  430. }
  431. } else {
  432. checkLength = true;
  433. }
  434. }
  435. return checkLength ? value.length !== undefined : false;
  436. }
  437. });
  438. Ext.apply(Ext, {
  439. /**
  440. * Clone almost any type of variable including array, object, DOM nodes and Date without keeping the old reference
  441. * @param {Object} item The variable to clone
  442. * @return {Object} clone
  443. */
  444. clone: function(item) {
  445. if (item === null || item === undefined) {
  446. return item;
  447. }
  448. // DOM nodes
  449. // TODO proxy this to Ext.Element.clone to handle automatic id attribute changing
  450. // recursively
  451. if (item.nodeType && item.cloneNode) {
  452. return item.cloneNode(true);
  453. }
  454. var type = toString.call(item);
  455. // Date
  456. if (type === '[object Date]') {
  457. return new Date(item.getTime());
  458. }
  459. var i, j, k, clone, key;
  460. // Array
  461. if (type === '[object Array]') {
  462. i = item.length;
  463. clone = [];
  464. while (i--) {
  465. clone[i] = Ext.clone(item[i]);
  466. }
  467. }
  468. // Object
  469. else if (type === '[object Object]' && item.constructor === Object) {
  470. clone = {};
  471. for (key in item) {
  472. clone[key] = Ext.clone(item[key]);
  473. }
  474. if (enumerables) {
  475. for (j = enumerables.length; j--;) {
  476. k = enumerables[j];
  477. clone[k] = item[k];
  478. }
  479. }
  480. }
  481. return clone || item;
  482. },
  483. /**
  484. * @private
  485. * Generate a unique reference of Ext in the global scope, useful for sandboxing
  486. */
  487. getUniqueGlobalNamespace: function() {
  488. var uniqueGlobalNamespace = this.uniqueGlobalNamespace;
  489. if (uniqueGlobalNamespace === undefined) {
  490. var i = 0;
  491. do {
  492. uniqueGlobalNamespace = 'ExtBox' + (++i);
  493. } while (Ext.global[uniqueGlobalNamespace] !== undefined);
  494. Ext.global[uniqueGlobalNamespace] = Ext;
  495. this.uniqueGlobalNamespace = uniqueGlobalNamespace;
  496. }
  497. return uniqueGlobalNamespace;
  498. },
  499. /**
  500. * @private
  501. */
  502. functionFactoryCache: {},
  503. cacheableFunctionFactory: function() {
  504. var me = this,
  505. args = Array.prototype.slice.call(arguments),
  506. cache = me.functionFactoryCache,
  507. idx, fn, ln;
  508. if (Ext.isSandboxed) {
  509. ln = args.length;
  510. if (ln > 0) {
  511. ln--;
  512. args[ln] = 'var Ext=window.' + Ext.name + ';' + args[ln];
  513. }
  514. }
  515. idx = args.join('');
  516. fn = cache[idx];
  517. if (!fn) {
  518. fn = Function.prototype.constructor.apply(Function.prototype, args);
  519. cache[idx] = fn;
  520. }
  521. return fn;
  522. },
  523. functionFactory: function() {
  524. var me = this,
  525. args = Array.prototype.slice.call(arguments),
  526. ln;
  527. if (Ext.isSandboxed) {
  528. ln = args.length;
  529. if (ln > 0) {
  530. ln--;
  531. args[ln] = 'var Ext=window.' + Ext.name + ';' + args[ln];
  532. }
  533. }
  534. return Function.prototype.constructor.apply(Function.prototype, args);
  535. },
  536. /**
  537. * @property
  538. * @private
  539. */
  540. globalEval: ('execScript' in global) ? function(code) {
  541. global.execScript(code)
  542. } : function(code) {
  543. (function(){
  544. eval(code);
  545. })();
  546. },
  547. /**
  548. * @private
  549. * @property
  550. */
  551. Logger: {
  552. verbose: emptyFn,
  553. log: emptyFn,
  554. info: emptyFn,
  555. warn: emptyFn,
  556. error: function(message) {
  557. throw new Error(message);
  558. },
  559. deprecate: emptyFn
  560. }
  561. });
  562. /**
  563. * Old alias to {@link Ext#typeOf}
  564. * @deprecated 4.0.0 Use {@link Ext#typeOf} instead
  565. * @method
  566. * @inheritdoc Ext#typeOf
  567. */
  568. Ext.type = Ext.typeOf;
  569. })();