/ext-4.0.7/builds/ext-foundation-dev.js

https://bitbucket.org/srogerf/javascript · JavaScript · 8848 lines · 5271 code · 753 blank · 2824 comment · 554 complexity · 1d768b28a5617b02c3abcaf2ee7d8efa MD5 · raw file

Large files are truncated click here to view the full file

  1. /*
  2. This file is part of Ext JS 4
  3. Copyright (c) 2011 Sencha Inc
  4. Contact: http://www.sencha.com/contact
  5. GNU General Public License Usage
  6. This file may be used under the terms of the GNU General Public License version 3.0 as published by the Free Software Foundation and appearing in the file LICENSE included in the packaging of this file. Please review the following information to ensure the GNU General Public License version 3.0 requirements will be met: http://www.gnu.org/copyleft/gpl.html.
  7. If you are unsure which license is appropriate for your use, please contact the sales department at http://www.sencha.com/contact.
  8. */
  9. /**
  10. * @class Ext
  11. * @singleton
  12. */
  13. (function() {
  14. var global = this,
  15. objectPrototype = Object.prototype,
  16. toString = objectPrototype.toString,
  17. enumerables = true,
  18. enumerablesTest = { toString: 1 },
  19. i;
  20. if (typeof Ext === 'undefined') {
  21. global.Ext = {};
  22. }
  23. Ext.global = global;
  24. for (i in enumerablesTest) {
  25. enumerables = null;
  26. }
  27. if (enumerables) {
  28. enumerables = ['hasOwnProperty', 'valueOf', 'isPrototypeOf', 'propertyIsEnumerable',
  29. 'toLocaleString', 'toString', 'constructor'];
  30. }
  31. /**
  32. * An array containing extra enumerables for old browsers
  33. * @property {String[]}
  34. */
  35. Ext.enumerables = enumerables;
  36. /**
  37. * Copies all the properties of config to the specified object.
  38. * Note that if recursive merging and cloning without referencing the original objects / arrays is needed, use
  39. * {@link Ext.Object#merge} instead.
  40. * @param {Object} object The receiver of the properties
  41. * @param {Object} config The source of the properties
  42. * @param {Object} defaults A different object that will also be applied for default values
  43. * @return {Object} returns obj
  44. */
  45. Ext.apply = function(object, config, defaults) {
  46. if (defaults) {
  47. Ext.apply(object, defaults);
  48. }
  49. if (object && config && typeof config === 'object') {
  50. var i, j, k;
  51. for (i in config) {
  52. object[i] = config[i];
  53. }
  54. if (enumerables) {
  55. for (j = enumerables.length; j--;) {
  56. k = enumerables[j];
  57. if (config.hasOwnProperty(k)) {
  58. object[k] = config[k];
  59. }
  60. }
  61. }
  62. }
  63. return object;
  64. };
  65. Ext.buildSettings = Ext.apply({
  66. baseCSSPrefix: 'x-',
  67. scopeResetCSS: false
  68. }, Ext.buildSettings || {});
  69. Ext.apply(Ext, {
  70. /**
  71. * A reusable empty function
  72. */
  73. emptyFn: function() {},
  74. baseCSSPrefix: Ext.buildSettings.baseCSSPrefix,
  75. /**
  76. * Copies all the properties of config to object if they don't already exist.
  77. * @param {Object} object The receiver of the properties
  78. * @param {Object} config The source of the properties
  79. * @return {Object} returns obj
  80. */
  81. applyIf: function(object, config) {
  82. var property;
  83. if (object) {
  84. for (property in config) {
  85. if (object[property] === undefined) {
  86. object[property] = config[property];
  87. }
  88. }
  89. }
  90. return object;
  91. },
  92. /**
  93. * Iterates either an array or an object. This method delegates to
  94. * {@link Ext.Array#each Ext.Array.each} if the given value is iterable, and {@link Ext.Object#each Ext.Object.each} otherwise.
  95. *
  96. * @param {Object/Array} object The object or array to be iterated.
  97. * @param {Function} fn The function to be called for each iteration. See and {@link Ext.Array#each Ext.Array.each} and
  98. * {@link Ext.Object#each Ext.Object.each} for detailed lists of arguments passed to this function depending on the given object
  99. * type that is being iterated.
  100. * @param {Object} scope (Optional) The scope (`this` reference) in which the specified function is executed.
  101. * Defaults to the object being iterated itself.
  102. * @markdown
  103. */
  104. iterate: function(object, fn, scope) {
  105. if (Ext.isEmpty(object)) {
  106. return;
  107. }
  108. if (scope === undefined) {
  109. scope = object;
  110. }
  111. if (Ext.isIterable(object)) {
  112. Ext.Array.each.call(Ext.Array, object, fn, scope);
  113. }
  114. else {
  115. Ext.Object.each.call(Ext.Object, object, fn, scope);
  116. }
  117. }
  118. });
  119. Ext.apply(Ext, {
  120. /**
  121. * This method deprecated. Use {@link Ext#define Ext.define} instead.
  122. * @method
  123. * @param {Function} superclass
  124. * @param {Object} overrides
  125. * @return {Function} The subclass constructor from the <tt>overrides</tt> parameter, or a generated one if not provided.
  126. * @deprecated 4.0.0 Use {@link Ext#define Ext.define} instead
  127. */
  128. extend: function() {
  129. // inline overrides
  130. var objectConstructor = objectPrototype.constructor,
  131. inlineOverrides = function(o) {
  132. for (var m in o) {
  133. if (!o.hasOwnProperty(m)) {
  134. continue;
  135. }
  136. this[m] = o[m];
  137. }
  138. };
  139. return function(subclass, superclass, overrides) {
  140. // First we check if the user passed in just the superClass with overrides
  141. if (Ext.isObject(superclass)) {
  142. overrides = superclass;
  143. superclass = subclass;
  144. subclass = overrides.constructor !== objectConstructor ? overrides.constructor : function() {
  145. superclass.apply(this, arguments);
  146. };
  147. }
  148. if (!superclass) {
  149. Ext.Error.raise({
  150. sourceClass: 'Ext',
  151. sourceMethod: 'extend',
  152. msg: 'Attempting to extend from a class which has not been loaded on the page.'
  153. });
  154. }
  155. // We create a new temporary class
  156. var F = function() {},
  157. subclassProto, superclassProto = superclass.prototype;
  158. F.prototype = superclassProto;
  159. subclassProto = subclass.prototype = new F();
  160. subclassProto.constructor = subclass;
  161. subclass.superclass = superclassProto;
  162. if (superclassProto.constructor === objectConstructor) {
  163. superclassProto.constructor = superclass;
  164. }
  165. subclass.override = function(overrides) {
  166. Ext.override(subclass, overrides);
  167. };
  168. subclassProto.override = inlineOverrides;
  169. subclassProto.proto = subclassProto;
  170. subclass.override(overrides);
  171. subclass.extend = function(o) {
  172. return Ext.extend(subclass, o);
  173. };
  174. return subclass;
  175. };
  176. }(),
  177. /**
  178. * Proxy to {@link Ext.Base#override}. Please refer {@link Ext.Base#override} for further details.
  179. Ext.define('My.cool.Class', {
  180. sayHi: function() {
  181. alert('Hi!');
  182. }
  183. }
  184. Ext.override(My.cool.Class, {
  185. sayHi: function() {
  186. alert('About to say...');
  187. this.callOverridden();
  188. }
  189. });
  190. var cool = new My.cool.Class();
  191. cool.sayHi(); // alerts 'About to say...'
  192. // alerts 'Hi!'
  193. * Please note that `this.callOverridden()` only works if the class was previously
  194. * created with {@link Ext#define)
  195. *
  196. * @param {Object} cls The class to override
  197. * @param {Object} overrides The list of functions to add to origClass. This should be specified as an object literal
  198. * containing one or more methods.
  199. * @method override
  200. * @markdown
  201. */
  202. override: function(cls, overrides) {
  203. if (cls.prototype.$className) {
  204. return cls.override(overrides);
  205. }
  206. else {
  207. Ext.apply(cls.prototype, overrides);
  208. }
  209. }
  210. });
  211. // A full set of static methods to do type checking
  212. Ext.apply(Ext, {
  213. /**
  214. * Returns the given value itself if it's not empty, as described in {@link Ext#isEmpty}; returns the default
  215. * value (second argument) otherwise.
  216. *
  217. * @param {Object} value The value to test
  218. * @param {Object} defaultValue The value to return if the original value is empty
  219. * @param {Boolean} allowBlank (optional) true to allow zero length strings to qualify as non-empty (defaults to false)
  220. * @return {Object} value, if non-empty, else defaultValue
  221. */
  222. valueFrom: function(value, defaultValue, allowBlank){
  223. return Ext.isEmpty(value, allowBlank) ? defaultValue : value;
  224. },
  225. /**
  226. * Returns the type of the given variable in string format. List of possible values are:
  227. *
  228. * - `undefined`: If the given value is `undefined`
  229. * - `null`: If the given value is `null`
  230. * - `string`: If the given value is a string
  231. * - `number`: If the given value is a number
  232. * - `boolean`: If the given value is a boolean value
  233. * - `date`: If the given value is a `Date` object
  234. * - `function`: If the given value is a function reference
  235. * - `object`: If the given value is an object
  236. * - `array`: If the given value is an array
  237. * - `regexp`: If the given value is a regular expression
  238. * - `element`: If the given value is a DOM Element
  239. * - `textnode`: If the given value is a DOM text node and contains something other than whitespace
  240. * - `whitespace`: If the given value is a DOM text node and contains only whitespace
  241. *
  242. * @param {Object} value
  243. * @return {String}
  244. * @markdown
  245. */
  246. typeOf: function(value) {
  247. if (value === null) {
  248. return 'null';
  249. }
  250. var type = typeof value;
  251. if (type === 'undefined' || type === 'string' || type === 'number' || type === 'boolean') {
  252. return type;
  253. }
  254. var typeToString = toString.call(value);
  255. switch(typeToString) {
  256. case '[object Array]':
  257. return 'array';
  258. case '[object Date]':
  259. return 'date';
  260. case '[object Boolean]':
  261. return 'boolean';
  262. case '[object Number]':
  263. return 'number';
  264. case '[object RegExp]':
  265. return 'regexp';
  266. }
  267. if (type === 'function') {
  268. return 'function';
  269. }
  270. if (type === 'object') {
  271. if (value.nodeType !== undefined) {
  272. if (value.nodeType === 3) {
  273. return (/\S/).test(value.nodeValue) ? 'textnode' : 'whitespace';
  274. }
  275. else {
  276. return 'element';
  277. }
  278. }
  279. return 'object';
  280. }
  281. Ext.Error.raise({
  282. sourceClass: 'Ext',
  283. sourceMethod: 'typeOf',
  284. msg: 'Failed to determine the type of the specified value "' + value + '". This is most likely a bug.'
  285. });
  286. },
  287. /**
  288. * Returns true if the passed value is empty, false otherwise. The value is deemed to be empty if it is either:
  289. *
  290. * - `null`
  291. * - `undefined`
  292. * - a zero-length array
  293. * - a zero-length string (Unless the `allowEmptyString` parameter is set to `true`)
  294. *
  295. * @param {Object} value The value to test
  296. * @param {Boolean} allowEmptyString (optional) true to allow empty strings (defaults to false)
  297. * @return {Boolean}
  298. * @markdown
  299. */
  300. isEmpty: function(value, allowEmptyString) {
  301. return (value === null) || (value === undefined) || (!allowEmptyString ? value === '' : false) || (Ext.isArray(value) && value.length === 0);
  302. },
  303. /**
  304. * Returns true if the passed value is a JavaScript Array, false otherwise.
  305. *
  306. * @param {Object} target The target to test
  307. * @return {Boolean}
  308. * @method
  309. */
  310. isArray: ('isArray' in Array) ? Array.isArray : function(value) {
  311. return toString.call(value) === '[object Array]';
  312. },
  313. /**
  314. * Returns true if the passed value is a JavaScript Date object, false otherwise.
  315. * @param {Object} object The object to test
  316. * @return {Boolean}
  317. */
  318. isDate: function(value) {
  319. return toString.call(value) === '[object Date]';
  320. },
  321. /**
  322. * Returns true if the passed value is a JavaScript Object, false otherwise.
  323. * @param {Object} value The value to test
  324. * @return {Boolean}
  325. * @method
  326. */
  327. isObject: (toString.call(null) === '[object Object]') ?
  328. function(value) {
  329. // check ownerDocument here as well to exclude DOM nodes
  330. return value !== null && value !== undefined && toString.call(value) === '[object Object]' && value.ownerDocument === undefined;
  331. } :
  332. function(value) {
  333. return toString.call(value) === '[object 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.prorotype.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. return (value && typeof value !== 'string') ? value.length !== undefined : false;
  422. }
  423. });
  424. Ext.apply(Ext, {
  425. /**
  426. * Clone almost any type of variable including array, object, DOM nodes and Date without keeping the old reference
  427. * @param {Object} item The variable to clone
  428. * @return {Object} clone
  429. */
  430. clone: function(item) {
  431. if (item === null || item === undefined) {
  432. return item;
  433. }
  434. // DOM nodes
  435. // TODO proxy this to Ext.Element.clone to handle automatic id attribute changing
  436. // recursively
  437. if (item.nodeType && item.cloneNode) {
  438. return item.cloneNode(true);
  439. }
  440. var type = toString.call(item);
  441. // Date
  442. if (type === '[object Date]') {
  443. return new Date(item.getTime());
  444. }
  445. var i, j, k, clone, key;
  446. // Array
  447. if (type === '[object Array]') {
  448. i = item.length;
  449. clone = [];
  450. while (i--) {
  451. clone[i] = Ext.clone(item[i]);
  452. }
  453. }
  454. // Object
  455. else if (type === '[object Object]' && item.constructor === Object) {
  456. clone = {};
  457. for (key in item) {
  458. clone[key] = Ext.clone(item[key]);
  459. }
  460. if (enumerables) {
  461. for (j = enumerables.length; j--;) {
  462. k = enumerables[j];
  463. clone[k] = item[k];
  464. }
  465. }
  466. }
  467. return clone || item;
  468. },
  469. /**
  470. * @private
  471. * Generate a unique reference of Ext in the global scope, useful for sandboxing
  472. */
  473. getUniqueGlobalNamespace: function() {
  474. var uniqueGlobalNamespace = this.uniqueGlobalNamespace;
  475. if (uniqueGlobalNamespace === undefined) {
  476. var i = 0;
  477. do {
  478. uniqueGlobalNamespace = 'ExtBox' + (++i);
  479. } while (Ext.global[uniqueGlobalNamespace] !== undefined);
  480. Ext.global[uniqueGlobalNamespace] = Ext;
  481. this.uniqueGlobalNamespace = uniqueGlobalNamespace;
  482. }
  483. return uniqueGlobalNamespace;
  484. },
  485. /**
  486. * @private
  487. */
  488. functionFactory: function() {
  489. var args = Array.prototype.slice.call(arguments);
  490. if (args.length > 0) {
  491. args[args.length - 1] = 'var Ext=window.' + this.getUniqueGlobalNamespace() + ';' +
  492. args[args.length - 1];
  493. }
  494. return Function.prototype.constructor.apply(Function.prototype, args);
  495. }
  496. });
  497. /**
  498. * Old alias to {@link Ext#typeOf}
  499. * @deprecated 4.0.0 Use {@link Ext#typeOf} instead
  500. * @method
  501. * @alias Ext#typeOf
  502. */
  503. Ext.type = Ext.typeOf;
  504. })();
  505. /**
  506. * @author Jacky Nguyen <jacky@sencha.com>
  507. * @docauthor Jacky Nguyen <jacky@sencha.com>
  508. * @class Ext.Version
  509. *
  510. * A utility class that wrap around a string version number and provide convenient
  511. * method to perform comparison. See also: {@link Ext.Version#compare compare}. Example:
  512. var version = new Ext.Version('1.0.2beta');
  513. console.log("Version is " + version); // Version is 1.0.2beta
  514. console.log(version.getMajor()); // 1
  515. console.log(version.getMinor()); // 0
  516. console.log(version.getPatch()); // 2
  517. console.log(version.getBuild()); // 0
  518. console.log(version.getRelease()); // beta
  519. console.log(version.isGreaterThan('1.0.1')); // True
  520. console.log(version.isGreaterThan('1.0.2alpha')); // True
  521. console.log(version.isGreaterThan('1.0.2RC')); // False
  522. console.log(version.isGreaterThan('1.0.2')); // False
  523. console.log(version.isLessThan('1.0.2')); // True
  524. console.log(version.match(1.0)); // True
  525. console.log(version.match('1.0.2')); // True
  526. * @markdown
  527. */
  528. (function() {
  529. // Current core version
  530. var version = '4.0.7', Version;
  531. Ext.Version = Version = Ext.extend(Object, {
  532. /**
  533. * @param {String/Number} version The version number in the follow standard format: major[.minor[.patch[.build[release]]]]
  534. * Examples: 1.0 or 1.2.3beta or 1.2.3.4RC
  535. * @return {Ext.Version} this
  536. */
  537. constructor: function(version) {
  538. var parts, releaseStartIndex;
  539. if (version instanceof Version) {
  540. return version;
  541. }
  542. this.version = this.shortVersion = String(version).toLowerCase().replace(/_/g, '.').replace(/[\-+]/g, '');
  543. releaseStartIndex = this.version.search(/([^\d\.])/);
  544. if (releaseStartIndex !== -1) {
  545. this.release = this.version.substr(releaseStartIndex, version.length);
  546. this.shortVersion = this.version.substr(0, releaseStartIndex);
  547. }
  548. this.shortVersion = this.shortVersion.replace(/[^\d]/g, '');
  549. parts = this.version.split('.');
  550. this.major = parseInt(parts.shift() || 0, 10);
  551. this.minor = parseInt(parts.shift() || 0, 10);
  552. this.patch = parseInt(parts.shift() || 0, 10);
  553. this.build = parseInt(parts.shift() || 0, 10);
  554. return this;
  555. },
  556. /**
  557. * Override the native toString method
  558. * @private
  559. * @return {String} version
  560. */
  561. toString: function() {
  562. return this.version;
  563. },
  564. /**
  565. * Override the native valueOf method
  566. * @private
  567. * @return {String} version
  568. */
  569. valueOf: function() {
  570. return this.version;
  571. },
  572. /**
  573. * Returns the major component value
  574. * @return {Number} major
  575. */
  576. getMajor: function() {
  577. return this.major || 0;
  578. },
  579. /**
  580. * Returns the minor component value
  581. * @return {Number} minor
  582. */
  583. getMinor: function() {
  584. return this.minor || 0;
  585. },
  586. /**
  587. * Returns the patch component value
  588. * @return {Number} patch
  589. */
  590. getPatch: function() {
  591. return this.patch || 0;
  592. },
  593. /**
  594. * Returns the build component value
  595. * @return {Number} build
  596. */
  597. getBuild: function() {
  598. return this.build || 0;
  599. },
  600. /**
  601. * Returns the release component value
  602. * @return {Number} release
  603. */
  604. getRelease: function() {
  605. return this.release || '';
  606. },
  607. /**
  608. * Returns whether this version if greater than the supplied argument
  609. * @param {String/Number} target The version to compare with
  610. * @return {Boolean} True if this version if greater than the target, false otherwise
  611. */
  612. isGreaterThan: function(target) {
  613. return Version.compare(this.version, target) === 1;
  614. },
  615. /**
  616. * Returns whether this version if smaller than the supplied argument
  617. * @param {String/Number} target The version to compare with
  618. * @return {Boolean} True if this version if smaller than the target, false otherwise
  619. */
  620. isLessThan: function(target) {
  621. return Version.compare(this.version, target) === -1;
  622. },
  623. /**
  624. * Returns whether this version equals to the supplied argument
  625. * @param {String/Number} target The version to compare with
  626. * @return {Boolean} True if this version equals to the target, false otherwise
  627. */
  628. equals: function(target) {
  629. return Version.compare(this.version, target) === 0;
  630. },
  631. /**
  632. * Returns whether this version matches the supplied argument. Example:
  633. * <pre><code>
  634. * var version = new Ext.Version('1.0.2beta');
  635. * console.log(version.match(1)); // True
  636. * console.log(version.match(1.0)); // True
  637. * console.log(version.match('1.0.2')); // True
  638. * console.log(version.match('1.0.2RC')); // False
  639. * </code></pre>
  640. * @param {String/Number} target The version to compare with
  641. * @return {Boolean} True if this version matches the target, false otherwise
  642. */
  643. match: function(target) {
  644. target = String(target);
  645. return this.version.substr(0, target.length) === target;
  646. },
  647. /**
  648. * Returns this format: [major, minor, patch, build, release]. Useful for comparison
  649. * @return {Number[]}
  650. */
  651. toArray: function() {
  652. return [this.getMajor(), this.getMinor(), this.getPatch(), this.getBuild(), this.getRelease()];
  653. },
  654. /**
  655. * Returns shortVersion version without dots and release
  656. * @return {String}
  657. */
  658. getShortVersion: function() {
  659. return this.shortVersion;
  660. }
  661. });
  662. Ext.apply(Version, {
  663. // @private
  664. releaseValueMap: {
  665. 'dev': -6,
  666. 'alpha': -5,
  667. 'a': -5,
  668. 'beta': -4,
  669. 'b': -4,
  670. 'rc': -3,
  671. '#': -2,
  672. 'p': -1,
  673. 'pl': -1
  674. },
  675. /**
  676. * Converts a version component to a comparable value
  677. *
  678. * @static
  679. * @param {Object} value The value to convert
  680. * @return {Object}
  681. */
  682. getComponentValue: function(value) {
  683. return !value ? 0 : (isNaN(value) ? this.releaseValueMap[value] || value : parseInt(value, 10));
  684. },
  685. /**
  686. * Compare 2 specified versions, starting from left to right. If a part contains special version strings,
  687. * they are handled in the following order:
  688. * 'dev' < 'alpha' = 'a' < 'beta' = 'b' < 'RC' = 'rc' < '#' < 'pl' = 'p' < 'anything else'
  689. *
  690. * @static
  691. * @param {String} current The current version to compare to
  692. * @param {String} target The target version to compare to
  693. * @return {Number} Returns -1 if the current version is smaller than the target version, 1 if greater, and 0 if they're equivalent
  694. */
  695. compare: function(current, target) {
  696. var currentValue, targetValue, i;
  697. current = new Version(current).toArray();
  698. target = new Version(target).toArray();
  699. for (i = 0; i < Math.max(current.length, target.length); i++) {
  700. currentValue = this.getComponentValue(current[i]);
  701. targetValue = this.getComponentValue(target[i]);
  702. if (currentValue < targetValue) {
  703. return -1;
  704. } else if (currentValue > targetValue) {
  705. return 1;
  706. }
  707. }
  708. return 0;
  709. }
  710. });
  711. Ext.apply(Ext, {
  712. /**
  713. * @private
  714. */
  715. versions: {},
  716. /**
  717. * @private
  718. */
  719. lastRegisteredVersion: null,
  720. /**
  721. * Set version number for the given package name.
  722. *
  723. * @param {String} packageName The package name, for example: 'core', 'touch', 'extjs'
  724. * @param {String/Ext.Version} version The version, for example: '1.2.3alpha', '2.4.0-dev'
  725. * @return {Ext}
  726. */
  727. setVersion: function(packageName, version) {
  728. Ext.versions[packageName] = new Version(version);
  729. Ext.lastRegisteredVersion = Ext.versions[packageName];
  730. return this;
  731. },
  732. /**
  733. * Get the version number of the supplied package name; will return the last registered version
  734. * (last Ext.setVersion call) if there's no package name given.
  735. *
  736. * @param {String} packageName (Optional) The package name, for example: 'core', 'touch', 'extjs'
  737. * @return {Ext.Version} The version
  738. */
  739. getVersion: function(packageName) {
  740. if (packageName === undefined) {
  741. return Ext.lastRegisteredVersion;
  742. }
  743. return Ext.versions[packageName];
  744. },
  745. /**
  746. * Create a closure for deprecated code.
  747. *
  748. // This means Ext.oldMethod is only supported in 4.0.0beta and older.
  749. // If Ext.getVersion('extjs') returns a version that is later than '4.0.0beta', for example '4.0.0RC',
  750. // the closure will not be invoked
  751. Ext.deprecate('extjs', '4.0.0beta', function() {
  752. Ext.oldMethod = Ext.newMethod;
  753. ...
  754. });
  755. * @param {String} packageName The package name
  756. * @param {String} since The last version before it's deprecated
  757. * @param {Function} closure The callback function to be executed with the specified version is less than the current version
  758. * @param {Object} scope The execution scope (<tt>this</tt>) if the closure
  759. * @markdown
  760. */
  761. deprecate: function(packageName, since, closure, scope) {
  762. if (Version.compare(Ext.getVersion(packageName), since) < 1) {
  763. closure.call(scope);
  764. }
  765. }
  766. }); // End Versioning
  767. Ext.setVersion('core', version);
  768. })();
  769. /**
  770. * @class Ext.String
  771. *
  772. * A collection of useful static methods to deal with strings
  773. * @singleton
  774. */
  775. Ext.String = {
  776. trimRegex: /^[\x09\x0a\x0b\x0c\x0d\x20\xa0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u2028\u2029\u202f\u205f\u3000]+|[\x09\x0a\x0b\x0c\x0d\x20\xa0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u2028\u2029\u202f\u205f\u3000]+$/g,
  777. escapeRe: /('|\\)/g,
  778. formatRe: /\{(\d+)\}/g,
  779. escapeRegexRe: /([-.*+?^${}()|[\]\/\\])/g,
  780. /**
  781. * Convert certain characters (&, <, >, and ") to their HTML character equivalents for literal display in web pages.
  782. * @param {String} value The string to encode
  783. * @return {String} The encoded text
  784. * @method
  785. */
  786. htmlEncode: (function() {
  787. var entities = {
  788. '&': '&amp;',
  789. '>': '&gt;',
  790. '<': '&lt;',
  791. '"': '&quot;'
  792. }, keys = [], p, regex;
  793. for (p in entities) {
  794. keys.push(p);
  795. }
  796. regex = new RegExp('(' + keys.join('|') + ')', 'g');
  797. return function(value) {
  798. return (!value) ? value : String(value).replace(regex, function(match, capture) {
  799. return entities[capture];
  800. });
  801. };
  802. })(),
  803. /**
  804. * Convert certain characters (&, <, >, and ") from their HTML character equivalents.
  805. * @param {String} value The string to decode
  806. * @return {String} The decoded text
  807. * @method
  808. */
  809. htmlDecode: (function() {
  810. var entities = {
  811. '&amp;': '&',
  812. '&gt;': '>',
  813. '&lt;': '<',
  814. '&quot;': '"'
  815. }, keys = [], p, regex;
  816. for (p in entities) {
  817. keys.push(p);
  818. }
  819. regex = new RegExp('(' + keys.join('|') + '|&#[0-9]{1,5};' + ')', 'g');
  820. return function(value) {
  821. return (!value) ? value : String(value).replace(regex, function(match, capture) {
  822. if (capture in entities) {
  823. return entities[capture];
  824. } else {
  825. return String.fromCharCode(parseInt(capture.substr(2), 10));
  826. }
  827. });
  828. };
  829. })(),
  830. /**
  831. * Appends content to the query string of a URL, handling logic for whether to place
  832. * a question mark or ampersand.
  833. * @param {String} url The URL to append to.
  834. * @param {String} string The content to append to the URL.
  835. * @return (String) The resulting URL
  836. */
  837. urlAppend : function(url, string) {
  838. if (!Ext.isEmpty(string)) {
  839. return url + (url.indexOf('?') === -1 ? '?' : '&') + string;
  840. }
  841. return url;
  842. },
  843. /**
  844. * Trims whitespace from either end of a string, leaving spaces within the string intact. Example:
  845. * @example
  846. var s = ' foo bar ';
  847. alert('-' + s + '-'); //alerts "- foo bar -"
  848. alert('-' + Ext.String.trim(s) + '-'); //alerts "-foo bar-"
  849. * @param {String} string The string to escape
  850. * @return {String} The trimmed string
  851. */
  852. trim: function(string) {
  853. return string.replace(Ext.String.trimRegex, "");
  854. },
  855. /**
  856. * Capitalize the given string
  857. * @param {String} string
  858. * @return {String}
  859. */
  860. capitalize: function(string) {
  861. return string.charAt(0).toUpperCase() + string.substr(1);
  862. },
  863. /**
  864. * Truncate a string and add an ellipsis ('...') to the end if it exceeds the specified length
  865. * @param {String} value The string to truncate
  866. * @param {Number} length The maximum length to allow before truncating
  867. * @param {Boolean} word True to try to find a common word break
  868. * @return {String} The converted text
  869. */
  870. ellipsis: function(value, len, word) {
  871. if (value && value.length > len) {
  872. if (word) {
  873. var vs = value.substr(0, len - 2),
  874. index = Math.max(vs.lastIndexOf(' '), vs.lastIndexOf('.'), vs.lastIndexOf('!'), vs.lastIndexOf('?'));
  875. if (index !== -1 && index >= (len - 15)) {
  876. return vs.substr(0, index) + "...";
  877. }
  878. }
  879. return value.substr(0, len - 3) + "...";
  880. }
  881. return value;
  882. },
  883. /**
  884. * Escapes the passed string for use in a regular expression
  885. * @param {String} string
  886. * @return {String}
  887. */
  888. escapeRegex: function(string) {
  889. return string.replace(Ext.String.escapeRegexRe, "\\$1");
  890. },
  891. /**
  892. * Escapes the passed string for ' and \
  893. * @param {String} string The string to escape
  894. * @return {String} The escaped string
  895. */
  896. escape: function(string) {
  897. return string.replace(Ext.String.escapeRe, "\\$1");
  898. },
  899. /**
  900. * Utility function that allows you to easily switch a string between two alternating values. The passed value
  901. * is compared to the current string, and if they are equal, the other value that was passed in is returned. If
  902. * they are already different, the first value passed in is returned. Note that this method returns the new value
  903. * but does not change the current string.
  904. * <pre><code>
  905. // alternate sort directions
  906. sort = Ext.String.toggle(sort, 'ASC', 'DESC');
  907. // instead of conditional logic:
  908. sort = (sort == 'ASC' ? 'DESC' : 'ASC');
  909. </code></pre>
  910. * @param {String} string The current string
  911. * @param {String} value The value to compare to the current string
  912. * @param {String} other The new value to use if the string already equals the first value passed in
  913. * @return {String} The new value
  914. */
  915. toggle: function(string, value, other) {
  916. return string === value ? other : value;
  917. },
  918. /**
  919. * Pads the left side of a string with a specified character. This is especially useful
  920. * for normalizing number and date strings. Example usage:
  921. *
  922. * <pre><code>
  923. var s = Ext.String.leftPad('123', 5, '0');
  924. // s now contains the string: '00123'
  925. </code></pre>
  926. * @param {String} string The original string
  927. * @param {Number} size The total length of the output string
  928. * @param {String} character (optional) The character with which to pad the original string (defaults to empty string " ")
  929. * @return {String} The padded string
  930. */
  931. leftPad: function(string, size, character) {
  932. var result = String(string);
  933. character = character || " ";
  934. while (result.length < size) {
  935. result = character + result;
  936. }
  937. return result;
  938. },
  939. /**
  940. * Allows you to define a tokenized string and pass an arbitrary number of arguments to replace the tokens. Each
  941. * token must be unique, and must increment in the format {0}, {1}, etc. Example usage:
  942. * <pre><code>
  943. var cls = 'my-class', text = 'Some text';
  944. var s = Ext.String.format('&lt;div class="{0}">{1}&lt;/div>', cls, text);
  945. // s now contains the string: '&lt;div class="my-class">Some text&lt;/div>'
  946. </code></pre>
  947. * @param {String} string The tokenized string to be formatted
  948. * @param {String} value1 The value to replace token {0}
  949. * @param {String} value2 Etc...
  950. * @return {String} The formatted string
  951. */
  952. format: function(format) {
  953. var args = Ext.Array.toArray(arguments, 1);
  954. return format.replace(Ext.String.formatRe, function(m, i) {
  955. return args[i];
  956. });
  957. },
  958. /**
  959. * Returns a string with a specified number of repititions a given string pattern.
  960. * The pattern be separated by a different string.
  961. *
  962. * var s = Ext.String.repeat('---', 4); // = '------------'
  963. * var t = Ext.String.repeat('--', 3, '/'); // = '--/--/--'
  964. *
  965. * @param {String} pattern The pattern to repeat.
  966. * @param {Number} count The number of times to repeat the pattern (may be 0).
  967. * @param {String} sep An option string to separate each pattern.
  968. */
  969. repeat: function(pattern, count, sep) {
  970. for (var buf = [], i = count; i--; ) {
  971. buf.push(pattern);
  972. }
  973. return buf.join(sep || '');
  974. }
  975. };
  976. /**
  977. * @class Ext.Number
  978. *
  979. * A collection of useful static methods to deal with numbers
  980. * @singleton
  981. */
  982. (function() {
  983. var isToFixedBroken = (0.9).toFixed() !== '1';
  984. Ext.Number = {
  985. /**
  986. * Checks whether or not the passed number is within a desired range. If the number is already within the
  987. * range it is returned, otherwise the min or max value is returned depending on which side of the range is
  988. * exceeded. Note that this method returns the constrained value but does not change the current number.
  989. * @param {Number} number The number to check
  990. * @param {Number} min The minimum number in the range
  991. * @param {Number} max The maximum number in the range
  992. * @return {Number} The constrained value if outside the range, otherwise the current value
  993. */
  994. constrain: function(number, min, max) {
  995. number = parseFloat(number);
  996. if (!isNaN(min)) {
  997. number = Math.max(number, min);
  998. }
  999. if (!isNaN(max)) {
  1000. number = Math.min(number, max);
  1001. }
  1002. return number;
  1003. },
  1004. /**
  1005. * Snaps the passed number between stopping points based upon a passed increment value.
  1006. * @param {Number} value The unsnapped value.
  1007. * @param {Number} increment The increment by which the value must move.
  1008. * @param {Number} minValue The minimum value to which the returned value must be constrained. Overrides the increment..
  1009. * @param {Number} maxValue The maximum value to which the returned value must be constrained. Overrides the increment..
  1010. * @return {Number} The value of the nearest snap target.
  1011. */
  1012. snap : function(value, increment, minValue, maxValue) {
  1013. var newValue = value,
  1014. m;
  1015. if (!(increment && value)) {
  1016. return value;
  1017. }
  1018. m = value % increment;
  1019. if (m !== 0) {
  1020. newValue -= m;
  1021. if (m * 2 >= increment) {
  1022. newValue += increment;
  1023. } else if (m * 2 < -increment) {
  1024. newValue -= increment;
  1025. }
  1026. }
  1027. return Ext.Number.constrain(newValue, minValue, maxValue);
  1028. },
  1029. /**
  1030. * Formats a number using fixed-point notation
  1031. * @param {Number} value The number to format
  1032. * @param {Number} precision The number of digits to show after the decimal point
  1033. */
  1034. toFixed: function(value, precision) {
  1035. if (isToFixedBroken) {
  1036. precision = precision || 0;
  1037. var pow = Math.pow(10, precision);
  1038. return (Math.round(value * pow) / pow).toFixed(precision);
  1039. }
  1040. return value.toFixed(precision);
  1041. },
  1042. /**
  1043. * Validate that a value is numeric and convert it to a number if necessary. Returns the specified default value if
  1044. * it is not.
  1045. Ext.Number.from('1.23', 1); // returns 1.23
  1046. Ext.Number.from('abc', 1); // returns 1
  1047. * @param {Object} value
  1048. * @param {Number} defaultValue The value to return if the original value is non-numeric
  1049. * @return {Number} value, if numeric, defaultValue otherwise
  1050. */
  1051. from: function(value, defaultValue) {
  1052. if (isFinite(value)) {
  1053. value = parseFloat(value);
  1054. }
  1055. return !isNaN(value) ? value : defaultValue;
  1056. }
  1057. };
  1058. })();
  1059. /**
  1060. * @deprecated 4.0.0 Please use {@link Ext.Number#from} instead.
  1061. * @member Ext
  1062. * @method num
  1063. * @alias Ext.Number#from
  1064. */
  1065. Ext.num = function() {
  1066. return Ext.Number.from.apply(this, arguments);
  1067. };
  1068. /**
  1069. * @class Ext.Array
  1070. * @singleton
  1071. * @author Jacky Nguyen <jacky@sencha.com>
  1072. * @docauthor Jacky Nguyen <jacky@sencha.com>
  1073. *
  1074. * A set of useful static methods to deal with arrays; provide missing methods for older browsers.
  1075. */
  1076. (function() {
  1077. var arrayPrototype = Array.prototype,
  1078. slice = arrayPrototype.slice,
  1079. supportsSplice = function () {
  1080. var array = [],
  1081. lengthBefore,
  1082. j = 20;
  1083. if (!array.splice) {
  1084. return false;
  1085. }
  1086. // This detects a bug in IE8 splice method:
  1087. // see http://social.msdn.microsoft.com/Forums/en-US/iewebdevelopment/thread/6e946d03-e09f-4b22-a4dd-cd5e276bf05a/
  1088. while (j--) {
  1089. array.push("A");
  1090. }
  1091. array.splice(15, 0, "F", "F", "F", "F", "F","F","F","F","F","F","F","F","F","F","F","F","F","F","F","F","F");
  1092. lengthBefore = array.length; //41
  1093. array.splice(13, 0, "XXX"); // add one element
  1094. if (lengthBefore+1 != array.length) {
  1095. return false;
  1096. }
  1097. // end IE8 bug
  1098. return true;
  1099. }(),
  1100. supportsForEach = 'forEach' in arrayPrototype,
  1101. supportsMap = 'map' in arrayPrototype,
  1102. supportsIndexOf = 'indexOf' in arrayPrototype,
  1103. supportsEvery = 'every' in arrayPrototype,
  1104. supportsSome = 'some' in arrayPrototype,
  1105. supportsFilter = 'filter' in arrayPrototype,
  1106. supportsSort = function() {
  1107. var a = [1,2,3,4,5].sort(function(){ return 0; });
  1108. return a[0] === 1 && a[1] === 2 && a[2] === 3 && a[3] === 4 && a[4] === 5;
  1109. }(),
  1110. supportsSliceOnNodeList = true,
  1111. ExtArray;
  1112. try {
  1113. // IE 6 - 8 will throw an error when using Array.prototype.slice on NodeList
  1114. if (typeof document !== 'undefined') {
  1115. slice.call(document.getElementsByTagName('body'));
  1116. }
  1117. } catch (e) {
  1118. supportsSliceOnNodeList = false;
  1119. }
  1120. function fixArrayIndex (array, index) {
  1121. return (index < 0) ? Math.max(0, array.length + index)
  1122. : Math.min(array.length, index);
  1123. }
  1124. /*
  1125. Does the same work as splice, but with a slightly more convenient signature. The splice
  1126. method has bugs in IE8, so this is the implementation we use on that platform.
  1127. The rippling of items in the array can be tricky. Consider two use cases:
  1128. index=2
  1129. removeCount=2
  1130. /=====\
  1131. +---+---+---+---+---+---+---+---+
  1132. | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
  1133. +---+---+---+---+---+---+---+---+
  1134. / \/ \/ \/ \
  1135. / /\ /\ /\ \
  1136. / / \/ \/ \ +--------------------------+
  1137. / / /\ /\ +--------------------------+ \
  1138. / / / \/ +--------------------------+ \ \
  1139. / / / /+--------------------------+ \ \ \
  1140. / / / / \ \ \ \
  1141. v v v v v v v v
  1142. +---+---+---+---+---+---+ +---+---+---+---+---+---+---+---+---+
  1143. | 0 | 1 | 4 | 5 | 6 | 7 | | 0 | 1 | a | b | c | 4 | 5 | 6 | 7 |
  1144. +---+---+---+---+---+---+ +---+---+---+---+---+---+---+---+---+
  1145. A B \=========/
  1146. insert=[a,b,c]
  1147. In case A, it is obvious that copying of [4,5,6,7] must be left-to-right so
  1148. that we don't end up with [0,1,6,7,6,7]. In case B, we have the opposite; we
  1149. must go right-to-left or else we would end up with [0,1,a,b,c,4,4,4,4].
  1150. */
  1151. function replaceSim (array, index, removeCount, insert) {
  1152. var add = insert ? insert.length : 0,
  1153. length = array.length,
  1154. pos = fixArrayIndex(array, index);
  1155. // we try to use Array.push when we can for efficiency...
  1156. if (pos === length) {
  1157. if (add) {
  1158. array.push.apply(array, insert);
  1159. }
  1160. } else {
  1161. var remove = Math.min(removeCount, length - pos),
  1162. tailOldPos = pos + remove,
  1163. tailNewPos = tailOldPos + add - remove,
  1164. tailCount = length - tailOldPos,
  1165. lengthAfterRemove = length - remove,
  1166. i;
  1167. if (tailNewPos < tailOldPos) { // case A
  1168. for (i = 0; i < tailCount; ++i) {
  1169. array[tailNewPos+i] = array[tailOldPos+i];
  1170. }
  1171. } else if (tailNewPos > tailOldPos) { // case B
  1172. for (i = tailCount; i--; ) {
  1173. array[tailNewPos+i] = array[tailOldPos+i];
  1174. }
  1175. } // else, add == remove (nothing to do)
  1176. if (add && pos === lengthAfterRemove) {
  1177. array.length = lengthAfterRemove; // truncate array
  1178. array.push.apply(array, insert);
  1179. } else {
  1180. array.length = lengthAfterRemove + add; // reserves space
  1181. for (i = 0; i < add; ++i) {
  1182. array[pos+i] = insert[i];
  1183. }
  1184. }
  1185. }
  1186. return array;
  1187. }
  1188. function replaceNative (array, index, removeCount, insert) {
  1189. if (insert && insert.length) {
  1190. if (index < array.length) {
  1191. array.splice.apply(array, [index, removeCount].concat(insert));
  1192. } else {
  1193. array.push.apply(array, insert);
  1194. }
  1195. } else {
  1196. array.splice(index, removeCount);
  1197. }
  1198. return array;
  1199. }
  1200. function eraseSim (array, index, removeCount) {
  1201. return replaceSim(array, index, removeCount);
  1202. }
  1203. function eraseNative (array, index, removeCount) {
  1204. array.splice(index, removeCount);
  1205. return array;
  1206. }
  1207. function spliceSim (array, index, removeCount) {
  1208. var pos = fixArrayIndex(array, index),
  1209. removed = array.slice(index, fixArrayIndex(array, pos+removeCount));
  1210. if (arguments.length < 4) {
  1211. replaceSim(array, pos, removeCount);
  1212. } else {
  1213. replaceSim(array, pos, removeCount, slice.call(arguments, 3));
  1214. }
  1215. return removed;
  1216. }
  1217. function spliceNative (array) {
  1218. return array.splice.apply(array, slice.call(arguments, 1));
  1219. }
  1220. var erase = supportsSplice ? eraseNative : eraseSim,
  1221. replace = supportsSplice ? replaceNative : replaceSim,
  1222. splice = supportsSplice ? spliceNative : spliceSim;
  1223. // NOTE: from here on, use erase, replace or splice (not native methods)...
  1224. ExtArray = Ext.Array = {
  1225. /**
  1226. * Iterates an array or an iterable value and invoke the given callback function for each item.
  1227. *
  1228. * var countries = ['Vietnam', 'Singapore', 'United States', 'Russia'];
  1229. *
  1230. * Ext.Array.each(countries, function(name, index, countriesItSelf) {
  1231. * console.log(name);
  1232. * });
  1233. *
  1234. * var sum = function() {
  1235. * var sum = 0;
  1236. *
  1237. * Ext.Array.each(arguments, function(value) {
  1238. * sum += value;
  1239. * });
  1240. *
  1241. * return sum;
  1242. * };
  1243. *
  1244. * sum(1, 2, 3); // returns 6
  1245. *
  1246. * The iteration can be stopped by returning false in the function callback.
  1247. *
  1248. * Ext.Array.each(countries, function(name, index, countriesItSelf) {
  1249. * if (name === 'Singapore') {
  1250. * return false; // break here
  1251. * }
  1252. * });
  1253. *
  1254. * {@link Ext#each Ext.each} is alias for {@link Ext.Array#each Ext…