mirror of https://github.com/sipwise/ngcp-csc.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
35981 lines
1.2 MiB
35981 lines
1.2 MiB
/*
|
|
This file is part of Ext JS 6.2.0.981
|
|
|
|
Copyright (c) 2011-2016 Sencha Inc
|
|
|
|
Contact: http://www.sencha.com/contact
|
|
|
|
GNU General Public License Usage
|
|
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.
|
|
|
|
If you are unsure which license is appropriate for your use, please contact the sales department
|
|
at http://www.sencha.com/contact.
|
|
|
|
Version: 6.2.0.981 Build date: 2016-08-31 14:49:44 (08dbbd0ec0b8bc0e014d725fdb7d9650d510b343)
|
|
|
|
*/
|
|
|
|
var Ext = Ext || {};
|
|
(function(manifest){
|
|
if(!Ext.manifest) {
|
|
Ext.manifest = manifest;
|
|
} else {
|
|
for(var name in manifest) {
|
|
Ext.manifest[name] = manifest[name];
|
|
}
|
|
}
|
|
})({
|
|
"paths": {
|
|
"Ext": "../classic/classic/src",
|
|
"Ext.AbstractManager": "../packages/core/src/AbstractManager.js",
|
|
"Ext.Ajax": "../packages/core/src/Ajax.js",
|
|
"Ext.AnimationQueue": "../packages/core/src/AnimationQueue.js",
|
|
"Ext.ComponentManager": "../packages/core/src/ComponentManager.js",
|
|
"Ext.ComponentQuery": "../packages/core/src/ComponentQuery.js",
|
|
"Ext.Deferred": "../packages/core/src/Deferred.js",
|
|
"Ext.Evented": "../packages/core/src/Evented.js",
|
|
"Ext.Factory": "../packages/core/src/mixin/Factoryable.js",
|
|
"Ext.GlobalEvents": "../packages/core/src/GlobalEvents.js",
|
|
"Ext.Glyph": "../packages/core/src/Glyph.js",
|
|
"Ext.JSON": "../packages/core/src/JSON.js",
|
|
"Ext.Mixin": "../packages/core/src/class/Mixin.js",
|
|
"Ext.Msg": "../classic/classic/src/window/MessageBox.js",
|
|
"Ext.Progress": "../packages/core/src/Progress.js",
|
|
"Ext.ProgressBase": "../packages/core/src/ProgressBase.js",
|
|
"Ext.Promise": "../packages/core/src/Promise.js",
|
|
"Ext.String.format": "../packages/core/src/Template.js",
|
|
"Ext.TaskQueue": "../packages/core/src/TaskQueue.js",
|
|
"Ext.Template": "../packages/core/src/Template.js",
|
|
"Ext.Widget": "../packages/core/src/Widget.js",
|
|
"Ext.XTemplate": "../packages/core/src/XTemplate.js",
|
|
"Ext.app": "../packages/core/src/app",
|
|
"Ext.data": "../packages/core/src/data",
|
|
"Ext.direct": "../packages/core/src/direct",
|
|
"Ext.dom": "../packages/core/src/dom",
|
|
"Ext.dom.ButtonElement": "../classic/classic/src/dom/ButtonElement.js",
|
|
"Ext.dom.Layer": "../classic/classic/src/dom/Layer.js",
|
|
"Ext.drag": "../packages/core/src/drag",
|
|
"Ext.event": "../packages/core/src/event",
|
|
"Ext.event.publisher.MouseEnterLeave": "../classic/classic/src/event/publisher/MouseEnterLeave.js",
|
|
"Ext.fx.Animation": "../packages/core/src/fx/Animation.js",
|
|
"Ext.fx.Runner": "../packages/core/src/fx/Runner.js",
|
|
"Ext.fx.State": "../packages/core/src/fx/State.js",
|
|
"Ext.fx.animation": "../packages/core/src/fx/animation",
|
|
"Ext.fx.easing": "../packages/core/src/fx/easing",
|
|
"Ext.fx.layout": "../packages/core/src/fx/layout",
|
|
"Ext.fx.runner": "../packages/core/src/fx/runner",
|
|
"Ext.list": "../packages/core/src/list",
|
|
"Ext.mixin": "../packages/core/src/mixin",
|
|
"Ext.parse": "../packages/core/src/parse",
|
|
"Ext.perf": "../packages/core/src/perf",
|
|
"Ext.plugin.Abstract": "../packages/core/src/plugin/Abstract.js",
|
|
"Ext.plugin.LazyItems": "../packages/core/src/plugin/LazyItems.js",
|
|
"Ext.plugin.MouseEnter": "../packages/core/src/plugin/MousEnter.js",
|
|
"Ext.promise": "../packages/core/src/promise",
|
|
"Ext.scroll.Scroller": "../packages/core/src/scroll/Scroller.js",
|
|
"Ext.sparkline": "../packages/core/src/sparkline",
|
|
"Ext.util": "../packages/core/src/util",
|
|
"Ext.util.Animate": "../classic/classic/src/util/Animate.js",
|
|
"Ext.util.ClickRepeater": "../classic/classic/src/util/ClickRepeater.js",
|
|
"Ext.util.ComponentDragger": "../classic/classic/src/util/ComponentDragger.js",
|
|
"Ext.util.Cookies": "../classic/classic/src/util/Cookies.js",
|
|
"Ext.util.ElementContainer": "../classic/classic/src/util/ElementContainer.js",
|
|
"Ext.util.Floating": "../classic/classic/src/util/Floating.js",
|
|
"Ext.util.Focusable": "../classic/classic/src/util/Focusable.js",
|
|
"Ext.util.FocusableContainer": "../classic/classic/src/util/FocusableContainer.js",
|
|
"Ext.util.Format.format": "../packages/core/src/Template.js",
|
|
"Ext.util.KeyMap": "../classic/classic/src/util/KeyMap.js",
|
|
"Ext.util.KeyNav": "../classic/classic/src/util/KeyNav.js",
|
|
"Ext.util.Memento": "../classic/classic/src/util/Memento.js",
|
|
"Ext.util.ProtoElement": "../classic/classic/src/util/ProtoElement.js",
|
|
"Ext.util.Queue": "../classic/classic/src/util/Queue.js",
|
|
"Ext.util.Renderable": "../classic/classic/src/util/Renderable.js",
|
|
"Ext.util.StoreHolder": "../classic/classic/src/util/StoreHolder.js"
|
|
},
|
|
"loadOrder": [
|
|
{
|
|
"path": "../packages/core/src/class/Mixin.js",
|
|
"requires": [],
|
|
"uses": [],
|
|
"idx": 0
|
|
},
|
|
{
|
|
"path": "../packages/core/src/util/DelayedTask.js",
|
|
"requires": [],
|
|
"uses": [
|
|
76
|
|
],
|
|
"idx": 1
|
|
},
|
|
{
|
|
"path": "../packages/core/src/util/Event.js",
|
|
"requires": [
|
|
1
|
|
],
|
|
"uses": [
|
|
23
|
|
],
|
|
"idx": 2
|
|
},
|
|
{
|
|
"path": "../packages/core/src/mixin/Identifiable.js",
|
|
"requires": [],
|
|
"uses": [],
|
|
"idx": 3
|
|
},
|
|
{
|
|
"path": "../packages/core/src/mixin/Observable.js",
|
|
"requires": [
|
|
0,
|
|
2,
|
|
3
|
|
],
|
|
"uses": [
|
|
51
|
|
],
|
|
"idx": 4
|
|
},
|
|
{
|
|
"path": "../packages/core/src/util/HashMap.js",
|
|
"requires": [
|
|
4
|
|
],
|
|
"uses": [],
|
|
"idx": 5
|
|
},
|
|
{
|
|
"path": "../packages/core/src/AbstractManager.js",
|
|
"requires": [
|
|
5
|
|
],
|
|
"uses": [],
|
|
"idx": 6
|
|
},
|
|
{
|
|
"path": "../packages/core/src/promise/Consequence.js",
|
|
"requires": [],
|
|
"uses": [
|
|
8
|
|
],
|
|
"idx": 7
|
|
},
|
|
{
|
|
"path": "../packages/core/src/promise/Deferred.js",
|
|
"requires": [
|
|
7
|
|
],
|
|
"uses": [
|
|
9
|
|
],
|
|
"idx": 8
|
|
},
|
|
{
|
|
"path": "../packages/core/src/promise/Promise.js",
|
|
"requires": [
|
|
8
|
|
],
|
|
"uses": [],
|
|
"idx": 9
|
|
},
|
|
{
|
|
"path": "../packages/core/src/Promise.js",
|
|
"requires": [
|
|
9
|
|
],
|
|
"uses": [
|
|
8
|
|
],
|
|
"idx": 10
|
|
},
|
|
{
|
|
"path": "../packages/core/src/Deferred.js",
|
|
"requires": [
|
|
8,
|
|
10
|
|
],
|
|
"uses": [
|
|
9
|
|
],
|
|
"idx": 11
|
|
},
|
|
{
|
|
"path": "../packages/core/src/mixin/Factoryable.js",
|
|
"requires": [],
|
|
"uses": [],
|
|
"idx": 12
|
|
},
|
|
{
|
|
"path": "../packages/core/src/data/request/Base.js",
|
|
"requires": [
|
|
11,
|
|
12
|
|
],
|
|
"uses": [
|
|
17
|
|
],
|
|
"idx": 13
|
|
},
|
|
{
|
|
"path": "../packages/core/src/data/flash/BinaryXhr.js",
|
|
"requires": [],
|
|
"uses": [
|
|
76
|
|
],
|
|
"idx": 14
|
|
},
|
|
{
|
|
"path": "../packages/core/src/data/request/Ajax.js",
|
|
"requires": [
|
|
13,
|
|
14
|
|
],
|
|
"uses": [
|
|
76
|
|
],
|
|
"idx": 15
|
|
},
|
|
{
|
|
"path": "../packages/core/src/data/request/Form.js",
|
|
"requires": [
|
|
13
|
|
],
|
|
"uses": [],
|
|
"idx": 16
|
|
},
|
|
{
|
|
"path": "../packages/core/src/data/Connection.js",
|
|
"requires": [
|
|
4,
|
|
11,
|
|
14,
|
|
15,
|
|
16
|
|
],
|
|
"uses": [
|
|
12,
|
|
49
|
|
],
|
|
"idx": 17
|
|
},
|
|
{
|
|
"path": "../packages/core/src/Ajax.js",
|
|
"requires": [
|
|
17
|
|
],
|
|
"uses": [],
|
|
"idx": 18
|
|
},
|
|
{
|
|
"path": "../packages/core/src/AnimationQueue.js",
|
|
"requires": [],
|
|
"uses": [],
|
|
"idx": 19
|
|
},
|
|
{
|
|
"path": "../packages/core/src/ComponentManager.js",
|
|
"requires": [],
|
|
"uses": [
|
|
23,
|
|
49
|
|
],
|
|
"idx": 20
|
|
},
|
|
{
|
|
"path": "../packages/core/src/util/Operators.js",
|
|
"requires": [],
|
|
"uses": [],
|
|
"idx": 21
|
|
},
|
|
{
|
|
"path": "../packages/core/src/util/LruCache.js",
|
|
"requires": [
|
|
5
|
|
],
|
|
"uses": [],
|
|
"idx": 22
|
|
},
|
|
{
|
|
"path": "../packages/core/src/ComponentQuery.js",
|
|
"requires": [
|
|
20,
|
|
21,
|
|
22
|
|
],
|
|
"uses": [
|
|
87
|
|
],
|
|
"idx": 23
|
|
},
|
|
{
|
|
"path": "../packages/core/src/Evented.js",
|
|
"requires": [
|
|
4
|
|
],
|
|
"uses": [],
|
|
"idx": 24
|
|
},
|
|
{
|
|
"path": "../packages/core/src/util/Positionable.js",
|
|
"requires": [],
|
|
"uses": [
|
|
33,
|
|
49
|
|
],
|
|
"idx": 25
|
|
},
|
|
{
|
|
"path": "../packages/core/src/dom/UnderlayPool.js",
|
|
"requires": [],
|
|
"uses": [
|
|
49
|
|
],
|
|
"idx": 26
|
|
},
|
|
{
|
|
"path": "../packages/core/src/dom/Underlay.js",
|
|
"requires": [
|
|
26
|
|
],
|
|
"uses": [],
|
|
"idx": 27
|
|
},
|
|
{
|
|
"path": "../packages/core/src/dom/Shadow.js",
|
|
"requires": [
|
|
27
|
|
],
|
|
"uses": [],
|
|
"idx": 28
|
|
},
|
|
{
|
|
"path": "../packages/core/src/dom/Shim.js",
|
|
"requires": [
|
|
27
|
|
],
|
|
"uses": [],
|
|
"idx": 29
|
|
},
|
|
{
|
|
"path": "../packages/core/src/dom/ElementEvent.js",
|
|
"requires": [
|
|
2
|
|
],
|
|
"uses": [
|
|
36
|
|
],
|
|
"idx": 30
|
|
},
|
|
{
|
|
"path": "../packages/core/src/event/publisher/Publisher.js",
|
|
"requires": [],
|
|
"uses": [],
|
|
"idx": 31
|
|
},
|
|
{
|
|
"path": "../packages/core/src/util/Offset.js",
|
|
"requires": [],
|
|
"uses": [],
|
|
"idx": 32
|
|
},
|
|
{
|
|
"path": "../packages/core/src/util/Region.js",
|
|
"requires": [
|
|
32
|
|
],
|
|
"uses": [],
|
|
"idx": 33
|
|
},
|
|
{
|
|
"path": "../packages/core/src/util/Point.js",
|
|
"requires": [
|
|
33
|
|
],
|
|
"uses": [],
|
|
"idx": 34
|
|
},
|
|
{
|
|
"path": "../packages/core/src/event/Event.js",
|
|
"requires": [
|
|
34
|
|
],
|
|
"uses": [],
|
|
"idx": 35
|
|
},
|
|
{
|
|
"path": "../packages/core/src/event/publisher/Dom.js",
|
|
"requires": [
|
|
31,
|
|
35
|
|
],
|
|
"uses": [
|
|
76
|
|
],
|
|
"idx": 36
|
|
},
|
|
{
|
|
"path": "../packages/core/src/event/publisher/Gesture.js",
|
|
"requires": [
|
|
19,
|
|
34,
|
|
36
|
|
],
|
|
"uses": [
|
|
35,
|
|
49,
|
|
265,
|
|
276,
|
|
277,
|
|
278,
|
|
279,
|
|
280,
|
|
281,
|
|
282,
|
|
283,
|
|
284,
|
|
285,
|
|
286
|
|
],
|
|
"idx": 37
|
|
},
|
|
{
|
|
"path": "../packages/core/src/mixin/Templatable.js",
|
|
"requires": [
|
|
0
|
|
],
|
|
"uses": [
|
|
49
|
|
],
|
|
"idx": 38
|
|
},
|
|
{
|
|
"path": "../packages/core/src/TaskQueue.js",
|
|
"requires": [
|
|
19
|
|
],
|
|
"uses": [],
|
|
"idx": 39
|
|
},
|
|
{
|
|
"path": "../packages/core/src/util/sizemonitor/Abstract.js",
|
|
"requires": [
|
|
38,
|
|
39
|
|
],
|
|
"uses": [],
|
|
"idx": 40
|
|
},
|
|
{
|
|
"path": "../packages/core/src/util/sizemonitor/Scroll.js",
|
|
"requires": [
|
|
40
|
|
],
|
|
"uses": [
|
|
39
|
|
],
|
|
"idx": 41
|
|
},
|
|
{
|
|
"path": "../packages/core/src/util/sizemonitor/OverflowChange.js",
|
|
"requires": [
|
|
40
|
|
],
|
|
"uses": [
|
|
39
|
|
],
|
|
"idx": 42
|
|
},
|
|
{
|
|
"path": "../packages/core/src/util/SizeMonitor.js",
|
|
"requires": [
|
|
41,
|
|
42
|
|
],
|
|
"uses": [],
|
|
"idx": 43
|
|
},
|
|
{
|
|
"path": "../packages/core/src/event/publisher/ElementSize.js",
|
|
"requires": [
|
|
31,
|
|
43
|
|
],
|
|
"uses": [
|
|
39
|
|
],
|
|
"idx": 44
|
|
},
|
|
{
|
|
"path": "../packages/core/src/util/paintmonitor/Abstract.js",
|
|
"requires": [],
|
|
"uses": [
|
|
49
|
|
],
|
|
"idx": 45
|
|
},
|
|
{
|
|
"path": "../packages/core/src/util/paintmonitor/CssAnimation.js",
|
|
"requires": [
|
|
45
|
|
],
|
|
"uses": [],
|
|
"idx": 46
|
|
},
|
|
{
|
|
"path": "../packages/core/src/util/PaintMonitor.js",
|
|
"requires": [
|
|
46
|
|
],
|
|
"uses": [],
|
|
"idx": 47
|
|
},
|
|
{
|
|
"path": "../packages/core/src/event/publisher/ElementPaint.js",
|
|
"requires": [
|
|
31,
|
|
39,
|
|
47
|
|
],
|
|
"uses": [],
|
|
"idx": 48
|
|
},
|
|
{
|
|
"path": "../packages/core/src/dom/Element.js",
|
|
"requires": [
|
|
4,
|
|
25,
|
|
28,
|
|
29,
|
|
30,
|
|
36,
|
|
37,
|
|
44,
|
|
48
|
|
],
|
|
"uses": [
|
|
31,
|
|
33,
|
|
74,
|
|
75,
|
|
76,
|
|
87,
|
|
94,
|
|
233,
|
|
266,
|
|
287,
|
|
297,
|
|
299
|
|
],
|
|
"idx": 49
|
|
},
|
|
{
|
|
"path": "../packages/core/src/util/Filter.js",
|
|
"requires": [],
|
|
"uses": [],
|
|
"idx": 50
|
|
},
|
|
{
|
|
"path": "../packages/core/src/util/Observable.js",
|
|
"requires": [
|
|
4
|
|
],
|
|
"uses": [],
|
|
"idx": 51
|
|
},
|
|
{
|
|
"path": "../packages/core/src/util/AbstractMixedCollection.js",
|
|
"requires": [
|
|
50,
|
|
51
|
|
],
|
|
"uses": [],
|
|
"idx": 52
|
|
},
|
|
{
|
|
"path": "../packages/core/src/util/Sorter.js",
|
|
"requires": [],
|
|
"uses": [],
|
|
"idx": 53
|
|
},
|
|
{
|
|
"path": "../packages/core/src/util/Sortable.js",
|
|
"requires": [
|
|
53
|
|
],
|
|
"uses": [
|
|
55
|
|
],
|
|
"idx": 54
|
|
},
|
|
{
|
|
"path": "../packages/core/src/util/MixedCollection.js",
|
|
"requires": [
|
|
52,
|
|
54
|
|
],
|
|
"uses": [],
|
|
"idx": 55
|
|
},
|
|
{
|
|
"path": "../packages/core/src/util/TaskRunner.js",
|
|
"requires": [],
|
|
"uses": [
|
|
76
|
|
],
|
|
"idx": 56
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/fx/target/Target.js",
|
|
"requires": [],
|
|
"uses": [],
|
|
"idx": 57
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/fx/target/Element.js",
|
|
"requires": [
|
|
57
|
|
],
|
|
"uses": [],
|
|
"idx": 58
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/fx/target/ElementCSS.js",
|
|
"requires": [
|
|
58
|
|
],
|
|
"uses": [],
|
|
"idx": 59
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/fx/target/CompositeElement.js",
|
|
"requires": [
|
|
58
|
|
],
|
|
"uses": [],
|
|
"idx": 60
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/fx/target/CompositeElementCSS.js",
|
|
"requires": [
|
|
59,
|
|
60
|
|
],
|
|
"uses": [],
|
|
"idx": 61
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/fx/target/Sprite.js",
|
|
"requires": [
|
|
57
|
|
],
|
|
"uses": [],
|
|
"idx": 62
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/fx/target/CompositeSprite.js",
|
|
"requires": [
|
|
62
|
|
],
|
|
"uses": [],
|
|
"idx": 63
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/fx/target/Component.js",
|
|
"requires": [
|
|
57
|
|
],
|
|
"uses": [
|
|
76
|
|
],
|
|
"idx": 64
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/fx/Queue.js",
|
|
"requires": [
|
|
5
|
|
],
|
|
"uses": [],
|
|
"idx": 65
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/fx/Manager.js",
|
|
"requires": [
|
|
55,
|
|
56,
|
|
58,
|
|
59,
|
|
60,
|
|
61,
|
|
62,
|
|
63,
|
|
64,
|
|
65
|
|
],
|
|
"uses": [],
|
|
"idx": 66
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/fx/Animator.js",
|
|
"requires": [
|
|
51,
|
|
66
|
|
],
|
|
"uses": [
|
|
72
|
|
],
|
|
"idx": 67
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/fx/CubicBezier.js",
|
|
"requires": [],
|
|
"uses": [],
|
|
"idx": 68
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/fx/Easing.js",
|
|
"requires": [
|
|
68
|
|
],
|
|
"uses": [],
|
|
"idx": 69
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/fx/DrawPath.js",
|
|
"requires": [],
|
|
"uses": [],
|
|
"idx": 70
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/fx/PropertyHandler.js",
|
|
"requires": [
|
|
70
|
|
],
|
|
"uses": [],
|
|
"idx": 71
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/fx/Anim.js",
|
|
"requires": [
|
|
51,
|
|
66,
|
|
67,
|
|
68,
|
|
69,
|
|
71
|
|
],
|
|
"uses": [],
|
|
"idx": 72
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/util/Animate.js",
|
|
"requires": [
|
|
66,
|
|
72
|
|
],
|
|
"uses": [],
|
|
"idx": 73
|
|
},
|
|
{
|
|
"path": "../packages/core/src/dom/Fly.js",
|
|
"requires": [
|
|
49
|
|
],
|
|
"uses": [],
|
|
"idx": 74
|
|
},
|
|
{
|
|
"path": "../packages/core/src/dom/CompositeElementLite.js",
|
|
"requires": [
|
|
74
|
|
],
|
|
"uses": [
|
|
49
|
|
],
|
|
"idx": 75
|
|
},
|
|
{
|
|
"path": "../packages/core/src/GlobalEvents.js",
|
|
"requires": [
|
|
4,
|
|
49
|
|
],
|
|
"uses": [],
|
|
"idx": 76
|
|
},
|
|
{
|
|
"path": "../packages/core/src/Glyph.js",
|
|
"requires": [],
|
|
"uses": [],
|
|
"idx": 77
|
|
},
|
|
{
|
|
"path": "../packages/core/src/JSON.js",
|
|
"requires": [],
|
|
"uses": [],
|
|
"idx": 78
|
|
},
|
|
{
|
|
"path": "../packages/core/src/mixin/Inheritable.js",
|
|
"requires": [
|
|
0
|
|
],
|
|
"uses": [
|
|
20
|
|
],
|
|
"idx": 79
|
|
},
|
|
{
|
|
"path": "../packages/core/src/mixin/Bindable.js",
|
|
"requires": [],
|
|
"uses": [
|
|
12
|
|
],
|
|
"idx": 80
|
|
},
|
|
{
|
|
"path": "../packages/core/src/mixin/ComponentDelegation.js",
|
|
"requires": [
|
|
0,
|
|
4
|
|
],
|
|
"uses": [
|
|
2
|
|
],
|
|
"idx": 81
|
|
},
|
|
{
|
|
"path": "../packages/core/src/mixin/Pluggable.js",
|
|
"requires": [],
|
|
"uses": [],
|
|
"idx": 82
|
|
},
|
|
{
|
|
"path": "../packages/core/src/Widget.js",
|
|
"requires": [
|
|
24,
|
|
49,
|
|
79,
|
|
80,
|
|
81,
|
|
82
|
|
],
|
|
"uses": [
|
|
20,
|
|
23,
|
|
90
|
|
],
|
|
"idx": 83
|
|
},
|
|
{
|
|
"path": "../packages/core/src/ProgressBase.js",
|
|
"requires": [],
|
|
"uses": [
|
|
90
|
|
],
|
|
"idx": 84
|
|
},
|
|
{
|
|
"path": "../packages/core/src/Progress.js",
|
|
"requires": [
|
|
83,
|
|
84
|
|
],
|
|
"uses": [],
|
|
"idx": 85
|
|
},
|
|
{
|
|
"path": "../packages/core/src/util/Format.js",
|
|
"requires": [],
|
|
"uses": [
|
|
87,
|
|
233
|
|
],
|
|
"idx": 86
|
|
},
|
|
{
|
|
"path": "../packages/core/src/Template.js",
|
|
"requires": [
|
|
86
|
|
],
|
|
"uses": [
|
|
233
|
|
],
|
|
"idx": 87
|
|
},
|
|
{
|
|
"path": "../packages/core/src/util/XTemplateParser.js",
|
|
"requires": [],
|
|
"uses": [],
|
|
"idx": 88
|
|
},
|
|
{
|
|
"path": "../packages/core/src/util/XTemplateCompiler.js",
|
|
"requires": [
|
|
88
|
|
],
|
|
"uses": [],
|
|
"idx": 89
|
|
},
|
|
{
|
|
"path": "../packages/core/src/XTemplate.js",
|
|
"requires": [
|
|
87,
|
|
89
|
|
],
|
|
"uses": [],
|
|
"idx": 90
|
|
},
|
|
{
|
|
"path": "../packages/core/src/app/EventDomain.js",
|
|
"requires": [
|
|
2
|
|
],
|
|
"uses": [],
|
|
"idx": 91
|
|
},
|
|
{
|
|
"path": "../packages/core/src/app/domain/Component.js",
|
|
"requires": [
|
|
83,
|
|
91
|
|
],
|
|
"uses": [],
|
|
"idx": 92
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/util/ProtoElement.js",
|
|
"requires": [],
|
|
"uses": [
|
|
49,
|
|
233
|
|
],
|
|
"idx": 93
|
|
},
|
|
{
|
|
"path": "../packages/core/src/dom/CompositeElement.js",
|
|
"requires": [
|
|
75
|
|
],
|
|
"uses": [],
|
|
"idx": 94
|
|
},
|
|
{
|
|
"path": "../packages/core/src/util/CSS.js",
|
|
"requires": [],
|
|
"uses": [
|
|
49
|
|
],
|
|
"idx": 95
|
|
},
|
|
{
|
|
"path": "../packages/core/src/fx/easing/Abstract.js",
|
|
"requires": [],
|
|
"uses": [],
|
|
"idx": 96
|
|
},
|
|
{
|
|
"path": "../packages/core/src/fx/easing/Linear.js",
|
|
"requires": [
|
|
96
|
|
],
|
|
"uses": [],
|
|
"idx": 97
|
|
},
|
|
{
|
|
"path": "../packages/core/src/util/translatable/Abstract.js",
|
|
"requires": [
|
|
24,
|
|
97
|
|
],
|
|
"uses": [
|
|
19
|
|
],
|
|
"idx": 98
|
|
},
|
|
{
|
|
"path": "../packages/core/src/util/translatable/Dom.js",
|
|
"requires": [
|
|
98
|
|
],
|
|
"uses": [],
|
|
"idx": 99
|
|
},
|
|
{
|
|
"path": "../packages/core/src/util/translatable/ScrollPosition.js",
|
|
"requires": [
|
|
99
|
|
],
|
|
"uses": [],
|
|
"idx": 100
|
|
},
|
|
{
|
|
"path": "../packages/core/src/scroll/Scroller.js",
|
|
"requires": [
|
|
12,
|
|
24,
|
|
95,
|
|
100
|
|
],
|
|
"uses": [
|
|
76
|
|
],
|
|
"idx": 101
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/util/Floating.js",
|
|
"requires": [],
|
|
"uses": [
|
|
20,
|
|
49,
|
|
76,
|
|
376
|
|
],
|
|
"idx": 102
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/util/ElementContainer.js",
|
|
"requires": [],
|
|
"uses": [],
|
|
"idx": 103
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/util/Renderable.js",
|
|
"requires": [
|
|
49
|
|
],
|
|
"uses": [
|
|
90,
|
|
111,
|
|
233
|
|
],
|
|
"idx": 104
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/state/Provider.js",
|
|
"requires": [
|
|
51
|
|
],
|
|
"uses": [],
|
|
"idx": 105
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/state/Manager.js",
|
|
"requires": [
|
|
105
|
|
],
|
|
"uses": [],
|
|
"idx": 106
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/state/Stateful.js",
|
|
"requires": [
|
|
56,
|
|
106
|
|
],
|
|
"uses": [],
|
|
"idx": 107
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/util/Focusable.js",
|
|
"requires": [
|
|
1
|
|
],
|
|
"uses": [
|
|
20,
|
|
23,
|
|
35,
|
|
49
|
|
],
|
|
"idx": 108
|
|
},
|
|
{
|
|
"path": "../packages/core/src/mixin/Accessible.js",
|
|
"requires": [
|
|
0
|
|
],
|
|
"uses": [],
|
|
"idx": 109
|
|
},
|
|
{
|
|
"path": "../packages/core/src/mixin/Keyboard.js",
|
|
"requires": [
|
|
0
|
|
],
|
|
"uses": [
|
|
35
|
|
],
|
|
"idx": 110
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/Component.js",
|
|
"requires": [
|
|
20,
|
|
23,
|
|
25,
|
|
51,
|
|
73,
|
|
76,
|
|
79,
|
|
80,
|
|
81,
|
|
93,
|
|
94,
|
|
101,
|
|
102,
|
|
103,
|
|
104,
|
|
107,
|
|
108,
|
|
109,
|
|
110
|
|
],
|
|
"uses": [
|
|
1,
|
|
49,
|
|
66,
|
|
90,
|
|
233,
|
|
371,
|
|
372,
|
|
373,
|
|
376,
|
|
383,
|
|
385,
|
|
455,
|
|
602,
|
|
617,
|
|
621
|
|
],
|
|
"idx": 111
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/layout/container/border/Region.js",
|
|
"requires": [],
|
|
"uses": [],
|
|
"idx": 112
|
|
},
|
|
{
|
|
"path": "../packages/core/src/app/EventBus.js",
|
|
"requires": [
|
|
92
|
|
],
|
|
"uses": [
|
|
91
|
|
],
|
|
"idx": 113
|
|
},
|
|
{
|
|
"path": "../packages/core/src/app/domain/Global.js",
|
|
"requires": [
|
|
76,
|
|
91
|
|
],
|
|
"uses": [],
|
|
"idx": 114
|
|
},
|
|
{
|
|
"path": "../packages/core/src/app/BaseController.js",
|
|
"requires": [
|
|
4,
|
|
113,
|
|
114
|
|
],
|
|
"uses": [
|
|
171,
|
|
172,
|
|
212
|
|
],
|
|
"idx": 115
|
|
},
|
|
{
|
|
"path": "../packages/core/src/app/Util.js",
|
|
"requires": [],
|
|
"uses": [],
|
|
"idx": 116
|
|
},
|
|
{
|
|
"path": "../packages/core/src/util/CollectionKey.js",
|
|
"requires": [
|
|
3
|
|
],
|
|
"uses": [],
|
|
"idx": 117
|
|
},
|
|
{
|
|
"path": "../packages/core/src/util/Grouper.js",
|
|
"requires": [
|
|
53
|
|
],
|
|
"uses": [],
|
|
"idx": 118
|
|
},
|
|
{
|
|
"path": "../packages/core/src/util/Collection.js",
|
|
"requires": [
|
|
4,
|
|
50,
|
|
53,
|
|
117,
|
|
118
|
|
],
|
|
"uses": [
|
|
161,
|
|
162,
|
|
163
|
|
],
|
|
"idx": 119
|
|
},
|
|
{
|
|
"path": "../packages/core/src/util/ObjectTemplate.js",
|
|
"requires": [
|
|
90
|
|
],
|
|
"uses": [],
|
|
"idx": 120
|
|
},
|
|
{
|
|
"path": "../packages/core/src/data/schema/Role.js",
|
|
"requires": [],
|
|
"uses": [
|
|
12
|
|
],
|
|
"idx": 121
|
|
},
|
|
{
|
|
"path": "../packages/core/src/data/schema/Association.js",
|
|
"requires": [
|
|
121
|
|
],
|
|
"uses": [],
|
|
"idx": 122
|
|
},
|
|
{
|
|
"path": "../packages/core/src/data/schema/OneToOne.js",
|
|
"requires": [
|
|
122
|
|
],
|
|
"uses": [],
|
|
"idx": 123
|
|
},
|
|
{
|
|
"path": "../packages/core/src/data/schema/ManyToOne.js",
|
|
"requires": [
|
|
122
|
|
],
|
|
"uses": [],
|
|
"idx": 124
|
|
},
|
|
{
|
|
"path": "../packages/core/src/data/schema/ManyToMany.js",
|
|
"requires": [
|
|
122
|
|
],
|
|
"uses": [],
|
|
"idx": 125
|
|
},
|
|
{
|
|
"path": "../packages/core/src/util/Inflector.js",
|
|
"requires": [],
|
|
"uses": [],
|
|
"idx": 126
|
|
},
|
|
{
|
|
"path": "../packages/core/src/data/schema/Namer.js",
|
|
"requires": [
|
|
12,
|
|
126
|
|
],
|
|
"uses": [],
|
|
"idx": 127
|
|
},
|
|
{
|
|
"path": "../packages/core/src/data/schema/Schema.js",
|
|
"requires": [
|
|
12,
|
|
120,
|
|
123,
|
|
124,
|
|
125,
|
|
127
|
|
],
|
|
"uses": [],
|
|
"idx": 128
|
|
},
|
|
{
|
|
"path": "../packages/core/src/data/AbstractStore.js",
|
|
"requires": [
|
|
4,
|
|
12,
|
|
50,
|
|
119,
|
|
128
|
|
],
|
|
"uses": [
|
|
167
|
|
],
|
|
"idx": 129
|
|
},
|
|
{
|
|
"path": "../packages/core/src/data/Error.js",
|
|
"requires": [],
|
|
"uses": [],
|
|
"idx": 130
|
|
},
|
|
{
|
|
"path": "../packages/core/src/data/ErrorCollection.js",
|
|
"requires": [
|
|
55,
|
|
130
|
|
],
|
|
"uses": [
|
|
139
|
|
],
|
|
"idx": 131
|
|
},
|
|
{
|
|
"path": "../packages/core/src/data/operation/Operation.js",
|
|
"requires": [],
|
|
"uses": [],
|
|
"idx": 132
|
|
},
|
|
{
|
|
"path": "../packages/core/src/data/operation/Create.js",
|
|
"requires": [
|
|
132
|
|
],
|
|
"uses": [],
|
|
"idx": 133
|
|
},
|
|
{
|
|
"path": "../packages/core/src/data/operation/Destroy.js",
|
|
"requires": [
|
|
132
|
|
],
|
|
"uses": [],
|
|
"idx": 134
|
|
},
|
|
{
|
|
"path": "../packages/core/src/data/operation/Read.js",
|
|
"requires": [
|
|
132
|
|
],
|
|
"uses": [],
|
|
"idx": 135
|
|
},
|
|
{
|
|
"path": "../packages/core/src/data/operation/Update.js",
|
|
"requires": [
|
|
132
|
|
],
|
|
"uses": [],
|
|
"idx": 136
|
|
},
|
|
{
|
|
"path": "../packages/core/src/data/SortTypes.js",
|
|
"requires": [],
|
|
"uses": [],
|
|
"idx": 137
|
|
},
|
|
{
|
|
"path": "../packages/core/src/data/validator/Validator.js",
|
|
"requires": [
|
|
12
|
|
],
|
|
"uses": [],
|
|
"idx": 138
|
|
},
|
|
{
|
|
"path": "../packages/core/src/data/field/Field.js",
|
|
"requires": [
|
|
12,
|
|
137,
|
|
138
|
|
],
|
|
"uses": [],
|
|
"idx": 139
|
|
},
|
|
{
|
|
"path": "../packages/core/src/data/field/Boolean.js",
|
|
"requires": [
|
|
139
|
|
],
|
|
"uses": [],
|
|
"idx": 140
|
|
},
|
|
{
|
|
"path": "../packages/core/src/data/field/Date.js",
|
|
"requires": [
|
|
139
|
|
],
|
|
"uses": [],
|
|
"idx": 141
|
|
},
|
|
{
|
|
"path": "../packages/core/src/data/field/Integer.js",
|
|
"requires": [
|
|
139
|
|
],
|
|
"uses": [],
|
|
"idx": 142
|
|
},
|
|
{
|
|
"path": "../packages/core/src/data/field/Number.js",
|
|
"requires": [
|
|
142
|
|
],
|
|
"uses": [],
|
|
"idx": 143
|
|
},
|
|
{
|
|
"path": "../packages/core/src/data/field/String.js",
|
|
"requires": [
|
|
139
|
|
],
|
|
"uses": [],
|
|
"idx": 144
|
|
},
|
|
{
|
|
"path": "../packages/core/src/data/identifier/Generator.js",
|
|
"requires": [
|
|
12
|
|
],
|
|
"uses": [],
|
|
"idx": 145
|
|
},
|
|
{
|
|
"path": "../packages/core/src/data/identifier/Sequential.js",
|
|
"requires": [
|
|
145
|
|
],
|
|
"uses": [],
|
|
"idx": 146
|
|
},
|
|
{
|
|
"path": "../packages/core/src/data/Model.js",
|
|
"requires": [
|
|
128,
|
|
131,
|
|
132,
|
|
133,
|
|
134,
|
|
135,
|
|
136,
|
|
138,
|
|
139,
|
|
140,
|
|
141,
|
|
142,
|
|
143,
|
|
144,
|
|
145,
|
|
146
|
|
],
|
|
"uses": [
|
|
12,
|
|
149,
|
|
232
|
|
],
|
|
"idx": 147
|
|
},
|
|
{
|
|
"path": "../packages/core/src/data/ResultSet.js",
|
|
"requires": [],
|
|
"uses": [],
|
|
"idx": 148
|
|
},
|
|
{
|
|
"path": "../packages/core/src/data/reader/Reader.js",
|
|
"requires": [
|
|
4,
|
|
12,
|
|
22,
|
|
90,
|
|
148
|
|
],
|
|
"uses": [
|
|
128
|
|
],
|
|
"idx": 149
|
|
},
|
|
{
|
|
"path": "../packages/core/src/data/writer/Writer.js",
|
|
"requires": [
|
|
12
|
|
],
|
|
"uses": [],
|
|
"idx": 150
|
|
},
|
|
{
|
|
"path": "../packages/core/src/data/proxy/Proxy.js",
|
|
"requires": [
|
|
4,
|
|
12,
|
|
128,
|
|
149,
|
|
150
|
|
],
|
|
"uses": [
|
|
132,
|
|
133,
|
|
134,
|
|
135,
|
|
136,
|
|
147,
|
|
180
|
|
],
|
|
"idx": 151
|
|
},
|
|
{
|
|
"path": "../packages/core/src/data/proxy/Client.js",
|
|
"requires": [
|
|
151
|
|
],
|
|
"uses": [],
|
|
"idx": 152
|
|
},
|
|
{
|
|
"path": "../packages/core/src/data/proxy/Memory.js",
|
|
"requires": [
|
|
152
|
|
],
|
|
"uses": [
|
|
50,
|
|
54
|
|
],
|
|
"idx": 153
|
|
},
|
|
{
|
|
"path": "../packages/core/src/data/ProxyStore.js",
|
|
"requires": [
|
|
129,
|
|
132,
|
|
133,
|
|
134,
|
|
135,
|
|
136,
|
|
147,
|
|
151,
|
|
153
|
|
],
|
|
"uses": [
|
|
128
|
|
],
|
|
"idx": 154
|
|
},
|
|
{
|
|
"path": "../packages/core/src/data/LocalStore.js",
|
|
"requires": [
|
|
0
|
|
],
|
|
"uses": [
|
|
119
|
|
],
|
|
"idx": 155
|
|
},
|
|
{
|
|
"path": "../packages/core/src/data/proxy/Server.js",
|
|
"requires": [
|
|
151
|
|
],
|
|
"uses": [
|
|
87,
|
|
229
|
|
],
|
|
"idx": 156
|
|
},
|
|
{
|
|
"path": "../packages/core/src/data/proxy/Ajax.js",
|
|
"requires": [
|
|
18,
|
|
156
|
|
],
|
|
"uses": [],
|
|
"idx": 157
|
|
},
|
|
{
|
|
"path": "../packages/core/src/data/reader/Json.js",
|
|
"requires": [
|
|
78,
|
|
149
|
|
],
|
|
"uses": [],
|
|
"idx": 158
|
|
},
|
|
{
|
|
"path": "../packages/core/src/data/writer/Json.js",
|
|
"requires": [
|
|
150
|
|
],
|
|
"uses": [],
|
|
"idx": 159
|
|
},
|
|
{
|
|
"path": "../packages/core/src/util/Group.js",
|
|
"requires": [
|
|
119
|
|
],
|
|
"uses": [],
|
|
"idx": 160
|
|
},
|
|
{
|
|
"path": "../packages/core/src/util/SorterCollection.js",
|
|
"requires": [
|
|
53,
|
|
119
|
|
],
|
|
"uses": [],
|
|
"idx": 161
|
|
},
|
|
{
|
|
"path": "../packages/core/src/util/FilterCollection.js",
|
|
"requires": [
|
|
50,
|
|
119
|
|
],
|
|
"uses": [],
|
|
"idx": 162
|
|
},
|
|
{
|
|
"path": "../packages/core/src/util/GroupCollection.js",
|
|
"requires": [
|
|
119,
|
|
160,
|
|
161,
|
|
162
|
|
],
|
|
"uses": [],
|
|
"idx": 163
|
|
},
|
|
{
|
|
"path": "../packages/core/src/data/Store.js",
|
|
"requires": [
|
|
1,
|
|
147,
|
|
154,
|
|
155,
|
|
157,
|
|
158,
|
|
159,
|
|
163
|
|
],
|
|
"uses": [
|
|
118,
|
|
167,
|
|
217
|
|
],
|
|
"idx": 164
|
|
},
|
|
{
|
|
"path": "../packages/core/src/data/reader/Array.js",
|
|
"requires": [
|
|
158
|
|
],
|
|
"uses": [],
|
|
"idx": 165
|
|
},
|
|
{
|
|
"path": "../packages/core/src/data/ArrayStore.js",
|
|
"requires": [
|
|
153,
|
|
164,
|
|
165
|
|
],
|
|
"uses": [],
|
|
"idx": 166
|
|
},
|
|
{
|
|
"path": "../packages/core/src/data/StoreManager.js",
|
|
"requires": [
|
|
55,
|
|
166
|
|
],
|
|
"uses": [
|
|
12,
|
|
153,
|
|
159,
|
|
164,
|
|
165
|
|
],
|
|
"idx": 167
|
|
},
|
|
{
|
|
"path": "../packages/core/src/app/domain/Store.js",
|
|
"requires": [
|
|
91,
|
|
129
|
|
],
|
|
"uses": [],
|
|
"idx": 168
|
|
},
|
|
{
|
|
"path": "../packages/core/src/app/route/Queue.js",
|
|
"requires": [],
|
|
"uses": [
|
|
55
|
|
],
|
|
"idx": 169
|
|
},
|
|
{
|
|
"path": "../packages/core/src/app/route/Route.js",
|
|
"requires": [],
|
|
"uses": [
|
|
86,
|
|
87
|
|
],
|
|
"idx": 170
|
|
},
|
|
{
|
|
"path": "../packages/core/src/util/History.js",
|
|
"requires": [
|
|
51
|
|
],
|
|
"uses": [
|
|
362
|
|
],
|
|
"idx": 171
|
|
},
|
|
{
|
|
"path": "../packages/core/src/app/route/Router.js",
|
|
"requires": [
|
|
169,
|
|
170,
|
|
171
|
|
],
|
|
"uses": [],
|
|
"idx": 172
|
|
},
|
|
{
|
|
"path": "../packages/core/src/app/Controller.js",
|
|
"requires": [
|
|
20,
|
|
92,
|
|
115,
|
|
116,
|
|
167,
|
|
168,
|
|
172
|
|
],
|
|
"uses": [
|
|
23,
|
|
128
|
|
],
|
|
"idx": 173
|
|
},
|
|
{
|
|
"path": "../packages/core/src/app/Application.js",
|
|
"requires": [
|
|
55,
|
|
171,
|
|
173
|
|
],
|
|
"uses": [
|
|
172
|
|
],
|
|
"idx": 174
|
|
},
|
|
{
|
|
"path": "../packages/core/src/app/Profile.js",
|
|
"requires": [
|
|
4
|
|
],
|
|
"uses": [
|
|
173
|
|
],
|
|
"idx": 175
|
|
},
|
|
{
|
|
"path": "../packages/core/src/app/domain/View.js",
|
|
"requires": [
|
|
83,
|
|
91
|
|
],
|
|
"uses": [],
|
|
"idx": 176
|
|
},
|
|
{
|
|
"path": "../packages/core/src/app/ViewController.js",
|
|
"requires": [
|
|
12,
|
|
115,
|
|
176
|
|
],
|
|
"uses": [],
|
|
"idx": 177
|
|
},
|
|
{
|
|
"path": "../packages/core/src/util/Bag.js",
|
|
"requires": [],
|
|
"uses": [],
|
|
"idx": 178
|
|
},
|
|
{
|
|
"path": "../packages/core/src/util/Scheduler.js",
|
|
"requires": [
|
|
4,
|
|
178
|
|
],
|
|
"uses": [
|
|
76
|
|
],
|
|
"idx": 179
|
|
},
|
|
{
|
|
"path": "../packages/core/src/data/Batch.js",
|
|
"requires": [
|
|
4
|
|
],
|
|
"uses": [],
|
|
"idx": 180
|
|
},
|
|
{
|
|
"path": "../packages/core/src/data/matrix/Slice.js",
|
|
"requires": [],
|
|
"uses": [],
|
|
"idx": 181
|
|
},
|
|
{
|
|
"path": "../packages/core/src/data/matrix/Side.js",
|
|
"requires": [
|
|
181
|
|
],
|
|
"uses": [],
|
|
"idx": 182
|
|
},
|
|
{
|
|
"path": "../packages/core/src/data/matrix/Matrix.js",
|
|
"requires": [
|
|
182
|
|
],
|
|
"uses": [],
|
|
"idx": 183
|
|
},
|
|
{
|
|
"path": "../packages/core/src/data/session/ChangesVisitor.js",
|
|
"requires": [],
|
|
"uses": [],
|
|
"idx": 184
|
|
},
|
|
{
|
|
"path": "../packages/core/src/data/session/ChildChangesVisitor.js",
|
|
"requires": [
|
|
184
|
|
],
|
|
"uses": [],
|
|
"idx": 185
|
|
},
|
|
{
|
|
"path": "../packages/core/src/data/session/BatchVisitor.js",
|
|
"requires": [],
|
|
"uses": [
|
|
180
|
|
],
|
|
"idx": 186
|
|
},
|
|
{
|
|
"path": "../packages/core/src/mixin/Dirty.js",
|
|
"requires": [],
|
|
"uses": [],
|
|
"idx": 187
|
|
},
|
|
{
|
|
"path": "../packages/core/src/data/Session.js",
|
|
"requires": [
|
|
4,
|
|
128,
|
|
180,
|
|
183,
|
|
184,
|
|
185,
|
|
186,
|
|
187
|
|
],
|
|
"uses": [],
|
|
"idx": 188
|
|
},
|
|
{
|
|
"path": "../packages/core/src/util/Schedulable.js",
|
|
"requires": [],
|
|
"uses": [],
|
|
"idx": 189
|
|
},
|
|
{
|
|
"path": "../packages/core/src/app/bind/BaseBinding.js",
|
|
"requires": [
|
|
189
|
|
],
|
|
"uses": [],
|
|
"idx": 190
|
|
},
|
|
{
|
|
"path": "../packages/core/src/app/bind/Binding.js",
|
|
"requires": [
|
|
190
|
|
],
|
|
"uses": [],
|
|
"idx": 191
|
|
},
|
|
{
|
|
"path": "../packages/core/src/app/bind/AbstractStub.js",
|
|
"requires": [
|
|
189,
|
|
191
|
|
],
|
|
"uses": [],
|
|
"idx": 192
|
|
},
|
|
{
|
|
"path": "../packages/core/src/app/bind/Stub.js",
|
|
"requires": [
|
|
191,
|
|
192
|
|
],
|
|
"uses": [
|
|
197
|
|
],
|
|
"idx": 193
|
|
},
|
|
{
|
|
"path": "../packages/core/src/app/bind/LinkStub.js",
|
|
"requires": [
|
|
193
|
|
],
|
|
"uses": [],
|
|
"idx": 194
|
|
},
|
|
{
|
|
"path": "../packages/core/src/app/bind/RootStub.js",
|
|
"requires": [
|
|
192,
|
|
193,
|
|
194
|
|
],
|
|
"uses": [],
|
|
"idx": 195
|
|
},
|
|
{
|
|
"path": "../packages/core/src/app/bind/Multi.js",
|
|
"requires": [
|
|
190
|
|
],
|
|
"uses": [],
|
|
"idx": 196
|
|
},
|
|
{
|
|
"path": "../packages/core/src/app/bind/Formula.js",
|
|
"requires": [
|
|
22,
|
|
189
|
|
],
|
|
"uses": [],
|
|
"idx": 197
|
|
},
|
|
{
|
|
"path": "../packages/core/src/util/Fly.js",
|
|
"requires": [],
|
|
"uses": [],
|
|
"idx": 198
|
|
},
|
|
{
|
|
"path": "../packages/core/src/parse/Tokenizer.js",
|
|
"requires": [
|
|
198
|
|
],
|
|
"uses": [],
|
|
"idx": 199
|
|
},
|
|
{
|
|
"path": "../packages/core/src/parse/Symbol.js",
|
|
"requires": [],
|
|
"uses": [],
|
|
"idx": 200
|
|
},
|
|
{
|
|
"path": "../packages/core/src/parse/symbol/Constant.js",
|
|
"requires": [
|
|
200
|
|
],
|
|
"uses": [],
|
|
"idx": 201
|
|
},
|
|
{
|
|
"path": "../packages/core/src/parse/symbol/Infix.js",
|
|
"requires": [
|
|
200
|
|
],
|
|
"uses": [],
|
|
"idx": 202
|
|
},
|
|
{
|
|
"path": "../packages/core/src/parse/symbol/InfixRight.js",
|
|
"requires": [
|
|
202
|
|
],
|
|
"uses": [],
|
|
"idx": 203
|
|
},
|
|
{
|
|
"path": "../packages/core/src/parse/symbol/Paren.js",
|
|
"requires": [
|
|
200
|
|
],
|
|
"uses": [],
|
|
"idx": 204
|
|
},
|
|
{
|
|
"path": "../packages/core/src/parse/symbol/Prefix.js",
|
|
"requires": [
|
|
200
|
|
],
|
|
"uses": [],
|
|
"idx": 205
|
|
},
|
|
{
|
|
"path": "../packages/core/src/parse/Parser.js",
|
|
"requires": [
|
|
198,
|
|
199,
|
|
201,
|
|
203,
|
|
204,
|
|
205
|
|
],
|
|
"uses": [
|
|
200,
|
|
202
|
|
],
|
|
"idx": 206
|
|
},
|
|
{
|
|
"path": "../packages/core/src/app/bind/Parser.js",
|
|
"requires": [
|
|
86,
|
|
206
|
|
],
|
|
"uses": [],
|
|
"idx": 207
|
|
},
|
|
{
|
|
"path": "../packages/core/src/app/bind/Template.js",
|
|
"requires": [
|
|
86,
|
|
207
|
|
],
|
|
"uses": [],
|
|
"idx": 208
|
|
},
|
|
{
|
|
"path": "../packages/core/src/app/bind/TemplateBinding.js",
|
|
"requires": [
|
|
190,
|
|
196,
|
|
208
|
|
],
|
|
"uses": [],
|
|
"idx": 209
|
|
},
|
|
{
|
|
"path": "../packages/core/src/data/ChainedStore.js",
|
|
"requires": [
|
|
129,
|
|
155
|
|
],
|
|
"uses": [
|
|
87,
|
|
167
|
|
],
|
|
"idx": 210
|
|
},
|
|
{
|
|
"path": "../packages/core/src/app/ViewModel.js",
|
|
"requires": [
|
|
3,
|
|
12,
|
|
179,
|
|
188,
|
|
194,
|
|
195,
|
|
196,
|
|
197,
|
|
209,
|
|
210
|
|
],
|
|
"uses": [
|
|
1,
|
|
128
|
|
],
|
|
"idx": 211
|
|
},
|
|
{
|
|
"path": "../packages/core/src/app/domain/Controller.js",
|
|
"requires": [
|
|
91,
|
|
173
|
|
],
|
|
"uses": [
|
|
115
|
|
],
|
|
"idx": 212
|
|
},
|
|
{
|
|
"path": "../packages/core/src/direct/Manager.js",
|
|
"requires": [
|
|
4,
|
|
55
|
|
],
|
|
"uses": [
|
|
87
|
|
],
|
|
"idx": 213
|
|
},
|
|
{
|
|
"path": "../packages/core/src/direct/Provider.js",
|
|
"requires": [
|
|
4,
|
|
213
|
|
],
|
|
"uses": [
|
|
18
|
|
],
|
|
"idx": 214
|
|
},
|
|
{
|
|
"path": "../packages/core/src/app/domain/Direct.js",
|
|
"requires": [
|
|
91,
|
|
214
|
|
],
|
|
"uses": [],
|
|
"idx": 215
|
|
},
|
|
{
|
|
"path": "../packages/core/src/data/PageMap.js",
|
|
"requires": [
|
|
22
|
|
],
|
|
"uses": [],
|
|
"idx": 216
|
|
},
|
|
{
|
|
"path": "../packages/core/src/data/BufferedStore.js",
|
|
"requires": [
|
|
50,
|
|
53,
|
|
118,
|
|
154,
|
|
216
|
|
],
|
|
"uses": [
|
|
161,
|
|
162,
|
|
163
|
|
],
|
|
"idx": 217
|
|
},
|
|
{
|
|
"path": "../packages/core/src/data/proxy/Direct.js",
|
|
"requires": [
|
|
156,
|
|
213
|
|
],
|
|
"uses": [],
|
|
"idx": 218
|
|
},
|
|
{
|
|
"path": "../packages/core/src/data/DirectStore.js",
|
|
"requires": [
|
|
164,
|
|
218
|
|
],
|
|
"uses": [],
|
|
"idx": 219
|
|
},
|
|
{
|
|
"path": "../packages/core/src/data/JsonP.js",
|
|
"requires": [],
|
|
"uses": [
|
|
76
|
|
],
|
|
"idx": 220
|
|
},
|
|
{
|
|
"path": "../packages/core/src/data/proxy/JsonP.js",
|
|
"requires": [
|
|
156,
|
|
220
|
|
],
|
|
"uses": [],
|
|
"idx": 221
|
|
},
|
|
{
|
|
"path": "../packages/core/src/data/JsonPStore.js",
|
|
"requires": [
|
|
158,
|
|
164,
|
|
221
|
|
],
|
|
"uses": [],
|
|
"idx": 222
|
|
},
|
|
{
|
|
"path": "../packages/core/src/data/JsonStore.js",
|
|
"requires": [
|
|
157,
|
|
158,
|
|
159,
|
|
164
|
|
],
|
|
"uses": [],
|
|
"idx": 223
|
|
},
|
|
{
|
|
"path": "../packages/core/src/data/ModelManager.js",
|
|
"requires": [
|
|
128
|
|
],
|
|
"uses": [
|
|
147
|
|
],
|
|
"idx": 224
|
|
},
|
|
{
|
|
"path": "../packages/core/src/data/NodeInterface.js",
|
|
"requires": [
|
|
4,
|
|
140,
|
|
142,
|
|
144,
|
|
159
|
|
],
|
|
"uses": [
|
|
128
|
|
],
|
|
"idx": 225
|
|
},
|
|
{
|
|
"path": "../packages/core/src/mixin/Queryable.js",
|
|
"requires": [],
|
|
"uses": [
|
|
23
|
|
],
|
|
"idx": 226
|
|
},
|
|
{
|
|
"path": "../packages/core/src/data/TreeModel.js",
|
|
"requires": [
|
|
147,
|
|
225,
|
|
226
|
|
],
|
|
"uses": [],
|
|
"idx": 227
|
|
},
|
|
{
|
|
"path": "../packages/core/src/data/NodeStore.js",
|
|
"requires": [
|
|
164,
|
|
225,
|
|
227
|
|
],
|
|
"uses": [
|
|
147
|
|
],
|
|
"idx": 228
|
|
},
|
|
{
|
|
"path": "../packages/core/src/data/Request.js",
|
|
"requires": [],
|
|
"uses": [],
|
|
"idx": 229
|
|
},
|
|
{
|
|
"path": "../packages/core/src/data/TreeStore.js",
|
|
"requires": [
|
|
53,
|
|
164,
|
|
225,
|
|
227
|
|
],
|
|
"uses": [
|
|
147
|
|
],
|
|
"idx": 230
|
|
},
|
|
{
|
|
"path": "../packages/core/src/data/Types.js",
|
|
"requires": [
|
|
137
|
|
],
|
|
"uses": [],
|
|
"idx": 231
|
|
},
|
|
{
|
|
"path": "../packages/core/src/data/Validation.js",
|
|
"requires": [
|
|
147
|
|
],
|
|
"uses": [],
|
|
"idx": 232
|
|
},
|
|
{
|
|
"path": "../packages/core/src/dom/Helper.js",
|
|
"requires": [],
|
|
"uses": [
|
|
87
|
|
],
|
|
"idx": 233
|
|
},
|
|
{
|
|
"path": "../packages/core/src/dom/Query.js",
|
|
"requires": [
|
|
21,
|
|
233
|
|
],
|
|
"uses": [
|
|
22
|
|
],
|
|
"idx": 234
|
|
},
|
|
{
|
|
"path": "../packages/core/src/data/reader/Xml.js",
|
|
"requires": [
|
|
149,
|
|
234
|
|
],
|
|
"uses": [],
|
|
"idx": 235
|
|
},
|
|
{
|
|
"path": "../packages/core/src/data/writer/Xml.js",
|
|
"requires": [
|
|
150
|
|
],
|
|
"uses": [],
|
|
"idx": 236
|
|
},
|
|
{
|
|
"path": "../packages/core/src/data/XmlStore.js",
|
|
"requires": [
|
|
157,
|
|
164,
|
|
235,
|
|
236
|
|
],
|
|
"uses": [],
|
|
"idx": 237
|
|
},
|
|
{
|
|
"path": "../packages/core/src/data/identifier/Negative.js",
|
|
"requires": [
|
|
146
|
|
],
|
|
"uses": [],
|
|
"idx": 238
|
|
},
|
|
{
|
|
"path": "../packages/core/src/data/identifier/Uuid.js",
|
|
"requires": [
|
|
145
|
|
],
|
|
"uses": [],
|
|
"idx": 239
|
|
},
|
|
{
|
|
"path": "../packages/core/src/data/proxy/WebStorage.js",
|
|
"requires": [
|
|
146,
|
|
152
|
|
],
|
|
"uses": [
|
|
53,
|
|
87,
|
|
148
|
|
],
|
|
"idx": 240
|
|
},
|
|
{
|
|
"path": "../packages/core/src/data/proxy/LocalStorage.js",
|
|
"requires": [
|
|
240
|
|
],
|
|
"uses": [],
|
|
"idx": 241
|
|
},
|
|
{
|
|
"path": "../packages/core/src/data/proxy/Rest.js",
|
|
"requires": [
|
|
157
|
|
],
|
|
"uses": [],
|
|
"idx": 242
|
|
},
|
|
{
|
|
"path": "../packages/core/src/data/proxy/SessionStorage.js",
|
|
"requires": [
|
|
240
|
|
],
|
|
"uses": [],
|
|
"idx": 243
|
|
},
|
|
{
|
|
"path": "../packages/core/src/data/schema/BelongsTo.js",
|
|
"requires": [],
|
|
"uses": [],
|
|
"idx": 244
|
|
},
|
|
{
|
|
"path": "../packages/core/src/data/schema/HasMany.js",
|
|
"requires": [],
|
|
"uses": [],
|
|
"idx": 245
|
|
},
|
|
{
|
|
"path": "../packages/core/src/data/schema/HasOne.js",
|
|
"requires": [],
|
|
"uses": [],
|
|
"idx": 246
|
|
},
|
|
{
|
|
"path": "../packages/core/src/data/schema/Reference.js",
|
|
"requires": [],
|
|
"uses": [],
|
|
"idx": 247
|
|
},
|
|
{
|
|
"path": "../packages/core/src/data/validator/Bound.js",
|
|
"requires": [
|
|
138
|
|
],
|
|
"uses": [
|
|
87
|
|
],
|
|
"idx": 248
|
|
},
|
|
{
|
|
"path": "../packages/core/src/data/validator/Format.js",
|
|
"requires": [
|
|
138
|
|
],
|
|
"uses": [],
|
|
"idx": 249
|
|
},
|
|
{
|
|
"path": "../packages/core/src/data/validator/Email.js",
|
|
"requires": [
|
|
249
|
|
],
|
|
"uses": [],
|
|
"idx": 250
|
|
},
|
|
{
|
|
"path": "../packages/core/src/data/validator/List.js",
|
|
"requires": [
|
|
138
|
|
],
|
|
"uses": [],
|
|
"idx": 251
|
|
},
|
|
{
|
|
"path": "../packages/core/src/data/validator/Exclusion.js",
|
|
"requires": [
|
|
251
|
|
],
|
|
"uses": [],
|
|
"idx": 252
|
|
},
|
|
{
|
|
"path": "../packages/core/src/data/validator/Inclusion.js",
|
|
"requires": [
|
|
251
|
|
],
|
|
"uses": [],
|
|
"idx": 253
|
|
},
|
|
{
|
|
"path": "../packages/core/src/data/validator/Length.js",
|
|
"requires": [
|
|
248
|
|
],
|
|
"uses": [],
|
|
"idx": 254
|
|
},
|
|
{
|
|
"path": "../packages/core/src/data/validator/Presence.js",
|
|
"requires": [
|
|
138
|
|
],
|
|
"uses": [],
|
|
"idx": 255
|
|
},
|
|
{
|
|
"path": "../packages/core/src/data/validator/Range.js",
|
|
"requires": [
|
|
248
|
|
],
|
|
"uses": [],
|
|
"idx": 256
|
|
},
|
|
{
|
|
"path": "../packages/core/src/direct/Event.js",
|
|
"requires": [],
|
|
"uses": [],
|
|
"idx": 257
|
|
},
|
|
{
|
|
"path": "../packages/core/src/direct/RemotingEvent.js",
|
|
"requires": [
|
|
257
|
|
],
|
|
"uses": [
|
|
213
|
|
],
|
|
"idx": 258
|
|
},
|
|
{
|
|
"path": "../packages/core/src/direct/ExceptionEvent.js",
|
|
"requires": [
|
|
258
|
|
],
|
|
"uses": [],
|
|
"idx": 259
|
|
},
|
|
{
|
|
"path": "../packages/core/src/direct/JsonProvider.js",
|
|
"requires": [
|
|
214
|
|
],
|
|
"uses": [
|
|
213,
|
|
259
|
|
],
|
|
"idx": 260
|
|
},
|
|
{
|
|
"path": "../packages/core/src/direct/PollingProvider.js",
|
|
"requires": [
|
|
18,
|
|
56,
|
|
259,
|
|
260
|
|
],
|
|
"uses": [
|
|
213,
|
|
362
|
|
],
|
|
"idx": 261
|
|
},
|
|
{
|
|
"path": "../packages/core/src/direct/RemotingMethod.js",
|
|
"requires": [],
|
|
"uses": [],
|
|
"idx": 262
|
|
},
|
|
{
|
|
"path": "../packages/core/src/direct/Transaction.js",
|
|
"requires": [],
|
|
"uses": [],
|
|
"idx": 263
|
|
},
|
|
{
|
|
"path": "../packages/core/src/direct/RemotingProvider.js",
|
|
"requires": [
|
|
1,
|
|
55,
|
|
213,
|
|
260,
|
|
262,
|
|
263
|
|
],
|
|
"uses": [
|
|
78,
|
|
259
|
|
],
|
|
"idx": 264
|
|
},
|
|
{
|
|
"path": "../packages/core/src/dom/GarbageCollector.js",
|
|
"requires": [],
|
|
"uses": [
|
|
49
|
|
],
|
|
"idx": 265
|
|
},
|
|
{
|
|
"path": "../packages/core/src/dom/TouchAction.js",
|
|
"requires": [
|
|
34,
|
|
49
|
|
],
|
|
"uses": [],
|
|
"idx": 266
|
|
},
|
|
{
|
|
"path": "../packages/core/src/drag/Constraint.js",
|
|
"requires": [
|
|
12
|
|
],
|
|
"uses": [],
|
|
"idx": 267
|
|
},
|
|
{
|
|
"path": "../packages/core/src/drag/Info.js",
|
|
"requires": [
|
|
10
|
|
],
|
|
"uses": [],
|
|
"idx": 268
|
|
},
|
|
{
|
|
"path": "../packages/core/src/drag/Item.js",
|
|
"requires": [
|
|
3,
|
|
4
|
|
],
|
|
"uses": [],
|
|
"idx": 269
|
|
},
|
|
{
|
|
"path": "../packages/core/src/drag/Manager.js",
|
|
"requires": [],
|
|
"uses": [
|
|
49,
|
|
268
|
|
],
|
|
"idx": 270
|
|
},
|
|
{
|
|
"path": "../packages/core/src/drag/Source.js",
|
|
"requires": [
|
|
76,
|
|
267,
|
|
269
|
|
],
|
|
"uses": [
|
|
12,
|
|
268
|
|
],
|
|
"idx": 271
|
|
},
|
|
{
|
|
"path": "../packages/core/src/drag/Target.js",
|
|
"requires": [
|
|
269,
|
|
270
|
|
],
|
|
"uses": [],
|
|
"idx": 272
|
|
},
|
|
{
|
|
"path": "../packages/core/src/drag/proxy/None.js",
|
|
"requires": [
|
|
12
|
|
],
|
|
"uses": [],
|
|
"idx": 273
|
|
},
|
|
{
|
|
"path": "../packages/core/src/drag/proxy/Original.js",
|
|
"requires": [
|
|
273
|
|
],
|
|
"uses": [],
|
|
"idx": 274
|
|
},
|
|
{
|
|
"path": "../packages/core/src/drag/proxy/Placeholder.js",
|
|
"requires": [
|
|
273
|
|
],
|
|
"uses": [],
|
|
"idx": 275
|
|
},
|
|
{
|
|
"path": "../packages/core/src/event/gesture/Recognizer.js",
|
|
"requires": [
|
|
3,
|
|
37
|
|
],
|
|
"uses": [],
|
|
"idx": 276
|
|
},
|
|
{
|
|
"path": "../packages/core/src/event/gesture/SingleTouch.js",
|
|
"requires": [
|
|
276
|
|
],
|
|
"uses": [],
|
|
"idx": 277
|
|
},
|
|
{
|
|
"path": "../packages/core/src/event/gesture/DoubleTap.js",
|
|
"requires": [
|
|
277
|
|
],
|
|
"uses": [
|
|
49
|
|
],
|
|
"idx": 278
|
|
},
|
|
{
|
|
"path": "../packages/core/src/event/gesture/Drag.js",
|
|
"requires": [
|
|
277
|
|
],
|
|
"uses": [
|
|
49
|
|
],
|
|
"idx": 279
|
|
},
|
|
{
|
|
"path": "../packages/core/src/event/gesture/Swipe.js",
|
|
"requires": [
|
|
277
|
|
],
|
|
"uses": [],
|
|
"idx": 280
|
|
},
|
|
{
|
|
"path": "../packages/core/src/event/gesture/EdgeSwipe.js",
|
|
"requires": [
|
|
280
|
|
],
|
|
"uses": [
|
|
49
|
|
],
|
|
"idx": 281
|
|
},
|
|
{
|
|
"path": "../packages/core/src/event/gesture/LongPress.js",
|
|
"requires": [
|
|
277
|
|
],
|
|
"uses": [
|
|
37,
|
|
49,
|
|
279
|
|
],
|
|
"idx": 282
|
|
},
|
|
{
|
|
"path": "../packages/core/src/event/gesture/MultiTouch.js",
|
|
"requires": [
|
|
276
|
|
],
|
|
"uses": [],
|
|
"idx": 283
|
|
},
|
|
{
|
|
"path": "../packages/core/src/event/gesture/Pinch.js",
|
|
"requires": [
|
|
283
|
|
],
|
|
"uses": [],
|
|
"idx": 284
|
|
},
|
|
{
|
|
"path": "../packages/core/src/event/gesture/Rotate.js",
|
|
"requires": [
|
|
283
|
|
],
|
|
"uses": [],
|
|
"idx": 285
|
|
},
|
|
{
|
|
"path": "../packages/core/src/event/gesture/Tap.js",
|
|
"requires": [
|
|
277
|
|
],
|
|
"uses": [
|
|
49
|
|
],
|
|
"idx": 286
|
|
},
|
|
{
|
|
"path": "../packages/core/src/event/publisher/Focus.js",
|
|
"requires": [
|
|
36,
|
|
49,
|
|
76
|
|
],
|
|
"uses": [
|
|
35
|
|
],
|
|
"idx": 287
|
|
},
|
|
{
|
|
"path": "../packages/core/src/fx/State.js",
|
|
"requires": [],
|
|
"uses": [],
|
|
"idx": 288
|
|
},
|
|
{
|
|
"path": "../packages/core/src/fx/animation/Abstract.js",
|
|
"requires": [
|
|
24,
|
|
288
|
|
],
|
|
"uses": [],
|
|
"idx": 289
|
|
},
|
|
{
|
|
"path": "../packages/core/src/fx/animation/Slide.js",
|
|
"requires": [
|
|
289
|
|
],
|
|
"uses": [],
|
|
"idx": 290
|
|
},
|
|
{
|
|
"path": "../packages/core/src/fx/animation/SlideOut.js",
|
|
"requires": [
|
|
290
|
|
],
|
|
"uses": [],
|
|
"idx": 291
|
|
},
|
|
{
|
|
"path": "../packages/core/src/fx/animation/Fade.js",
|
|
"requires": [
|
|
289
|
|
],
|
|
"uses": [],
|
|
"idx": 292
|
|
},
|
|
{
|
|
"path": "../packages/core/src/fx/animation/FadeOut.js",
|
|
"requires": [
|
|
292
|
|
],
|
|
"uses": [],
|
|
"idx": 293
|
|
},
|
|
{
|
|
"path": "../packages/core/src/fx/animation/Flip.js",
|
|
"requires": [
|
|
289
|
|
],
|
|
"uses": [],
|
|
"idx": 294
|
|
},
|
|
{
|
|
"path": "../packages/core/src/fx/animation/Pop.js",
|
|
"requires": [
|
|
289
|
|
],
|
|
"uses": [],
|
|
"idx": 295
|
|
},
|
|
{
|
|
"path": "../packages/core/src/fx/animation/PopOut.js",
|
|
"requires": [
|
|
295
|
|
],
|
|
"uses": [],
|
|
"idx": 296
|
|
},
|
|
{
|
|
"path": "../packages/core/src/fx/Animation.js",
|
|
"requires": [
|
|
290,
|
|
291,
|
|
292,
|
|
293,
|
|
294,
|
|
295,
|
|
296
|
|
],
|
|
"uses": [
|
|
289
|
|
],
|
|
"idx": 297
|
|
},
|
|
{
|
|
"path": "../packages/core/src/fx/runner/Css.js",
|
|
"requires": [
|
|
24,
|
|
297
|
|
],
|
|
"uses": [],
|
|
"idx": 298
|
|
},
|
|
{
|
|
"path": "../packages/core/src/fx/runner/CssTransition.js",
|
|
"requires": [
|
|
19,
|
|
298
|
|
],
|
|
"uses": [
|
|
297
|
|
],
|
|
"idx": 299
|
|
},
|
|
{
|
|
"path": "../packages/core/src/fx/Runner.js",
|
|
"requires": [
|
|
299
|
|
],
|
|
"uses": [],
|
|
"idx": 300
|
|
},
|
|
{
|
|
"path": "../packages/core/src/fx/animation/Cube.js",
|
|
"requires": [
|
|
289
|
|
],
|
|
"uses": [],
|
|
"idx": 301
|
|
},
|
|
{
|
|
"path": "../packages/core/src/fx/animation/Wipe.js",
|
|
"requires": [
|
|
297
|
|
],
|
|
"uses": [],
|
|
"idx": 302
|
|
},
|
|
{
|
|
"path": "../packages/core/src/fx/animation/WipeOut.js",
|
|
"requires": [
|
|
302
|
|
],
|
|
"uses": [],
|
|
"idx": 303
|
|
},
|
|
{
|
|
"path": "../packages/core/src/fx/easing/Bounce.js",
|
|
"requires": [
|
|
96
|
|
],
|
|
"uses": [],
|
|
"idx": 304
|
|
},
|
|
{
|
|
"path": "../packages/core/src/fx/easing/Momentum.js",
|
|
"requires": [
|
|
96
|
|
],
|
|
"uses": [],
|
|
"idx": 305
|
|
},
|
|
{
|
|
"path": "../packages/core/src/fx/easing/BoundMomentum.js",
|
|
"requires": [
|
|
96,
|
|
304,
|
|
305
|
|
],
|
|
"uses": [],
|
|
"idx": 306
|
|
},
|
|
{
|
|
"path": "../packages/core/src/fx/easing/EaseIn.js",
|
|
"requires": [
|
|
97
|
|
],
|
|
"uses": [],
|
|
"idx": 307
|
|
},
|
|
{
|
|
"path": "../packages/core/src/fx/easing/EaseOut.js",
|
|
"requires": [
|
|
97
|
|
],
|
|
"uses": [],
|
|
"idx": 308
|
|
},
|
|
{
|
|
"path": "../packages/core/src/fx/easing/Easing.js",
|
|
"requires": [
|
|
97
|
|
],
|
|
"uses": [],
|
|
"idx": 309
|
|
},
|
|
{
|
|
"path": "../packages/core/src/fx/layout/card/Abstract.js",
|
|
"requires": [
|
|
24
|
|
],
|
|
"uses": [],
|
|
"idx": 310
|
|
},
|
|
{
|
|
"path": "../packages/core/src/fx/layout/card/Style.js",
|
|
"requires": [
|
|
297,
|
|
310
|
|
],
|
|
"uses": [
|
|
299
|
|
],
|
|
"idx": 311
|
|
},
|
|
{
|
|
"path": "../packages/core/src/fx/layout/card/Slide.js",
|
|
"requires": [
|
|
311
|
|
],
|
|
"uses": [],
|
|
"idx": 312
|
|
},
|
|
{
|
|
"path": "../packages/core/src/fx/layout/card/Cover.js",
|
|
"requires": [
|
|
311
|
|
],
|
|
"uses": [],
|
|
"idx": 313
|
|
},
|
|
{
|
|
"path": "../packages/core/src/fx/layout/card/Reveal.js",
|
|
"requires": [
|
|
311
|
|
],
|
|
"uses": [],
|
|
"idx": 314
|
|
},
|
|
{
|
|
"path": "../packages/core/src/fx/layout/card/Fade.js",
|
|
"requires": [
|
|
311
|
|
],
|
|
"uses": [],
|
|
"idx": 315
|
|
},
|
|
{
|
|
"path": "../packages/core/src/fx/layout/card/Flip.js",
|
|
"requires": [
|
|
311
|
|
],
|
|
"uses": [],
|
|
"idx": 316
|
|
},
|
|
{
|
|
"path": "../packages/core/src/fx/layout/card/Pop.js",
|
|
"requires": [
|
|
311
|
|
],
|
|
"uses": [],
|
|
"idx": 317
|
|
},
|
|
{
|
|
"path": "../packages/core/src/fx/layout/card/Scroll.js",
|
|
"requires": [
|
|
97,
|
|
310
|
|
],
|
|
"uses": [
|
|
19
|
|
],
|
|
"idx": 318
|
|
},
|
|
{
|
|
"path": "../packages/core/src/fx/layout/Card.js",
|
|
"requires": [
|
|
312,
|
|
313,
|
|
314,
|
|
315,
|
|
316,
|
|
317,
|
|
318
|
|
],
|
|
"uses": [
|
|
310
|
|
],
|
|
"idx": 319
|
|
},
|
|
{
|
|
"path": "../packages/core/src/fx/layout/card/Cube.js",
|
|
"requires": [
|
|
311
|
|
],
|
|
"uses": [],
|
|
"idx": 320
|
|
},
|
|
{
|
|
"path": "../packages/core/src/fx/layout/card/ScrollCover.js",
|
|
"requires": [
|
|
318
|
|
],
|
|
"uses": [],
|
|
"idx": 321
|
|
},
|
|
{
|
|
"path": "../packages/core/src/fx/layout/card/ScrollReveal.js",
|
|
"requires": [
|
|
318
|
|
],
|
|
"uses": [],
|
|
"idx": 322
|
|
},
|
|
{
|
|
"path": "../packages/core/src/fx/runner/CssAnimation.js",
|
|
"requires": [
|
|
298
|
|
],
|
|
"uses": [
|
|
297
|
|
],
|
|
"idx": 323
|
|
},
|
|
{
|
|
"path": "../packages/core/src/list/AbstractTreeItem.js",
|
|
"requires": [
|
|
83
|
|
],
|
|
"uses": [],
|
|
"idx": 324
|
|
},
|
|
{
|
|
"path": "../packages/core/src/list/RootTreeItem.js",
|
|
"requires": [
|
|
324
|
|
],
|
|
"uses": [],
|
|
"idx": 325
|
|
},
|
|
{
|
|
"path": "../packages/core/src/list/TreeItem.js",
|
|
"requires": [
|
|
83,
|
|
324
|
|
],
|
|
"uses": [],
|
|
"idx": 326
|
|
},
|
|
{
|
|
"path": "../packages/core/src/list/Tree.js",
|
|
"requires": [
|
|
83,
|
|
325,
|
|
326
|
|
],
|
|
"uses": [
|
|
167
|
|
],
|
|
"idx": 327
|
|
},
|
|
{
|
|
"path": "../packages/core/src/mixin/ConfigState.js",
|
|
"requires": [
|
|
0
|
|
],
|
|
"uses": [],
|
|
"idx": 328
|
|
},
|
|
{
|
|
"path": "../packages/core/src/mixin/Container.js",
|
|
"requires": [
|
|
0
|
|
],
|
|
"uses": [
|
|
20
|
|
],
|
|
"idx": 329
|
|
},
|
|
{
|
|
"path": "../packages/core/src/mixin/Hookable.js",
|
|
"requires": [
|
|
0
|
|
],
|
|
"uses": [],
|
|
"idx": 330
|
|
},
|
|
{
|
|
"path": "../packages/core/src/mixin/Mashup.js",
|
|
"requires": [
|
|
0
|
|
],
|
|
"uses": [],
|
|
"idx": 331
|
|
},
|
|
{
|
|
"path": "../packages/core/src/mixin/Responsive.js",
|
|
"requires": [
|
|
0,
|
|
76
|
|
],
|
|
"uses": [
|
|
49
|
|
],
|
|
"idx": 332
|
|
},
|
|
{
|
|
"path": "../packages/core/src/mixin/Selectable.js",
|
|
"requires": [
|
|
0
|
|
],
|
|
"uses": [
|
|
55
|
|
],
|
|
"idx": 333
|
|
},
|
|
{
|
|
"path": "../packages/core/src/mixin/StyleCacher.js",
|
|
"requires": [
|
|
0
|
|
],
|
|
"uses": [],
|
|
"idx": 334
|
|
},
|
|
{
|
|
"path": "../packages/core/src/mixin/Traversable.js",
|
|
"requires": [
|
|
0
|
|
],
|
|
"uses": [],
|
|
"idx": 335
|
|
},
|
|
{
|
|
"path": "../packages/core/src/perf/Accumulator.js",
|
|
"requires": [
|
|
90
|
|
],
|
|
"uses": [],
|
|
"idx": 336
|
|
},
|
|
{
|
|
"path": "../packages/core/src/perf/Monitor.js",
|
|
"requires": [
|
|
336
|
|
],
|
|
"uses": [],
|
|
"idx": 337
|
|
},
|
|
{
|
|
"path": "../packages/core/src/plugin/Abstract.js",
|
|
"requires": [],
|
|
"uses": [],
|
|
"idx": 338
|
|
},
|
|
{
|
|
"path": "../packages/core/src/plugin/LazyItems.js",
|
|
"requires": [
|
|
338
|
|
],
|
|
"uses": [],
|
|
"idx": 339
|
|
},
|
|
{
|
|
"path": "../packages/core/src/plugin/MousEnter.js",
|
|
"requires": [
|
|
338
|
|
],
|
|
"uses": [],
|
|
"idx": 340
|
|
},
|
|
{
|
|
"path": "../packages/core/src/sparkline/Shape.js",
|
|
"requires": [],
|
|
"uses": [],
|
|
"idx": 341
|
|
},
|
|
{
|
|
"path": "../packages/core/src/sparkline/CanvasBase.js",
|
|
"requires": [
|
|
341
|
|
],
|
|
"uses": [],
|
|
"idx": 342
|
|
},
|
|
{
|
|
"path": "../packages/core/src/sparkline/CanvasCanvas.js",
|
|
"requires": [
|
|
342
|
|
],
|
|
"uses": [],
|
|
"idx": 343
|
|
},
|
|
{
|
|
"path": "../packages/core/src/sparkline/VmlCanvas.js",
|
|
"requires": [
|
|
342
|
|
],
|
|
"uses": [],
|
|
"idx": 344
|
|
},
|
|
{
|
|
"path": "../packages/core/src/util/Color.js",
|
|
"requires": [],
|
|
"uses": [],
|
|
"idx": 345
|
|
},
|
|
{
|
|
"path": "../packages/core/src/sparkline/Base.js",
|
|
"requires": [
|
|
83,
|
|
90,
|
|
343,
|
|
344,
|
|
345
|
|
],
|
|
"uses": [],
|
|
"idx": 346
|
|
},
|
|
{
|
|
"path": "../packages/core/src/sparkline/BarBase.js",
|
|
"requires": [
|
|
346
|
|
],
|
|
"uses": [],
|
|
"idx": 347
|
|
},
|
|
{
|
|
"path": "../packages/core/src/sparkline/RangeMap.js",
|
|
"requires": [],
|
|
"uses": [],
|
|
"idx": 348
|
|
},
|
|
{
|
|
"path": "../packages/core/src/sparkline/Bar.js",
|
|
"requires": [
|
|
347,
|
|
348
|
|
],
|
|
"uses": [],
|
|
"idx": 349
|
|
},
|
|
{
|
|
"path": "../packages/core/src/sparkline/Box.js",
|
|
"requires": [
|
|
346
|
|
],
|
|
"uses": [],
|
|
"idx": 350
|
|
},
|
|
{
|
|
"path": "../packages/core/src/sparkline/Bullet.js",
|
|
"requires": [
|
|
346
|
|
],
|
|
"uses": [],
|
|
"idx": 351
|
|
},
|
|
{
|
|
"path": "../packages/core/src/sparkline/Discrete.js",
|
|
"requires": [
|
|
347
|
|
],
|
|
"uses": [],
|
|
"idx": 352
|
|
},
|
|
{
|
|
"path": "../packages/core/src/sparkline/Line.js",
|
|
"requires": [
|
|
346,
|
|
348
|
|
],
|
|
"uses": [],
|
|
"idx": 353
|
|
},
|
|
{
|
|
"path": "../packages/core/src/sparkline/Pie.js",
|
|
"requires": [
|
|
346
|
|
],
|
|
"uses": [],
|
|
"idx": 354
|
|
},
|
|
{
|
|
"path": "../packages/core/src/sparkline/TriState.js",
|
|
"requires": [
|
|
347,
|
|
348
|
|
],
|
|
"uses": [],
|
|
"idx": 355
|
|
},
|
|
{
|
|
"path": "../packages/core/src/util/Base64.js",
|
|
"requires": [],
|
|
"uses": [],
|
|
"idx": 356
|
|
},
|
|
{
|
|
"path": "../packages/core/src/util/DelimitedValue.js",
|
|
"requires": [],
|
|
"uses": [],
|
|
"idx": 357
|
|
},
|
|
{
|
|
"path": "../packages/core/src/util/CSV.js",
|
|
"requires": [
|
|
357
|
|
],
|
|
"uses": [],
|
|
"idx": 358
|
|
},
|
|
{
|
|
"path": "../packages/core/src/util/ItemCollection.js",
|
|
"requires": [
|
|
55
|
|
],
|
|
"uses": [],
|
|
"idx": 359
|
|
},
|
|
{
|
|
"path": "../packages/core/src/util/LocalStorage.js",
|
|
"requires": [],
|
|
"uses": [],
|
|
"idx": 360
|
|
},
|
|
{
|
|
"path": "../packages/core/src/util/TSV.js",
|
|
"requires": [
|
|
357
|
|
],
|
|
"uses": [],
|
|
"idx": 361
|
|
},
|
|
{
|
|
"path": "../packages/core/src/util/TaskManager.js",
|
|
"requires": [
|
|
56
|
|
],
|
|
"uses": [],
|
|
"idx": 362
|
|
},
|
|
{
|
|
"path": "../packages/core/src/util/TextMetrics.js",
|
|
"requires": [
|
|
49
|
|
],
|
|
"uses": [],
|
|
"idx": 363
|
|
},
|
|
{
|
|
"path": "../packages/core/src/util/translatable/CssTransform.js",
|
|
"requires": [
|
|
99
|
|
],
|
|
"uses": [],
|
|
"idx": 364
|
|
},
|
|
{
|
|
"path": "../packages/core/src/util/translatable/ScrollParent.js",
|
|
"requires": [
|
|
99
|
|
],
|
|
"uses": [],
|
|
"idx": 365
|
|
},
|
|
{
|
|
"path": "../packages/core/src/util/translatable/CssPosition.js",
|
|
"requires": [
|
|
99
|
|
],
|
|
"uses": [],
|
|
"idx": 366
|
|
},
|
|
{
|
|
"path": "../packages/core/src/util/Translatable.js",
|
|
"requires": [
|
|
100,
|
|
364,
|
|
365,
|
|
366
|
|
],
|
|
"uses": [],
|
|
"idx": 367
|
|
},
|
|
{
|
|
"path": "../packages/core/src/util/paintmonitor/OverflowChange.js",
|
|
"requires": [
|
|
45
|
|
],
|
|
"uses": [],
|
|
"idx": 368
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/Action.js",
|
|
"requires": [],
|
|
"uses": [],
|
|
"idx": 369
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/ElementLoader.js",
|
|
"requires": [
|
|
51
|
|
],
|
|
"uses": [
|
|
17,
|
|
18
|
|
],
|
|
"idx": 370
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/ComponentLoader.js",
|
|
"requires": [
|
|
370
|
|
],
|
|
"uses": [],
|
|
"idx": 371
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/layout/SizeModel.js",
|
|
"requires": [],
|
|
"uses": [],
|
|
"idx": 372
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/layout/Layout.js",
|
|
"requires": [
|
|
12,
|
|
90,
|
|
372
|
|
],
|
|
"uses": [
|
|
49,
|
|
602
|
|
],
|
|
"idx": 373
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/layout/container/Container.js",
|
|
"requires": [
|
|
90,
|
|
103,
|
|
373
|
|
],
|
|
"uses": [
|
|
233
|
|
],
|
|
"idx": 374
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/layout/container/Auto.js",
|
|
"requires": [
|
|
374
|
|
],
|
|
"uses": [
|
|
90
|
|
],
|
|
"idx": 375
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/ZIndexManager.js",
|
|
"requires": [
|
|
76,
|
|
161,
|
|
162
|
|
],
|
|
"uses": [
|
|
49,
|
|
119
|
|
],
|
|
"idx": 376
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/container/Container.js",
|
|
"requires": [
|
|
55,
|
|
111,
|
|
226,
|
|
329,
|
|
359,
|
|
369,
|
|
375,
|
|
376
|
|
],
|
|
"uses": [
|
|
12,
|
|
20,
|
|
23,
|
|
49
|
|
],
|
|
"idx": 377
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/layout/container/Editor.js",
|
|
"requires": [
|
|
374
|
|
],
|
|
"uses": [],
|
|
"idx": 378
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/Editor.js",
|
|
"requires": [
|
|
377,
|
|
378
|
|
],
|
|
"uses": [
|
|
1,
|
|
20
|
|
],
|
|
"idx": 379
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/EventManager.js",
|
|
"requires": [],
|
|
"uses": [
|
|
76
|
|
],
|
|
"idx": 380
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/Img.js",
|
|
"requires": [
|
|
77,
|
|
111
|
|
],
|
|
"uses": [],
|
|
"idx": 381
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/util/StoreHolder.js",
|
|
"requires": [
|
|
167
|
|
],
|
|
"uses": [],
|
|
"idx": 382
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/LoadMask.js",
|
|
"requires": [
|
|
111,
|
|
382
|
|
],
|
|
"uses": [
|
|
49,
|
|
76,
|
|
167
|
|
],
|
|
"idx": 383
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/layout/component/Component.js",
|
|
"requires": [
|
|
373
|
|
],
|
|
"uses": [],
|
|
"idx": 384
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/layout/component/Auto.js",
|
|
"requires": [
|
|
384
|
|
],
|
|
"uses": [],
|
|
"idx": 385
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/layout/component/ProgressBar.js",
|
|
"requires": [
|
|
385
|
|
],
|
|
"uses": [],
|
|
"idx": 386
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/ProgressBar.js",
|
|
"requires": [
|
|
84,
|
|
87,
|
|
94,
|
|
111,
|
|
362,
|
|
386
|
|
],
|
|
"uses": [
|
|
72
|
|
],
|
|
"idx": 387
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/dom/ButtonElement.js",
|
|
"requires": [
|
|
49
|
|
],
|
|
"uses": [],
|
|
"idx": 388
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/button/Manager.js",
|
|
"requires": [],
|
|
"uses": [],
|
|
"idx": 389
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/menu/Manager.js",
|
|
"requires": [],
|
|
"uses": [
|
|
20,
|
|
101,
|
|
111,
|
|
565
|
|
],
|
|
"idx": 390
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/util/ClickRepeater.js",
|
|
"requires": [
|
|
51
|
|
],
|
|
"uses": [],
|
|
"idx": 391
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/button/Button.js",
|
|
"requires": [
|
|
77,
|
|
111,
|
|
226,
|
|
363,
|
|
388,
|
|
389,
|
|
390,
|
|
391
|
|
],
|
|
"uses": [
|
|
509
|
|
],
|
|
"idx": 392
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/button/Split.js",
|
|
"requires": [
|
|
392
|
|
],
|
|
"uses": [
|
|
49
|
|
],
|
|
"idx": 393
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/button/Cycle.js",
|
|
"requires": [
|
|
393
|
|
],
|
|
"uses": [],
|
|
"idx": 394
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/layout/container/SegmentedButton.js",
|
|
"requires": [
|
|
374
|
|
],
|
|
"uses": [],
|
|
"idx": 395
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/button/Segmented.js",
|
|
"requires": [
|
|
377,
|
|
392,
|
|
395
|
|
],
|
|
"uses": [],
|
|
"idx": 396
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/panel/Bar.js",
|
|
"requires": [
|
|
377
|
|
],
|
|
"uses": [],
|
|
"idx": 397
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/panel/Title.js",
|
|
"requires": [
|
|
77,
|
|
111
|
|
],
|
|
"uses": [],
|
|
"idx": 398
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/panel/Tool.js",
|
|
"requires": [
|
|
77,
|
|
111
|
|
],
|
|
"uses": [
|
|
509
|
|
],
|
|
"idx": 399
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/util/KeyMap.js",
|
|
"requires": [],
|
|
"uses": [],
|
|
"idx": 400
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/util/KeyNav.js",
|
|
"requires": [
|
|
400
|
|
],
|
|
"uses": [],
|
|
"idx": 401
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/util/FocusableContainer.js",
|
|
"requires": [
|
|
0,
|
|
401
|
|
],
|
|
"uses": [
|
|
111
|
|
],
|
|
"idx": 402
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/panel/Header.js",
|
|
"requires": [
|
|
385,
|
|
397,
|
|
398,
|
|
399,
|
|
402
|
|
],
|
|
"uses": [
|
|
20
|
|
],
|
|
"idx": 403
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/layout/container/boxOverflow/None.js",
|
|
"requires": [
|
|
12
|
|
],
|
|
"uses": [],
|
|
"idx": 404
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/layout/container/boxOverflow/Scroller.js",
|
|
"requires": [
|
|
4,
|
|
49,
|
|
391,
|
|
404
|
|
],
|
|
"uses": [],
|
|
"idx": 405
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/dd/DragDropManager.js",
|
|
"requires": [
|
|
33,
|
|
34
|
|
],
|
|
"uses": [
|
|
49,
|
|
438,
|
|
509
|
|
],
|
|
"idx": 406
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/resizer/Splitter.js",
|
|
"requires": [
|
|
90,
|
|
111
|
|
],
|
|
"uses": [
|
|
434
|
|
],
|
|
"idx": 407
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/layout/container/Box.js",
|
|
"requires": [
|
|
86,
|
|
374,
|
|
404,
|
|
405,
|
|
406,
|
|
407
|
|
],
|
|
"uses": [
|
|
12,
|
|
372,
|
|
385
|
|
],
|
|
"idx": 408
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/layout/container/HBox.js",
|
|
"requires": [
|
|
408
|
|
],
|
|
"uses": [],
|
|
"idx": 409
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/layout/container/VBox.js",
|
|
"requires": [
|
|
408
|
|
],
|
|
"uses": [],
|
|
"idx": 410
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/toolbar/Toolbar.js",
|
|
"requires": [
|
|
377,
|
|
385,
|
|
402,
|
|
409,
|
|
410
|
|
],
|
|
"uses": [
|
|
491,
|
|
512,
|
|
637,
|
|
638
|
|
],
|
|
"idx": 411
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/dd/DragDrop.js",
|
|
"requires": [
|
|
406
|
|
],
|
|
"uses": [
|
|
49
|
|
],
|
|
"idx": 412
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/dd/DD.js",
|
|
"requires": [
|
|
406,
|
|
412
|
|
],
|
|
"uses": [
|
|
49
|
|
],
|
|
"idx": 413
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/dd/DDProxy.js",
|
|
"requires": [
|
|
413
|
|
],
|
|
"uses": [
|
|
406
|
|
],
|
|
"idx": 414
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/dd/StatusProxy.js",
|
|
"requires": [
|
|
111
|
|
],
|
|
"uses": [],
|
|
"idx": 415
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/dd/DragSource.js",
|
|
"requires": [
|
|
406,
|
|
414,
|
|
415
|
|
],
|
|
"uses": [
|
|
385
|
|
],
|
|
"idx": 416
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/panel/Proxy.js",
|
|
"requires": [],
|
|
"uses": [
|
|
49
|
|
],
|
|
"idx": 417
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/panel/DD.js",
|
|
"requires": [
|
|
416,
|
|
417
|
|
],
|
|
"uses": [],
|
|
"idx": 418
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/layout/component/Dock.js",
|
|
"requires": [
|
|
384
|
|
],
|
|
"uses": [
|
|
23,
|
|
49,
|
|
372
|
|
],
|
|
"idx": 419
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/util/Memento.js",
|
|
"requires": [],
|
|
"uses": [],
|
|
"idx": 420
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/container/DockingContainer.js",
|
|
"requires": [
|
|
49,
|
|
55
|
|
],
|
|
"uses": [
|
|
23,
|
|
233,
|
|
359
|
|
],
|
|
"idx": 421
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/panel/Panel.js",
|
|
"requires": [
|
|
49,
|
|
55,
|
|
72,
|
|
90,
|
|
377,
|
|
403,
|
|
411,
|
|
418,
|
|
419,
|
|
420,
|
|
421
|
|
],
|
|
"uses": [
|
|
1,
|
|
20,
|
|
33,
|
|
86,
|
|
93,
|
|
94,
|
|
111,
|
|
233,
|
|
375,
|
|
385,
|
|
399,
|
|
401,
|
|
455
|
|
],
|
|
"idx": 422
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/layout/container/Table.js",
|
|
"requires": [
|
|
374
|
|
],
|
|
"uses": [],
|
|
"idx": 423
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/container/ButtonGroup.js",
|
|
"requires": [
|
|
402,
|
|
422,
|
|
423
|
|
],
|
|
"uses": [],
|
|
"idx": 424
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/container/Monitor.js",
|
|
"requires": [],
|
|
"uses": [
|
|
23,
|
|
55
|
|
],
|
|
"idx": 425
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/plugin/Responsive.js",
|
|
"requires": [
|
|
332
|
|
],
|
|
"uses": [],
|
|
"idx": 426
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/plugin/Viewport.js",
|
|
"requires": [
|
|
426
|
|
],
|
|
"uses": [
|
|
49,
|
|
372
|
|
],
|
|
"idx": 427
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/container/Viewport.js",
|
|
"requires": [
|
|
332,
|
|
377,
|
|
427
|
|
],
|
|
"uses": [],
|
|
"idx": 428
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/layout/container/Anchor.js",
|
|
"requires": [
|
|
375
|
|
],
|
|
"uses": [],
|
|
"idx": 429
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/dashboard/Panel.js",
|
|
"requires": [
|
|
422
|
|
],
|
|
"uses": [
|
|
20
|
|
],
|
|
"idx": 430
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/dashboard/Column.js",
|
|
"requires": [
|
|
377,
|
|
429,
|
|
430
|
|
],
|
|
"uses": [],
|
|
"idx": 431
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/layout/container/Column.js",
|
|
"requires": [
|
|
375
|
|
],
|
|
"uses": [],
|
|
"idx": 432
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/dd/DragTracker.js",
|
|
"requires": [
|
|
51
|
|
],
|
|
"uses": [
|
|
20,
|
|
33,
|
|
401
|
|
],
|
|
"idx": 433
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/resizer/SplitterTracker.js",
|
|
"requires": [
|
|
33,
|
|
433
|
|
],
|
|
"uses": [
|
|
49,
|
|
97
|
|
],
|
|
"idx": 434
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/layout/container/ColumnSplitterTracker.js",
|
|
"requires": [
|
|
434
|
|
],
|
|
"uses": [],
|
|
"idx": 435
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/layout/container/ColumnSplitter.js",
|
|
"requires": [
|
|
407,
|
|
435
|
|
],
|
|
"uses": [],
|
|
"idx": 436
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/layout/container/Dashboard.js",
|
|
"requires": [
|
|
432,
|
|
436
|
|
],
|
|
"uses": [
|
|
385
|
|
],
|
|
"idx": 437
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/dd/DDTarget.js",
|
|
"requires": [
|
|
412
|
|
],
|
|
"uses": [],
|
|
"idx": 438
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/dd/ScrollManager.js",
|
|
"requires": [
|
|
406
|
|
],
|
|
"uses": [],
|
|
"idx": 439
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/dd/DropTarget.js",
|
|
"requires": [
|
|
438,
|
|
439
|
|
],
|
|
"uses": [],
|
|
"idx": 440
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/dashboard/DropZone.js",
|
|
"requires": [
|
|
440
|
|
],
|
|
"uses": [],
|
|
"idx": 441
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/dashboard/Part.js",
|
|
"requires": [
|
|
3,
|
|
12,
|
|
120
|
|
],
|
|
"uses": [],
|
|
"idx": 442
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/dashboard/Dashboard.js",
|
|
"requires": [
|
|
422,
|
|
431,
|
|
437,
|
|
441,
|
|
442
|
|
],
|
|
"uses": [
|
|
12,
|
|
106,
|
|
119
|
|
],
|
|
"idx": 443
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/dd/DragZone.js",
|
|
"requires": [
|
|
416
|
|
],
|
|
"uses": [
|
|
439,
|
|
445
|
|
],
|
|
"idx": 444
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/dd/Registry.js",
|
|
"requires": [],
|
|
"uses": [],
|
|
"idx": 445
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/dd/DropZone.js",
|
|
"requires": [
|
|
440,
|
|
445
|
|
],
|
|
"uses": [
|
|
406
|
|
],
|
|
"idx": 446
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/dom/Layer.js",
|
|
"requires": [
|
|
49
|
|
],
|
|
"uses": [
|
|
233
|
|
],
|
|
"idx": 447
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/enums.js",
|
|
"requires": [],
|
|
"uses": [],
|
|
"idx": 448
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/event/publisher/MouseEnterLeave.js",
|
|
"requires": [
|
|
36
|
|
],
|
|
"uses": [],
|
|
"idx": 449
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/flash/Component.js",
|
|
"requires": [
|
|
111
|
|
],
|
|
"uses": [],
|
|
"idx": 450
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/form/action/Action.js",
|
|
"requires": [],
|
|
"uses": [],
|
|
"idx": 451
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/form/action/Load.js",
|
|
"requires": [
|
|
17,
|
|
451
|
|
],
|
|
"uses": [
|
|
18
|
|
],
|
|
"idx": 452
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/form/action/Submit.js",
|
|
"requires": [
|
|
451
|
|
],
|
|
"uses": [
|
|
18,
|
|
233
|
|
],
|
|
"idx": 453
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/form/action/StandardSubmit.js",
|
|
"requires": [
|
|
453
|
|
],
|
|
"uses": [],
|
|
"idx": 454
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/util/ComponentDragger.js",
|
|
"requires": [
|
|
433
|
|
],
|
|
"uses": [
|
|
33,
|
|
49
|
|
],
|
|
"idx": 455
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/window/Window.js",
|
|
"requires": [
|
|
33,
|
|
422,
|
|
455
|
|
],
|
|
"uses": [],
|
|
"idx": 456
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/form/Labelable.js",
|
|
"requires": [
|
|
0,
|
|
90
|
|
],
|
|
"uses": [
|
|
49,
|
|
508
|
|
],
|
|
"idx": 457
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/form/field/Field.js",
|
|
"requires": [],
|
|
"uses": [],
|
|
"idx": 458
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/form/field/Base.js",
|
|
"requires": [
|
|
1,
|
|
90,
|
|
111,
|
|
457,
|
|
458
|
|
],
|
|
"uses": [
|
|
87,
|
|
233
|
|
],
|
|
"idx": 459
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/form/field/VTypes.js",
|
|
"requires": [],
|
|
"uses": [],
|
|
"idx": 460
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/form/trigger/Trigger.js",
|
|
"requires": [
|
|
12,
|
|
391
|
|
],
|
|
"uses": [
|
|
49,
|
|
90
|
|
],
|
|
"idx": 461
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/form/field/Text.js",
|
|
"requires": [
|
|
363,
|
|
459,
|
|
460,
|
|
461
|
|
],
|
|
"uses": [
|
|
86,
|
|
87,
|
|
94
|
|
],
|
|
"idx": 462
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/form/field/TextArea.js",
|
|
"requires": [
|
|
1,
|
|
90,
|
|
462
|
|
],
|
|
"uses": [
|
|
86,
|
|
363
|
|
],
|
|
"idx": 463
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/window/MessageBox.js",
|
|
"requires": [
|
|
387,
|
|
392,
|
|
409,
|
|
411,
|
|
429,
|
|
456,
|
|
462,
|
|
463
|
|
],
|
|
"uses": [
|
|
111,
|
|
377,
|
|
385,
|
|
386
|
|
],
|
|
"idx": 464
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/form/Basic.js",
|
|
"requires": [
|
|
1,
|
|
51,
|
|
55,
|
|
131,
|
|
452,
|
|
453,
|
|
454,
|
|
464
|
|
],
|
|
"uses": [
|
|
425
|
|
],
|
|
"idx": 465
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/form/FieldAncestor.js",
|
|
"requires": [
|
|
0,
|
|
425
|
|
],
|
|
"uses": [],
|
|
"idx": 466
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/layout/component/field/FieldContainer.js",
|
|
"requires": [
|
|
385
|
|
],
|
|
"uses": [],
|
|
"idx": 467
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/form/FieldContainer.js",
|
|
"requires": [
|
|
377,
|
|
457,
|
|
466,
|
|
467
|
|
],
|
|
"uses": [],
|
|
"idx": 468
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/layout/container/CheckboxGroup.js",
|
|
"requires": [
|
|
374
|
|
],
|
|
"uses": [
|
|
233
|
|
],
|
|
"idx": 469
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/form/CheckboxManager.js",
|
|
"requires": [
|
|
55
|
|
],
|
|
"uses": [],
|
|
"idx": 470
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/form/field/Checkbox.js",
|
|
"requires": [
|
|
90,
|
|
459,
|
|
470
|
|
],
|
|
"uses": [],
|
|
"idx": 471
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/form/CheckboxGroup.js",
|
|
"requires": [
|
|
458,
|
|
459,
|
|
468,
|
|
469,
|
|
471
|
|
],
|
|
"uses": [],
|
|
"idx": 472
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/form/FieldSet.js",
|
|
"requires": [
|
|
377,
|
|
466
|
|
],
|
|
"uses": [
|
|
49,
|
|
93,
|
|
111,
|
|
233,
|
|
385,
|
|
399,
|
|
429,
|
|
471,
|
|
605
|
|
],
|
|
"idx": 473
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/form/Label.js",
|
|
"requires": [
|
|
86,
|
|
111
|
|
],
|
|
"uses": [],
|
|
"idx": 474
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/form/Panel.js",
|
|
"requires": [
|
|
56,
|
|
422,
|
|
465,
|
|
466
|
|
],
|
|
"uses": [],
|
|
"idx": 475
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/form/RadioManager.js",
|
|
"requires": [
|
|
55
|
|
],
|
|
"uses": [],
|
|
"idx": 476
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/form/field/Radio.js",
|
|
"requires": [
|
|
471,
|
|
476
|
|
],
|
|
"uses": [],
|
|
"idx": 477
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/form/RadioGroup.js",
|
|
"requires": [
|
|
472,
|
|
477
|
|
],
|
|
"uses": [
|
|
476
|
|
],
|
|
"idx": 478
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/form/action/DirectAction.js",
|
|
"requires": [
|
|
0
|
|
],
|
|
"uses": [
|
|
213
|
|
],
|
|
"idx": 479
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/form/action/DirectLoad.js",
|
|
"requires": [
|
|
213,
|
|
452,
|
|
479
|
|
],
|
|
"uses": [],
|
|
"idx": 480
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/form/action/DirectSubmit.js",
|
|
"requires": [
|
|
213,
|
|
453,
|
|
479
|
|
],
|
|
"uses": [],
|
|
"idx": 481
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/form/field/Picker.js",
|
|
"requires": [
|
|
401,
|
|
462
|
|
],
|
|
"uses": [],
|
|
"idx": 482
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/selection/Model.js",
|
|
"requires": [
|
|
4,
|
|
12,
|
|
178,
|
|
382
|
|
],
|
|
"uses": [],
|
|
"idx": 483
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/selection/DataViewModel.js",
|
|
"requires": [
|
|
401,
|
|
483
|
|
],
|
|
"uses": [],
|
|
"idx": 484
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/view/NavigationModel.js",
|
|
"requires": [
|
|
12,
|
|
51,
|
|
382
|
|
],
|
|
"uses": [
|
|
401
|
|
],
|
|
"idx": 485
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/view/AbstractView.js",
|
|
"requires": [
|
|
75,
|
|
95,
|
|
111,
|
|
382,
|
|
383,
|
|
484,
|
|
485
|
|
],
|
|
"uses": [
|
|
12,
|
|
19,
|
|
49,
|
|
87,
|
|
90,
|
|
167,
|
|
233,
|
|
362
|
|
],
|
|
"idx": 486
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/view/View.js",
|
|
"requires": [
|
|
486
|
|
],
|
|
"uses": [],
|
|
"idx": 487
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/view/BoundListKeyNav.js",
|
|
"requires": [
|
|
485
|
|
],
|
|
"uses": [
|
|
35,
|
|
401
|
|
],
|
|
"idx": 488
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/layout/component/BoundList.js",
|
|
"requires": [
|
|
385
|
|
],
|
|
"uses": [],
|
|
"idx": 489
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/toolbar/Item.js",
|
|
"requires": [
|
|
111,
|
|
411
|
|
],
|
|
"uses": [],
|
|
"idx": 490
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/toolbar/TextItem.js",
|
|
"requires": [
|
|
90,
|
|
411,
|
|
490
|
|
],
|
|
"uses": [],
|
|
"idx": 491
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/form/trigger/Spinner.js",
|
|
"requires": [
|
|
461
|
|
],
|
|
"uses": [],
|
|
"idx": 492
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/form/field/Spinner.js",
|
|
"requires": [
|
|
401,
|
|
462,
|
|
492
|
|
],
|
|
"uses": [],
|
|
"idx": 493
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/form/field/Number.js",
|
|
"requires": [
|
|
493
|
|
],
|
|
"uses": [
|
|
86,
|
|
87
|
|
],
|
|
"idx": 494
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/toolbar/Paging.js",
|
|
"requires": [
|
|
382,
|
|
411,
|
|
491,
|
|
494
|
|
],
|
|
"uses": [
|
|
87,
|
|
385,
|
|
492
|
|
],
|
|
"idx": 495
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/view/BoundList.js",
|
|
"requires": [
|
|
49,
|
|
226,
|
|
487,
|
|
488,
|
|
489,
|
|
495
|
|
],
|
|
"uses": [
|
|
90,
|
|
385
|
|
],
|
|
"idx": 496
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/form/field/ComboBox.js",
|
|
"requires": [
|
|
1,
|
|
167,
|
|
382,
|
|
482,
|
|
496
|
|
],
|
|
"uses": [
|
|
49,
|
|
50,
|
|
90,
|
|
119,
|
|
147,
|
|
162,
|
|
233,
|
|
401,
|
|
484,
|
|
488,
|
|
489
|
|
],
|
|
"idx": 497
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/picker/Month.js",
|
|
"requires": [
|
|
90,
|
|
111,
|
|
391,
|
|
392
|
|
],
|
|
"uses": [
|
|
385
|
|
],
|
|
"idx": 498
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/picker/Date.js",
|
|
"requires": [
|
|
66,
|
|
90,
|
|
111,
|
|
391,
|
|
392,
|
|
393,
|
|
401,
|
|
498
|
|
],
|
|
"uses": [
|
|
87,
|
|
233,
|
|
385
|
|
],
|
|
"idx": 499
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/form/field/Date.js",
|
|
"requires": [
|
|
482,
|
|
499
|
|
],
|
|
"uses": [
|
|
87,
|
|
385
|
|
],
|
|
"idx": 500
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/form/field/Display.js",
|
|
"requires": [
|
|
86,
|
|
90,
|
|
459
|
|
],
|
|
"uses": [],
|
|
"idx": 501
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/form/field/FileButton.js",
|
|
"requires": [
|
|
392
|
|
],
|
|
"uses": [],
|
|
"idx": 502
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/form/trigger/Component.js",
|
|
"requires": [
|
|
461
|
|
],
|
|
"uses": [],
|
|
"idx": 503
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/form/field/File.js",
|
|
"requires": [
|
|
462,
|
|
502,
|
|
503
|
|
],
|
|
"uses": [
|
|
385
|
|
],
|
|
"idx": 504
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/form/field/Hidden.js",
|
|
"requires": [
|
|
459
|
|
],
|
|
"uses": [],
|
|
"idx": 505
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/tip/Tip.js",
|
|
"requires": [
|
|
422
|
|
],
|
|
"uses": [
|
|
34,
|
|
111
|
|
],
|
|
"idx": 506
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/tip/ToolTip.js",
|
|
"requires": [
|
|
32,
|
|
506
|
|
],
|
|
"uses": [
|
|
34,
|
|
74
|
|
],
|
|
"idx": 507
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/tip/QuickTip.js",
|
|
"requires": [
|
|
507
|
|
],
|
|
"uses": [],
|
|
"idx": 508
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/tip/QuickTipManager.js",
|
|
"requires": [
|
|
508
|
|
],
|
|
"uses": [],
|
|
"idx": 509
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/picker/Color.js",
|
|
"requires": [
|
|
90,
|
|
111
|
|
],
|
|
"uses": [],
|
|
"idx": 510
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/layout/component/field/HtmlEditor.js",
|
|
"requires": [
|
|
467
|
|
],
|
|
"uses": [],
|
|
"idx": 511
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/toolbar/Separator.js",
|
|
"requires": [
|
|
411,
|
|
490
|
|
],
|
|
"uses": [],
|
|
"idx": 512
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/layout/container/boxOverflow/Menu.js",
|
|
"requires": [
|
|
392,
|
|
404,
|
|
512
|
|
],
|
|
"uses": [
|
|
385,
|
|
405,
|
|
410,
|
|
419,
|
|
471,
|
|
563,
|
|
565,
|
|
637
|
|
],
|
|
"idx": 513
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/form/field/HtmlEditor.js",
|
|
"requires": [
|
|
86,
|
|
362,
|
|
410,
|
|
411,
|
|
458,
|
|
468,
|
|
490,
|
|
509,
|
|
510,
|
|
511,
|
|
513
|
|
],
|
|
"uses": [
|
|
1,
|
|
87,
|
|
111,
|
|
233,
|
|
385,
|
|
405,
|
|
419,
|
|
565
|
|
],
|
|
"idx": 514
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/view/TagKeyNav.js",
|
|
"requires": [
|
|
488
|
|
],
|
|
"uses": [],
|
|
"idx": 515
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/form/field/Tag.js",
|
|
"requires": [
|
|
164,
|
|
210,
|
|
483,
|
|
497,
|
|
515
|
|
],
|
|
"uses": [
|
|
50,
|
|
87,
|
|
90,
|
|
153,
|
|
158,
|
|
159
|
|
],
|
|
"idx": 516
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/picker/Time.js",
|
|
"requires": [
|
|
164,
|
|
496
|
|
],
|
|
"uses": [
|
|
50
|
|
],
|
|
"idx": 517
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/form/field/Time.js",
|
|
"requires": [
|
|
488,
|
|
497,
|
|
500,
|
|
517
|
|
],
|
|
"uses": [
|
|
87,
|
|
90,
|
|
484,
|
|
489
|
|
],
|
|
"idx": 518
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/form/field/Trigger.js",
|
|
"requires": [
|
|
233,
|
|
391,
|
|
462
|
|
],
|
|
"uses": [],
|
|
"idx": 519
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/grid/CellContext.js",
|
|
"requires": [],
|
|
"uses": [],
|
|
"idx": 520
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/grid/CellEditor.js",
|
|
"requires": [
|
|
379
|
|
],
|
|
"uses": [
|
|
49,
|
|
377
|
|
],
|
|
"idx": 521
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/grid/ColumnComponentLayout.js",
|
|
"requires": [
|
|
385
|
|
],
|
|
"uses": [],
|
|
"idx": 522
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/layout/container/Fit.js",
|
|
"requires": [
|
|
374
|
|
],
|
|
"uses": [],
|
|
"idx": 523
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/panel/Table.js",
|
|
"requires": [
|
|
422,
|
|
523
|
|
],
|
|
"uses": [
|
|
1,
|
|
76,
|
|
167,
|
|
233,
|
|
527,
|
|
534,
|
|
544,
|
|
578,
|
|
579,
|
|
622,
|
|
623,
|
|
624
|
|
],
|
|
"idx": 524
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/grid/ColumnLayout.js",
|
|
"requires": [
|
|
409,
|
|
524
|
|
],
|
|
"uses": [],
|
|
"idx": 525
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/grid/ColumnManager.js",
|
|
"requires": [],
|
|
"uses": [],
|
|
"idx": 526
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/grid/NavigationModel.js",
|
|
"requires": [
|
|
485
|
|
],
|
|
"uses": [
|
|
20,
|
|
35,
|
|
49,
|
|
74,
|
|
111,
|
|
401,
|
|
520
|
|
],
|
|
"idx": 527
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/view/TableLayout.js",
|
|
"requires": [
|
|
385
|
|
],
|
|
"uses": [],
|
|
"idx": 528
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/grid/locking/RowSynchronizer.js",
|
|
"requires": [],
|
|
"uses": [],
|
|
"idx": 529
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/view/NodeCache.js",
|
|
"requires": [
|
|
75
|
|
],
|
|
"uses": [
|
|
49,
|
|
74
|
|
],
|
|
"idx": 530
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/scroll/TableScroller.js",
|
|
"requires": [
|
|
101
|
|
],
|
|
"uses": [],
|
|
"idx": 531
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/view/Table.js",
|
|
"requires": [
|
|
1,
|
|
55,
|
|
226,
|
|
487,
|
|
520,
|
|
528,
|
|
529,
|
|
530,
|
|
531
|
|
],
|
|
"uses": [
|
|
12,
|
|
49,
|
|
74,
|
|
90,
|
|
111,
|
|
147,
|
|
544
|
|
],
|
|
"idx": 532
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/grid/Panel.js",
|
|
"requires": [
|
|
524,
|
|
532
|
|
],
|
|
"uses": [],
|
|
"idx": 533
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/grid/RowContext.js",
|
|
"requires": [],
|
|
"uses": [
|
|
12
|
|
],
|
|
"idx": 534
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/grid/RowEditorButtons.js",
|
|
"requires": [
|
|
377
|
|
],
|
|
"uses": [
|
|
385,
|
|
392,
|
|
422
|
|
],
|
|
"idx": 535
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/grid/RowEditor.js",
|
|
"requires": [
|
|
401,
|
|
475,
|
|
507,
|
|
535
|
|
],
|
|
"uses": [
|
|
49,
|
|
66,
|
|
76,
|
|
375,
|
|
377,
|
|
385,
|
|
419,
|
|
501,
|
|
520
|
|
],
|
|
"idx": 536
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/grid/Scroller.js",
|
|
"requires": [],
|
|
"uses": [],
|
|
"idx": 537
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/view/DropZone.js",
|
|
"requires": [
|
|
446
|
|
],
|
|
"uses": [
|
|
111,
|
|
385
|
|
],
|
|
"idx": 538
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/grid/ViewDropZone.js",
|
|
"requires": [
|
|
538
|
|
],
|
|
"uses": [],
|
|
"idx": 539
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/grid/plugin/HeaderResizer.js",
|
|
"requires": [
|
|
33,
|
|
338,
|
|
433
|
|
],
|
|
"uses": [
|
|
545
|
|
],
|
|
"idx": 540
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/grid/header/DragZone.js",
|
|
"requires": [
|
|
444
|
|
],
|
|
"uses": [],
|
|
"idx": 541
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/grid/header/DropZone.js",
|
|
"requires": [
|
|
446
|
|
],
|
|
"uses": [
|
|
406
|
|
],
|
|
"idx": 542
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/grid/plugin/HeaderReorderer.js",
|
|
"requires": [
|
|
338,
|
|
541,
|
|
542
|
|
],
|
|
"uses": [],
|
|
"idx": 543
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/grid/header/Container.js",
|
|
"requires": [
|
|
377,
|
|
401,
|
|
402,
|
|
525,
|
|
540,
|
|
543
|
|
],
|
|
"uses": [
|
|
1,
|
|
111,
|
|
385,
|
|
405,
|
|
410,
|
|
419,
|
|
526,
|
|
545,
|
|
563,
|
|
564,
|
|
565
|
|
],
|
|
"idx": 544
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/grid/column/Column.js",
|
|
"requires": [
|
|
207,
|
|
522,
|
|
525,
|
|
544
|
|
],
|
|
"uses": [
|
|
53,
|
|
86,
|
|
540
|
|
],
|
|
"idx": 545
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/grid/column/ActionProxy.js",
|
|
"requires": [],
|
|
"uses": [],
|
|
"idx": 546
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/grid/column/Action.js",
|
|
"requires": [
|
|
77,
|
|
545,
|
|
546
|
|
],
|
|
"uses": [
|
|
49
|
|
],
|
|
"idx": 547
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/grid/column/Boolean.js",
|
|
"requires": [
|
|
545
|
|
],
|
|
"uses": [],
|
|
"idx": 548
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/grid/column/Check.js",
|
|
"requires": [
|
|
545
|
|
],
|
|
"uses": [
|
|
520
|
|
],
|
|
"idx": 549
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/grid/column/Date.js",
|
|
"requires": [
|
|
545
|
|
],
|
|
"uses": [
|
|
86
|
|
],
|
|
"idx": 550
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/grid/column/Number.js",
|
|
"requires": [
|
|
86,
|
|
545
|
|
],
|
|
"uses": [],
|
|
"idx": 551
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/grid/column/RowNumberer.js",
|
|
"requires": [
|
|
545
|
|
],
|
|
"uses": [],
|
|
"idx": 552
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/grid/column/Template.js",
|
|
"requires": [
|
|
90,
|
|
545
|
|
],
|
|
"uses": [
|
|
549
|
|
],
|
|
"idx": 553
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/grid/column/Widget.js",
|
|
"requires": [
|
|
334,
|
|
545
|
|
],
|
|
"uses": [],
|
|
"idx": 554
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/grid/feature/Feature.js",
|
|
"requires": [
|
|
51
|
|
],
|
|
"uses": [],
|
|
"idx": 555
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/grid/feature/AbstractSummary.js",
|
|
"requires": [
|
|
555
|
|
],
|
|
"uses": [],
|
|
"idx": 556
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/grid/feature/GroupStore.js",
|
|
"requires": [
|
|
51
|
|
],
|
|
"uses": [
|
|
119
|
|
],
|
|
"idx": 557
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/grid/feature/Grouping.js",
|
|
"requires": [
|
|
555,
|
|
556,
|
|
557
|
|
],
|
|
"uses": [
|
|
90,
|
|
147,
|
|
544
|
|
],
|
|
"idx": 558
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/grid/feature/GroupingSummary.js",
|
|
"requires": [
|
|
558
|
|
],
|
|
"uses": [],
|
|
"idx": 559
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/grid/feature/RowBody.js",
|
|
"requires": [
|
|
555
|
|
],
|
|
"uses": [
|
|
90
|
|
],
|
|
"idx": 560
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/grid/feature/Summary.js",
|
|
"requires": [
|
|
556
|
|
],
|
|
"uses": [
|
|
90,
|
|
111,
|
|
147,
|
|
385
|
|
],
|
|
"idx": 561
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/menu/Item.js",
|
|
"requires": [
|
|
77,
|
|
111,
|
|
226
|
|
],
|
|
"uses": [
|
|
390,
|
|
509
|
|
],
|
|
"idx": 562
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/menu/CheckItem.js",
|
|
"requires": [
|
|
562
|
|
],
|
|
"uses": [
|
|
390
|
|
],
|
|
"idx": 563
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/menu/Separator.js",
|
|
"requires": [
|
|
562
|
|
],
|
|
"uses": [],
|
|
"idx": 564
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/menu/Menu.js",
|
|
"requires": [
|
|
390,
|
|
402,
|
|
410,
|
|
422,
|
|
562,
|
|
563,
|
|
564
|
|
],
|
|
"uses": [
|
|
1,
|
|
20,
|
|
35,
|
|
49,
|
|
385,
|
|
401
|
|
],
|
|
"idx": 565
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/grid/filters/filter/Base.js",
|
|
"requires": [
|
|
12,
|
|
405,
|
|
410,
|
|
419,
|
|
565
|
|
],
|
|
"uses": [
|
|
1,
|
|
50
|
|
],
|
|
"idx": 566
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/grid/filters/filter/SingleFilter.js",
|
|
"requires": [
|
|
566
|
|
],
|
|
"uses": [],
|
|
"idx": 567
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/grid/filters/filter/Boolean.js",
|
|
"requires": [
|
|
567
|
|
],
|
|
"uses": [],
|
|
"idx": 568
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/grid/filters/filter/TriFilter.js",
|
|
"requires": [
|
|
566
|
|
],
|
|
"uses": [],
|
|
"idx": 569
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/grid/filters/filter/Date.js",
|
|
"requires": [
|
|
385,
|
|
563,
|
|
569
|
|
],
|
|
"uses": [
|
|
405,
|
|
410,
|
|
419,
|
|
499,
|
|
615
|
|
],
|
|
"idx": 570
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/grid/filters/filter/List.js",
|
|
"requires": [
|
|
567
|
|
],
|
|
"uses": [
|
|
164,
|
|
167
|
|
],
|
|
"idx": 571
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/grid/filters/filter/Number.js",
|
|
"requires": [
|
|
385,
|
|
492,
|
|
569
|
|
],
|
|
"uses": [
|
|
494
|
|
],
|
|
"idx": 572
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/grid/filters/filter/String.js",
|
|
"requires": [
|
|
385,
|
|
462,
|
|
567
|
|
],
|
|
"uses": [
|
|
50
|
|
],
|
|
"idx": 573
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/grid/filters/Filters.js",
|
|
"requires": [
|
|
338,
|
|
382,
|
|
566,
|
|
567,
|
|
568,
|
|
569,
|
|
570,
|
|
571,
|
|
572,
|
|
573
|
|
],
|
|
"uses": [
|
|
12
|
|
],
|
|
"idx": 574
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/grid/locking/HeaderContainer.js",
|
|
"requires": [
|
|
526,
|
|
544
|
|
],
|
|
"uses": [],
|
|
"idx": 575
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/grid/locking/View.js",
|
|
"requires": [
|
|
51,
|
|
108,
|
|
111,
|
|
382,
|
|
486,
|
|
532
|
|
],
|
|
"uses": [
|
|
101,
|
|
383,
|
|
520
|
|
],
|
|
"idx": 576
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/scroll/LockingScroller.js",
|
|
"requires": [
|
|
101
|
|
],
|
|
"uses": [],
|
|
"idx": 577
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/grid/locking/Lockable.js",
|
|
"requires": [
|
|
111,
|
|
532,
|
|
544,
|
|
575,
|
|
576,
|
|
577
|
|
],
|
|
"uses": [
|
|
1,
|
|
33,
|
|
101,
|
|
167,
|
|
375,
|
|
385,
|
|
407,
|
|
408,
|
|
422,
|
|
524
|
|
],
|
|
"idx": 578
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/grid/plugin/BufferedRenderer.js",
|
|
"requires": [
|
|
338
|
|
],
|
|
"uses": [
|
|
1,
|
|
49,
|
|
111,
|
|
529
|
|
],
|
|
"idx": 579
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/grid/plugin/Editing.js",
|
|
"requires": [
|
|
4,
|
|
338,
|
|
401,
|
|
459,
|
|
532,
|
|
545
|
|
],
|
|
"uses": [
|
|
20,
|
|
111,
|
|
385,
|
|
520
|
|
],
|
|
"idx": 580
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/grid/plugin/CellEditing.js",
|
|
"requires": [
|
|
1,
|
|
521,
|
|
580
|
|
],
|
|
"uses": [
|
|
55,
|
|
520
|
|
],
|
|
"idx": 581
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/plugin/AbstractClipboard.js",
|
|
"requires": [
|
|
338,
|
|
400
|
|
],
|
|
"uses": [
|
|
49
|
|
],
|
|
"idx": 582
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/grid/plugin/Clipboard.js",
|
|
"requires": [
|
|
86,
|
|
361,
|
|
582
|
|
],
|
|
"uses": [
|
|
520
|
|
],
|
|
"idx": 583
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/grid/plugin/DragDrop.js",
|
|
"requires": [
|
|
338
|
|
],
|
|
"uses": [
|
|
539,
|
|
643
|
|
],
|
|
"idx": 584
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/grid/plugin/RowEditing.js",
|
|
"requires": [
|
|
536,
|
|
580
|
|
],
|
|
"uses": [],
|
|
"idx": 585
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/grid/plugin/RowExpander.js",
|
|
"requires": [
|
|
338,
|
|
560
|
|
],
|
|
"uses": [
|
|
90,
|
|
545
|
|
],
|
|
"idx": 586
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/grid/plugin/RowWidget.js",
|
|
"requires": [
|
|
3,
|
|
334,
|
|
586
|
|
],
|
|
"uses": [
|
|
338,
|
|
560
|
|
],
|
|
"idx": 587
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/grid/property/Grid.js",
|
|
"requires": [
|
|
533
|
|
],
|
|
"uses": [
|
|
20,
|
|
90,
|
|
147,
|
|
378,
|
|
385,
|
|
459,
|
|
462,
|
|
492,
|
|
494,
|
|
497,
|
|
500,
|
|
520,
|
|
521,
|
|
532,
|
|
581,
|
|
589,
|
|
592
|
|
],
|
|
"idx": 588
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/grid/property/HeaderContainer.js",
|
|
"requires": [
|
|
86,
|
|
544
|
|
],
|
|
"uses": [],
|
|
"idx": 589
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/grid/property/Property.js",
|
|
"requires": [
|
|
147
|
|
],
|
|
"uses": [],
|
|
"idx": 590
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/grid/property/Reader.js",
|
|
"requires": [
|
|
149
|
|
],
|
|
"uses": [
|
|
148
|
|
],
|
|
"idx": 591
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/grid/property/Store.js",
|
|
"requires": [
|
|
153,
|
|
164,
|
|
590,
|
|
591
|
|
],
|
|
"uses": [
|
|
159
|
|
],
|
|
"idx": 592
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/grid/selection/Selection.js",
|
|
"requires": [],
|
|
"uses": [],
|
|
"idx": 593
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/grid/selection/Cells.js",
|
|
"requires": [
|
|
593
|
|
],
|
|
"uses": [
|
|
520
|
|
],
|
|
"idx": 594
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/grid/selection/Columns.js",
|
|
"requires": [
|
|
593
|
|
],
|
|
"uses": [
|
|
520
|
|
],
|
|
"idx": 595
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/grid/selection/Replicator.js",
|
|
"requires": [
|
|
338
|
|
],
|
|
"uses": [],
|
|
"idx": 596
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/grid/selection/Rows.js",
|
|
"requires": [
|
|
119,
|
|
593
|
|
],
|
|
"uses": [
|
|
520
|
|
],
|
|
"idx": 597
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/grid/selection/SelectionExtender.js",
|
|
"requires": [
|
|
433
|
|
],
|
|
"uses": [
|
|
49,
|
|
362
|
|
],
|
|
"idx": 598
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/grid/selection/SpreadsheetModel.js",
|
|
"requires": [
|
|
483,
|
|
552,
|
|
593,
|
|
594,
|
|
595,
|
|
597,
|
|
598
|
|
],
|
|
"uses": [
|
|
375,
|
|
439,
|
|
520,
|
|
522,
|
|
549
|
|
],
|
|
"idx": 599
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/util/Queue.js",
|
|
"requires": [],
|
|
"uses": [],
|
|
"idx": 600
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/layout/ContextItem.js",
|
|
"requires": [],
|
|
"uses": [
|
|
55,
|
|
66,
|
|
72,
|
|
372
|
|
],
|
|
"idx": 601
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/layout/Context.js",
|
|
"requires": [
|
|
66,
|
|
72,
|
|
337,
|
|
373,
|
|
600,
|
|
601
|
|
],
|
|
"uses": [],
|
|
"idx": 602
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/layout/SizePolicy.js",
|
|
"requires": [],
|
|
"uses": [],
|
|
"idx": 603
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/layout/component/Body.js",
|
|
"requires": [
|
|
385
|
|
],
|
|
"uses": [],
|
|
"idx": 604
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/layout/component/FieldSet.js",
|
|
"requires": [
|
|
604
|
|
],
|
|
"uses": [],
|
|
"idx": 605
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/layout/container/Absolute.js",
|
|
"requires": [
|
|
429
|
|
],
|
|
"uses": [],
|
|
"idx": 606
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/layout/container/Accordion.js",
|
|
"requires": [
|
|
410
|
|
],
|
|
"uses": [],
|
|
"idx": 607
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/resizer/BorderSplitter.js",
|
|
"requires": [
|
|
407
|
|
],
|
|
"uses": [
|
|
618
|
|
],
|
|
"idx": 608
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/layout/container/Border.js",
|
|
"requires": [
|
|
72,
|
|
112,
|
|
374,
|
|
608
|
|
],
|
|
"uses": [
|
|
86,
|
|
385
|
|
],
|
|
"idx": 609
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/layout/container/Card.js",
|
|
"requires": [
|
|
523
|
|
],
|
|
"uses": [
|
|
49
|
|
],
|
|
"idx": 610
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/layout/container/Center.js",
|
|
"requires": [
|
|
523
|
|
],
|
|
"uses": [],
|
|
"idx": 611
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/layout/container/Form.js",
|
|
"requires": [
|
|
375
|
|
],
|
|
"uses": [],
|
|
"idx": 612
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/menu/Bar.js",
|
|
"requires": [
|
|
565
|
|
],
|
|
"uses": [],
|
|
"idx": 613
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/menu/ColorPicker.js",
|
|
"requires": [
|
|
510,
|
|
565
|
|
],
|
|
"uses": [
|
|
385,
|
|
390
|
|
],
|
|
"idx": 614
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/menu/DatePicker.js",
|
|
"requires": [
|
|
499,
|
|
565
|
|
],
|
|
"uses": [
|
|
385,
|
|
390
|
|
],
|
|
"idx": 615
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/panel/Pinnable.js",
|
|
"requires": [
|
|
0
|
|
],
|
|
"uses": [
|
|
385,
|
|
399
|
|
],
|
|
"idx": 616
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/plugin/Manager.js",
|
|
"requires": [],
|
|
"uses": [],
|
|
"idx": 617
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/resizer/BorderSplitterTracker.js",
|
|
"requires": [
|
|
33,
|
|
434
|
|
],
|
|
"uses": [],
|
|
"idx": 618
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/resizer/Handle.js",
|
|
"requires": [
|
|
111
|
|
],
|
|
"uses": [],
|
|
"idx": 619
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/resizer/ResizeTracker.js",
|
|
"requires": [
|
|
433
|
|
],
|
|
"uses": [
|
|
49
|
|
],
|
|
"idx": 620
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/resizer/Resizer.js",
|
|
"requires": [
|
|
51
|
|
],
|
|
"uses": [
|
|
49,
|
|
87,
|
|
111,
|
|
620
|
|
],
|
|
"idx": 621
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/selection/CellModel.js",
|
|
"requires": [
|
|
484,
|
|
520
|
|
],
|
|
"uses": [],
|
|
"idx": 622
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/selection/RowModel.js",
|
|
"requires": [
|
|
484,
|
|
520
|
|
],
|
|
"uses": [],
|
|
"idx": 623
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/selection/CheckboxModel.js",
|
|
"requires": [
|
|
549,
|
|
623
|
|
],
|
|
"uses": [
|
|
375,
|
|
520,
|
|
522
|
|
],
|
|
"idx": 624
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/selection/TreeModel.js",
|
|
"requires": [
|
|
623
|
|
],
|
|
"uses": [],
|
|
"idx": 625
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/slider/Thumb.js",
|
|
"requires": [
|
|
86,
|
|
433
|
|
],
|
|
"uses": [
|
|
72
|
|
],
|
|
"idx": 626
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/slider/Tip.js",
|
|
"requires": [
|
|
506
|
|
],
|
|
"uses": [],
|
|
"idx": 627
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/slider/Multi.js",
|
|
"requires": [
|
|
86,
|
|
87,
|
|
459,
|
|
626,
|
|
627
|
|
],
|
|
"uses": [
|
|
233
|
|
],
|
|
"idx": 628
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/slider/Single.js",
|
|
"requires": [
|
|
628
|
|
],
|
|
"uses": [],
|
|
"idx": 629
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/slider/Widget.js",
|
|
"requires": [
|
|
83,
|
|
628
|
|
],
|
|
"uses": [
|
|
72,
|
|
86
|
|
],
|
|
"idx": 630
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/state/CookieProvider.js",
|
|
"requires": [
|
|
105
|
|
],
|
|
"uses": [],
|
|
"idx": 631
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/state/LocalStorageProvider.js",
|
|
"requires": [
|
|
105,
|
|
360
|
|
],
|
|
"uses": [],
|
|
"idx": 632
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/tab/Tab.js",
|
|
"requires": [
|
|
392
|
|
],
|
|
"uses": [],
|
|
"idx": 633
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/tab/Bar.js",
|
|
"requires": [
|
|
34,
|
|
397,
|
|
402,
|
|
604,
|
|
633
|
|
],
|
|
"uses": [
|
|
33
|
|
],
|
|
"idx": 634
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/tab/Panel.js",
|
|
"requires": [
|
|
422,
|
|
610,
|
|
634
|
|
],
|
|
"uses": [
|
|
385,
|
|
633
|
|
],
|
|
"idx": 635
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/toolbar/Breadcrumb.js",
|
|
"requires": [
|
|
230,
|
|
377,
|
|
393,
|
|
402
|
|
],
|
|
"uses": [
|
|
23,
|
|
167
|
|
],
|
|
"idx": 636
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/toolbar/Fill.js",
|
|
"requires": [
|
|
111,
|
|
411
|
|
],
|
|
"uses": [],
|
|
"idx": 637
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/toolbar/Spacer.js",
|
|
"requires": [
|
|
111,
|
|
411
|
|
],
|
|
"uses": [],
|
|
"idx": 638
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/tree/Column.js",
|
|
"requires": [
|
|
545
|
|
],
|
|
"uses": [
|
|
77
|
|
],
|
|
"idx": 639
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/tree/NavigationModel.js",
|
|
"requires": [
|
|
527
|
|
],
|
|
"uses": [
|
|
35
|
|
],
|
|
"idx": 640
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/tree/View.js",
|
|
"requires": [
|
|
532
|
|
],
|
|
"uses": [
|
|
49
|
|
],
|
|
"idx": 641
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/tree/Panel.js",
|
|
"requires": [
|
|
230,
|
|
524,
|
|
625,
|
|
639,
|
|
640,
|
|
641
|
|
],
|
|
"uses": [
|
|
167,
|
|
375,
|
|
522
|
|
],
|
|
"idx": 642
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/view/DragZone.js",
|
|
"requires": [
|
|
444
|
|
],
|
|
"uses": [
|
|
49,
|
|
87
|
|
],
|
|
"idx": 643
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/tree/ViewDragZone.js",
|
|
"requires": [
|
|
643
|
|
],
|
|
"uses": [
|
|
87
|
|
],
|
|
"idx": 644
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/tree/ViewDropZone.js",
|
|
"requires": [
|
|
538
|
|
],
|
|
"uses": [],
|
|
"idx": 645
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/tree/plugin/TreeViewDragDrop.js",
|
|
"requires": [
|
|
338
|
|
],
|
|
"uses": [
|
|
644,
|
|
645
|
|
],
|
|
"idx": 646
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/util/Cookies.js",
|
|
"requires": [],
|
|
"uses": [],
|
|
"idx": 647
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/view/MultiSelectorSearch.js",
|
|
"requires": [
|
|
422
|
|
],
|
|
"uses": [
|
|
50,
|
|
167,
|
|
385,
|
|
419,
|
|
462,
|
|
523,
|
|
533
|
|
],
|
|
"idx": 648
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/view/MultiSelector.js",
|
|
"requires": [
|
|
419,
|
|
523,
|
|
533,
|
|
648
|
|
],
|
|
"uses": [],
|
|
"idx": 649
|
|
},
|
|
{
|
|
"path": "../classic/classic/src/window/Toast.js",
|
|
"requires": [
|
|
456
|
|
],
|
|
"uses": [
|
|
1
|
|
],
|
|
"idx": 650
|
|
}
|
|
],
|
|
"classes": {
|
|
"Ext.AbstractManager": {
|
|
"idx": 6,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.Action": {
|
|
"idx": 369,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.Ajax": {
|
|
"idx": 18,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.AnimationQueue": {
|
|
"idx": 19,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.Component": {
|
|
"idx": 111,
|
|
"alias": [
|
|
"widget.box",
|
|
"widget.component"
|
|
],
|
|
"alternates": [
|
|
"Ext.AbstractComponent"
|
|
]
|
|
},
|
|
"Ext.ComponentLoader": {
|
|
"idx": 371,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.ComponentManager": {
|
|
"idx": 20,
|
|
"alias": [],
|
|
"alternates": [
|
|
"Ext.ComponentMgr"
|
|
]
|
|
},
|
|
"Ext.ComponentQuery": {
|
|
"idx": 23,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.Deferred": {
|
|
"idx": 11,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.Editor": {
|
|
"idx": 379,
|
|
"alias": [
|
|
"widget.editor"
|
|
],
|
|
"alternates": []
|
|
},
|
|
"Ext.ElementLoader": {
|
|
"idx": 370,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.EventManager": {
|
|
"idx": 380,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.Evented": {
|
|
"idx": 24,
|
|
"alias": [],
|
|
"alternates": [
|
|
"Ext.EventedBase"
|
|
]
|
|
},
|
|
"Ext.GlobalEvents": {
|
|
"idx": 76,
|
|
"alias": [],
|
|
"alternates": [
|
|
"Ext.globalEvents"
|
|
]
|
|
},
|
|
"Ext.Glyph": {
|
|
"idx": 77,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.Img": {
|
|
"idx": 381,
|
|
"alias": [
|
|
"widget.image",
|
|
"widget.imagecomponent"
|
|
],
|
|
"alternates": []
|
|
},
|
|
"Ext.LoadMask": {
|
|
"idx": 383,
|
|
"alias": [
|
|
"widget.loadmask"
|
|
],
|
|
"alternates": []
|
|
},
|
|
"Ext.Mixin": {
|
|
"idx": 0,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.Progress": {
|
|
"idx": 85,
|
|
"alias": [
|
|
"widget.progress",
|
|
"widget.progressbarwidget"
|
|
],
|
|
"alternates": [
|
|
"Ext.ProgressBarWidget"
|
|
]
|
|
},
|
|
"Ext.ProgressBar": {
|
|
"idx": 387,
|
|
"alias": [
|
|
"widget.progressbar"
|
|
],
|
|
"alternates": []
|
|
},
|
|
"Ext.ProgressBase": {
|
|
"idx": 84,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.Promise": {
|
|
"idx": 10,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.TaskQueue": {
|
|
"idx": 39,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.Template": {
|
|
"idx": 87,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.Widget": {
|
|
"idx": 83,
|
|
"alias": [
|
|
"widget.widget"
|
|
],
|
|
"alternates": [
|
|
"Ext.Gadget"
|
|
]
|
|
},
|
|
"Ext.XTemplate": {
|
|
"idx": 90,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.ZIndexManager": {
|
|
"idx": 376,
|
|
"alias": [],
|
|
"alternates": [
|
|
"Ext.WindowGroup"
|
|
]
|
|
},
|
|
"Ext.app.Application": {
|
|
"idx": 174,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.app.BaseController": {
|
|
"idx": 115,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.app.Controller": {
|
|
"idx": 173,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.app.EventBus": {
|
|
"idx": 113,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.app.EventDomain": {
|
|
"idx": 91,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.app.Profile": {
|
|
"idx": 175,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.app.Util": {
|
|
"idx": 116,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.app.ViewController": {
|
|
"idx": 177,
|
|
"alias": [
|
|
"controller.controller"
|
|
],
|
|
"alternates": []
|
|
},
|
|
"Ext.app.ViewModel": {
|
|
"idx": 211,
|
|
"alias": [
|
|
"viewmodel.default"
|
|
],
|
|
"alternates": []
|
|
},
|
|
"Ext.app.bind.AbstractStub": {
|
|
"idx": 192,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.app.bind.BaseBinding": {
|
|
"idx": 190,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.app.bind.Binding": {
|
|
"idx": 191,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.app.bind.Formula": {
|
|
"idx": 197,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.app.bind.LinkStub": {
|
|
"idx": 194,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.app.bind.Multi": {
|
|
"idx": 196,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.app.bind.Parser": {
|
|
"idx": 207,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.app.bind.RootStub": {
|
|
"idx": 195,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.app.bind.Stub": {
|
|
"idx": 193,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.app.bind.Template": {
|
|
"idx": 208,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.app.bind.TemplateBinding": {
|
|
"idx": 209,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.app.domain.Component": {
|
|
"idx": 92,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.app.domain.Controller": {
|
|
"idx": 212,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.app.domain.Direct": {
|
|
"idx": 215,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.app.domain.Global": {
|
|
"idx": 114,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.app.domain.Store": {
|
|
"idx": 168,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.app.domain.View": {
|
|
"idx": 176,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.app.route.Queue": {
|
|
"idx": 169,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.app.route.Route": {
|
|
"idx": 170,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.app.route.Router": {
|
|
"idx": 172,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.button.Button": {
|
|
"idx": 392,
|
|
"alias": [
|
|
"widget.button"
|
|
],
|
|
"alternates": [
|
|
"Ext.Button"
|
|
]
|
|
},
|
|
"Ext.button.Cycle": {
|
|
"idx": 394,
|
|
"alias": [
|
|
"widget.cycle"
|
|
],
|
|
"alternates": [
|
|
"Ext.CycleButton"
|
|
]
|
|
},
|
|
"Ext.button.Manager": {
|
|
"idx": 389,
|
|
"alias": [],
|
|
"alternates": [
|
|
"Ext.ButtonToggleManager"
|
|
]
|
|
},
|
|
"Ext.button.Segmented": {
|
|
"idx": 396,
|
|
"alias": [
|
|
"widget.segmentedbutton"
|
|
],
|
|
"alternates": []
|
|
},
|
|
"Ext.button.Split": {
|
|
"idx": 393,
|
|
"alias": [
|
|
"widget.splitbutton"
|
|
],
|
|
"alternates": [
|
|
"Ext.SplitButton"
|
|
]
|
|
},
|
|
"Ext.container.ButtonGroup": {
|
|
"idx": 424,
|
|
"alias": [
|
|
"widget.buttongroup"
|
|
],
|
|
"alternates": [
|
|
"Ext.ButtonGroup"
|
|
]
|
|
},
|
|
"Ext.container.Container": {
|
|
"idx": 377,
|
|
"alias": [
|
|
"widget.container"
|
|
],
|
|
"alternates": [
|
|
"Ext.Container",
|
|
"Ext.AbstractContainer"
|
|
]
|
|
},
|
|
"Ext.container.DockingContainer": {
|
|
"idx": 421,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.container.Monitor": {
|
|
"idx": 425,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.container.Viewport": {
|
|
"idx": 428,
|
|
"alias": [
|
|
"widget.viewport"
|
|
],
|
|
"alternates": [
|
|
"Ext.Viewport"
|
|
]
|
|
},
|
|
"Ext.dashboard.Column": {
|
|
"idx": 431,
|
|
"alias": [
|
|
"widget.dashboard-column"
|
|
],
|
|
"alternates": []
|
|
},
|
|
"Ext.dashboard.Dashboard": {
|
|
"idx": 443,
|
|
"alias": [
|
|
"widget.dashboard"
|
|
],
|
|
"alternates": []
|
|
},
|
|
"Ext.dashboard.DropZone": {
|
|
"idx": 441,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.dashboard.Panel": {
|
|
"idx": 430,
|
|
"alias": [
|
|
"widget.dashboard-panel"
|
|
],
|
|
"alternates": []
|
|
},
|
|
"Ext.dashboard.Part": {
|
|
"idx": 442,
|
|
"alias": [
|
|
"part.part"
|
|
],
|
|
"alternates": []
|
|
},
|
|
"Ext.data.AbstractStore": {
|
|
"idx": 129,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.data.ArrayStore": {
|
|
"idx": 166,
|
|
"alias": [
|
|
"store.array"
|
|
],
|
|
"alternates": [
|
|
"Ext.data.SimpleStore"
|
|
]
|
|
},
|
|
"Ext.data.Batch": {
|
|
"idx": 180,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.data.BufferedStore": {
|
|
"idx": 217,
|
|
"alias": [
|
|
"store.buffered"
|
|
],
|
|
"alternates": []
|
|
},
|
|
"Ext.data.ChainedStore": {
|
|
"idx": 210,
|
|
"alias": [
|
|
"store.chained"
|
|
],
|
|
"alternates": []
|
|
},
|
|
"Ext.data.Connection": {
|
|
"idx": 17,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.data.DirectStore": {
|
|
"idx": 219,
|
|
"alias": [
|
|
"store.direct"
|
|
],
|
|
"alternates": []
|
|
},
|
|
"Ext.data.Error": {
|
|
"idx": 130,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.data.ErrorCollection": {
|
|
"idx": 131,
|
|
"alias": [],
|
|
"alternates": [
|
|
"Ext.data.Errors"
|
|
]
|
|
},
|
|
"Ext.data.JsonP": {
|
|
"idx": 220,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.data.JsonPStore": {
|
|
"idx": 222,
|
|
"alias": [
|
|
"store.jsonp"
|
|
],
|
|
"alternates": []
|
|
},
|
|
"Ext.data.JsonStore": {
|
|
"idx": 223,
|
|
"alias": [
|
|
"store.json"
|
|
],
|
|
"alternates": []
|
|
},
|
|
"Ext.data.LocalStore": {
|
|
"idx": 155,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.data.Model": {
|
|
"idx": 147,
|
|
"alias": [],
|
|
"alternates": [
|
|
"Ext.data.Record"
|
|
]
|
|
},
|
|
"Ext.data.ModelManager": {
|
|
"idx": 224,
|
|
"alias": [],
|
|
"alternates": [
|
|
"Ext.ModelMgr"
|
|
]
|
|
},
|
|
"Ext.data.NodeInterface": {
|
|
"idx": 225,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.data.NodeStore": {
|
|
"idx": 228,
|
|
"alias": [
|
|
"store.node"
|
|
],
|
|
"alternates": []
|
|
},
|
|
"Ext.data.PageMap": {
|
|
"idx": 216,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.data.ProxyStore": {
|
|
"idx": 154,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.data.Request": {
|
|
"idx": 229,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.data.ResultSet": {
|
|
"idx": 148,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.data.Session": {
|
|
"idx": 188,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.data.SortTypes": {
|
|
"idx": 137,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.data.Store": {
|
|
"idx": 164,
|
|
"alias": [
|
|
"store.store"
|
|
],
|
|
"alternates": []
|
|
},
|
|
"Ext.data.StoreManager": {
|
|
"idx": 167,
|
|
"alias": [],
|
|
"alternates": [
|
|
"Ext.StoreMgr",
|
|
"Ext.data.StoreMgr",
|
|
"Ext.StoreManager"
|
|
]
|
|
},
|
|
"Ext.data.TreeModel": {
|
|
"idx": 227,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.data.TreeStore": {
|
|
"idx": 230,
|
|
"alias": [
|
|
"store.tree"
|
|
],
|
|
"alternates": []
|
|
},
|
|
"Ext.data.Types": {
|
|
"idx": 231,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.data.Validation": {
|
|
"idx": 232,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.data.XmlStore": {
|
|
"idx": 237,
|
|
"alias": [
|
|
"store.xml"
|
|
],
|
|
"alternates": []
|
|
},
|
|
"Ext.data.field.Boolean": {
|
|
"idx": 140,
|
|
"alias": [
|
|
"data.field.bool",
|
|
"data.field.boolean"
|
|
],
|
|
"alternates": []
|
|
},
|
|
"Ext.data.field.Date": {
|
|
"idx": 141,
|
|
"alias": [
|
|
"data.field.date"
|
|
],
|
|
"alternates": []
|
|
},
|
|
"Ext.data.field.Field": {
|
|
"idx": 139,
|
|
"alias": [
|
|
"data.field.auto"
|
|
],
|
|
"alternates": [
|
|
"Ext.data.Field"
|
|
]
|
|
},
|
|
"Ext.data.field.Integer": {
|
|
"idx": 142,
|
|
"alias": [
|
|
"data.field.int",
|
|
"data.field.integer"
|
|
],
|
|
"alternates": []
|
|
},
|
|
"Ext.data.field.Number": {
|
|
"idx": 143,
|
|
"alias": [
|
|
"data.field.float",
|
|
"data.field.number"
|
|
],
|
|
"alternates": []
|
|
},
|
|
"Ext.data.field.String": {
|
|
"idx": 144,
|
|
"alias": [
|
|
"data.field.string"
|
|
],
|
|
"alternates": []
|
|
},
|
|
"Ext.data.flash.BinaryXhr": {
|
|
"idx": 14,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.data.identifier.Generator": {
|
|
"idx": 145,
|
|
"alias": [
|
|
"data.identifier.default"
|
|
],
|
|
"alternates": []
|
|
},
|
|
"Ext.data.identifier.Negative": {
|
|
"idx": 238,
|
|
"alias": [
|
|
"data.identifier.negative"
|
|
],
|
|
"alternates": []
|
|
},
|
|
"Ext.data.identifier.Sequential": {
|
|
"idx": 146,
|
|
"alias": [
|
|
"data.identifier.sequential"
|
|
],
|
|
"alternates": []
|
|
},
|
|
"Ext.data.identifier.Uuid": {
|
|
"idx": 239,
|
|
"alias": [
|
|
"data.identifier.uuid"
|
|
],
|
|
"alternates": []
|
|
},
|
|
"Ext.data.matrix.Matrix": {
|
|
"idx": 183,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.data.matrix.Side": {
|
|
"idx": 182,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.data.matrix.Slice": {
|
|
"idx": 181,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.data.operation.Create": {
|
|
"idx": 133,
|
|
"alias": [
|
|
"data.operation.create"
|
|
],
|
|
"alternates": []
|
|
},
|
|
"Ext.data.operation.Destroy": {
|
|
"idx": 134,
|
|
"alias": [
|
|
"data.operation.destroy"
|
|
],
|
|
"alternates": []
|
|
},
|
|
"Ext.data.operation.Operation": {
|
|
"idx": 132,
|
|
"alias": [],
|
|
"alternates": [
|
|
"Ext.data.Operation"
|
|
]
|
|
},
|
|
"Ext.data.operation.Read": {
|
|
"idx": 135,
|
|
"alias": [
|
|
"data.operation.read"
|
|
],
|
|
"alternates": []
|
|
},
|
|
"Ext.data.operation.Update": {
|
|
"idx": 136,
|
|
"alias": [
|
|
"data.operation.update"
|
|
],
|
|
"alternates": []
|
|
},
|
|
"Ext.data.proxy.Ajax": {
|
|
"idx": 157,
|
|
"alias": [
|
|
"proxy.ajax"
|
|
],
|
|
"alternates": [
|
|
"Ext.data.HttpProxy",
|
|
"Ext.data.AjaxProxy"
|
|
]
|
|
},
|
|
"Ext.data.proxy.Client": {
|
|
"idx": 152,
|
|
"alias": [],
|
|
"alternates": [
|
|
"Ext.data.ClientProxy"
|
|
]
|
|
},
|
|
"Ext.data.proxy.Direct": {
|
|
"idx": 218,
|
|
"alias": [
|
|
"proxy.direct"
|
|
],
|
|
"alternates": [
|
|
"Ext.data.DirectProxy"
|
|
]
|
|
},
|
|
"Ext.data.proxy.JsonP": {
|
|
"idx": 221,
|
|
"alias": [
|
|
"proxy.jsonp",
|
|
"proxy.scripttag"
|
|
],
|
|
"alternates": [
|
|
"Ext.data.ScriptTagProxy"
|
|
]
|
|
},
|
|
"Ext.data.proxy.LocalStorage": {
|
|
"idx": 241,
|
|
"alias": [
|
|
"proxy.localstorage"
|
|
],
|
|
"alternates": [
|
|
"Ext.data.LocalStorageProxy"
|
|
]
|
|
},
|
|
"Ext.data.proxy.Memory": {
|
|
"idx": 153,
|
|
"alias": [
|
|
"proxy.memory"
|
|
],
|
|
"alternates": [
|
|
"Ext.data.MemoryProxy"
|
|
]
|
|
},
|
|
"Ext.data.proxy.Proxy": {
|
|
"idx": 151,
|
|
"alias": [
|
|
"proxy.proxy"
|
|
],
|
|
"alternates": [
|
|
"Ext.data.DataProxy",
|
|
"Ext.data.Proxy"
|
|
]
|
|
},
|
|
"Ext.data.proxy.Rest": {
|
|
"idx": 242,
|
|
"alias": [
|
|
"proxy.rest"
|
|
],
|
|
"alternates": [
|
|
"Ext.data.RestProxy"
|
|
]
|
|
},
|
|
"Ext.data.proxy.Server": {
|
|
"idx": 156,
|
|
"alias": [
|
|
"proxy.server"
|
|
],
|
|
"alternates": [
|
|
"Ext.data.ServerProxy"
|
|
]
|
|
},
|
|
"Ext.data.proxy.SessionStorage": {
|
|
"idx": 243,
|
|
"alias": [
|
|
"proxy.sessionstorage"
|
|
],
|
|
"alternates": [
|
|
"Ext.data.SessionStorageProxy"
|
|
]
|
|
},
|
|
"Ext.data.proxy.WebStorage": {
|
|
"idx": 240,
|
|
"alias": [],
|
|
"alternates": [
|
|
"Ext.data.WebStorageProxy"
|
|
]
|
|
},
|
|
"Ext.data.reader.Array": {
|
|
"idx": 165,
|
|
"alias": [
|
|
"reader.array"
|
|
],
|
|
"alternates": [
|
|
"Ext.data.ArrayReader"
|
|
]
|
|
},
|
|
"Ext.data.reader.Json": {
|
|
"idx": 158,
|
|
"alias": [
|
|
"reader.json"
|
|
],
|
|
"alternates": [
|
|
"Ext.data.JsonReader"
|
|
]
|
|
},
|
|
"Ext.data.reader.Reader": {
|
|
"idx": 149,
|
|
"alias": [
|
|
"reader.base"
|
|
],
|
|
"alternates": [
|
|
"Ext.data.Reader",
|
|
"Ext.data.DataReader"
|
|
]
|
|
},
|
|
"Ext.data.reader.Xml": {
|
|
"idx": 235,
|
|
"alias": [
|
|
"reader.xml"
|
|
],
|
|
"alternates": [
|
|
"Ext.data.XmlReader"
|
|
]
|
|
},
|
|
"Ext.data.request.Ajax": {
|
|
"idx": 15,
|
|
"alias": [
|
|
"request.ajax"
|
|
],
|
|
"alternates": []
|
|
},
|
|
"Ext.data.request.Base": {
|
|
"idx": 13,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.data.request.Form": {
|
|
"idx": 16,
|
|
"alias": [
|
|
"request.form"
|
|
],
|
|
"alternates": []
|
|
},
|
|
"Ext.data.schema.Association": {
|
|
"idx": 122,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.data.schema.ManyToMany": {
|
|
"idx": 125,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.data.schema.ManyToOne": {
|
|
"idx": 124,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.data.schema.Namer": {
|
|
"idx": 127,
|
|
"alias": [
|
|
"namer.default"
|
|
],
|
|
"alternates": []
|
|
},
|
|
"Ext.data.schema.OneToOne": {
|
|
"idx": 123,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.data.schema.Role": {
|
|
"idx": 121,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.data.schema.Schema": {
|
|
"idx": 128,
|
|
"alias": [
|
|
"schema.default"
|
|
],
|
|
"alternates": []
|
|
},
|
|
"Ext.data.session.BatchVisitor": {
|
|
"idx": 186,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.data.session.ChangesVisitor": {
|
|
"idx": 184,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.data.session.ChildChangesVisitor": {
|
|
"idx": 185,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.data.validator.Bound": {
|
|
"idx": 248,
|
|
"alias": [
|
|
"data.validator.bound"
|
|
],
|
|
"alternates": []
|
|
},
|
|
"Ext.data.validator.Email": {
|
|
"idx": 250,
|
|
"alias": [
|
|
"data.validator.email"
|
|
],
|
|
"alternates": []
|
|
},
|
|
"Ext.data.validator.Exclusion": {
|
|
"idx": 252,
|
|
"alias": [
|
|
"data.validator.exclusion"
|
|
],
|
|
"alternates": []
|
|
},
|
|
"Ext.data.validator.Format": {
|
|
"idx": 249,
|
|
"alias": [
|
|
"data.validator.format"
|
|
],
|
|
"alternates": []
|
|
},
|
|
"Ext.data.validator.Inclusion": {
|
|
"idx": 253,
|
|
"alias": [
|
|
"data.validator.inclusion"
|
|
],
|
|
"alternates": []
|
|
},
|
|
"Ext.data.validator.Length": {
|
|
"idx": 254,
|
|
"alias": [
|
|
"data.validator.length"
|
|
],
|
|
"alternates": []
|
|
},
|
|
"Ext.data.validator.List": {
|
|
"idx": 251,
|
|
"alias": [
|
|
"data.validator.list"
|
|
],
|
|
"alternates": []
|
|
},
|
|
"Ext.data.validator.Presence": {
|
|
"idx": 255,
|
|
"alias": [
|
|
"data.validator.presence"
|
|
],
|
|
"alternates": []
|
|
},
|
|
"Ext.data.validator.Range": {
|
|
"idx": 256,
|
|
"alias": [
|
|
"data.validator.range"
|
|
],
|
|
"alternates": []
|
|
},
|
|
"Ext.data.validator.Validator": {
|
|
"idx": 138,
|
|
"alias": [
|
|
"data.validator.base"
|
|
],
|
|
"alternates": []
|
|
},
|
|
"Ext.data.writer.Json": {
|
|
"idx": 159,
|
|
"alias": [
|
|
"writer.json"
|
|
],
|
|
"alternates": [
|
|
"Ext.data.JsonWriter"
|
|
]
|
|
},
|
|
"Ext.data.writer.Writer": {
|
|
"idx": 150,
|
|
"alias": [
|
|
"writer.base"
|
|
],
|
|
"alternates": [
|
|
"Ext.data.DataWriter",
|
|
"Ext.data.Writer"
|
|
]
|
|
},
|
|
"Ext.data.writer.Xml": {
|
|
"idx": 236,
|
|
"alias": [
|
|
"writer.xml"
|
|
],
|
|
"alternates": [
|
|
"Ext.data.XmlWriter"
|
|
]
|
|
},
|
|
"Ext.dd.DD": {
|
|
"idx": 413,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.dd.DDProxy": {
|
|
"idx": 414,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.dd.DDTarget": {
|
|
"idx": 438,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.dd.DragDrop": {
|
|
"idx": 412,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.dd.DragDropManager": {
|
|
"idx": 406,
|
|
"alias": [],
|
|
"alternates": [
|
|
"Ext.dd.DragDropMgr",
|
|
"Ext.dd.DDM"
|
|
]
|
|
},
|
|
"Ext.dd.DragSource": {
|
|
"idx": 416,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.dd.DragTracker": {
|
|
"idx": 433,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.dd.DragZone": {
|
|
"idx": 444,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.dd.DropTarget": {
|
|
"idx": 440,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.dd.DropZone": {
|
|
"idx": 446,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.dd.Registry": {
|
|
"idx": 445,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.dd.ScrollManager": {
|
|
"idx": 439,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.dd.StatusProxy": {
|
|
"idx": 415,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.direct.Event": {
|
|
"idx": 257,
|
|
"alias": [
|
|
"direct.event"
|
|
],
|
|
"alternates": []
|
|
},
|
|
"Ext.direct.ExceptionEvent": {
|
|
"idx": 259,
|
|
"alias": [
|
|
"direct.exception"
|
|
],
|
|
"alternates": []
|
|
},
|
|
"Ext.direct.JsonProvider": {
|
|
"idx": 260,
|
|
"alias": [
|
|
"direct.jsonprovider"
|
|
],
|
|
"alternates": []
|
|
},
|
|
"Ext.direct.Manager": {
|
|
"idx": 213,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.direct.PollingProvider": {
|
|
"idx": 261,
|
|
"alias": [
|
|
"direct.pollingprovider"
|
|
],
|
|
"alternates": []
|
|
},
|
|
"Ext.direct.Provider": {
|
|
"idx": 214,
|
|
"alias": [
|
|
"direct.provider"
|
|
],
|
|
"alternates": []
|
|
},
|
|
"Ext.direct.RemotingEvent": {
|
|
"idx": 258,
|
|
"alias": [
|
|
"direct.rpc"
|
|
],
|
|
"alternates": []
|
|
},
|
|
"Ext.direct.RemotingMethod": {
|
|
"idx": 262,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.direct.RemotingProvider": {
|
|
"idx": 264,
|
|
"alias": [
|
|
"direct.remotingprovider"
|
|
],
|
|
"alternates": []
|
|
},
|
|
"Ext.direct.Transaction": {
|
|
"idx": 263,
|
|
"alias": [
|
|
"direct.transaction"
|
|
],
|
|
"alternates": []
|
|
},
|
|
"Ext.dom.ButtonElement": {
|
|
"idx": 388,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.dom.CompositeElement": {
|
|
"idx": 94,
|
|
"alias": [],
|
|
"alternates": [
|
|
"Ext.CompositeElement"
|
|
]
|
|
},
|
|
"Ext.dom.CompositeElementLite": {
|
|
"idx": 75,
|
|
"alias": [],
|
|
"alternates": [
|
|
"Ext.CompositeElementLite"
|
|
]
|
|
},
|
|
"Ext.dom.Element": {
|
|
"idx": 49,
|
|
"alias": [],
|
|
"alternates": [
|
|
"Ext.Element"
|
|
]
|
|
},
|
|
"Ext.dom.ElementEvent": {
|
|
"idx": 30,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.dom.Fly": {
|
|
"idx": 74,
|
|
"alias": [],
|
|
"alternates": [
|
|
"Ext.dom.Element.Fly"
|
|
]
|
|
},
|
|
"Ext.dom.GarbageCollector": {
|
|
"idx": 265,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.dom.Helper": {
|
|
"idx": 233,
|
|
"alias": [],
|
|
"alternates": [
|
|
"Ext.DomHelper",
|
|
"Ext.core.DomHelper"
|
|
]
|
|
},
|
|
"Ext.dom.Layer": {
|
|
"idx": 447,
|
|
"alias": [],
|
|
"alternates": [
|
|
"Ext.Layer"
|
|
]
|
|
},
|
|
"Ext.dom.Query": {
|
|
"idx": 234,
|
|
"alias": [],
|
|
"alternates": [
|
|
"Ext.core.DomQuery",
|
|
"Ext.DomQuery"
|
|
]
|
|
},
|
|
"Ext.dom.Shadow": {
|
|
"idx": 28,
|
|
"alias": [],
|
|
"alternates": [
|
|
"Ext.Shadow"
|
|
]
|
|
},
|
|
"Ext.dom.Shim": {
|
|
"idx": 29,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.dom.TouchAction": {
|
|
"idx": 266,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.dom.Underlay": {
|
|
"idx": 27,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.dom.UnderlayPool": {
|
|
"idx": 26,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.drag.Constraint": {
|
|
"idx": 267,
|
|
"alias": [
|
|
"drag.constraint.base"
|
|
],
|
|
"alternates": []
|
|
},
|
|
"Ext.drag.Info": {
|
|
"idx": 268,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.drag.Item": {
|
|
"idx": 269,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.drag.Manager": {
|
|
"idx": 270,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.drag.Source": {
|
|
"idx": 271,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.drag.Target": {
|
|
"idx": 272,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.drag.proxy.None": {
|
|
"idx": 273,
|
|
"alias": [
|
|
"drag.proxy.none"
|
|
],
|
|
"alternates": []
|
|
},
|
|
"Ext.drag.proxy.Original": {
|
|
"idx": 274,
|
|
"alias": [
|
|
"drag.proxy.original"
|
|
],
|
|
"alternates": []
|
|
},
|
|
"Ext.drag.proxy.Placeholder": {
|
|
"idx": 275,
|
|
"alias": [
|
|
"drag.proxy.placeholder"
|
|
],
|
|
"alternates": []
|
|
},
|
|
"Ext.event.Event": {
|
|
"idx": 35,
|
|
"alias": [],
|
|
"alternates": [
|
|
"Ext.EventObjectImpl"
|
|
]
|
|
},
|
|
"Ext.event.gesture.DoubleTap": {
|
|
"idx": 278,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.event.gesture.Drag": {
|
|
"idx": 279,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.event.gesture.EdgeSwipe": {
|
|
"idx": 281,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.event.gesture.LongPress": {
|
|
"idx": 282,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.event.gesture.MultiTouch": {
|
|
"idx": 283,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.event.gesture.Pinch": {
|
|
"idx": 284,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.event.gesture.Recognizer": {
|
|
"idx": 276,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.event.gesture.Rotate": {
|
|
"idx": 285,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.event.gesture.SingleTouch": {
|
|
"idx": 277,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.event.gesture.Swipe": {
|
|
"idx": 280,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.event.gesture.Tap": {
|
|
"idx": 286,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.event.publisher.Dom": {
|
|
"idx": 36,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.event.publisher.ElementPaint": {
|
|
"idx": 48,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.event.publisher.ElementSize": {
|
|
"idx": 44,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.event.publisher.Focus": {
|
|
"idx": 287,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.event.publisher.Gesture": {
|
|
"idx": 37,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.event.publisher.MouseEnterLeave": {
|
|
"idx": 449,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.event.publisher.Publisher": {
|
|
"idx": 31,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.flash.Component": {
|
|
"idx": 450,
|
|
"alias": [
|
|
"widget.flash"
|
|
],
|
|
"alternates": [
|
|
"Ext.FlashComponent"
|
|
]
|
|
},
|
|
"Ext.form.Basic": {
|
|
"idx": 465,
|
|
"alias": [],
|
|
"alternates": [
|
|
"Ext.form.BasicForm"
|
|
]
|
|
},
|
|
"Ext.form.CheckboxGroup": {
|
|
"idx": 472,
|
|
"alias": [
|
|
"widget.checkboxgroup"
|
|
],
|
|
"alternates": []
|
|
},
|
|
"Ext.form.CheckboxManager": {
|
|
"idx": 470,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.form.FieldAncestor": {
|
|
"idx": 466,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.form.FieldContainer": {
|
|
"idx": 468,
|
|
"alias": [
|
|
"widget.fieldcontainer"
|
|
],
|
|
"alternates": []
|
|
},
|
|
"Ext.form.FieldSet": {
|
|
"idx": 473,
|
|
"alias": [
|
|
"widget.fieldset"
|
|
],
|
|
"alternates": []
|
|
},
|
|
"Ext.form.Label": {
|
|
"idx": 474,
|
|
"alias": [
|
|
"widget.label"
|
|
],
|
|
"alternates": []
|
|
},
|
|
"Ext.form.Labelable": {
|
|
"idx": 457,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.form.Panel": {
|
|
"idx": 475,
|
|
"alias": [
|
|
"widget.form"
|
|
],
|
|
"alternates": [
|
|
"Ext.FormPanel",
|
|
"Ext.form.FormPanel"
|
|
]
|
|
},
|
|
"Ext.form.RadioGroup": {
|
|
"idx": 478,
|
|
"alias": [
|
|
"widget.radiogroup"
|
|
],
|
|
"alternates": []
|
|
},
|
|
"Ext.form.RadioManager": {
|
|
"idx": 476,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.form.action.Action": {
|
|
"idx": 451,
|
|
"alias": [],
|
|
"alternates": [
|
|
"Ext.form.Action"
|
|
]
|
|
},
|
|
"Ext.form.action.DirectAction": {
|
|
"idx": 479,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.form.action.DirectLoad": {
|
|
"idx": 480,
|
|
"alias": [
|
|
"formaction.directload"
|
|
],
|
|
"alternates": [
|
|
"Ext.form.Action.DirectLoad"
|
|
]
|
|
},
|
|
"Ext.form.action.DirectSubmit": {
|
|
"idx": 481,
|
|
"alias": [
|
|
"formaction.directsubmit"
|
|
],
|
|
"alternates": [
|
|
"Ext.form.Action.DirectSubmit"
|
|
]
|
|
},
|
|
"Ext.form.action.Load": {
|
|
"idx": 452,
|
|
"alias": [
|
|
"formaction.load"
|
|
],
|
|
"alternates": [
|
|
"Ext.form.Action.Load"
|
|
]
|
|
},
|
|
"Ext.form.action.StandardSubmit": {
|
|
"idx": 454,
|
|
"alias": [
|
|
"formaction.standardsubmit"
|
|
],
|
|
"alternates": []
|
|
},
|
|
"Ext.form.action.Submit": {
|
|
"idx": 453,
|
|
"alias": [
|
|
"formaction.submit"
|
|
],
|
|
"alternates": [
|
|
"Ext.form.Action.Submit"
|
|
]
|
|
},
|
|
"Ext.form.field.Base": {
|
|
"idx": 459,
|
|
"alias": [
|
|
"widget.field"
|
|
],
|
|
"alternates": [
|
|
"Ext.form.Field",
|
|
"Ext.form.BaseField"
|
|
]
|
|
},
|
|
"Ext.form.field.Checkbox": {
|
|
"idx": 471,
|
|
"alias": [
|
|
"widget.checkbox",
|
|
"widget.checkboxfield"
|
|
],
|
|
"alternates": [
|
|
"Ext.form.Checkbox"
|
|
]
|
|
},
|
|
"Ext.form.field.ComboBox": {
|
|
"idx": 497,
|
|
"alias": [
|
|
"widget.combo",
|
|
"widget.combobox"
|
|
],
|
|
"alternates": [
|
|
"Ext.form.ComboBox"
|
|
]
|
|
},
|
|
"Ext.form.field.Date": {
|
|
"idx": 500,
|
|
"alias": [
|
|
"widget.datefield"
|
|
],
|
|
"alternates": [
|
|
"Ext.form.DateField",
|
|
"Ext.form.Date"
|
|
]
|
|
},
|
|
"Ext.form.field.Display": {
|
|
"idx": 501,
|
|
"alias": [
|
|
"widget.displayfield"
|
|
],
|
|
"alternates": [
|
|
"Ext.form.DisplayField",
|
|
"Ext.form.Display"
|
|
]
|
|
},
|
|
"Ext.form.field.Field": {
|
|
"idx": 458,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.form.field.File": {
|
|
"idx": 504,
|
|
"alias": [
|
|
"widget.filefield",
|
|
"widget.fileuploadfield"
|
|
],
|
|
"alternates": [
|
|
"Ext.form.FileUploadField",
|
|
"Ext.ux.form.FileUploadField",
|
|
"Ext.form.File"
|
|
]
|
|
},
|
|
"Ext.form.field.FileButton": {
|
|
"idx": 502,
|
|
"alias": [
|
|
"widget.filebutton"
|
|
],
|
|
"alternates": []
|
|
},
|
|
"Ext.form.field.Hidden": {
|
|
"idx": 505,
|
|
"alias": [
|
|
"widget.hidden",
|
|
"widget.hiddenfield"
|
|
],
|
|
"alternates": [
|
|
"Ext.form.Hidden"
|
|
]
|
|
},
|
|
"Ext.form.field.HtmlEditor": {
|
|
"idx": 514,
|
|
"alias": [
|
|
"widget.htmleditor"
|
|
],
|
|
"alternates": [
|
|
"Ext.form.HtmlEditor"
|
|
]
|
|
},
|
|
"Ext.form.field.Number": {
|
|
"idx": 494,
|
|
"alias": [
|
|
"widget.numberfield"
|
|
],
|
|
"alternates": [
|
|
"Ext.form.NumberField",
|
|
"Ext.form.Number"
|
|
]
|
|
},
|
|
"Ext.form.field.Picker": {
|
|
"idx": 482,
|
|
"alias": [
|
|
"widget.pickerfield"
|
|
],
|
|
"alternates": [
|
|
"Ext.form.Picker"
|
|
]
|
|
},
|
|
"Ext.form.field.Radio": {
|
|
"idx": 477,
|
|
"alias": [
|
|
"widget.radio",
|
|
"widget.radiofield"
|
|
],
|
|
"alternates": [
|
|
"Ext.form.Radio"
|
|
]
|
|
},
|
|
"Ext.form.field.Spinner": {
|
|
"idx": 493,
|
|
"alias": [
|
|
"widget.spinnerfield"
|
|
],
|
|
"alternates": [
|
|
"Ext.form.Spinner"
|
|
]
|
|
},
|
|
"Ext.form.field.Tag": {
|
|
"idx": 516,
|
|
"alias": [
|
|
"widget.tagfield"
|
|
],
|
|
"alternates": []
|
|
},
|
|
"Ext.form.field.Text": {
|
|
"idx": 462,
|
|
"alias": [
|
|
"widget.textfield"
|
|
],
|
|
"alternates": [
|
|
"Ext.form.TextField",
|
|
"Ext.form.Text"
|
|
]
|
|
},
|
|
"Ext.form.field.TextArea": {
|
|
"idx": 463,
|
|
"alias": [
|
|
"widget.textarea",
|
|
"widget.textareafield"
|
|
],
|
|
"alternates": [
|
|
"Ext.form.TextArea"
|
|
]
|
|
},
|
|
"Ext.form.field.Time": {
|
|
"idx": 518,
|
|
"alias": [
|
|
"widget.timefield"
|
|
],
|
|
"alternates": [
|
|
"Ext.form.TimeField",
|
|
"Ext.form.Time"
|
|
]
|
|
},
|
|
"Ext.form.field.Trigger": {
|
|
"idx": 519,
|
|
"alias": [
|
|
"widget.trigger",
|
|
"widget.triggerfield"
|
|
],
|
|
"alternates": [
|
|
"Ext.form.TriggerField",
|
|
"Ext.form.TwinTriggerField",
|
|
"Ext.form.Trigger"
|
|
]
|
|
},
|
|
"Ext.form.field.VTypes": {
|
|
"idx": 460,
|
|
"alias": [],
|
|
"alternates": [
|
|
"Ext.form.VTypes"
|
|
]
|
|
},
|
|
"Ext.form.trigger.Component": {
|
|
"idx": 503,
|
|
"alias": [
|
|
"trigger.component"
|
|
],
|
|
"alternates": []
|
|
},
|
|
"Ext.form.trigger.Spinner": {
|
|
"idx": 492,
|
|
"alias": [
|
|
"trigger.spinner"
|
|
],
|
|
"alternates": []
|
|
},
|
|
"Ext.form.trigger.Trigger": {
|
|
"idx": 461,
|
|
"alias": [
|
|
"trigger.trigger"
|
|
],
|
|
"alternates": []
|
|
},
|
|
"Ext.fx.Anim": {
|
|
"idx": 72,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.fx.Animation": {
|
|
"idx": 297,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.fx.Animator": {
|
|
"idx": 67,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.fx.CubicBezier": {
|
|
"idx": 68,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.fx.DrawPath": {
|
|
"idx": 70,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.fx.Easing": {
|
|
"idx": 69,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.fx.Manager": {
|
|
"idx": 66,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.fx.PropertyHandler": {
|
|
"idx": 71,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.fx.Queue": {
|
|
"idx": 65,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.fx.Runner": {
|
|
"idx": 300,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.fx.State": {
|
|
"idx": 288,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.fx.animation.Abstract": {
|
|
"idx": 289,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.fx.animation.Cube": {
|
|
"idx": 301,
|
|
"alias": [
|
|
"animation.cube"
|
|
],
|
|
"alternates": []
|
|
},
|
|
"Ext.fx.animation.Fade": {
|
|
"idx": 292,
|
|
"alias": [
|
|
"animation.fade",
|
|
"animation.fadeIn"
|
|
],
|
|
"alternates": [
|
|
"Ext.fx.animation.FadeIn"
|
|
]
|
|
},
|
|
"Ext.fx.animation.FadeOut": {
|
|
"idx": 293,
|
|
"alias": [
|
|
"animation.fadeOut"
|
|
],
|
|
"alternates": []
|
|
},
|
|
"Ext.fx.animation.Flip": {
|
|
"idx": 294,
|
|
"alias": [
|
|
"animation.flip"
|
|
],
|
|
"alternates": []
|
|
},
|
|
"Ext.fx.animation.Pop": {
|
|
"idx": 295,
|
|
"alias": [
|
|
"animation.pop",
|
|
"animation.popIn"
|
|
],
|
|
"alternates": [
|
|
"Ext.fx.animation.PopIn"
|
|
]
|
|
},
|
|
"Ext.fx.animation.PopOut": {
|
|
"idx": 296,
|
|
"alias": [
|
|
"animation.popOut"
|
|
],
|
|
"alternates": []
|
|
},
|
|
"Ext.fx.animation.Slide": {
|
|
"idx": 290,
|
|
"alias": [
|
|
"animation.slide",
|
|
"animation.slideIn"
|
|
],
|
|
"alternates": [
|
|
"Ext.fx.animation.SlideIn"
|
|
]
|
|
},
|
|
"Ext.fx.animation.SlideOut": {
|
|
"idx": 291,
|
|
"alias": [
|
|
"animation.slideOut"
|
|
],
|
|
"alternates": []
|
|
},
|
|
"Ext.fx.animation.Wipe": {
|
|
"idx": 302,
|
|
"alias": [],
|
|
"alternates": [
|
|
"Ext.fx.animation.WipeIn"
|
|
]
|
|
},
|
|
"Ext.fx.animation.WipeOut": {
|
|
"idx": 303,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.fx.easing.Abstract": {
|
|
"idx": 96,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.fx.easing.Bounce": {
|
|
"idx": 304,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.fx.easing.BoundMomentum": {
|
|
"idx": 306,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.fx.easing.EaseIn": {
|
|
"idx": 307,
|
|
"alias": [
|
|
"easing.ease-in"
|
|
],
|
|
"alternates": []
|
|
},
|
|
"Ext.fx.easing.EaseOut": {
|
|
"idx": 308,
|
|
"alias": [
|
|
"easing.ease-out"
|
|
],
|
|
"alternates": []
|
|
},
|
|
"Ext.fx.easing.Easing": {
|
|
"idx": 309,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.fx.easing.Linear": {
|
|
"idx": 97,
|
|
"alias": [
|
|
"easing.linear"
|
|
],
|
|
"alternates": []
|
|
},
|
|
"Ext.fx.easing.Momentum": {
|
|
"idx": 305,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.fx.layout.Card": {
|
|
"idx": 319,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.fx.layout.card.Abstract": {
|
|
"idx": 310,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.fx.layout.card.Cover": {
|
|
"idx": 313,
|
|
"alias": [
|
|
"fx.layout.card.cover"
|
|
],
|
|
"alternates": []
|
|
},
|
|
"Ext.fx.layout.card.Cube": {
|
|
"idx": 320,
|
|
"alias": [
|
|
"fx.layout.card.cube"
|
|
],
|
|
"alternates": []
|
|
},
|
|
"Ext.fx.layout.card.Fade": {
|
|
"idx": 315,
|
|
"alias": [
|
|
"fx.layout.card.fade"
|
|
],
|
|
"alternates": []
|
|
},
|
|
"Ext.fx.layout.card.Flip": {
|
|
"idx": 316,
|
|
"alias": [
|
|
"fx.layout.card.flip"
|
|
],
|
|
"alternates": []
|
|
},
|
|
"Ext.fx.layout.card.Pop": {
|
|
"idx": 317,
|
|
"alias": [
|
|
"fx.layout.card.pop"
|
|
],
|
|
"alternates": []
|
|
},
|
|
"Ext.fx.layout.card.Reveal": {
|
|
"idx": 314,
|
|
"alias": [
|
|
"fx.layout.card.reveal"
|
|
],
|
|
"alternates": []
|
|
},
|
|
"Ext.fx.layout.card.Scroll": {
|
|
"idx": 318,
|
|
"alias": [
|
|
"fx.layout.card.scroll"
|
|
],
|
|
"alternates": []
|
|
},
|
|
"Ext.fx.layout.card.ScrollCover": {
|
|
"idx": 321,
|
|
"alias": [
|
|
"fx.layout.card.scrollcover"
|
|
],
|
|
"alternates": []
|
|
},
|
|
"Ext.fx.layout.card.ScrollReveal": {
|
|
"idx": 322,
|
|
"alias": [
|
|
"fx.layout.card.scrollreveal"
|
|
],
|
|
"alternates": []
|
|
},
|
|
"Ext.fx.layout.card.Slide": {
|
|
"idx": 312,
|
|
"alias": [
|
|
"fx.layout.card.slide"
|
|
],
|
|
"alternates": []
|
|
},
|
|
"Ext.fx.layout.card.Style": {
|
|
"idx": 311,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.fx.runner.Css": {
|
|
"idx": 298,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.fx.runner.CssAnimation": {
|
|
"idx": 323,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.fx.runner.CssTransition": {
|
|
"idx": 299,
|
|
"alias": [],
|
|
"alternates": [
|
|
"Ext.Animator"
|
|
]
|
|
},
|
|
"Ext.fx.target.Component": {
|
|
"idx": 64,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.fx.target.CompositeElement": {
|
|
"idx": 60,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.fx.target.CompositeElementCSS": {
|
|
"idx": 61,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.fx.target.CompositeSprite": {
|
|
"idx": 63,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.fx.target.Element": {
|
|
"idx": 58,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.fx.target.ElementCSS": {
|
|
"idx": 59,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.fx.target.Sprite": {
|
|
"idx": 62,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.fx.target.Target": {
|
|
"idx": 57,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.grid.CellContext": {
|
|
"idx": 520,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.grid.CellEditor": {
|
|
"idx": 521,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.grid.ColumnComponentLayout": {
|
|
"idx": 522,
|
|
"alias": [
|
|
"layout.columncomponent"
|
|
],
|
|
"alternates": []
|
|
},
|
|
"Ext.grid.ColumnLayout": {
|
|
"idx": 525,
|
|
"alias": [
|
|
"layout.gridcolumn"
|
|
],
|
|
"alternates": []
|
|
},
|
|
"Ext.grid.ColumnManager": {
|
|
"idx": 526,
|
|
"alias": [],
|
|
"alternates": [
|
|
"Ext.grid.ColumnModel"
|
|
]
|
|
},
|
|
"Ext.grid.NavigationModel": {
|
|
"idx": 527,
|
|
"alias": [
|
|
"view.navigation.grid"
|
|
],
|
|
"alternates": []
|
|
},
|
|
"Ext.grid.Panel": {
|
|
"idx": 533,
|
|
"alias": [
|
|
"widget.grid",
|
|
"widget.gridpanel"
|
|
],
|
|
"alternates": [
|
|
"Ext.list.ListView",
|
|
"Ext.ListView",
|
|
"Ext.grid.GridPanel"
|
|
]
|
|
},
|
|
"Ext.grid.RowContext": {
|
|
"idx": 534,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.grid.RowEditor": {
|
|
"idx": 536,
|
|
"alias": [
|
|
"widget.roweditor"
|
|
],
|
|
"alternates": []
|
|
},
|
|
"Ext.grid.RowEditorButtons": {
|
|
"idx": 535,
|
|
"alias": [
|
|
"widget.roweditorbuttons"
|
|
],
|
|
"alternates": []
|
|
},
|
|
"Ext.grid.Scroller": {
|
|
"idx": 537,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.grid.ViewDropZone": {
|
|
"idx": 539,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.grid.column.Action": {
|
|
"idx": 547,
|
|
"alias": [
|
|
"widget.actioncolumn"
|
|
],
|
|
"alternates": [
|
|
"Ext.grid.ActionColumn"
|
|
]
|
|
},
|
|
"Ext.grid.column.ActionProxy": {
|
|
"idx": 546,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.grid.column.Boolean": {
|
|
"idx": 548,
|
|
"alias": [
|
|
"widget.booleancolumn"
|
|
],
|
|
"alternates": [
|
|
"Ext.grid.BooleanColumn"
|
|
]
|
|
},
|
|
"Ext.grid.column.Check": {
|
|
"idx": 549,
|
|
"alias": [
|
|
"widget.checkcolumn"
|
|
],
|
|
"alternates": [
|
|
"Ext.ux.CheckColumn",
|
|
"Ext.grid.column.CheckColumn"
|
|
]
|
|
},
|
|
"Ext.grid.column.Column": {
|
|
"idx": 545,
|
|
"alias": [
|
|
"widget.gridcolumn"
|
|
],
|
|
"alternates": [
|
|
"Ext.grid.Column"
|
|
]
|
|
},
|
|
"Ext.grid.column.Date": {
|
|
"idx": 550,
|
|
"alias": [
|
|
"widget.datecolumn"
|
|
],
|
|
"alternates": [
|
|
"Ext.grid.DateColumn"
|
|
]
|
|
},
|
|
"Ext.grid.column.Number": {
|
|
"idx": 551,
|
|
"alias": [
|
|
"widget.numbercolumn"
|
|
],
|
|
"alternates": [
|
|
"Ext.grid.NumberColumn"
|
|
]
|
|
},
|
|
"Ext.grid.column.RowNumberer": {
|
|
"idx": 552,
|
|
"alias": [
|
|
"widget.rownumberer"
|
|
],
|
|
"alternates": [
|
|
"Ext.grid.RowNumberer"
|
|
]
|
|
},
|
|
"Ext.grid.column.Template": {
|
|
"idx": 553,
|
|
"alias": [
|
|
"widget.templatecolumn"
|
|
],
|
|
"alternates": [
|
|
"Ext.grid.TemplateColumn"
|
|
]
|
|
},
|
|
"Ext.grid.column.Widget": {
|
|
"idx": 554,
|
|
"alias": [
|
|
"widget.widgetcolumn"
|
|
],
|
|
"alternates": []
|
|
},
|
|
"Ext.grid.feature.AbstractSummary": {
|
|
"idx": 556,
|
|
"alias": [
|
|
"feature.abstractsummary"
|
|
],
|
|
"alternates": []
|
|
},
|
|
"Ext.grid.feature.Feature": {
|
|
"idx": 555,
|
|
"alias": [
|
|
"feature.feature"
|
|
],
|
|
"alternates": []
|
|
},
|
|
"Ext.grid.feature.GroupStore": {
|
|
"idx": 557,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.grid.feature.Grouping": {
|
|
"idx": 558,
|
|
"alias": [
|
|
"feature.grouping"
|
|
],
|
|
"alternates": []
|
|
},
|
|
"Ext.grid.feature.GroupingSummary": {
|
|
"idx": 559,
|
|
"alias": [
|
|
"feature.groupingsummary"
|
|
],
|
|
"alternates": []
|
|
},
|
|
"Ext.grid.feature.RowBody": {
|
|
"idx": 560,
|
|
"alias": [
|
|
"feature.rowbody"
|
|
],
|
|
"alternates": []
|
|
},
|
|
"Ext.grid.feature.Summary": {
|
|
"idx": 561,
|
|
"alias": [
|
|
"feature.summary"
|
|
],
|
|
"alternates": []
|
|
},
|
|
"Ext.grid.filters.Filters": {
|
|
"idx": 574,
|
|
"alias": [
|
|
"plugin.gridfilters"
|
|
],
|
|
"alternates": []
|
|
},
|
|
"Ext.grid.filters.filter.Base": {
|
|
"idx": 566,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.grid.filters.filter.Boolean": {
|
|
"idx": 568,
|
|
"alias": [
|
|
"grid.filter.boolean"
|
|
],
|
|
"alternates": []
|
|
},
|
|
"Ext.grid.filters.filter.Date": {
|
|
"idx": 570,
|
|
"alias": [
|
|
"grid.filter.date"
|
|
],
|
|
"alternates": []
|
|
},
|
|
"Ext.grid.filters.filter.List": {
|
|
"idx": 571,
|
|
"alias": [
|
|
"grid.filter.list"
|
|
],
|
|
"alternates": []
|
|
},
|
|
"Ext.grid.filters.filter.Number": {
|
|
"idx": 572,
|
|
"alias": [
|
|
"grid.filter.number",
|
|
"grid.filter.numeric"
|
|
],
|
|
"alternates": []
|
|
},
|
|
"Ext.grid.filters.filter.SingleFilter": {
|
|
"idx": 567,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.grid.filters.filter.String": {
|
|
"idx": 573,
|
|
"alias": [
|
|
"grid.filter.string"
|
|
],
|
|
"alternates": []
|
|
},
|
|
"Ext.grid.filters.filter.TriFilter": {
|
|
"idx": 569,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.grid.header.Container": {
|
|
"idx": 544,
|
|
"alias": [
|
|
"widget.headercontainer"
|
|
],
|
|
"alternates": []
|
|
},
|
|
"Ext.grid.header.DragZone": {
|
|
"idx": 541,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.grid.header.DropZone": {
|
|
"idx": 542,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.grid.locking.HeaderContainer": {
|
|
"idx": 575,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.grid.locking.Lockable": {
|
|
"idx": 578,
|
|
"alias": [],
|
|
"alternates": [
|
|
"Ext.grid.Lockable"
|
|
]
|
|
},
|
|
"Ext.grid.locking.RowSynchronizer": {
|
|
"idx": 529,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.grid.locking.View": {
|
|
"idx": 576,
|
|
"alias": [],
|
|
"alternates": [
|
|
"Ext.grid.LockingView"
|
|
]
|
|
},
|
|
"Ext.grid.plugin.BufferedRenderer": {
|
|
"idx": 579,
|
|
"alias": [
|
|
"plugin.bufferedrenderer"
|
|
],
|
|
"alternates": []
|
|
},
|
|
"Ext.grid.plugin.CellEditing": {
|
|
"idx": 581,
|
|
"alias": [
|
|
"plugin.cellediting"
|
|
],
|
|
"alternates": []
|
|
},
|
|
"Ext.grid.plugin.Clipboard": {
|
|
"idx": 583,
|
|
"alias": [
|
|
"plugin.clipboard"
|
|
],
|
|
"alternates": []
|
|
},
|
|
"Ext.grid.plugin.DragDrop": {
|
|
"idx": 584,
|
|
"alias": [
|
|
"plugin.gridviewdragdrop"
|
|
],
|
|
"alternates": []
|
|
},
|
|
"Ext.grid.plugin.Editing": {
|
|
"idx": 580,
|
|
"alias": [
|
|
"editing.editing"
|
|
],
|
|
"alternates": []
|
|
},
|
|
"Ext.grid.plugin.HeaderReorderer": {
|
|
"idx": 543,
|
|
"alias": [
|
|
"plugin.gridheaderreorderer"
|
|
],
|
|
"alternates": []
|
|
},
|
|
"Ext.grid.plugin.HeaderResizer": {
|
|
"idx": 540,
|
|
"alias": [
|
|
"plugin.gridheaderresizer"
|
|
],
|
|
"alternates": []
|
|
},
|
|
"Ext.grid.plugin.RowEditing": {
|
|
"idx": 585,
|
|
"alias": [
|
|
"plugin.rowediting"
|
|
],
|
|
"alternates": []
|
|
},
|
|
"Ext.grid.plugin.RowExpander": {
|
|
"idx": 586,
|
|
"alias": [
|
|
"plugin.rowexpander"
|
|
],
|
|
"alternates": []
|
|
},
|
|
"Ext.grid.plugin.RowWidget": {
|
|
"idx": 587,
|
|
"alias": [
|
|
"plugin.rowwidget"
|
|
],
|
|
"alternates": []
|
|
},
|
|
"Ext.grid.property.Grid": {
|
|
"idx": 588,
|
|
"alias": [
|
|
"widget.propertygrid"
|
|
],
|
|
"alternates": [
|
|
"Ext.grid.PropertyGrid"
|
|
]
|
|
},
|
|
"Ext.grid.property.HeaderContainer": {
|
|
"idx": 589,
|
|
"alias": [],
|
|
"alternates": [
|
|
"Ext.grid.PropertyColumnModel"
|
|
]
|
|
},
|
|
"Ext.grid.property.Property": {
|
|
"idx": 590,
|
|
"alias": [],
|
|
"alternates": [
|
|
"Ext.PropGridProperty"
|
|
]
|
|
},
|
|
"Ext.grid.property.Reader": {
|
|
"idx": 591,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.grid.property.Store": {
|
|
"idx": 592,
|
|
"alias": [],
|
|
"alternates": [
|
|
"Ext.grid.PropertyStore"
|
|
]
|
|
},
|
|
"Ext.grid.selection.Cells": {
|
|
"idx": 594,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.grid.selection.Columns": {
|
|
"idx": 595,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.grid.selection.Replicator": {
|
|
"idx": 596,
|
|
"alias": [
|
|
"plugin.selectionreplicator"
|
|
],
|
|
"alternates": []
|
|
},
|
|
"Ext.grid.selection.Rows": {
|
|
"idx": 597,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.grid.selection.Selection": {
|
|
"idx": 593,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.grid.selection.SelectionExtender": {
|
|
"idx": 598,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.grid.selection.SpreadsheetModel": {
|
|
"idx": 599,
|
|
"alias": [
|
|
"selection.spreadsheet"
|
|
],
|
|
"alternates": []
|
|
},
|
|
"Ext.layout.Context": {
|
|
"idx": 602,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.layout.ContextItem": {
|
|
"idx": 601,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.layout.Layout": {
|
|
"idx": 373,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.layout.SizeModel": {
|
|
"idx": 372,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.layout.component.Auto": {
|
|
"idx": 385,
|
|
"alias": [
|
|
"layout.autocomponent"
|
|
],
|
|
"alternates": []
|
|
},
|
|
"Ext.layout.component.Body": {
|
|
"idx": 604,
|
|
"alias": [
|
|
"layout.body"
|
|
],
|
|
"alternates": []
|
|
},
|
|
"Ext.layout.component.BoundList": {
|
|
"idx": 489,
|
|
"alias": [
|
|
"layout.boundlist"
|
|
],
|
|
"alternates": []
|
|
},
|
|
"Ext.layout.component.Component": {
|
|
"idx": 384,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.layout.component.Dock": {
|
|
"idx": 419,
|
|
"alias": [
|
|
"layout.dock"
|
|
],
|
|
"alternates": [
|
|
"Ext.layout.component.AbstractDock"
|
|
]
|
|
},
|
|
"Ext.layout.component.FieldSet": {
|
|
"idx": 605,
|
|
"alias": [
|
|
"layout.fieldset"
|
|
],
|
|
"alternates": []
|
|
},
|
|
"Ext.layout.component.ProgressBar": {
|
|
"idx": 386,
|
|
"alias": [
|
|
"layout.progressbar"
|
|
],
|
|
"alternates": []
|
|
},
|
|
"Ext.layout.component.field.FieldContainer": {
|
|
"idx": 467,
|
|
"alias": [
|
|
"layout.fieldcontainer"
|
|
],
|
|
"alternates": []
|
|
},
|
|
"Ext.layout.component.field.HtmlEditor": {
|
|
"idx": 511,
|
|
"alias": [
|
|
"layout.htmleditor"
|
|
],
|
|
"alternates": []
|
|
},
|
|
"Ext.layout.container.Absolute": {
|
|
"idx": 606,
|
|
"alias": [
|
|
"layout.absolute"
|
|
],
|
|
"alternates": [
|
|
"Ext.layout.AbsoluteLayout"
|
|
]
|
|
},
|
|
"Ext.layout.container.Accordion": {
|
|
"idx": 607,
|
|
"alias": [
|
|
"layout.accordion"
|
|
],
|
|
"alternates": [
|
|
"Ext.layout.AccordionLayout"
|
|
]
|
|
},
|
|
"Ext.layout.container.Anchor": {
|
|
"idx": 429,
|
|
"alias": [
|
|
"layout.anchor"
|
|
],
|
|
"alternates": [
|
|
"Ext.layout.AnchorLayout"
|
|
]
|
|
},
|
|
"Ext.layout.container.Auto": {
|
|
"idx": 375,
|
|
"alias": [
|
|
"layout.auto",
|
|
"layout.autocontainer"
|
|
],
|
|
"alternates": []
|
|
},
|
|
"Ext.layout.container.Border": {
|
|
"idx": 609,
|
|
"alias": [
|
|
"layout.border"
|
|
],
|
|
"alternates": [
|
|
"Ext.layout.BorderLayout"
|
|
]
|
|
},
|
|
"Ext.layout.container.Box": {
|
|
"idx": 408,
|
|
"alias": [
|
|
"layout.box"
|
|
],
|
|
"alternates": [
|
|
"Ext.layout.BoxLayout"
|
|
]
|
|
},
|
|
"Ext.layout.container.Card": {
|
|
"idx": 610,
|
|
"alias": [
|
|
"layout.card"
|
|
],
|
|
"alternates": [
|
|
"Ext.layout.CardLayout"
|
|
]
|
|
},
|
|
"Ext.layout.container.Center": {
|
|
"idx": 611,
|
|
"alias": [
|
|
"layout.center",
|
|
"layout.ux.center"
|
|
],
|
|
"alternates": [
|
|
"Ext.ux.layout.Center"
|
|
]
|
|
},
|
|
"Ext.layout.container.CheckboxGroup": {
|
|
"idx": 469,
|
|
"alias": [
|
|
"layout.checkboxgroup"
|
|
],
|
|
"alternates": []
|
|
},
|
|
"Ext.layout.container.Column": {
|
|
"idx": 432,
|
|
"alias": [
|
|
"layout.column"
|
|
],
|
|
"alternates": [
|
|
"Ext.layout.ColumnLayout"
|
|
]
|
|
},
|
|
"Ext.layout.container.ColumnSplitter": {
|
|
"idx": 436,
|
|
"alias": [
|
|
"widget.columnsplitter"
|
|
],
|
|
"alternates": []
|
|
},
|
|
"Ext.layout.container.ColumnSplitterTracker": {
|
|
"idx": 435,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.layout.container.Container": {
|
|
"idx": 374,
|
|
"alias": [
|
|
"layout.container"
|
|
],
|
|
"alternates": [
|
|
"Ext.layout.ContainerLayout"
|
|
]
|
|
},
|
|
"Ext.layout.container.Dashboard": {
|
|
"idx": 437,
|
|
"alias": [
|
|
"layout.dashboard"
|
|
],
|
|
"alternates": []
|
|
},
|
|
"Ext.layout.container.Editor": {
|
|
"idx": 378,
|
|
"alias": [
|
|
"layout.editor"
|
|
],
|
|
"alternates": []
|
|
},
|
|
"Ext.layout.container.Fit": {
|
|
"idx": 523,
|
|
"alias": [
|
|
"layout.fit"
|
|
],
|
|
"alternates": [
|
|
"Ext.layout.FitLayout"
|
|
]
|
|
},
|
|
"Ext.layout.container.Form": {
|
|
"idx": 612,
|
|
"alias": [
|
|
"layout.form"
|
|
],
|
|
"alternates": [
|
|
"Ext.layout.FormLayout"
|
|
]
|
|
},
|
|
"Ext.layout.container.HBox": {
|
|
"idx": 409,
|
|
"alias": [
|
|
"layout.hbox"
|
|
],
|
|
"alternates": [
|
|
"Ext.layout.HBoxLayout"
|
|
]
|
|
},
|
|
"Ext.layout.container.SegmentedButton": {
|
|
"idx": 395,
|
|
"alias": [
|
|
"layout.segmentedbutton"
|
|
],
|
|
"alternates": []
|
|
},
|
|
"Ext.layout.container.Table": {
|
|
"idx": 423,
|
|
"alias": [
|
|
"layout.table"
|
|
],
|
|
"alternates": [
|
|
"Ext.layout.TableLayout"
|
|
]
|
|
},
|
|
"Ext.layout.container.VBox": {
|
|
"idx": 410,
|
|
"alias": [
|
|
"layout.vbox"
|
|
],
|
|
"alternates": [
|
|
"Ext.layout.VBoxLayout"
|
|
]
|
|
},
|
|
"Ext.layout.container.border.Region": {
|
|
"idx": 112,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.layout.container.boxOverflow.Menu": {
|
|
"idx": 513,
|
|
"alias": [
|
|
"box.overflow.Menu",
|
|
"box.overflow.menu"
|
|
],
|
|
"alternates": [
|
|
"Ext.layout.boxOverflow.Menu"
|
|
]
|
|
},
|
|
"Ext.layout.container.boxOverflow.None": {
|
|
"idx": 404,
|
|
"alias": [
|
|
"box.overflow.None",
|
|
"box.overflow.none"
|
|
],
|
|
"alternates": [
|
|
"Ext.layout.boxOverflow.None"
|
|
]
|
|
},
|
|
"Ext.layout.container.boxOverflow.Scroller": {
|
|
"idx": 405,
|
|
"alias": [
|
|
"box.overflow.Scroller",
|
|
"box.overflow.scroller"
|
|
],
|
|
"alternates": [
|
|
"Ext.layout.boxOverflow.Scroller"
|
|
]
|
|
},
|
|
"Ext.list.AbstractTreeItem": {
|
|
"idx": 324,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.list.RootTreeItem": {
|
|
"idx": 325,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.list.Tree": {
|
|
"idx": 327,
|
|
"alias": [
|
|
"widget.treelist"
|
|
],
|
|
"alternates": []
|
|
},
|
|
"Ext.list.TreeItem": {
|
|
"idx": 326,
|
|
"alias": [
|
|
"widget.treelistitem"
|
|
],
|
|
"alternates": []
|
|
},
|
|
"Ext.menu.Bar": {
|
|
"idx": 613,
|
|
"alias": [
|
|
"widget.menubar"
|
|
],
|
|
"alternates": []
|
|
},
|
|
"Ext.menu.CheckItem": {
|
|
"idx": 563,
|
|
"alias": [
|
|
"widget.menucheckitem"
|
|
],
|
|
"alternates": []
|
|
},
|
|
"Ext.menu.ColorPicker": {
|
|
"idx": 614,
|
|
"alias": [
|
|
"widget.colormenu"
|
|
],
|
|
"alternates": []
|
|
},
|
|
"Ext.menu.DatePicker": {
|
|
"idx": 615,
|
|
"alias": [
|
|
"widget.datemenu"
|
|
],
|
|
"alternates": []
|
|
},
|
|
"Ext.menu.Item": {
|
|
"idx": 562,
|
|
"alias": [
|
|
"widget.menuitem"
|
|
],
|
|
"alternates": [
|
|
"Ext.menu.TextItem"
|
|
]
|
|
},
|
|
"Ext.menu.Manager": {
|
|
"idx": 390,
|
|
"alias": [],
|
|
"alternates": [
|
|
"Ext.menu.MenuMgr"
|
|
]
|
|
},
|
|
"Ext.menu.Menu": {
|
|
"idx": 565,
|
|
"alias": [
|
|
"widget.menu"
|
|
],
|
|
"alternates": []
|
|
},
|
|
"Ext.menu.Separator": {
|
|
"idx": 564,
|
|
"alias": [
|
|
"widget.menuseparator"
|
|
],
|
|
"alternates": []
|
|
},
|
|
"Ext.mixin.Accessible": {
|
|
"idx": 109,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.mixin.Bindable": {
|
|
"idx": 80,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.mixin.ComponentDelegation": {
|
|
"idx": 81,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.mixin.ConfigState": {
|
|
"idx": 328,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.mixin.Container": {
|
|
"idx": 329,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.mixin.Dirty": {
|
|
"idx": 187,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.mixin.Factoryable": {
|
|
"idx": 12,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.mixin.Hookable": {
|
|
"idx": 330,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.mixin.Identifiable": {
|
|
"idx": 3,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.mixin.Inheritable": {
|
|
"idx": 79,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.mixin.Keyboard": {
|
|
"idx": 110,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.mixin.Mashup": {
|
|
"idx": 331,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.mixin.Observable": {
|
|
"idx": 4,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.mixin.Pluggable": {
|
|
"idx": 82,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.mixin.Queryable": {
|
|
"idx": 226,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.mixin.Responsive": {
|
|
"idx": 332,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.mixin.Selectable": {
|
|
"idx": 333,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.mixin.StyleCacher": {
|
|
"idx": 334,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.mixin.Templatable": {
|
|
"idx": 38,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.mixin.Traversable": {
|
|
"idx": 335,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.panel.Bar": {
|
|
"idx": 397,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.panel.DD": {
|
|
"idx": 418,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.panel.Header": {
|
|
"idx": 403,
|
|
"alias": [
|
|
"widget.header"
|
|
],
|
|
"alternates": []
|
|
},
|
|
"Ext.panel.Panel": {
|
|
"idx": 422,
|
|
"alias": [
|
|
"widget.panel"
|
|
],
|
|
"alternates": [
|
|
"Ext.Panel"
|
|
]
|
|
},
|
|
"Ext.panel.Pinnable": {
|
|
"idx": 616,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.panel.Proxy": {
|
|
"idx": 417,
|
|
"alias": [],
|
|
"alternates": [
|
|
"Ext.dd.PanelProxy"
|
|
]
|
|
},
|
|
"Ext.panel.Table": {
|
|
"idx": 524,
|
|
"alias": [
|
|
"widget.tablepanel"
|
|
],
|
|
"alternates": []
|
|
},
|
|
"Ext.panel.Title": {
|
|
"idx": 398,
|
|
"alias": [
|
|
"widget.title"
|
|
],
|
|
"alternates": []
|
|
},
|
|
"Ext.panel.Tool": {
|
|
"idx": 399,
|
|
"alias": [
|
|
"widget.tool"
|
|
],
|
|
"alternates": []
|
|
},
|
|
"Ext.parse.Parser": {
|
|
"idx": 206,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.parse.Symbol": {
|
|
"idx": 200,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.parse.Tokenizer": {
|
|
"idx": 199,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.parse.symbol.Constant": {
|
|
"idx": 201,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.parse.symbol.Infix": {
|
|
"idx": 202,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.parse.symbol.InfixRight": {
|
|
"idx": 203,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.parse.symbol.Paren": {
|
|
"idx": 204,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.parse.symbol.Prefix": {
|
|
"idx": 205,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.perf.Accumulator": {
|
|
"idx": 336,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.perf.Monitor": {
|
|
"idx": 337,
|
|
"alias": [],
|
|
"alternates": [
|
|
"Ext.Perf"
|
|
]
|
|
},
|
|
"Ext.picker.Color": {
|
|
"idx": 510,
|
|
"alias": [
|
|
"widget.colorpicker"
|
|
],
|
|
"alternates": [
|
|
"Ext.ColorPalette"
|
|
]
|
|
},
|
|
"Ext.picker.Date": {
|
|
"idx": 499,
|
|
"alias": [
|
|
"widget.datepicker"
|
|
],
|
|
"alternates": [
|
|
"Ext.DatePicker"
|
|
]
|
|
},
|
|
"Ext.picker.Month": {
|
|
"idx": 498,
|
|
"alias": [
|
|
"widget.monthpicker"
|
|
],
|
|
"alternates": [
|
|
"Ext.MonthPicker"
|
|
]
|
|
},
|
|
"Ext.picker.Time": {
|
|
"idx": 517,
|
|
"alias": [
|
|
"widget.timepicker"
|
|
],
|
|
"alternates": []
|
|
},
|
|
"Ext.plugin.Abstract": {
|
|
"idx": 338,
|
|
"alias": [],
|
|
"alternates": [
|
|
"Ext.AbstractPlugin"
|
|
]
|
|
},
|
|
"Ext.plugin.AbstractClipboard": {
|
|
"idx": 582,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.plugin.LazyItems": {
|
|
"idx": 339,
|
|
"alias": [
|
|
"plugin.lazyitems"
|
|
],
|
|
"alternates": []
|
|
},
|
|
"Ext.plugin.Manager": {
|
|
"idx": 617,
|
|
"alias": [],
|
|
"alternates": [
|
|
"Ext.PluginManager",
|
|
"Ext.PluginMgr"
|
|
]
|
|
},
|
|
"Ext.plugin.MouseEnter": {
|
|
"idx": 340,
|
|
"alias": [
|
|
"plugin.mouseenter"
|
|
],
|
|
"alternates": []
|
|
},
|
|
"Ext.plugin.Responsive": {
|
|
"idx": 426,
|
|
"alias": [
|
|
"plugin.responsive"
|
|
],
|
|
"alternates": []
|
|
},
|
|
"Ext.plugin.Viewport": {
|
|
"idx": 427,
|
|
"alias": [
|
|
"plugin.viewport"
|
|
],
|
|
"alternates": []
|
|
},
|
|
"Ext.promise.Consequence": {
|
|
"idx": 7,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.promise.Deferred": {
|
|
"idx": 8,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.promise.Promise": {
|
|
"idx": 9,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.resizer.BorderSplitter": {
|
|
"idx": 608,
|
|
"alias": [
|
|
"widget.bordersplitter"
|
|
],
|
|
"alternates": []
|
|
},
|
|
"Ext.resizer.BorderSplitterTracker": {
|
|
"idx": 618,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.resizer.Handle": {
|
|
"idx": 619,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.resizer.ResizeTracker": {
|
|
"idx": 620,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.resizer.Resizer": {
|
|
"idx": 621,
|
|
"alias": [],
|
|
"alternates": [
|
|
"Ext.Resizable"
|
|
]
|
|
},
|
|
"Ext.resizer.Splitter": {
|
|
"idx": 407,
|
|
"alias": [
|
|
"widget.splitter"
|
|
],
|
|
"alternates": []
|
|
},
|
|
"Ext.resizer.SplitterTracker": {
|
|
"idx": 434,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.scroll.LockingScroller": {
|
|
"idx": 577,
|
|
"alias": [
|
|
"scroller.locking"
|
|
],
|
|
"alternates": []
|
|
},
|
|
"Ext.scroll.Scroller": {
|
|
"idx": 101,
|
|
"alias": [
|
|
"scroller.scroller"
|
|
],
|
|
"alternates": []
|
|
},
|
|
"Ext.scroll.TableScroller": {
|
|
"idx": 531,
|
|
"alias": [
|
|
"scroller.table"
|
|
],
|
|
"alternates": []
|
|
},
|
|
"Ext.selection.CellModel": {
|
|
"idx": 622,
|
|
"alias": [
|
|
"selection.cellmodel"
|
|
],
|
|
"alternates": []
|
|
},
|
|
"Ext.selection.CheckboxModel": {
|
|
"idx": 624,
|
|
"alias": [
|
|
"selection.checkboxmodel"
|
|
],
|
|
"alternates": []
|
|
},
|
|
"Ext.selection.DataViewModel": {
|
|
"idx": 484,
|
|
"alias": [
|
|
"selection.dataviewmodel"
|
|
],
|
|
"alternates": []
|
|
},
|
|
"Ext.selection.Model": {
|
|
"idx": 483,
|
|
"alias": [
|
|
"selection.abstract"
|
|
],
|
|
"alternates": [
|
|
"Ext.AbstractSelectionModel"
|
|
]
|
|
},
|
|
"Ext.selection.RowModel": {
|
|
"idx": 623,
|
|
"alias": [
|
|
"selection.rowmodel"
|
|
],
|
|
"alternates": []
|
|
},
|
|
"Ext.selection.TreeModel": {
|
|
"idx": 625,
|
|
"alias": [
|
|
"selection.treemodel"
|
|
],
|
|
"alternates": []
|
|
},
|
|
"Ext.slider.Multi": {
|
|
"idx": 628,
|
|
"alias": [
|
|
"widget.multislider"
|
|
],
|
|
"alternates": [
|
|
"Ext.slider.MultiSlider"
|
|
]
|
|
},
|
|
"Ext.slider.Single": {
|
|
"idx": 629,
|
|
"alias": [
|
|
"widget.slider",
|
|
"widget.sliderfield"
|
|
],
|
|
"alternates": [
|
|
"Ext.Slider",
|
|
"Ext.form.SliderField",
|
|
"Ext.slider.SingleSlider",
|
|
"Ext.slider.Slider"
|
|
]
|
|
},
|
|
"Ext.slider.Thumb": {
|
|
"idx": 626,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.slider.Tip": {
|
|
"idx": 627,
|
|
"alias": [
|
|
"widget.slidertip"
|
|
],
|
|
"alternates": []
|
|
},
|
|
"Ext.slider.Widget": {
|
|
"idx": 630,
|
|
"alias": [
|
|
"widget.sliderwidget"
|
|
],
|
|
"alternates": []
|
|
},
|
|
"Ext.sparkline.Bar": {
|
|
"idx": 349,
|
|
"alias": [
|
|
"widget.sparklinebar"
|
|
],
|
|
"alternates": []
|
|
},
|
|
"Ext.sparkline.BarBase": {
|
|
"idx": 347,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.sparkline.Base": {
|
|
"idx": 346,
|
|
"alias": [
|
|
"widget.sparkline"
|
|
],
|
|
"alternates": []
|
|
},
|
|
"Ext.sparkline.Box": {
|
|
"idx": 350,
|
|
"alias": [
|
|
"widget.sparklinebox"
|
|
],
|
|
"alternates": []
|
|
},
|
|
"Ext.sparkline.Bullet": {
|
|
"idx": 351,
|
|
"alias": [
|
|
"widget.sparklinebullet"
|
|
],
|
|
"alternates": []
|
|
},
|
|
"Ext.sparkline.CanvasBase": {
|
|
"idx": 342,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.sparkline.CanvasCanvas": {
|
|
"idx": 343,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.sparkline.Discrete": {
|
|
"idx": 352,
|
|
"alias": [
|
|
"widget.sparklinediscrete"
|
|
],
|
|
"alternates": []
|
|
},
|
|
"Ext.sparkline.Line": {
|
|
"idx": 353,
|
|
"alias": [
|
|
"widget.sparklineline"
|
|
],
|
|
"alternates": []
|
|
},
|
|
"Ext.sparkline.Pie": {
|
|
"idx": 354,
|
|
"alias": [
|
|
"widget.sparklinepie"
|
|
],
|
|
"alternates": []
|
|
},
|
|
"Ext.sparkline.RangeMap": {
|
|
"idx": 348,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.sparkline.Shape": {
|
|
"idx": 341,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.sparkline.TriState": {
|
|
"idx": 355,
|
|
"alias": [
|
|
"widget.sparklinetristate"
|
|
],
|
|
"alternates": []
|
|
},
|
|
"Ext.sparkline.VmlCanvas": {
|
|
"idx": 344,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.state.CookieProvider": {
|
|
"idx": 631,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.state.LocalStorageProvider": {
|
|
"idx": 632,
|
|
"alias": [
|
|
"state.localstorage"
|
|
],
|
|
"alternates": []
|
|
},
|
|
"Ext.state.Manager": {
|
|
"idx": 106,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.state.Provider": {
|
|
"idx": 105,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.state.Stateful": {
|
|
"idx": 107,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.tab.Bar": {
|
|
"idx": 634,
|
|
"alias": [
|
|
"widget.tabbar"
|
|
],
|
|
"alternates": []
|
|
},
|
|
"Ext.tab.Panel": {
|
|
"idx": 635,
|
|
"alias": [
|
|
"widget.tabpanel"
|
|
],
|
|
"alternates": [
|
|
"Ext.TabPanel"
|
|
]
|
|
},
|
|
"Ext.tab.Tab": {
|
|
"idx": 633,
|
|
"alias": [
|
|
"widget.tab"
|
|
],
|
|
"alternates": []
|
|
},
|
|
"Ext.tip.QuickTip": {
|
|
"idx": 508,
|
|
"alias": [
|
|
"widget.quicktip"
|
|
],
|
|
"alternates": [
|
|
"Ext.QuickTip"
|
|
]
|
|
},
|
|
"Ext.tip.QuickTipManager": {
|
|
"idx": 509,
|
|
"alias": [],
|
|
"alternates": [
|
|
"Ext.QuickTips"
|
|
]
|
|
},
|
|
"Ext.tip.Tip": {
|
|
"idx": 506,
|
|
"alias": [
|
|
"widget.tip"
|
|
],
|
|
"alternates": [
|
|
"Ext.Tip"
|
|
]
|
|
},
|
|
"Ext.tip.ToolTip": {
|
|
"idx": 507,
|
|
"alias": [
|
|
"widget.tooltip"
|
|
],
|
|
"alternates": [
|
|
"Ext.ToolTip"
|
|
]
|
|
},
|
|
"Ext.toolbar.Breadcrumb": {
|
|
"idx": 636,
|
|
"alias": [
|
|
"widget.breadcrumb"
|
|
],
|
|
"alternates": []
|
|
},
|
|
"Ext.toolbar.Fill": {
|
|
"idx": 637,
|
|
"alias": [
|
|
"widget.tbfill"
|
|
],
|
|
"alternates": [
|
|
"Ext.Toolbar.Fill"
|
|
]
|
|
},
|
|
"Ext.toolbar.Item": {
|
|
"idx": 490,
|
|
"alias": [
|
|
"widget.tbitem"
|
|
],
|
|
"alternates": [
|
|
"Ext.Toolbar.Item"
|
|
]
|
|
},
|
|
"Ext.toolbar.Paging": {
|
|
"idx": 495,
|
|
"alias": [
|
|
"widget.pagingtoolbar"
|
|
],
|
|
"alternates": [
|
|
"Ext.PagingToolbar"
|
|
]
|
|
},
|
|
"Ext.toolbar.Separator": {
|
|
"idx": 512,
|
|
"alias": [
|
|
"widget.tbseparator"
|
|
],
|
|
"alternates": [
|
|
"Ext.Toolbar.Separator"
|
|
]
|
|
},
|
|
"Ext.toolbar.Spacer": {
|
|
"idx": 638,
|
|
"alias": [
|
|
"widget.tbspacer"
|
|
],
|
|
"alternates": [
|
|
"Ext.Toolbar.Spacer"
|
|
]
|
|
},
|
|
"Ext.toolbar.TextItem": {
|
|
"idx": 491,
|
|
"alias": [
|
|
"widget.tbtext"
|
|
],
|
|
"alternates": [
|
|
"Ext.Toolbar.TextItem"
|
|
]
|
|
},
|
|
"Ext.toolbar.Toolbar": {
|
|
"idx": 411,
|
|
"alias": [
|
|
"widget.toolbar"
|
|
],
|
|
"alternates": [
|
|
"Ext.Toolbar"
|
|
]
|
|
},
|
|
"Ext.tree.Column": {
|
|
"idx": 639,
|
|
"alias": [
|
|
"widget.treecolumn"
|
|
],
|
|
"alternates": []
|
|
},
|
|
"Ext.tree.NavigationModel": {
|
|
"idx": 640,
|
|
"alias": [
|
|
"view.navigation.tree"
|
|
],
|
|
"alternates": []
|
|
},
|
|
"Ext.tree.Panel": {
|
|
"idx": 642,
|
|
"alias": [
|
|
"widget.treepanel"
|
|
],
|
|
"alternates": [
|
|
"Ext.tree.TreePanel",
|
|
"Ext.TreePanel"
|
|
]
|
|
},
|
|
"Ext.tree.View": {
|
|
"idx": 641,
|
|
"alias": [
|
|
"widget.treeview"
|
|
],
|
|
"alternates": []
|
|
},
|
|
"Ext.tree.ViewDragZone": {
|
|
"idx": 644,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.tree.ViewDropZone": {
|
|
"idx": 645,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.tree.plugin.TreeViewDragDrop": {
|
|
"idx": 646,
|
|
"alias": [
|
|
"plugin.treeviewdragdrop"
|
|
],
|
|
"alternates": []
|
|
},
|
|
"Ext.util.AbstractMixedCollection": {
|
|
"idx": 52,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.util.Animate": {
|
|
"idx": 73,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.util.Bag": {
|
|
"idx": 178,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.util.Base64": {
|
|
"idx": 356,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.util.CSS": {
|
|
"idx": 95,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.util.CSV": {
|
|
"idx": 358,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.util.ClickRepeater": {
|
|
"idx": 391,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.util.Collection": {
|
|
"idx": 119,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.util.CollectionKey": {
|
|
"idx": 117,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.util.Color": {
|
|
"idx": 345,
|
|
"alias": [],
|
|
"alternates": [
|
|
"Ext.draw.Color"
|
|
]
|
|
},
|
|
"Ext.util.ComponentDragger": {
|
|
"idx": 455,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.util.Cookies": {
|
|
"idx": 647,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.util.DelimitedValue": {
|
|
"idx": 357,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.util.ElementContainer": {
|
|
"idx": 103,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.util.Event": {
|
|
"idx": 2,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.util.Filter": {
|
|
"idx": 50,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.util.FilterCollection": {
|
|
"idx": 162,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.util.Floating": {
|
|
"idx": 102,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.util.Fly": {
|
|
"idx": 198,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.util.Focusable": {
|
|
"idx": 108,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.util.FocusableContainer": {
|
|
"idx": 402,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.util.Format": {
|
|
"idx": 86,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.util.Group": {
|
|
"idx": 160,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.util.GroupCollection": {
|
|
"idx": 163,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.util.Grouper": {
|
|
"idx": 118,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.util.HashMap": {
|
|
"idx": 5,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.util.History": {
|
|
"idx": 171,
|
|
"alias": [],
|
|
"alternates": [
|
|
"Ext.History"
|
|
]
|
|
},
|
|
"Ext.util.Inflector": {
|
|
"idx": 126,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.util.ItemCollection": {
|
|
"idx": 359,
|
|
"alias": [],
|
|
"alternates": [
|
|
"Ext.ItemCollection"
|
|
]
|
|
},
|
|
"Ext.util.KeyMap": {
|
|
"idx": 400,
|
|
"alias": [],
|
|
"alternates": [
|
|
"Ext.KeyMap"
|
|
]
|
|
},
|
|
"Ext.util.KeyNav": {
|
|
"idx": 401,
|
|
"alias": [],
|
|
"alternates": [
|
|
"Ext.KeyNav"
|
|
]
|
|
},
|
|
"Ext.util.LocalStorage": {
|
|
"idx": 360,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.util.LruCache": {
|
|
"idx": 22,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.util.Memento": {
|
|
"idx": 420,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.util.MixedCollection": {
|
|
"idx": 55,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.util.ObjectTemplate": {
|
|
"idx": 120,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.util.Observable": {
|
|
"idx": 51,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.util.Offset": {
|
|
"idx": 32,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.util.PaintMonitor": {
|
|
"idx": 47,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.util.Point": {
|
|
"idx": 34,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.util.Positionable": {
|
|
"idx": 25,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.util.ProtoElement": {
|
|
"idx": 93,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.util.Queue": {
|
|
"idx": 600,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.util.Region": {
|
|
"idx": 33,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.util.Renderable": {
|
|
"idx": 104,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.util.Schedulable": {
|
|
"idx": 189,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.util.Scheduler": {
|
|
"idx": 179,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.util.SizeMonitor": {
|
|
"idx": 43,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.util.Sortable": {
|
|
"idx": 54,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.util.Sorter": {
|
|
"idx": 53,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.util.SorterCollection": {
|
|
"idx": 161,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.util.StoreHolder": {
|
|
"idx": 382,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.util.TSV": {
|
|
"idx": 361,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.util.TaskManager": {
|
|
"idx": 362,
|
|
"alias": [],
|
|
"alternates": [
|
|
"Ext.TaskManager"
|
|
]
|
|
},
|
|
"Ext.util.TaskRunner": {
|
|
"idx": 56,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.util.TextMetrics": {
|
|
"idx": 363,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.util.Translatable": {
|
|
"idx": 367,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.util.XTemplateCompiler": {
|
|
"idx": 89,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.util.XTemplateParser": {
|
|
"idx": 88,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.util.paintmonitor.Abstract": {
|
|
"idx": 45,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.util.paintmonitor.CssAnimation": {
|
|
"idx": 46,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.util.paintmonitor.OverflowChange": {
|
|
"idx": 368,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.util.sizemonitor.Abstract": {
|
|
"idx": 40,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.util.sizemonitor.OverflowChange": {
|
|
"idx": 42,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.util.sizemonitor.Scroll": {
|
|
"idx": 41,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.util.translatable.Abstract": {
|
|
"idx": 98,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.util.translatable.CssPosition": {
|
|
"idx": 366,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.util.translatable.CssTransform": {
|
|
"idx": 364,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.util.translatable.Dom": {
|
|
"idx": 99,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.util.translatable.ScrollParent": {
|
|
"idx": 365,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.util.translatable.ScrollPosition": {
|
|
"idx": 100,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.view.AbstractView": {
|
|
"idx": 486,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.view.BoundList": {
|
|
"idx": 496,
|
|
"alias": [
|
|
"widget.boundlist"
|
|
],
|
|
"alternates": [
|
|
"Ext.BoundList"
|
|
]
|
|
},
|
|
"Ext.view.BoundListKeyNav": {
|
|
"idx": 488,
|
|
"alias": [
|
|
"view.navigation.boundlist"
|
|
],
|
|
"alternates": []
|
|
},
|
|
"Ext.view.DragZone": {
|
|
"idx": 643,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.view.DropZone": {
|
|
"idx": 538,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.view.MultiSelector": {
|
|
"idx": 649,
|
|
"alias": [
|
|
"widget.multiselector"
|
|
],
|
|
"alternates": []
|
|
},
|
|
"Ext.view.MultiSelectorSearch": {
|
|
"idx": 648,
|
|
"alias": [
|
|
"widget.multiselector-search"
|
|
],
|
|
"alternates": []
|
|
},
|
|
"Ext.view.NavigationModel": {
|
|
"idx": 485,
|
|
"alias": [
|
|
"view.navigation.default"
|
|
],
|
|
"alternates": []
|
|
},
|
|
"Ext.view.NodeCache": {
|
|
"idx": 530,
|
|
"alias": [],
|
|
"alternates": []
|
|
},
|
|
"Ext.view.Table": {
|
|
"idx": 532,
|
|
"alias": [
|
|
"widget.gridview",
|
|
"widget.tableview"
|
|
],
|
|
"alternates": [
|
|
"Ext.grid.View"
|
|
]
|
|
},
|
|
"Ext.view.TableLayout": {
|
|
"idx": 528,
|
|
"alias": [
|
|
"layout.tableview"
|
|
],
|
|
"alternates": []
|
|
},
|
|
"Ext.view.TagKeyNav": {
|
|
"idx": 515,
|
|
"alias": [
|
|
"view.navigation.tagfield"
|
|
],
|
|
"alternates": []
|
|
},
|
|
"Ext.view.View": {
|
|
"idx": 487,
|
|
"alias": [
|
|
"widget.dataview"
|
|
],
|
|
"alternates": [
|
|
"Ext.DataView"
|
|
]
|
|
},
|
|
"Ext.window.MessageBox": {
|
|
"idx": 464,
|
|
"alias": [
|
|
"widget.messagebox"
|
|
],
|
|
"alternates": []
|
|
},
|
|
"Ext.window.Toast": {
|
|
"idx": 650,
|
|
"alias": [
|
|
"widget.toast"
|
|
],
|
|
"alternates": []
|
|
},
|
|
"Ext.window.Window": {
|
|
"idx": 456,
|
|
"alias": [
|
|
"widget.window"
|
|
],
|
|
"alternates": [
|
|
"Ext.Window"
|
|
]
|
|
}
|
|
},
|
|
"packages": {
|
|
"classic": {
|
|
"build": {
|
|
"dir": "${package.output}"
|
|
},
|
|
"creator": "Sencha",
|
|
"namespace": "Ext",
|
|
"requires": [
|
|
"ext",
|
|
"core",
|
|
"classic"
|
|
],
|
|
"type": "toolkit",
|
|
"version": "6.2.0.981"
|
|
},
|
|
"cmd": {
|
|
"version": "6.2.0.103"
|
|
},
|
|
"core": {
|
|
"alternateName": [
|
|
"sencha-core"
|
|
],
|
|
"creator": "Sencha",
|
|
"requires": [
|
|
"ext"
|
|
],
|
|
"type": "code",
|
|
"version": "6.2.0.981"
|
|
},
|
|
"ext": {
|
|
"build": {
|
|
"dir": "${package.output.base}"
|
|
},
|
|
"creator": "Sencha",
|
|
"license": "gpl",
|
|
"namespace": "Ext",
|
|
"requires": [],
|
|
"resource": {
|
|
"paths": [
|
|
"resources"
|
|
]
|
|
},
|
|
"type": "framework",
|
|
"version": "6.2.0.981"
|
|
}
|
|
},
|
|
"bootRelative": true
|
|
});
|
|
// @tag core
|
|
// @define Ext.Boot
|
|
var Ext = Ext || {};
|
|
//<editor-fold desc="Boot">
|
|
/**
|
|
* @class Ext.Boot
|
|
* @singleton
|
|
* @private
|
|
*/
|
|
Ext.Boot = Ext.Boot || (function(emptyFn) {
|
|
var doc = document,
|
|
_emptyArray = [],
|
|
_config = {
|
|
/**
|
|
* @cfg {Boolean} [disableCaching=true]
|
|
* If `true` current timestamp is added to script URL's to prevent caching.
|
|
* In debug builds, adding a "cache" or "disableCacheBuster" query parameter
|
|
* to the page's URL will set this to `false`.
|
|
*/
|
|
disableCaching: (/[?&](?:cache|disableCacheBuster)\b/i.test(location.search) || !(/http[s]?\:/i.test(location.href)) || /(^|[ ;])ext-cache=1/.test(doc.cookie)) ? false : true,
|
|
/**
|
|
* @cfg {String} [disableCachingParam="_dc"]
|
|
* The query parameter name for the cache buster's timestamp.
|
|
*/
|
|
disableCachingParam: '_dc',
|
|
/**
|
|
* @cfg {Boolean} loadDelay
|
|
* Millisecond delay between asynchronous script injection (prevents stack
|
|
* overflow on some user agents) 'false' disables delay but potentially
|
|
* increases stack load.
|
|
*/
|
|
loadDelay: false,
|
|
/**
|
|
* @cfg {Boolean} preserveScripts
|
|
* `false` to remove asynchronously loaded scripts, `true` to retain script
|
|
* element for browser debugger compatibility and improved load performance.
|
|
*/
|
|
preserveScripts: true,
|
|
/**
|
|
* @cfg {String} [charset=UTF-8]
|
|
* Optional charset to specify encoding of dynamic content.
|
|
*/
|
|
charset: 'UTF-8'
|
|
},
|
|
_assetConfig = {},
|
|
cssRe = /\.css(?:\?|$)/i,
|
|
resolverEl = doc.createElement('a'),
|
|
isBrowser = typeof window !== 'undefined',
|
|
_environment = {
|
|
browser: isBrowser,
|
|
node: !isBrowser && (typeof require === 'function'),
|
|
phantom: (window && (window._phantom || window.callPhantom)) || /PhantomJS/.test(window.navigator.userAgent)
|
|
},
|
|
_tags = (Ext.platformTags = {}),
|
|
// All calls to _debug are commented out to speed up old browsers a bit;
|
|
// yes that makes a difference because the cost of concatenating strings
|
|
// and passing them into _debug() adds up pretty quickly.
|
|
_debug = function(message) {},
|
|
//console.log(message);
|
|
_apply = function(object, config, defaults) {
|
|
if (defaults) {
|
|
_apply(object, defaults);
|
|
}
|
|
if (object && config && typeof config === 'object') {
|
|
for (var i in config) {
|
|
object[i] = config[i];
|
|
}
|
|
}
|
|
return object;
|
|
},
|
|
_merge = function() {
|
|
var lowerCase = false,
|
|
obj = Array.prototype.shift.call(arguments),
|
|
index, i, len, value;
|
|
if (typeof arguments[arguments.length - 1] === 'boolean') {
|
|
lowerCase = Array.prototype.pop.call(arguments);
|
|
}
|
|
len = arguments.length;
|
|
for (index = 0; index < len; index++) {
|
|
value = arguments[index];
|
|
if (typeof value === 'object') {
|
|
for (i in value) {
|
|
obj[lowerCase ? i.toLowerCase() : i] = value[i];
|
|
}
|
|
}
|
|
}
|
|
return obj;
|
|
},
|
|
_getKeys = (typeof Object.keys == 'function') ? function(object) {
|
|
if (!object) {
|
|
return [];
|
|
}
|
|
return Object.keys(object);
|
|
} : function(object) {
|
|
var keys = [],
|
|
property;
|
|
for (property in object) {
|
|
if (object.hasOwnProperty(property)) {
|
|
keys.push(property);
|
|
}
|
|
}
|
|
return keys;
|
|
},
|
|
/*
|
|
* The Boot loader class manages Request objects that contain one or
|
|
* more individual urls that need to be loaded. Requests can be performed
|
|
* synchronously or asynchronously, but will always evaluate urls in the
|
|
* order specified on the request object.
|
|
*/
|
|
Boot = {
|
|
loading: 0,
|
|
loaded: 0,
|
|
apply: _apply,
|
|
env: _environment,
|
|
config: _config,
|
|
/**
|
|
* @cfg {Object} assetConfig
|
|
* A map (url->assetConfig) that contains information about assets loaded by the Microlaoder.
|
|
*/
|
|
assetConfig: _assetConfig,
|
|
// Keyed by absolute URL this object holds "true" if that URL is already loaded
|
|
// or an array of callbacks to call once it loads.
|
|
scripts: {},
|
|
/*
|
|
Entry objects
|
|
|
|
'http://foo.com/bar/baz/Thing.js': {
|
|
done: true,
|
|
el: scriptEl || linkEl,
|
|
preserve: true,
|
|
requests: [ request1, ... ]
|
|
}
|
|
*/
|
|
/**
|
|
* contains the current script name being loaded
|
|
* (loadSync or sequential load only)
|
|
*/
|
|
currentFile: null,
|
|
suspendedQueue: [],
|
|
currentRequest: null,
|
|
// when loadSync is called, need to cause subsequent load requests to also be loadSync,
|
|
// eg, when Ext.require(...) is called
|
|
syncMode: false,
|
|
/*
|
|
* simple helper method for debugging
|
|
*/
|
|
debug: _debug,
|
|
/**
|
|
* enables / disables loading scripts via script / link elements rather
|
|
* than using ajax / eval
|
|
*/
|
|
useElements: true,
|
|
listeners: [],
|
|
Request: Request,
|
|
Entry: Entry,
|
|
allowMultipleBrowsers: false,
|
|
browserNames: {
|
|
ie: 'IE',
|
|
firefox: 'Firefox',
|
|
safari: 'Safari',
|
|
chrome: 'Chrome',
|
|
opera: 'Opera',
|
|
dolfin: 'Dolfin',
|
|
edge: 'Edge',
|
|
webosbrowser: 'webOSBrowser',
|
|
chromeMobile: 'ChromeMobile',
|
|
chromeiOS: 'ChromeiOS',
|
|
silk: 'Silk',
|
|
other: 'Other'
|
|
},
|
|
osNames: {
|
|
ios: 'iOS',
|
|
android: 'Android',
|
|
windowsPhone: 'WindowsPhone',
|
|
webos: 'webOS',
|
|
blackberry: 'BlackBerry',
|
|
rimTablet: 'RIMTablet',
|
|
mac: 'MacOS',
|
|
win: 'Windows',
|
|
tizen: 'Tizen',
|
|
linux: 'Linux',
|
|
bada: 'Bada',
|
|
chromeOS: 'ChromeOS',
|
|
other: 'Other'
|
|
},
|
|
browserPrefixes: {
|
|
ie: 'MSIE ',
|
|
edge: 'Edge/',
|
|
firefox: 'Firefox/',
|
|
chrome: 'Chrome/',
|
|
safari: 'Version/',
|
|
opera: 'OPR/',
|
|
dolfin: 'Dolfin/',
|
|
webosbrowser: 'wOSBrowser/',
|
|
chromeMobile: 'CrMo/',
|
|
chromeiOS: 'CriOS/',
|
|
silk: 'Silk/'
|
|
},
|
|
// When a UA reports multiple browsers this list is used to prioritize the 'real' browser
|
|
// lower index number will win
|
|
browserPriority: [
|
|
'edge',
|
|
'opera',
|
|
'dolfin',
|
|
'webosbrowser',
|
|
'silk',
|
|
'chromeiOS',
|
|
'chromeMobile',
|
|
'ie',
|
|
'firefox',
|
|
'safari',
|
|
'chrome'
|
|
],
|
|
osPrefixes: {
|
|
tizen: '(Tizen )',
|
|
ios: 'i(?:Pad|Phone|Pod)(?:.*)CPU(?: iPhone)? OS ',
|
|
android: '(Android |HTC_|Silk/)',
|
|
// Some HTC devices ship with an OSX userAgent by default,
|
|
// so we need to add a direct check for HTC_
|
|
windowsPhone: 'Windows Phone ',
|
|
blackberry: '(?:BlackBerry|BB)(?:.*)Version/',
|
|
rimTablet: 'RIM Tablet OS ',
|
|
webos: '(?:webOS|hpwOS)/',
|
|
bada: 'Bada/',
|
|
chromeOS: 'CrOS '
|
|
},
|
|
fallbackOSPrefixes: {
|
|
windows: 'win',
|
|
mac: 'mac',
|
|
linux: 'linux'
|
|
},
|
|
devicePrefixes: {
|
|
iPhone: 'iPhone',
|
|
iPod: 'iPod',
|
|
iPad: 'iPad'
|
|
},
|
|
maxIEVersion: 12,
|
|
/**
|
|
* The default function that detects various platforms and sets tags
|
|
* in the platform map accordingly. Examples are iOS, android, tablet, etc.
|
|
* @param tags the set of tags to populate
|
|
*/
|
|
detectPlatformTags: function() {
|
|
var me = this,
|
|
ua = navigator.userAgent,
|
|
isMobile = /Mobile(\/|\s)/.test(ua),
|
|
element = document.createElement('div'),
|
|
isEventSupported = function(name, tag) {
|
|
if (tag === undefined) {
|
|
tag = window;
|
|
}
|
|
var eventName = 'on' + name.toLowerCase(),
|
|
isSupported = (eventName in element);
|
|
if (!isSupported) {
|
|
if (element.setAttribute && element.removeAttribute) {
|
|
element.setAttribute(eventName, '');
|
|
isSupported = typeof element[eventName] === 'function';
|
|
if (typeof element[eventName] !== 'undefined') {
|
|
element[eventName] = undefined;
|
|
}
|
|
element.removeAttribute(eventName);
|
|
}
|
|
}
|
|
return isSupported;
|
|
},
|
|
// Browser Detection
|
|
getBrowsers = function() {
|
|
var browsers = {},
|
|
maxIEVersion, prefix, value, key, index, len, match, version, matched;
|
|
// MS Edge browser (and possibly others) can report multiple browsers in the UserAgent
|
|
// "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.135 Safari/537.36 Edge/12.10240"
|
|
// we use this to prioritize the actual browser in this situation
|
|
len = me.browserPriority.length;
|
|
for (index = 0; index < len; index++) {
|
|
key = me.browserPriority[index];
|
|
if (!matched) {
|
|
value = me.browserPrefixes[key];
|
|
match = ua.match(new RegExp('(' + value + ')([\\w\\._]+)'));
|
|
version = match && match.length > 1 ? parseInt(match[2]) : 0;
|
|
if (version) {
|
|
matched = true;
|
|
}
|
|
} else {
|
|
version = 0;
|
|
}
|
|
browsers[key] = version;
|
|
}
|
|
//Deal with IE document mode
|
|
if (browsers.ie) {
|
|
var mode = document.documentMode;
|
|
if (mode >= 8) {
|
|
browsers.ie = mode;
|
|
}
|
|
}
|
|
// Fancy IE greater than and less then quick tags
|
|
version = browsers.ie || false;
|
|
maxIEVersion = Math.max(version, me.maxIEVersion);
|
|
for (index = 8; index <= maxIEVersion; ++index) {
|
|
prefix = 'ie' + index;
|
|
browsers[prefix + 'm'] = version ? version <= index : 0;
|
|
browsers[prefix] = version ? version === index : 0;
|
|
browsers[prefix + 'p'] = version ? version >= index : 0;
|
|
}
|
|
return browsers;
|
|
},
|
|
//OS Detection
|
|
getOperatingSystems = function() {
|
|
var systems = {},
|
|
value, key, keys, index, len, match, matched, version, activeCount;
|
|
keys = _getKeys(me.osPrefixes);
|
|
len = keys.length;
|
|
for (index = 0 , activeCount = 0; index < len; index++) {
|
|
key = keys[index];
|
|
value = me.osPrefixes[key];
|
|
match = ua.match(new RegExp('(' + value + ')([^\\s;]+)'));
|
|
matched = match ? match[1] : null;
|
|
// This is here because some HTC android devices show an OSX Snow Leopard userAgent by default.
|
|
// And the Kindle Fire doesn't have any indicator of Android as the OS in its User Agent
|
|
if (matched && (matched === 'HTC_' || matched === 'Silk/')) {
|
|
version = 2.3;
|
|
} else {
|
|
version = match && match.length > 1 ? parseFloat(match[match.length - 1]) : 0;
|
|
}
|
|
if (version) {
|
|
activeCount++;
|
|
}
|
|
systems[key] = version;
|
|
}
|
|
keys = _getKeys(me.fallbackOSPrefixes);
|
|
// If no OS could be found we resort to the fallbacks, otherwise we just
|
|
// falsify the fallbacks
|
|
len = keys.length;
|
|
for (index = 0; index < len; index++) {
|
|
key = keys[index];
|
|
// No OS was detected from osPrefixes
|
|
if (activeCount === 0) {
|
|
value = me.fallbackOSPrefixes[key];
|
|
match = ua.toLowerCase().match(new RegExp(value));
|
|
systems[key] = match ? true : 0;
|
|
} else {
|
|
systems[key] = 0;
|
|
}
|
|
}
|
|
return systems;
|
|
},
|
|
// Device Detection
|
|
getDevices = function() {
|
|
var devices = {},
|
|
value, key, keys, index, len, match;
|
|
keys = _getKeys(me.devicePrefixes);
|
|
len = keys.length;
|
|
for (index = 0; index < len; index++) {
|
|
key = keys[index];
|
|
value = me.devicePrefixes[key];
|
|
match = ua.match(new RegExp(value));
|
|
devices[key] = match ? true : 0;
|
|
}
|
|
return devices;
|
|
},
|
|
browsers = getBrowsers(),
|
|
systems = getOperatingSystems(),
|
|
devices = getDevices(),
|
|
platformParams = Boot.loadPlatformsParam();
|
|
// We apply platformParams from the query here first to allow for forced user valued
|
|
// to be used in calculation of generated tags
|
|
_merge(_tags, browsers, systems, devices, platformParams, true);
|
|
_tags.phone = !!((_tags.iphone || _tags.ipod) || (!_tags.silk && (_tags.android && (_tags.android < 3 || isMobile))) || (_tags.blackberry && isMobile) || (_tags.windowsphone));
|
|
_tags.tablet = !!(!_tags.phone && (_tags.ipad || _tags.android || _tags.silk || _tags.rimtablet || (_tags.ie10 && /; Touch/.test(ua))));
|
|
_tags.touch = // if the browser has touch events we can be reasonably sure the device has
|
|
// a touch screen
|
|
isEventSupported('touchend') || // browsers that use pointer event have maxTouchPoints > 0 if the
|
|
// device supports touch input
|
|
// http://www.w3.org/TR/pointerevents/#widl-Navigator-maxTouchPoints
|
|
navigator.maxTouchPoints || // IE10 uses a vendor-prefixed maxTouchPoints property
|
|
navigator.msMaxTouchPoints;
|
|
_tags.desktop = !_tags.phone && !_tags.tablet;
|
|
_tags.cordova = _tags.phonegap = !!(window.PhoneGap || window.Cordova || window.cordova);
|
|
_tags.webview = /(iPhone|iPod|iPad).*AppleWebKit(?!.*Safari)(?!.*FBAN)/i.test(ua);
|
|
_tags.androidstock = (_tags.android <= 4.3) && (_tags.safari || _tags.silk);
|
|
// Re-apply any query params here to allow for user override of generated tags (desktop, touch, tablet, etc)
|
|
_merge(_tags, platformParams, true);
|
|
},
|
|
/**
|
|
* Extracts user supplied platform tags from the "platformTags" query parameter
|
|
* of the form:
|
|
*
|
|
* ?platformTags=name:state,name:state,...
|
|
*
|
|
* (each tag defaults to true when state is unspecified)
|
|
*
|
|
* Example:
|
|
*
|
|
* ?platformTags=isTablet,isPhone:false,isDesktop:0,iOS:1,Safari:true, ...
|
|
*
|
|
* @returns {Object} the platform tags supplied by the query string
|
|
*/
|
|
loadPlatformsParam: function() {
|
|
// Check if the ?platform parameter is set in the URL
|
|
var paramsString = window.location.search.substr(1),
|
|
paramsArray = paramsString.split("&"),
|
|
params = {},
|
|
i,
|
|
platforms = {},
|
|
tmpArray, tmplen, platform, name, enabled;
|
|
for (i = 0; i < paramsArray.length; i++) {
|
|
tmpArray = paramsArray[i].split("=");
|
|
params[tmpArray[0]] = tmpArray[1];
|
|
}
|
|
if (params.platformTags) {
|
|
tmpArray = params.platformTags.split(",");
|
|
for (tmplen = tmpArray.length , i = 0; i < tmplen; i++) {
|
|
platform = tmpArray[i].split(":");
|
|
name = platform[0];
|
|
enabled = true;
|
|
if (platform.length > 1) {
|
|
enabled = platform[1];
|
|
if (enabled === 'false' || enabled === '0') {
|
|
enabled = false;
|
|
}
|
|
}
|
|
platforms[name] = enabled;
|
|
}
|
|
}
|
|
return platforms;
|
|
},
|
|
filterPlatform: function(platform, excludes) {
|
|
platform = _emptyArray.concat(platform || _emptyArray);
|
|
excludes = _emptyArray.concat(excludes || _emptyArray);
|
|
var plen = platform.length,
|
|
elen = excludes.length,
|
|
include = (!plen && elen),
|
|
// default true if only excludes specified
|
|
i, tag;
|
|
for (i = 0; i < plen && !include; i++) {
|
|
tag = platform[i];
|
|
include = !!_tags[tag];
|
|
}
|
|
for (i = 0; i < elen && include; i++) {
|
|
tag = excludes[i];
|
|
include = !_tags[tag];
|
|
}
|
|
return include;
|
|
},
|
|
init: function() {
|
|
var scriptEls = doc.getElementsByTagName('script'),
|
|
script = scriptEls[0],
|
|
len = scriptEls.length,
|
|
re = /\/ext(\-[a-z\-]+)?\.js$/,
|
|
entry, src, state, baseUrl, key, n, origin;
|
|
// No check for script definedness because there always should be at least one
|
|
Boot.hasReadyState = ("readyState" in script);
|
|
Boot.hasAsync = ("async" in script);
|
|
Boot.hasDefer = ("defer" in script);
|
|
Boot.hasOnLoad = ("onload" in script);
|
|
// Feature detecting IE
|
|
Boot.isIE8 = Boot.hasReadyState && !Boot.hasAsync && Boot.hasDefer && !Boot.hasOnLoad;
|
|
Boot.isIE9 = Boot.hasReadyState && !Boot.hasAsync && Boot.hasDefer && Boot.hasOnLoad;
|
|
Boot.isIE10p = Boot.hasReadyState && Boot.hasAsync && Boot.hasDefer && Boot.hasOnLoad;
|
|
Boot.isIE10 = (new Function('/*@cc_on return @_jscript_version @*/')()) === 10;
|
|
Boot.isIE10m = Boot.isIE10 || Boot.isIE9 || Boot.isIE8;
|
|
// IE11 does not support conditional compilation so we detect it by exclusion
|
|
Boot.isIE11 = Boot.isIE10p && !Boot.isIE10;
|
|
// Since we are loading after other scripts, and we needed to gather them
|
|
// anyway, we track them in _scripts so we don't have to ask for them all
|
|
// repeatedly.
|
|
for (n = 0; n < len; n++) {
|
|
src = (script = scriptEls[n]).src;
|
|
if (!src) {
|
|
|
|
continue;
|
|
}
|
|
state = script.readyState || null;
|
|
// If we find a script file called "ext-*.js", then the base path is that file's base path.
|
|
if (!baseUrl && re.test(src)) {
|
|
baseUrl = src;
|
|
}
|
|
if (!Boot.scripts[key = Boot.canonicalUrl(src)]) {
|
|
// _debug("creating entry " + key + " in Boot.init");
|
|
entry = new Entry({
|
|
key: key,
|
|
url: src,
|
|
done: state === null || // non-IE
|
|
state === 'loaded' || state === 'complete',
|
|
// IE only
|
|
el: script,
|
|
prop: 'src'
|
|
});
|
|
}
|
|
}
|
|
if (!baseUrl) {
|
|
script = scriptEls[scriptEls.length - 1];
|
|
baseUrl = script.src;
|
|
}
|
|
Boot.baseUrl = baseUrl.substring(0, baseUrl.lastIndexOf('/') + 1);
|
|
origin = window.location.origin || window.location.protocol + "//" + window.location.hostname + (window.location.port ? ':' + window.location.port : '');
|
|
Boot.origin = origin;
|
|
Boot.detectPlatformTags();
|
|
Ext.filterPlatform = Boot.filterPlatform;
|
|
},
|
|
/**
|
|
* This method returns a canonical URL for the given URL.
|
|
*
|
|
* For example, the following all produce the same canonical URL (which is the
|
|
* last one):
|
|
*
|
|
* http://foo.com/bar/baz/zoo/derp/../../goo/Thing.js?_dc=12345
|
|
* http://foo.com/bar/baz/zoo/derp/../../goo/Thing.js
|
|
* http://foo.com/bar/baz/zoo/derp/../jazz/../../goo/Thing.js
|
|
* http://foo.com/bar/baz/zoo/../goo/Thing.js
|
|
* http://foo.com/bar/baz/goo/Thing.js
|
|
*
|
|
* @private
|
|
*/
|
|
canonicalUrl: function(url) {
|
|
// *WARNING WARNING WARNING*
|
|
// This method yields the most correct result we can get but it is EXPENSIVE!
|
|
// In ALL browsers! When called multiple times in a sequence, as if when
|
|
// we resolve dependencies for entries, it will cause garbage collection events
|
|
// and overall painful slowness. This is why we try to avoid it as much as we can.
|
|
//
|
|
// @TODO - see if we need this fallback logic
|
|
// http://stackoverflow.com/questions/470832/getting-an-absolute-url-from-a-relative-one-ie6-issue
|
|
resolverEl.href = url;
|
|
var ret = resolverEl.href,
|
|
dc = _config.disableCachingParam,
|
|
pos = dc ? ret.indexOf(dc + '=') : -1,
|
|
c, end;
|
|
// If we have a _dc query parameter we need to remove it from the canonical
|
|
// URL.
|
|
if (pos > 0 && ((c = ret.charAt(pos - 1)) === '?' || c === '&')) {
|
|
end = ret.indexOf('&', pos);
|
|
end = (end < 0) ? '' : ret.substring(end);
|
|
if (end && c === '?') {
|
|
++pos;
|
|
// keep the '?'
|
|
end = end.substring(1);
|
|
}
|
|
// remove the '&'
|
|
ret = ret.substring(0, pos - 1) + end;
|
|
}
|
|
return ret;
|
|
},
|
|
/**
|
|
* Get the config value corresponding to the specified name. If no name is given, will return the config object
|
|
* @param {String} name The config property name
|
|
* @return {Object}
|
|
*/
|
|
getConfig: function(name) {
|
|
return name ? Boot.config[name] : Boot.config;
|
|
},
|
|
/**
|
|
* Set the configuration.
|
|
* @param {Object} config The config object to override the default values.
|
|
* @return {Ext.Boot} this
|
|
*/
|
|
setConfig: function(name, value) {
|
|
if (typeof name === 'string') {
|
|
Boot.config[name] = value;
|
|
} else {
|
|
for (var s in name) {
|
|
Boot.setConfig(s, name[s]);
|
|
}
|
|
}
|
|
return Boot;
|
|
},
|
|
getHead: function() {
|
|
return Boot.docHead || (Boot.docHead = doc.head || doc.getElementsByTagName('head')[0]);
|
|
},
|
|
create: function(url, key, cfg) {
|
|
var config = cfg || {};
|
|
config.url = url;
|
|
config.key = key;
|
|
return Boot.scripts[key] = new Entry(config);
|
|
},
|
|
getEntry: function(url, cfg, canonicalPath) {
|
|
var key, entry;
|
|
// Canonicalizing URLs via anchor element href yields the most correct result
|
|
// but is *extremely* resource heavy so we need to avoid it whenever possible
|
|
key = canonicalPath ? url : Boot.canonicalUrl(url);
|
|
entry = Boot.scripts[key];
|
|
if (!entry) {
|
|
entry = Boot.create(url, key, cfg);
|
|
if (canonicalPath) {
|
|
entry.canonicalPath = true;
|
|
}
|
|
}
|
|
return entry;
|
|
},
|
|
registerContent: function(url, type, content) {
|
|
var cfg = {
|
|
content: content,
|
|
loaded: true,
|
|
css: type === 'css'
|
|
};
|
|
return Boot.getEntry(url, cfg);
|
|
},
|
|
processRequest: function(request, sync) {
|
|
request.loadEntries(sync);
|
|
},
|
|
load: function(request) {
|
|
// _debug("Boot.load called");
|
|
var request = new Request(request);
|
|
if (request.sync || Boot.syncMode) {
|
|
return Boot.loadSync(request);
|
|
}
|
|
// If there is a request in progress, we must
|
|
// queue this new request to be fired when the current request completes.
|
|
if (Boot.currentRequest) {
|
|
// _debug("current active request, suspending this request");
|
|
// trigger assignment of entries now to ensure that overlapping
|
|
// entries with currently running requests will synchronize state
|
|
// with this pending one as they complete
|
|
request.getEntries();
|
|
Boot.suspendedQueue.push(request);
|
|
} else {
|
|
Boot.currentRequest = request;
|
|
Boot.processRequest(request, false);
|
|
}
|
|
return Boot;
|
|
},
|
|
loadSync: function(request) {
|
|
// _debug("Boot.loadSync called");
|
|
var request = new Request(request);
|
|
Boot.syncMode++;
|
|
Boot.processRequest(request, true);
|
|
Boot.syncMode--;
|
|
return Boot;
|
|
},
|
|
loadBasePrefix: function(request) {
|
|
request = new Request(request);
|
|
request.prependBaseUrl = true;
|
|
return Boot.load(request);
|
|
},
|
|
loadSyncBasePrefix: function(request) {
|
|
request = new Request(request);
|
|
request.prependBaseUrl = true;
|
|
return Boot.loadSync(request);
|
|
},
|
|
requestComplete: function(request) {
|
|
var next;
|
|
if (Boot.currentRequest === request) {
|
|
Boot.currentRequest = null;
|
|
while (Boot.suspendedQueue.length > 0) {
|
|
next = Boot.suspendedQueue.shift();
|
|
if (!next.done) {
|
|
// _debug("resuming suspended request");
|
|
Boot.load(next);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (!Boot.currentRequest && Boot.suspendedQueue.length == 0) {
|
|
Boot.fireListeners();
|
|
}
|
|
},
|
|
isLoading: function() {
|
|
return !Boot.currentRequest && Boot.suspendedQueue.length == 0;
|
|
},
|
|
fireListeners: function() {
|
|
var listener;
|
|
while (Boot.isLoading() && (listener = Boot.listeners.shift())) {
|
|
listener();
|
|
}
|
|
},
|
|
onBootReady: function(listener) {
|
|
if (!Boot.isLoading()) {
|
|
listener();
|
|
} else {
|
|
Boot.listeners.push(listener);
|
|
}
|
|
},
|
|
/**
|
|
* this is a helper function used by Ext.Loader to flush out
|
|
* 'uses' arrays for classes in some Ext versions
|
|
*/
|
|
getPathsFromIndexes: function(indexMap, loadOrder) {
|
|
// In older versions indexMap was an object instead of a sparse array
|
|
if (!('length' in indexMap)) {
|
|
var indexArray = [],
|
|
index;
|
|
for (index in indexMap) {
|
|
if (!isNaN(+index)) {
|
|
indexArray[+index] = indexMap[index];
|
|
}
|
|
}
|
|
indexMap = indexArray;
|
|
}
|
|
return Request.prototype.getPathsFromIndexes(indexMap, loadOrder);
|
|
},
|
|
createLoadOrderMap: function(loadOrder) {
|
|
return Request.prototype.createLoadOrderMap(loadOrder);
|
|
},
|
|
fetch: function(url, complete, scope, async) {
|
|
async = (async === undefined) ? !!complete : async;
|
|
var xhr = new XMLHttpRequest(),
|
|
result, status, content,
|
|
exception = false,
|
|
readyStateChange = function() {
|
|
if (xhr && xhr.readyState == 4) {
|
|
status = (xhr.status === 1223) ? 204 : (xhr.status === 0 && ((self.location || {}).protocol === 'file:' || (self.location || {}).protocol === 'ionp:')) ? 200 : xhr.status;
|
|
content = xhr.responseText;
|
|
result = {
|
|
content: content,
|
|
status: status,
|
|
exception: exception
|
|
};
|
|
if (complete) {
|
|
complete.call(scope, result);
|
|
}
|
|
xhr.onreadystatechange = emptyFn;
|
|
xhr = null;
|
|
}
|
|
};
|
|
if (async) {
|
|
xhr.onreadystatechange = readyStateChange;
|
|
}
|
|
try {
|
|
// _debug("fetching " + url + " " + (async ? "async" : "sync"));
|
|
xhr.open('GET', url, async);
|
|
xhr.send(null);
|
|
} catch (err) {
|
|
exception = err;
|
|
readyStateChange();
|
|
return result;
|
|
}
|
|
if (!async) {
|
|
readyStateChange();
|
|
}
|
|
return result;
|
|
},
|
|
notifyAll: function(entry) {
|
|
entry.notifyRequests();
|
|
}
|
|
};
|
|
function Request(cfg) {
|
|
//The request class encapsulates a series of Entry objects
|
|
//and provides notification around the completion of all Entries
|
|
//in this request.
|
|
if (cfg.$isRequest) {
|
|
return cfg;
|
|
}
|
|
var cfg = cfg.url ? cfg : {
|
|
url: cfg
|
|
},
|
|
url = cfg.url,
|
|
urls = url.charAt ? [
|
|
url
|
|
] : url,
|
|
charset = cfg.charset || Boot.config.charset;
|
|
_apply(this, cfg);
|
|
delete this.url;
|
|
this.urls = urls;
|
|
this.charset = charset;
|
|
}
|
|
|
|
Request.prototype = {
|
|
$isRequest: true,
|
|
createLoadOrderMap: function(loadOrder) {
|
|
var len = loadOrder.length,
|
|
loadOrderMap = {},
|
|
i, element;
|
|
for (i = 0; i < len; i++) {
|
|
element = loadOrder[i];
|
|
loadOrderMap[element.path] = element;
|
|
}
|
|
return loadOrderMap;
|
|
},
|
|
getLoadIndexes: function(item, indexMap, loadOrder, includeUses, skipLoaded) {
|
|
var resolved = [],
|
|
queue = [
|
|
item
|
|
],
|
|
itemIndex = item.idx,
|
|
queue, entry, dependencies, depIndex, i, len;
|
|
if (indexMap[itemIndex]) {
|
|
// prevent cycles
|
|
return resolved;
|
|
}
|
|
// Both indexMap and resolved are sparse arrays keyed by indexes.
|
|
// This gives us a naturally sorted sequence of indexes later on
|
|
// when we need to convert them to paths.
|
|
// indexMap is the map of all indexes we have visited at least once
|
|
// per the current expandUrls() invocation, and resolved is the map
|
|
// of all dependencies for the current item that are not included
|
|
// in indexMap.
|
|
indexMap[itemIndex] = resolved[itemIndex] = true;
|
|
while (item = queue.shift()) {
|
|
// Canonicalizing URLs is expensive, we try to avoid it
|
|
if (item.canonicalPath) {
|
|
entry = Boot.getEntry(item.path, null, true);
|
|
} else {
|
|
entry = Boot.getEntry(this.prepareUrl(item.path));
|
|
}
|
|
if (!(skipLoaded && entry.done)) {
|
|
if (includeUses && item.uses && item.uses.length) {
|
|
dependencies = item.requires.concat(item.uses);
|
|
} else {
|
|
dependencies = item.requires;
|
|
}
|
|
for (i = 0 , len = dependencies.length; i < len; i++) {
|
|
depIndex = dependencies[i];
|
|
if (!indexMap[depIndex]) {
|
|
indexMap[depIndex] = resolved[depIndex] = true;
|
|
queue.push(loadOrder[depIndex]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return resolved;
|
|
},
|
|
getPathsFromIndexes: function(indexes, loadOrder) {
|
|
var paths = [],
|
|
index, len;
|
|
// indexes is a sparse array with values being true for defined indexes
|
|
for (index = 0 , len = indexes.length; index < len; index++) {
|
|
if (indexes[index]) {
|
|
paths.push(loadOrder[index].path);
|
|
}
|
|
}
|
|
return paths;
|
|
},
|
|
expandUrl: function(url, loadOrder, loadOrderMap, indexMap, includeUses, skipLoaded) {
|
|
var item, resolved;
|
|
if (loadOrder) {
|
|
item = loadOrderMap[url];
|
|
if (item) {
|
|
resolved = this.getLoadIndexes(item, indexMap, loadOrder, includeUses, skipLoaded);
|
|
if (resolved.length) {
|
|
return this.getPathsFromIndexes(resolved, loadOrder);
|
|
}
|
|
}
|
|
}
|
|
return [
|
|
url
|
|
];
|
|
},
|
|
expandUrls: function(urls, includeUses) {
|
|
var me = this,
|
|
loadOrder = me.loadOrder,
|
|
expanded = [],
|
|
expandMap = {},
|
|
indexMap = [],
|
|
loadOrderMap, tmpExpanded, i, len, t, tlen, tUrl;
|
|
if (typeof urls === "string") {
|
|
urls = [
|
|
urls
|
|
];
|
|
}
|
|
if (loadOrder) {
|
|
loadOrderMap = me.loadOrderMap;
|
|
if (!loadOrderMap) {
|
|
loadOrderMap = me.loadOrderMap = me.createLoadOrderMap(loadOrder);
|
|
}
|
|
}
|
|
for (i = 0 , len = urls.length; i < len; i++) {
|
|
// We don't want to skip loaded entries (last argument === false).
|
|
// There are some overrides that get loaded before their respective classes,
|
|
// and when the class dependencies are processed we don't want to skip over
|
|
// the overrides' dependencies just because they were loaded first.
|
|
tmpExpanded = this.expandUrl(urls[i], loadOrder, loadOrderMap, indexMap, includeUses, false);
|
|
for (t = 0 , tlen = tmpExpanded.length; t < tlen; t++) {
|
|
tUrl = tmpExpanded[t];
|
|
if (!expandMap[tUrl]) {
|
|
expandMap[tUrl] = true;
|
|
expanded.push(tUrl);
|
|
}
|
|
}
|
|
}
|
|
if (expanded.length === 0) {
|
|
expanded = urls;
|
|
}
|
|
return expanded;
|
|
},
|
|
expandLoadOrder: function() {
|
|
var me = this,
|
|
urls = me.urls,
|
|
expanded;
|
|
if (!me.expanded) {
|
|
expanded = this.expandUrls(urls, true);
|
|
me.expanded = true;
|
|
} else {
|
|
expanded = urls;
|
|
}
|
|
me.urls = expanded;
|
|
// if we added some urls to the request to honor the indicated
|
|
// load order, the request needs to be sequential
|
|
if (urls.length != expanded.length) {
|
|
me.sequential = true;
|
|
}
|
|
return me;
|
|
},
|
|
getUrls: function() {
|
|
this.expandLoadOrder();
|
|
return this.urls;
|
|
},
|
|
prepareUrl: function(url) {
|
|
if (this.prependBaseUrl) {
|
|
return Boot.baseUrl + url;
|
|
}
|
|
return url;
|
|
},
|
|
getEntries: function() {
|
|
var me = this,
|
|
entries = me.entries,
|
|
loadOrderMap, item, i, entry, urls, url;
|
|
if (!entries) {
|
|
entries = [];
|
|
urls = me.getUrls();
|
|
// If we have loadOrder array then the map will be expanded by now
|
|
if (me.loadOrder) {
|
|
loadOrderMap = me.loadOrderMap;
|
|
}
|
|
for (i = 0; i < urls.length; i++) {
|
|
url = me.prepareUrl(urls[i]);
|
|
if (loadOrderMap) {
|
|
item = loadOrderMap[url];
|
|
}
|
|
entry = Boot.getEntry(url, {
|
|
buster: me.buster,
|
|
charset: me.charset
|
|
}, item && item.canonicalPath);
|
|
entry.requests.push(me);
|
|
entries.push(entry);
|
|
}
|
|
me.entries = entries;
|
|
}
|
|
return entries;
|
|
},
|
|
loadEntries: function(sync) {
|
|
var me = this,
|
|
entries = me.getEntries(),
|
|
len = entries.length,
|
|
start = me.loadStart || 0,
|
|
continueLoad, entries, entry, i;
|
|
if (sync !== undefined) {
|
|
me.sync = sync;
|
|
}
|
|
me.loaded = me.loaded || 0;
|
|
me.loading = me.loading || len;
|
|
for (i = start; i < len; i++) {
|
|
entry = entries[i];
|
|
if (!entry.loaded) {
|
|
continueLoad = entries[i].load(me.sync);
|
|
} else {
|
|
continueLoad = true;
|
|
}
|
|
if (!continueLoad) {
|
|
me.loadStart = i;
|
|
entry.onDone(function() {
|
|
me.loadEntries(sync);
|
|
});
|
|
break;
|
|
}
|
|
}
|
|
me.processLoadedEntries();
|
|
},
|
|
processLoadedEntries: function() {
|
|
var me = this,
|
|
entries = me.getEntries(),
|
|
len = entries.length,
|
|
start = me.startIndex || 0,
|
|
i, entry;
|
|
if (!me.done) {
|
|
for (i = start; i < len; i++) {
|
|
entry = entries[i];
|
|
if (!entry.loaded) {
|
|
me.startIndex = i;
|
|
return;
|
|
}
|
|
if (!entry.evaluated) {
|
|
entry.evaluate();
|
|
}
|
|
if (entry.error) {
|
|
me.error = true;
|
|
}
|
|
}
|
|
me.notify();
|
|
}
|
|
},
|
|
notify: function() {
|
|
var me = this;
|
|
if (!me.done) {
|
|
var error = me.error,
|
|
fn = me[error ? 'failure' : 'success'],
|
|
delay = ('delay' in me) ? me.delay : (error ? 1 : Boot.config.chainDelay),
|
|
scope = me.scope || me;
|
|
me.done = true;
|
|
if (fn) {
|
|
if (delay === 0 || delay > 0) {
|
|
// Free the stack (and defer the next script)
|
|
setTimeout(function() {
|
|
fn.call(scope, me);
|
|
}, delay);
|
|
} else {
|
|
fn.call(scope, me);
|
|
}
|
|
}
|
|
me.fireListeners();
|
|
Boot.requestComplete(me);
|
|
}
|
|
},
|
|
onDone: function(listener) {
|
|
var me = this,
|
|
listeners = me.listeners || (me.listeners = []);
|
|
if (me.done) {
|
|
listener(me);
|
|
} else {
|
|
listeners.push(listener);
|
|
}
|
|
},
|
|
fireListeners: function() {
|
|
var listeners = this.listeners,
|
|
listener;
|
|
if (listeners) {
|
|
// _debug("firing request listeners");
|
|
while ((listener = listeners.shift())) {
|
|
listener(this);
|
|
}
|
|
}
|
|
}
|
|
};
|
|
function Entry(cfg) {
|
|
//The Entry class is a token to manage the load and evaluation
|
|
//state of a particular url. It is used to notify all Requests
|
|
//interested in this url that the content is available.
|
|
if (cfg.$isEntry) {
|
|
return cfg;
|
|
}
|
|
// _debug("creating entry for " + cfg.url);
|
|
var charset = cfg.charset || Boot.config.charset,
|
|
manifest = Ext.manifest,
|
|
loader = manifest && manifest.loader,
|
|
cache = (cfg.cache !== undefined) ? cfg.cache : (loader && loader.cache),
|
|
buster, busterParam;
|
|
if (Boot.config.disableCaching) {
|
|
if (cache === undefined) {
|
|
cache = !Boot.config.disableCaching;
|
|
}
|
|
if (cache === false) {
|
|
buster = +new Date();
|
|
} else if (cache !== true) {
|
|
buster = cache;
|
|
}
|
|
if (buster) {
|
|
busterParam = (loader && loader.cacheParam) || Boot.config.disableCachingParam;
|
|
buster = busterParam + "=" + buster;
|
|
}
|
|
}
|
|
_apply(this, cfg);
|
|
this.charset = charset;
|
|
this.buster = buster;
|
|
this.requests = [];
|
|
}
|
|
|
|
Entry.prototype = {
|
|
$isEntry: true,
|
|
done: false,
|
|
evaluated: false,
|
|
loaded: false,
|
|
isCrossDomain: function() {
|
|
var me = this;
|
|
if (me.crossDomain === undefined) {
|
|
// _debug("checking " + me.getLoadUrl() + " for prefix " + Boot.origin);
|
|
me.crossDomain = (me.getLoadUrl().indexOf(Boot.origin) !== 0);
|
|
}
|
|
return me.crossDomain;
|
|
},
|
|
isCss: function() {
|
|
var me = this;
|
|
if (me.css === undefined) {
|
|
if (me.url) {
|
|
var assetConfig = Boot.assetConfig[me.url];
|
|
me.css = assetConfig ? assetConfig.type === "css" : cssRe.test(me.url);
|
|
} else {
|
|
me.css = false;
|
|
}
|
|
}
|
|
return this.css;
|
|
},
|
|
getElement: function(tag) {
|
|
var me = this,
|
|
el = me.el;
|
|
if (!el) {
|
|
// _debug("creating element for " + me.url);
|
|
if (me.isCss()) {
|
|
tag = tag || "link";
|
|
el = doc.createElement(tag);
|
|
if (tag == "link") {
|
|
el.rel = 'stylesheet';
|
|
me.prop = 'href';
|
|
} else {
|
|
me.prop = "textContent";
|
|
}
|
|
el.type = "text/css";
|
|
} else {
|
|
tag = tag || "script";
|
|
el = doc.createElement(tag);
|
|
el.type = 'text/javascript';
|
|
me.prop = 'src';
|
|
if (me.charset) {
|
|
el.charset = me.charset;
|
|
}
|
|
if (Boot.hasAsync) {
|
|
el.async = false;
|
|
}
|
|
}
|
|
me.el = el;
|
|
}
|
|
return el;
|
|
},
|
|
getLoadUrl: function() {
|
|
var me = this,
|
|
url;
|
|
url = me.canonicalPath ? me.url : Boot.canonicalUrl(me.url);
|
|
if (!me.loadUrl) {
|
|
me.loadUrl = !!me.buster ? (url + (url.indexOf('?') === -1 ? '?' : '&') + me.buster) : url;
|
|
}
|
|
return me.loadUrl;
|
|
},
|
|
fetch: function(req) {
|
|
var url = this.getLoadUrl(),
|
|
async = !!req.async,
|
|
complete = req.complete;
|
|
Boot.fetch(url, complete, this, async);
|
|
},
|
|
onContentLoaded: function(response) {
|
|
var me = this,
|
|
status = response.status,
|
|
content = response.content,
|
|
exception = response.exception,
|
|
url = this.getLoadUrl();
|
|
me.loaded = true;
|
|
if ((exception || status === 0) && !_environment.phantom) {
|
|
me.error = ("Failed loading synchronously via XHR: '" + url + "'. It's likely that the file is either being loaded from a " + "different domain or from the local file system where cross " + "origin requests are not allowed for security reasons. Try " + "asynchronous loading instead.") || true;
|
|
me.evaluated = true;
|
|
} else if ((status >= 200 && status < 300) || status === 304 || _environment.phantom || (status === 0 && content.length > 0)) {
|
|
me.content = content;
|
|
} else {
|
|
me.error = ("Failed loading synchronously via XHR: '" + url + "'. Please verify that the file exists. XHR status code: " + status) || true;
|
|
me.evaluated = true;
|
|
}
|
|
},
|
|
createLoadElement: function(callback) {
|
|
var me = this,
|
|
el = me.getElement();
|
|
me.preserve = true;
|
|
el.onerror = function() {
|
|
me.error = true;
|
|
if (callback) {
|
|
callback();
|
|
callback = null;
|
|
}
|
|
};
|
|
if (Boot.isIE10m) {
|
|
el.onreadystatechange = function() {
|
|
if (this.readyState === 'loaded' || this.readyState === 'complete') {
|
|
if (callback) {
|
|
callback();
|
|
callback = this.onreadystatechange = this.onerror = null;
|
|
}
|
|
}
|
|
};
|
|
} else {
|
|
el.onload = function() {
|
|
callback();
|
|
callback = this.onload = this.onerror = null;
|
|
};
|
|
}
|
|
// IE starts loading here
|
|
el[me.prop] = me.getLoadUrl();
|
|
},
|
|
onLoadElementReady: function() {
|
|
Boot.getHead().appendChild(this.getElement());
|
|
this.evaluated = true;
|
|
},
|
|
inject: function(content, asset) {
|
|
// _debug("injecting content for " + this.url);
|
|
var me = this,
|
|
head = Boot.getHead(),
|
|
url = me.url,
|
|
key = me.key,
|
|
base, el, ieMode, basePath;
|
|
if (me.isCss()) {
|
|
me.preserve = true;
|
|
basePath = key.substring(0, key.lastIndexOf("/") + 1);
|
|
base = doc.createElement('base');
|
|
base.href = basePath;
|
|
if (head.firstChild) {
|
|
head.insertBefore(base, head.firstChild);
|
|
} else {
|
|
head.appendChild(base);
|
|
}
|
|
// reset the href attribute to cuase IE to pick up the change
|
|
base.href = base.href;
|
|
if (url) {
|
|
content += "\n/*# sourceURL=" + key + " */";
|
|
}
|
|
// create element after setting base
|
|
el = me.getElement("style");
|
|
ieMode = ('styleSheet' in el);
|
|
head.appendChild(base);
|
|
if (ieMode) {
|
|
head.appendChild(el);
|
|
el.styleSheet.cssText = content;
|
|
} else {
|
|
el.textContent = content;
|
|
head.appendChild(el);
|
|
}
|
|
head.removeChild(base);
|
|
} else {
|
|
// Debugger friendly, file names are still shown even though they're
|
|
// eval'ed code. Breakpoints work on both Firebug and Chrome's Web
|
|
// Inspector.
|
|
if (url) {
|
|
content += "\n//# sourceURL=" + key;
|
|
}
|
|
Ext.globalEval(content);
|
|
}
|
|
return me;
|
|
},
|
|
loadCrossDomain: function() {
|
|
var me = this,
|
|
complete = function() {
|
|
me.el.onerror = me.el.onload = emptyFn;
|
|
me.el = null;
|
|
me.loaded = me.evaluated = me.done = true;
|
|
me.notifyRequests();
|
|
};
|
|
me.createLoadElement(function() {
|
|
complete();
|
|
});
|
|
me.evaluateLoadElement();
|
|
// at this point, we need sequential evaluation,
|
|
// which means we can't advance the load until
|
|
// this entry has fully completed
|
|
return false;
|
|
},
|
|
loadElement: function() {
|
|
var me = this,
|
|
complete = function() {
|
|
me.el.onerror = me.el.onload = emptyFn;
|
|
me.el = null;
|
|
me.loaded = me.evaluated = me.done = true;
|
|
me.notifyRequests();
|
|
};
|
|
me.createLoadElement(function() {
|
|
complete();
|
|
});
|
|
me.evaluateLoadElement();
|
|
return true;
|
|
},
|
|
loadSync: function() {
|
|
var me = this;
|
|
me.fetch({
|
|
async: false,
|
|
complete: function(response) {
|
|
me.onContentLoaded(response);
|
|
}
|
|
});
|
|
me.evaluate();
|
|
me.notifyRequests();
|
|
},
|
|
load: function(sync) {
|
|
var me = this;
|
|
if (!me.loaded) {
|
|
if (me.loading) {
|
|
// if we're calling back through load and we're loading but haven't
|
|
// yet loaded, then we should be in a sequential, cross domain
|
|
// load scenario which means we can't continue the load on the
|
|
// request until this entry has fully evaluated, which will mean
|
|
// loaded = evaluated = done = true in one step. For css files, this
|
|
// will happen immediately upon <link> element creation / insertion,
|
|
// but <script> elements will set this upon load notification
|
|
return false;
|
|
}
|
|
me.loading = true;
|
|
// for async modes, we have some options
|
|
if (!sync) {
|
|
// if cross domain, just inject the script tag and let the onload
|
|
// events drive the progression.
|
|
// IE10 also needs sequential loading because of a bug that makes it
|
|
// fire readystate event prematurely:
|
|
// https://connect.microsoft.com/IE/feedback/details/729164/ie10-dynamic-script-element-fires-loaded-readystate-prematurely
|
|
if (Boot.isIE10 || me.isCrossDomain()) {
|
|
return me.loadCrossDomain();
|
|
}
|
|
// for IE, use the readyStateChange allows us to load scripts in parallel
|
|
// but serialize the evaluation by appending the script node to the
|
|
// document
|
|
else if (!me.isCss() && Boot.hasReadyState) {
|
|
me.createLoadElement(function() {
|
|
me.loaded = true;
|
|
me.notifyRequests();
|
|
});
|
|
} else if (Boot.useElements && // older webkit, phantomjs included, won't fire load for link elements
|
|
!(me.isCss() && _environment.phantom)) {
|
|
return me.loadElement();
|
|
} else // for other browsers, just ajax the content down in parallel, and use
|
|
// globalEval to serialize evaluation
|
|
{
|
|
me.fetch({
|
|
async: !sync,
|
|
complete: function(response) {
|
|
me.onContentLoaded(response);
|
|
me.notifyRequests();
|
|
}
|
|
});
|
|
}
|
|
} else // for sync mode in js, global eval FTW. IE won't honor the comment
|
|
// paths in the debugger, so eventually we need a sync mode for IE that
|
|
// uses the readyStateChange mechanism
|
|
{
|
|
me.loadSync();
|
|
}
|
|
}
|
|
// signal that the load process can continue
|
|
return true;
|
|
},
|
|
evaluateContent: function() {
|
|
this.inject(this.content);
|
|
this.content = null;
|
|
},
|
|
evaluateLoadElement: function() {
|
|
Boot.getHead().appendChild(this.getElement());
|
|
},
|
|
evaluate: function() {
|
|
var me = this;
|
|
if (!me.evaluated) {
|
|
if (me.evaluating) {
|
|
return;
|
|
}
|
|
me.evaluating = true;
|
|
if (me.content !== undefined) {
|
|
me.evaluateContent();
|
|
} else if (!me.error) {
|
|
me.evaluateLoadElement();
|
|
}
|
|
me.evaluated = me.done = true;
|
|
me.cleanup();
|
|
}
|
|
},
|
|
cleanup: function() {
|
|
var me = this,
|
|
el = me.el,
|
|
prop;
|
|
if (!el) {
|
|
return;
|
|
}
|
|
if (!me.preserve) {
|
|
me.el = null;
|
|
el.parentNode.removeChild(el);
|
|
// Remove, since its useless now
|
|
for (prop in el) {
|
|
try {
|
|
if (prop !== me.prop) {
|
|
// If we set the src property to null IE
|
|
// will try and request a script at './null'
|
|
el[prop] = null;
|
|
}
|
|
delete el[prop];
|
|
} // and prepare for GC
|
|
catch (cleanEx) {}
|
|
}
|
|
}
|
|
//ignore
|
|
// Setting to null can cause exceptions if IE ever needs to call these
|
|
// again (like onreadystatechange). This emptyFn has nothing locked in
|
|
// closure scope so it is about as safe as null for memory leaks.
|
|
el.onload = el.onerror = el.onreadystatechange = emptyFn;
|
|
},
|
|
notifyRequests: function() {
|
|
var requests = this.requests,
|
|
len = requests.length,
|
|
i, request;
|
|
for (i = 0; i < len; i++) {
|
|
request = requests[i];
|
|
request.processLoadedEntries();
|
|
}
|
|
if (this.done) {
|
|
this.fireListeners();
|
|
}
|
|
},
|
|
onDone: function(listener) {
|
|
var me = this,
|
|
listeners = me.listeners || (me.listeners = []);
|
|
if (me.done) {
|
|
listener(me);
|
|
} else {
|
|
listeners.push(listener);
|
|
}
|
|
},
|
|
fireListeners: function() {
|
|
var listeners = this.listeners,
|
|
listener;
|
|
if (listeners && listeners.length > 0) {
|
|
// _debug("firing event listeners for url " + this.url);
|
|
while ((listener = listeners.shift())) {
|
|
listener(this);
|
|
}
|
|
}
|
|
}
|
|
};
|
|
/**
|
|
* Turns on or off the "cache buster" applied to dynamically loaded scripts. Normally
|
|
* dynamically loaded scripts have an extra query parameter appended to avoid stale
|
|
* cached scripts. This method can be used to disable this mechanism, and is primarily
|
|
* useful for testing. This is done using a cookie.
|
|
* @param {Boolean} disable True to disable the cache buster.
|
|
* @param {String} [path="/"] An optional path to scope the cookie.
|
|
*/
|
|
Ext.disableCacheBuster = function(disable, path) {
|
|
var date = new Date();
|
|
date.setTime(date.getTime() + (disable ? 10 * 365 : -1) * 24 * 60 * 60 * 1000);
|
|
date = date.toGMTString();
|
|
doc.cookie = 'ext-cache=1; expires=' + date + '; path=' + (path || '/');
|
|
};
|
|
Boot.init();
|
|
return Boot;
|
|
}(// NOTE: We run the eval at global scope to protect the body of the function and allow
|
|
// compressors to still process it.
|
|
function() {}));
|
|
//(eval("/*@cc_on!@*/!1"));
|
|
/**
|
|
* This method evaluates the given code free of any local variable. This
|
|
* will be at global scope, in others it will be in a function.
|
|
* @param {String} code The code to evaluate.
|
|
* @private
|
|
* @method
|
|
* @member Ext
|
|
*/
|
|
Ext.globalEval = Ext.globalEval || (this.execScript ? function(code) {
|
|
execScript(code);
|
|
} : function($$code) {
|
|
eval.call(window, $$code);
|
|
});
|
|
/*
|
|
* Only IE8 & IE/Quirks lack Function.prototype.bind so we polyfill that here.
|
|
*/
|
|
if (!Function.prototype.bind) {
|
|
(function() {
|
|
var slice = Array.prototype.slice,
|
|
// To reduce overhead on call of the bound fn we have two flavors based on
|
|
// whether we have args to prepend or not:
|
|
bind = function(me) {
|
|
var args = slice.call(arguments, 1),
|
|
method = this;
|
|
if (args.length) {
|
|
return function() {
|
|
var t = arguments;
|
|
// avoid the slice/concat if the caller does not supply args
|
|
return method.apply(me, t.length ? args.concat(slice.call(t)) : args);
|
|
};
|
|
}
|
|
// this is the majority use case - just fn.bind(this) and no args
|
|
args = null;
|
|
return function() {
|
|
return method.apply(me, arguments);
|
|
};
|
|
};
|
|
Function.prototype.bind = bind;
|
|
bind.$extjs = true;
|
|
}());
|
|
}
|
|
// to detect this polyfill if one want to improve it
|
|
//</editor-fold>
|
|
Ext.setResourcePath = function(poolName, path) {
|
|
var manifest = Ext.manifest || (Ext.manifest = {}),
|
|
paths = manifest.resources || (manifest.resources = {});
|
|
if (manifest) {
|
|
if (typeof poolName !== 'string') {
|
|
Ext.apply(paths, poolName);
|
|
} else {
|
|
paths[poolName] = path;
|
|
}
|
|
manifest.resources = paths;
|
|
}
|
|
};
|
|
Ext.getResourcePath = function(path, poolName, packageName) {
|
|
if (typeof path !== 'string') {
|
|
poolName = path.pool;
|
|
packageName = path.packageName;
|
|
path = path.path;
|
|
}
|
|
var manifest = Ext.manifest,
|
|
paths = manifest && manifest.resources,
|
|
poolPath = paths[poolName],
|
|
output = [];
|
|
if (poolPath == null) {
|
|
poolPath = paths.path;
|
|
if (poolPath == null) {
|
|
poolPath = 'resources';
|
|
}
|
|
}
|
|
if (poolPath) {
|
|
output.push(poolPath);
|
|
}
|
|
if (packageName) {
|
|
output.push(packageName);
|
|
}
|
|
output.push(path);
|
|
return output.join('/');
|
|
};
|
|
|
|
// @tag core
|
|
/**
|
|
* @class Ext
|
|
*
|
|
* The Ext namespace (global object) encapsulates all classes, singletons, and
|
|
* utility methods provided by Sencha's libraries.
|
|
*
|
|
* Most user interface Components are at a lower level of nesting in the namespace,
|
|
* but many common utility functions are provided as direct properties of the Ext namespace.
|
|
*
|
|
* Also many frequently used methods from other classes are provided as shortcuts
|
|
* within the Ext namespace. For example {@link Ext#getCmp Ext.getCmp} aliases
|
|
* {@link Ext.ComponentManager#get Ext.ComponentManager.get}.
|
|
*
|
|
* Many applications are initiated with {@link Ext#application Ext.application} which is
|
|
* called once the DOM is ready. This ensures all scripts have been loaded, preventing
|
|
* dependency issues. For example:
|
|
*
|
|
* Ext.application({
|
|
* name: 'MyApp',
|
|
*
|
|
* launch: function () {
|
|
* Ext.Msg.alert(this.name, 'Ready to go!');
|
|
* }
|
|
* });
|
|
*
|
|
* <b><a href="http://www.sencha.com/products/sencha-cmd/">Sencha Cmd</a></b> is a free tool
|
|
* for helping you generate and build Ext JS (and Sencha Touch) applications. See
|
|
* `{@link Ext.app.Application Application}` for more information about creating an app.
|
|
*
|
|
* A lower-level technique that does not use the `Ext.app.Application` architecture is
|
|
* {@link Ext#onReady Ext.onReady}.
|
|
*
|
|
* For more information about how to use the Ext classes, see:
|
|
*
|
|
* - <a href="http://www.sencha.com/learn/">The Learning Center</a>
|
|
* - <a href="http://www.sencha.com/learn/Ext_FAQ">The FAQ</a>
|
|
* - <a href="http://www.sencha.com/forum/">The forums</a>
|
|
*
|
|
* @singleton
|
|
*/
|
|
var Ext = Ext || {};
|
|
// jshint ignore:line
|
|
// @define Ext
|
|
(function() {
|
|
var global = this,
|
|
objectPrototype = Object.prototype,
|
|
toString = objectPrototype.toString,
|
|
enumerables = [
|
|
//'hasOwnProperty', 'isPrototypeOf', 'propertyIsEnumerable',
|
|
'valueOf',
|
|
'toLocaleString',
|
|
'toString',
|
|
'constructor'
|
|
],
|
|
emptyFn = function() {},
|
|
privateFn = function() {},
|
|
identityFn = function(o) {
|
|
return o;
|
|
},
|
|
// This is the "$previous" method of a hook function on an instance. When called, it
|
|
// calls through the class prototype by the name of the called method.
|
|
callOverrideParent = function() {
|
|
var method = callOverrideParent.caller.caller;
|
|
// skip callParent (our caller)
|
|
return method.$owner.prototype[method.$name].apply(this, arguments);
|
|
},
|
|
manifest = Ext.manifest || {},
|
|
i,
|
|
iterableRe = /\[object\s*(?:Array|Arguments|\w*Collection|\w*List|HTML\s+document\.all\s+class)\]/,
|
|
MSDateRe = /^\\?\/Date\(([-+])?(\d+)(?:[+-]\d{4})?\)\\?\/$/;
|
|
Ext.global = global;
|
|
/**
|
|
* Returns the current timestamp.
|
|
* @return {Number} Milliseconds since UNIX epoch.
|
|
* @method now
|
|
* @member Ext
|
|
*/
|
|
Ext.now = Date.now || (Date.now = function() {
|
|
return +new Date();
|
|
});
|
|
/**
|
|
* Returns the current high-resolution timestamp.
|
|
* @return {Number} Milliseconds ellapsed since arbitrary epoch.
|
|
* @method ticks
|
|
* @member Ext
|
|
* @since 6.0.1
|
|
*/
|
|
Ext.ticks = (global.performance && global.performance.now) ? function() {
|
|
return performance.now();
|
|
} : // jshint ignore:line
|
|
Ext.now;
|
|
Ext._startTime = Ext.ticks();
|
|
// Mark these special fn's for easy identification:
|
|
emptyFn.$nullFn = identityFn.$nullFn = emptyFn.$emptyFn = identityFn.$identityFn = privateFn.$nullFn = true;
|
|
privateFn.$privacy = 'framework';
|
|
// We also want to prevent these functions from being cleaned up on destroy
|
|
emptyFn.$noClearOnDestroy = identityFn.$noClearOnDestroy = true;
|
|
privateFn.$noClearOnDestroy = true;
|
|
// These are emptyFn's in core and are redefined only in Ext JS (we use this syntax
|
|
// so Cmd does not detect them):
|
|
Ext['suspendLayouts'] = Ext['resumeLayouts'] = emptyFn;
|
|
// jshint ignore:line
|
|
for (i in {
|
|
toString: 1
|
|
}) {
|
|
enumerables = null;
|
|
}
|
|
/**
|
|
* An array containing extra enumerables for old browsers
|
|
* @property {String[]}
|
|
*/
|
|
Ext.enumerables = enumerables;
|
|
/**
|
|
* Copies all the properties of `config` to the specified `object`. There are two levels
|
|
* of defaulting supported:
|
|
*
|
|
* Ext.apply(obj, { a: 1 }, { a: 2 });
|
|
* //obj.a === 1
|
|
*
|
|
* Ext.apply(obj, { }, { a: 2 });
|
|
* //obj.a === 2
|
|
*
|
|
* Note that if recursive merging and cloning without referencing the original objects
|
|
* or arrays is needed, use {@link Ext.Object#merge} instead.
|
|
*
|
|
* @param {Object} object The receiver of the properties.
|
|
* @param {Object} config The primary source of the properties.
|
|
* @param {Object} [defaults] An object that will also be applied for default values.
|
|
* @return {Object} returns `object`.
|
|
*/
|
|
Ext.apply = function(object, config, defaults) {
|
|
if (defaults) {
|
|
Ext.apply(object, defaults);
|
|
}
|
|
if (object && config && typeof config === 'object') {
|
|
var i, j, k;
|
|
for (i in config) {
|
|
object[i] = config[i];
|
|
}
|
|
if (enumerables) {
|
|
for (j = enumerables.length; j--; ) {
|
|
k = enumerables[j];
|
|
if (config.hasOwnProperty(k)) {
|
|
object[k] = config[k];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return object;
|
|
};
|
|
// Used by Ext.override
|
|
function addInstanceOverrides(target, owner, overrides) {
|
|
var name, value;
|
|
for (name in overrides) {
|
|
if (overrides.hasOwnProperty(name)) {
|
|
value = overrides[name];
|
|
if (typeof value === 'function') {
|
|
if (owner.$className) {
|
|
value.name = owner.$className + '#' + name;
|
|
}
|
|
value.$name = name;
|
|
value.$owner = owner;
|
|
value.$previous = target.hasOwnProperty(name) ? target[name] : // already hooked, so call previous hook
|
|
callOverrideParent;
|
|
}
|
|
// calls by name on prototype
|
|
target[name] = value;
|
|
}
|
|
}
|
|
}
|
|
Ext.buildSettings = Ext.apply({
|
|
baseCSSPrefix: 'x-'
|
|
}, Ext.buildSettings || {});
|
|
Ext.apply(Ext, {
|
|
/**
|
|
* @private
|
|
*/
|
|
idSeed: 0,
|
|
/**
|
|
* @private
|
|
*/
|
|
idPrefix: 'ext-',
|
|
/**
|
|
* @property {Boolean} isSecure
|
|
* True if the page is running over SSL
|
|
* @readonly
|
|
*/
|
|
isSecure: /^https/i.test(window.location.protocol),
|
|
/**
|
|
* `true` to automatically uncache orphaned Ext.Elements periodically. If set to
|
|
* `false`, the application will be required to clean up orphaned Ext.Elements and
|
|
* it's listeners as to not cause memory leakage.
|
|
*/
|
|
enableGarbageCollector: false,
|
|
/**
|
|
* True to automatically purge event listeners during garbageCollection.
|
|
*/
|
|
enableListenerCollection: true,
|
|
/**
|
|
* @property {String} [name='Ext']
|
|
* <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>
|
|
* <p>This is usually <code>"Ext"</code>, but if a sandboxed build of ExtJS is being used, this will be an alternative name.</p>
|
|
* <p>If code is being generated for use by <code>eval</code> or to create a <code>new Function</code>, and the global instance
|
|
* of Ext must be referenced, this is the name that should be built into the code.</p>
|
|
*/
|
|
name: Ext.sandboxName || 'Ext',
|
|
/**
|
|
* @property {Function}
|
|
* A reusable empty function for use as `privates` members.
|
|
*
|
|
* Ext.define('MyClass', {
|
|
* nothing: Ext.emptyFn,
|
|
*
|
|
* privates: {
|
|
* privateNothing: Ext.privateFn
|
|
* }
|
|
* });
|
|
*
|
|
*/
|
|
privateFn: privateFn,
|
|
/**
|
|
* @property {Function}
|
|
* A reusable empty function.
|
|
*/
|
|
emptyFn: emptyFn,
|
|
/**
|
|
* @property {Function}
|
|
* A reusable identity function that simply returns its first argument.
|
|
*/
|
|
identityFn: identityFn,
|
|
/**
|
|
* This indicate the start timestamp of current cycle.
|
|
* It is only reliable during dom-event-initiated cycles and
|
|
* {@link Ext.draw.Animator} initiated cycles.
|
|
*/
|
|
frameStartTime: Ext.now(),
|
|
/**
|
|
* This object is initialized prior to loading the framework (Ext JS or Sencha
|
|
* Touch) and contains settings and other information describing the application.
|
|
*
|
|
* For applications built using Sencha Cmd, this is produced from the `"app.json"`
|
|
* file with information extracted from all of the required packages' `"package.json"`
|
|
* files. This can be set to a string when your application is using the
|
|
* (microloader)[#/guide/microloader]. In this case, the string of "foo" will be
|
|
* requested as `"foo.json"` and the object in that JSON file will parsed and set
|
|
* as this object.
|
|
*
|
|
* @cfg {String/Object} manifest
|
|
*
|
|
* @cfg {String/Object} manifest.compatibility An object keyed by package name with
|
|
* the value being to desired compatibility level as a version number. If this is
|
|
* just a string, this version is assumed to apply to the framework ('ext' or
|
|
* 'touch'). Setting this value to less than 5 for 'ext' will enable the compatibility
|
|
* layer to assist in the application upgrade process. For details on the upgrade
|
|
* process, see the (Upgrade Guide)[#/guides/upgrade_50].
|
|
*
|
|
* @cfg {Object} manifest.debug An object configuring the debugging characteristics
|
|
* of the framework. See `Ext.debugConfig` which is set to this value.
|
|
*
|
|
* @cfg {Object} manifest.packages An object keyed by package name with the value
|
|
* being a subset of the package's `"package.json"` descriptor.
|
|
* @since 5.0.0
|
|
*/
|
|
manifest: manifest,
|
|
/**
|
|
* @cfg {Object} [debugConfig]
|
|
* This object is used to enable or disable debugging for classes or namespaces. The
|
|
* default instance looks like this:
|
|
*
|
|
* Ext.debugConfig = {
|
|
* hooks: {
|
|
* '*': true
|
|
* }
|
|
* };
|
|
*
|
|
* Typically applications will set this in their `"app.json"` like so:
|
|
*
|
|
* {
|
|
* "debug": {
|
|
* "hooks": {
|
|
* // Default for all namespaces:
|
|
* '*': true,
|
|
*
|
|
* // Except for Ext namespace which is disabled
|
|
* 'Ext': false,
|
|
*
|
|
* // Except for Ext.layout namespace which is enabled
|
|
* 'Ext.layout': true
|
|
* }
|
|
* }
|
|
* }
|
|
*
|
|
* Alternatively, because this property is consumed very early in the load process of
|
|
* the framework, this can be set in a `script` tag that is defined prior to loading
|
|
* the framework itself.
|
|
*
|
|
* For example, to enable debugging for the `Ext.layout` namespace only:
|
|
*
|
|
* var Ext = Ext || {};
|
|
* Ext.debugConfig = {
|
|
* hooks: {
|
|
* //...
|
|
* }
|
|
* };
|
|
*
|
|
* For any class declared, the longest matching namespace specified determines if its
|
|
* `debugHooks` will be enabled. The default setting is specified by the '*' property.
|
|
*
|
|
* **NOTE:** This option only applies to debug builds. All debugging is disabled in
|
|
* production builds.
|
|
*/
|
|
debugConfig: Ext.debugConfig || manifest.debug || {
|
|
hooks: {
|
|
'*': true
|
|
}
|
|
},
|
|
/**
|
|
* @property {Boolean} [enableAria=true] This property is provided for backward
|
|
* compatibility with previous versions of Ext JS. Accessibility is always enabled
|
|
* in Ext JS 6.0+.
|
|
*
|
|
* This property is deprecated. To disable WAI-ARIA compatibility warnings,
|
|
* override `Ext.ariaWarn` function in your application startup code:
|
|
*
|
|
* Ext.application({
|
|
* launch: function() {
|
|
* Ext.ariaWarn = Ext.emptyFn;
|
|
* }
|
|
* });
|
|
*
|
|
* For stricter compatibility with WAI-ARIA requirements, replace `Ext.ariaWarn`
|
|
* with a function that will raise an error instead:
|
|
*
|
|
* Ext.application({
|
|
* launch: function() {
|
|
* Ext.ariaWarn = function(target, msg) {
|
|
* Ext.raise({
|
|
* msg: msg,
|
|
* component: target
|
|
* });
|
|
* };
|
|
* }
|
|
* });
|
|
*
|
|
* @since 6.0.0
|
|
* @deprecated 6.0.2
|
|
*/
|
|
enableAria: true,
|
|
startsWithHashRe: /^#/,
|
|
/**
|
|
* @property {RegExp}
|
|
* @private
|
|
* Regular expression used for validating identifiers.
|
|
*/
|
|
validIdRe: /^[a-z_][a-z0-9\-_]*$/i,
|
|
/**
|
|
* @property {String} BLANK_IMAGE_URL
|
|
* URL to a 1x1 transparent gif image used by Ext to create inline icons with
|
|
* CSS background images.
|
|
*/
|
|
BLANK_IMAGE_URL: 'data:image/gif;base64,R0lGODlhAQABAID/AMDAwAAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==',
|
|
/**
|
|
* Converts an id (`'foo'`) into an id selector (`'#foo'`). This method is used
|
|
* internally by the framework whenever an id needs to be converted into a selector
|
|
* and is provided as a hook for those that need to escape IDs selectors since,
|
|
* as of Ext 5.0, the framework no longer escapes IDs by default.
|
|
* @private
|
|
* @param {String} id
|
|
* @return {String}
|
|
*/
|
|
makeIdSelector: function(id) {
|
|
if (!Ext.validIdRe.test(id)) {
|
|
Ext.raise('Invalid id selector: "' + id + '"');
|
|
}
|
|
return '#' + id;
|
|
},
|
|
/**
|
|
* Generates unique ids. If the object/element is passes and it already has an `id`, it is unchanged.
|
|
* @param {Object} [o] The object to generate an id for.
|
|
* @param {String} [prefix=ext-gen] (optional) The `id` prefix.
|
|
* @return {String} The generated `id`.
|
|
*/
|
|
id: function(o, prefix) {
|
|
if (o && o.id) {
|
|
return o.id;
|
|
}
|
|
var id = (prefix || Ext.idPrefix) + (++Ext.idSeed);
|
|
if (o) {
|
|
o.id = id;
|
|
}
|
|
return id;
|
|
},
|
|
/**
|
|
* A reusable function which returns the value of `getId()` called upon a single passed parameter.
|
|
* Useful when creating a {@link Ext.util.MixedCollection} of objects keyed by an identifier returned from a `getId` method.
|
|
*/
|
|
returnId: function(o) {
|
|
return o.getId();
|
|
},
|
|
/**
|
|
* A reusable function which returns `true`.
|
|
*/
|
|
returnTrue: function() {
|
|
return true;
|
|
},
|
|
/**
|
|
* A zero length string which will pass a truth test. Useful for passing to methods
|
|
* which use a truth test to reject <i>falsy</i> values where a string value must be cleared.
|
|
*/
|
|
emptyString: new String(),
|
|
// jshint ignore:line
|
|
/**
|
|
* @property {String} [baseCSSPrefix='x-']
|
|
* The base prefix to use for all `Ext` components. To configure this property, you should use the
|
|
* Ext.buildSettings object before the framework is loaded:
|
|
*
|
|
* Ext.buildSettings = {
|
|
* baseCSSPrefix : 'abc-'
|
|
* };
|
|
*
|
|
* or you can change it before any components are rendered:
|
|
*
|
|
* Ext.baseCSSPrefix = Ext.buildSettings.baseCSSPrefix = 'abc-';
|
|
*
|
|
* This will change what CSS classes components will use and you should
|
|
* then recompile the SASS changing the `$prefix` SASS variable to match.
|
|
*/
|
|
baseCSSPrefix: Ext.buildSettings.baseCSSPrefix,
|
|
/**
|
|
* @property {Object} $eventNameMap
|
|
* A map of event names which contained the lower-cased versions of any mixed
|
|
* case event names.
|
|
* @private
|
|
*/
|
|
$eventNameMap: {},
|
|
// Vendor-specific events do not work if lower-cased. This regex specifies event
|
|
// prefixes for names that should NOT be lower-cased by Ext.canonicalEventName()
|
|
$vendorEventRe: /^(DOMMouse|Moz.+|MS.+|webkit.+)/,
|
|
// TODO: inlinable function - SDKTOOLS-686
|
|
/**
|
|
* @private
|
|
* @inline
|
|
*/
|
|
canonicalEventName: function(name) {
|
|
return Ext.$eventNameMap[name] || (Ext.$eventNameMap[name] = (Ext.$vendorEventRe.test(name) ? name : name.toLowerCase()));
|
|
},
|
|
/**
|
|
* Copies all the properties of config to object if they don't already exist.
|
|
* @param {Object} object The receiver of the properties
|
|
* @param {Object} config The source of the properties
|
|
* @return {Object} returns obj
|
|
*/
|
|
applyIf: function(object, config) {
|
|
var property;
|
|
if (object) {
|
|
for (property in config) {
|
|
if (object[property] === undefined) {
|
|
object[property] = config[property];
|
|
}
|
|
}
|
|
}
|
|
return object;
|
|
},
|
|
/**
|
|
* Destroys all of the given objects. If arrays are passed, the elements of these
|
|
* are destroyed recursively.
|
|
*
|
|
* What it means to "destroy" an object depends on the type of object.
|
|
*
|
|
* * `Array`: Each element of the array is destroyed recursively.
|
|
* * `Object`: Any object with a `destroy` method will have that method called.
|
|
*
|
|
* @param {Mixed...} args Any number of objects or arrays.
|
|
*/
|
|
destroy: function() {
|
|
var ln = arguments.length,
|
|
i, arg;
|
|
for (i = 0; i < ln; i++) {
|
|
arg = arguments[i];
|
|
if (arg) {
|
|
if (Ext.isArray(arg)) {
|
|
this.destroy.apply(this, arg);
|
|
} else if (Ext.isFunction(arg.destroy)) {
|
|
arg.destroy();
|
|
}
|
|
}
|
|
}
|
|
return null;
|
|
},
|
|
/**
|
|
* Destroys the specified named members of the given object using `Ext.destroy`. These
|
|
* properties will be set to `null`.
|
|
* @param {Object} object The object who's properties you wish to destroy.
|
|
* @param {String...} args One or more names of the properties to destroy and remove from the object.
|
|
*/
|
|
destroyMembers: function(object) {
|
|
for (var ref, name,
|
|
i = 1,
|
|
a = arguments,
|
|
len = a.length; i < len; i++) {
|
|
ref = object[name = a[i]];
|
|
// Avoid adding the property if it does not already exist
|
|
if (ref != null) {
|
|
object[name] = Ext.destroy(ref);
|
|
}
|
|
}
|
|
},
|
|
/**
|
|
* Overrides members of the specified `target` with the given values.
|
|
*
|
|
* If the `target` is a class declared using {@link Ext#define Ext.define}, the
|
|
* `override` method of that class is called (see {@link Ext.Base#override}) given
|
|
* the `overrides`.
|
|
*
|
|
* If the `target` is a function, it is assumed to be a constructor and the contents
|
|
* of `overrides` are applied to its `prototype` using {@link Ext#apply Ext.apply}.
|
|
*
|
|
* If the `target` is an instance of a class declared using {@link Ext#define Ext.define},
|
|
* the `overrides` are applied to only that instance. In this case, methods are
|
|
* specially processed to allow them to use {@link Ext.Base#callParent}.
|
|
*
|
|
* var panel = new Ext.Panel({ ... });
|
|
*
|
|
* Ext.override(panel, {
|
|
* initComponent: function () {
|
|
* // extra processing...
|
|
*
|
|
* this.callParent();
|
|
* }
|
|
* });
|
|
*
|
|
* If the `target` is none of these, the `overrides` are applied to the `target`
|
|
* using {@link Ext#apply Ext.apply}.
|
|
*
|
|
* Please refer to {@link Ext#define Ext.define} and {@link Ext.Base#override} for
|
|
* further details.
|
|
*
|
|
* @param {Object} target The target to override.
|
|
* @param {Object} overrides The properties to add or replace on `target`.
|
|
* @method override
|
|
*/
|
|
override: function(target, overrides) {
|
|
if (target.$isClass) {
|
|
target.override(overrides);
|
|
} else if (typeof target === 'function') {
|
|
Ext.apply(target.prototype, overrides);
|
|
} else {
|
|
var owner = target.self,
|
|
privates;
|
|
if (owner && owner.$isClass) {
|
|
// if (instance of Ext.define'd class)
|
|
privates = overrides.privates;
|
|
if (privates) {
|
|
overrides = Ext.apply({}, overrides);
|
|
delete overrides.privates;
|
|
addInstanceOverrides(target, owner, privates);
|
|
}
|
|
addInstanceOverrides(target, owner, overrides);
|
|
} else {
|
|
Ext.apply(target, overrides);
|
|
}
|
|
}
|
|
return target;
|
|
},
|
|
/**
|
|
* Returns the given value itself if it's not empty, as described in {@link Ext#isEmpty}; returns the default
|
|
* value (second argument) otherwise.
|
|
*
|
|
* @param {Object} value The value to test.
|
|
* @param {Object} defaultValue The value to return if the original value is empty.
|
|
* @param {Boolean} [allowBlank=false] `true` to allow zero length strings to qualify as non-empty.
|
|
* @return {Object} value, if non-empty, else defaultValue.
|
|
*/
|
|
valueFrom: function(value, defaultValue, allowBlank) {
|
|
return Ext.isEmpty(value, allowBlank) ? defaultValue : value;
|
|
},
|
|
/**
|
|
* Returns true if the passed value is empty, false otherwise. The value is deemed to be empty if it is either:
|
|
*
|
|
* - `null`
|
|
* - `undefined`
|
|
* - a zero-length array
|
|
* - a zero-length string (Unless the `allowEmptyString` parameter is set to `true`)
|
|
*
|
|
* @param {Object} value The value to test.
|
|
* @param {Boolean} [allowEmptyString=false] `true` to allow empty strings.
|
|
* @return {Boolean}
|
|
*/
|
|
isEmpty: function(value, allowEmptyString) {
|
|
return (value == null) || (!allowEmptyString ? value === '' : false) || (Ext.isArray(value) && value.length === 0);
|
|
},
|
|
/**
|
|
* Returns `true` if the passed value is a JavaScript Array, `false` otherwise.
|
|
*
|
|
* @param {Object} target The target to test.
|
|
* @return {Boolean}
|
|
* @method
|
|
*/
|
|
isArray: ('isArray' in Array) ? Array.isArray : function(value) {
|
|
return toString.call(value) === '[object Array]';
|
|
},
|
|
/**
|
|
* Returns `true` if the passed value is a JavaScript Date object, `false` otherwise.
|
|
* @param {Object} object The object to test.
|
|
* @return {Boolean}
|
|
*/
|
|
isDate: function(value) {
|
|
return toString.call(value) === '[object Date]';
|
|
},
|
|
/**
|
|
* Returns 'true' if the passed value is a String that matches the MS Date JSON
|
|
* encoding format.
|
|
* @param {String} value The string to test.
|
|
* @return {Boolean}
|
|
*/
|
|
isMSDate: function(value) {
|
|
if (!Ext.isString(value)) {
|
|
return false;
|
|
}
|
|
return MSDateRe.test(value);
|
|
},
|
|
/**
|
|
* Returns `true` if the passed value is a JavaScript Object, `false` otherwise.
|
|
* @param {Object} value The value to test.
|
|
* @return {Boolean}
|
|
* @method
|
|
*/
|
|
isObject: (toString.call(null) === '[object Object]') ? function(value) {
|
|
// check ownerDocument here as well to exclude DOM nodes
|
|
return value !== null && value !== undefined && toString.call(value) === '[object Object]' && value.ownerDocument === undefined;
|
|
} : function(value) {
|
|
return toString.call(value) === '[object Object]';
|
|
},
|
|
/**
|
|
* @private
|
|
*/
|
|
isSimpleObject: function(value) {
|
|
return value instanceof Object && value.constructor === Object;
|
|
},
|
|
/**
|
|
* Returns `true` if the passed value is a JavaScript 'primitive', a string, number
|
|
* or boolean.
|
|
* @param {Object} value The value to test.
|
|
* @return {Boolean}
|
|
*/
|
|
isPrimitive: function(value) {
|
|
var type = typeof value;
|
|
return type === 'string' || type === 'number' || type === 'boolean';
|
|
},
|
|
/**
|
|
* Returns `true` if the passed value is a JavaScript Function, `false` otherwise.
|
|
* @param {Object} value The value to test.
|
|
* @return {Boolean}
|
|
* @method
|
|
*/
|
|
isFunction: // Safari 3.x and 4.x returns 'function' for typeof <NodeList>, hence we need to fall back to using
|
|
// Object.prototype.toString (slower)
|
|
(typeof document !== 'undefined' && typeof document.getElementsByTagName('body') === 'function') ? function(value) {
|
|
return !!value && toString.call(value) === '[object Function]';
|
|
} : function(value) {
|
|
return !!value && typeof value === 'function';
|
|
},
|
|
/**
|
|
* Returns `true` if the passed value is a number. Returns `false` for non-finite numbers.
|
|
* @param {Object} value The value to test.
|
|
* @return {Boolean}
|
|
*/
|
|
isNumber: function(value) {
|
|
return typeof value === 'number' && isFinite(value);
|
|
},
|
|
/**
|
|
* Validates that a value is numeric.
|
|
* @param {Object} value Examples: 1, '1', '2.34'
|
|
* @return {Boolean} True if numeric, false otherwise
|
|
*/
|
|
isNumeric: function(value) {
|
|
return !isNaN(parseFloat(value)) && isFinite(value);
|
|
},
|
|
/**
|
|
* Returns `true `if the passed value is a string.
|
|
* @param {Object} value The value to test.
|
|
* @return {Boolean}
|
|
*/
|
|
isString: function(value) {
|
|
return typeof value === 'string';
|
|
},
|
|
/**
|
|
* Returns `true` if the passed value is a boolean.
|
|
*
|
|
* @param {Object} value The value to test.
|
|
* @return {Boolean}
|
|
*/
|
|
isBoolean: function(value) {
|
|
return typeof value === 'boolean';
|
|
},
|
|
/**
|
|
* Returns `true` if the passed value is an HTMLElement
|
|
* @param {Object} value The value to test.
|
|
* @return {Boolean}
|
|
*/
|
|
isElement: function(value) {
|
|
return value ? value.nodeType === 1 : false;
|
|
},
|
|
/**
|
|
* Returns `true` if the passed value is a TextNode
|
|
* @param {Object} value The value to test.
|
|
* @return {Boolean}
|
|
*/
|
|
isTextNode: function(value) {
|
|
return value ? value.nodeName === "#text" : false;
|
|
},
|
|
/**
|
|
* Returns `true` if the passed value is defined.
|
|
* @param {Object} value The value to test.
|
|
* @return {Boolean}
|
|
*/
|
|
isDefined: function(value) {
|
|
return typeof value !== 'undefined';
|
|
},
|
|
/**
|
|
* Returns `true` if the passed value is iterable, that is, if elements of it are addressable using array
|
|
* notation with numeric indices, `false` otherwise.
|
|
*
|
|
* Arrays and function `arguments` objects are iterable. Also HTML collections such as `NodeList` and `HTMLCollection'
|
|
* are iterable.
|
|
*
|
|
* @param {Object} value The value to test
|
|
* @return {Boolean}
|
|
*/
|
|
isIterable: function(value) {
|
|
// To be iterable, the object must have a numeric length property and must not be a string or function.
|
|
if (!value || typeof value.length !== 'number' || typeof value === 'string' || Ext.isFunction(value)) {
|
|
return false;
|
|
}
|
|
// Certain "standard" collections in IE (such as document.images) do not offer the correct
|
|
// Javascript Object interface; specifically, they lack the propertyIsEnumerable method.
|
|
// And the item property while it does exist is not typeof "function"
|
|
if (!value.propertyIsEnumerable) {
|
|
return !!value.item;
|
|
}
|
|
// If it is a regular, interrogatable JS object (not an IE ActiveX object), then...
|
|
// If it has its own property called "length", but not enumerable, it's iterable
|
|
if (value.hasOwnProperty('length') && !value.propertyIsEnumerable('length')) {
|
|
return true;
|
|
}
|
|
// Test against whitelist which includes known iterable collection types
|
|
return iterableRe.test(toString.call(value));
|
|
},
|
|
/**
|
|
* This method returns `true` if debug is enabled for the specified class. This is
|
|
* done by checking the `Ext.debugConfig.hooks` config for the closest match to the
|
|
* given `className`.
|
|
* @param {String} className The name of the class.
|
|
* @return {Boolean} `true` if debug is enabled for the specified class.
|
|
*/
|
|
isDebugEnabled: function(className, defaultEnabled) {
|
|
var debugConfig = Ext.debugConfig.hooks;
|
|
if (debugConfig.hasOwnProperty(className)) {
|
|
return debugConfig[className];
|
|
}
|
|
var enabled = debugConfig['*'],
|
|
prefixLength = 0;
|
|
if (defaultEnabled !== undefined) {
|
|
enabled = defaultEnabled;
|
|
}
|
|
if (!className) {
|
|
return enabled;
|
|
}
|
|
for (var prefix in debugConfig) {
|
|
var value = debugConfig[prefix];
|
|
// if prefix=='Ext' match 'Ext.foo.Bar' but not 'Ext4.foo.Bar'
|
|
if (className.charAt(prefix.length) === '.') {
|
|
if (className.substring(0, prefix.length) === prefix) {
|
|
if (prefixLength < prefix.length) {
|
|
prefixLength = prefix.length;
|
|
enabled = value;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return enabled;
|
|
} || emptyFn,
|
|
/**
|
|
* Clone simple variables including array, {}-like objects, DOM nodes and Date without keeping the old reference.
|
|
* A reference for the object itself is returned if it's not a direct descendant of Object. For model cloning,
|
|
* see {@link Ext.data.Model#copy Model.copy}.
|
|
*
|
|
* @param {Object} item The variable to clone
|
|
* @param {Boolean} [cloneDom=true] `true` to clone DOM nodes.
|
|
* @return {Object} clone
|
|
*/
|
|
clone: function(item, cloneDom) {
|
|
if (item === null || item === undefined) {
|
|
return item;
|
|
}
|
|
// DOM nodes
|
|
// TODO proxy this to Ext.Element.clone to handle automatic id attribute changing
|
|
// recursively
|
|
if (cloneDom !== false && item.nodeType && item.cloneNode) {
|
|
return item.cloneNode(true);
|
|
}
|
|
var type = toString.call(item),
|
|
i, j, k, clone, key;
|
|
// Date
|
|
if (type === '[object Date]') {
|
|
return new Date(item.getTime());
|
|
}
|
|
// Array
|
|
if (type === '[object Array]') {
|
|
i = item.length;
|
|
clone = [];
|
|
while (i--) {
|
|
clone[i] = Ext.clone(item[i], cloneDom);
|
|
}
|
|
}
|
|
// Object
|
|
else if (type === '[object Object]' && item.constructor === Object) {
|
|
clone = {};
|
|
for (key in item) {
|
|
clone[key] = Ext.clone(item[key], cloneDom);
|
|
}
|
|
if (enumerables) {
|
|
for (j = enumerables.length; j--; ) {
|
|
k = enumerables[j];
|
|
if (item.hasOwnProperty(k)) {
|
|
clone[k] = item[k];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return clone || item;
|
|
},
|
|
/**
|
|
* @private
|
|
* Generate a unique reference of Ext in the global scope, useful for sandboxing
|
|
*/
|
|
getUniqueGlobalNamespace: function() {
|
|
var uniqueGlobalNamespace = this.uniqueGlobalNamespace,
|
|
i;
|
|
if (uniqueGlobalNamespace === undefined) {
|
|
i = 0;
|
|
do {
|
|
uniqueGlobalNamespace = 'ExtBox' + (++i);
|
|
} while (global[uniqueGlobalNamespace] !== undefined);
|
|
global[uniqueGlobalNamespace] = Ext;
|
|
this.uniqueGlobalNamespace = uniqueGlobalNamespace;
|
|
}
|
|
return uniqueGlobalNamespace;
|
|
},
|
|
/**
|
|
* @private
|
|
*/
|
|
functionFactoryCache: {},
|
|
cacheableFunctionFactory: function() {
|
|
var me = this,
|
|
args = Array.prototype.slice.call(arguments),
|
|
cache = me.functionFactoryCache,
|
|
idx, fn, ln;
|
|
if (Ext.isSandboxed) {
|
|
ln = args.length;
|
|
if (ln > 0) {
|
|
ln--;
|
|
args[ln] = 'var Ext=window.' + Ext.name + ';' + args[ln];
|
|
}
|
|
}
|
|
idx = args.join('');
|
|
fn = cache[idx];
|
|
if (!fn) {
|
|
fn = Function.prototype.constructor.apply(Function.prototype, args);
|
|
cache[idx] = fn;
|
|
}
|
|
return fn;
|
|
},
|
|
functionFactory: function() {
|
|
var args = Array.prototype.slice.call(arguments),
|
|
ln;
|
|
if (Ext.isSandboxed) {
|
|
ln = args.length;
|
|
if (ln > 0) {
|
|
ln--;
|
|
args[ln] = 'var Ext=window.' + Ext.name + ';' + args[ln];
|
|
}
|
|
}
|
|
return Function.prototype.constructor.apply(Function.prototype, args);
|
|
},
|
|
/**
|
|
* @private
|
|
*/
|
|
Logger: {
|
|
log: function(message, priority) {
|
|
if (message && global.console) {
|
|
if (!priority || !(priority in global.console)) {
|
|
priority = 'log';
|
|
}
|
|
message = '[' + priority.toUpperCase() + '] ' + message;
|
|
global.console[priority](message);
|
|
}
|
|
},
|
|
verbose: function(message) {
|
|
this.log(message, 'verbose');
|
|
},
|
|
info: function(message) {
|
|
this.log(message, 'info');
|
|
},
|
|
warn: function(message) {
|
|
this.log(message, 'warn');
|
|
},
|
|
error: function(message) {
|
|
throw new Error(message);
|
|
},
|
|
deprecate: function(message) {
|
|
this.log(message, 'warn');
|
|
}
|
|
} || {
|
|
verbose: emptyFn,
|
|
log: emptyFn,
|
|
info: emptyFn,
|
|
warn: emptyFn,
|
|
error: function(message) {
|
|
throw new Error(message);
|
|
},
|
|
deprecate: emptyFn
|
|
},
|
|
ariaWarn: function(target, msg) {
|
|
// The checks still can be disabled by setting Ext.enableAria to false;
|
|
// this is for backwards compatibility. Also make sure we're not running
|
|
// under the slicer, warnings are pointless in that case.
|
|
if (Ext.enableAria && !Ext.slicer) {
|
|
if (!Ext.ariaWarn.first) {
|
|
Ext.ariaWarn.first = true;
|
|
Ext.log.warn("WAI-ARIA compatibility warnings can be suppressed " + "by adding the following to application startup code:");
|
|
Ext.log.warn(" Ext.ariaWarn = Ext.emptyFn;");
|
|
}
|
|
Ext.log.warn({
|
|
msg: msg,
|
|
dump: target
|
|
});
|
|
}
|
|
},
|
|
/**
|
|
* @private
|
|
*/
|
|
getElementById: function(id) {
|
|
return document.getElementById(id);
|
|
},
|
|
/**
|
|
* @member Ext
|
|
* @private
|
|
*/
|
|
splitAndUnescape: (function() {
|
|
var cache = {};
|
|
return function(origin, delimiter) {
|
|
if (!origin) {
|
|
return [];
|
|
} else if (!delimiter) {
|
|
return [
|
|
origin
|
|
];
|
|
}
|
|
var replaceRe = cache[delimiter] || (cache[delimiter] = new RegExp('\\\\' + delimiter, 'g')),
|
|
result = [],
|
|
parts, part;
|
|
parts = origin.split(delimiter);
|
|
while ((part = parts.shift()) !== undefined) {
|
|
// If any of the parts ends with the delimiter that means
|
|
// the delimiter was escaped and the split was invalid. Roll back.
|
|
while (part.charAt(part.length - 1) === '\\' && parts.length > 0) {
|
|
part = part + delimiter + parts.shift();
|
|
}
|
|
// Now that we have split the parts, unescape the delimiter char
|
|
part = part.replace(replaceRe, delimiter);
|
|
result.push(part);
|
|
}
|
|
return result;
|
|
};
|
|
})()
|
|
});
|
|
// Ext.apply(Ext
|
|
Ext.returnTrue.$nullFn = Ext.returnId.$nullFn = true;
|
|
}());
|
|
|
|
// @override Ext
|
|
// This file is order extremely early (typically right after Ext.js) due to the
|
|
// above Cmd directive. This ensures that the "modern" and "classic" platform tags
|
|
// are properly set up as soon as possible.
|
|
Ext.platformTags.modern = !(Ext.platformTags.classic = Ext.isClassic = true);
|
|
|
|
/**
|
|
* A helper class for the native JavaScript Error object that adds a few useful capabilities for handling
|
|
* errors in an application. When you use Ext.Error to {@link #raise} an error from within any class that
|
|
* uses the Class System, the Error class can automatically add the source class and method from which
|
|
* the error was raised. It also includes logic to automatically log the error to the console, if available,
|
|
* with additional metadata about the error. In all cases, the error will always be thrown at the end so that
|
|
* execution will halt.
|
|
*
|
|
* Ext.Error also offers a global error {@link #handle handling} method that can be overridden in order to
|
|
* handle application-wide errors in a single spot. You can optionally {@link #ignore} errors altogether,
|
|
* although in a real application it's usually a better idea to override the handling function and perform
|
|
* logging or some other method of reporting the errors in a way that is meaningful to the application.
|
|
*
|
|
* At its simplest you can simply raise an error as a simple string from within any code:
|
|
*
|
|
* Example usage:
|
|
*
|
|
* Ext.raise('Something bad happened!');
|
|
*
|
|
* If raised from plain JavaScript code, the error will be logged to the console (if available) and the message
|
|
* displayed. In most cases however you'll be raising errors from within a class, and it may often be useful to add
|
|
* additional metadata about the error being raised. The {@link #raise} method can also take a config object.
|
|
* In this form the `msg` attribute becomes the error description, and any other data added to the config gets
|
|
* added to the error object and, if the console is available, logged to the console for inspection.
|
|
*
|
|
* Example usage:
|
|
*
|
|
* Ext.define('Ext.Foo', {
|
|
* doSomething: function(option){
|
|
* if (someCondition === false) {
|
|
* Ext.raise({
|
|
* msg: 'You cannot do that!',
|
|
* option: option, // whatever was passed into the method
|
|
* 'error code': 100 // other arbitrary info
|
|
* });
|
|
* }
|
|
* }
|
|
* });
|
|
*
|
|
* If a console is available (that supports the `console.dir` function) you'll see console output like:
|
|
*
|
|
* An error was raised with the following data:
|
|
* option: Object { foo: "bar"}
|
|
* foo: "bar"
|
|
* error code: 100
|
|
* msg: "You cannot do that!"
|
|
* sourceClass: "Ext.Foo"
|
|
* sourceMethod: "doSomething"
|
|
*
|
|
* uncaught exception: You cannot do that!
|
|
*
|
|
* As you can see, the error will report exactly where it was raised and will include as much information as the
|
|
* raising code can usefully provide.
|
|
*
|
|
* If you want to handle all application errors globally you can simply override the static {@link #handle} method
|
|
* and provide whatever handling logic you need. If the method returns true then the error is considered handled
|
|
* and will not be thrown to the browser. If anything but true is returned then the error will be thrown normally.
|
|
*
|
|
* Example usage:
|
|
*
|
|
* Ext.Error.handle = function(err) {
|
|
* if (err.someProperty == 'NotReallyAnError') {
|
|
* // maybe log something to the application here if applicable
|
|
* return true;
|
|
* }
|
|
* // any non-true return value (including none) will cause the error to be thrown
|
|
* }
|
|
*
|
|
* @class Ext.Error
|
|
*/
|
|
(function() {
|
|
// @define Ext.lang.Error
|
|
// @define Ext.Error
|
|
// @require Ext
|
|
function toString() {
|
|
var me = this,
|
|
cls = me.sourceClass,
|
|
method = me.sourceMethod,
|
|
msg = me.msg;
|
|
if (method) {
|
|
if (msg) {
|
|
method += '(): ';
|
|
method += msg;
|
|
} else {
|
|
method += '()';
|
|
}
|
|
}
|
|
if (cls) {
|
|
method = method ? (cls + '.' + method) : cls;
|
|
}
|
|
return method || msg || '';
|
|
}
|
|
Ext.Error = function(config) {
|
|
if (Ext.isString(config)) {
|
|
config = {
|
|
msg: config
|
|
};
|
|
}
|
|
var error = new Error();
|
|
Ext.apply(error, config);
|
|
error.message = error.message || error.msg;
|
|
// 'message' is standard ('msg' is non-standard)
|
|
// note: the above does not work in old WebKit (me.message is readonly) (Safari 4)
|
|
error.toString = toString;
|
|
return error;
|
|
};
|
|
Ext.apply(Ext.Error, {
|
|
/**
|
|
* @property {Boolean} ignore
|
|
* Static flag that can be used to globally disable error reporting to the browser if set to true
|
|
* (defaults to false). Note that if you ignore Ext errors it's likely that some other code may fail
|
|
* and throw a native JavaScript error thereafter, so use with caution. In most cases it will probably
|
|
* be preferable to supply a custom error {@link #handle handling} function instead.
|
|
*
|
|
* Example usage:
|
|
*
|
|
* Ext.Error.ignore = true;
|
|
*
|
|
* @static
|
|
*/
|
|
ignore: false,
|
|
/**
|
|
* This method is called internally by {@link Ext#raise}. Application code should
|
|
* call {@link Ext#raise} instead of calling this method directly.
|
|
*
|
|
* @static
|
|
* @deprecated 6.0.0 Use {@link Ext#raise} instead.
|
|
*/
|
|
raise: function(err) {
|
|
err = err || {};
|
|
if (Ext.isString(err)) {
|
|
err = {
|
|
msg: err
|
|
};
|
|
}
|
|
var me = this,
|
|
method = me.raise.caller,
|
|
msg, name;
|
|
if (method === Ext.raise) {
|
|
method = method.caller;
|
|
}
|
|
if (method) {
|
|
if (!err.sourceMethod && (name = method.$name)) {
|
|
err.sourceMethod = name;
|
|
}
|
|
if (!err.sourceClass && (name = method.$owner) && (name = name.$className)) {
|
|
err.sourceClass = name;
|
|
}
|
|
}
|
|
if (me.handle(err) !== true) {
|
|
msg = toString.call(err);
|
|
Ext.log({
|
|
msg: msg,
|
|
level: 'error',
|
|
dump: err,
|
|
stack: true
|
|
});
|
|
throw new Ext.Error(err);
|
|
}
|
|
},
|
|
/**
|
|
* Globally handle any Ext errors that may be raised, optionally providing custom logic to
|
|
* handle different errors individually. Return true from the function to bypass throwing the
|
|
* error to the browser, otherwise the error will be thrown and execution will halt.
|
|
*
|
|
* Example usage:
|
|
*
|
|
* Ext.Error.handle = function(err) {
|
|
* if (err.someProperty == 'NotReallyAnError') {
|
|
* // maybe log something to the application here if applicable
|
|
* return true;
|
|
* }
|
|
* // any non-true return value (including none) will cause the error to be thrown
|
|
* }
|
|
*
|
|
* @param {Object} err The error being raised. It will contain any attributes that were originally
|
|
* raised with it, plus properties about the method and class from which the error originated
|
|
* (if raised from a class that uses the Class System).
|
|
* @static
|
|
*/
|
|
handle: function() {
|
|
return this.ignore;
|
|
}
|
|
});
|
|
})();
|
|
/**
|
|
* Create a function that will throw an error if called (in debug mode) with a message that
|
|
* indicates the method has been removed.
|
|
* @param {String} suggestion Optional text to include in the message (a workaround perhaps).
|
|
* @return {Function} The generated function.
|
|
* @private
|
|
*/
|
|
Ext.deprecated = function(suggestion) {
|
|
if (!suggestion) {
|
|
suggestion = '';
|
|
}
|
|
function fail() {
|
|
Ext.raise('The method "' + fail.$owner.$className + '.' + fail.$name + '" has been removed. ' + suggestion);
|
|
}
|
|
return fail;
|
|
return Ext.emptyFn;
|
|
};
|
|
/**
|
|
* Raise an error that can include additional data and supports automatic console logging
|
|
* if available. You can pass a string error message or an object with the `msg` attribute
|
|
* which will be used as the error message. The object can contain any other name-value
|
|
* attributes (or objects) to be logged along with the error.
|
|
*
|
|
* Note that after displaying the error message a JavaScript error will ultimately be
|
|
* thrown so that execution will halt.
|
|
*
|
|
* Example usage:
|
|
*
|
|
* Ext.raise('A simple string error message');
|
|
*
|
|
* // or...
|
|
*
|
|
* Ext.define('Ext.Foo', {
|
|
* doSomething: function(option){
|
|
* if (someCondition === false) {
|
|
* Ext.raise({
|
|
* msg: 'You cannot do that!',
|
|
* option: option, // whatever was passed into the method
|
|
* code: 100 // other arbitrary info
|
|
* });
|
|
* }
|
|
* }
|
|
* });
|
|
*
|
|
* @param {String/Object} err The error message string, or an object containing the
|
|
* attribute "msg" that will be used as the error message. Any other data included in the
|
|
* object will also be logged to the browser console, if available.
|
|
* @method raise
|
|
* @member Ext
|
|
*/
|
|
Ext.raise = function() {
|
|
Ext.Error.raise.apply(Ext.Error, arguments);
|
|
};
|
|
/*
|
|
* This mechanism is used to notify the user of the first error encountered on the page. In
|
|
* most cases errors go unobserved especially on IE. This mechanism pushes this information
|
|
* to the status bar so that users don't miss it.
|
|
*/
|
|
(function() {
|
|
if (typeof window === 'undefined') {
|
|
return;
|
|
}
|
|
// build system or some such environment...
|
|
var last = 0,
|
|
// This method is called to notify the user of the current error status.
|
|
notify = function() {
|
|
var cnt = Ext.log && Ext.log.counters,
|
|
n = cnt && (cnt.error + cnt.warn + cnt.info + cnt.log),
|
|
msg;
|
|
// Put log counters to the status bar (for most browsers):
|
|
if (n && last !== n) {
|
|
msg = [];
|
|
if (cnt.error) {
|
|
msg.push('Errors: ' + cnt.error);
|
|
}
|
|
if (cnt.warn) {
|
|
msg.push('Warnings: ' + cnt.warn);
|
|
}
|
|
if (cnt.info) {
|
|
msg.push('Info: ' + cnt.info);
|
|
}
|
|
if (cnt.log) {
|
|
msg.push('Log: ' + cnt.log);
|
|
}
|
|
window.status = '*** ' + msg.join(' -- ');
|
|
last = n;
|
|
}
|
|
};
|
|
// window.onerror sounds ideal but it prevents the built-in error dialog from doing
|
|
// its (better) thing.
|
|
setInterval(notify, 1000);
|
|
}());
|
|
|
|
/**
|
|
* @class Ext.Array
|
|
* @singleton
|
|
*
|
|
* A set of useful static methods to deal with arrays; provide missing methods for
|
|
* older browsers.
|
|
*/
|
|
Ext.Array = (function() {
|
|
// @define Ext.lang.Array
|
|
// @define Ext.Array
|
|
// @require Ext
|
|
// @require Ext.lang.Error
|
|
var arrayPrototype = Array.prototype,
|
|
slice = arrayPrototype.slice,
|
|
supportsSplice = (function() {
|
|
var array = [],
|
|
lengthBefore,
|
|
j = 20;
|
|
if (!array.splice) {
|
|
return false;
|
|
}
|
|
// This detects a bug in IE8 splice method:
|
|
// see http://social.msdn.microsoft.com/Forums/en-US/iewebdevelopment/thread/6e946d03-e09f-4b22-a4dd-cd5e276bf05a/
|
|
while (j--) {
|
|
array.push("A");
|
|
}
|
|
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");
|
|
lengthBefore = array.length;
|
|
//41
|
|
array.splice(13, 0, "XXX");
|
|
// add one element
|
|
if (lengthBefore + 1 !== array.length) {
|
|
return false;
|
|
}
|
|
// end IE8 bug
|
|
return true;
|
|
}()),
|
|
supportsIndexOf = 'indexOf' in arrayPrototype,
|
|
supportsSliceOnNodeList = true;
|
|
// Sort an array using the comparator, but if the comparator returns zero, use the objects' original indices to tiebreak
|
|
// This results in a stable sort.
|
|
function stableSort(array, userComparator) {
|
|
var len = array.length,
|
|
indices = new Array(len),
|
|
i;
|
|
// generate 0-n index map from original array
|
|
for (i = 0; i < len; i++) {
|
|
indices[i] = i;
|
|
}
|
|
// Sort indices array using a comparator which compares the original values at the two indices, and uses those indices as a tiebreaker
|
|
indices.sort(function(index1, index2) {
|
|
return userComparator(array[index1], array[index2]) || (index1 - index2);
|
|
});
|
|
// Reconsitute a sorted array using the array that the indices have been sorted into
|
|
for (i = 0; i < len; i++) {
|
|
indices[i] = array[indices[i]];
|
|
}
|
|
// Rebuild the original array
|
|
for (i = 0; i < len; i++) {
|
|
array[i] = indices[i];
|
|
}
|
|
return array;
|
|
}
|
|
try {
|
|
// IE 6 - 8 will throw an error when using Array.prototype.slice on NodeList
|
|
if (typeof document !== 'undefined') {
|
|
slice.call(document.getElementsByTagName('body'));
|
|
}
|
|
} catch (e) {
|
|
supportsSliceOnNodeList = false;
|
|
}
|
|
var fixArrayIndex = function(array, index) {
|
|
return (index < 0) ? Math.max(0, array.length + index) : Math.min(array.length, index);
|
|
},
|
|
/*
|
|
Does the same work as splice, but with a slightly more convenient signature. The splice
|
|
method has bugs in IE8, so this is the implementation we use on that platform.
|
|
|
|
The rippling of items in the array can be tricky. Consider two use cases:
|
|
|
|
index=2
|
|
removeCount=2
|
|
/=====\
|
|
+---+---+---+---+---+---+---+---+
|
|
| 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
|
|
+---+---+---+---+---+---+---+---+
|
|
/ \/ \/ \/ \
|
|
/ /\ /\ /\ \
|
|
/ / \/ \/ \ +--------------------------+
|
|
/ / /\ /\ +--------------------------+ \
|
|
/ / / \/ +--------------------------+ \ \
|
|
/ / / /+--------------------------+ \ \ \
|
|
/ / / / \ \ \ \
|
|
v v v v v v v v
|
|
+---+---+---+---+---+---+ +---+---+---+---+---+---+---+---+---+
|
|
| 0 | 1 | 4 | 5 | 6 | 7 | | 0 | 1 | a | b | c | 4 | 5 | 6 | 7 |
|
|
+---+---+---+---+---+---+ +---+---+---+---+---+---+---+---+---+
|
|
A B \=========/
|
|
insert=[a,b,c]
|
|
|
|
In case A, it is obvious that copying of [4,5,6,7] must be left-to-right so
|
|
that we don't end up with [0,1,6,7,6,7]. In case B, we have the opposite; we
|
|
must go right-to-left or else we would end up with [0,1,a,b,c,4,4,4,4].
|
|
*/
|
|
replaceSim = function(array, index, removeCount, insert) {
|
|
var add = insert ? insert.length : 0,
|
|
length = array.length,
|
|
pos = fixArrayIndex(array, index);
|
|
// we try to use Array.push when we can for efficiency...
|
|
if (pos === length) {
|
|
if (add) {
|
|
array.push.apply(array, insert);
|
|
}
|
|
} else {
|
|
var remove = Math.min(removeCount, length - pos),
|
|
tailOldPos = pos + remove,
|
|
tailNewPos = tailOldPos + add - remove,
|
|
tailCount = length - tailOldPos,
|
|
lengthAfterRemove = length - remove,
|
|
i;
|
|
if (tailNewPos < tailOldPos) {
|
|
// case A
|
|
for (i = 0; i < tailCount; ++i) {
|
|
array[tailNewPos + i] = array[tailOldPos + i];
|
|
}
|
|
} else if (tailNewPos > tailOldPos) {
|
|
// case B
|
|
for (i = tailCount; i--; ) {
|
|
array[tailNewPos + i] = array[tailOldPos + i];
|
|
}
|
|
}
|
|
// else, add == remove (nothing to do)
|
|
if (add && pos === lengthAfterRemove) {
|
|
array.length = lengthAfterRemove;
|
|
// truncate array
|
|
array.push.apply(array, insert);
|
|
} else {
|
|
array.length = lengthAfterRemove + add;
|
|
// reserves space
|
|
for (i = 0; i < add; ++i) {
|
|
array[pos + i] = insert[i];
|
|
}
|
|
}
|
|
}
|
|
return array;
|
|
},
|
|
replaceNative = function(array, index, removeCount, insert) {
|
|
if (insert && insert.length) {
|
|
// Inserting at index zero with no removing: use unshift
|
|
if (index === 0 && !removeCount) {
|
|
array.unshift.apply(array, insert);
|
|
}
|
|
// Inserting/replacing in middle of array
|
|
else if (index < array.length) {
|
|
array.splice.apply(array, [
|
|
index,
|
|
removeCount
|
|
].concat(insert));
|
|
} else // Appending to array
|
|
{
|
|
array.push.apply(array, insert);
|
|
}
|
|
} else {
|
|
array.splice(index, removeCount);
|
|
}
|
|
return array;
|
|
},
|
|
eraseSim = function(array, index, removeCount) {
|
|
return replaceSim(array, index, removeCount);
|
|
},
|
|
eraseNative = function(array, index, removeCount) {
|
|
array.splice(index, removeCount);
|
|
return array;
|
|
},
|
|
spliceSim = function(array, index, removeCount) {
|
|
var len = arguments.length,
|
|
pos = fixArrayIndex(array, index),
|
|
removed;
|
|
if (len < 3) {
|
|
removeCount = array.length - pos;
|
|
}
|
|
removed = array.slice(index, fixArrayIndex(array, pos + removeCount));
|
|
if (len < 4) {
|
|
replaceSim(array, pos, removeCount);
|
|
} else {
|
|
replaceSim(array, pos, removeCount, slice.call(arguments, 3));
|
|
}
|
|
return removed;
|
|
},
|
|
spliceNative = function(array) {
|
|
return array.splice.apply(array, slice.call(arguments, 1));
|
|
},
|
|
erase = supportsSplice ? eraseNative : eraseSim,
|
|
replace = supportsSplice ? replaceNative : replaceSim,
|
|
splice = supportsSplice ? spliceNative : spliceSim,
|
|
// NOTE: from here on, use erase, replace or splice (not native methods)...
|
|
ExtArray = {
|
|
/**
|
|
* This method returns the index that a given item would be inserted into the
|
|
* given (sorted) `array`. Note that the given `item` may or may not be in the
|
|
* array. This method will return the index of where the item *should* be.
|
|
*
|
|
* For example:
|
|
*
|
|
* var array = [ 'A', 'D', 'G', 'K', 'O', 'R', 'X' ];
|
|
* var index = Ext.Array.binarySearch(array, 'E');
|
|
*
|
|
* console.log('index: ' + index);
|
|
* // logs "index: 2"
|
|
*
|
|
* array.splice(index, 0, 'E');
|
|
*
|
|
* console.log('array : ' + array.join(''));
|
|
* // logs "array: ADEGKORX"
|
|
*
|
|
* @param {Object[]} array The array to search.
|
|
* @param {Object} item The item that you want to insert into the `array`.
|
|
* @param {Number} [begin=0] The first index in the `array` to consider.
|
|
* @param {Number} [end=array.length] The index that marks the end of the range
|
|
* to consider. The item at this index is *not* considered.
|
|
* @param {Function} [compareFn] The comparison function that matches the sort
|
|
* order of the `array`. The default `compareFn` compares items using less-than
|
|
* and greater-than operators.
|
|
* @return {Number} The index for the given item in the given array based on
|
|
* the current sorters.
|
|
*/
|
|
binarySearch: function(array, item, begin, end, compareFn) {
|
|
var length = array.length,
|
|
middle, comparison;
|
|
if (begin instanceof Function) {
|
|
compareFn = begin;
|
|
begin = 0;
|
|
end = length;
|
|
} else if (end instanceof Function) {
|
|
compareFn = end;
|
|
end = length;
|
|
} else {
|
|
if (begin === undefined) {
|
|
begin = 0;
|
|
}
|
|
if (end === undefined) {
|
|
end = length;
|
|
}
|
|
compareFn = compareFn || ExtArray.lexicalCompare;
|
|
}
|
|
--end;
|
|
while (begin <= end) {
|
|
middle = (begin + end) >> 1;
|
|
comparison = compareFn(item, array[middle]);
|
|
if (comparison >= 0) {
|
|
begin = middle + 1;
|
|
} else if (comparison < 0) {
|
|
end = middle - 1;
|
|
}
|
|
}
|
|
return begin;
|
|
},
|
|
defaultCompare: function(lhs, rhs) {
|
|
return (lhs < rhs) ? -1 : ((lhs > rhs) ? 1 : 0);
|
|
},
|
|
// Default comparator to use when no comparator is specified for the sort method.
|
|
// Javascript sort does LEXICAL comparison.
|
|
lexicalCompare: function(lhs, rhs) {
|
|
lhs = String(lhs);
|
|
rhs = String(rhs);
|
|
return (lhs < rhs) ? -1 : ((lhs > rhs) ? 1 : 0);
|
|
},
|
|
/**
|
|
* Iterates an array or an iterable value and invoke the given callback function for each item.
|
|
*
|
|
* var countries = ['Vietnam', 'Singapore', 'United States', 'Russia'];
|
|
*
|
|
* Ext.Array.each(countries, function(name, index, countriesItSelf) {
|
|
* console.log(name);
|
|
* });
|
|
*
|
|
* var sum = function() {
|
|
* var sum = 0;
|
|
*
|
|
* Ext.Array.each(arguments, function(value) {
|
|
* sum += value;
|
|
* });
|
|
*
|
|
* return sum;
|
|
* };
|
|
*
|
|
* sum(1, 2, 3); // returns 6
|
|
*
|
|
* The iteration can be stopped by returning `false` from the callback function.
|
|
* Returning `undefined` (i.e `return;`) will only exit the callback function and
|
|
* proceed with the next iteration of the loop.
|
|
*
|
|
* Ext.Array.each(countries, function(name, index, countriesItSelf) {
|
|
* if (name === 'Singapore') {
|
|
* return false; // break here
|
|
* }
|
|
* });
|
|
*
|
|
* {@link Ext#each Ext.each} is alias for {@link Ext.Array#each Ext.Array.each}
|
|
*
|
|
* @param {Array/NodeList/Object} iterable The value to be iterated. If this
|
|
* argument is not iterable, the callback function is called once.
|
|
* @param {Function} fn The callback function. If it returns `false`, the iteration
|
|
* stops and this method returns the current `index`. Returning `undefined` (i.e
|
|
* `return;`) will only exit the callback function and proceed with the next iteration
|
|
* in the loop.
|
|
* @param {Object} fn.item The item at the current `index` in the passed `array`
|
|
* @param {Number} fn.index The current `index` within the `array`
|
|
* @param {Array} fn.allItems The `array` itself which was passed as the first argument
|
|
* @param {Boolean} fn.return Return `false` to stop iteration.
|
|
* @param {Object} [scope] The scope (`this` reference) in which the specified function is executed.
|
|
* @param {Boolean} [reverse=false] Reverse the iteration order (loop from the end to the beginning).
|
|
* @return {Boolean} See description for the `fn` parameter.
|
|
*/
|
|
each: function(array, fn, scope, reverse) {
|
|
array = ExtArray.from(array);
|
|
var i,
|
|
ln = array.length;
|
|
if (reverse !== true) {
|
|
for (i = 0; i < ln; i++) {
|
|
if (fn.call(scope || array[i], array[i], i, array) === false) {
|
|
return i;
|
|
}
|
|
}
|
|
} else {
|
|
for (i = ln - 1; i > -1; i--) {
|
|
if (fn.call(scope || array[i], array[i], i, array) === false) {
|
|
return i;
|
|
}
|
|
}
|
|
}
|
|
return true;
|
|
},
|
|
/**
|
|
* @method
|
|
* Iterates an array and invoke the given callback function for each item. Note that this will simply
|
|
* delegate to the native `Array.prototype.forEach` method if supported. It doesn't support stopping the
|
|
* iteration by returning `false` in the callback function like {@link Ext.Array#each}. However, performance
|
|
* could be much better in modern browsers comparing with {@link Ext.Array#each}
|
|
*
|
|
* @param {Array} array The array to iterate.
|
|
* @param {Function} fn The callback function.
|
|
* @param {Object} fn.item The item at the current `index` in the passed `array`.
|
|
* @param {Number} fn.index The current `index` within the `array`.
|
|
* @param {Array} fn.allItems The `array` itself which was passed as the first argument.
|
|
* @param {Object} scope (Optional) The execution scope (`this`) in which the
|
|
* specified function is executed.
|
|
*/
|
|
forEach: ('forEach' in arrayPrototype) ? function(array, fn, scope) {
|
|
return array.forEach(fn, scope);
|
|
} : function(array, fn, scope) {
|
|
for (var i = 0,
|
|
ln = array.length; i < ln; i++) {
|
|
fn.call(scope, array[i], i, array);
|
|
}
|
|
},
|
|
/**
|
|
* @method
|
|
* Get the index of the provided `item` in the given `array`, a supplement for the
|
|
* missing arrayPrototype.indexOf in Internet Explorer.
|
|
*
|
|
* @param {Array} array The array to check.
|
|
* @param {Object} item The item to find.
|
|
* @param {Number} from (Optional) The index at which to begin the search.
|
|
* @return {Number} The index of item in the array (or -1 if it is not found).
|
|
*/
|
|
indexOf: supportsIndexOf ? function(array, item, from) {
|
|
// May be called with no array which causes an error.
|
|
return array ? arrayPrototype.indexOf.call(array, item, from) : -1;
|
|
} : function(array, item, from) {
|
|
var i,
|
|
length = array ? array.length : 0;
|
|
for (i = (from < 0) ? Math.max(0, length + from) : from || 0; i < length; i++) {
|
|
if (array[i] === item) {
|
|
return i;
|
|
}
|
|
}
|
|
return -1;
|
|
},
|
|
/**
|
|
* @method
|
|
* Checks whether or not the given `array` contains the specified `item`.
|
|
*
|
|
* @param {Array} array The array to check.
|
|
* @param {Object} item The item to find.
|
|
* @return {Boolean} `true` if the array contains the item, `false` otherwise.
|
|
*/
|
|
contains: supportsIndexOf ? function(array, item) {
|
|
return arrayPrototype.indexOf.call(array, item) !== -1;
|
|
} : function(array, item) {
|
|
var i, ln;
|
|
for (i = 0 , ln = array.length; i < ln; i++) {
|
|
if (array[i] === item) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
},
|
|
/**
|
|
* Converts any iterable (numeric indices and a length property) into a true array.
|
|
*
|
|
* function test() {
|
|
* var args = Ext.Array.toArray(arguments),
|
|
* fromSecondToLastArgs = Ext.Array.toArray(arguments, 1);
|
|
*
|
|
* alert(args.join(' '));
|
|
* alert(fromSecondToLastArgs.join(' '));
|
|
* }
|
|
*
|
|
* test('just', 'testing', 'here'); // alerts 'just testing here';
|
|
* // alerts 'testing here';
|
|
*
|
|
* Ext.Array.toArray(document.getElementsByTagName('div')); // will convert the NodeList into an array
|
|
* Ext.Array.toArray('splitted'); // returns ['s', 'p', 'l', 'i', 't', 't', 'e', 'd']
|
|
* Ext.Array.toArray('splitted', 0, 3); // returns ['s', 'p', 'l']
|
|
*
|
|
* {@link Ext#toArray Ext.toArray} is alias for {@link Ext.Array#toArray Ext.Array.toArray}
|
|
*
|
|
* @param {Object} iterable the iterable object to be turned into a true Array.
|
|
* @param {Number} [start=0] a zero-based index that specifies the start of extraction.
|
|
* @param {Number} [end=-1] a 1-based index that specifies the end of extraction.
|
|
* @return {Array}
|
|
*/
|
|
toArray: function(iterable, start, end) {
|
|
if (!iterable || !iterable.length) {
|
|
return [];
|
|
}
|
|
if (typeof iterable === 'string') {
|
|
iterable = iterable.split('');
|
|
}
|
|
if (supportsSliceOnNodeList) {
|
|
return slice.call(iterable, start || 0, end || iterable.length);
|
|
}
|
|
var array = [],
|
|
i;
|
|
start = start || 0;
|
|
end = end ? ((end < 0) ? iterable.length + end : end) : iterable.length;
|
|
for (i = start; i < end; i++) {
|
|
array.push(iterable[i]);
|
|
}
|
|
return array;
|
|
},
|
|
/**
|
|
* Plucks the value of a property from each item in the Array. Example:
|
|
*
|
|
* Ext.Array.pluck(Ext.query("p"), "className"); // [el1.className, el2.className, ..., elN.className]
|
|
*
|
|
* @param {Array/NodeList} array The Array of items to pluck the value from.
|
|
* @param {String} propertyName The property name to pluck from each element.
|
|
* @return {Array} The value from each item in the Array.
|
|
*/
|
|
pluck: function(array, propertyName) {
|
|
var ret = [],
|
|
i, ln, item;
|
|
for (i = 0 , ln = array.length; i < ln; i++) {
|
|
item = array[i];
|
|
ret.push(item[propertyName]);
|
|
}
|
|
return ret;
|
|
},
|
|
/**
|
|
* @method
|
|
* Creates a new array with the results of calling a provided function on every element in this array.
|
|
*
|
|
* @param {Array} array
|
|
* @param {Function} fn Callback function for each item.
|
|
* @param {Mixed} fn.item Current item.
|
|
* @param {Number} fn.index Index of the item.
|
|
* @param {Array} fn.array The whole array that's being iterated.
|
|
* @param {Object} [scope] Callback function scope
|
|
* @return {Array} results
|
|
*/
|
|
map: ('map' in arrayPrototype) ? function(array, fn, scope) {
|
|
Ext.Assert.isFunction(fn, 'Ext.Array.map must have a callback function passed as second argument.');
|
|
return array.map(fn, scope);
|
|
} : function(array, fn, scope) {
|
|
Ext.Assert.isFunction(fn, 'Ext.Array.map must have a callback function passed as second argument.');
|
|
var len = array.length,
|
|
results = new Array(len),
|
|
i;
|
|
for (i = 0; i < len; i++) {
|
|
results[i] = fn.call(scope, array[i], i, array);
|
|
}
|
|
return results;
|
|
},
|
|
/**
|
|
* @method
|
|
* Executes the specified function for each array element until the function returns a falsy value.
|
|
* If such an item is found, the function will return `false` immediately.
|
|
* Otherwise, it will return `true`.
|
|
*
|
|
* @param {Array} array
|
|
* @param {Function} fn Callback function for each item.
|
|
* @param {Mixed} fn.item Current item.
|
|
* @param {Number} fn.index Index of the item.
|
|
* @param {Array} fn.array The whole array that's being iterated.
|
|
* @param {Object} scope Callback function scope.
|
|
* @return {Boolean} `treu` if no false value is returned by the callback function.
|
|
*/
|
|
every: ('every' in arrayPrototype) ? function(array, fn, scope) {
|
|
Ext.Assert.isFunction(fn, 'Ext.Array.every must have a callback function passed as second argument.');
|
|
return array.every(fn, scope);
|
|
} : function(array, fn, scope) {
|
|
Ext.Assert.isFunction(fn, 'Ext.Array.every must have a callback function passed as second argument.');
|
|
var i = 0,
|
|
ln = array.length;
|
|
for (; i < ln; ++i) {
|
|
if (!fn.call(scope, array[i], i, array)) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
},
|
|
/**
|
|
* @method
|
|
* Executes the specified function for each array element until the function returns a truthy value.
|
|
* If such an item is found, the function will return `true` immediately. Otherwise, it will return `false`.
|
|
*
|
|
* @param {Array} array
|
|
* @param {Function} fn Callback function for each item.
|
|
* @param {Mixed} fn.item Current item.
|
|
* @param {Number} fn.index Index of the item.
|
|
* @param {Array} fn.array The whole array that's being iterated.
|
|
* @param {Object} scope Callback function scope.
|
|
* @return {Boolean} `true` if the callback function returns a truthy value.
|
|
*/
|
|
some: ('some' in arrayPrototype) ? function(array, fn, scope) {
|
|
Ext.Assert.isFunction(fn, 'Ext.Array.some must have a callback function passed as second argument.');
|
|
return array.some(fn, scope);
|
|
} : function(array, fn, scope) {
|
|
Ext.Assert.isFunction(fn, 'Ext.Array.some must have a callback function passed as second argument.');
|
|
var i = 0,
|
|
ln = array.length;
|
|
for (; i < ln; ++i) {
|
|
if (fn.call(scope, array[i], i, array)) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
},
|
|
/**
|
|
* Shallow compares the contents of 2 arrays using strict equality.
|
|
* @param {Array} array1
|
|
* @param {Array} array2
|
|
* @return {Boolean} `true` if the arrays are equal.
|
|
*/
|
|
equals: function(array1, array2) {
|
|
var len1 = array1.length,
|
|
len2 = array2.length,
|
|
i;
|
|
// Short circuit if the same array is passed twice
|
|
if (array1 === array2) {
|
|
return true;
|
|
}
|
|
if (len1 !== len2) {
|
|
return false;
|
|
}
|
|
for (i = 0; i < len1; ++i) {
|
|
if (array1[i] !== array2[i]) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
},
|
|
/**
|
|
* Filter through an array and remove empty item as defined in {@link Ext#isEmpty Ext.isEmpty}.
|
|
*
|
|
* See {@link Ext.Array#filter}
|
|
*
|
|
* @param {Array} array
|
|
* @return {Array} results
|
|
*/
|
|
clean: function(array) {
|
|
var results = [],
|
|
i = 0,
|
|
ln = array.length,
|
|
item;
|
|
for (; i < ln; i++) {
|
|
item = array[i];
|
|
if (!Ext.isEmpty(item)) {
|
|
results.push(item);
|
|
}
|
|
}
|
|
return results;
|
|
},
|
|
/**
|
|
* Returns a new array with unique items.
|
|
*
|
|
* @param {Array} array
|
|
* @return {Array} results
|
|
*/
|
|
unique: function(array) {
|
|
var clone = [],
|
|
i = 0,
|
|
ln = array.length,
|
|
item;
|
|
for (; i < ln; i++) {
|
|
item = array[i];
|
|
if (ExtArray.indexOf(clone, item) === -1) {
|
|
clone.push(item);
|
|
}
|
|
}
|
|
return clone;
|
|
},
|
|
/**
|
|
* @method
|
|
* Creates a new array with all of the elements of this array for which
|
|
* the provided filtering function returns a truthy value.
|
|
*
|
|
* @param {Array} array
|
|
* @param {Function} fn Callback function for each item.
|
|
* @param {Mixed} fn.item Current item.
|
|
* @param {Number} fn.index Index of the item.
|
|
* @param {Array} fn.array The whole array that's being iterated.
|
|
* @param {Object} scope Callback function scope.
|
|
* @return {Array} results
|
|
*/
|
|
filter: ('filter' in arrayPrototype) ? function(array, fn, scope) {
|
|
Ext.Assert.isFunction(fn, 'Ext.Array.filter must have a filter function passed as second argument.');
|
|
return array.filter(fn, scope);
|
|
} : function(array, fn, scope) {
|
|
Ext.Assert.isFunction(fn, 'Ext.Array.filter must have a filter function passed as second argument.');
|
|
var results = [],
|
|
i = 0,
|
|
ln = array.length;
|
|
for (; i < ln; i++) {
|
|
if (fn.call(scope, array[i], i, array)) {
|
|
results.push(array[i]);
|
|
}
|
|
}
|
|
return results;
|
|
},
|
|
/**
|
|
* Returns the first item in the array which elicits a truthy return value from the
|
|
* passed selection function.
|
|
* @param {Array} array The array to search
|
|
* @param {Function} fn The selection function to execute for each item.
|
|
* @param {Mixed} fn.item The array item.
|
|
* @param {Number} fn.index The index of the array item.
|
|
* @param {Object} scope (optional) The scope (<code>this</code> reference) in which the
|
|
* function is executed. Defaults to the array
|
|
* @return {Object} The first item in the array which returned true from the selection
|
|
* function, or null if none was found.
|
|
*/
|
|
findBy: function(array, fn, scope) {
|
|
var i = 0,
|
|
len = array.length;
|
|
for (; i < len; i++) {
|
|
if (fn.call(scope || array, array[i], i)) {
|
|
return array[i];
|
|
}
|
|
}
|
|
return null;
|
|
},
|
|
/**
|
|
* Converts a value to an array if it's not already an array; returns:
|
|
*
|
|
* - An empty array if given value is `undefined` or `null`
|
|
* - Itself if given value is already an array
|
|
* - An array copy if given value is {@link Ext#isIterable iterable} (arguments, NodeList and alike)
|
|
* - An array with one item which is the given value, otherwise
|
|
*
|
|
* @param {Object} value The value to convert to an array if it's not already is an array.
|
|
* @param {Boolean} [newReference] `true` to clone the given array and return a new reference if necessary.
|
|
* @return {Array} array
|
|
*/
|
|
from: function(value, newReference) {
|
|
if (value === undefined || value === null) {
|
|
return [];
|
|
}
|
|
if (Ext.isArray(value)) {
|
|
return (newReference) ? slice.call(value) : value;
|
|
}
|
|
var type = typeof value;
|
|
// Both strings and functions will have a length property. In phantomJS, NodeList
|
|
// instances report typeof=='function' but don't have an apply method...
|
|
if (value && value.length !== undefined && type !== 'string' && (type !== 'function' || !value.apply)) {
|
|
return ExtArray.toArray(value);
|
|
}
|
|
return [
|
|
value
|
|
];
|
|
},
|
|
/**
|
|
* Removes the specified item from the array if it exists.
|
|
*
|
|
* @param {Array} array The array.
|
|
* @param {Object} item The item to remove.
|
|
* @return {Array} The passed array.
|
|
*/
|
|
remove: function(array, item) {
|
|
var index = ExtArray.indexOf(array, item);
|
|
if (index !== -1) {
|
|
erase(array, index, 1);
|
|
}
|
|
return array;
|
|
},
|
|
/**
|
|
* Removes item/s at the specified index.
|
|
*
|
|
* @param {Array} array The array.
|
|
* @param {Number} index The index of the item to be removed.
|
|
* @param {Number} [count=1] The number of items to be removed.
|
|
* @return {Array} The passed array.
|
|
*/
|
|
removeAt: function(array, index, count) {
|
|
var len = array.length;
|
|
if (index >= 0 && index < len) {
|
|
count = count || 1;
|
|
count = Math.min(count, len - index);
|
|
erase(array, index, count);
|
|
}
|
|
return array;
|
|
},
|
|
/**
|
|
* Push an item into the array only if the array doesn't contain it yet.
|
|
*
|
|
* @param {Array} array The array.
|
|
* @param {Object} item The item to include.
|
|
*/
|
|
include: function(array, item) {
|
|
if (!ExtArray.contains(array, item)) {
|
|
array.push(item);
|
|
}
|
|
},
|
|
/**
|
|
* Clone a flat array without referencing the previous one. Note that this is different
|
|
* from `Ext.clone` since it doesn't handle recursive cloning. It's simply a convenient, easy-to-remember method
|
|
* for `Array.prototype.slice.call(array)`.
|
|
*
|
|
* @param {Array} array The array.
|
|
* @return {Array} The clone array.
|
|
*/
|
|
clone: function(array) {
|
|
return slice.call(array);
|
|
},
|
|
/**
|
|
* Merge multiple arrays into one with unique items.
|
|
*
|
|
* {@link Ext.Array#union} is alias for {@link Ext.Array#merge}
|
|
*
|
|
* @param {Array} array1
|
|
* @param {Array} array2
|
|
* @param {Array} etc
|
|
* @return {Array} merged
|
|
*/
|
|
merge: function() {
|
|
var args = slice.call(arguments),
|
|
array = [],
|
|
i, ln;
|
|
for (i = 0 , ln = args.length; i < ln; i++) {
|
|
array = array.concat(args[i]);
|
|
}
|
|
return ExtArray.unique(array);
|
|
},
|
|
/**
|
|
* Merge multiple arrays into one with unique items that exist in all of the arrays.
|
|
*
|
|
* @param {Array} array1
|
|
* @param {Array} array2
|
|
* @param {Array} etc
|
|
* @return {Array} intersect
|
|
*/
|
|
intersect: function() {
|
|
var intersection = [],
|
|
arrays = slice.call(arguments),
|
|
arraysLength, array, arrayLength, minArray, minArrayIndex, minArrayCandidate, minArrayLength, element, elementCandidate, elementCount, i, j, k;
|
|
if (!arrays.length) {
|
|
return intersection;
|
|
}
|
|
// Find the smallest array
|
|
arraysLength = arrays.length;
|
|
for (i = minArrayIndex = 0; i < arraysLength; i++) {
|
|
minArrayCandidate = arrays[i];
|
|
if (!minArray || minArrayCandidate.length < minArray.length) {
|
|
minArray = minArrayCandidate;
|
|
minArrayIndex = i;
|
|
}
|
|
}
|
|
minArray = ExtArray.unique(minArray);
|
|
erase(arrays, minArrayIndex, 1);
|
|
// Use the smallest unique'd array as the anchor loop. If the other array(s) do contain
|
|
// an item in the small array, we're likely to find it before reaching the end
|
|
// of the inner loop and can terminate the search early.
|
|
minArrayLength = minArray.length;
|
|
arraysLength = arrays.length;
|
|
for (i = 0; i < minArrayLength; i++) {
|
|
element = minArray[i];
|
|
elementCount = 0;
|
|
for (j = 0; j < arraysLength; j++) {
|
|
array = arrays[j];
|
|
arrayLength = array.length;
|
|
for (k = 0; k < arrayLength; k++) {
|
|
elementCandidate = array[k];
|
|
if (element === elementCandidate) {
|
|
elementCount++;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (elementCount === arraysLength) {
|
|
intersection.push(element);
|
|
}
|
|
}
|
|
return intersection;
|
|
},
|
|
/**
|
|
* Perform a set difference A-B by subtracting all items in array B from array A.
|
|
*
|
|
* @param {Array} arrayA
|
|
* @param {Array} arrayB
|
|
* @return {Array} difference
|
|
*/
|
|
difference: function(arrayA, arrayB) {
|
|
var clone = slice.call(arrayA),
|
|
ln = clone.length,
|
|
i, j, lnB;
|
|
for (i = 0 , lnB = arrayB.length; i < lnB; i++) {
|
|
for (j = 0; j < ln; j++) {
|
|
if (clone[j] === arrayB[i]) {
|
|
erase(clone, j, 1);
|
|
j--;
|
|
ln--;
|
|
}
|
|
}
|
|
}
|
|
return clone;
|
|
},
|
|
/**
|
|
* This method applies the `reduceFn` function against an accumulator and each
|
|
* value of the `array` (from left-to-right) to reduce it to a single value.
|
|
*
|
|
* If no `initialValue` is specified, the first element of the array is used as
|
|
* the initial value. For example:
|
|
*
|
|
* function reducer (previous, value, index) {
|
|
* console.log('[' + index + ']: (' + previous + ',' + value + '}');
|
|
* return previous * 10 + value;
|
|
* }
|
|
*
|
|
* v = Ext.Array.reduce([2, 3, 4], reducer);
|
|
* console.log('v = ' + v);
|
|
*
|
|
* > [1]: (2, 3)
|
|
* > [2]: (23, 4)
|
|
* > v = 234
|
|
*
|
|
* v = Ext.Array.reduce([2, 3, 4], reducer, 1);
|
|
* console.log('v = ' + v);
|
|
*
|
|
* > [0]: (1, 2)
|
|
* > [1]: (12, 3)
|
|
* > [2]: (123, 4)
|
|
* > v = 1234
|
|
*
|
|
* @param {Array} array The array to process.
|
|
* @param {Function} reduceFn The reducing callback function.
|
|
* @param {Mixed} reduceFn.previous The previous value.
|
|
* @param {Mixed} reduceFn.value The current value.
|
|
* @param {Number} reduceFn.index The index in the array of the current `value`.
|
|
* @param {Array} reduceFn.array The array to being processed.
|
|
* @param {Mixed} [initialValue] The starting value.
|
|
* @return {Mixed} The reduced value.
|
|
* @method reduce
|
|
* @since 6.0.0
|
|
*/
|
|
reduce: Array.prototype.reduce ? function(array, reduceFn, initialValue) {
|
|
if (arguments.length === 3) {
|
|
return Array.prototype.reduce.call(array, reduceFn, initialValue);
|
|
}
|
|
return Array.prototype.reduce.call(array, reduceFn);
|
|
} : function(array, reduceFn, initialValue) {
|
|
array = Object(array);
|
|
if (!Ext.isFunction(reduceFn)) {
|
|
Ext.raise('Invalid parameter: expected a function.');
|
|
}
|
|
var index = 0,
|
|
length = array.length >>> 0,
|
|
reduced = initialValue;
|
|
if (arguments.length < 3) {
|
|
while (true) {
|
|
if (index in array) {
|
|
reduced = array[index++];
|
|
break;
|
|
}
|
|
if (++index >= length) {
|
|
throw new TypeError('Reduce of empty array with no initial value');
|
|
}
|
|
}
|
|
}
|
|
for (; index < length; ++index) {
|
|
if (index in array) {
|
|
reduced = reduceFn(reduced, array[index], index, array);
|
|
}
|
|
}
|
|
return reduced;
|
|
},
|
|
/**
|
|
* Returns a shallow copy of a part of an array. This is equivalent to the native
|
|
* call `Array.prototype.slice.call(array, begin, end)`. This is often used when "array"
|
|
* is "arguments" since the arguments object does not supply a slice method but can
|
|
* be the context object to `Array.prototype.slice`.
|
|
*
|
|
* @param {Array} array The array (or arguments object).
|
|
* @param {Number} begin The index at which to begin. Negative values are offsets from
|
|
* the end of the array.
|
|
* @param {Number} end The index at which to end. The copied items do not include
|
|
* end. Negative values are offsets from the end of the array. If end is omitted,
|
|
* all items up to the end of the array are copied.
|
|
* @return {Array} The copied piece of the array.
|
|
* @method slice
|
|
*/
|
|
// Note: IE8 will return [] on slice.call(x, undefined).
|
|
slice: ([
|
|
1,
|
|
2
|
|
].slice(1, undefined).length ? function(array, begin, end) {
|
|
return slice.call(array, begin, end);
|
|
} : function(array, begin, end) {
|
|
// see http://jsperf.com/slice-fix
|
|
if (typeof begin === 'undefined') {
|
|
return slice.call(array);
|
|
}
|
|
if (typeof end === 'undefined') {
|
|
return slice.call(array, begin);
|
|
}
|
|
return slice.call(array, begin, end);
|
|
}),
|
|
/**
|
|
* Sorts the elements of an Array in a stable manner (equivalently keyed values do not move relative to each other).
|
|
* By default, this method sorts the elements alphabetically and ascending.
|
|
* **Note:** This method modifies the passed array, in the same manner as the
|
|
* native javascript Array.sort.
|
|
*
|
|
* @param {Array} array The array to sort.
|
|
* @param {Function} [sortFn] The comparison function.
|
|
* @param {Mixed} sortFn.a The first item to compare.
|
|
* @param {Mixed} sortFn.b The second item to compare.
|
|
* @param {Number} sortFn.return `-1` if a < b, `1` if a > b, otherwise `0`.
|
|
* @return {Array} The sorted array.
|
|
*/
|
|
sort: function(array, sortFn) {
|
|
return stableSort(array, sortFn || ExtArray.lexicalCompare);
|
|
},
|
|
/**
|
|
* Recursively flattens into 1-d Array. Injects Arrays inline.
|
|
*
|
|
* @param {Array} array The array to flatten
|
|
* @return {Array} The 1-d array.
|
|
*/
|
|
flatten: function(array) {
|
|
var worker = [];
|
|
function rFlatten(a) {
|
|
var i, ln, v;
|
|
for (i = 0 , ln = a.length; i < ln; i++) {
|
|
v = a[i];
|
|
if (Ext.isArray(v)) {
|
|
rFlatten(v);
|
|
} else {
|
|
worker.push(v);
|
|
}
|
|
}
|
|
return worker;
|
|
}
|
|
return rFlatten(array);
|
|
},
|
|
/**
|
|
* Returns the minimum value in the Array.
|
|
*
|
|
* @param {Array/NodeList} array The Array from which to select the minimum value.
|
|
* @param {Function} comparisonFn (optional) a function to perform the comparison which determines minimization.
|
|
* If omitted the "<" operator will be used.
|
|
* __Note:__ gt = 1; eq = 0; lt = -1
|
|
* @param {Mixed} comparisonFn.min Current minimum value.
|
|
* @param {Mixed} comparisonFn.item The value to compare with the current minimum.
|
|
* @return {Object} minValue The minimum value.
|
|
*/
|
|
min: function(array, comparisonFn) {
|
|
var min = array[0],
|
|
i, ln, item;
|
|
for (i = 0 , ln = array.length; i < ln; i++) {
|
|
item = array[i];
|
|
if (comparisonFn) {
|
|
if (comparisonFn(min, item) === 1) {
|
|
min = item;
|
|
}
|
|
} else {
|
|
if (item < min) {
|
|
min = item;
|
|
}
|
|
}
|
|
}
|
|
return min;
|
|
},
|
|
/**
|
|
* Returns the maximum value in the Array.
|
|
*
|
|
* @param {Array/NodeList} array The Array from which to select the maximum value.
|
|
* @param {Function} comparisonFn (optional) a function to perform the comparison which determines maximization.
|
|
* If omitted the ">" operator will be used.
|
|
* __Note:__ gt = 1; eq = 0; lt = -1
|
|
* @param {Mixed} comparisonFn.max Current maximum value.
|
|
* @param {Mixed} comparisonFn.item The value to compare with the current maximum.
|
|
* @return {Object} maxValue The maximum value.
|
|
*/
|
|
max: function(array, comparisonFn) {
|
|
var max = array[0],
|
|
i, ln, item;
|
|
for (i = 0 , ln = array.length; i < ln; i++) {
|
|
item = array[i];
|
|
if (comparisonFn) {
|
|
if (comparisonFn(max, item) === -1) {
|
|
max = item;
|
|
}
|
|
} else {
|
|
if (item > max) {
|
|
max = item;
|
|
}
|
|
}
|
|
}
|
|
return max;
|
|
},
|
|
/**
|
|
* Calculates the mean of all items in the array.
|
|
*
|
|
* @param {Array} array The Array to calculate the mean value of.
|
|
* @return {Number} The mean.
|
|
*/
|
|
mean: function(array) {
|
|
return array.length > 0 ? ExtArray.sum(array) / array.length : undefined;
|
|
},
|
|
/**
|
|
* Calculates the sum of all items in the given array.
|
|
*
|
|
* @param {Array} array The Array to calculate the sum value of.
|
|
* @return {Number} The sum.
|
|
*/
|
|
sum: function(array) {
|
|
var sum = 0,
|
|
i, ln, item;
|
|
for (i = 0 , ln = array.length; i < ln; i++) {
|
|
item = array[i];
|
|
sum += item;
|
|
}
|
|
return sum;
|
|
},
|
|
/**
|
|
* Creates a map (object) keyed by the elements of the given array. The values in
|
|
* the map are the index+1 of the array element. For example:
|
|
*
|
|
* var map = Ext.Array.toMap(['a','b','c']);
|
|
*
|
|
* // map = { a: 1, b: 2, c: 3 };
|
|
*
|
|
* Or a key property can be specified:
|
|
*
|
|
* var map = Ext.Array.toMap([
|
|
* { name: 'a' },
|
|
* { name: 'b' },
|
|
* { name: 'c' }
|
|
* ], 'name');
|
|
*
|
|
* // map = { a: 1, b: 2, c: 3 };
|
|
*
|
|
* Lastly, a key extractor can be provided:
|
|
*
|
|
* var map = Ext.Array.toMap([
|
|
* { name: 'a' },
|
|
* { name: 'b' },
|
|
* { name: 'c' }
|
|
* ], function (obj) { return obj.name.toUpperCase(); });
|
|
*
|
|
* // map = { A: 1, B: 2, C: 3 };
|
|
*
|
|
* @param {Array} array The Array to create the map from.
|
|
* @param {String/Function} [getKey] Name of the object property to use
|
|
* as a key or a function to extract the key.
|
|
* @param {Object} [scope] Value of `this` inside callback specified for `getKey`.
|
|
* @return {Object} The resulting map.
|
|
*/
|
|
toMap: function(array, getKey, scope) {
|
|
var map = {},
|
|
i = array.length;
|
|
if (!getKey) {
|
|
while (i--) {
|
|
map[array[i]] = i + 1;
|
|
}
|
|
} else if (typeof getKey === 'string') {
|
|
while (i--) {
|
|
map[array[i][getKey]] = i + 1;
|
|
}
|
|
} else {
|
|
while (i--) {
|
|
map[getKey.call(scope, array[i])] = i + 1;
|
|
}
|
|
}
|
|
return map;
|
|
},
|
|
/**
|
|
* Creates a map (object) keyed by a property of elements of the given array. The values in
|
|
* the map are the array element. For example:
|
|
*
|
|
* var map = Ext.Array.toValueMap(['a','b','c']);
|
|
*
|
|
* // map = { a: 'a', b: 'b', c: 'c' };
|
|
*
|
|
* Or a key property can be specified:
|
|
*
|
|
* var map = Ext.Array.toValueMap([
|
|
* { name: 'a' },
|
|
* { name: 'b' },
|
|
* { name: 'c' }
|
|
* ], 'name');
|
|
*
|
|
* // map = { a: {name: 'a'}, b: {name: 'b'}, c: {name: 'c'} };
|
|
*
|
|
* Lastly, a key extractor can be provided:
|
|
*
|
|
* var map = Ext.Array.toValueMap([
|
|
* { name: 'a' },
|
|
* { name: 'b' },
|
|
* { name: 'c' }
|
|
* ], function (obj) { return obj.name.toUpperCase(); });
|
|
*
|
|
* // map = { A: {name: 'a'}, B: {name: 'b'}, C: {name: 'c'} };
|
|
*
|
|
* @param {Array} array The Array to create the map from.
|
|
* @param {String/Function} [getKey] Name of the object property to use
|
|
* as a key or a function to extract the key.
|
|
* @param {Object} [scope] Value of this inside callback. This parameter is only
|
|
* passed when `getKey` is a function. If `getKey` is not a function, the 3rd
|
|
* argument is `arrayify`.
|
|
* @param {Number} [arrayify] Pass `1` to create arrays for all map entries
|
|
* or `2` to create arrays for map entries that have 2 or more items with the
|
|
* same key. This only applies when `getKey` is specified. By default the map will
|
|
* hold the last entry with a given key.
|
|
* @return {Object} The resulting map.
|
|
*/
|
|
toValueMap: function(array, getKey, scope, arrayify) {
|
|
var map = {},
|
|
i = array.length,
|
|
autoArray, alwaysArray, entry, fn, key, value;
|
|
if (!getKey) {
|
|
while (i--) {
|
|
value = array[i];
|
|
map[value] = value;
|
|
}
|
|
} else {
|
|
if (!(fn = (typeof getKey !== 'string'))) {
|
|
arrayify = scope;
|
|
}
|
|
alwaysArray = arrayify === 1;
|
|
autoArray = arrayify === 2;
|
|
while (i--) {
|
|
value = array[i];
|
|
key = fn ? getKey.call(scope, value) : value[getKey];
|
|
if (alwaysArray) {
|
|
if (key in map) {
|
|
map[key].push(value);
|
|
} else {
|
|
map[key] = [
|
|
value
|
|
];
|
|
}
|
|
} else if (autoArray && (key in map)) {
|
|
if ((entry = map[key]) instanceof Array) {
|
|
entry.push(value);
|
|
} else {
|
|
map[key] = [
|
|
entry,
|
|
value
|
|
];
|
|
}
|
|
} else {
|
|
map[key] = value;
|
|
}
|
|
}
|
|
}
|
|
return map;
|
|
},
|
|
_replaceSim: replaceSim,
|
|
// for unit testing
|
|
_spliceSim: spliceSim,
|
|
/**
|
|
* Removes items from an array. This is functionally equivalent to the splice method
|
|
* of Array, but works around bugs in IE8's splice method and does not copy the
|
|
* removed elements in order to return them (because very often they are ignored).
|
|
*
|
|
* @param {Array} array The Array on which to replace.
|
|
* @param {Number} index The index in the array at which to operate.
|
|
* @param {Number} removeCount The number of items to remove at index.
|
|
* @return {Array} The array passed.
|
|
* @method
|
|
*/
|
|
erase: erase,
|
|
/**
|
|
* Inserts items in to an array.
|
|
*
|
|
* @param {Array} array The Array in which to insert.
|
|
* @param {Number} index The index in the array at which to operate.
|
|
* @param {Array} items The array of items to insert at index.
|
|
* @return {Array} The array passed.
|
|
*/
|
|
insert: function(array, index, items) {
|
|
return replace(array, index, 0, items);
|
|
},
|
|
move: function(array, fromIdx, toIdx) {
|
|
if (toIdx === fromIdx) {
|
|
return;
|
|
}
|
|
var item = array[fromIdx],
|
|
incr = toIdx > fromIdx ? 1 : -1,
|
|
i;
|
|
for (i = fromIdx; i != toIdx; i += incr) {
|
|
array[i] = array[i + incr];
|
|
}
|
|
array[toIdx] = item;
|
|
},
|
|
/**
|
|
* Replaces items in an array. This is functionally equivalent to the splice method
|
|
* of Array, but works around bugs in IE8's splice method and is often more convenient
|
|
* to call because it accepts an array of items to insert rather than use a variadic
|
|
* argument list.
|
|
*
|
|
* @param {Array} array The Array on which to replace.
|
|
* @param {Number} index The index in the array at which to operate.
|
|
* @param {Number} removeCount The number of items to remove at index (can be 0).
|
|
* @param {Array} insert (optional) An array of items to insert at index.
|
|
* @return {Array} The array passed.
|
|
* @method
|
|
*/
|
|
replace: replace,
|
|
/**
|
|
* Replaces items in an array. This is equivalent to the splice method of Array, but
|
|
* works around bugs in IE8's splice method. The signature is exactly the same as the
|
|
* splice method except that the array is the first argument. All arguments following
|
|
* removeCount are inserted in the array at index.
|
|
*
|
|
* @param {Array} array The Array on which to replace.
|
|
* @param {Number} index The index in the array at which to operate.
|
|
* @param {Number} removeCount The number of items to remove at index (can be 0).
|
|
* @param {Object...} elements The elements to add to the array. If you don't specify
|
|
* any elements, splice simply removes elements from the array.
|
|
* @return {Array} An array containing the removed items.
|
|
* @method
|
|
*/
|
|
splice: splice,
|
|
/**
|
|
* Pushes new items onto the end of an Array.
|
|
*
|
|
* Passed parameters may be single items, or arrays of items. If an Array is found in the argument list, all its
|
|
* elements are pushed into the end of the target Array.
|
|
*
|
|
* @param {Array} target The Array onto which to push new items
|
|
* @param {Object...} elements The elements to add to the array. Each parameter may
|
|
* be an Array, in which case all the elements of that Array will be pushed into the end of the
|
|
* destination Array.
|
|
* @return {Array} An array containing all the new items push onto the end.
|
|
*
|
|
*/
|
|
push: function(target) {
|
|
var len = arguments.length,
|
|
i = 1,
|
|
newItem;
|
|
if (target === undefined) {
|
|
target = [];
|
|
} else if (!Ext.isArray(target)) {
|
|
target = [
|
|
target
|
|
];
|
|
}
|
|
for (; i < len; i++) {
|
|
newItem = arguments[i];
|
|
Array.prototype.push[Ext.isIterable(newItem) ? 'apply' : 'call'](target, newItem);
|
|
}
|
|
return target;
|
|
},
|
|
/**
|
|
* A function used to sort an array by numeric value. By default, javascript array values
|
|
* are coerced to strings when sorting, which can be problematic when using numeric values. To
|
|
* ensure that the values are sorted numerically, this method can be passed to the sort method:
|
|
*
|
|
* Ext.Array.sort(myArray, Ext.Array.numericSortFn);
|
|
*/
|
|
numericSortFn: function(a, b) {
|
|
return a - b;
|
|
}
|
|
};
|
|
/**
|
|
* @method each
|
|
* @member Ext
|
|
* @inheritdoc Ext.Array#each
|
|
*/
|
|
Ext.each = ExtArray.each;
|
|
/**
|
|
* @method union
|
|
* @member Ext.Array
|
|
* @inheritdoc Ext.Array#merge
|
|
*/
|
|
ExtArray.union = ExtArray.merge;
|
|
/**
|
|
* Old alias to {@link Ext.Array#min}
|
|
* @deprecated 4.0.0 Use {@link Ext.Array#min} instead
|
|
* @method min
|
|
* @member Ext
|
|
* @inheritdoc Ext.Array#min
|
|
*/
|
|
Ext.min = ExtArray.min;
|
|
/**
|
|
* Old alias to {@link Ext.Array#max}
|
|
* @deprecated 4.0.0 Use {@link Ext.Array#max} instead
|
|
* @method max
|
|
* @member Ext
|
|
* @inheritdoc Ext.Array#max
|
|
*/
|
|
Ext.max = ExtArray.max;
|
|
/**
|
|
* Old alias to {@link Ext.Array#sum}
|
|
* @deprecated 4.0.0 Use {@link Ext.Array#sum} instead
|
|
* @method sum
|
|
* @member Ext
|
|
* @inheritdoc Ext.Array#sum
|
|
*/
|
|
Ext.sum = ExtArray.sum;
|
|
/**
|
|
* Old alias to {@link Ext.Array#mean}
|
|
* @deprecated 4.0.0 Use {@link Ext.Array#mean} instead
|
|
* @method mean
|
|
* @member Ext
|
|
* @inheritdoc Ext.Array#mean
|
|
*/
|
|
Ext.mean = ExtArray.mean;
|
|
/**
|
|
* Old alias to {@link Ext.Array#flatten}
|
|
* @deprecated 4.0.0 Use {@link Ext.Array#flatten} instead
|
|
* @method flatten
|
|
* @member Ext
|
|
* @inheritdoc Ext.Array#flatten
|
|
*/
|
|
Ext.flatten = ExtArray.flatten;
|
|
/**
|
|
* Old alias to {@link Ext.Array#clean}
|
|
* @deprecated 4.0.0 Use {@link Ext.Array#clean} instead
|
|
* @method clean
|
|
* @member Ext
|
|
* @inheritdoc Ext.Array#clean
|
|
*/
|
|
Ext.clean = ExtArray.clean;
|
|
/**
|
|
* Old alias to {@link Ext.Array#unique}
|
|
* @deprecated 4.0.0 Use {@link Ext.Array#unique} instead
|
|
* @method unique
|
|
* @member Ext
|
|
* @inheritdoc Ext.Array#unique
|
|
*/
|
|
Ext.unique = ExtArray.unique;
|
|
/**
|
|
* Old alias to {@link Ext.Array#pluck Ext.Array.pluck}
|
|
* @deprecated 4.0.0 Use {@link Ext.Array#pluck Ext.Array.pluck} instead
|
|
* @method pluck
|
|
* @member Ext
|
|
* @inheritdoc Ext.Array#pluck
|
|
*/
|
|
Ext.pluck = ExtArray.pluck;
|
|
/**
|
|
* @method toArray
|
|
* @member Ext
|
|
* @inheritdoc Ext.Array#toArray
|
|
*/
|
|
Ext.toArray = function() {
|
|
return ExtArray.toArray.apply(ExtArray, arguments);
|
|
};
|
|
return ExtArray;
|
|
}());
|
|
|
|
// @define Ext.lang.Assert
|
|
// @define Ext.Assert
|
|
// @require Ext.lang.Error
|
|
/**
|
|
* @class Ext.Assert
|
|
* This class provides help value testing methods useful for diagnostics. These are often
|
|
* used in `debugHooks`:
|
|
*
|
|
* Ext.define('Foo.bar.Class', {
|
|
*
|
|
* debugHooks: {
|
|
* method: function (a) {
|
|
* Ext.Assert.truthy(a, 'Expected "a" to be truthy');
|
|
* },
|
|
*
|
|
* foo: function (object) {
|
|
* Ext.Assert.isFunctionProp(object, 'doSomething');
|
|
* }
|
|
* }
|
|
* });
|
|
*
|
|
* **NOTE:** This class is entirely removed in production builds so all uses of it should
|
|
* be either in `debug` conditional comments or `debugHooks`.
|
|
*
|
|
* The following type detection methods from the `Ext` object are wrapped as assertions
|
|
* by this class:
|
|
*
|
|
* * `isEmpty`
|
|
* * `isArray`
|
|
* * `isDate`
|
|
* * `isObject`
|
|
* * `isSimpleObject`
|
|
* * `isPrimitive`
|
|
* * `isFunction`
|
|
* * `isNumber`
|
|
* * `isNumeric`
|
|
* * `isString`
|
|
* * `isBoolean`
|
|
* * `isElement`
|
|
* * `isTextNode`
|
|
* * `isDefined`
|
|
* * `isIterable`
|
|
*
|
|
* These appear both their exact name and with a "Prop" suffix for checking a property on
|
|
* an object. For example, these are almost identical:
|
|
*
|
|
* Ext.Assert.isFunction(object.foo);
|
|
*
|
|
* Ext.Assert.isFunctionProp(object, 'foo');
|
|
*
|
|
* The difference is the default error message generated is better in the second use case
|
|
* than the first.
|
|
*
|
|
* The above list are also expanded for "Not" flavors (and "Not...Prop"):
|
|
*
|
|
* * `isNotEmpty`
|
|
* * `isNotArray`
|
|
* * `isNotDate`
|
|
* * `isNotObject`
|
|
* * `isNotSimpleObject`
|
|
* * `isNotPrimitive`
|
|
* * `isNotFunction`
|
|
* * `isNotNumber`
|
|
* * `isNotNumeric`
|
|
* * `isNotString`
|
|
* * `isNotBoolean`
|
|
* * `isNotElement`
|
|
* * `isNotTextNode`
|
|
* * `isNotDefined`
|
|
* * `isNotIterable`
|
|
*/
|
|
Ext.Assert = {
|
|
/**
|
|
* Checks that the first argument is falsey and throws an `Error` if it is not.
|
|
*/
|
|
falsey: function(b, msg) {
|
|
if (b) {
|
|
Ext.raise(msg || ('Expected a falsey value but was ' + b));
|
|
}
|
|
},
|
|
/**
|
|
* Checks that the first argument is falsey and throws an `Error` if it is not.
|
|
*/
|
|
falseyProp: function(object, property) {
|
|
Ext.Assert.truthy(object);
|
|
var b = object[property];
|
|
if (b) {
|
|
if (object.$className) {
|
|
property = object.$className + '#' + property;
|
|
}
|
|
Ext.raise('Expected a falsey value for ' + property + ' but was ' + b);
|
|
}
|
|
},
|
|
/**
|
|
* Checks that the first argument is truthy and throws an `Error` if it is not.
|
|
*/
|
|
truthy: function(b, msg) {
|
|
if (!b) {
|
|
Ext.raise(msg || ('Expected a truthy value but was ' + typeof b));
|
|
}
|
|
},
|
|
/**
|
|
* Checks that the first argument is truthy and throws an `Error` if it is not.
|
|
*/
|
|
truthyProp: function(object, property) {
|
|
Ext.Assert.truthy(object);
|
|
var b = object[property];
|
|
if (!b) {
|
|
if (object.$className) {
|
|
property = object.$className + '#' + property;
|
|
}
|
|
Ext.raise('Expected a truthy value for ' + property + ' but was ' + typeof b);
|
|
}
|
|
}
|
|
};
|
|
(function() {
|
|
function makeAssert(name, kind) {
|
|
var testFn = Ext[name],
|
|
def;
|
|
return function(value, msg) {
|
|
if (!testFn(value)) {
|
|
Ext.raise(msg || def || (def = 'Expected value to be ' + kind));
|
|
}
|
|
};
|
|
}
|
|
function makeAssertProp(name, kind) {
|
|
var testFn = Ext[name],
|
|
def;
|
|
return function(object, prop) {
|
|
Ext.Assert.truthy(object);
|
|
if (!testFn(object[prop])) {
|
|
Ext.raise(def || (def = 'Expected ' + (object.$className ? object.$className + '#' : '') + prop + ' to be ' + kind));
|
|
}
|
|
};
|
|
}
|
|
function makeNotAssert(name, kind) {
|
|
var testFn = Ext[name],
|
|
def;
|
|
return function(value, msg) {
|
|
if (testFn(value)) {
|
|
Ext.raise(msg || def || (def = 'Expected value to NOT be ' + kind));
|
|
}
|
|
};
|
|
}
|
|
function makeNotAssertProp(name, kind) {
|
|
var testFn = Ext[name],
|
|
def;
|
|
return function(object, prop) {
|
|
Ext.Assert.truthy(object);
|
|
if (testFn(object[prop])) {
|
|
Ext.raise(def || (def = 'Expected ' + (object.$className ? object.$className + '#' : '') + prop + ' to NOT be ' + kind));
|
|
}
|
|
};
|
|
}
|
|
for (var name in Ext) {
|
|
if (name.substring(0, 2) == "is" && Ext.isFunction(Ext[name])) {
|
|
var kind = name.substring(2);
|
|
Ext.Assert[name] = makeAssert(name, kind);
|
|
Ext.Assert[name + 'Prop'] = makeAssertProp(name, kind);
|
|
Ext.Assert['isNot' + kind] = makeNotAssert(name, kind);
|
|
Ext.Assert['isNot' + kind + 'Prop'] = makeNotAssertProp(name, kind);
|
|
}
|
|
}
|
|
}());
|
|
|
|
/**
|
|
* @class Ext.String
|
|
*
|
|
* A collection of useful static methods to deal with strings.
|
|
* @singleton
|
|
*/
|
|
Ext.String = (function() {
|
|
// @define Ext.lang.String
|
|
// @define Ext.String
|
|
// @require Ext
|
|
// @require Ext.lang.Array
|
|
var 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,
|
|
escapeRe = /('|\\)/g,
|
|
escapeRegexRe = /([-.*+?\^${}()|\[\]\/\\])/g,
|
|
basicTrimRe = /^\s+|\s+$/g,
|
|
whitespaceRe = /\s+/,
|
|
varReplace = /(^[^a-z]*|[^\w])/gi,
|
|
charToEntity, entityToChar, charToEntityRegex, entityToCharRegex,
|
|
htmlEncodeReplaceFn = function(match, capture) {
|
|
return charToEntity[capture];
|
|
},
|
|
htmlDecodeReplaceFn = function(match, capture) {
|
|
return (capture in entityToChar) ? entityToChar[capture] : String.fromCharCode(parseInt(capture.substr(2), 10));
|
|
},
|
|
boundsCheck = function(s, other) {
|
|
if (s === null || s === undefined || other === null || other === undefined) {
|
|
return false;
|
|
}
|
|
return other.length <= s.length;
|
|
},
|
|
fromCharCode = String.fromCharCode,
|
|
ExtString;
|
|
return ExtString = {
|
|
/**
|
|
* Creates a string created by using the specified sequence of code points.
|
|
* @param {Number...} codePoint Codepoints from which to build the string.
|
|
* @return {String} A string built from the sequence of code points passed.
|
|
*/
|
|
fromCodePoint: String.fromCodePoint || function() {
|
|
var codePoint,
|
|
result = '',
|
|
codeUnits = [],
|
|
index = -1,
|
|
length = arguments.length;
|
|
while (++index < length) {
|
|
codePoint = Number(arguments[index]);
|
|
if (!isFinite(codePoint) || // `NaN`, `+Infinity`, or `-Infinity`
|
|
codePoint < 0 || // not a valid Unicode code point
|
|
codePoint > 1114111 || // not a valid Unicode code point
|
|
Math.floor(codePoint) !== codePoint) // not an integer
|
|
{
|
|
Ext.raise('Invalid code point: ' + codePoint);
|
|
}
|
|
if (codePoint <= 65535) {
|
|
// BMP code point
|
|
codeUnits.push(codePoint);
|
|
} else {
|
|
// Astral code point; split in surrogate halves
|
|
// http://mathiasbynens.be/notes/javascript-encoding#surrogate-formulae
|
|
codePoint -= 65536;
|
|
codeUnits.push((codePoint >> 10) + 55296, (codePoint % 1024) + 56320);
|
|
}
|
|
if (index + 1 === length) {
|
|
result += fromCharCode(codeUnits);
|
|
codeUnits.length = 0;
|
|
}
|
|
}
|
|
return result;
|
|
},
|
|
/**
|
|
* Inserts a substring into a string.
|
|
* @param {String} s The original string.
|
|
* @param {String} value The substring to insert.
|
|
* @param {Number} index The index to insert the substring. Negative indexes will insert from the end of
|
|
* the string. Example:
|
|
*
|
|
* Ext.String.insert("abcdefg", "h", -1); // abcdefhg
|
|
*
|
|
* @return {String} The value with the inserted substring
|
|
*/
|
|
insert: function(s, value, index) {
|
|
if (!s) {
|
|
return value;
|
|
}
|
|
if (!value) {
|
|
return s;
|
|
}
|
|
var len = s.length;
|
|
if (!index && index !== 0) {
|
|
index = len;
|
|
}
|
|
if (index < 0) {
|
|
index *= -1;
|
|
if (index >= len) {
|
|
// negative overflow, insert at start
|
|
index = 0;
|
|
} else {
|
|
index = len - index;
|
|
}
|
|
}
|
|
if (index === 0) {
|
|
s = value + s;
|
|
} else if (index >= s.length) {
|
|
s += value;
|
|
} else {
|
|
s = s.substr(0, index) + value + s.substr(index);
|
|
}
|
|
return s;
|
|
},
|
|
/**
|
|
* Checks if a string starts with a substring
|
|
* @param {String} s The original string
|
|
* @param {String} start The substring to check
|
|
* @param {Boolean} [ignoreCase=false] True to ignore the case in the comparison
|
|
*/
|
|
startsWith: function(s, start, ignoreCase) {
|
|
var result = boundsCheck(s, start);
|
|
if (result) {
|
|
if (ignoreCase) {
|
|
s = s.toLowerCase();
|
|
start = start.toLowerCase();
|
|
}
|
|
result = s.lastIndexOf(start, 0) === 0;
|
|
}
|
|
return result;
|
|
},
|
|
/**
|
|
* Checks if a string ends with a substring
|
|
* @param {String} s The original string
|
|
* @param {String} end The substring to check
|
|
* @param {Boolean} [ignoreCase=false] True to ignore the case in the comparison
|
|
*/
|
|
endsWith: function(s, end, ignoreCase) {
|
|
var result = boundsCheck(s, end);
|
|
if (result) {
|
|
if (ignoreCase) {
|
|
s = s.toLowerCase();
|
|
end = end.toLowerCase();
|
|
}
|
|
result = s.indexOf(end, s.length - end.length) !== -1;
|
|
}
|
|
return result;
|
|
},
|
|
/**
|
|
* Converts a string of characters into a legal, parse-able JavaScript `var` name as long as the passed
|
|
* string contains at least one alphabetic character. Non alphanumeric characters, and *leading* non alphabetic
|
|
* characters will be removed.
|
|
* @param {String} s A string to be converted into a `var` name.
|
|
* @return {String} A legal JavaScript `var` name.
|
|
*/
|
|
createVarName: function(s) {
|
|
return s.replace(varReplace, '');
|
|
},
|
|
/**
|
|
* Convert certain characters (&, <, >, ', and ") to their HTML character equivalents for literal display in web pages.
|
|
* @param {String} value The string to encode.
|
|
* @return {String} The encoded text.
|
|
* @method
|
|
*/
|
|
htmlEncode: function(value) {
|
|
return (!value) ? value : String(value).replace(charToEntityRegex, htmlEncodeReplaceFn);
|
|
},
|
|
/**
|
|
* Convert certain characters (&, <, >, ', and ") from their HTML character equivalents.
|
|
* @param {String} value The string to decode.
|
|
* @return {String} The decoded text.
|
|
* @method
|
|
*/
|
|
htmlDecode: function(value) {
|
|
return (!value) ? value : String(value).replace(entityToCharRegex, htmlDecodeReplaceFn);
|
|
},
|
|
/**
|
|
* Checks if a string has values needing to be html encoded.
|
|
* @private
|
|
* @param {String} s The string to test
|
|
* @return {Boolean} `true` if the string contains HTML characters
|
|
*/
|
|
hasHtmlCharacters: function(s) {
|
|
return charToEntityRegex.test(s);
|
|
},
|
|
/**
|
|
* Adds a set of character entity definitions to the set used by
|
|
* {@link Ext.String#htmlEncode} and {@link Ext.String#htmlDecode}.
|
|
*
|
|
* This object should be keyed by the entity name sequence,
|
|
* with the value being the textual representation of the entity.
|
|
*
|
|
* Ext.String.addCharacterEntities({
|
|
* '&Uuml;':'Ü',
|
|
* '&ccedil;':'ç',
|
|
* '&ntilde;':'ñ',
|
|
* '&egrave;':'è'
|
|
* });
|
|
* var s = Ext.String.htmlEncode("A string with entities: èÜçñ");
|
|
*
|
|
* __Note:__ the values of the character entities defined on this object are expected
|
|
* to be single character values. As such, the actual values represented by the
|
|
* characters are sensitive to the character encoding of the JavaScript source
|
|
* file when defined in string literal form. Script tags referencing server
|
|
* resources with character entities must ensure that the 'charset' attribute
|
|
* of the script node is consistent with the actual character encoding of the
|
|
* server resource.
|
|
*
|
|
* The set of character entities may be reset back to the default state by using
|
|
* the {@link Ext.String#resetCharacterEntities} method
|
|
*
|
|
* @param {Object} newEntities The set of character entities to add to the current
|
|
* definitions.
|
|
*/
|
|
addCharacterEntities: function(newEntities) {
|
|
var charKeys = [],
|
|
entityKeys = [],
|
|
key, echar;
|
|
for (key in newEntities) {
|
|
echar = newEntities[key];
|
|
entityToChar[key] = echar;
|
|
charToEntity[echar] = key;
|
|
charKeys.push(echar);
|
|
entityKeys.push(key);
|
|
}
|
|
charToEntityRegex = new RegExp('(' + charKeys.join('|') + ')', 'g');
|
|
entityToCharRegex = new RegExp('(' + entityKeys.join('|') + '|&#[0-9]{1,5};' + ')', 'g');
|
|
},
|
|
/**
|
|
* Resets the set of character entity definitions used by
|
|
* {@link Ext.String#htmlEncode} and {@link Ext.String#htmlDecode} back to the
|
|
* default state.
|
|
*/
|
|
resetCharacterEntities: function() {
|
|
charToEntity = {};
|
|
entityToChar = {};
|
|
// add the default set
|
|
this.addCharacterEntities({
|
|
'&': '&',
|
|
'>': '>',
|
|
'<': '<',
|
|
'"': '"',
|
|
''': "'"
|
|
});
|
|
},
|
|
/**
|
|
* Appends content to the query string of a URL, handling logic for whether to place
|
|
* a question mark or ampersand.
|
|
* @param {String} url The URL to append to.
|
|
* @param {String} string The content to append to the URL.
|
|
* @return {String} The resulting URL
|
|
*/
|
|
urlAppend: function(url, string) {
|
|
if (!Ext.isEmpty(string)) {
|
|
return url + (url.indexOf('?') === -1 ? '?' : '&') + string;
|
|
}
|
|
return url;
|
|
},
|
|
/**
|
|
* Trims whitespace from either end of a string, leaving spaces within the string intact. Example:
|
|
*
|
|
* var s = ' foo bar ';
|
|
* alert('-' + s + '-'); //alerts "- foo bar -"
|
|
* alert('-' + Ext.String.trim(s) + '-'); //alerts "-foo bar-"
|
|
*
|
|
* @param {String} string The string to trim.
|
|
* @return {String} The trimmed string.
|
|
*/
|
|
trim: function(string) {
|
|
if (string) {
|
|
string = string.replace(trimRegex, "");
|
|
}
|
|
return string || '';
|
|
},
|
|
/**
|
|
* Capitalize the first letter of the given string.
|
|
* @param {String} string
|
|
* @return {String}
|
|
*/
|
|
capitalize: function(string) {
|
|
if (string) {
|
|
string = string.charAt(0).toUpperCase() + string.substr(1);
|
|
}
|
|
return string || '';
|
|
},
|
|
/**
|
|
* Uncapitalize the first letter of a given string.
|
|
* @param {String} string
|
|
* @return {String}
|
|
*/
|
|
uncapitalize: function(string) {
|
|
if (string) {
|
|
string = string.charAt(0).toLowerCase() + string.substr(1);
|
|
}
|
|
return string || '';
|
|
},
|
|
/**
|
|
* Truncate a string and add an ellipsis ('...') to the end if it exceeds the specified length.
|
|
* @param {String} value The string to truncate.
|
|
* @param {Number} length The maximum length to allow before truncating.
|
|
* @param {Boolean} [word=false] `true` to try to find a common word break.
|
|
* @return {String} The converted text.
|
|
*/
|
|
ellipsis: function(value, length, word) {
|
|
if (value && value.length > length) {
|
|
if (word) {
|
|
var vs = value.substr(0, length - 2),
|
|
index = Math.max(vs.lastIndexOf(' '), vs.lastIndexOf('.'), vs.lastIndexOf('!'), vs.lastIndexOf('?'));
|
|
if (index !== -1 && index >= (length - 15)) {
|
|
return vs.substr(0, index) + "...";
|
|
}
|
|
}
|
|
return value.substr(0, length - 3) + "...";
|
|
}
|
|
return value;
|
|
},
|
|
/**
|
|
* Escapes the passed string for use in a regular expression.
|
|
* @param {String} string The string to escape.
|
|
* @return {String} The escaped string.
|
|
*/
|
|
escapeRegex: function(string) {
|
|
return string.replace(escapeRegexRe, "\\$1");
|
|
},
|
|
/**
|
|
* Creates a `RegExp` given a string `value` and optional flags. For example, the
|
|
* following two regular expressions are equivalent.
|
|
*
|
|
* var regex1 = Ext.String.createRegex('hello');
|
|
*
|
|
* var regex2 = /^hello$/i;
|
|
*
|
|
* The following two regular expressions are also equivalent:
|
|
*
|
|
* var regex1 = Ext.String.createRegex('world', false, false, false);
|
|
*
|
|
* var regex2 = /world/;
|
|
*
|
|
* @param {String/RegExp} value The String to convert to a `RegExp`.
|
|
* @param {Boolean} [startsWith=true] Pass `false` to allow a match to start
|
|
* anywhere in the string. By default the `value` will match only at the start
|
|
* of the string.
|
|
* @param {Boolean} [endsWith=true] Pass `false` to allow the match to end before
|
|
* the end of the string. By default the `value` will match only at the end of the
|
|
* string.
|
|
* @param {Boolean} [ignoreCase=true] Pass `false` to make the `RegExp` case
|
|
* sensitive (removes the 'i' flag).
|
|
* @since 5.0.0
|
|
* @return {RegExp}
|
|
*/
|
|
createRegex: function(value, startsWith, endsWith, ignoreCase) {
|
|
var ret = value;
|
|
if (value != null && !value.exec) {
|
|
// not a regex
|
|
ret = ExtString.escapeRegex(String(value));
|
|
if (startsWith !== false) {
|
|
ret = '^' + ret;
|
|
}
|
|
if (endsWith !== false) {
|
|
ret += '$';
|
|
}
|
|
ret = new RegExp(ret, (ignoreCase !== false) ? 'i' : '');
|
|
}
|
|
return ret;
|
|
},
|
|
/**
|
|
* Escapes the passed string for ' and \.
|
|
* @param {String} string The string to escape.
|
|
* @return {String} The escaped string.
|
|
*/
|
|
escape: function(string) {
|
|
return string.replace(escapeRe, "\\$1");
|
|
},
|
|
/**
|
|
* Utility function that allows you to easily switch a string between two alternating values. The passed value
|
|
* is compared to the current string, and if they are equal, the other value that was passed in is returned. If
|
|
* they are already different, the first value passed in is returned. Note that this method returns the new value
|
|
* but does not change the current string.
|
|
*
|
|
* // alternate sort directions
|
|
* sort = Ext.String.toggle(sort, 'ASC', 'DESC');
|
|
*
|
|
* // instead of conditional logic:
|
|
* sort = (sort === 'ASC' ? 'DESC' : 'ASC');
|
|
*
|
|
* @param {String} string The current string.
|
|
* @param {String} value The value to compare to the current string.
|
|
* @param {String} other The new value to use if the string already equals the first value passed in.
|
|
* @return {String} The new value.
|
|
*/
|
|
toggle: function(string, value, other) {
|
|
return string === value ? other : value;
|
|
},
|
|
/**
|
|
* Pads the left side of a string with a specified character. This is especially useful
|
|
* for normalizing number and date strings. Example usage:
|
|
*
|
|
* var s = Ext.String.leftPad('123', 5, '0');
|
|
* // s now contains the string: '00123'
|
|
*
|
|
* @param {String} string The original string.
|
|
* @param {Number} size The total length of the output string.
|
|
* @param {String} [character=' '] (optional) The character with which to pad the original string.
|
|
* @return {String} The padded string.
|
|
*/
|
|
leftPad: function(string, size, character) {
|
|
var result = String(string);
|
|
character = character || " ";
|
|
while (result.length < size) {
|
|
result = character + result;
|
|
}
|
|
return result;
|
|
},
|
|
/**
|
|
* Returns a string with a specified number of repetitions a given string pattern.
|
|
* The pattern be separated by a different string.
|
|
*
|
|
* var s = Ext.String.repeat('---', 4); // = '------------'
|
|
* var t = Ext.String.repeat('--', 3, '/'); // = '--/--/--'
|
|
*
|
|
* @param {String} pattern The pattern to repeat.
|
|
* @param {Number} count The number of times to repeat the pattern (may be 0).
|
|
* @param {String} sep An option string to separate each pattern.
|
|
*/
|
|
repeat: function(pattern, count, sep) {
|
|
if (count < 1) {
|
|
count = 0;
|
|
}
|
|
for (var buf = [],
|
|
i = count; i--; ) {
|
|
buf.push(pattern);
|
|
}
|
|
return buf.join(sep || '');
|
|
},
|
|
/**
|
|
* Splits a string of space separated words into an array, trimming as needed. If the
|
|
* words are already an array, it is returned.
|
|
*
|
|
* @param {String/Array} words
|
|
*/
|
|
splitWords: function(words) {
|
|
if (words && typeof words == 'string') {
|
|
return words.replace(basicTrimRe, '').split(whitespaceRe);
|
|
}
|
|
return words || [];
|
|
}
|
|
};
|
|
}());
|
|
// initialize the default encode / decode entities
|
|
Ext.String.resetCharacterEntities();
|
|
/**
|
|
* Old alias to {@link Ext.String#htmlEncode}
|
|
* @deprecated Use {@link Ext.String#htmlEncode} instead
|
|
* @method htmlEncode
|
|
* @member Ext
|
|
* @inheritdoc Ext.String#htmlEncode
|
|
*/
|
|
Ext.htmlEncode = Ext.String.htmlEncode;
|
|
/**
|
|
* Old alias to {@link Ext.String#htmlDecode}
|
|
* @deprecated Use {@link Ext.String#htmlDecode} instead
|
|
* @method htmlDecode
|
|
* @member Ext
|
|
* @inheritdoc Ext.String#htmlDecode
|
|
*/
|
|
Ext.htmlDecode = Ext.String.htmlDecode;
|
|
/**
|
|
* Old alias to {@link Ext.String#urlAppend}
|
|
* @deprecated Use {@link Ext.String#urlAppend} instead
|
|
* @method urlAppend
|
|
* @member Ext
|
|
* @inheritdoc Ext.String#urlAppend
|
|
*/
|
|
Ext.urlAppend = Ext.String.urlAppend;
|
|
|
|
/**
|
|
* @class Ext.Date
|
|
* This class defines some basic methods for handling dates.
|
|
*
|
|
* The date parsing and formatting syntax contains a subset of
|
|
* [PHP's `date()` function](http://www.php.net/date), and the formats that are
|
|
* supported will provide results equivalent to their PHP versions.
|
|
*
|
|
* The following is a list of all currently supported formats:
|
|
*
|
|
* Format Description Example returned values
|
|
* ------ ----------------------------------------------------------------------- -----------------------
|
|
* d Day of the month, 2 digits with leading zeros 01 to 31
|
|
* D A short textual representation of the day of the week Mon to Sun
|
|
* j Day of the month without leading zeros 1 to 31
|
|
* l A full textual representation of the day of the week Sunday to Saturday
|
|
* N ISO-8601 numeric representation of the day of the week 1 (for Monday) through 7 (for Sunday)
|
|
* S English ordinal suffix for the day of the month, 2 characters st, nd, rd or th. Works well with j
|
|
* w Numeric representation of the day of the week 0 (for Sunday) to 6 (for Saturday)
|
|
* z The day of the year (starting from 0) 0 to 364 (365 in leap years)
|
|
* W ISO-8601 week number of year, weeks starting on Monday 01 to 53
|
|
* F A full textual representation of a month, such as January or March January to December
|
|
* m Numeric representation of a month, with leading zeros 01 to 12
|
|
* M A short textual representation of a month Jan to Dec
|
|
* n Numeric representation of a month, without leading zeros 1 to 12
|
|
* t Number of days in the given month 28 to 31
|
|
* L Whether it's a leap year 1 if it is a leap year, 0 otherwise.
|
|
* o ISO-8601 year number (identical to (Y), but if the ISO week number (W) Examples: 1998 or 2004
|
|
* belongs to the previous or next year, that year is used instead)
|
|
* Y A full numeric representation of a year, 4 digits Examples: 1999 or 2003
|
|
* y A two digit representation of a year Examples: 99 or 03
|
|
* a Lowercase Ante meridiem and Post meridiem am or pm
|
|
* A Uppercase Ante meridiem and Post meridiem AM or PM
|
|
* g 12-hour format of an hour without leading zeros 1 to 12
|
|
* G 24-hour format of an hour without leading zeros 0 to 23
|
|
* h 12-hour format of an hour with leading zeros 01 to 12
|
|
* H 24-hour format of an hour with leading zeros 00 to 23
|
|
* i Minutes, with leading zeros 00 to 59
|
|
* s Seconds, with leading zeros 00 to 59
|
|
* u Decimal fraction of a second Examples:
|
|
* (minimum 1 digit, arbitrary number of digits allowed) 001 (i.e. 0.001s) or
|
|
* 100 (i.e. 0.100s) or
|
|
* 999 (i.e. 0.999s) or
|
|
* 999876543210 (i.e. 0.999876543210s)
|
|
* O Difference to Greenwich time (GMT) in hours and minutes Example: +1030
|
|
* P Difference to Greenwich time (GMT) with colon between hours and minutes Example: -08:00
|
|
* T Timezone abbreviation of the machine running the code Examples: EST, MDT, PDT ...
|
|
* Z Timezone offset in seconds (negative if west of UTC, positive if east) -43200 to 50400
|
|
* c ISO 8601 date represented as the local time with an offset to UTC appended.
|
|
* Notes: Examples:
|
|
* 1) If unspecified, the month / day defaults to the current month / day, 1991 or
|
|
* the time defaults to midnight, while the timezone defaults to the 1992-10 or
|
|
* browser's timezone. If a time is specified, it must include both hours 1993-09-20 or
|
|
* and minutes. The "T" delimiter, seconds, milliseconds and timezone 1994-08-19T16:20+01:00 or
|
|
* are optional. 1995-07-18T17:21:28-02:00 or
|
|
* 2) The decimal fraction of a second, if specified, must contain at 1996-06-17T18:22:29.98765+03:00 or
|
|
* least 1 digit (there is no limit to the maximum number 1997-05-16T19:23:30,12345-0400 or
|
|
* of digits allowed), and may be delimited by either a '.' or a ',' 1998-04-15T20:24:31.2468Z or
|
|
* Refer to the examples on the right for the various levels of 1999-03-14T20:24:32Z or
|
|
* date-time granularity which are supported, or see 2000-02-13T21:25:33
|
|
* http://www.w3.org/TR/NOTE-datetime for more info. 2001-01-12 22:26:34
|
|
* C An ISO date string as implemented by the native Date object's 1962-06-17T09:21:34.125Z
|
|
* [Date.toISOString](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString)
|
|
* method. This outputs the numeric part with *UTC* hour and minute
|
|
* values, and indicates this by appending the `'Z'` timezone
|
|
* identifier.
|
|
* U Seconds since the Unix Epoch (January 1 1970 00:00:00 GMT) 1193432466 or -2138434463
|
|
* MS Microsoft AJAX serialized dates \/Date(1238606590509)\/ (i.e. UTC milliseconds since epoch) or
|
|
* \/Date(1238606590509+0800)\/
|
|
* time A javascript millisecond timestamp 1350024476440
|
|
* timestamp A UNIX timestamp (same as U) 1350024866
|
|
*
|
|
* Example usage (note that you must escape format specifiers with '\\' to render them as character literals):
|
|
*
|
|
* // Sample date:
|
|
* // 'Wed Jan 10 2007 15:05:01 GMT-0600 (Central Standard Time)'
|
|
*
|
|
* var dt = new Date('1/10/2007 03:05:01 PM GMT-0600');
|
|
* console.log(Ext.Date.format(dt, 'Y-m-d')); // 2007-01-10
|
|
* console.log(Ext.Date.format(dt, 'F j, Y, g:i a')); // January 10, 2007, 3:05 pm
|
|
* console.log(Ext.Date.format(dt, 'l, \\t\\he jS \\of F Y h:i:s A')); // Wednesday, the 10th of January 2007 03:05:01 PM
|
|
*
|
|
* Here are some standard date/time patterns that you might find helpful. They
|
|
* are not part of the source of Ext.Date, but to use them you can simply copy this
|
|
* block of code into any script that is included after Ext.Date and they will also become
|
|
* globally available on the Date object. Feel free to add or remove patterns as needed in your code.
|
|
*
|
|
* Ext.Date.patterns = {
|
|
* ISO8601Long:"Y-m-d H:i:s",
|
|
* ISO8601Short:"Y-m-d",
|
|
* ShortDate: "n/j/Y",
|
|
* LongDate: "l, F d, Y",
|
|
* FullDateTime: "l, F d, Y g:i:s A",
|
|
* MonthDay: "F d",
|
|
* ShortTime: "g:i A",
|
|
* LongTime: "g:i:s A",
|
|
* SortableDateTime: "Y-m-d\\TH:i:s",
|
|
* UniversalSortableDateTime: "Y-m-d H:i:sO",
|
|
* YearMonth: "F, Y"
|
|
* };
|
|
*
|
|
* Example usage:
|
|
*
|
|
* var dt = new Date();
|
|
* console.log(Ext.Date.format(dt, Ext.Date.patterns.ShortDate));
|
|
*
|
|
* Developer-written, custom formats may be used by supplying both a formatting and a parsing function
|
|
* which perform to specialized requirements. The functions are stored in {@link #parseFunctions} and {@link #formatFunctions}.
|
|
* @singleton
|
|
*/
|
|
Ext.Date = (function() {
|
|
// @define Ext.lang.Date
|
|
// @define Ext.Date
|
|
// @require Ext
|
|
// @require Ext.lang.String
|
|
var utilDate,
|
|
nativeDate = Date,
|
|
stripEscapeRe = /(\\.)/g,
|
|
hourInfoRe = /([gGhHisucUOPZ]|MS)/,
|
|
dateInfoRe = /([djzmnYycU]|MS)/,
|
|
slashRe = /\\/gi,
|
|
numberTokenRe = /\{(\d+)\}/g,
|
|
MSFormatRe = new RegExp('\\/Date\\(([-+])?(\\d+)(?:[+-]\\d{4})?\\)\\/'),
|
|
pad = Ext.String.leftPad,
|
|
// Most of the date-formatting functions below are the excellent work of Baron Schwartz.
|
|
// (see http://www.xaprb.com/blog/2005/12/12/javascript-closures-for-runtime-efficiency/)
|
|
// They generate precompiled functions from format patterns instead of parsing and
|
|
// processing each pattern every time a date is formatted.
|
|
code = [
|
|
// date calculations (note: the code below creates a dependency on Ext.Number.from())
|
|
"var me = this, dt, y, m, d, h, i, s, ms, o, O, z, zz, u, v, W, year, jan4, week1monday, daysInMonth, dayMatched,",
|
|
"def = me.defaults,",
|
|
"from = Ext.Number.from,",
|
|
"results = String(input).match(me.parseRegexes[{0}]);",
|
|
// either null, or an array of matched strings
|
|
"if(results){",
|
|
"{1}",
|
|
"if(u != null){",
|
|
// i.e. unix time is defined
|
|
"v = new Date(u * 1000);",
|
|
// give top priority to UNIX time
|
|
"}else{",
|
|
// create Date object representing midnight of the current day;
|
|
// this will provide us with our date defaults
|
|
// (note: clearTime() handles Daylight Saving Time automatically)
|
|
"dt = me.clearTime(new Date);",
|
|
"y = from(y, from(def.y, dt.getFullYear()));",
|
|
"m = from(m, from(def.m - 1, dt.getMonth()));",
|
|
"dayMatched = d !== undefined;",
|
|
"d = from(d, from(def.d, dt.getDate()));",
|
|
// Attempt to validate the day. Since it defaults to today, it may go out
|
|
// of range, for example parsing m/Y where the value is 02/2000 on the 31st of May.
|
|
// It will attempt to parse 2000/02/31, which will overflow to March and end up
|
|
// returning 03/2000. We only do this when we default the day. If an invalid day value
|
|
// was set to be parsed by the user, continue on and either let it overflow or return null
|
|
// depending on the strict value. This will be in line with the normal Date behaviour.
|
|
"if (!dayMatched) {",
|
|
"dt.setDate(1);",
|
|
"dt.setMonth(m);",
|
|
"dt.setFullYear(y);",
|
|
"daysInMonth = me.getDaysInMonth(dt);",
|
|
"if (d > daysInMonth) {",
|
|
"d = daysInMonth;",
|
|
"}",
|
|
"}",
|
|
"h = from(h, from(def.h, dt.getHours()));",
|
|
"i = from(i, from(def.i, dt.getMinutes()));",
|
|
"s = from(s, from(def.s, dt.getSeconds()));",
|
|
"ms = from(ms, from(def.ms, dt.getMilliseconds()));",
|
|
"if(z >= 0 && y >= 0){",
|
|
// both the year and zero-based day of year are defined and >= 0.
|
|
// these 2 values alone provide sufficient info to create a full date object
|
|
// create Date object representing January 1st for the given year
|
|
// handle years < 100 appropriately
|
|
"v = me.add(new Date(y < 100 ? 100 : y, 0, 1, h, i, s, ms), me.YEAR, y < 100 ? y - 100 : 0);",
|
|
// then add day of year, checking for Date "rollover" if necessary
|
|
"v = !strict? v : (strict === true && (z <= 364 || (me.isLeapYear(v) && z <= 365))? me.add(v, me.DAY, z) : null);",
|
|
"}else if(strict === true && !me.isValid(y, m + 1, d, h, i, s, ms)){",
|
|
// check for Date "rollover"
|
|
"v = null;",
|
|
// invalid date, so return null
|
|
"}else{",
|
|
"if (W) {",
|
|
// support ISO-8601
|
|
// http://en.wikipedia.org/wiki/ISO_week_date
|
|
//
|
|
// Mutually equivalent definitions for week 01 are:
|
|
// a. the week starting with the Monday which is nearest in time to 1 January
|
|
// b. the week with 4 January in it
|
|
// ... there are many others ...
|
|
//
|
|
// We'll use letter b above to determine the first week of the year.
|
|
//
|
|
// So, first get a Date object for January 4th of whatever calendar year is desired.
|
|
//
|
|
// Then, the first Monday of the year can easily be determined by (operating on this Date):
|
|
// 1. Getting the day of the week.
|
|
// 2. Subtracting that by one.
|
|
// 3. Multiplying that by 86400000 (one day in ms).
|
|
// 4. Subtracting this number of days (in ms) from the January 4 date (represented in ms).
|
|
//
|
|
// Example #1 ...
|
|
//
|
|
// January 2012
|
|
// Su Mo Tu We Th Fr Sa
|
|
// 1 2 3 4 5 6 7
|
|
// 8 9 10 11 12 13 14
|
|
// 15 16 17 18 19 20 21
|
|
// 22 23 24 25 26 27 28
|
|
// 29 30 31
|
|
//
|
|
// 1. January 4th is a Wednesday.
|
|
// 2. Its day number is 3.
|
|
// 3. Simply substract 2 days from Wednesday.
|
|
// 4. The first week of the year begins on Monday, January 2. Simple!
|
|
//
|
|
// Example #2 ...
|
|
// January 1992
|
|
// Su Mo Tu We Th Fr Sa
|
|
// 1 2 3 4
|
|
// 5 6 7 8 9 10 11
|
|
// 12 13 14 15 16 17 18
|
|
// 19 20 21 22 23 24 25
|
|
// 26 27 28 29 30 31
|
|
//
|
|
// 1. January 4th is a Saturday.
|
|
// 2. Its day number is 6.
|
|
// 3. Simply subtract 5 days from Saturday.
|
|
// 4. The first week of the year begins on Monday, December 30. Simple!
|
|
//
|
|
// v = Ext.Date.clearTime(new Date(week1monday.getTime() + ((W - 1) * 604800000 + 43200000)));
|
|
// (This is essentially doing the same thing as above but for the week rather than the day)
|
|
"year = y || (new Date()).getFullYear();",
|
|
"jan4 = new Date(year, 0, 4, 0, 0, 0);",
|
|
"d = jan4.getDay();",
|
|
// If the 1st is a Thursday, then the 4th will be a Sunday, so we need the appropriate
|
|
// day number here, which is why we use the day === checks.
|
|
"week1monday = new Date(jan4.getTime() - ((d === 0 ? 6 : d - 1) * 86400000));",
|
|
// The reason for adding 43200000 (12 hours) is to avoid any complication with daylight saving
|
|
// switch overs. For example, if the clock is rolled back, an hour will repeat, so adding 7 days
|
|
// will leave us 1 hour short (Sun <date> 23:00:00). By setting is to 12:00, subtraction
|
|
// or addition of an hour won't make any difference.
|
|
"v = Ext.Date.clearTime(new Date(week1monday.getTime() + ((W - 1) * 604800000 + 43200000)));",
|
|
"} else {",
|
|
// plain old Date object
|
|
// handle years < 100 properly
|
|
"v = me.add(new Date(y < 100 ? 100 : y, m, d, h, i, s, ms), me.YEAR, y < 100 ? y - 100 : 0);",
|
|
"}",
|
|
"}",
|
|
"}",
|
|
"}",
|
|
"if(v){",
|
|
// favor UTC offset over GMT offset
|
|
"if(zz != null){",
|
|
// reset to UTC, then add offset
|
|
"v = me.add(v, me.SECOND, -v.getTimezoneOffset() * 60 - zz);",
|
|
"}else if(o){",
|
|
// reset to GMT, then add offset
|
|
"v = me.add(v, me.MINUTE, -v.getTimezoneOffset() + (sn == '+'? -1 : 1) * (hr * 60 + mn));",
|
|
"}",
|
|
"}",
|
|
"return (v != null) ? v : null;"
|
|
].join('\n');
|
|
// Polyfill Date's toISOString instance method where not implemented.
|
|
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString
|
|
// TODO: Remove this when IE8 retires.
|
|
if (!Date.prototype.toISOString) {
|
|
Date.prototype.toISOString = function() {
|
|
var me = this;
|
|
return pad(me.getUTCFullYear(), 4, '0') + '-' + pad(me.getUTCMonth() + 1, 2, '0') + '-' + pad(me.getUTCDate(), 2, '0') + 'T' + pad(me.getUTCHours(), 2, '0') + ':' + pad(me.getUTCMinutes(), 2, '0') + ':' + pad(me.getUTCSeconds(), 2, '0') + '.' + pad(me.getUTCMilliseconds(), 3, '0') + 'Z';
|
|
};
|
|
}
|
|
/**
|
|
* @method xf
|
|
* @private
|
|
* @param format
|
|
* Create private copy of Ext JS's `Ext.util.Format.format()` method
|
|
* + to remove unnecessary dependency
|
|
* + to resolve namespace conflict with MS-Ajax's implementation
|
|
*/
|
|
function xf(format) {
|
|
var args = Array.prototype.slice.call(arguments, 1);
|
|
return format.replace(numberTokenRe, function(m, i) {
|
|
return args[i];
|
|
});
|
|
}
|
|
utilDate = {
|
|
/** @ignore */
|
|
now: nativeDate.now,
|
|
// always available due to polyfill in Ext.js
|
|
/**
|
|
* @private
|
|
*/
|
|
toString: function(date) {
|
|
if (!date) {
|
|
date = new nativeDate();
|
|
}
|
|
return date.getFullYear() + "-" + pad(date.getMonth() + 1, 2, '0') + "-" + pad(date.getDate(), 2, '0') + "T" + pad(date.getHours(), 2, '0') + ":" + pad(date.getMinutes(), 2, '0') + ":" + pad(date.getSeconds(), 2, '0');
|
|
},
|
|
/**
|
|
* Returns the number of milliseconds between two dates.
|
|
* @param {Date} dateA The first date.
|
|
* @param {Date} [dateB=new Date()] (optional) The second date.
|
|
* @return {Number} The difference in milliseconds
|
|
*/
|
|
getElapsed: function(dateA, dateB) {
|
|
return Math.abs(dateA - (dateB || utilDate.now()));
|
|
},
|
|
/**
|
|
* Global flag which determines if strict date parsing should be used.
|
|
* Strict date parsing will not roll-over invalid dates, which is the
|
|
* default behavior of JavaScript Date objects.
|
|
* (see {@link #parse} for more information)
|
|
* @type Boolean
|
|
*/
|
|
useStrict: false,
|
|
/**
|
|
* @private
|
|
*/
|
|
formatCodeToRegex: function(character, currentGroup) {
|
|
// Note: currentGroup - position in regex result array (see notes for Ext.Date.parseCodes below)
|
|
var p = utilDate.parseCodes[character];
|
|
if (p) {
|
|
p = typeof p === 'function' ? p() : p;
|
|
utilDate.parseCodes[character] = p;
|
|
}
|
|
// reassign function result to prevent repeated execution
|
|
return p ? Ext.applyIf({
|
|
c: p.c ? xf(p.c, currentGroup || "{0}") : p.c
|
|
}, p) : {
|
|
g: 0,
|
|
c: null,
|
|
s: Ext.String.escapeRegex(character)
|
|
};
|
|
},
|
|
// treat unrecognized characters as literals
|
|
/**
|
|
* An object hash in which each property is a date parsing function. The property name is the
|
|
* format string which that function parses.
|
|
*
|
|
* This object is automatically populated with date parsing functions as
|
|
* date formats are requested for Ext standard formatting strings.
|
|
*
|
|
* Custom parsing functions may be inserted into this object, keyed by a name which from then on
|
|
* may be used as a format string to {@link #parse}.
|
|
*
|
|
* Example:
|
|
*
|
|
* Ext.Date.parseFunctions['x-date-format'] = myDateParser;
|
|
*
|
|
* A parsing function should return a Date object, and is passed the following parameters:
|
|
*
|
|
* - `date`: {@link String} - The date string to parse.
|
|
* - `strict`: {@link Boolean} - `true` to validate date strings while parsing
|
|
* (i.e. prevent JavaScript Date "rollover"). __The default must be `false`.__
|
|
* Invalid date strings should return `null` when parsed.
|
|
*
|
|
* To enable Dates to also be _formatted_ according to that format, a corresponding
|
|
* formatting function must be placed into the {@link #formatFunctions} property.
|
|
* @property parseFunctions
|
|
* @type Object
|
|
*/
|
|
parseFunctions: {
|
|
"MS": function(input, strict) {
|
|
// note: the timezone offset is ignored since the MS Ajax server sends
|
|
// a UTC milliseconds-since-Unix-epoch value (negative values are allowed)
|
|
var r = (input || '').match(MSFormatRe);
|
|
return r ? new nativeDate(((r[1] || '') + r[2]) * 1) : null;
|
|
},
|
|
"time": function(input, strict) {
|
|
var num = parseInt(input, 10);
|
|
if (num || num === 0) {
|
|
return new nativeDate(num);
|
|
}
|
|
return null;
|
|
},
|
|
"timestamp": function(input, strict) {
|
|
var num = parseInt(input, 10);
|
|
if (num || num === 0) {
|
|
return new nativeDate(num * 1000);
|
|
}
|
|
return null;
|
|
}
|
|
},
|
|
parseRegexes: [],
|
|
/**
|
|
* An object hash in which each property is a date formatting function. The property name is the
|
|
* format string which corresponds to the produced formatted date string.
|
|
*
|
|
* This object is automatically populated with date formatting functions as
|
|
* date formats are requested for Ext standard formatting strings.
|
|
*
|
|
* Custom formatting functions may be inserted into this object, keyed by a name which from then on
|
|
* may be used as a format string to {@link #format}.
|
|
*
|
|
* Example:
|
|
*
|
|
* Ext.Date.formatFunctions['x-date-format'] = myDateFormatter;
|
|
*
|
|
* A formatting function should return a string representation of the Date object which
|
|
* is the scope (this) of the function.
|
|
*
|
|
* To enable date strings to also be _parsed_ according to that format, a corresponding
|
|
* parsing function must be placed into the {@link #parseFunctions} property.
|
|
* @property formatFunctions
|
|
* @type Object
|
|
*/
|
|
formatFunctions: {
|
|
"MS": function() {
|
|
// UTC milliseconds since Unix epoch (MS-AJAX serialized date format (MRSF))
|
|
return '\\/Date(' + this.getTime() + ')\\/';
|
|
},
|
|
"time": function() {
|
|
return this.getTime().toString();
|
|
},
|
|
"timestamp": function() {
|
|
return utilDate.format(this, 'U');
|
|
}
|
|
},
|
|
y2kYear: 50,
|
|
/**
|
|
* Date interval constant.
|
|
* @type String
|
|
*/
|
|
MILLI: "ms",
|
|
/**
|
|
* Date interval constant.
|
|
* @type String
|
|
*/
|
|
SECOND: "s",
|
|
/**
|
|
* Date interval constant.
|
|
* @type String
|
|
*/
|
|
MINUTE: "mi",
|
|
/** Date interval constant.
|
|
* @type String
|
|
*/
|
|
HOUR: "h",
|
|
/**
|
|
* Date interval constant.
|
|
* @type String
|
|
*/
|
|
DAY: "d",
|
|
/**
|
|
* Date interval constant.
|
|
* @type String
|
|
*/
|
|
MONTH: "mo",
|
|
/**
|
|
* Date interval constant.
|
|
* @type String
|
|
*/
|
|
YEAR: "y",
|
|
/**
|
|
* The number of days in a week.
|
|
* @type Number
|
|
*/
|
|
DAYS_IN_WEEK: 7,
|
|
/**
|
|
* The number of months in a year.
|
|
* @type Number
|
|
*/
|
|
MONTHS_IN_YEAR: 12,
|
|
/**
|
|
* The maximum number of days in a month.
|
|
* @type {Number}
|
|
*/
|
|
MAX_DAYS_IN_MONTH: 31,
|
|
SUNDAY: 0,
|
|
MONDAY: 1,
|
|
TUESDAY: 2,
|
|
WEDNESDAY: 3,
|
|
THURSDAY: 4,
|
|
FRIDAY: 5,
|
|
SATURDAY: 6,
|
|
/**
|
|
* An object hash containing default date values used during date parsing.
|
|
*
|
|
* The following properties are available:
|
|
*
|
|
* - `y`: {@link Number} - The default year value. Defaults to `undefined`.
|
|
* - `m`: {@link Number} - The default 1-based month value. Defaults to `undefined`.
|
|
* - `d`: {@link Number} - The default day value. Defaults to `undefined`.
|
|
* - `h`: {@link Number} - The default hour value. Defaults to `undefined`.
|
|
* - `i`: {@link Number} - The default minute value. Defaults to `undefined`.
|
|
* - `s`: {@link Number} - The default second value. Defaults to `undefined`.
|
|
* - `ms`: {@link Number} - The default millisecond value. Defaults to `undefined`.
|
|
*
|
|
* Override these properties to customize the default date values used by the {@link #parse} method.
|
|
*
|
|
* __Note:__ In countries which experience Daylight Saving Time (i.e. DST), the `h`, `i`, `s`
|
|
* and `ms` properties may coincide with the exact time in which DST takes effect.
|
|
* It is the responsibility of the developer to account for this.
|
|
*
|
|
* Example Usage:
|
|
*
|
|
* // set default day value to the first day of the month
|
|
* Ext.Date.defaults.d = 1;
|
|
*
|
|
* // parse a February date string containing only year and month values.
|
|
* // setting the default day value to 1 prevents weird date rollover issues
|
|
* // when attempting to parse the following date string on, for example, March 31st 2009.
|
|
* Ext.Date.parse('2009-02', 'Y-m'); // returns a Date object representing February 1st 2009.
|
|
*
|
|
* @property defaults
|
|
* @type Object
|
|
*/
|
|
defaults: {},
|
|
//<locale type="array">
|
|
/**
|
|
* @property {String[]} dayNames
|
|
* An array of textual day names.
|
|
* Override these values for international dates.
|
|
*
|
|
* Example:
|
|
*
|
|
* Ext.Date.dayNames = [
|
|
* 'SundayInYourLang',
|
|
* 'MondayInYourLang'
|
|
* // ...
|
|
* ];
|
|
*/
|
|
dayNames: [
|
|
"Sunday",
|
|
"Monday",
|
|
"Tuesday",
|
|
"Wednesday",
|
|
"Thursday",
|
|
"Friday",
|
|
"Saturday"
|
|
],
|
|
//</locale>
|
|
//<locale type="array">
|
|
/**
|
|
* @property {String[]} monthNames
|
|
* An array of textual month names.
|
|
* Override these values for international dates.
|
|
*
|
|
* Example:
|
|
*
|
|
* Ext.Date.monthNames = [
|
|
* 'JanInYourLang',
|
|
* 'FebInYourLang'
|
|
* // ...
|
|
* ];
|
|
*/
|
|
monthNames: [
|
|
"January",
|
|
"February",
|
|
"March",
|
|
"April",
|
|
"May",
|
|
"June",
|
|
"July",
|
|
"August",
|
|
"September",
|
|
"October",
|
|
"November",
|
|
"December"
|
|
],
|
|
//</locale>
|
|
//<locale type="object">
|
|
/**
|
|
* @property {Object} monthNumbers
|
|
* An object hash of zero-based JavaScript month numbers (with short month names as keys).
|
|
*
|
|
* __Note:__ keys are case-sensitive.
|
|
*
|
|
* Override these values for international dates.
|
|
*
|
|
* Example:
|
|
*
|
|
* Ext.Date.monthNumbers = {
|
|
* 'LongJanNameInYourLang': 0,
|
|
* 'ShortJanNameInYourLang':0,
|
|
* 'LongFebNameInYourLang':1,
|
|
* 'ShortFebNameInYourLang':1
|
|
* // ...
|
|
* };
|
|
*/
|
|
monthNumbers: {
|
|
January: 0,
|
|
Jan: 0,
|
|
February: 1,
|
|
Feb: 1,
|
|
March: 2,
|
|
Mar: 2,
|
|
April: 3,
|
|
Apr: 3,
|
|
May: 4,
|
|
June: 5,
|
|
Jun: 5,
|
|
July: 6,
|
|
Jul: 6,
|
|
August: 7,
|
|
Aug: 7,
|
|
September: 8,
|
|
Sep: 8,
|
|
October: 9,
|
|
Oct: 9,
|
|
November: 10,
|
|
Nov: 10,
|
|
December: 11,
|
|
Dec: 11
|
|
},
|
|
//</locale>
|
|
//<locale>
|
|
/**
|
|
* @property {String} defaultFormat
|
|
* The date format string that the {@link Ext.util.Format#dateRenderer}
|
|
* and {@link Ext.util.Format#date} functions use. See {@link Ext.Date} for details.
|
|
*
|
|
* This may be overridden in a locale file.
|
|
*/
|
|
defaultFormat: "m/d/Y",
|
|
//</locale>
|
|
//<locale>
|
|
/**
|
|
* @property {Number} firstDayOfWeek
|
|
* The day on which the week starts. `0` being Sunday, through `6` being Saturday.
|
|
*
|
|
* This may be overridden in a locale file.
|
|
*/
|
|
firstDayOfWeek: 0,
|
|
//</locale>
|
|
//<locale>
|
|
/**
|
|
* @property {Number[]} weekendDays
|
|
* The days on which weekend falls. `0` being Sunday, through `6` being Saturday.
|
|
*
|
|
* This may be overridden in a locale file.
|
|
*/
|
|
weekendDays: [
|
|
0,
|
|
6
|
|
],
|
|
//</locale>
|
|
//<locale type="function">
|
|
/**
|
|
* Get the short month name for the given month number.
|
|
* Override this function for international dates.
|
|
* @param {Number} month A zero-based JavaScript month number.
|
|
* @return {String} The short month name.
|
|
*/
|
|
getShortMonthName: function(month) {
|
|
return utilDate.monthNames[month].substring(0, 3);
|
|
},
|
|
//</locale>
|
|
//<locale type="function">
|
|
/**
|
|
* Get the short day name for the given day number.
|
|
* Override this function for international dates.
|
|
* @param {Number} day A zero-based JavaScript day number.
|
|
* @return {String} The short day name.
|
|
*/
|
|
getShortDayName: function(day) {
|
|
return utilDate.dayNames[day].substring(0, 3);
|
|
},
|
|
//</locale>
|
|
//<locale type="function">
|
|
/**
|
|
* Get the zero-based JavaScript month number for the given short/full month name.
|
|
* Override this function for international dates.
|
|
* @param {String} name The short/full month name.
|
|
* @return {Number} The zero-based JavaScript month number.
|
|
*/
|
|
getMonthNumber: function(name) {
|
|
// handle camel casing for English month names (since the keys for the Ext.Date.monthNumbers hash are case sensitive)
|
|
return utilDate.monthNumbers[name.substring(0, 1).toUpperCase() + name.substring(1, 3).toLowerCase()];
|
|
},
|
|
//</locale>
|
|
/**
|
|
* Checks if the specified format contains hour information
|
|
* @param {String} format The format to check
|
|
* @return {Boolean} True if the format contains hour information
|
|
* @method
|
|
*/
|
|
formatContainsHourInfo: function(format) {
|
|
return hourInfoRe.test(format.replace(stripEscapeRe, ''));
|
|
},
|
|
/**
|
|
* Checks if the specified format contains information about
|
|
* anything other than the time.
|
|
* @param {String} format The format to check
|
|
* @return {Boolean} True if the format contains information about
|
|
* date/day information.
|
|
* @method
|
|
*/
|
|
formatContainsDateInfo: function(format) {
|
|
return dateInfoRe.test(format.replace(stripEscapeRe, ''));
|
|
},
|
|
/**
|
|
* Removes all escaping for a date format string. In date formats,
|
|
* using a '\' can be used to escape special characters.
|
|
* @param {String} format The format to unescape
|
|
* @return {String} The unescaped format
|
|
* @method
|
|
*/
|
|
unescapeFormat: function(format) {
|
|
// Escape the format, since \ can be used to escape special
|
|
// characters in a date format. For example, in a Spanish
|
|
// locale the format may be: 'd \\de F \\de Y'
|
|
return format.replace(slashRe, '');
|
|
},
|
|
/**
|
|
* The base format-code to formatting-function hashmap used by the {@link #format} method.
|
|
* Formatting functions are strings (or functions which return strings) which
|
|
* will return the appropriate value when evaluated in the context of the Date object
|
|
* from which the {@link #format} method is called.
|
|
* Add to / override these mappings for custom date formatting.
|
|
*
|
|
* __Note:__ `Ext.Date.format()` treats characters as literals if an appropriate mapping cannot be found.
|
|
*
|
|
* Example:
|
|
*
|
|
* Ext.Date.formatCodes.x = "Ext.util.Format.leftPad(this.getDate(), 2, '0')";
|
|
* console.log(Ext.Date.format(new Date(), 'X'); // returns the current day of the month
|
|
* @type Object
|
|
*/
|
|
formatCodes: {
|
|
d: "Ext.String.leftPad(m.getDate(), 2, '0')",
|
|
D: "Ext.Date.getShortDayName(m.getDay())",
|
|
// get localized short day name
|
|
j: "m.getDate()",
|
|
l: "Ext.Date.dayNames[m.getDay()]",
|
|
N: "(m.getDay() ? m.getDay() : 7)",
|
|
S: "Ext.Date.getSuffix(m)",
|
|
w: "m.getDay()",
|
|
z: "Ext.Date.getDayOfYear(m)",
|
|
W: "Ext.String.leftPad(Ext.Date.getWeekOfYear(m), 2, '0')",
|
|
F: "Ext.Date.monthNames[m.getMonth()]",
|
|
m: "Ext.String.leftPad(m.getMonth() + 1, 2, '0')",
|
|
M: "Ext.Date.getShortMonthName(m.getMonth())",
|
|
// get localized short month name
|
|
n: "(m.getMonth() + 1)",
|
|
t: "Ext.Date.getDaysInMonth(m)",
|
|
L: "(Ext.Date.isLeapYear(m) ? 1 : 0)",
|
|
o: "(m.getFullYear() + (Ext.Date.getWeekOfYear(m) == 1 && m.getMonth() > 0 ? +1 : (Ext.Date.getWeekOfYear(m) >= 52 && m.getMonth() < 11 ? -1 : 0)))",
|
|
Y: "Ext.String.leftPad(m.getFullYear(), 4, '0')",
|
|
y: "('' + m.getFullYear()).substring(2, 4)",
|
|
a: "(m.getHours() < 12 ? 'am' : 'pm')",
|
|
A: "(m.getHours() < 12 ? 'AM' : 'PM')",
|
|
g: "((m.getHours() % 12) ? m.getHours() % 12 : 12)",
|
|
G: "m.getHours()",
|
|
h: "Ext.String.leftPad((m.getHours() % 12) ? m.getHours() % 12 : 12, 2, '0')",
|
|
H: "Ext.String.leftPad(m.getHours(), 2, '0')",
|
|
i: "Ext.String.leftPad(m.getMinutes(), 2, '0')",
|
|
s: "Ext.String.leftPad(m.getSeconds(), 2, '0')",
|
|
u: "Ext.String.leftPad(m.getMilliseconds(), 3, '0')",
|
|
O: "Ext.Date.getGMTOffset(m)",
|
|
P: "Ext.Date.getGMTOffset(m, true)",
|
|
T: "Ext.Date.getTimezone(m)",
|
|
Z: "(m.getTimezoneOffset() * -60)",
|
|
c: function() {
|
|
// ISO-8601 -- GMT format
|
|
var c = "Y-m-dTH:i:sP",
|
|
code = [],
|
|
i,
|
|
l = c.length,
|
|
e;
|
|
for (i = 0; i < l; ++i) {
|
|
e = c.charAt(i);
|
|
code.push(e === "T" ? "'T'" : utilDate.getFormatCode(e));
|
|
}
|
|
// treat T as a character literal
|
|
return code.join(" + ");
|
|
},
|
|
C: function() {
|
|
// ISO-1601 -- browser format. UTC numerics with the 'Z' TZ id.
|
|
return 'm.toISOString()';
|
|
},
|
|
U: "Math.round(m.getTime() / 1000)"
|
|
},
|
|
/**
|
|
* Checks if the passed Date parameters will cause a JavaScript Date "rollover".
|
|
* @param {Number} year 4-digit year.
|
|
* @param {Number} month 1-based month-of-year.
|
|
* @param {Number} day Day of month.
|
|
* @param {Number} hour (optional) Hour.
|
|
* @param {Number} minute (optional) Minute.
|
|
* @param {Number} second (optional) Second.
|
|
* @param {Number} millisecond (optional) Millisecond.
|
|
* @return {Boolean} `true` if the passed parameters do not cause a Date "rollover", `false` otherwise.
|
|
*/
|
|
isValid: function(year, month, day, hour, minute, second, millisecond) {
|
|
// setup defaults
|
|
hour = hour || 0;
|
|
minute = minute || 0;
|
|
second = second || 0;
|
|
millisecond = millisecond || 0;
|
|
// Special handling for year < 100
|
|
var dt = utilDate.add(new nativeDate(year < 100 ? 100 : year, month - 1, day, hour, minute, second, millisecond), utilDate.YEAR, year < 100 ? year - 100 : 0);
|
|
return year === dt.getFullYear() && month === dt.getMonth() + 1 && day === dt.getDate() && hour === dt.getHours() && minute === dt.getMinutes() && second === dt.getSeconds() && millisecond === dt.getMilliseconds();
|
|
},
|
|
/**
|
|
* Parses the passed string using the specified date format.
|
|
* Note that this function expects normal calendar dates, meaning that months are 1-based (i.e. 1 = January).
|
|
* The {@link #defaults} hash will be used for any date value (i.e. year, month, day, hour, minute, second or millisecond)
|
|
* which cannot be found in the passed string. If a corresponding default date value has not been specified in the {@link #defaults} hash,
|
|
* the current date's year, month, day or DST-adjusted zero-hour time value will be used instead.
|
|
* Keep in mind that the input date string must precisely match the specified format string
|
|
* in order for the parse operation to be successful (failed parse operations return a
|
|
* `null` value).
|
|
*
|
|
* Example:
|
|
*
|
|
* //dt = Fri May 25 2007 (current date)
|
|
* var dt = new Date();
|
|
*
|
|
* //dt = Thu May 25 2006 (today's month/day in 2006)
|
|
* dt = Ext.Date.parse("2006", "Y");
|
|
*
|
|
* //dt = Sun Jan 15 2006 (all date parts specified)
|
|
* dt = Ext.Date.parse("2006-01-15", "Y-m-d");
|
|
*
|
|
* //dt = Sun Jan 15 2006 15:20:01
|
|
* dt = Ext.Date.parse("2006-01-15 3:20:01 PM", "Y-m-d g:i:s A");
|
|
*
|
|
* // attempt to parse Sun Feb 29 2006 03:20:01 in strict mode
|
|
* dt = Ext.Date.parse("2006-02-29 03:20:01", "Y-m-d H:i:s", true); // returns null
|
|
*
|
|
* @param {String} input The raw date string.
|
|
* @param {String} format The expected date string format.
|
|
* @param {Boolean} [strict=false] (optional) `true` to validate date strings while parsing (i.e. prevents JavaScript Date "rollover").
|
|
* Invalid date strings will return `null` when parsed.
|
|
* @return {Date/null} The parsed Date, or `null` if an invalid date string.
|
|
*/
|
|
parse: function(input, format, strict) {
|
|
var p = utilDate.parseFunctions;
|
|
if (p[format] == null) {
|
|
utilDate.createParser(format);
|
|
}
|
|
return p[format].call(utilDate, input, Ext.isDefined(strict) ? strict : utilDate.useStrict);
|
|
},
|
|
// Backwards compat
|
|
parseDate: function(input, format, strict) {
|
|
return utilDate.parse(input, format, strict);
|
|
},
|
|
/**
|
|
* @private
|
|
*/
|
|
getFormatCode: function(character) {
|
|
var f = utilDate.formatCodes[character];
|
|
if (f) {
|
|
f = typeof f === 'function' ? f() : f;
|
|
utilDate.formatCodes[character] = f;
|
|
}
|
|
// reassign function result to prevent repeated execution
|
|
// note: unknown characters are treated as literals
|
|
return f || ("'" + Ext.String.escape(character) + "'");
|
|
},
|
|
/**
|
|
* @private
|
|
*/
|
|
createFormat: function(format) {
|
|
var code = [],
|
|
special = false,
|
|
ch = '',
|
|
i;
|
|
for (i = 0; i < format.length; ++i) {
|
|
ch = format.charAt(i);
|
|
if (!special && ch === "\\") {
|
|
special = true;
|
|
} else if (special) {
|
|
special = false;
|
|
code.push("'" + Ext.String.escape(ch) + "'");
|
|
} else {
|
|
if (ch === '\n') {
|
|
code.push("'\\n'");
|
|
} else {
|
|
code.push(utilDate.getFormatCode(ch));
|
|
}
|
|
}
|
|
}
|
|
utilDate.formatFunctions[format] = Ext.functionFactory("var m=this;return " + code.join('+'));
|
|
},
|
|
/**
|
|
* @private
|
|
*/
|
|
createParser: function(format) {
|
|
var regexNum = utilDate.parseRegexes.length,
|
|
currentGroup = 1,
|
|
calc = [],
|
|
regex = [],
|
|
special = false,
|
|
ch = "",
|
|
i = 0,
|
|
len = format.length,
|
|
atEnd = [],
|
|
obj;
|
|
for (; i < len; ++i) {
|
|
ch = format.charAt(i);
|
|
if (!special && ch === "\\") {
|
|
special = true;
|
|
} else if (special) {
|
|
special = false;
|
|
regex.push(Ext.String.escape(ch));
|
|
} else {
|
|
obj = utilDate.formatCodeToRegex(ch, currentGroup);
|
|
currentGroup += obj.g;
|
|
regex.push(obj.s);
|
|
if (obj.g && obj.c) {
|
|
if (obj.calcAtEnd) {
|
|
atEnd.push(obj.c);
|
|
} else {
|
|
calc.push(obj.c);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
calc = calc.concat(atEnd);
|
|
utilDate.parseRegexes[regexNum] = new RegExp("^" + regex.join('') + "$", 'i');
|
|
utilDate.parseFunctions[format] = Ext.functionFactory("input", "strict", xf(code, regexNum, calc.join('')));
|
|
},
|
|
/**
|
|
* @private
|
|
*/
|
|
parseCodes: {
|
|
/**
|
|
* Notes:
|
|
* g = {Number} calculation group (0 or 1. only group 1 contributes to date calculations.)
|
|
* c = {String} calculation method (required for group 1. null for group 0. {0} = currentGroup - position in regex result array)
|
|
* s = {String} regex pattern. all matches are stored in results[], and are accessible by the calculation mapped to 'c'
|
|
*/
|
|
d: {
|
|
g: 1,
|
|
c: "d = parseInt(results[{0}], 10);\n",
|
|
s: "(3[0-1]|[1-2][0-9]|0[1-9])"
|
|
},
|
|
// day of month with leading zeroes (01 - 31)
|
|
j: {
|
|
g: 1,
|
|
c: "d = parseInt(results[{0}], 10);\n",
|
|
s: "(3[0-1]|[1-2][0-9]|[1-9])"
|
|
},
|
|
// day of month without leading zeroes (1 - 31)
|
|
D: function() {
|
|
for (var a = [],
|
|
i = 0; i < 7; a.push(utilDate.getShortDayName(i)) , ++i){}
|
|
// get localised short day names
|
|
return {
|
|
g: 0,
|
|
c: null,
|
|
s: "(?:" + a.join("|") + ")"
|
|
};
|
|
},
|
|
l: function() {
|
|
return {
|
|
g: 0,
|
|
c: null,
|
|
s: "(?:" + utilDate.dayNames.join("|") + ")"
|
|
};
|
|
},
|
|
N: {
|
|
g: 0,
|
|
c: null,
|
|
s: "[1-7]"
|
|
},
|
|
// ISO-8601 day number (1 (monday) - 7 (sunday))
|
|
//<locale type="object" property="parseCodes">
|
|
S: {
|
|
g: 0,
|
|
c: null,
|
|
s: "(?:st|nd|rd|th)"
|
|
},
|
|
//</locale>
|
|
w: {
|
|
g: 0,
|
|
c: null,
|
|
s: "[0-6]"
|
|
},
|
|
// JavaScript day number (0 (sunday) - 6 (saturday))
|
|
z: {
|
|
g: 1,
|
|
c: "z = parseInt(results[{0}], 10);\n",
|
|
s: "(\\d{1,3})"
|
|
},
|
|
// day of the year (0 - 364 (365 in leap years))
|
|
W: {
|
|
g: 1,
|
|
c: "W = parseInt(results[{0}], 10);\n",
|
|
s: "(\\d{2})"
|
|
},
|
|
// ISO-8601 week number (with leading zero)
|
|
F: function() {
|
|
return {
|
|
g: 1,
|
|
c: "m = parseInt(me.getMonthNumber(results[{0}]), 10);\n",
|
|
// get localised month number
|
|
s: "(" + utilDate.monthNames.join("|") + ")"
|
|
};
|
|
},
|
|
M: function() {
|
|
for (var a = [],
|
|
i = 0; i < 12; a.push(utilDate.getShortMonthName(i)) , ++i){}
|
|
// get localised short month names
|
|
return Ext.applyIf({
|
|
s: "(" + a.join("|") + ")"
|
|
}, utilDate.formatCodeToRegex("F"));
|
|
},
|
|
m: {
|
|
g: 1,
|
|
c: "m = parseInt(results[{0}], 10) - 1;\n",
|
|
s: "(1[0-2]|0[1-9])"
|
|
},
|
|
// month number with leading zeros (01 - 12)
|
|
n: {
|
|
g: 1,
|
|
c: "m = parseInt(results[{0}], 10) - 1;\n",
|
|
s: "(1[0-2]|[1-9])"
|
|
},
|
|
// month number without leading zeros (1 - 12)
|
|
t: {
|
|
g: 0,
|
|
c: null,
|
|
s: "(?:\\d{2})"
|
|
},
|
|
// no. of days in the month (28 - 31)
|
|
L: {
|
|
g: 0,
|
|
c: null,
|
|
s: "(?:1|0)"
|
|
},
|
|
o: {
|
|
g: 1,
|
|
c: "y = parseInt(results[{0}], 10);\n",
|
|
s: "(\\d{4})"
|
|
},
|
|
// ISO-8601 year number (with leading zero)
|
|
Y: {
|
|
g: 1,
|
|
c: "y = parseInt(results[{0}], 10);\n",
|
|
s: "(\\d{4})"
|
|
},
|
|
// 4-digit year
|
|
y: {
|
|
g: 1,
|
|
c: "var ty = parseInt(results[{0}], 10);\n" + "y = ty > me.y2kYear ? 1900 + ty : 2000 + ty;\n",
|
|
// 2-digit year
|
|
s: "(\\d{2})"
|
|
},
|
|
/**
|
|
* In the am/pm parsing routines, we allow both upper and lower case
|
|
* even though it doesn't exactly match the spec. It gives much more flexibility
|
|
* in being able to specify case insensitive regexes.
|
|
*/
|
|
//<locale type="object" property="parseCodes">
|
|
a: {
|
|
g: 1,
|
|
c: "if (/(am)/i.test(results[{0}])) {\n" + "if (!h || h == 12) { h = 0; }\n" + "} else { if (!h || h < 12) { h = (h || 0) + 12; }}",
|
|
s: "(am|pm|AM|PM)",
|
|
calcAtEnd: true
|
|
},
|
|
//</locale>
|
|
//<locale type="object" property="parseCodes">
|
|
A: {
|
|
g: 1,
|
|
c: "if (/(am)/i.test(results[{0}])) {\n" + "if (!h || h == 12) { h = 0; }\n" + "} else { if (!h || h < 12) { h = (h || 0) + 12; }}",
|
|
s: "(AM|PM|am|pm)",
|
|
calcAtEnd: true
|
|
},
|
|
//</locale>
|
|
g: {
|
|
g: 1,
|
|
c: "h = parseInt(results[{0}], 10);\n",
|
|
s: "(1[0-2]|[0-9])"
|
|
},
|
|
// 12-hr format of an hour without leading zeroes (1 - 12)
|
|
G: {
|
|
g: 1,
|
|
c: "h = parseInt(results[{0}], 10);\n",
|
|
s: "(2[0-3]|1[0-9]|[0-9])"
|
|
},
|
|
// 24-hr format of an hour without leading zeroes (0 - 23)
|
|
h: {
|
|
g: 1,
|
|
c: "h = parseInt(results[{0}], 10);\n",
|
|
s: "(1[0-2]|0[1-9])"
|
|
},
|
|
// 12-hr format of an hour with leading zeroes (01 - 12)
|
|
H: {
|
|
g: 1,
|
|
c: "h = parseInt(results[{0}], 10);\n",
|
|
s: "(2[0-3]|[0-1][0-9])"
|
|
},
|
|
// 24-hr format of an hour with leading zeroes (00 - 23)
|
|
i: {
|
|
g: 1,
|
|
c: "i = parseInt(results[{0}], 10);\n",
|
|
s: "([0-5][0-9])"
|
|
},
|
|
// minutes with leading zeros (00 - 59)
|
|
s: {
|
|
g: 1,
|
|
c: "s = parseInt(results[{0}], 10);\n",
|
|
s: "([0-5][0-9])"
|
|
},
|
|
// seconds with leading zeros (00 - 59)
|
|
u: {
|
|
g: 1,
|
|
c: "ms = results[{0}]; ms = parseInt(ms, 10)/Math.pow(10, ms.length - 3);\n",
|
|
s: "(\\d+)"
|
|
},
|
|
// decimal fraction of a second (minimum = 1 digit, maximum = unlimited)
|
|
O: {
|
|
g: 1,
|
|
c: [
|
|
"o = results[{0}];",
|
|
"var sn = o.substring(0,1),",
|
|
// get + / - sign
|
|
"hr = o.substring(1,3)*1 + Math.floor(o.substring(3,5) / 60),",
|
|
// get hours (performs minutes-to-hour conversion also, just in case)
|
|
"mn = o.substring(3,5) % 60;",
|
|
// get minutes
|
|
"o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))? (sn + Ext.String.leftPad(hr, 2, '0') + Ext.String.leftPad(mn, 2, '0')) : null;\n"
|
|
].// -12hrs <= GMT offset <= 14hrs
|
|
join("\n"),
|
|
s: "([+-]\\d{4})"
|
|
},
|
|
// GMT offset in hrs and mins
|
|
P: {
|
|
g: 1,
|
|
c: [
|
|
"o = results[{0}];",
|
|
"var sn = o.substring(0,1),",
|
|
// get + / - sign
|
|
"hr = o.substring(1,3)*1 + Math.floor(o.substring(4,6) / 60),",
|
|
// get hours (performs minutes-to-hour conversion also, just in case)
|
|
"mn = o.substring(4,6) % 60;",
|
|
// get minutes
|
|
"o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))? (sn + Ext.String.leftPad(hr, 2, '0') + Ext.String.leftPad(mn, 2, '0')) : null;\n"
|
|
].// -12hrs <= GMT offset <= 14hrs
|
|
join("\n"),
|
|
s: "([+-]\\d{2}:\\d{2})"
|
|
},
|
|
// GMT offset in hrs and mins (with colon separator)
|
|
T: {
|
|
g: 0,
|
|
c: null,
|
|
s: "[A-Z]{1,5}"
|
|
},
|
|
// timezone abbrev. may be between 1 - 5 chars
|
|
Z: {
|
|
g: 1,
|
|
c: "zz = results[{0}] * 1;\n" + // -43200 <= UTC offset <= 50400
|
|
"zz = (-43200 <= zz && zz <= 50400)? zz : null;\n",
|
|
s: "([+-]?\\d{1,5})"
|
|
},
|
|
// leading '+' sign is optional for UTC offset
|
|
c: function() {
|
|
var calc = [],
|
|
arr = [
|
|
utilDate.formatCodeToRegex("Y", 1),
|
|
// year
|
|
utilDate.formatCodeToRegex("m", 2),
|
|
// month
|
|
utilDate.formatCodeToRegex("d", 3),
|
|
// day
|
|
utilDate.formatCodeToRegex("H", 4),
|
|
// hour
|
|
utilDate.formatCodeToRegex("i", 5),
|
|
// minute
|
|
utilDate.formatCodeToRegex("s", 6),
|
|
// second
|
|
{
|
|
c: "ms = results[7] || '0'; ms = parseInt(ms, 10)/Math.pow(10, ms.length - 3);\n"
|
|
},
|
|
// decimal fraction of a second (minimum = 1 digit, maximum = unlimited)
|
|
{
|
|
c: [
|
|
// allow either "Z" (i.e. UTC) or "-0530" or "+08:00" (i.e. UTC offset) timezone delimiters. assumes local timezone if no timezone is specified
|
|
"if(results[8]) {",
|
|
// timezone specified
|
|
"if(results[8] == 'Z'){",
|
|
"zz = 0;",
|
|
// UTC
|
|
"}else if (results[8].indexOf(':') > -1){",
|
|
utilDate.formatCodeToRegex("P", 8).c,
|
|
// timezone offset with colon separator
|
|
"}else{",
|
|
utilDate.formatCodeToRegex("O", 8).c,
|
|
// timezone offset without colon separator
|
|
"}",
|
|
"}"
|
|
].join('\n')
|
|
}
|
|
],
|
|
i, l;
|
|
for (i = 0 , l = arr.length; i < l; ++i) {
|
|
calc.push(arr[i].c);
|
|
}
|
|
return {
|
|
g: 1,
|
|
c: calc.join(""),
|
|
s: [
|
|
arr[0].s,
|
|
// year (required)
|
|
"(?:",
|
|
"-",
|
|
arr[1].s,
|
|
// month (optional)
|
|
"(?:",
|
|
"-",
|
|
arr[2].s,
|
|
// day (optional)
|
|
"(?:",
|
|
"(?:T| )?",
|
|
// time delimiter -- either a "T" or a single blank space
|
|
arr[3].s,
|
|
":",
|
|
arr[4].s,
|
|
// hour AND minute, delimited by a single colon (optional). MUST be preceded by either a "T" or a single blank space
|
|
"(?::",
|
|
arr[5].s,
|
|
")?",
|
|
// seconds (optional)
|
|
"(?:(?:\\.|,)(\\d+))?",
|
|
// decimal fraction of a second (e.g. ",12345" or ".98765") (optional)
|
|
"(Z|(?:[-+]\\d{2}(?::)?\\d{2}))?",
|
|
// "Z" (UTC) or "-0530" (UTC offset without colon delimiter) or "+08:00" (UTC offset with colon delimiter) (optional)
|
|
")?",
|
|
")?",
|
|
")?"
|
|
].join("")
|
|
};
|
|
},
|
|
U: {
|
|
g: 1,
|
|
c: "u = parseInt(results[{0}], 10);\n",
|
|
s: "(-?\\d+)"
|
|
}
|
|
},
|
|
// leading minus sign indicates seconds before UNIX epoch
|
|
//Old Ext.Date prototype methods.
|
|
/**
|
|
* @private
|
|
*/
|
|
dateFormat: function(date, format) {
|
|
return utilDate.format(date, format);
|
|
},
|
|
/**
|
|
* Compares if two dates are equal by comparing their values.
|
|
* @param {Date} date1
|
|
* @param {Date} date2
|
|
* @return {Boolean} `true` if the date values are equal
|
|
*/
|
|
isEqual: function(date1, date2) {
|
|
// check we have 2 date objects
|
|
if (date1 && date2) {
|
|
return (date1.getTime() === date2.getTime());
|
|
}
|
|
// one or both isn't a date, only equal if both are falsey
|
|
return !(date1 || date2);
|
|
},
|
|
/**
|
|
* Formats a date given the supplied format string.
|
|
* @param {Date} date The date to format
|
|
* @param {String} format The format string
|
|
* @return {String} The formatted date or an empty string if date parameter is not a JavaScript Date object
|
|
*/
|
|
format: function(date, format) {
|
|
var formatFunctions = utilDate.formatFunctions;
|
|
if (!Ext.isDate(date)) {
|
|
return '';
|
|
}
|
|
if (formatFunctions[format] == null) {
|
|
utilDate.createFormat(format);
|
|
}
|
|
return formatFunctions[format].call(date) + '';
|
|
},
|
|
/**
|
|
* Get the timezone abbreviation of the current date (equivalent to the format specifier 'T').
|
|
*
|
|
* __Note:__ The date string returned by the JavaScript Date object's `toString()` method varies
|
|
* between browsers (e.g. FF vs IE) and system region settings (e.g. IE in Asia vs IE in America).
|
|
* For a given date string e.g. "Thu Oct 25 2007 22:55:35 GMT+0800 (Malay Peninsula Standard Time)",
|
|
* `getTimezone()` first tries to get the timezone abbreviation from between a pair of parentheses
|
|
* (which may or may not be present), failing which it proceeds to get the timezone abbreviation
|
|
* from the GMT offset portion of the date string.
|
|
*
|
|
* @example
|
|
* var dt = new Date('9/17/2011');
|
|
* console.log(Ext.Date.getTimezone(dt));
|
|
*
|
|
* @param {Date} date The date
|
|
* @return {String} The abbreviated timezone name (e.g. 'CST', 'PDT', 'EDT', 'MPST' ...).
|
|
*/
|
|
getTimezone: function(date) {
|
|
// the following list shows the differences between date strings from different browsers on a WinXP SP2 machine from an Asian locale:
|
|
//
|
|
// Opera : "Thu, 25 Oct 2007 22:53:45 GMT+0800" -- shortest (weirdest) date string of the lot
|
|
// Safari : "Thu Oct 25 2007 22:55:35 GMT+0800 (Malay Peninsula Standard Time)" -- value in parentheses always gives the correct timezone (same as FF)
|
|
// FF : "Thu Oct 25 2007 22:55:35 GMT+0800 (Malay Peninsula Standard Time)" -- value in parentheses always gives the correct timezone
|
|
// IE : "Thu Oct 25 22:54:35 UTC+0800 2007" -- (Asian system setting) look for 3-4 letter timezone abbrev
|
|
// IE : "Thu Oct 25 17:06:37 PDT 2007" -- (American system setting) look for 3-4 letter timezone abbrev
|
|
//
|
|
// this crazy regex attempts to guess the correct timezone abbreviation despite these differences.
|
|
// step 1: (?:\((.*)\) -- find timezone in parentheses
|
|
// step 2: ([A-Z]{1,4})(?:[\-+][0-9]{4})?(?: -?\d+)?) -- if nothing was found in step 1, find timezone from timezone offset portion of date string
|
|
// step 3: remove all non uppercase characters found in step 1 and 2
|
|
return date.toString().replace(/^.* (?:\((.*)\)|([A-Z]{1,5})(?:[\-+][0-9]{4})?(?: -?\d+)?)$/, "$1$2").replace(/[^A-Z]/g, "");
|
|
},
|
|
/**
|
|
* Get the offset from GMT of the current date (equivalent to the format specifier 'O').
|
|
*
|
|
* @example
|
|
* var dt = new Date('9/17/2011');
|
|
* console.log(Ext.Date.getGMTOffset(dt));
|
|
*
|
|
* @param {Date} date The date
|
|
* @param {Boolean} [colon=false] `true` to separate the hours and minutes with a colon.
|
|
* @return {String} The 4-character offset string prefixed with + or - (e.g. '-0600').
|
|
*/
|
|
getGMTOffset: function(date, colon) {
|
|
var offset = date.getTimezoneOffset();
|
|
return (offset > 0 ? "-" : "+") + Ext.String.leftPad(Math.floor(Math.abs(offset) / 60), 2, "0") + (colon ? ":" : "") + Ext.String.leftPad(Math.abs(offset % 60), 2, "0");
|
|
},
|
|
/**
|
|
* Get the numeric day number of the year, adjusted for leap year.
|
|
*
|
|
* @example
|
|
* var dt = new Date('9/17/2011');
|
|
* console.log(Ext.Date.getDayOfYear(dt)); // 259
|
|
*
|
|
* @param {Date} date The date
|
|
* @return {Number} 0 to 364 (365 in leap years).
|
|
*/
|
|
getDayOfYear: function(date) {
|
|
var num = 0,
|
|
d = utilDate.clone(date),
|
|
m = date.getMonth(),
|
|
i;
|
|
for (i = 0 , d.setDate(1) , d.setMonth(0); i < m; d.setMonth(++i)) {
|
|
num += utilDate.getDaysInMonth(d);
|
|
}
|
|
return num + date.getDate() - 1;
|
|
},
|
|
/**
|
|
* Get the numeric ISO-8601 week number of the year.
|
|
* (equivalent to the format specifier 'W', but without a leading zero).
|
|
*
|
|
* @example
|
|
* var dt = new Date('9/17/2011');
|
|
* console.log(Ext.Date.getWeekOfYear(dt)); // 37
|
|
*
|
|
* @param {Date} date The date.
|
|
* @return {Number} 1 to 53.
|
|
* @method
|
|
*/
|
|
getWeekOfYear: (function() {
|
|
// adapted from http://www.merlyn.demon.co.uk/weekcalc.htm
|
|
var ms1d = 86400000,
|
|
// milliseconds in a day
|
|
ms7d = 7 * ms1d;
|
|
// milliseconds in a week
|
|
return function(date) {
|
|
// return a closure so constants get calculated only once
|
|
var DC3 = nativeDate.UTC(date.getFullYear(), date.getMonth(), date.getDate() + 3) / ms1d,
|
|
// an Absolute Day Number
|
|
AWN = Math.floor(DC3 / 7),
|
|
// an Absolute Week Number
|
|
Wyr = new nativeDate(AWN * ms7d).getUTCFullYear();
|
|
return AWN - Math.floor(nativeDate.UTC(Wyr, 0, 7) / ms7d) + 1;
|
|
};
|
|
}()),
|
|
/**
|
|
* Checks if the current date falls within a leap year.
|
|
*
|
|
* @example
|
|
* var dt = new Date('1/10/2011');
|
|
* console.log(Ext.Date.isLeapYear(dt)); // false
|
|
*
|
|
* @param {Date} date The date
|
|
* @return {Boolean} `true` if the current date falls within a leap year, `false` otherwise.
|
|
*/
|
|
isLeapYear: function(date) {
|
|
var year = date.getFullYear();
|
|
return !!((year & 3) === 0 && (year % 100 || (year % 400 === 0 && year)));
|
|
},
|
|
/**
|
|
* Get the first day of the current month, adjusted for leap year. The returned value
|
|
* is the numeric day index within the week (0-6) which can be used in conjunction with
|
|
* the {@link #monthNames} array to retrieve the textual day name.
|
|
*
|
|
* @example
|
|
* var dt = new Date('1/10/2007'),
|
|
* firstDay = Ext.Date.getFirstDayOfMonth(dt);
|
|
*
|
|
* console.log(Ext.Date.dayNames[firstDay]); // output: 'Monday'
|
|
*
|
|
* @param {Date} date The date
|
|
* @return {Number} The day number (0-6).
|
|
*/
|
|
getFirstDayOfMonth: function(date) {
|
|
var day = (date.getDay() - (date.getDate() - 1)) % 7;
|
|
return (day < 0) ? (day + 7) : day;
|
|
},
|
|
/**
|
|
* Get the last day of the current month, adjusted for leap year. The returned value
|
|
* is the numeric day index within the week (0-6) which can be used in conjunction with
|
|
* the {@link #monthNames} array to retrieve the textual day name.
|
|
*
|
|
* @example
|
|
* var dt = new Date('1/10/2007'),
|
|
* lastDay = Ext.Date.getLastDayOfMonth(dt);
|
|
*
|
|
* console.log(Ext.Date.dayNames[lastDay]); // output: 'Wednesday'
|
|
*
|
|
* @param {Date} date The date
|
|
* @return {Number} The day number (0-6).
|
|
*/
|
|
getLastDayOfMonth: function(date) {
|
|
return utilDate.getLastDateOfMonth(date).getDay();
|
|
},
|
|
/**
|
|
* Get the date of the first day of the month in which this date resides.
|
|
* @param {Date} date The date
|
|
* @return {Date}
|
|
*/
|
|
getFirstDateOfMonth: function(date) {
|
|
return new nativeDate(date.getFullYear(), date.getMonth(), 1);
|
|
},
|
|
/**
|
|
* Get the date of the last day of the month in which this date resides.
|
|
* @param {Date} date The date
|
|
* @return {Date}
|
|
*/
|
|
getLastDateOfMonth: function(date) {
|
|
return new nativeDate(date.getFullYear(), date.getMonth(), utilDate.getDaysInMonth(date));
|
|
},
|
|
/**
|
|
* Get the number of days in the current month, adjusted for leap year.
|
|
* @param {Date} date The date
|
|
* @return {Number} The number of days in the month.
|
|
* @method
|
|
*/
|
|
getDaysInMonth: (function() {
|
|
var daysInMonth = [
|
|
31,
|
|
28,
|
|
31,
|
|
30,
|
|
31,
|
|
30,
|
|
31,
|
|
31,
|
|
30,
|
|
31,
|
|
30,
|
|
31
|
|
];
|
|
return function(date) {
|
|
// return a closure for efficiency
|
|
var m = date.getMonth();
|
|
return m === 1 && utilDate.isLeapYear(date) ? 29 : daysInMonth[m];
|
|
};
|
|
}()),
|
|
//<locale type="function">
|
|
/**
|
|
* Get the English ordinal suffix of the current day (equivalent to the format specifier 'S').
|
|
* @param {Date} date The date
|
|
* @return {String} 'st, 'nd', 'rd' or 'th'.
|
|
*/
|
|
getSuffix: function(date) {
|
|
switch (date.getDate()) {
|
|
case 1:
|
|
case 21:
|
|
case 31:
|
|
return "st";
|
|
case 2:
|
|
case 22:
|
|
return "nd";
|
|
case 3:
|
|
case 23:
|
|
return "rd";
|
|
default:
|
|
return "th";
|
|
}
|
|
},
|
|
//</locale>
|
|
/**
|
|
* Creates and returns a new Date instance with the exact same date value as the called instance.
|
|
* Dates are copied and passed by reference, so if a copied date variable is modified later, the original
|
|
* variable will also be changed. When the intention is to create a new variable that will not
|
|
* modify the original instance, you should create a clone.
|
|
*
|
|
* Example of correctly cloning a date:
|
|
*
|
|
* //wrong way:
|
|
* var orig = new Date('10/1/2006');
|
|
* var copy = orig;
|
|
* copy.setDate(5);
|
|
* console.log(orig); // returns 'Thu Oct 05 2006'!
|
|
*
|
|
* //correct way:
|
|
* var orig = new Date('10/1/2006'),
|
|
* copy = Ext.Date.clone(orig);
|
|
* copy.setDate(5);
|
|
* console.log(orig); // returns 'Thu Oct 01 2006'
|
|
*
|
|
* @param {Date} date The date.
|
|
* @return {Date} The new Date instance.
|
|
*/
|
|
clone: function(date) {
|
|
return new nativeDate(date.getTime());
|
|
},
|
|
/**
|
|
* Checks if the current date is affected by Daylight Saving Time (DST).
|
|
* @param {Date} date The date
|
|
* @return {Boolean} `true` if the current date is affected by DST.
|
|
*/
|
|
isDST: function(date) {
|
|
// adapted from http://sencha.com/forum/showthread.php?p=247172#post247172
|
|
// courtesy of @geoffrey.mcgill
|
|
return new nativeDate(date.getFullYear(), 0, 1).getTimezoneOffset() !== date.getTimezoneOffset();
|
|
},
|
|
/**
|
|
* Attempts to clear all time information from this Date by setting the time to midnight of the same day,
|
|
* automatically adjusting for Daylight Saving Time (DST) where applicable.
|
|
*
|
|
* __Note:__ DST timezone information for the browser's host operating system is assumed to be up-to-date.
|
|
* @param {Date} date The date
|
|
* @param {Boolean} [clone=false] `true` to create a clone of this date, clear the time and return it.
|
|
* @return {Date} this or the clone.
|
|
*/
|
|
clearTime: function(date, clone) {
|
|
// handles invalid dates preventing the browser from crashing.
|
|
if (isNaN(date.getTime())) {
|
|
return date;
|
|
}
|
|
if (clone) {
|
|
return utilDate.clearTime(utilDate.clone(date));
|
|
}
|
|
// get current date before clearing time
|
|
var d = date.getDate(),
|
|
hr, c;
|
|
// clear time
|
|
date.setHours(0);
|
|
date.setMinutes(0);
|
|
date.setSeconds(0);
|
|
date.setMilliseconds(0);
|
|
if (date.getDate() !== d) {
|
|
// account for DST (i.e. day of month changed when setting hour = 0)
|
|
// note: DST adjustments are assumed to occur in multiples of 1 hour (this is almost always the case)
|
|
// refer to http://www.timeanddate.com/time/aboutdst.html for the (rare) exceptions to this rule
|
|
// increment hour until cloned date == current date
|
|
for (hr = 1 , c = utilDate.add(date, utilDate.HOUR, hr); c.getDate() !== d; hr++ , c = utilDate.add(date, utilDate.HOUR, hr)){}
|
|
date.setDate(d);
|
|
date.setHours(c.getHours());
|
|
}
|
|
return date;
|
|
},
|
|
/**
|
|
* Provides a convenient method for performing basic date arithmetic. This method
|
|
* does not modify the Date instance being called - it creates and returns
|
|
* a new Date instance containing the resulting date value.
|
|
*
|
|
* Examples:
|
|
*
|
|
* // Basic usage:
|
|
* var dt = Ext.Date.add(new Date('10/29/2006'), Ext.Date.DAY, 5);
|
|
* console.log(dt); // returns 'Fri Nov 03 2006 00:00:00'
|
|
*
|
|
* // Negative values will be subtracted:
|
|
* var dt2 = Ext.Date.add(new Date('10/1/2006'), Ext.Date.DAY, -5);
|
|
* console.log(dt2); // returns 'Tue Sep 26 2006 00:00:00'
|
|
*
|
|
* // Decimal values can be used:
|
|
* var dt3 = Ext.Date.add(new Date('10/1/2006'), Ext.Date.DAY, 1.25);
|
|
* console.log(dt3); // returns 'Mon Oct 02 2006 06:00:00'
|
|
*
|
|
* @param {Date} date The date to modify
|
|
* @param {String} interval A valid date interval enum value.
|
|
* @param {Number} value The amount to add to the current date.
|
|
* @return {Date} The new Date instance.
|
|
*/
|
|
add: function(date, interval, value) {
|
|
var d = utilDate.clone(date),
|
|
base = 0,
|
|
day, decimalValue;
|
|
if (!interval || value === 0) {
|
|
return d;
|
|
}
|
|
decimalValue = value - parseInt(value, 10);
|
|
value = parseInt(value, 10);
|
|
if (value) {
|
|
switch (interval.toLowerCase()) {
|
|
// See EXTJSIV-7418. We use setTime() here to deal with issues related to
|
|
// the switchover that occurs when changing to daylight savings and vice
|
|
// versa. setTime() handles this correctly where setHour/Minute/Second/Millisecond
|
|
// do not. Let's assume the DST change occurs at 2am and we're incrementing using add
|
|
// for 15 minutes at time. When entering DST, we should see:
|
|
// 01:30am
|
|
// 01:45am
|
|
// 03:00am // skip 2am because the hour does not exist
|
|
// ...
|
|
// Similarly, leaving DST, we should see:
|
|
// 01:30am
|
|
// 01:45am
|
|
// 01:00am // repeat 1am because that's the change over
|
|
// 01:30am
|
|
// 01:45am
|
|
// 02:00am
|
|
// ....
|
|
//
|
|
case utilDate.MILLI:
|
|
d.setTime(d.getTime() + value);
|
|
break;
|
|
case utilDate.SECOND:
|
|
d.setTime(d.getTime() + value * 1000);
|
|
break;
|
|
case utilDate.MINUTE:
|
|
d.setTime(d.getTime() + value * 60 * 1000);
|
|
break;
|
|
case utilDate.HOUR:
|
|
d.setTime(d.getTime() + value * 60 * 60 * 1000);
|
|
break;
|
|
case utilDate.DAY:
|
|
d.setTime(d.getTime() + value * 24 * 60 * 60 * 1000);
|
|
break;
|
|
case utilDate.MONTH:
|
|
day = date.getDate();
|
|
if (day > 28) {
|
|
day = Math.min(day, utilDate.getLastDateOfMonth(utilDate.add(utilDate.getFirstDateOfMonth(date), utilDate.MONTH, value)).getDate());
|
|
};
|
|
d.setDate(day);
|
|
d.setMonth(date.getMonth() + value);
|
|
break;
|
|
case utilDate.YEAR:
|
|
day = date.getDate();
|
|
if (day > 28) {
|
|
day = Math.min(day, utilDate.getLastDateOfMonth(utilDate.add(utilDate.getFirstDateOfMonth(date), utilDate.YEAR, value)).getDate());
|
|
};
|
|
d.setDate(day);
|
|
d.setFullYear(date.getFullYear() + value);
|
|
break;
|
|
}
|
|
}
|
|
if (decimalValue) {
|
|
switch (interval.toLowerCase()) {
|
|
case utilDate.MILLI:
|
|
base = 1;
|
|
break;
|
|
case utilDate.SECOND:
|
|
base = 1000;
|
|
break;
|
|
case utilDate.MINUTE:
|
|
base = 1000 * 60;
|
|
break;
|
|
case utilDate.HOUR:
|
|
base = 1000 * 60 * 60;
|
|
break;
|
|
case utilDate.DAY:
|
|
base = 1000 * 60 * 60 * 24;
|
|
break;
|
|
case utilDate.MONTH:
|
|
day = utilDate.getDaysInMonth(d);
|
|
base = 1000 * 60 * 60 * 24 * day;
|
|
break;
|
|
case utilDate.YEAR:
|
|
day = (utilDate.isLeapYear(d) ? 366 : 365);
|
|
base = 1000 * 60 * 60 * 24 * day;
|
|
break;
|
|
}
|
|
if (base) {
|
|
d.setTime(d.getTime() + base * decimalValue);
|
|
}
|
|
}
|
|
return d;
|
|
},
|
|
/**
|
|
* Provides a convenient method for performing basic date arithmetic. This method
|
|
* does not modify the Date instance being called - it creates and returns
|
|
* a new Date instance containing the resulting date value.
|
|
*
|
|
* Examples:
|
|
*
|
|
* // Basic usage:
|
|
* var dt = Ext.Date.subtract(new Date('10/29/2006'), Ext.Date.DAY, 5);
|
|
* console.log(dt); // returns 'Tue Oct 24 2006 00:00:00'
|
|
*
|
|
* // Negative values will be added:
|
|
* var dt2 = Ext.Date.subtract(new Date('10/1/2006'), Ext.Date.DAY, -5);
|
|
* console.log(dt2); // returns 'Fri Oct 6 2006 00:00:00'
|
|
*
|
|
* // Decimal values can be used:
|
|
* var dt3 = Ext.Date.subtract(new Date('10/1/2006'), Ext.Date.DAY, 1.25);
|
|
* console.log(dt3); // returns 'Fri Sep 29 2006 06:00:00'
|
|
*
|
|
* @param {Date} date The date to modify
|
|
* @param {String} interval A valid date interval enum value.
|
|
* @param {Number} value The amount to subtract from the current date.
|
|
* @return {Date} The new Date instance.
|
|
*/
|
|
subtract: function(date, interval, value) {
|
|
return utilDate.add(date, interval, -value);
|
|
},
|
|
/**
|
|
* Checks if a date falls on or between the given start and end dates.
|
|
* @param {Date} date The date to check
|
|
* @param {Date} start Start date
|
|
* @param {Date} end End date
|
|
* @return {Boolean} `true` if this date falls on or between the given start and end dates.
|
|
*/
|
|
between: function(date, start, end) {
|
|
var t = date.getTime();
|
|
return start.getTime() <= t && t <= end.getTime();
|
|
},
|
|
/**
|
|
* Checks if the date is a weekend day. Uses {@link #weekendDays}.
|
|
* @param {Date} date The date.
|
|
* @return {Boolean} `true` if the day falls on a weekend.
|
|
*
|
|
* @since 6.2.0
|
|
*/
|
|
isWeekend: function(date) {
|
|
return Ext.Array.indexOf(this.weekendDays, date.getDay()) > -1;
|
|
},
|
|
/**
|
|
* Converts the passed UTC date into a local date.
|
|
* For example, if the passed date is:
|
|
* `Wed Jun 01 2016 00:10:00 GMT+1000 (AUS Eastern Standard Time)`, then
|
|
* the returned date will be `Wed Jun 01 2016 00:00:00 GMT+1000 (AUS Eastern Standard Time)`.
|
|
* @param {Date} d The date to convert.
|
|
* @return {Date} The date as a local. Does not modify the passed date.
|
|
*
|
|
* @since 6.2.0
|
|
*/
|
|
utcToLocal: function(d) {
|
|
return new Date(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate(), d.getUTCHours(), d.getUTCMinutes(), d.getUTCSeconds(), d.getUTCMilliseconds());
|
|
},
|
|
/**
|
|
* Converts the passed local date into a UTC date.
|
|
* For example, if the passed date is:
|
|
* `Wed Jun 01 2016 00:00:00 GMT+1000 (AUS Eastern Standard Time)`, then
|
|
* the returned date will be `Wed Jun 01 2016 10:00:00 GMT+1000 (AUS Eastern Standard Time)`.
|
|
* @param {Date} d The date to convert.
|
|
* @return {Date} The date as UTC. Does not modify the passed date.
|
|
*
|
|
* @since 6.2.0
|
|
*/
|
|
localToUtc: function(d) {
|
|
return utilDate.utc(d.getFullYear(), d.getMonth(), d.getDate(), d.getHours(), d.getMinutes(), d.getSeconds(), d.getMilliseconds());
|
|
},
|
|
/**
|
|
* Create a UTC date.
|
|
* @param {Number} year The year.
|
|
* @param {Number} month The month.
|
|
* @param {Number} day The day.
|
|
* @param {Number} [hour=0] The hour.
|
|
* @param {Number} [min=0] The minutes.
|
|
* @param {Number} [s=0] The seconds.
|
|
* @param {Number} [ms=0] The milliseconds.
|
|
* @return {Date} The UTC date.
|
|
*
|
|
* @since 6.2.0
|
|
*/
|
|
utc: function(year, month, day, hour, min, s, ms) {
|
|
return new Date(Date.UTC(year, month, day, hour || 0, min || 0, s || 0, ms || 0));
|
|
},
|
|
//Maintains compatibility with old static and prototype window.Date methods.
|
|
compat: function() {
|
|
var p,
|
|
statics = [
|
|
'useStrict',
|
|
'formatCodeToRegex',
|
|
'parseFunctions',
|
|
'parseRegexes',
|
|
'formatFunctions',
|
|
'y2kYear',
|
|
'MILLI',
|
|
'SECOND',
|
|
'MINUTE',
|
|
'HOUR',
|
|
'DAY',
|
|
'MONTH',
|
|
'YEAR',
|
|
'defaults',
|
|
'dayNames',
|
|
'monthNames',
|
|
'monthNumbers',
|
|
'getShortMonthName',
|
|
'getShortDayName',
|
|
'getMonthNumber',
|
|
'formatCodes',
|
|
'isValid',
|
|
'parseDate',
|
|
'getFormatCode',
|
|
'createFormat',
|
|
'createParser',
|
|
'parseCodes'
|
|
],
|
|
proto = [
|
|
'dateFormat',
|
|
'format',
|
|
'getTimezone',
|
|
'getGMTOffset',
|
|
'getDayOfYear',
|
|
'getWeekOfYear',
|
|
'isLeapYear',
|
|
'getFirstDayOfMonth',
|
|
'getLastDayOfMonth',
|
|
'getDaysInMonth',
|
|
'getSuffix',
|
|
'clone',
|
|
'isDST',
|
|
'clearTime',
|
|
'add',
|
|
'between'
|
|
],
|
|
sLen = statics.length,
|
|
pLen = proto.length,
|
|
stat, prot, s;
|
|
//Append statics
|
|
for (s = 0; s < sLen; s++) {
|
|
stat = statics[s];
|
|
nativeDate[stat] = utilDate[stat];
|
|
}
|
|
//Append to prototype
|
|
for (p = 0; p < pLen; p++) {
|
|
prot = proto[p];
|
|
nativeDate.prototype[prot] = function() {
|
|
var args = Array.prototype.slice.call(arguments);
|
|
args.unshift(this);
|
|
return utilDate[prot].apply(utilDate, args);
|
|
};
|
|
}
|
|
},
|
|
/**
|
|
* Calculate how many units are there between two time.
|
|
* @param {Date} min The first time.
|
|
* @param {Date} max The second time.
|
|
* @param {String} unit The unit. This unit is compatible with the date interval constants.
|
|
* @return {Number} The maximum number n of units that min + n * unit <= max.
|
|
*/
|
|
diff: function(min, max, unit) {
|
|
var est,
|
|
diff = +max - min;
|
|
switch (unit) {
|
|
case utilDate.MILLI:
|
|
return diff;
|
|
case utilDate.SECOND:
|
|
return Math.floor(diff / 1000);
|
|
case utilDate.MINUTE:
|
|
return Math.floor(diff / 60000);
|
|
case utilDate.HOUR:
|
|
return Math.floor(diff / 3600000);
|
|
case utilDate.DAY:
|
|
return Math.floor(diff / 86400000);
|
|
case 'w':
|
|
return Math.floor(diff / 604800000);
|
|
case utilDate.MONTH:
|
|
est = (max.getFullYear() * 12 + max.getMonth()) - (min.getFullYear() * 12 + min.getMonth());
|
|
if (utilDate.add(min, unit, est) > max) {
|
|
return est - 1;
|
|
};
|
|
return est;
|
|
case utilDate.YEAR:
|
|
est = max.getFullYear() - min.getFullYear();
|
|
if (utilDate.add(min, unit, est) > max) {
|
|
return est - 1;
|
|
} else {
|
|
return est;
|
|
};
|
|
}
|
|
},
|
|
/**
|
|
* Align the date to `unit`.
|
|
* @param {Date} date The date to be aligned.
|
|
* @param {String} unit The unit. This unit is compatible with the date interval constants.
|
|
* @param {Number} step
|
|
* @return {Date} The aligned date.
|
|
*/
|
|
align: function(date, unit, step) {
|
|
var num = new nativeDate(+date);
|
|
switch (unit.toLowerCase()) {
|
|
case utilDate.MILLI:
|
|
return num;
|
|
case utilDate.SECOND:
|
|
num.setUTCSeconds(num.getUTCSeconds() - num.getUTCSeconds() % step);
|
|
num.setUTCMilliseconds(0);
|
|
return num;
|
|
case utilDate.MINUTE:
|
|
num.setUTCMinutes(num.getUTCMinutes() - num.getUTCMinutes() % step);
|
|
num.setUTCSeconds(0);
|
|
num.setUTCMilliseconds(0);
|
|
return num;
|
|
case utilDate.HOUR:
|
|
num.setUTCHours(num.getUTCHours() - num.getUTCHours() % step);
|
|
num.setUTCMinutes(0);
|
|
num.setUTCSeconds(0);
|
|
num.setUTCMilliseconds(0);
|
|
return num;
|
|
case utilDate.DAY:
|
|
if (step === 7 || step === 14) {
|
|
num.setUTCDate(num.getUTCDate() - num.getUTCDay() + 1);
|
|
};
|
|
num.setUTCHours(0);
|
|
num.setUTCMinutes(0);
|
|
num.setUTCSeconds(0);
|
|
num.setUTCMilliseconds(0);
|
|
return num;
|
|
case utilDate.MONTH:
|
|
num.setUTCMonth(num.getUTCMonth() - (num.getUTCMonth() - 1) % step, 1);
|
|
num.setUTCHours(0);
|
|
num.setUTCMinutes(0);
|
|
num.setUTCSeconds(0);
|
|
num.setUTCMilliseconds(0);
|
|
return num;
|
|
case utilDate.YEAR:
|
|
num.setUTCFullYear(num.getUTCFullYear() - num.getUTCFullYear() % step, 1, 1);
|
|
num.setUTCHours(0);
|
|
num.setUTCMinutes(0);
|
|
num.setUTCSeconds(0);
|
|
num.setUTCMilliseconds(0);
|
|
return date;
|
|
}
|
|
}
|
|
};
|
|
utilDate.parseCodes.C = utilDate.parseCodes.c;
|
|
return utilDate;
|
|
}());
|
|
|
|
/**
|
|
* @class Ext.Function
|
|
*
|
|
* A collection of useful static methods to deal with function callbacks.
|
|
* @singleton
|
|
*/
|
|
Ext.Function = (function() {
|
|
// @define Ext.lang.Function
|
|
// @define Ext.Function
|
|
// @require Ext
|
|
// @require Ext.lang.Array
|
|
var lastTime = 0,
|
|
animFrameId,
|
|
animFrameHandlers = [],
|
|
animFrameNoArgs = [],
|
|
idSource = 0,
|
|
animFrameMap = {},
|
|
win = window,
|
|
global = Ext.global,
|
|
hasImmediate = !!(global.setImmediate && global.clearImmediate),
|
|
requestAnimFrame = win.requestAnimationFrame || win.webkitRequestAnimationFrame || win.mozRequestAnimationFrame || win.oRequestAnimationFrame || function(callback) {
|
|
var currTime = Ext.now(),
|
|
timeToCall = Math.max(0, 16 - (currTime - lastTime)),
|
|
id = win.setTimeout(function() {
|
|
callback(currTime + timeToCall);
|
|
}, timeToCall);
|
|
lastTime = currTime + timeToCall;
|
|
return id;
|
|
},
|
|
fireHandlers = function() {
|
|
var len = animFrameHandlers.length,
|
|
id, i, handler;
|
|
animFrameId = null;
|
|
// Fire all animation frame handlers in one go
|
|
for (i = 0; i < len; i++) {
|
|
handler = animFrameHandlers[i];
|
|
id = handler[3];
|
|
// Check if this timer has been canceled; its map entry is going to be removed
|
|
if (animFrameMap[id]) {
|
|
handler[0].apply(handler[1] || global, handler[2] || animFrameNoArgs);
|
|
delete animFrameMap[id];
|
|
}
|
|
}
|
|
// Clear all fired animation frame handlers, don't forget that new handlers
|
|
// could have been created in user handler functions called in the loop above
|
|
animFrameHandlers = animFrameHandlers.slice(len);
|
|
},
|
|
fireElevatedHandlers = function() {
|
|
Ext.elevateFunction(fireHandlers);
|
|
},
|
|
ExtFunction = {
|
|
/**
|
|
* A very commonly used method throughout the framework. It acts as a wrapper around another method
|
|
* which originally accepts 2 arguments for `name` and `value`.
|
|
* The wrapped function then allows "flexible" value setting of either:
|
|
*
|
|
* - `name` and `value` as 2 arguments
|
|
* - one single object argument with multiple key - value pairs
|
|
*
|
|
* For example:
|
|
*
|
|
* var setValue = Ext.Function.flexSetter(function(name, value) {
|
|
* this[name] = value;
|
|
* });
|
|
*
|
|
* // Afterwards
|
|
* // Setting a single name - value
|
|
* setValue('name1', 'value1');
|
|
*
|
|
* // Settings multiple name - value pairs
|
|
* setValue({
|
|
* name1: 'value1',
|
|
* name2: 'value2',
|
|
* name3: 'value3'
|
|
* });
|
|
*
|
|
* @param {Function} setter The single value setter method.
|
|
* @param {String} setter.name The name of the value being set.
|
|
* @param {Object} setter.value The value being set.
|
|
* @return {Function}
|
|
*/
|
|
flexSetter: function(setter) {
|
|
return function(name, value) {
|
|
var k, i;
|
|
if (name !== null) {
|
|
if (typeof name !== 'string') {
|
|
for (k in name) {
|
|
if (name.hasOwnProperty(k)) {
|
|
setter.call(this, k, name[k]);
|
|
}
|
|
}
|
|
if (Ext.enumerables) {
|
|
for (i = Ext.enumerables.length; i--; ) {
|
|
k = Ext.enumerables[i];
|
|
if (name.hasOwnProperty(k)) {
|
|
setter.call(this, k, name[k]);
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
setter.call(this, name, value);
|
|
}
|
|
}
|
|
return this;
|
|
};
|
|
},
|
|
/**
|
|
* Create a new function from the provided `fn`, change `this` to the provided scope,
|
|
* optionally overrides arguments for the call. Defaults to the arguments passed by
|
|
* the caller.
|
|
*
|
|
* {@link Ext#bind Ext.bind} is alias for {@link Ext.Function#bind Ext.Function.bind}
|
|
*
|
|
* **NOTE:** This method is deprecated. Use the standard `bind` method of JavaScript
|
|
* `Function` instead:
|
|
*
|
|
* function foo () {
|
|
* ...
|
|
* }
|
|
*
|
|
* var fn = foo.bind(this);
|
|
*
|
|
* This method is unavailable natively on IE8 and IE/Quirks but Ext JS provides a
|
|
* "polyfill" to emulate the important features of the standard `bind` method. In
|
|
* particular, the polyfill only provides binding of "this" and optional arguments.
|
|
*
|
|
* @param {Function} fn The function to delegate.
|
|
* @param {Object} scope (optional) The scope (`this` reference) in which the function is executed.
|
|
* **If omitted, defaults to the default global environment object (usually the browser window).**
|
|
* @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
|
|
* @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
|
|
* if a number the args are inserted at the specified position.
|
|
* @return {Function} The new function.
|
|
*/
|
|
bind: function(fn, scope, args, appendArgs) {
|
|
if (arguments.length === 2) {
|
|
return function() {
|
|
return fn.apply(scope, arguments);
|
|
};
|
|
}
|
|
var method = fn,
|
|
slice = Array.prototype.slice;
|
|
return function() {
|
|
var callArgs = args || arguments;
|
|
if (appendArgs === true) {
|
|
callArgs = slice.call(arguments, 0);
|
|
callArgs = callArgs.concat(args);
|
|
} else if (typeof appendArgs === 'number') {
|
|
callArgs = slice.call(arguments, 0);
|
|
// copy arguments first
|
|
Ext.Array.insert(callArgs, appendArgs, args);
|
|
}
|
|
return method.apply(scope || global, callArgs);
|
|
};
|
|
},
|
|
/**
|
|
* Captures the given parameters for a later call to `Ext.callback`. This binding is
|
|
* most useful for resolving scopes for example to an `Ext.app.ViewController`.
|
|
*
|
|
* The arguments match that of `Ext.callback` except for the `args` which, if provided
|
|
* to this method, are prepended to any arguments supplied by the eventual caller of
|
|
* the returned function.
|
|
*
|
|
* @return {Function} A function that, when called, uses `Ext.callback` to call the
|
|
* captured `callback`.
|
|
* @since 5.0.0
|
|
*/
|
|
bindCallback: function(callback, scope, args, delay, caller) {
|
|
return function() {
|
|
var a = Ext.Array.slice(arguments);
|
|
return Ext.callback(callback, scope, args ? args.concat(a) : a, delay, caller);
|
|
};
|
|
},
|
|
/**
|
|
* Create a new function from the provided `fn`, the arguments of which are pre-set to `args`.
|
|
* New arguments passed to the newly created callback when it's invoked are appended after the pre-set ones.
|
|
* This is especially useful when creating callbacks.
|
|
*
|
|
* For example:
|
|
*
|
|
* var originalFunction = function(){
|
|
* alert(Ext.Array.from(arguments).join(' '));
|
|
* };
|
|
*
|
|
* var callback = Ext.Function.pass(originalFunction, ['Hello', 'World']);
|
|
*
|
|
* callback(); // alerts 'Hello World'
|
|
* callback('by Me'); // alerts 'Hello World by Me'
|
|
*
|
|
* {@link Ext#pass Ext.pass} is alias for {@link Ext.Function#pass Ext.Function.pass}
|
|
*
|
|
* @param {Function} fn The original function.
|
|
* @param {Array} args The arguments to pass to new callback.
|
|
* @param {Object} scope (optional) The scope (`this` reference) in which the function is executed.
|
|
* @return {Function} The new callback function.
|
|
*/
|
|
pass: function(fn, args, scope) {
|
|
if (!Ext.isArray(args)) {
|
|
if (Ext.isIterable(args)) {
|
|
args = Ext.Array.clone(args);
|
|
} else {
|
|
args = args !== undefined ? [
|
|
args
|
|
] : [];
|
|
}
|
|
}
|
|
return function() {
|
|
var fnArgs = args.slice();
|
|
fnArgs.push.apply(fnArgs, arguments);
|
|
return fn.apply(scope || this, fnArgs);
|
|
};
|
|
},
|
|
/**
|
|
* Create an alias to the provided method property with name `methodName` of `object`.
|
|
* Note that the execution scope will still be bound to the provided `object` itself.
|
|
*
|
|
* @param {Object/Function} object
|
|
* @param {String} methodName
|
|
* @return {Function} aliasFn
|
|
*/
|
|
alias: function(object, methodName) {
|
|
return function() {
|
|
return object[methodName].apply(object, arguments);
|
|
};
|
|
},
|
|
/**
|
|
* Create a "clone" of the provided method. The returned method will call the given
|
|
* method passing along all arguments and the "this" pointer and return its result.
|
|
*
|
|
* @param {Function} method
|
|
* @return {Function} cloneFn
|
|
*/
|
|
clone: function(method) {
|
|
return function() {
|
|
return method.apply(this, arguments);
|
|
};
|
|
},
|
|
/**
|
|
* Creates an interceptor function. The passed function is called before the original one. If it returns false,
|
|
* the original one is not called. The resulting function returns the results of the original function.
|
|
* The passed function is called with the parameters of the original function. Example usage:
|
|
*
|
|
* var sayHi = function(name){
|
|
* alert('Hi, ' + name);
|
|
* };
|
|
*
|
|
* sayHi('Fred'); // alerts "Hi, Fred"
|
|
*
|
|
* // create a new function that validates input without
|
|
* // directly modifying the original function:
|
|
* var sayHiToFriend = Ext.Function.createInterceptor(sayHi, function(name){
|
|
* return name === 'Brian';
|
|
* });
|
|
*
|
|
* sayHiToFriend('Fred'); // no alert
|
|
* sayHiToFriend('Brian'); // alerts "Hi, Brian"
|
|
*
|
|
* @param {Function} origFn The original function.
|
|
* @param {Function} newFn The function to call before the original.
|
|
* @param {Object} [scope] The scope (`this` reference) in which the passed function is executed.
|
|
* **If omitted, defaults to the scope in which the original function is called or the browser window.**
|
|
* @param {Object} [returnValue=null] The value to return if the passed function return `false`.
|
|
* @return {Function} The new function.
|
|
*/
|
|
createInterceptor: function(origFn, newFn, scope, returnValue) {
|
|
if (!Ext.isFunction(newFn)) {
|
|
return origFn;
|
|
} else {
|
|
returnValue = Ext.isDefined(returnValue) ? returnValue : null;
|
|
return function() {
|
|
var me = this,
|
|
args = arguments;
|
|
return (newFn.apply(scope || me || global, args) !== false) ? origFn.apply(me || global, args) : returnValue;
|
|
};
|
|
}
|
|
},
|
|
/**
|
|
* Creates a delegate (callback) which, when called, executes after a specific delay.
|
|
*
|
|
* @param {Function} fn The function which will be called on a delay when the returned function is called.
|
|
* Optionally, a replacement (or additional) argument list may be specified.
|
|
* @param {Number} delay The number of milliseconds to defer execution by whenever called.
|
|
* @param {Object} scope (optional) The scope (`this` reference) used by the function at execution time.
|
|
* @param {Array} args (optional) Override arguments for the call. (Defaults to the arguments passed by the caller)
|
|
* @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
|
|
* if a number the args are inserted at the specified position.
|
|
* @return {Function} A function which, when called, executes the original function after the specified delay.
|
|
*/
|
|
createDelayed: function(fn, delay, scope, args, appendArgs) {
|
|
if (scope || args) {
|
|
fn = Ext.Function.bind(fn, scope, args, appendArgs);
|
|
}
|
|
return function() {
|
|
var me = this,
|
|
args = Array.prototype.slice.call(arguments);
|
|
setTimeout(function() {
|
|
if (Ext.elevateFunction) {
|
|
Ext.elevateFunction(fn, me, args);
|
|
} else {
|
|
fn.apply(me, args);
|
|
}
|
|
}, delay);
|
|
};
|
|
},
|
|
/**
|
|
* Calls this function after the number of milliseconds specified, optionally in a specific scope. Example usage:
|
|
*
|
|
* var sayHi = function(name){
|
|
* alert('Hi, ' + name);
|
|
* }
|
|
*
|
|
* // executes immediately:
|
|
* sayHi('Fred');
|
|
*
|
|
* // executes after 2 seconds:
|
|
* Ext.Function.defer(sayHi, 2000, this, ['Fred']);
|
|
*
|
|
* // this syntax is sometimes useful for deferring
|
|
* // execution of an anonymous function:
|
|
* Ext.Function.defer(function(){
|
|
* alert('Anonymous');
|
|
* }, 100);
|
|
*
|
|
* {@link Ext#defer Ext.defer} is alias for {@link Ext.Function#defer Ext.Function.defer}
|
|
*
|
|
* @param {Function} fn The function to defer.
|
|
* @param {Number} millis The number of milliseconds for the `setTimeout` call
|
|
* (if less than or equal to 0 the function is executed immediately).
|
|
* @param {Object} scope (optional) The scope (`this` reference) in which the function is executed.
|
|
* **If omitted, defaults to the browser window.**
|
|
* @param {Array} [args] Overrides arguments for the call. Defaults to the arguments passed by the caller.
|
|
* @param {Boolean/Number} [appendArgs=false] If `true` args are appended to call args instead of overriding,
|
|
* or, if a number, then the args are inserted at the specified position.
|
|
* @return {Number} The timeout id that can be used with `clearTimeout`.
|
|
*/
|
|
defer: function(fn, millis, scope, args, appendArgs) {
|
|
fn = Ext.Function.bind(fn, scope, args, appendArgs);
|
|
if (millis > 0) {
|
|
return setTimeout(function() {
|
|
if (Ext.elevateFunction) {
|
|
Ext.elevateFunction(fn);
|
|
} else {
|
|
fn();
|
|
}
|
|
}, millis);
|
|
}
|
|
fn();
|
|
return 0;
|
|
},
|
|
/**
|
|
* Calls this function repeatedly at a given interval, optionally in a specific scope.
|
|
*
|
|
* {@link Ext#defer Ext.defer} is alias for {@link Ext.Function#defer Ext.Function.defer}
|
|
*
|
|
* @param {Function} fn The function to defer.
|
|
* @param {Number} millis The number of milliseconds for the `setInterval` call
|
|
* @param {Object} scope (optional) The scope (`this` reference) in which the function is executed.
|
|
* **If omitted, defaults to the browser window.**
|
|
* @param {Array} [args] Overrides arguments for the call. Defaults to the arguments passed by the caller.
|
|
* @param {Boolean/Number} [appendArgs=false] If `true` args are appended to call args instead of overriding,
|
|
* or, if a number, then the args are inserted at the specified position.
|
|
* @return {Number} The interval id that can be used with `clearInterval`.
|
|
*/
|
|
interval: function(fn, millis, scope, args, appendArgs) {
|
|
fn = Ext.Function.bind(fn, scope, args, appendArgs);
|
|
return setInterval(function() {
|
|
if (Ext.elevateFunction) {
|
|
Ext.elevateFunction(fn);
|
|
} else {
|
|
fn();
|
|
}
|
|
}, millis);
|
|
},
|
|
/**
|
|
* Create a combined function call sequence of the original function + the passed function.
|
|
* The resulting function returns the results of the original function.
|
|
* The passed function is called with the parameters of the original function. Example usage:
|
|
*
|
|
* var sayHi = function(name){
|
|
* alert('Hi, ' + name);
|
|
* };
|
|
*
|
|
* sayHi('Fred'); // alerts "Hi, Fred"
|
|
*
|
|
* var sayGoodbye = Ext.Function.createSequence(sayHi, function(name){
|
|
* alert('Bye, ' + name);
|
|
* });
|
|
*
|
|
* sayGoodbye('Fred'); // both alerts show
|
|
*
|
|
* @param {Function} originalFn The original function.
|
|
* @param {Function} newFn The function to sequence.
|
|
* @param {Object} [scope] The scope (`this` reference) in which the passed function is executed.
|
|
* If omitted, defaults to the scope in which the original function is called or the
|
|
* default global environment object (usually the browser window).
|
|
* @return {Function} The new function.
|
|
*/
|
|
createSequence: function(originalFn, newFn, scope) {
|
|
if (!newFn) {
|
|
return originalFn;
|
|
} else {
|
|
return function() {
|
|
var result = originalFn.apply(this, arguments);
|
|
newFn.apply(scope || this, arguments);
|
|
return result;
|
|
};
|
|
}
|
|
},
|
|
/**
|
|
* Creates a delegate function, optionally with a bound scope which, when called, buffers
|
|
* the execution of the passed function for the configured number of milliseconds.
|
|
* If called again within that period, the impending invocation will be canceled, and the
|
|
* timeout period will begin again.
|
|
*
|
|
* @param {Function} fn The function to invoke on a buffered timer.
|
|
* @param {Number} buffer The number of milliseconds by which to buffer the invocation of the
|
|
* function.
|
|
* @param {Object} [scope] The scope (`this` reference) in which.
|
|
* the passed function is executed. If omitted, defaults to the scope specified by the caller.
|
|
* @param {Array} [args] Override arguments for the call. Defaults to the arguments
|
|
* passed by the caller.
|
|
* @return {Function} A function which invokes the passed function after buffering for the specified time.
|
|
*/
|
|
createBuffered: function(fn, buffer, scope, args) {
|
|
var timerId;
|
|
return function() {
|
|
var callArgs = args || Array.prototype.slice.call(arguments, 0),
|
|
me = scope || this;
|
|
if (timerId) {
|
|
clearTimeout(timerId);
|
|
}
|
|
timerId = setTimeout(function() {
|
|
if (Ext.elevateFunction) {
|
|
Ext.elevateFunction(fn, me, callArgs);
|
|
} else {
|
|
fn.apply(me, callArgs);
|
|
}
|
|
}, buffer);
|
|
};
|
|
},
|
|
/**
|
|
* Creates a wrapped function that, when invoked, defers execution until the next
|
|
* animation frame
|
|
* @private
|
|
* @param {Function} fn The function to call.
|
|
* @param {Object} [scope] The scope (`this` reference) in which the function is executed. Defaults to the window object.
|
|
* @param {Array} [args] The argument list to pass to the function.
|
|
* @param {Number} [queueStrategy=3] A bit flag that indicates how multiple calls to
|
|
* the returned function within the same animation frame should be handled.
|
|
*
|
|
* - 1: All calls will be queued - FIFO order
|
|
* - 2: Only the first call will be queued
|
|
* - 3: The last call will replace all previous calls
|
|
*
|
|
* @return {Function}
|
|
*/
|
|
createAnimationFrame: function(fn, scope, args, queueStrategy) {
|
|
var timerId;
|
|
queueStrategy = queueStrategy || 3;
|
|
return function() {
|
|
var callArgs = args || Array.prototype.slice.call(arguments, 0);
|
|
scope = scope || this;
|
|
if (queueStrategy === 3 && timerId) {
|
|
ExtFunction.cancelAnimationFrame(timerId);
|
|
}
|
|
if ((queueStrategy & 1) || !timerId) {
|
|
timerId = ExtFunction.requestAnimationFrame(function() {
|
|
timerId = null;
|
|
fn.apply(scope, callArgs);
|
|
});
|
|
}
|
|
};
|
|
},
|
|
/**
|
|
* @private
|
|
* Schedules the passed function to be called on the next animation frame.
|
|
* @param {Function} fn The function to call.
|
|
* @param {Object} [scope] The scope (`this` reference) in which the function is executed. Defaults to the window object.
|
|
* @param {Mixed[]} [args] The argument list to pass to the function.
|
|
*
|
|
* @return {Number} Timer id for the new animation frame to use when canceling it.
|
|
*/
|
|
requestAnimationFrame: function(fn, scope, args) {
|
|
var id = ++idSource,
|
|
// Ids start at 1
|
|
handler = Array.prototype.slice.call(arguments, 0);
|
|
handler[3] = id;
|
|
animFrameMap[id] = 1;
|
|
// A flag to indicate that the timer exists
|
|
// We might be in fireHandlers at this moment but this new entry will not
|
|
// be executed until the next frame
|
|
animFrameHandlers.push(handler);
|
|
if (!animFrameId) {
|
|
animFrameId = requestAnimFrame(Ext.elevateFunction ? fireElevatedHandlers : fireHandlers);
|
|
}
|
|
return id;
|
|
},
|
|
cancelAnimationFrame: function(id) {
|
|
// Don't remove any handlers from animFrameHandlers array, because
|
|
// the might be in use at the moment (when cancelAnimationFrame is called).
|
|
// Just remove the handler id from the map so it will not be executed
|
|
delete animFrameMap[id];
|
|
},
|
|
/**
|
|
* Creates a throttled version of the passed function which, when called repeatedly and
|
|
* rapidly, invokes the passed function only after a certain interval has elapsed since the
|
|
* previous invocation.
|
|
*
|
|
* This is useful for wrapping functions which may be called repeatedly, such as
|
|
* a handler of a mouse move event when the processing is expensive.
|
|
*
|
|
* @param {Function} fn The function to execute at a regular time interval.
|
|
* @param {Number} interval The interval in milliseconds on which the passed function is executed.
|
|
* @param {Object} [scope] The scope (`this` reference) in which
|
|
* the passed function is executed. If omitted, defaults to the scope specified by the caller.
|
|
* @return {Function} A function which invokes the passed function at the specified interval.
|
|
*/
|
|
createThrottled: function(fn, interval, scope) {
|
|
var lastCallTime = 0,
|
|
elapsed, lastArgs, timer,
|
|
execute = function() {
|
|
if (Ext.elevateFunction) {
|
|
Ext.elevateFunction(fn, scope, lastArgs);
|
|
} else {
|
|
fn.apply(scope, lastArgs);
|
|
}
|
|
lastCallTime = Ext.now();
|
|
timer = null;
|
|
};
|
|
return function() {
|
|
// Use scope of last call unless the creator specified a scope
|
|
if (!scope) {
|
|
scope = this;
|
|
}
|
|
elapsed = Ext.now() - lastCallTime;
|
|
lastArgs = arguments;
|
|
// If this is the first invocation, or the throttle interval has been reached, clear any
|
|
// pending invocation, and call the target function now.
|
|
if (elapsed >= interval) {
|
|
clearTimeout(timer);
|
|
execute();
|
|
}
|
|
// Throttle interval has not yet been reached. Only set the timer to fire if not already set.
|
|
else if (!timer) {
|
|
timer = Ext.defer(execute, interval - elapsed);
|
|
}
|
|
};
|
|
},
|
|
/**
|
|
* Wraps the passed function in a barrier function which will call the passed function after the passed number of invocations.
|
|
* @param {Number} count The number of invocations which will result in the calling of the passed function.
|
|
* @param {Function} fn The function to call after the required number of invocations.
|
|
* @param {Object} scope The scope (`this` reference) in which the function will be called.
|
|
*/
|
|
createBarrier: function(count, fn, scope) {
|
|
return function() {
|
|
if (!--count) {
|
|
fn.apply(scope, arguments);
|
|
}
|
|
};
|
|
},
|
|
/**
|
|
* Adds behavior to an existing method that is executed before the
|
|
* original behavior of the function. For example:
|
|
*
|
|
* var soup = {
|
|
* contents: [],
|
|
* add: function(ingredient) {
|
|
* this.contents.push(ingredient);
|
|
* }
|
|
* };
|
|
* Ext.Function.interceptBefore(soup, "add", function(ingredient){
|
|
* if (!this.contents.length && ingredient !== "water") {
|
|
* // Always add water to start with
|
|
* this.contents.push("water");
|
|
* }
|
|
* });
|
|
* soup.add("onions");
|
|
* soup.add("salt");
|
|
* soup.contents; // will contain: water, onions, salt
|
|
*
|
|
* @param {Object} object The target object
|
|
* @param {String} methodName Name of the method to override
|
|
* @param {Function} fn Function with the new behavior. It will
|
|
* be called with the same arguments as the original method. The
|
|
* return value of this function will be the return value of the
|
|
* new method.
|
|
* @param {Object} [scope] The scope to execute the interceptor function. Defaults to the object.
|
|
* @return {Function} The new function just created.
|
|
*/
|
|
interceptBefore: function(object, methodName, fn, scope) {
|
|
var method = object[methodName] || Ext.emptyFn;
|
|
return (object[methodName] = function() {
|
|
var ret = fn.apply(scope || this, arguments);
|
|
method.apply(this, arguments);
|
|
return ret;
|
|
});
|
|
},
|
|
/**
|
|
* Adds behavior to an existing method that is executed after the
|
|
* original behavior of the function. For example:
|
|
*
|
|
* var soup = {
|
|
* contents: [],
|
|
* add: function(ingredient) {
|
|
* this.contents.push(ingredient);
|
|
* }
|
|
* };
|
|
* Ext.Function.interceptAfter(soup, "add", function(ingredient){
|
|
* // Always add a bit of extra salt
|
|
* this.contents.push("salt");
|
|
* });
|
|
* soup.add("water");
|
|
* soup.add("onions");
|
|
* soup.contents; // will contain: water, salt, onions, salt
|
|
*
|
|
* @param {Object} object The target object
|
|
* @param {String} methodName Name of the method to override
|
|
* @param {Function} fn Function with the new behavior. It will
|
|
* be called with the same arguments as the original method. The
|
|
* return value of this function will be the return value of the
|
|
* new method.
|
|
* @param {Object} [scope] The scope to execute the interceptor function. Defaults to the object.
|
|
* @return {Function} The new function just created.
|
|
*/
|
|
interceptAfter: function(object, methodName, fn, scope) {
|
|
var method = object[methodName] || Ext.emptyFn;
|
|
return (object[methodName] = function() {
|
|
method.apply(this, arguments);
|
|
return fn.apply(scope || this, arguments);
|
|
});
|
|
},
|
|
interceptAfterOnce: function(object, methodName, fn, scope) {
|
|
var origMethod = object[methodName],
|
|
newMethod;
|
|
newMethod = function() {
|
|
var ret;
|
|
if (origMethod) {
|
|
origMethod.apply(this, arguments);
|
|
}
|
|
ret = fn.apply(scope || this, arguments);
|
|
object[methodName] = origMethod;
|
|
object = methodName = fn = scope = origMethod = newMethod = null;
|
|
return ret;
|
|
};
|
|
object[methodName] = newMethod;
|
|
return newMethod;
|
|
},
|
|
makeCallback: function(callback, scope) {
|
|
if (!scope[callback]) {
|
|
if (scope.$className) {
|
|
Ext.raise('No method "' + callback + '" on ' + scope.$className);
|
|
}
|
|
Ext.raise('No method "' + callback + '"');
|
|
}
|
|
return function() {
|
|
return scope[callback].apply(scope, arguments);
|
|
};
|
|
},
|
|
/**
|
|
* Returns a wrapper function that caches the return value for previously
|
|
* processed function argument(s).
|
|
*
|
|
* For example:
|
|
*
|
|
* function factorial (value) {
|
|
* var ret = value;
|
|
*
|
|
* while (--value > 1) {
|
|
* ret *= value;
|
|
* }
|
|
*
|
|
* return ret;
|
|
* }
|
|
*
|
|
* Each call to `factorial` will loop and multiply to produce the answer. Using
|
|
* this function we can wrap the above and cache its answers:
|
|
*
|
|
* factorial = Ext.Function.memoize(factorial);
|
|
*
|
|
* The returned function operates in the same manner as before, but results are
|
|
* stored in a cache to avoid calling the wrapped function when given the same
|
|
* arguments.
|
|
*
|
|
* var x = factorial(20); // first time; call real factorial()
|
|
* var y = factorial(20); // second time; return value from first call
|
|
*
|
|
* To support multi-argument methods, you will need to provide a `hashFn`.
|
|
*
|
|
* function permutation (n, k) {
|
|
* return factorial(n) / factorial(n - k);
|
|
* }
|
|
*
|
|
* permutation = Ext.Function.memoize(permutation, null, function (n, k) {
|
|
* n + '-' + k;
|
|
* });
|
|
*
|
|
* In this case, the `memoize` of `factorial` is sufficient optimization, but the
|
|
* example is simply to illustrate how to generate a unique key for an expensive,
|
|
* multi-argument method.
|
|
*
|
|
* **IMPORTANT**: This cache is unbounded so be cautious of memory leaks if the
|
|
* `memoize`d function is kept indefinitely or is given an unbounded set of
|
|
* possible arguments.
|
|
*
|
|
* @param {Function} fn Function to wrap.
|
|
* @param {Object} scope Optional scope in which to execute the wrapped function.
|
|
* @param {Function} hashFn Optional function used to compute a hash key for
|
|
* storing the result, based on the arguments to the original function.
|
|
* @return {Function} The caching wrapper function.
|
|
* @since 6.0.0
|
|
*/
|
|
memoize: function(fn, scope, hashFn) {
|
|
var memo = {},
|
|
isFunc = hashFn && Ext.isFunction(hashFn);
|
|
return function(value) {
|
|
var key = isFunc ? hashFn.apply(scope, arguments) : value;
|
|
if (!(key in memo)) {
|
|
memo[key] = fn.apply(scope, arguments);
|
|
}
|
|
return memo[key];
|
|
};
|
|
}
|
|
};
|
|
// ExtFunction
|
|
/**
|
|
* @member Ext
|
|
* @method asap
|
|
* Schedules the specified callback function to be executed on the next turn of the
|
|
* event loop. Where available, this method uses the browser's `setImmediate` API. If
|
|
* not available, this method substitutes `setTimeout(0)`. Though not a perfect
|
|
* replacement for `setImmediate` it is sufficient for many use cases.
|
|
*
|
|
* For more details see [MDN](https://developer.mozilla.org/en-US/docs/Web/API/Window/setImmediate).
|
|
*
|
|
* @param {Function} fn Callback function.
|
|
* @param {Object} [scope] The scope for the callback (`this` pointer).
|
|
* @param {Mixed[]} [parameters] Additional parameters to pass to `fn`.
|
|
* @return {Number} A cancelation id for `{@link Ext#asapCancel}`.
|
|
*/
|
|
Ext.asap = hasImmediate ? function(fn, scope, parameters) {
|
|
if (scope != null || parameters != null) {
|
|
fn = ExtFunction.bind(fn, scope, parameters);
|
|
}
|
|
return setImmediate(function() {
|
|
if (Ext.elevateFunction) {
|
|
Ext.elevateFunction(fn);
|
|
} else {
|
|
fn();
|
|
}
|
|
});
|
|
} : function(fn, scope, parameters) {
|
|
if (scope != null || parameters != null) {
|
|
fn = ExtFunction.bind(fn, scope, parameters);
|
|
}
|
|
return setTimeout(function() {
|
|
if (Ext.elevateFunction) {
|
|
Ext.elevateFunction(fn);
|
|
} else {
|
|
fn();
|
|
}
|
|
}, 0, true);
|
|
} , /**
|
|
* @member Ext
|
|
* @method asapCancel
|
|
* Cancels a previously scheduled call to `{@link Ext#asap}`.
|
|
*
|
|
* var asapId = Ext.asap(me.method, me);
|
|
* ...
|
|
*
|
|
* if (nevermind) {
|
|
* Ext.apasCancel(asapId);
|
|
* }
|
|
*
|
|
* @param {Number} id The id returned by `{@link Ext#asap}`.
|
|
*/
|
|
Ext.asapCancel = hasImmediate ? function(id) {
|
|
clearImmediate(id);
|
|
} : function(id) {
|
|
clearTimeout(id);
|
|
};
|
|
/**
|
|
* @method defer
|
|
* @member Ext
|
|
* @inheritdoc Ext.Function#defer
|
|
*/
|
|
Ext.defer = ExtFunction.defer;
|
|
/**
|
|
* @method interval
|
|
* @member Ext
|
|
* @inheritdoc Ext.Function#interval
|
|
*/
|
|
Ext.interval = ExtFunction.interval;
|
|
/**
|
|
* @method pass
|
|
* @member Ext
|
|
* @inheritdoc Ext.Function#pass
|
|
*/
|
|
Ext.pass = ExtFunction.pass;
|
|
/**
|
|
* @method bind
|
|
* @member Ext
|
|
* @inheritdoc Ext.Function#bind
|
|
*/
|
|
Ext.bind = ExtFunction.bind;
|
|
Ext.deferCallback = ExtFunction.requestAnimationFrame;
|
|
return ExtFunction;
|
|
})();
|
|
|
|
/**
|
|
* @class Ext.Number
|
|
*
|
|
* A collection of useful static methods to deal with numbers
|
|
* @singleton
|
|
*/
|
|
Ext.Number = (new function() {
|
|
// jshint ignore:line
|
|
// @define Ext.lang.Number
|
|
// @define Ext.Number
|
|
// @require Ext
|
|
var ExtNumber = this,
|
|
isToFixedBroken = (0.9).toFixed() !== '1',
|
|
math = Math,
|
|
ClipDefault = {
|
|
count: false,
|
|
inclusive: false,
|
|
wrap: true
|
|
};
|
|
Ext.apply(ExtNumber, {
|
|
MIN_SAFE_INTEGER: Number.MIN_SAFE_INTEGER || -(math.pow(2, 53) - 1),
|
|
MAX_SAFE_INTEGER: Number.MAX_SAFE_INTEGER || math.pow(2, 53) - 1,
|
|
Clip: {
|
|
DEFAULT: ClipDefault,
|
|
COUNT: Ext.applyIf({
|
|
count: true
|
|
}, ClipDefault),
|
|
INCLUSIVE: Ext.applyIf({
|
|
inclusive: true
|
|
}, ClipDefault),
|
|
NOWRAP: Ext.applyIf({
|
|
wrap: false
|
|
}, ClipDefault)
|
|
},
|
|
/**
|
|
* Coerces a given index into a valid index given a `length`.
|
|
*
|
|
* Negative indexes are interpreted starting at the end of the collection. That is,
|
|
* a value of -1 indicates the last item, or equivalent to `length - 1`.
|
|
*
|
|
* When handling methods that take "begin" and "end" arguments like most array or
|
|
* string methods, this method can be used like so:
|
|
*
|
|
* function foo (array, begin, end) {
|
|
* var range = Ext.Number.clipIndices(array.length, [begin, end]);
|
|
*
|
|
* begin = range[0];
|
|
* end = range[1];
|
|
*
|
|
* // 0 <= begin <= end <= array.length
|
|
*
|
|
* var length = end - begin;
|
|
* }
|
|
*
|
|
* For example:
|
|
*
|
|
* +---+---+---+---+---+---+---+---+
|
|
* | | | | | | | | | length = 8
|
|
* +---+---+---+---+---+---+---+---+
|
|
* 0 1 2 3 4 5 6 7
|
|
* -8 -7 -6 -5 -4 -3 -2 -1
|
|
*
|
|
* console.log(Ext.Number.clipIndices(8, [3, 10]); // logs "[3, 8]"
|
|
* console.log(Ext.Number.clipIndices(8, [-5]); // logs "[3, 8]"
|
|
* console.log(Ext.Number.clipIndices(8, []);
|
|
* console.log(Ext.Number.clipIndices(8, []);
|
|
*
|
|
* @param {Number} length
|
|
* @param {Number[]} indices
|
|
* @param {Object} [options] An object with different option flags.
|
|
* @param {Boolean} [options.count=false] The second number in `indices` is the
|
|
* count not and an index.
|
|
* @param {Boolean} [options.inclusive=false] The second number in `indices` is
|
|
* "inclusive" meaning that the item should be considered in the range. Normally,
|
|
* the second number is considered the first item outside the range or as an
|
|
* "exclusive" bound.
|
|
* @param {Boolean} [options.wrap=true] Wraps negative numbers backwards from the
|
|
* end of the array. Passing `false` simply clips negative index values at 0.
|
|
* @return {Number[]} The normalized `[begin, end]` array where `end` is now
|
|
* exclusive such that `length = end - begin`. Both values are between 0 and the
|
|
* given `length` and `end` will not be less-than `begin`.
|
|
*/
|
|
clipIndices: function(length, indices, options) {
|
|
options = options || ClipDefault;
|
|
var defaultValue = 0,
|
|
// default value for "begin"
|
|
wrap = options.wrap,
|
|
begin, end, i;
|
|
indices = indices || [];
|
|
for (i = 0; i < 2; ++i) {
|
|
// names are off on first pass but used this way so things make sense
|
|
// following the loop..
|
|
begin = end;
|
|
// pick up and keep the result from the first loop
|
|
end = indices[i];
|
|
if (end == null) {
|
|
end = defaultValue;
|
|
} else if (i && options.count) {
|
|
end += begin;
|
|
// this is the length not "end" so convert to "end"
|
|
end = (end > length) ? length : end;
|
|
} else {
|
|
if (wrap) {
|
|
end = (end < 0) ? (length + end) : end;
|
|
}
|
|
if (i && options.inclusive) {
|
|
++end;
|
|
}
|
|
end = (end < 0) ? 0 : ((end > length) ? length : end);
|
|
}
|
|
defaultValue = length;
|
|
}
|
|
// default value for "end"
|
|
// after loop:
|
|
// 0 <= begin <= length (calculated from indices[0])
|
|
// 0 <= end <= length (calculated from indices[1])
|
|
indices[0] = begin;
|
|
indices[1] = (end < begin) ? begin : end;
|
|
return indices;
|
|
},
|
|
/**
|
|
* Checks whether or not the passed number is within a desired range. If the number is already within the
|
|
* range it is returned, otherwise the min or max value is returned depending on which side of the range is
|
|
* exceeded. Note that this method returns the constrained value but does not change the current number.
|
|
* @param {Number} number The number to check
|
|
* @param {Number} min The minimum number in the range
|
|
* @param {Number} max The maximum number in the range
|
|
* @return {Number} The constrained value if outside the range, otherwise the current value
|
|
*/
|
|
constrain: function(number, min, max) {
|
|
var x = parseFloat(number);
|
|
// (x < Nan) || (x < undefined) == false
|
|
// same for (x > NaN) || (x > undefined)
|
|
// sadly this is not true of null - (1 > null)
|
|
if (min === null) {
|
|
min = number;
|
|
}
|
|
if (max === null) {
|
|
max = number;
|
|
}
|
|
// Watch out for NaN in Chrome 18
|
|
// V8bug: http://code.google.com/p/v8/issues/detail?id=2056
|
|
// Operators are faster than Math.min/max. See http://jsperf.com/number-constrain
|
|
return (x < min) ? min : ((x > max) ? max : x);
|
|
},
|
|
/**
|
|
* Snaps the passed number between stopping points based upon a passed increment value.
|
|
*
|
|
* The difference between this and {@link #snapInRange} is that {@link #snapInRange} uses the minValue
|
|
* when calculating snap points:
|
|
*
|
|
* r = Ext.Number.snap(56, 2, 55, 65); // Returns 56 - snap points are zero based
|
|
*
|
|
* r = Ext.Number.snapInRange(56, 2, 55, 65); // Returns 57 - snap points are based from minValue
|
|
*
|
|
* @param {Number} value The unsnapped value.
|
|
* @param {Number} increment The increment by which the value must move.
|
|
* @param {Number} minValue The minimum value to which the returned value must be constrained. Overrides the increment.
|
|
* @param {Number} maxValue The maximum value to which the returned value must be constrained. Overrides the increment.
|
|
* @return {Number} The value of the nearest snap target.
|
|
*/
|
|
snap: function(value, increment, minValue, maxValue) {
|
|
var m;
|
|
// If no value passed, or minValue was passed and value is less than minValue (anything < undefined is false)
|
|
// Then use the minValue (or zero if the value was undefined)
|
|
if (value === undefined || value < minValue) {
|
|
return minValue || 0;
|
|
}
|
|
if (increment) {
|
|
m = value % increment;
|
|
if (m !== 0) {
|
|
value -= m;
|
|
if (m * 2 >= increment) {
|
|
value += increment;
|
|
} else if (m * 2 < -increment) {
|
|
value -= increment;
|
|
}
|
|
}
|
|
}
|
|
return ExtNumber.constrain(value, minValue, maxValue);
|
|
},
|
|
/**
|
|
* Snaps the passed number between stopping points based upon a passed increment value.
|
|
*
|
|
* The difference between this and {@link #snap} is that {@link #snap} does not use the minValue
|
|
* when calculating snap points:
|
|
*
|
|
* r = Ext.Number.snap(56, 2, 55, 65); // Returns 56 - snap points are zero based
|
|
*
|
|
* r = Ext.Number.snapInRange(56, 2, 55, 65); // Returns 57 - snap points are based from minValue
|
|
*
|
|
* @param {Number} value The unsnapped value.
|
|
* @param {Number} increment The increment by which the value must move.
|
|
* @param {Number} [minValue=0] The minimum value to which the returned value must be constrained.
|
|
* @param {Number} [maxValue=Infinity] The maximum value to which the returned value must be constrained.
|
|
* @return {Number} The value of the nearest snap target.
|
|
*/
|
|
snapInRange: function(value, increment, minValue, maxValue) {
|
|
var tween;
|
|
// default minValue to zero
|
|
minValue = (minValue || 0);
|
|
// If value is undefined, or less than minValue, use minValue
|
|
if (value === undefined || value < minValue) {
|
|
return minValue;
|
|
}
|
|
// Calculate how many snap points from the minValue the passed value is.
|
|
if (increment && (tween = ((value - minValue) % increment))) {
|
|
value -= tween;
|
|
tween *= 2;
|
|
if (tween >= increment) {
|
|
value += increment;
|
|
}
|
|
}
|
|
// If constraining within a maximum, ensure the maximum is on a snap point
|
|
if (maxValue !== undefined) {
|
|
if (value > (maxValue = ExtNumber.snapInRange(maxValue, increment, minValue))) {
|
|
value = maxValue;
|
|
}
|
|
}
|
|
return value;
|
|
},
|
|
/**
|
|
* Round a number to the nearest interval.
|
|
* @param {Number} value The value to round.
|
|
* @param {Number} interval The interval to round to.
|
|
* @return {Number} The rounded value.
|
|
*
|
|
* @since 6.2.0
|
|
*/
|
|
roundToNearest: function(value, interval) {
|
|
interval = interval || 1;
|
|
return interval * math.round(value / interval);
|
|
},
|
|
/**
|
|
* Returns the sign of the given number. See also MDN for Math.sign documentation
|
|
* for the standard method this method emulates.
|
|
* @param {Number} x The number.
|
|
* @return {Number} The sign of the number `x`, indicating whether the number is
|
|
* positive (1), negative (-1) or zero (0).
|
|
* @method sign
|
|
*/
|
|
sign: math.sign || function(x) {
|
|
x = +x;
|
|
// force to a Number
|
|
if (x === 0 || isNaN(x)) {
|
|
return x;
|
|
}
|
|
return (x > 0) ? 1 : -1;
|
|
},
|
|
/**
|
|
* Returns the base 10 logarithm of a number.
|
|
* This will use Math.log10, if available (ES6).
|
|
* @param {Number} x The number.
|
|
* @return {Number} Base 10 logarithm of the number 'x'.
|
|
* @method log10
|
|
*/
|
|
log10: math.log10 || function(x) {
|
|
return math.log(x) * math.LOG10E;
|
|
},
|
|
/**
|
|
* Determines if two numbers `n1` and `n2` are equal within a given
|
|
* margin of precision `epsilon`.
|
|
* @param {Number} n1 First number.
|
|
* @param {Number} n2 Second number.
|
|
* @param {Number} epsilon Margin of precision.
|
|
* @returns {Boolean} `true`, if numbers are equal. `false` otherwise.
|
|
*/
|
|
isEqual: function(n1, n2, epsilon) {
|
|
if (!(typeof n1 === 'number' && typeof n2 === 'number' && typeof epsilon === 'number')) {
|
|
Ext.raise("All parameters should be valid numbers.");
|
|
}
|
|
return math.abs(n1 - n2) < epsilon;
|
|
},
|
|
/**
|
|
* Determines if the value passed is a number and also finite.
|
|
* This a Polyfill version of Number.isFinite(),differently than
|
|
* the isFinite() function, this method doesn't convert the parameter to a number.
|
|
* @param {Number} value Number to be tested.
|
|
* @returns {Boolean} `true`, if the parameter is a number and finite, `false` otherwise.
|
|
* @since 6.2
|
|
*/
|
|
isFinite: Number.isFinite || function(value) {
|
|
return typeof value === 'number' && isFinite(value);
|
|
},
|
|
/**
|
|
* @method
|
|
* Formats a number using fixed-point notation
|
|
* @param {Number} value The number to format
|
|
* @param {Number} precision The number of digits to show after the decimal point
|
|
*/
|
|
toFixed: isToFixedBroken ? function(value, precision) {
|
|
precision = precision || 0;
|
|
var pow = math.pow(10, precision);
|
|
return (math.round(value * pow) / pow).toFixed(precision);
|
|
} : function(value, precision) {
|
|
return value.toFixed(precision);
|
|
},
|
|
/**
|
|
* Validate that a value is numeric and convert it to a number if necessary. Returns the specified default value if
|
|
* it is not.
|
|
|
|
Ext.Number.from('1.23', 1); // returns 1.23
|
|
Ext.Number.from('abc', 1); // returns 1
|
|
|
|
* @param {Object} value
|
|
* @param {Number} defaultValue The value to return if the original value is non-numeric
|
|
* @return {Number} value, if numeric, defaultValue otherwise
|
|
*/
|
|
from: function(value, defaultValue) {
|
|
if (isFinite(value)) {
|
|
value = parseFloat(value);
|
|
}
|
|
return !isNaN(value) ? value : defaultValue;
|
|
},
|
|
/**
|
|
* Returns a random integer between the specified range (inclusive)
|
|
* @param {Number} from Lowest value to return.
|
|
* @param {Number} to Highest value to return.
|
|
* @return {Number} A random integer within the specified range.
|
|
*/
|
|
randomInt: function(from, to) {
|
|
return math.floor(math.random() * (to - from + 1) + from);
|
|
},
|
|
/**
|
|
* Corrects floating point numbers that overflow to a non-precise
|
|
* value because of their floating nature, for example `0.1 + 0.2`
|
|
* @param {Number} n The number
|
|
* @return {Number} The correctly rounded number
|
|
*/
|
|
correctFloat: function(n) {
|
|
// This is to correct the type of errors where 2 floats end with
|
|
// a long string of decimals, eg 0.1 + 0.2. When they overflow in this
|
|
// manner, they usually go to 15-16 decimals, so we cut it off at 14.
|
|
return parseFloat(n.toPrecision(14));
|
|
}
|
|
});
|
|
/**
|
|
* @deprecated 4.0.0 Please use {@link Ext.Number#from} instead.
|
|
* @member Ext
|
|
* @method num
|
|
* @inheritdoc Ext.Number#from
|
|
*/
|
|
Ext.num = function() {
|
|
return ExtNumber.from.apply(this, arguments);
|
|
};
|
|
}());
|
|
|
|
/**
|
|
* @class Ext.Object
|
|
*
|
|
* A collection of useful static methods to deal with objects.
|
|
*
|
|
* @singleton
|
|
*/
|
|
(function() {
|
|
// The "constructor" for chain:
|
|
var TemplateClass = function() {},
|
|
queryRe = /^\?/,
|
|
keyRe = /(\[):?([^\]]*)\]/g,
|
|
nameRe = /^([^\[]+)/,
|
|
plusRe = /\+/g,
|
|
ExtObject = Ext.Object = {
|
|
// @define Ext.lang.Object
|
|
// @define Ext.Object
|
|
// @require Ext
|
|
// @require Ext.lang.Date
|
|
/**
|
|
* @method
|
|
* Returns a new object with the given object as the prototype chain. This method is
|
|
* designed to mimic the ECMA standard `Object.create` method and is assigned to that
|
|
* function when it is available.
|
|
*
|
|
* **NOTE** This method does not support the property definitions capability of the
|
|
* `Object.create` method. Only the first argument is supported.
|
|
*
|
|
* @param {Object} object The prototype chain for the new object.
|
|
*/
|
|
chain: Object.create || function(object) {
|
|
TemplateClass.prototype = object;
|
|
var result = new TemplateClass();
|
|
TemplateClass.prototype = null;
|
|
return result;
|
|
},
|
|
/**
|
|
* This method removes all keys from the given object.
|
|
* @param {Object} object The object from which to remove all keys.
|
|
* @return {Object} The given object.
|
|
*/
|
|
clear: function(object) {
|
|
// Safe to delete during iteration
|
|
for (var key in object) {
|
|
delete object[key];
|
|
}
|
|
return object;
|
|
},
|
|
/**
|
|
* Freezes the given object making it immutable. This operation is by default shallow
|
|
* and does not effect objects referenced by the given object.
|
|
*
|
|
* @method
|
|
* @param {Object} obj The object to freeze.
|
|
* @param {Boolean} [deep=false] Pass `true` to freeze sub-objects recursively.
|
|
* @return {Object} The given object `obj`.
|
|
*/
|
|
freeze: Object.freeze ? function(obj, deep) {
|
|
if (obj && typeof obj === 'object' && !Object.isFrozen(obj)) {
|
|
Object.freeze(obj);
|
|
if (deep) {
|
|
for (var name in obj) {
|
|
ExtObject.freeze(obj[name], deep);
|
|
}
|
|
}
|
|
}
|
|
return obj;
|
|
} : Ext.identityFn,
|
|
/**
|
|
* Converts a `name` - `value` pair to an array of objects with support for nested structures. Useful to construct
|
|
* query strings. For example:
|
|
*
|
|
* var objects = Ext.Object.toQueryObjects('hobbies', ['reading', 'cooking', 'swimming']);
|
|
*
|
|
* // objects then equals:
|
|
* [
|
|
* { name: 'hobbies', value: 'reading' },
|
|
* { name: 'hobbies', value: 'cooking' },
|
|
* { name: 'hobbies', value: 'swimming' },
|
|
* ];
|
|
*
|
|
* var objects = Ext.Object.toQueryObjects('dateOfBirth', {
|
|
* day: 3,
|
|
* month: 8,
|
|
* year: 1987,
|
|
* extra: {
|
|
* hour: 4
|
|
* minute: 30
|
|
* }
|
|
* }, true); // Recursive
|
|
*
|
|
* // objects then equals:
|
|
* [
|
|
* { name: 'dateOfBirth[day]', value: 3 },
|
|
* { name: 'dateOfBirth[month]', value: 8 },
|
|
* { name: 'dateOfBirth[year]', value: 1987 },
|
|
* { name: 'dateOfBirth[extra][hour]', value: 4 },
|
|
* { name: 'dateOfBirth[extra][minute]', value: 30 },
|
|
* ];
|
|
*
|
|
* @param {String} name
|
|
* @param {Object/Array} value
|
|
* @param {Boolean} [recursive=false] True to traverse object recursively
|
|
* @return {Object[]}
|
|
*/
|
|
toQueryObjects: function(name, value, recursive) {
|
|
var self = ExtObject.toQueryObjects,
|
|
objects = [],
|
|
i, ln;
|
|
if (Ext.isArray(value)) {
|
|
for (i = 0 , ln = value.length; i < ln; i++) {
|
|
if (recursive) {
|
|
objects = objects.concat(self(name + '[' + i + ']', value[i], true));
|
|
} else {
|
|
objects.push({
|
|
name: name,
|
|
value: value[i]
|
|
});
|
|
}
|
|
}
|
|
} else if (Ext.isObject(value)) {
|
|
for (i in value) {
|
|
if (value.hasOwnProperty(i)) {
|
|
if (recursive) {
|
|
objects = objects.concat(self(name + '[' + i + ']', value[i], true));
|
|
} else {
|
|
objects.push({
|
|
name: name,
|
|
value: value[i]
|
|
});
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
objects.push({
|
|
name: name,
|
|
value: value
|
|
});
|
|
}
|
|
return objects;
|
|
},
|
|
/**
|
|
* Takes an object and converts it to an encoded query string.
|
|
*
|
|
* Non-recursive:
|
|
*
|
|
* Ext.Object.toQueryString({foo: 1, bar: 2}); // returns "foo=1&bar=2"
|
|
* Ext.Object.toQueryString({foo: null, bar: 2}); // returns "foo=&bar=2"
|
|
* Ext.Object.toQueryString({'some price': '$300'}); // returns "some%20price=%24300"
|
|
* Ext.Object.toQueryString({date: new Date(2011, 0, 1)}); // returns "date=%222011-01-01T00%3A00%3A00%22"
|
|
* Ext.Object.toQueryString({colors: ['red', 'green', 'blue']}); // returns "colors=red&colors=green&colors=blue"
|
|
*
|
|
* Recursive:
|
|
*
|
|
* Ext.Object.toQueryString({
|
|
* username: 'Jacky',
|
|
* dateOfBirth: {
|
|
* day: 1,
|
|
* month: 2,
|
|
* year: 1911
|
|
* },
|
|
* hobbies: ['coding', 'eating', 'sleeping', ['nested', 'stuff']]
|
|
* }, true); // returns the following string (broken down and url-decoded for ease of reading purpose):
|
|
* // username=Jacky
|
|
* // &dateOfBirth[day]=1&dateOfBirth[month]=2&dateOfBirth[year]=1911
|
|
* // &hobbies[0]=coding&hobbies[1]=eating&hobbies[2]=sleeping&hobbies[3][0]=nested&hobbies[3][1]=stuff
|
|
*
|
|
* @param {Object} object The object to encode
|
|
* @param {Boolean} [recursive=false] Whether or not to interpret the object in recursive format.
|
|
* (PHP / Ruby on Rails servers and similar).
|
|
* @return {String} queryString
|
|
*/
|
|
toQueryString: function(object, recursive) {
|
|
var paramObjects = [],
|
|
params = [],
|
|
i, j, ln, paramObject, value;
|
|
for (i in object) {
|
|
if (object.hasOwnProperty(i)) {
|
|
paramObjects = paramObjects.concat(ExtObject.toQueryObjects(i, object[i], recursive));
|
|
}
|
|
}
|
|
for (j = 0 , ln = paramObjects.length; j < ln; j++) {
|
|
paramObject = paramObjects[j];
|
|
value = paramObject.value;
|
|
if (Ext.isEmpty(value)) {
|
|
value = '';
|
|
} else if (Ext.isDate(value)) {
|
|
value = Ext.Date.toString(value);
|
|
}
|
|
params.push(encodeURIComponent(paramObject.name) + '=' + encodeURIComponent(String(value)));
|
|
}
|
|
return params.join('&');
|
|
},
|
|
/**
|
|
* Converts a query string back into an object.
|
|
*
|
|
* Non-recursive:
|
|
*
|
|
* Ext.Object.fromQueryString("foo=1&bar=2"); // returns {foo: '1', bar: '2'}
|
|
* Ext.Object.fromQueryString("foo=&bar=2"); // returns {foo: '', bar: '2'}
|
|
* Ext.Object.fromQueryString("some%20price=%24300"); // returns {'some price': '$300'}
|
|
* Ext.Object.fromQueryString("colors=red&colors=green&colors=blue"); // returns {colors: ['red', 'green', 'blue']}
|
|
*
|
|
* Recursive:
|
|
*
|
|
* Ext.Object.fromQueryString(
|
|
* "username=Jacky&"+
|
|
* "dateOfBirth[day]=1&dateOfBirth[month]=2&dateOfBirth[year]=1911&"+
|
|
* "hobbies[0]=coding&hobbies[1]=eating&hobbies[2]=sleeping&"+
|
|
* "hobbies[3][0]=nested&hobbies[3][1]=stuff", true);
|
|
*
|
|
* // returns
|
|
* {
|
|
* username: 'Jacky',
|
|
* dateOfBirth: {
|
|
* day: '1',
|
|
* month: '2',
|
|
* year: '1911'
|
|
* },
|
|
* hobbies: ['coding', 'eating', 'sleeping', ['nested', 'stuff']]
|
|
* }
|
|
*
|
|
* @param {String} queryString The query string to decode
|
|
* @param {Boolean} [recursive=false] Whether or not to recursively decode the string. This format is supported by
|
|
* PHP / Ruby on Rails servers and similar.
|
|
* @return {Object}
|
|
*/
|
|
fromQueryString: function(queryString, recursive) {
|
|
var parts = queryString.replace(queryRe, '').split('&'),
|
|
object = {},
|
|
temp, components, name, value, i, ln, part, j, subLn, matchedKeys, matchedName, keys, key, nextKey;
|
|
for (i = 0 , ln = parts.length; i < ln; i++) {
|
|
part = parts[i];
|
|
if (part.length > 0) {
|
|
components = part.split('=');
|
|
name = components[0];
|
|
name = name.replace(plusRe, '%20');
|
|
name = decodeURIComponent(name);
|
|
value = components[1];
|
|
if (value !== undefined) {
|
|
value = value.replace(plusRe, '%20');
|
|
value = decodeURIComponent(value);
|
|
} else {
|
|
value = '';
|
|
}
|
|
if (!recursive) {
|
|
if (object.hasOwnProperty(name)) {
|
|
if (!Ext.isArray(object[name])) {
|
|
object[name] = [
|
|
object[name]
|
|
];
|
|
}
|
|
object[name].push(value);
|
|
} else {
|
|
object[name] = value;
|
|
}
|
|
} else {
|
|
matchedKeys = name.match(keyRe);
|
|
matchedName = name.match(nameRe);
|
|
if (!matchedName) {
|
|
throw new Error('[Ext.Object.fromQueryString] Malformed query string given, failed parsing name from "' + part + '"');
|
|
}
|
|
name = matchedName[0];
|
|
keys = [];
|
|
if (matchedKeys === null) {
|
|
object[name] = value;
|
|
|
|
continue;
|
|
}
|
|
for (j = 0 , subLn = matchedKeys.length; j < subLn; j++) {
|
|
key = matchedKeys[j];
|
|
key = (key.length === 2) ? '' : key.substring(1, key.length - 1);
|
|
keys.push(key);
|
|
}
|
|
keys.unshift(name);
|
|
temp = object;
|
|
for (j = 0 , subLn = keys.length; j < subLn; j++) {
|
|
key = keys[j];
|
|
if (j === subLn - 1) {
|
|
if (Ext.isArray(temp) && key === '') {
|
|
temp.push(value);
|
|
} else {
|
|
temp[key] = value;
|
|
}
|
|
} else {
|
|
if (temp[key] === undefined || typeof temp[key] === 'string') {
|
|
nextKey = keys[j + 1];
|
|
temp[key] = (Ext.isNumeric(nextKey) || nextKey === '') ? [] : {};
|
|
}
|
|
temp = temp[key];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return object;
|
|
},
|
|
/**
|
|
* Iterates through an object and invokes the given callback function for each iteration.
|
|
* The iteration can be stopped by returning `false` in the callback function. For example:
|
|
*
|
|
* var person = {
|
|
* name: 'Jacky'
|
|
* hairColor: 'black'
|
|
* loves: ['food', 'sleeping', 'wife']
|
|
* };
|
|
*
|
|
* Ext.Object.each(person, function(key, value, myself) {
|
|
* console.log(key + ":" + value);
|
|
*
|
|
* if (key === 'hairColor') {
|
|
* return false; // stop the iteration
|
|
* }
|
|
* });
|
|
*
|
|
* @param {Object} object The object to iterate
|
|
* @param {Function} fn The callback function.
|
|
* @param {String} fn.key
|
|
* @param {Object} fn.value
|
|
* @param {Object} fn.object The object itself
|
|
* @param {Object} [scope] The execution scope (`this`) of the callback function
|
|
*/
|
|
each: function(object, fn, scope) {
|
|
var enumerables = Ext.enumerables,
|
|
i, property;
|
|
if (object) {
|
|
scope = scope || object;
|
|
for (property in object) {
|
|
if (object.hasOwnProperty(property)) {
|
|
if (fn.call(scope, property, object[property], object) === false) {
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
if (enumerables) {
|
|
for (i = enumerables.length; i--; ) {
|
|
if (object.hasOwnProperty(property = enumerables[i])) {
|
|
if (fn.call(scope, property, object[property], object) === false) {
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
/**
|
|
* Iterates through an object and invokes the given callback function for each iteration.
|
|
* The iteration can be stopped by returning `false` in the callback function. For example:
|
|
*
|
|
* var items = {
|
|
* 1: 'Hello',
|
|
* 2: 'World'
|
|
* };
|
|
*
|
|
* Ext.Object.eachValue(items, function (value) {
|
|
* console.log("Value: " + value);
|
|
* });
|
|
*
|
|
* This will log 'Hello' and 'World' in no particular order. This method is useful
|
|
* in cases where the keys are not important to the processing, just the values.
|
|
*
|
|
* @param {Object} object The object to iterate
|
|
* @param {Function} fn The callback function.
|
|
* @param {Object} fn.value The value of
|
|
* @param {Object} [scope] The execution scope (`this`) of the callback function
|
|
*/
|
|
eachValue: function(object, fn, scope) {
|
|
var enumerables = Ext.enumerables,
|
|
i, property;
|
|
scope = scope || object;
|
|
for (property in object) {
|
|
if (object.hasOwnProperty(property)) {
|
|
if (fn.call(scope, object[property]) === false) {
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
if (enumerables) {
|
|
for (i = enumerables.length; i--; ) {
|
|
if (object.hasOwnProperty(property = enumerables[i])) {
|
|
if (fn.call(scope, object[property]) === false) {
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
/**
|
|
* Merges any number of objects recursively without referencing them or their children.
|
|
*
|
|
* var extjs = {
|
|
* companyName: 'Ext JS',
|
|
* products: ['Ext JS', 'Ext GWT', 'Ext Designer'],
|
|
* isSuperCool: true,
|
|
* office: {
|
|
* size: 2000,
|
|
* location: 'Palo Alto',
|
|
* isFun: true
|
|
* }
|
|
* };
|
|
*
|
|
* var newStuff = {
|
|
* companyName: 'Sencha Inc.',
|
|
* products: ['Ext JS', 'Ext GWT', 'Ext Designer', 'Sencha Touch', 'Sencha Animator'],
|
|
* office: {
|
|
* size: 40000,
|
|
* location: 'Redwood City'
|
|
* }
|
|
* };
|
|
*
|
|
* var sencha = Ext.Object.merge(extjs, newStuff);
|
|
*
|
|
* // extjs and sencha then equals to
|
|
* {
|
|
* companyName: 'Sencha Inc.',
|
|
* products: ['Ext JS', 'Ext GWT', 'Ext Designer', 'Sencha Touch', 'Sencha Animator'],
|
|
* isSuperCool: true,
|
|
* office: {
|
|
* size: 40000,
|
|
* location: 'Redwood City',
|
|
* isFun: true
|
|
* }
|
|
* }
|
|
*
|
|
* @param {Object} destination The object into which all subsequent objects are merged.
|
|
* @param {Object...} object Any number of objects to merge into the destination.
|
|
* @return {Object} merged The destination object with all passed objects merged in.
|
|
*/
|
|
merge: function(destination) {
|
|
var i = 1,
|
|
ln = arguments.length,
|
|
mergeFn = ExtObject.merge,
|
|
cloneFn = Ext.clone,
|
|
object, key, value, sourceKey;
|
|
for (; i < ln; i++) {
|
|
object = arguments[i];
|
|
for (key in object) {
|
|
value = object[key];
|
|
if (value && value.constructor === Object) {
|
|
sourceKey = destination[key];
|
|
if (sourceKey && sourceKey.constructor === Object) {
|
|
mergeFn(sourceKey, value);
|
|
} else {
|
|
destination[key] = cloneFn(value);
|
|
}
|
|
} else {
|
|
destination[key] = value;
|
|
}
|
|
}
|
|
}
|
|
return destination;
|
|
},
|
|
/**
|
|
* @private
|
|
* @param destination
|
|
*/
|
|
mergeIf: function(destination) {
|
|
var i = 1,
|
|
ln = arguments.length,
|
|
cloneFn = Ext.clone,
|
|
object, key, value;
|
|
for (; i < ln; i++) {
|
|
object = arguments[i];
|
|
for (key in object) {
|
|
if (!(key in destination)) {
|
|
value = object[key];
|
|
if (value && value.constructor === Object) {
|
|
destination[key] = cloneFn(value);
|
|
} else {
|
|
destination[key] = value;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return destination;
|
|
},
|
|
/**
|
|
* Returns all keys of the given object as an array.
|
|
*
|
|
* @param {Object} object
|
|
* @return {String[]} An array of keys from the object or any of its prototypes.
|
|
* @method
|
|
*/
|
|
getAllKeys: function(object) {
|
|
var keys = [],
|
|
property;
|
|
for (property in object) {
|
|
keys.push(property);
|
|
}
|
|
return keys;
|
|
},
|
|
/**
|
|
* Returns the first matching key corresponding to the given value.
|
|
* If no matching value is found, null is returned.
|
|
*
|
|
* var person = {
|
|
* name: 'Jacky',
|
|
* loves: 'food'
|
|
* };
|
|
*
|
|
* alert(Ext.Object.getKey(person, 'food')); // alerts 'loves'
|
|
*
|
|
* @param {Object} object
|
|
* @param {Object} value The value to find
|
|
*/
|
|
getKey: function(object, value) {
|
|
for (var property in object) {
|
|
if (object.hasOwnProperty(property) && object[property] === value) {
|
|
return property;
|
|
}
|
|
}
|
|
return null;
|
|
},
|
|
/**
|
|
* Gets all values of the given object as an array.
|
|
*
|
|
* var values = Ext.Object.getValues({
|
|
* name: 'Jacky',
|
|
* loves: 'food'
|
|
* }); // ['Jacky', 'food']
|
|
*
|
|
* @param {Object} object
|
|
* @return {Array} An array of values from the object
|
|
*/
|
|
getValues: function(object) {
|
|
var values = [],
|
|
property;
|
|
for (property in object) {
|
|
if (object.hasOwnProperty(property)) {
|
|
values.push(object[property]);
|
|
}
|
|
}
|
|
return values;
|
|
},
|
|
/**
|
|
* Returns the `hasOwnProperty` keys of the given object as an array.
|
|
*
|
|
* var values = Ext.Object.getKeys({
|
|
* name: 'Jacky',
|
|
* loves: 'food'
|
|
* }); // ['name', 'loves']
|
|
*
|
|
* @param {Object} object
|
|
* @return {String[]} An array of keys from the object
|
|
* @method
|
|
*/
|
|
getKeys: (typeof Object.keys == 'function') ? function(object) {
|
|
if (!object) {
|
|
return [];
|
|
}
|
|
return Object.keys(object);
|
|
} : function(object) {
|
|
var keys = [],
|
|
property;
|
|
for (property in object) {
|
|
if (object.hasOwnProperty(property)) {
|
|
keys.push(property);
|
|
}
|
|
}
|
|
return keys;
|
|
},
|
|
/**
|
|
* Gets the total number of this object's own properties
|
|
*
|
|
* var size = Ext.Object.getSize({
|
|
* name: 'Jacky',
|
|
* loves: 'food'
|
|
* }); // size equals 2
|
|
*
|
|
* @param {Object} object
|
|
* @return {Number} size
|
|
*/
|
|
getSize: function(object) {
|
|
var size = 0,
|
|
property;
|
|
for (property in object) {
|
|
if (object.hasOwnProperty(property)) {
|
|
size++;
|
|
}
|
|
}
|
|
return size;
|
|
},
|
|
/**
|
|
* Checks if there are any properties on this object.
|
|
* @param {Object} object
|
|
* @return {Boolean} `true` if there no properties on the object.
|
|
*/
|
|
isEmpty: function(object) {
|
|
for (var key in object) {
|
|
if (object.hasOwnProperty(key)) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
},
|
|
/**
|
|
* @method
|
|
* Shallow compares the contents of 2 objects using strict equality. Objects are
|
|
* considered equal if they both have the same set of properties and the
|
|
* value for those properties equals the other in the corresponding object.
|
|
*
|
|
* // Returns true
|
|
* Ext.Object.equals({
|
|
* foo: 1,
|
|
* bar: 2
|
|
* }, {
|
|
* foo: 1,
|
|
* bar: 2
|
|
* });
|
|
*
|
|
* @param {Object} object1
|
|
* @param {Object} object2
|
|
* @return {Boolean} `true` if the objects are equal.
|
|
*/
|
|
equals: (function() {
|
|
var check = function(o1, o2) {
|
|
var key;
|
|
for (key in o1) {
|
|
if (o1.hasOwnProperty(key)) {
|
|
if (o1[key] !== o2[key]) {
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
return true;
|
|
};
|
|
return function(object1, object2) {
|
|
// Short circuit if the same object is passed twice
|
|
if (object1 === object2) {
|
|
return true;
|
|
}
|
|
if (object1 && object2) {
|
|
// Do the second check because we could have extra keys in
|
|
// object2 that don't exist in object1.
|
|
return check(object1, object2) && check(object2, object1);
|
|
} else if (!object1 && !object2) {
|
|
return object1 === object2;
|
|
} else {
|
|
return false;
|
|
}
|
|
};
|
|
})(),
|
|
/**
|
|
* @private
|
|
*/
|
|
fork: function(obj) {
|
|
var ret, key, value;
|
|
if (obj && obj.constructor === Object) {
|
|
ret = ExtObject.chain(obj);
|
|
for (key in obj) {
|
|
value = obj[key];
|
|
if (value) {
|
|
if (value.constructor === Object) {
|
|
ret[key] = ExtObject.fork(value);
|
|
} else if (value instanceof Array) {
|
|
ret[key] = Ext.Array.clone(value);
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
ret = obj;
|
|
}
|
|
return ret;
|
|
},
|
|
defineProperty: ('defineProperty' in Object) ? Object.defineProperty : function(object, name, descriptor) {
|
|
if (!Object.prototype.__defineGetter__) {
|
|
return;
|
|
}
|
|
if (descriptor.get) {
|
|
object.__defineGetter__(name, descriptor.get);
|
|
}
|
|
if (descriptor.set) {
|
|
object.__defineSetter__(name, descriptor.set);
|
|
}
|
|
},
|
|
/**
|
|
* @private
|
|
*/
|
|
classify: function(object) {
|
|
var prototype = object,
|
|
objectProperties = [],
|
|
propertyClassesMap = {},
|
|
objectClass = function() {
|
|
var i = 0,
|
|
ln = objectProperties.length,
|
|
property;
|
|
for (; i < ln; i++) {
|
|
property = objectProperties[i];
|
|
this[property] = new propertyClassesMap[property]();
|
|
}
|
|
},
|
|
key, value;
|
|
for (key in object) {
|
|
if (object.hasOwnProperty(key)) {
|
|
value = object[key];
|
|
if (value && value.constructor === Object) {
|
|
objectProperties.push(key);
|
|
propertyClassesMap[key] = ExtObject.classify(value);
|
|
}
|
|
}
|
|
}
|
|
objectClass.prototype = prototype;
|
|
return objectClass;
|
|
}
|
|
};
|
|
/**
|
|
* A convenient alias method for {@link Ext.Object#merge}.
|
|
*
|
|
* @member Ext
|
|
* @method merge
|
|
* @inheritdoc Ext.Object#merge
|
|
*/
|
|
Ext.merge = Ext.Object.merge;
|
|
/**
|
|
* @private
|
|
* @member Ext
|
|
*/
|
|
Ext.mergeIf = Ext.Object.mergeIf;
|
|
}());
|
|
|
|
/*
|
|
* This file contains miscellaneous utility methods that depends on various helper classes
|
|
* like `Ext.Array` and `Ext.Date`. Historically these methods were defined in Ext.js or
|
|
* Ext-more.js but that creates circular dependencies so they were consolidated here.
|
|
*/
|
|
Ext.apply(Ext, {
|
|
// @define Ext.Util
|
|
// @require Ext
|
|
// @require Ext.lang.*
|
|
// shortcut for the special named scopes for listener scope resolution
|
|
_namedScopes: {
|
|
'this': {
|
|
isThis: 1
|
|
},
|
|
controller: {
|
|
isController: 1
|
|
},
|
|
// these two are private, used to indicate that listeners were declared on the
|
|
// class body with either an unspecified scope, or scope:'controller'
|
|
self: {
|
|
isSelf: 1
|
|
},
|
|
'self.controller': {
|
|
isSelf: 1,
|
|
isController: 1
|
|
}
|
|
},
|
|
escapeId: (function() {
|
|
var validIdRe = /^[a-zA-Z_][a-zA-Z0-9_\-]*$/i,
|
|
escapeRx = /([\W]{1})/g,
|
|
leadingNumRx = /^(\d)/g,
|
|
escapeFn = function(match, capture) {
|
|
return "\\" + capture;
|
|
},
|
|
numEscapeFn = function(match, capture) {
|
|
return '\\00' + capture.charCodeAt(0).toString(16) + ' ';
|
|
};
|
|
return function(id) {
|
|
return validIdRe.test(id) ? id : // replace the number portion last to keep the trailing ' '
|
|
// from being escaped
|
|
id.replace(escapeRx, escapeFn).replace(leadingNumRx, numEscapeFn);
|
|
};
|
|
}()),
|
|
/**
|
|
* @method callback
|
|
* @member Ext
|
|
* Execute a callback function in a particular scope. If `callback` argument is a
|
|
* function reference, that is called. If it is a string, the string is assumed to
|
|
* be the name of a method on the given `scope`. If no function is passed the call
|
|
* is ignored.
|
|
*
|
|
* For example, these calls are equivalent:
|
|
*
|
|
* var myFunc = this.myFunc;
|
|
*
|
|
* Ext.callback('myFunc', this, [arg1, arg2]);
|
|
* Ext.callback(myFunc, this, [arg1, arg2]);
|
|
*
|
|
* Ext.isFunction(myFunc) && this.myFunc(arg1, arg2);
|
|
*
|
|
* @param {Function/String} callback The callback function to execute or the name of
|
|
* the callback method on the provided `scope`.
|
|
* @param {Object} [scope] The scope in which `callback` should be invoked. If `callback`
|
|
* is a string this object provides the method by that name. If this is `null` then
|
|
* the `caller` is used to resolve the scope to a `ViewController` or the proper
|
|
* `defaultListenerScope`.
|
|
* @param {Array} [args] The arguments to pass to the function.
|
|
* @param {Number} [delay] Pass a number to delay the call by a number of milliseconds.
|
|
* @param {Object} [caller] The object calling the callback. This is used to resolve
|
|
* named methods when no explicit `scope` is provided.
|
|
* @param {Object} [defaultScope=caller] The default scope to return if none is found.
|
|
* @return The value returned by the callback or `undefined` (if there is a `delay`
|
|
* or if the `callback` is not a function).
|
|
*/
|
|
callback: function(callback, scope, args, delay, caller, defaultScope) {
|
|
if (!callback) {
|
|
return;
|
|
}
|
|
var namedScope = (scope in Ext._namedScopes);
|
|
if (callback.charAt) {
|
|
// if (isString(fn))
|
|
if ((!scope || namedScope) && caller) {
|
|
scope = caller.resolveListenerScope(namedScope ? scope : defaultScope);
|
|
}
|
|
if (!scope || !Ext.isObject(scope)) {
|
|
Ext.raise('Named method "' + callback + '" requires a scope object');
|
|
}
|
|
if (!Ext.isFunction(scope[callback])) {
|
|
Ext.raise('No method named "' + callback + '" on ' + (scope.$className || 'scope object'));
|
|
}
|
|
callback = scope[callback];
|
|
} else if (namedScope) {
|
|
scope = defaultScope || caller;
|
|
} else if (!scope) {
|
|
scope = caller;
|
|
}
|
|
var ret;
|
|
if (callback && Ext.isFunction(callback)) {
|
|
scope = scope || Ext.global;
|
|
if (delay) {
|
|
Ext.defer(callback, delay, scope, args);
|
|
} else if (Ext.elevateFunction) {
|
|
ret = Ext.elevateFunction(callback, scope, args);
|
|
} else if (args) {
|
|
ret = callback.apply(scope, args);
|
|
} else {
|
|
ret = callback.call(scope);
|
|
}
|
|
}
|
|
return ret;
|
|
},
|
|
/**
|
|
* @method coerce
|
|
* @member Ext
|
|
* Coerces the first value if possible so that it is comparable to the second value.
|
|
*
|
|
* Coercion only works between the basic atomic data types String, Boolean, Number, Date, null and undefined.
|
|
*
|
|
* Numbers and numeric strings are coerced to Dates using the value as the millisecond era value.
|
|
*
|
|
* Strings are coerced to Dates by parsing using the {@link Ext.Date#defaultFormat defaultFormat}.
|
|
*
|
|
* For example
|
|
*
|
|
* Ext.coerce('false', true);
|
|
*
|
|
* returns the boolean value `false` because the second parameter is of type `Boolean`.
|
|
*
|
|
* @param {Mixed} from The value to coerce
|
|
* @param {Mixed} to The value it must be compared against
|
|
* @return The coerced value.
|
|
*/
|
|
coerce: function(from, to) {
|
|
var fromType = Ext.typeOf(from),
|
|
toType = Ext.typeOf(to),
|
|
isString = typeof from === 'string';
|
|
if (fromType !== toType) {
|
|
switch (toType) {
|
|
case 'string':
|
|
return String(from);
|
|
case 'number':
|
|
return Number(from);
|
|
case 'boolean':
|
|
// See http://ecma262-5.com/ELS5_HTML.htm#Section_11.9.3 as to why '0'.
|
|
// TL;DR => ('0' == 0), so if given string '0', we must return boolean false.
|
|
return isString && (!from || from === 'false' || from === '0') ? false : Boolean(from);
|
|
case 'null':
|
|
return isString && (!from || from === 'null') ? null : false;
|
|
case 'undefined':
|
|
return isString && (!from || from === 'undefined') ? undefined : false;
|
|
case 'date':
|
|
return isString && isNaN(from) ? Ext.Date.parse(from, Ext.Date.defaultFormat) : Date(Number(from));
|
|
}
|
|
}
|
|
return from;
|
|
},
|
|
/**
|
|
* @method copyTo
|
|
* @member Ext
|
|
* Copies a set of named properties fom the source object to the destination object.
|
|
*
|
|
* Example:
|
|
*
|
|
* var foo = { a: 1, b: 2, c: 3 };
|
|
*
|
|
* var bar = Ext.copyTo({}, foo, 'a,c');
|
|
* // bar = { a: 1, c: 3 };
|
|
*
|
|
* Important note: To borrow class prototype methods, use {@link Ext.Base#borrow} instead.
|
|
*
|
|
* @param {Object} dest The destination object.
|
|
* @param {Object} source The source object.
|
|
* @param {String/String[]} names Either an Array of property names, or a comma-delimited list
|
|
* of property names to copy.
|
|
* @param {Boolean} [usePrototypeKeys=false] Pass `true` to copy keys off of the
|
|
* prototype as well as the instance.
|
|
* @return {Object} The `dest` object.
|
|
* @deprecated 6.0.1 Use {@link Ext#copy Ext.copy} instead. This old method
|
|
* would copy the named preoperties even if they did not exist in the source which
|
|
* could produce `undefined` values in the destination.
|
|
*/
|
|
copyTo: function(dest, source, names, usePrototypeKeys) {
|
|
if (typeof names === 'string') {
|
|
names = names.split(Ext.propertyNameSplitRe);
|
|
}
|
|
for (var name,
|
|
i = 0,
|
|
n = names ? names.length : 0; i < n; i++) {
|
|
name = names[i];
|
|
if (usePrototypeKeys || source.hasOwnProperty(name)) {
|
|
dest[name] = source[name];
|
|
}
|
|
}
|
|
return dest;
|
|
},
|
|
/**
|
|
* @method copy
|
|
* @member Ext
|
|
* Copies a set of named properties fom the source object to the destination object.
|
|
*
|
|
* Example:
|
|
*
|
|
* var foo = { a: 1, b: 2, c: 3 };
|
|
*
|
|
* var bar = Ext.copy({}, foo, 'a,c');
|
|
* // bar = { a: 1, c: 3 };
|
|
*
|
|
* Important note: To borrow class prototype methods, use {@link Ext.Base#borrow} instead.
|
|
*
|
|
* @param {Object} dest The destination object.
|
|
* @param {Object} source The source object.
|
|
* @param {String/String[]} names Either an Array of property names, or a comma-delimited list
|
|
* of property names to copy.
|
|
* @param {Boolean} [usePrototypeKeys=false] Pass `true` to copy keys off of the
|
|
* prototype as well as the instance.
|
|
* @return {Object} The `dest` object.
|
|
*/
|
|
copy: function(dest, source, names, usePrototypeKeys) {
|
|
if (typeof names === 'string') {
|
|
names = names.split(Ext.propertyNameSplitRe);
|
|
}
|
|
for (var name,
|
|
i = 0,
|
|
n = names ? names.length : 0; i < n; i++) {
|
|
name = names[i];
|
|
// Only copy a property if the source actually *has* that property.
|
|
// If we are including prototype properties, then ensure that a property of
|
|
// that name can be found *somewhere* in the prototype chain (otherwise we'd be copying undefined in which may break things)
|
|
if (source.hasOwnProperty(name) || (usePrototypeKeys && name in source)) {
|
|
dest[name] = source[name];
|
|
}
|
|
}
|
|
return dest;
|
|
},
|
|
propertyNameSplitRe: /[,;\s]+/,
|
|
/**
|
|
* @method copyToIf
|
|
* @member Ext
|
|
* Copies a set of named properties fom the source object to the destination object
|
|
* if the destination object does not already have them.
|
|
*
|
|
* Example:
|
|
*
|
|
* var foo = { a: 1, b: 2, c: 3 };
|
|
*
|
|
* var bar = Ext.copyToIf({ a:42 }, foo, 'a,c');
|
|
* // bar = { a: 42, c: 3 };
|
|
*
|
|
* @param {Object} destination The destination object.
|
|
* @param {Object} source The source object.
|
|
* @param {String/String[]} names Either an Array of property names, or a single string
|
|
* with a list of property names separated by ",", ";" or spaces.
|
|
* @return {Object} The `dest` object.
|
|
* @deprecated 6.0.1 Use {@link Ext#copyIf Ext.copyIf} instead. This old method
|
|
* would copy the named preoperties even if they did not exist in the source which
|
|
* could produce `undefined` values in the destination.
|
|
*/
|
|
copyToIf: function(destination, source, names) {
|
|
if (typeof names === 'string') {
|
|
names = names.split(Ext.propertyNameSplitRe);
|
|
}
|
|
for (var name,
|
|
i = 0,
|
|
n = names ? names.length : 0; i < n; i++) {
|
|
name = names[i];
|
|
if (destination[name] === undefined) {
|
|
destination[name] = source[name];
|
|
}
|
|
}
|
|
return destination;
|
|
},
|
|
/**
|
|
* @method copyIf
|
|
* @member Ext
|
|
* Copies a set of named properties fom the source object to the destination object
|
|
* if the destination object does not already have them.
|
|
*
|
|
* Example:
|
|
*
|
|
* var foo = { a: 1, b: 2, c: 3 };
|
|
*
|
|
* var bar = Ext.copyIf({ a:42 }, foo, 'a,c');
|
|
* // bar = { a: 42, c: 3 };
|
|
*
|
|
* @param {Object} destination The destination object.
|
|
* @param {Object} source The source object.
|
|
* @param {String/String[]} names Either an Array of property names, or a single string
|
|
* with a list of property names separated by ",", ";" or spaces.
|
|
* @return {Object} The `dest` object.
|
|
*/
|
|
copyIf: function(destination, source, names) {
|
|
if (typeof names === 'string') {
|
|
names = names.split(Ext.propertyNameSplitRe);
|
|
}
|
|
for (var name,
|
|
i = 0,
|
|
n = names ? names.length : 0; i < n; i++) {
|
|
name = names[i];
|
|
// Only copy a property if the destination has no property by that name
|
|
if (!(name in destination) && (name in source)) {
|
|
destination[name] = source[name];
|
|
}
|
|
}
|
|
return destination;
|
|
},
|
|
/**
|
|
* @method extend
|
|
* @member Ext
|
|
* This method deprecated. Use {@link Ext#define Ext.define} instead.
|
|
* @param {Function} superclass
|
|
* @param {Object} overrides
|
|
* @return {Function} The subclass constructor from the <tt>overrides</tt> parameter, or a generated one if not provided.
|
|
* @deprecated 4.0.0 Use {@link Ext#define Ext.define} instead
|
|
*/
|
|
extend: (function() {
|
|
// inline overrides
|
|
var objectConstructor = Object.prototype.constructor,
|
|
inlineOverrides = function(o) {
|
|
var m;
|
|
for (m in o) {
|
|
if (!o.hasOwnProperty(m)) {
|
|
|
|
continue;
|
|
}
|
|
this[m] = o[m];
|
|
}
|
|
};
|
|
return function(subclass, superclass, overrides) {
|
|
// First we check if the user passed in just the superClass with overrides
|
|
if (Ext.isObject(superclass)) {
|
|
overrides = superclass;
|
|
superclass = subclass;
|
|
subclass = overrides.constructor !== objectConstructor ? overrides.constructor : function() {
|
|
superclass.apply(this, arguments);
|
|
};
|
|
}
|
|
if (!superclass) {
|
|
Ext.raise({
|
|
sourceClass: 'Ext',
|
|
sourceMethod: 'extend',
|
|
msg: 'Attempting to extend from a class which has not been loaded on the page.'
|
|
});
|
|
}
|
|
// We create a new temporary class
|
|
var F = function() {},
|
|
subclassProto,
|
|
superclassProto = superclass.prototype;
|
|
F.prototype = superclassProto;
|
|
subclassProto = subclass.prototype = new F();
|
|
subclassProto.constructor = subclass;
|
|
subclass.superclass = superclassProto;
|
|
if (superclassProto.constructor === objectConstructor) {
|
|
superclassProto.constructor = superclass;
|
|
}
|
|
subclass.override = function(overrides) {
|
|
Ext.override(subclass, overrides);
|
|
};
|
|
subclassProto.override = inlineOverrides;
|
|
subclassProto.proto = subclassProto;
|
|
subclass.override(overrides);
|
|
subclass.extend = function(o) {
|
|
return Ext.extend(subclass, o);
|
|
};
|
|
return subclass;
|
|
};
|
|
}()),
|
|
/**
|
|
* @method iterate
|
|
* @member Ext
|
|
* Iterates either an array or an object. This method delegates to
|
|
* {@link Ext.Array#each Ext.Array.each} if the given value is iterable, and {@link Ext.Object#each Ext.Object.each} otherwise.
|
|
*
|
|
* @param {Object/Array} object The object or array to be iterated.
|
|
* @param {Function} fn The function to be called for each iteration. See and {@link Ext.Array#each Ext.Array.each} and
|
|
* {@link Ext.Object#each Ext.Object.each} for detailed lists of arguments passed to this function depending on the given object
|
|
* type that is being iterated.
|
|
* @param {Object} [scope] The scope (`this` reference) in which the specified function is executed.
|
|
* Defaults to the object being iterated itself.
|
|
*/
|
|
iterate: function(object, fn, scope) {
|
|
if (Ext.isEmpty(object)) {
|
|
return;
|
|
}
|
|
if (scope === undefined) {
|
|
scope = object;
|
|
}
|
|
if (Ext.isIterable(object)) {
|
|
Ext.Array.each.call(Ext.Array, object, fn, scope);
|
|
} else {
|
|
Ext.Object.each.call(Ext.Object, object, fn, scope);
|
|
}
|
|
},
|
|
_resourcePoolRe: /^[<]([^<>@:]*)(?:[@]([^<>@:]+))?[>](.+)$/,
|
|
/**
|
|
* Resolves a resource URL that may contain a resource pool identifier token at the
|
|
* front. The tokens are formatted as HTML tags "<poolName@packageName>" followed
|
|
* by a normal relative path. This token is only processed if present at the first
|
|
* character of the given string.
|
|
*
|
|
* These tokens are parsed and the pieces are then passed to the
|
|
* {@link Ext#getResourcePath} method.
|
|
*
|
|
* For example:
|
|
*
|
|
* [{
|
|
* xtype: 'image',
|
|
* src: '<shared>images/foo.png'
|
|
* },{
|
|
* xtype: 'image',
|
|
* src: '<@package>images/foo.png'
|
|
* },{
|
|
* xtype: 'image',
|
|
* src: '<shared@package>images/foo.png'
|
|
* }]
|
|
*
|
|
* In the above example, "shared" is the name of a Sencha Cmd resource pool and
|
|
* "package" is the name of a Sencha Cmd package.
|
|
* @member Ext
|
|
* @param {String} url The URL that may contain a resource pool token at the front.
|
|
* @return {String}
|
|
* @since 6.0.1
|
|
*/
|
|
resolveResource: function(url) {
|
|
var ret = url,
|
|
m;
|
|
if (url && url.charAt(0) === '<') {
|
|
m = Ext._resourcePoolRe.exec(url);
|
|
if (m) {
|
|
ret = Ext.getResourcePath(m[3], m[1], m[2]);
|
|
}
|
|
}
|
|
return ret;
|
|
},
|
|
/**
|
|
*
|
|
* @member Ext
|
|
* @method urlEncode
|
|
* @inheritdoc Ext.Object#toQueryString
|
|
* @deprecated 4.0.0 Use {@link Ext.Object#toQueryString} instead
|
|
*/
|
|
urlEncode: function() {
|
|
var args = Ext.Array.from(arguments),
|
|
prefix = '';
|
|
// Support for the old `pre` argument
|
|
if (Ext.isString(args[1])) {
|
|
prefix = args[1] + '&';
|
|
args[1] = false;
|
|
}
|
|
return prefix + Ext.Object.toQueryString.apply(Ext.Object, args);
|
|
},
|
|
/**
|
|
* Alias for {@link Ext.Object#fromQueryString}.
|
|
*
|
|
* @member Ext
|
|
* @method urlDecode
|
|
* @inheritdoc Ext.Object#fromQueryString
|
|
* @deprecated 4.0.0 Use {@link Ext.Object#fromQueryString} instead
|
|
*/
|
|
urlDecode: function() {
|
|
return Ext.Object.fromQueryString.apply(Ext.Object, arguments);
|
|
},
|
|
/**
|
|
* @method getScrollbarSize
|
|
* @member Ext
|
|
* Returns the size of the browser scrollbars. This can differ depending on
|
|
* operating system settings, such as the theme or font size.
|
|
* @param {Boolean} [force] true to force a recalculation of the value.
|
|
* @return {Object} An object containing scrollbar sizes.
|
|
* @return {Number} return.width The width of the vertical scrollbar.
|
|
* @return {Number} return.height The height of the horizontal scrollbar.
|
|
*/
|
|
getScrollbarSize: function(force) {
|
|
if (!Ext.isDomReady) {
|
|
Ext.raise("getScrollbarSize called before DomReady");
|
|
}
|
|
var scrollbarSize = Ext._scrollbarSize;
|
|
if (force || !scrollbarSize) {
|
|
var db = document.body,
|
|
div = document.createElement('div');
|
|
div.style.width = div.style.height = '100px';
|
|
div.style.overflow = 'scroll';
|
|
div.style.position = 'absolute';
|
|
db.appendChild(div);
|
|
// now we can measure the div...
|
|
// at least in iE9 the div is not 100px - the scrollbar size is removed!
|
|
Ext._scrollbarSize = scrollbarSize = {
|
|
width: div.offsetWidth - div.clientWidth,
|
|
height: div.offsetHeight - div.clientHeight
|
|
};
|
|
db.removeChild(div);
|
|
}
|
|
return scrollbarSize;
|
|
},
|
|
/**
|
|
* @method typeOf
|
|
* @member Ext
|
|
* Returns the type of the given variable in string format. List of possible values are:
|
|
*
|
|
* - `undefined`: If the given value is `undefined`
|
|
* - `null`: If the given value is `null`
|
|
* - `string`: If the given value is a string
|
|
* - `number`: If the given value is a number
|
|
* - `boolean`: If the given value is a boolean value
|
|
* - `date`: If the given value is a `Date` object
|
|
* - `function`: If the given value is a function reference
|
|
* - `object`: If the given value is an object
|
|
* - `array`: If the given value is an array
|
|
* - `regexp`: If the given value is a regular expression
|
|
* - `element`: If the given value is a DOM Element
|
|
* - `textnode`: If the given value is a DOM text node and contains something other than whitespace
|
|
* - `whitespace`: If the given value is a DOM text node and contains only whitespace
|
|
*
|
|
* @param {Object} value
|
|
* @return {String}
|
|
*/
|
|
typeOf: (function() {
|
|
var nonWhitespaceRe = /\S/,
|
|
toString = Object.prototype.toString,
|
|
typeofTypes = {
|
|
number: 1,
|
|
string: 1,
|
|
'boolean': 1,
|
|
'undefined': 1
|
|
},
|
|
toStringTypes = {
|
|
'[object Array]': 'array',
|
|
'[object Date]': 'date',
|
|
'[object Boolean]': 'boolean',
|
|
'[object Number]': 'number',
|
|
'[object RegExp]': 'regexp'
|
|
};
|
|
return function(value) {
|
|
if (value === null) {
|
|
return 'null';
|
|
}
|
|
var type = typeof value,
|
|
ret, typeToString;
|
|
if (typeofTypes[type]) {
|
|
return type;
|
|
}
|
|
ret = toStringTypes[typeToString = toString.call(value)];
|
|
if (ret) {
|
|
return ret;
|
|
}
|
|
if (type === 'function') {
|
|
return 'function';
|
|
}
|
|
if (type === 'object') {
|
|
if (value.nodeType !== undefined) {
|
|
if (value.nodeType === 3) {
|
|
return nonWhitespaceRe.test(value.nodeValue) ? 'textnode' : 'whitespace';
|
|
} else {
|
|
return 'element';
|
|
}
|
|
}
|
|
return 'object';
|
|
}
|
|
Ext.raise({
|
|
sourceClass: 'Ext',
|
|
sourceMethod: 'typeOf',
|
|
msg: 'Failed to determine the type of "' + value + '".'
|
|
});
|
|
return typeToString;
|
|
};
|
|
}()),
|
|
/**
|
|
* A global factory method to instantiate a class from a config object. For example,
|
|
* these two calls are equivalent:
|
|
*
|
|
* Ext.factory({ text: 'My Button' }, 'Ext.Button');
|
|
* Ext.create('Ext.Button', { text: 'My Button' });
|
|
*
|
|
* If an existing instance is also specified, it will be updated with the supplied config object. This is useful
|
|
* if you need to either create or update an object, depending on if an instance already exists. For example:
|
|
*
|
|
* var button;
|
|
* button = Ext.factory({ text: 'New Button' }, 'Ext.Button', button); // Button created
|
|
* button = Ext.factory({ text: 'Updated Button' }, 'Ext.Button', button); // Button updated
|
|
*
|
|
* @param {Object} config The config object to instantiate or update an instance with.
|
|
* @param {String} [classReference] The class to instantiate from (if there is a default).
|
|
* @param {Object} [instance] The instance to update.
|
|
* @param [aliasNamespace]
|
|
* @member Ext
|
|
*/
|
|
factory: function(config, classReference, instance, aliasNamespace) {
|
|
var manager = Ext.ClassManager,
|
|
newInstance;
|
|
// If config is falsy or a valid instance, destroy the current instance
|
|
// (if it exists) and replace with the new one
|
|
if (!config || config.isInstance) {
|
|
if (instance && instance !== config) {
|
|
instance.destroy();
|
|
}
|
|
return config;
|
|
}
|
|
if (aliasNamespace) {
|
|
// If config is a string value, treat it as an alias
|
|
if (typeof config === 'string') {
|
|
return manager.instantiateByAlias(aliasNamespace + '.' + config);
|
|
}
|
|
// Same if 'type' is given in config
|
|
else if (Ext.isObject(config) && 'type' in config) {
|
|
return manager.instantiateByAlias(aliasNamespace + '.' + config.type, config);
|
|
}
|
|
}
|
|
if (config === true) {
|
|
if (!instance && !classReference) {
|
|
Ext.raise('[Ext.factory] Cannot determine type of class to create');
|
|
}
|
|
return instance || Ext.create(classReference);
|
|
}
|
|
if (!Ext.isObject(config)) {
|
|
Ext.raise("Invalid config, must be a valid config object");
|
|
}
|
|
if ('xtype' in config) {
|
|
newInstance = manager.instantiateByAlias('widget.' + config.xtype, config);
|
|
} else if ('xclass' in config) {
|
|
newInstance = Ext.create(config.xclass, config);
|
|
}
|
|
if (newInstance) {
|
|
if (instance) {
|
|
instance.destroy();
|
|
}
|
|
return newInstance;
|
|
}
|
|
if (instance) {
|
|
return instance.setConfig(config);
|
|
}
|
|
return Ext.create(classReference, config);
|
|
},
|
|
/**
|
|
* @method log
|
|
* @member Ext
|
|
* Logs a message. If a console is present it will be used. On Opera, the method
|
|
* "opera.postError" is called. In other cases, the message is logged to an array
|
|
* "Ext.log.out". An attached debugger can watch this array and view the log. The
|
|
* log buffer is limited to a maximum of "Ext.log.max" entries (defaults to 250).
|
|
*
|
|
* If additional parameters are passed, they are joined and appended to the message.
|
|
* A technique for tracing entry and exit of a function is this:
|
|
*
|
|
* function foo () {
|
|
* Ext.log({ indent: 1 }, '>> foo');
|
|
*
|
|
* // log statements in here or methods called from here will be indented
|
|
* // by one step
|
|
*
|
|
* Ext.log({ outdent: 1 }, '<< foo');
|
|
* }
|
|
*
|
|
* This method does nothing in a release build.
|
|
*
|
|
* @param {String/Object} [options] The message to log or an options object with any
|
|
* of the following properties:
|
|
*
|
|
* - `msg`: The message to log (required).
|
|
* - `level`: One of: "error", "warn", "info" or "log" (the default is "log").
|
|
* - `dump`: An object to dump to the log as part of the message.
|
|
* - `stack`: True to include a stack trace in the log.
|
|
* - `indent`: Cause subsequent log statements to be indented one step.
|
|
* - `outdent`: Cause this and following statements to be one step less indented.
|
|
*
|
|
* @param {String...} [message] The message to log (required unless specified in
|
|
* options object).
|
|
*/
|
|
log: (function() {
|
|
/*
|
|
* Iterate through an object to dump its content into a string.
|
|
* For example:
|
|
* {
|
|
* style: {
|
|
* lineWidth: 1
|
|
* },
|
|
* label: {},
|
|
* marker: {
|
|
* strokeStyle: "#555",
|
|
* radius: 3,
|
|
* size: 3
|
|
* },
|
|
* subStyle: {
|
|
* fillStyle: [
|
|
* 0: "#133987",
|
|
* 1: "#1c55ca",
|
|
* 2: "#4d7fe6"
|
|
* ]
|
|
* },
|
|
* markerSubStyle: {}
|
|
* }
|
|
*
|
|
* @param {Object} object The object to iterate
|
|
* @param {Number} [level] Current level of identation (and recursion). Default is 0.
|
|
* @param {Number} [maxLevel] Maximum level of recursion. Default is 3.
|
|
* @param {Boolean} [withFunctions] Include functions in the output.
|
|
* @return {String} The string with the contents of the object
|
|
*/
|
|
var primitiveRe = /string|number|boolean/;
|
|
function dumpObject(object, level, maxLevel, withFunctions) {
|
|
var member, type, value, name, prefix, suffix,
|
|
members = [];
|
|
if (Ext.isArray(object)) {
|
|
prefix = '[';
|
|
suffix = ']';
|
|
} else if (Ext.isObject(object)) {
|
|
prefix = '{';
|
|
suffix = '}';
|
|
}
|
|
if (!maxLevel) {
|
|
maxLevel = 3;
|
|
}
|
|
if (level > maxLevel) {
|
|
return prefix + '...' + suffix;
|
|
}
|
|
level = level || 1;
|
|
var spacer = (new Array(level)).join(' ');
|
|
// Cannot use Ext.encode since it can recurse endlessly
|
|
for (name in object) {
|
|
if (object.hasOwnProperty(name)) {
|
|
value = object[name];
|
|
type = typeof value;
|
|
if (type === 'function') {
|
|
if (!withFunctions) {
|
|
|
|
continue;
|
|
}
|
|
member = type;
|
|
} else if (type === 'undefined') {
|
|
member = type;
|
|
} else if (value === null || primitiveRe.test(type) || Ext.isDate(value)) {
|
|
member = Ext.encode(value);
|
|
} else if (Ext.isArray(value)) {
|
|
member = dumpObject(value, level + 1, maxLevel, withFunctions);
|
|
} else if (Ext.isObject(value)) {
|
|
member = dumpObject(value, level + 1, maxLevel, withFunctions);
|
|
} else {
|
|
member = type;
|
|
}
|
|
members.push(spacer + name + ': ' + member);
|
|
}
|
|
}
|
|
// or Ext.encode(name)
|
|
if (members.length) {
|
|
return prefix + '\n ' + members.join(',\n ') + '\n' + spacer + suffix;
|
|
}
|
|
return prefix + suffix;
|
|
}
|
|
function log(message) {
|
|
var options, dump,
|
|
con = Ext.global.console,
|
|
level = 'log',
|
|
indent = log.indent || 0,
|
|
prefix, stack, fn, out, max;
|
|
log.indent = indent;
|
|
if (typeof message !== 'string') {
|
|
options = message;
|
|
message = options.msg || '';
|
|
level = options.level || level;
|
|
dump = options.dump;
|
|
stack = options.stack;
|
|
prefix = options.prefix;
|
|
fn = options.fn;
|
|
if (options.indent) {
|
|
++log.indent;
|
|
} else if (options.outdent) {
|
|
log.indent = indent = Math.max(indent - 1, 0);
|
|
}
|
|
if (dump && !(con && con.dir)) {
|
|
message += dumpObject(dump);
|
|
dump = null;
|
|
}
|
|
}
|
|
if (arguments.length > 1) {
|
|
message += Array.prototype.slice.call(arguments, 1).join('');
|
|
}
|
|
if (prefix) {
|
|
message = prefix + ' - ' + message;
|
|
}
|
|
message = indent ? Ext.String.repeat(' ', log.indentSize * indent) + message : message;
|
|
// w/o console, all messages are equal, so munge the level into the message:
|
|
if (level !== 'log') {
|
|
message = '[' + level.charAt(0).toUpperCase() + '] ' + message;
|
|
}
|
|
if (fn) {
|
|
message += '\nCaller: ' + fn.toString();
|
|
}
|
|
// Not obvious, but 'console' comes and goes when Firebug is turned on/off, so
|
|
// an early test may fail either direction if Firebug is toggled.
|
|
//
|
|
if (con) {
|
|
// if (Firebug-like console)
|
|
if (con[level]) {
|
|
con[level](message);
|
|
} else {
|
|
con.log(message);
|
|
}
|
|
if (dump) {
|
|
con.dir(dump);
|
|
}
|
|
if (stack && con.trace) {
|
|
// Firebug's console.error() includes a trace already...
|
|
if (!con.firebug || level !== 'error') {
|
|
con.trace();
|
|
}
|
|
}
|
|
} else if (Ext.isOpera) {
|
|
opera.postError(message);
|
|
} else // jshint ignore:line
|
|
{
|
|
out = log.out;
|
|
max = log.max;
|
|
if (out.length >= max) {
|
|
// this formula allows out.max to change (via debugger), where the
|
|
// more obvious "max/4" would not quite be the same
|
|
Ext.Array.erase(out, 0, out.length - 3 * Math.floor(max / 4));
|
|
}
|
|
// keep newest 75%
|
|
out.push(message);
|
|
}
|
|
// Mostly informational, but the Ext.Error notifier uses them:
|
|
++log.count;
|
|
++log.counters[level];
|
|
}
|
|
function logx(level, args) {
|
|
if (typeof args[0] === 'string') {
|
|
args.unshift({});
|
|
}
|
|
args[0].level = level;
|
|
log.apply(this, args);
|
|
}
|
|
log.error = function() {
|
|
logx('error', Array.prototype.slice.call(arguments));
|
|
};
|
|
log.info = function() {
|
|
logx('info', Array.prototype.slice.call(arguments));
|
|
};
|
|
log.warn = function() {
|
|
logx('warn', Array.prototype.slice.call(arguments));
|
|
};
|
|
log.count = 0;
|
|
log.counters = {
|
|
error: 0,
|
|
warn: 0,
|
|
info: 0,
|
|
log: 0
|
|
};
|
|
log.indentSize = 2;
|
|
log.out = [];
|
|
log.max = 750;
|
|
return log;
|
|
}()) || (function() {
|
|
var nullLog = function() {};
|
|
nullLog.info = nullLog.warn = nullLog.error = Ext.emptyFn;
|
|
return nullLog;
|
|
}())
|
|
});
|
|
|
|
/**
|
|
* @class Ext.Version
|
|
*
|
|
* A utility class that wraps around a version number string and provides convenient methods
|
|
* to perform comparisons. A version number is expressed in the following general format:
|
|
*
|
|
* major[.minor[.patch[.build[release]]]]
|
|
*
|
|
* The `Version` instance holds various readonly properties that contain the digested form
|
|
* of the version string. The numeric componnets of `major`, `minor`, `patch` and `build`
|
|
* as well as the textual suffix called `release`.
|
|
*
|
|
* Not depicted in the above syntax are three possible prefixes used to control partial
|
|
* matching. These are '^' (the default), '>' and '~'. These are discussed below.
|
|
*
|
|
* Examples:
|
|
*
|
|
* var version = new Ext.Version('1.0.2beta'); // or maybe "1.0" or "1.2.3.4RC"
|
|
* console.log("Version is " + version); // Version is 1.0.2beta
|
|
*
|
|
* console.log(version.getMajor()); // 1
|
|
* console.log(version.getMinor()); // 0
|
|
* console.log(version.getPatch()); // 2
|
|
* console.log(version.getBuild()); // 0
|
|
* console.log(version.getRelease()); // beta
|
|
*
|
|
* The understood values of `release` are assigned numberic equivalents for the sake of
|
|
* comparsion. The order of these from smallest to largest is as follows:
|
|
*
|
|
* * `"dev"`
|
|
* * `"alpha"` or `"a"`
|
|
* * `"beta"` or `"b"`
|
|
* * `"RC"` or `"rc"`
|
|
* * `"#"`
|
|
* * `"pl"` or `"p"`
|
|
*
|
|
* Any other (unrecognized) suffix is consider greater than any of these.
|
|
*
|
|
* ## Comparisons
|
|
* There are two forms of comparison that are commonly needed: full and partial. Full
|
|
* comparison is simpler and is also the default.
|
|
*
|
|
* Example:
|
|
*
|
|
* var version = new Ext.Version('1.0.2beta');
|
|
*
|
|
* console.log(version.isGreaterThan('1.0.1')); // True
|
|
* console.log(version.isGreaterThan('1.0.2alpha')); // True
|
|
* console.log(version.isGreaterThan('1.0.2RC')); // False
|
|
* console.log(version.isGreaterThan('1.0.2')); // False
|
|
* console.log(version.isLessThan('1.0.2')); // True
|
|
*
|
|
* console.log(version.match(1.0)); // True (using a Number)
|
|
* console.log(version.match('1.0.2')); // True (using a String)
|
|
*
|
|
* These comparisons are ultimately implemented by {@link Ext.Version#compareTo compareTo}
|
|
* which returns -1, 0 or 1 depending on whether the `Version' instance is less than, equal
|
|
* to, or greater than the given "other" version.
|
|
*
|
|
* For example:
|
|
*
|
|
* var n = version.compareTo('1.0.1'); // == 1 (because 1.0.2beta > 1.0.1)
|
|
*
|
|
* n = version.compareTo('1.1'); // == -1
|
|
* n = version.compareTo(version); // == 0
|
|
*
|
|
* ### Partial Comparisons
|
|
* By default, unspecified version number fields are filled with 0. In other words, the
|
|
* version number fields are 0-padded on the right or a "lower bound". This produces the
|
|
* most commonly used forms of comparsion:
|
|
*
|
|
* var ver = new Version('4.2');
|
|
*
|
|
* n = ver.compareTo('4.2.1'); // == -1 (4.2 promotes to 4.2.0 and is less than 4.2.1)
|
|
*
|
|
* There are two other ways to interpret comparisons of versions of different length. The
|
|
* first of these is to change the padding on the right to be a large number (scuh as
|
|
* Infinity) instead of 0. This has the effect of making the version an upper bound. For
|
|
* example:
|
|
*
|
|
* var ver = new Version('^4.2'); // NOTE: the '^' prefix used
|
|
*
|
|
* n = ver.compareTo('4.3'); // == -1 (less than 4.3)
|
|
*
|
|
* n = ver.compareTo('4.2'); // == 1 (greater than all 4.2's)
|
|
* n = ver.compareTo('4.2.1'); // == 1
|
|
* n = ver.compareTo('4.2.9'); // == 1
|
|
*
|
|
* The second way to interpret this comparison is to ignore the extra digits, making the
|
|
* match a prefix match. For example:
|
|
*
|
|
* var ver = new Version('~4.2'); // NOTE: the '~' prefix used
|
|
*
|
|
* n = ver.compareTo('4.3'); // == -1
|
|
*
|
|
* n = ver.compareTo('4.2'); // == 0
|
|
* n = ver.compareTo('4.2.1'); // == 0
|
|
*
|
|
* This final form can be useful when version numbers contain more components than are
|
|
* important for certain comparisons. For example, the full version of Ext JS 4.2.1 is
|
|
* "4.2.1.883" where 883 is the `build` number.
|
|
*
|
|
* This is how to create a "partial" `Version` and compare versions to it:
|
|
*
|
|
* var version421ish = new Version('~4.2.1');
|
|
*
|
|
* n = version421ish.compareTo('4.2.1.883'); // == 0
|
|
* n = version421ish.compareTo('4.2.1.2'); // == 0
|
|
* n = version421ish.compareTo('4.2.1'); // == 0
|
|
*
|
|
* n = version421ish.compareTo('4.2'); // == 1
|
|
*
|
|
* In the above example, '4.2.1.2' compares as equal to '4.2.1' because digits beyond the
|
|
* given "4.2.1" are ignored. However, '4.2' is less than the '4.2.1' prefix; its missing
|
|
* digit is filled with 0.
|
|
*/
|
|
(function() {
|
|
// @define Ext.Version
|
|
// @require Ext.String
|
|
var // used by checkVersion to avoid temp arrays:
|
|
checkVerTemp = [
|
|
''
|
|
],
|
|
endOfVersionRe = /([^\d\.])/,
|
|
notDigitsRe = /[^\d]/g,
|
|
plusMinusRe = /[\-+]/g,
|
|
stripRe = /\s/g,
|
|
underscoreRe = /_/g,
|
|
toolkitNames = {
|
|
classic: 1,
|
|
modern: 1
|
|
},
|
|
Version;
|
|
Ext.Version = Version = function(version, defaultMode) {
|
|
var me = this,
|
|
padModes = me.padModes,
|
|
ch, i, pad, parts, release, releaseStartIndex, ver;
|
|
if (version.isVersion) {
|
|
version = version.version;
|
|
}
|
|
me.version = ver = String(version).toLowerCase().replace(underscoreRe, '.').replace(plusMinusRe, '');
|
|
ch = ver.charAt(0);
|
|
if (ch in padModes) {
|
|
ver = ver.substring(1);
|
|
pad = padModes[ch];
|
|
} else {
|
|
pad = defaultMode ? padModes[defaultMode] : 0;
|
|
}
|
|
// careful - NaN is falsey!
|
|
me.pad = pad;
|
|
releaseStartIndex = ver.search(endOfVersionRe);
|
|
me.shortVersion = ver;
|
|
if (releaseStartIndex !== -1) {
|
|
me.release = release = ver.substr(releaseStartIndex, version.length);
|
|
me.shortVersion = ver.substr(0, releaseStartIndex);
|
|
release = Version.releaseValueMap[release] || release;
|
|
}
|
|
me.releaseValue = release || pad;
|
|
me.shortVersion = me.shortVersion.replace(notDigitsRe, '');
|
|
/**
|
|
* @property {Number[]} parts
|
|
* The split array of version number components found in the version string.
|
|
* For example, for "1.2.3", this would be `[1, 2, 3]`.
|
|
* @readonly
|
|
* @private
|
|
*/
|
|
me.parts = parts = ver.split('.');
|
|
for (i = parts.length; i--; ) {
|
|
parts[i] = parseInt(parts[i], 10);
|
|
}
|
|
if (pad === Infinity) {
|
|
// have to add this to the end to create an upper bound:
|
|
parts.push(pad);
|
|
}
|
|
/**
|
|
* @property {Number} major
|
|
* The first numeric part of the version number string.
|
|
* @readonly
|
|
*/
|
|
me.major = parts[0] || pad;
|
|
/**
|
|
* @property {Number} [minor]
|
|
* The second numeric part of the version number string.
|
|
* @readonly
|
|
*/
|
|
me.minor = parts[1] || pad;
|
|
/**
|
|
* @property {Number} [patch]
|
|
* The third numeric part of the version number string.
|
|
* @readonly
|
|
*/
|
|
me.patch = parts[2] || pad;
|
|
/**
|
|
* @property {Number} [build]
|
|
* The fourth numeric part of the version number string.
|
|
* @readonly
|
|
*/
|
|
me.build = parts[3] || pad;
|
|
return me;
|
|
};
|
|
Version.prototype = {
|
|
isVersion: true,
|
|
padModes: {
|
|
'~': NaN,
|
|
'^': Infinity
|
|
},
|
|
/**
|
|
* @property {String} [release=""]
|
|
* The release level. The following values are understood:
|
|
*
|
|
* * `"dev"`
|
|
* * `"alpha"` or `"a"`
|
|
* * `"beta"` or `"b"`
|
|
* * `"RC"` or `"rc"`
|
|
* * `"#"`
|
|
* * `"pl"` or `"p"`
|
|
* @readonly
|
|
*/
|
|
release: '',
|
|
/**
|
|
* Compares this version instance to the specified `other` version.
|
|
*
|
|
* @param {String/Number/Ext.Version} other The other version to which to compare.
|
|
* @return {Number} -1 if this version is less than the target version, 1 if this
|
|
* version is greater, and 0 if they are equal.
|
|
*/
|
|
compareTo: function(other) {
|
|
// "lhs" == "left-hand-side"
|
|
// "rhs" == "right-hand-side"
|
|
var me = this,
|
|
lhsPad = me.pad,
|
|
lhsParts = me.parts,
|
|
lhsLength = lhsParts.length,
|
|
rhsVersion = other.isVersion ? other : new Version(other),
|
|
rhsPad = rhsVersion.pad,
|
|
rhsParts = rhsVersion.parts,
|
|
rhsLength = rhsParts.length,
|
|
length = Math.max(lhsLength, rhsLength),
|
|
i, lhs, rhs;
|
|
for (i = 0; i < length; i++) {
|
|
lhs = (i < lhsLength) ? lhsParts[i] : lhsPad;
|
|
rhs = (i < rhsLength) ? rhsParts[i] : rhsPad;
|
|
// When one or both of the values are NaN these tests produce false
|
|
// and we end up treating NaN as equal to anything.
|
|
if (lhs < rhs) {
|
|
return -1;
|
|
}
|
|
if (lhs > rhs) {
|
|
return 1;
|
|
}
|
|
}
|
|
// same comments about NaN apply here...
|
|
lhs = me.releaseValue;
|
|
rhs = rhsVersion.releaseValue;
|
|
if (lhs < rhs) {
|
|
return -1;
|
|
}
|
|
if (lhs > rhs) {
|
|
return 1;
|
|
}
|
|
return 0;
|
|
},
|
|
/**
|
|
* Override the native `toString` method
|
|
* @private
|
|
* @return {String} version
|
|
*/
|
|
toString: function() {
|
|
return this.version;
|
|
},
|
|
/**
|
|
* Override the native `valueOf` method
|
|
* @private
|
|
* @return {String} version
|
|
*/
|
|
valueOf: function() {
|
|
return this.version;
|
|
},
|
|
/**
|
|
* Returns the major component value.
|
|
* @return {Number}
|
|
*/
|
|
getMajor: function() {
|
|
return this.major;
|
|
},
|
|
/**
|
|
* Returns the minor component value.
|
|
* @return {Number}
|
|
*/
|
|
getMinor: function() {
|
|
return this.minor;
|
|
},
|
|
/**
|
|
* Returns the patch component value.
|
|
* @return {Number}
|
|
*/
|
|
getPatch: function() {
|
|
return this.patch;
|
|
},
|
|
/**
|
|
* Returns the build component value.
|
|
* @return {Number}
|
|
*/
|
|
getBuild: function() {
|
|
return this.build;
|
|
},
|
|
/**
|
|
* Returns the release component text (e.g., "beta").
|
|
* @return {String}
|
|
*/
|
|
getRelease: function() {
|
|
return this.release;
|
|
},
|
|
/**
|
|
* Returns the release component value for comparison purposes.
|
|
* @return {Number/String}
|
|
*/
|
|
getReleaseValue: function() {
|
|
return this.releaseValue;
|
|
},
|
|
/**
|
|
* Returns whether this version if greater than the supplied argument
|
|
* @param {String/Number} target The version to compare with
|
|
* @return {Boolean} `true` if this version if greater than the target, `false` otherwise
|
|
*/
|
|
isGreaterThan: function(target) {
|
|
return this.compareTo(target) > 0;
|
|
},
|
|
/**
|
|
* Returns whether this version if greater than or equal to the supplied argument
|
|
* @param {String/Number} target The version to compare with
|
|
* @return {Boolean} `true` if this version if greater than or equal to the target, `false` otherwise
|
|
*/
|
|
isGreaterThanOrEqual: function(target) {
|
|
return this.compareTo(target) >= 0;
|
|
},
|
|
/**
|
|
* Returns whether this version if smaller than the supplied argument
|
|
* @param {String/Number} target The version to compare with
|
|
* @return {Boolean} `true` if this version if smaller than the target, `false` otherwise
|
|
*/
|
|
isLessThan: function(target) {
|
|
return this.compareTo(target) < 0;
|
|
},
|
|
/**
|
|
* Returns whether this version if less than or equal to the supplied argument
|
|
* @param {String/Number} target The version to compare with
|
|
* @return {Boolean} `true` if this version if less than or equal to the target, `false` otherwise
|
|
*/
|
|
isLessThanOrEqual: function(target) {
|
|
return this.compareTo(target) <= 0;
|
|
},
|
|
/**
|
|
* Returns whether this version equals to the supplied argument
|
|
* @param {String/Number} target The version to compare with
|
|
* @return {Boolean} `true` if this version equals to the target, `false` otherwise
|
|
*/
|
|
equals: function(target) {
|
|
return this.compareTo(target) === 0;
|
|
},
|
|
/**
|
|
* Returns whether this version matches the supplied argument. Example:
|
|
*
|
|
* var version = new Ext.Version('1.0.2beta');
|
|
* console.log(version.match(1)); // true
|
|
* console.log(version.match(1.0)); // true
|
|
* console.log(version.match('1.0.2')); // true
|
|
* console.log(version.match('1.0.2RC')); // false
|
|
*
|
|
* @param {String/Number} target The version to compare with
|
|
* @return {Boolean} `true` if this version matches the target, `false` otherwise
|
|
*/
|
|
match: function(target) {
|
|
target = String(target);
|
|
return this.version.substr(0, target.length) === target;
|
|
},
|
|
/**
|
|
* Returns this format: [major, minor, patch, build, release]. Useful for comparison.
|
|
* @return {Number[]}
|
|
*/
|
|
toArray: function() {
|
|
var me = this;
|
|
return [
|
|
me.getMajor(),
|
|
me.getMinor(),
|
|
me.getPatch(),
|
|
me.getBuild(),
|
|
me.getRelease()
|
|
];
|
|
},
|
|
/**
|
|
* Returns shortVersion version without dots and release
|
|
* @return {String}
|
|
*/
|
|
getShortVersion: function() {
|
|
return this.shortVersion;
|
|
},
|
|
/**
|
|
* Convenient alias to {@link Ext.Version#isGreaterThan isGreaterThan}
|
|
* @param {String/Number/Ext.Version} target
|
|
* @return {Boolean}
|
|
*/
|
|
gt: function(target) {
|
|
return this.compareTo(target) > 0;
|
|
},
|
|
/**
|
|
* Convenient alias to {@link Ext.Version#isLessThan isLessThan}
|
|
* @param {String/Number/Ext.Version} target
|
|
* @return {Boolean}
|
|
*/
|
|
lt: function(target) {
|
|
return this.compareTo(target) < 0;
|
|
},
|
|
/**
|
|
* Convenient alias to {@link Ext.Version#isGreaterThanOrEqual isGreaterThanOrEqual}
|
|
* @param {String/Number/Ext.Version} target
|
|
* @return {Boolean}
|
|
*/
|
|
gtEq: function(target) {
|
|
return this.compareTo(target) >= 0;
|
|
},
|
|
/**
|
|
* Convenient alias to {@link Ext.Version#isLessThanOrEqual isLessThanOrEqual}
|
|
* @param {String/Number/Ext.Version} target
|
|
* @return {Boolean}
|
|
*/
|
|
ltEq: function(target) {
|
|
return this.compareTo(target) <= 0;
|
|
}
|
|
};
|
|
Ext.apply(Version, {
|
|
aliases: {
|
|
from: {
|
|
extjs: 'ext',
|
|
core: 'core',
|
|
touch: 'modern'
|
|
},
|
|
to: {
|
|
ext: [
|
|
'extjs'
|
|
],
|
|
'core': [
|
|
'core'
|
|
],
|
|
modern: [
|
|
'touch'
|
|
]
|
|
}
|
|
},
|
|
/**
|
|
* @private
|
|
*/
|
|
releaseValueMap: {
|
|
dev: -6,
|
|
alpha: -5,
|
|
a: -5,
|
|
beta: -4,
|
|
b: -4,
|
|
rc: -3,
|
|
'#': -2,
|
|
p: -1,
|
|
pl: -1
|
|
},
|
|
/**
|
|
* Converts a version component to a comparable value
|
|
*
|
|
* @static
|
|
* @param {Object} value The value to convert
|
|
* @return {Object}
|
|
*/
|
|
getComponentValue: function(value) {
|
|
return !value ? 0 : (isNaN(value) ? this.releaseValueMap[value] || value : parseInt(value, 10));
|
|
},
|
|
/**
|
|
* Compare 2 specified versions by ensuring the first parameter is a `Version`
|
|
* instance and then calling the `compareTo` method.
|
|
*
|
|
* @static
|
|
* @param {String} current The current version to compare to
|
|
* @param {String} target The target version to compare to
|
|
* @return {Number} Returns -1 if the current version is smaller than the target version, 1 if greater, and 0 if they're equivalent
|
|
*/
|
|
compare: function(current, target) {
|
|
var ver = current.isVersion ? current : new Version(current);
|
|
return ver.compareTo(target);
|
|
},
|
|
set: function(collection, packageName, version) {
|
|
var aliases = Version.aliases.to[packageName],
|
|
ver = version.isVersion ? version : new Version(version),
|
|
i;
|
|
collection[packageName] = ver;
|
|
if (aliases) {
|
|
for (i = aliases.length; i-- > 0; ) {
|
|
collection[aliases[i]] = ver;
|
|
}
|
|
}
|
|
return ver;
|
|
}
|
|
});
|
|
/**
|
|
* @class Ext
|
|
*/
|
|
Ext.apply(Ext, {
|
|
/**
|
|
* @private
|
|
*/
|
|
compatVersions: {},
|
|
/**
|
|
* @private
|
|
*
|
|
* Object containing version information for all packages utilized by your
|
|
* application.
|
|
*
|
|
* For a public getter, please see `Ext.getVersion()`.
|
|
*/
|
|
versions: {},
|
|
/**
|
|
* @private
|
|
*/
|
|
lastRegisteredVersion: null,
|
|
/**
|
|
* Get the compatibility level (a version number) for the given package name. If
|
|
* none has been registered with `Ext.setCompatVersion` then `Ext.getVersion` is
|
|
* used to get the current version.
|
|
*
|
|
* @param {String} packageName The package name, e.g. 'core', 'touch', 'ext'.
|
|
* @since 5.0.0
|
|
* @private
|
|
*/
|
|
getCompatVersion: function(packageName) {
|
|
var versions = Ext.compatVersions,
|
|
compat;
|
|
if (!packageName) {
|
|
compat = versions.ext || versions.touch || versions.core;
|
|
} else {
|
|
compat = versions[Version.aliases.from[packageName] || packageName];
|
|
}
|
|
return compat || Ext.getVersion(packageName);
|
|
},
|
|
/**
|
|
* Set the compatibility level (a version number) for the given package name.
|
|
*
|
|
* @param {String} packageName The package name, e.g. 'core', 'touch', 'ext'.
|
|
* @param {String/Ext.Version} version The version, e.g. '4.2'.
|
|
* @since 5.0.0
|
|
* @private
|
|
*/
|
|
setCompatVersion: function(packageName, version) {
|
|
Version.set(Ext.compatVersions, packageName, version);
|
|
},
|
|
/**
|
|
* Set version number for the given package name.
|
|
*
|
|
* @param {String} packageName The package name, e.g. 'core', 'touch', 'ext'.
|
|
* @param {String/Ext.Version} version The version, e.g. '1.2.3alpha', '2.4.0-dev'.
|
|
* @return {Ext}
|
|
*/
|
|
setVersion: function(packageName, version) {
|
|
if (packageName in toolkitNames) {
|
|
Ext.toolkit = packageName;
|
|
}
|
|
Ext.lastRegisteredVersion = Version.set(Ext.versions, packageName, version);
|
|
return this;
|
|
},
|
|
/**
|
|
* Get the version number of the supplied package name; will return the version of
|
|
* the framework.
|
|
*
|
|
* @param {String} [packageName] The package name, e.g., 'core', 'touch', 'ext'.
|
|
* @return {Ext.Version} The version.
|
|
*/
|
|
getVersion: function(packageName) {
|
|
var versions = Ext.versions;
|
|
if (!packageName) {
|
|
return versions.ext || versions.touch || versions.core;
|
|
}
|
|
return versions[Version.aliases.from[packageName] || packageName];
|
|
},
|
|
/**
|
|
* This method checks the registered package versions against the provided version
|
|
* `specs`. A `spec` is either a string or an object indicating a boolean operator.
|
|
* This method accepts either form or an array of these as the first argument. The
|
|
* second argument applies only when the first is an array and indicates whether
|
|
* all `specs` must match or just one.
|
|
*
|
|
* ## Package Version Specifications
|
|
* The string form of a `spec` is used to indicate a version or range of versions
|
|
* for a particular package. This form of `spec` consists of three (3) parts:
|
|
*
|
|
* * Package name followed by "@". If not provided, the framework is assumed.
|
|
* * Minimum version.
|
|
* * Maximum version.
|
|
*
|
|
* At least one version number must be provided. If both minimum and maximum are
|
|
* provided, these must be separated by a "-".
|
|
*
|
|
* Some examples of package version specifications:
|
|
*
|
|
* 4.2.2 (exactly version 4.2.2 of the framework)
|
|
* 4.2.2+ (version 4.2.2 or higher of the framework)
|
|
* 4.2.2- (version 4.2.2 or higher of the framework)
|
|
* 4.2.1 - 4.2.3 (versions from 4.2.1 up to 4.2.3 of the framework)
|
|
* - 4.2.2 (any version up to version 4.2.1 of the framework)
|
|
*
|
|
* foo@1.0 (exactly version 1.0 of package "foo")
|
|
* foo@1.0-1.3 (versions 1.0 up to 1.3 of package "foo")
|
|
*
|
|
* **NOTE:** This syntax is the same as that used in Sencha Cmd's package
|
|
* requirements declarations.
|
|
*
|
|
* ## Boolean Operator Specifications
|
|
* Instead of a string, an object can be used to describe a boolean operation to
|
|
* perform on one or more `specs`. The operator is either **`and`** or **`or`**
|
|
* and can contain an optional **`not`**.
|
|
*
|
|
* For example:
|
|
*
|
|
* {
|
|
* not: true, // negates boolean result
|
|
* and: [
|
|
* '4.2.2',
|
|
* 'foo@1.0.1 - 2.0.1'
|
|
* ]
|
|
* }
|
|
*
|
|
* Each element of the array can in turn be a string or object spec. In other
|
|
* words, the value is passed to this method (recursively) as the first argument
|
|
* so these two calls are equivalent:
|
|
*
|
|
* Ext.checkVersion({
|
|
* not: true, // negates boolean result
|
|
* and: [
|
|
* '4.2.2',
|
|
* 'foo@1.0.1 - 2.0.1'
|
|
* ]
|
|
* });
|
|
*
|
|
* !Ext.checkVersion([
|
|
* '4.2.2',
|
|
* 'foo@1.0.1 - 2.0.1'
|
|
* ], true);
|
|
*
|
|
* ## Examples
|
|
*
|
|
* // A specific framework version
|
|
* Ext.checkVersion('4.2.2');
|
|
*
|
|
* // A range of framework versions:
|
|
* Ext.checkVersion('4.2.1-4.2.3');
|
|
*
|
|
* // A specific version of a package:
|
|
* Ext.checkVersion('foo@1.0.1');
|
|
*
|
|
* // A single spec that requires both a framework version and package
|
|
* // version range to match:
|
|
* Ext.checkVersion({
|
|
* and: [
|
|
* '4.2.2',
|
|
* 'foo@1.0.1-1.0.2'
|
|
* ]
|
|
* });
|
|
*
|
|
* // These checks can be nested:
|
|
* Ext.checkVersion({
|
|
* and: [
|
|
* '4.2.2', // exactly version 4.2.2 of the framework *AND*
|
|
* {
|
|
* // either (or both) of these package specs:
|
|
* or: [
|
|
* 'foo@1.0.1-1.0.2',
|
|
* 'bar@3.0+'
|
|
* ]
|
|
* }
|
|
* ]
|
|
* });
|
|
*
|
|
* ## Version Comparisons
|
|
* Version comparsions are assumed to be "prefix" based. That is to say, `"foo@1.2"`
|
|
* matches any version of "foo" that has a major version 1 and a minor version of 2.
|
|
*
|
|
* This also applies to ranges. For example `"foo@1.2-2.2"` matches all versions
|
|
* of "foo" from 1.2 up to 2.2 regardless of the specific patch and build.
|
|
*
|
|
* ## Use in Overrides
|
|
* This methods primary use is in support of conditional overrides on an
|
|
* `Ext.define` declaration.
|
|
*
|
|
* @param {String/Array/Object} specs A version specification string, an object
|
|
* containing `or` or `and` with a value that is equivalent to `specs` or an array
|
|
* of either of these.
|
|
* @param {Boolean} [matchAll=false] Pass `true` to require all specs to match.
|
|
* @return {Boolean} True if `specs` matches the registered package versions.
|
|
*/
|
|
checkVersion: function(specs, matchAll) {
|
|
var isArray = Ext.isArray(specs),
|
|
aliases = Version.aliases.from,
|
|
compat = isArray ? specs : checkVerTemp,
|
|
length = compat.length,
|
|
versions = Ext.versions,
|
|
frameworkVer = versions.ext || versions.touch,
|
|
i, index, matches, minVer, maxVer, packageName, spec, range, ver;
|
|
if (!isArray) {
|
|
checkVerTemp[0] = specs;
|
|
}
|
|
for (i = 0; i < length; ++i) {
|
|
if (!Ext.isString(spec = compat[i])) {
|
|
matches = Ext.checkVersion(spec.and || spec.or, !spec.or);
|
|
if (spec.not) {
|
|
matches = !matches;
|
|
}
|
|
} else {
|
|
if (spec.indexOf(' ') >= 0) {
|
|
spec = spec.replace(stripRe, '');
|
|
}
|
|
// For "name@..." syntax, we need to find the package by the given name
|
|
// as a registered package.
|
|
index = spec.indexOf('@');
|
|
if (index < 0) {
|
|
range = spec;
|
|
ver = frameworkVer;
|
|
} else {
|
|
packageName = spec.substring(0, index);
|
|
if (!(ver = versions[aliases[packageName] || packageName])) {
|
|
// The package is not registered, so if we must matchAll then
|
|
// we are done - FAIL:
|
|
if (matchAll) {
|
|
return false;
|
|
}
|
|
// Otherwise this spec is not a match so we can move on to the
|
|
// next...
|
|
|
|
continue;
|
|
}
|
|
range = spec.substring(index + 1);
|
|
}
|
|
// Now look for a version, version range or partial range:
|
|
index = range.indexOf('-');
|
|
if (index < 0) {
|
|
// just a version or "1.0+"
|
|
if (range.charAt(index = range.length - 1) === '+') {
|
|
minVer = range.substring(0, index);
|
|
maxVer = null;
|
|
} else {
|
|
minVer = maxVer = range;
|
|
}
|
|
} else if (index > 0) {
|
|
// a range like "1.0-1.5" or "1.0-"
|
|
minVer = range.substring(0, index);
|
|
maxVer = range.substring(index + 1);
|
|
} else // may be empty
|
|
{
|
|
// an upper limit like "-1.5"
|
|
minVer = null;
|
|
maxVer = range.substring(index + 1);
|
|
}
|
|
matches = true;
|
|
if (minVer) {
|
|
minVer = new Version(minVer, '~');
|
|
// prefix matching
|
|
matches = minVer.ltEq(ver);
|
|
}
|
|
if (matches && maxVer) {
|
|
maxVer = new Version(maxVer, '~');
|
|
// prefix matching
|
|
matches = maxVer.gtEq(ver);
|
|
}
|
|
}
|
|
// string spec
|
|
if (matches) {
|
|
// spec matched and we are looking for any match, so we are GO!
|
|
if (!matchAll) {
|
|
return true;
|
|
}
|
|
} else if (matchAll) {
|
|
// spec does not match the registered package version
|
|
return false;
|
|
}
|
|
}
|
|
// In the loop above, for matchAll we return FALSE on mismatch, so getting
|
|
// here with matchAll means we had no mismatches. On the other hand, if we
|
|
// are !matchAll, we return TRUE on match and so we get here only if we found
|
|
// no matches.
|
|
return !!matchAll;
|
|
},
|
|
/**
|
|
* Create a closure for deprecated code.
|
|
*
|
|
* // This means Ext.oldMethod is only supported in 4.0.0beta and older.
|
|
* // If Ext.getVersion('extjs') returns a version that is later than '4.0.0beta', for example '4.0.0RC',
|
|
* // the closure will not be invoked
|
|
* Ext.deprecate('extjs', '4.0.0beta', function() {
|
|
* Ext.oldMethod = Ext.newMethod;
|
|
*
|
|
* ...
|
|
* });
|
|
*
|
|
* @param {String} packageName The package name
|
|
* @param {String} since The last version before it's deprecated
|
|
* @param {Function} closure The callback function to be executed with the specified version is less than the current version
|
|
* @param {Object} scope The execution scope (`this`) if the closure
|
|
* @private
|
|
*/
|
|
deprecate: function(packageName, since, closure, scope) {
|
|
if (Version.compare(Ext.getVersion(packageName), since) < 1) {
|
|
closure.call(scope);
|
|
}
|
|
}
|
|
});
|
|
}());
|
|
// End Versioning
|
|
// load the cmd-5 style app manifest metadata now, if available...
|
|
(function(manifest) {
|
|
var packages = (manifest && manifest.packages) || {},
|
|
compat = manifest && manifest.compatibility,
|
|
name, pkg;
|
|
for (name in packages) {
|
|
pkg = packages[name];
|
|
Ext.setVersion(name, pkg.version);
|
|
}
|
|
if (compat) {
|
|
if (Ext.isString(compat)) {
|
|
Ext.setCompatVersion('core', compat);
|
|
} else {
|
|
for (name in compat) {
|
|
Ext.setCompatVersion(name, compat[name]);
|
|
}
|
|
}
|
|
}
|
|
if (!packages.ext && !packages.touch) {
|
|
Ext.setVersion('ext', '6.2.0.981');
|
|
Ext.setVersion('core', '6.2.0.981');
|
|
}
|
|
})(Ext.manifest);
|
|
|
|
/**
|
|
* @class Ext.Config
|
|
* This class manages a config property. Instances of this type are created and cached as
|
|
* classes declare their config properties. One instance of this class is created per
|
|
* config property name.
|
|
*
|
|
* Ext.define('MyClass', {
|
|
* config: {
|
|
* foo: 42
|
|
* }
|
|
* });
|
|
*
|
|
* This uses the cached `Ext.Config` instance for the "foo" property.
|
|
*
|
|
* When config properties apply options to config properties a prototype chained object is
|
|
* created from the cached instance. For example:
|
|
*
|
|
* Ext.define('MyClass', {
|
|
* config: {
|
|
* foo: {
|
|
* $value: 42,
|
|
* lazy: true
|
|
* }
|
|
* }
|
|
* });
|
|
*
|
|
* This creates a prototype chain to the cached "foo" instance of `Ext.Config` and applies
|
|
* the `lazy` option to that new instance. This chained instance is then kept by the
|
|
* `Ext.Configurator` for that class.
|
|
* @private
|
|
*/
|
|
Ext.Config = function(name) {
|
|
// @define Ext.class.Config
|
|
// @define Ext.Config
|
|
var me = this,
|
|
capitalizedName = name.charAt(0).toUpperCase() + name.substr(1);
|
|
/**
|
|
* @property {String} name
|
|
* The name of this config property.
|
|
* @readonly
|
|
* @private
|
|
* @since 5.0.0
|
|
*/
|
|
me.name = name;
|
|
/**
|
|
* @property {Object} names
|
|
* This object holds the cached names used to lookup properties or methods for this
|
|
* config property. The properties of this object are explained in the context of an
|
|
* example property named "foo".
|
|
*
|
|
* @property {String} names.internal The default backing property ("_foo").
|
|
*
|
|
* @property {String} names.initializing The property that is `true` when the config
|
|
* is being initialized ("isFooInitializing").
|
|
*
|
|
* @property {String} names.apply The name of the applier method ("applyFoo").
|
|
*
|
|
* @property {String} names.update The name of the updater method ("updateFoo").
|
|
*
|
|
* @property {String} names.get The name of the getter method ("getFoo").
|
|
*
|
|
* @property {String} names.set The name of the setter method ("setFoo").
|
|
*
|
|
* @property {String} names.initGet The name of the initializing getter ("initGetFoo").
|
|
*
|
|
* @property {String} names.changeEvent The name of the change event ("foochange").
|
|
*
|
|
* @readonly
|
|
* @private
|
|
* @since 5.0.0
|
|
*/
|
|
me.names = {
|
|
internal: '_' + name,
|
|
initializing: 'is' + capitalizedName + 'Initializing',
|
|
apply: 'apply' + capitalizedName,
|
|
update: 'update' + capitalizedName,
|
|
get: 'get' + capitalizedName,
|
|
set: 'set' + capitalizedName,
|
|
initGet: 'initGet' + capitalizedName,
|
|
changeEvent: name.toLowerCase() + 'change'
|
|
};
|
|
// This allows folks to prototype chain on top of these objects and yet still cache
|
|
// generated methods at the bottom of the chain.
|
|
me.root = me;
|
|
};
|
|
Ext.Config.map = {};
|
|
Ext.Config.get = function(name) {
|
|
var map = Ext.Config.map,
|
|
ret = map[name] || (map[name] = new Ext.Config(name));
|
|
return ret;
|
|
};
|
|
Ext.Config.prototype = {
|
|
self: Ext.Config,
|
|
isConfig: true,
|
|
/**
|
|
* @cfg {Boolean} [cached=false]
|
|
* When set as `true` the config property will be stored on the class prototype once
|
|
* the first instance has had a chance to process the default value.
|
|
* @private
|
|
* @since 5.0.0
|
|
*/
|
|
/**
|
|
* @cfg {Boolean} [lazy=false]
|
|
* When set as `true` the config property will not be immediately initialized during
|
|
* the `initConfig` call.
|
|
* @private
|
|
* @since 5.0.0
|
|
*/
|
|
/**
|
|
* @cfg {Boolean} [evented=false]
|
|
* When set as `true` the config property will be treated as a {@link Ext.Evented Evented Config}.
|
|
* @private
|
|
* @since 6.0.0
|
|
*/
|
|
/**
|
|
* @cfg {Function} [merge]
|
|
* This function if supplied will be called as classes or instances provide values
|
|
* that need to be combined with inherited values. The function should return the
|
|
* value that will be the config value. Further calls may receive such returned
|
|
* values as `oldValue`.
|
|
*
|
|
* @cfg {Mixed} merge.newValue The new value to merge with the old.
|
|
*
|
|
* @cfg {Mixed} merge.oldValue The current value prior to `newValue` being merged.
|
|
*
|
|
* @cfg {Mixed} merge.target The class or instance to which the merged config value
|
|
* will be applied.
|
|
*
|
|
* @cfg {Ext.Class} merge.mixinClass The mixin providing the `newValue` or `null` if
|
|
* the `newValue` is not being provided by a mixin.
|
|
*/
|
|
getGetter: function() {
|
|
return this.getter || (this.root.getter = this.makeGetter());
|
|
},
|
|
getInitGetter: function() {
|
|
return this.initGetter || (this.root.initGetter = this.makeInitGetter());
|
|
},
|
|
getSetter: function() {
|
|
return this.setter || (this.root.setter = this.makeSetter());
|
|
},
|
|
getEventedSetter: function() {
|
|
return this.eventedSetter || (this.root.eventedSetter = this.makeEventedSetter());
|
|
},
|
|
/**
|
|
* Returns the name of the property that stores this config on the given instance or
|
|
* class prototype.
|
|
* @param {Object} target
|
|
* @return {String}
|
|
*/
|
|
getInternalName: function(target) {
|
|
return target.$configPrefixed ? this.names.internal : this.name;
|
|
},
|
|
mergeNew: function(newValue, oldValue, target, mixinClass) {
|
|
var ret, key;
|
|
if (!oldValue) {
|
|
ret = newValue;
|
|
} else if (!newValue) {
|
|
ret = oldValue;
|
|
} else {
|
|
ret = Ext.Object.chain(oldValue);
|
|
for (key in newValue) {
|
|
if (!mixinClass || !(key in ret)) {
|
|
ret[key] = newValue[key];
|
|
}
|
|
}
|
|
}
|
|
return ret;
|
|
},
|
|
/**
|
|
* Merges the `newValue` and the `oldValue` assuming that these are basically objects
|
|
* the represent sets. For example something like:
|
|
*
|
|
* {
|
|
* foo: true,
|
|
* bar: true
|
|
* }
|
|
*
|
|
* The merge process converts arrays like the following into the above:
|
|
*
|
|
* [ 'foo', 'bar' ]
|
|
*
|
|
* @param {String/String[]/Object} newValue
|
|
* @param {Object} oldValue
|
|
* @param {Boolean} [preserveExisting=false]
|
|
* @return {Object}
|
|
* @private
|
|
* @since 5.0.0
|
|
*/
|
|
mergeSets: function(newValue, oldValue, preserveExisting) {
|
|
var ret = oldValue ? Ext.Object.chain(oldValue) : {},
|
|
i, val;
|
|
if (newValue instanceof Array) {
|
|
for (i = newValue.length; i--; ) {
|
|
val = newValue[i];
|
|
if (!preserveExisting || !(val in ret)) {
|
|
ret[val] = true;
|
|
}
|
|
}
|
|
} else if (newValue) {
|
|
if (newValue.constructor === Object) {
|
|
for (i in newValue) {
|
|
val = newValue[i];
|
|
if (!preserveExisting || !(i in ret)) {
|
|
ret[i] = val;
|
|
}
|
|
}
|
|
} else if (!preserveExisting || !(newValue in ret)) {
|
|
ret[newValue] = true;
|
|
}
|
|
}
|
|
return ret;
|
|
},
|
|
//--------------------------------------------------
|
|
// Factories
|
|
makeGetter: function() {
|
|
var name = this.name,
|
|
prefixedName = this.names.internal;
|
|
return function() {
|
|
var internalName = this.$configPrefixed ? prefixedName : name;
|
|
return this[internalName];
|
|
};
|
|
},
|
|
makeInitGetter: function() {
|
|
var name = this.name,
|
|
names = this.names,
|
|
setName = names.set,
|
|
getName = names.get,
|
|
initializingName = names.initializing;
|
|
return function() {
|
|
var me = this;
|
|
me[initializingName] = true;
|
|
// Remove the initGetter from the instance now that the value has been set.
|
|
delete me[getName];
|
|
me[setName](me.config[name]);
|
|
delete me[initializingName];
|
|
return me[getName].apply(me, arguments);
|
|
};
|
|
},
|
|
makeSetter: function() {
|
|
var name = this.name,
|
|
names = this.names,
|
|
prefixedName = names.internal,
|
|
getName = names.get,
|
|
applyName = names.apply,
|
|
updateName = names.update,
|
|
setter;
|
|
// http://jsperf.com/method-call-apply-or-direct
|
|
// http://jsperf.com/method-detect-invoke
|
|
setter = function(value) {
|
|
var me = this,
|
|
internalName = me.$configPrefixed ? prefixedName : name,
|
|
oldValue = me[internalName];
|
|
// Remove the initGetter from the instance now that the value has been set.
|
|
delete me[getName];
|
|
if (!me[applyName] || (value = me[applyName](value, oldValue)) !== undefined) {
|
|
// The old value might have been changed at this point
|
|
// (after the apply call chain) so it should be read again
|
|
if (value !== (oldValue = me[internalName])) {
|
|
me[internalName] = value;
|
|
if (me[updateName]) {
|
|
me[updateName](value, oldValue);
|
|
}
|
|
}
|
|
}
|
|
return me;
|
|
};
|
|
setter.$isDefault = true;
|
|
return setter;
|
|
},
|
|
makeEventedSetter: function() {
|
|
var name = this.name,
|
|
names = this.names,
|
|
prefixedName = names.internal,
|
|
getName = names.get,
|
|
applyName = names.apply,
|
|
updateName = names.update,
|
|
changeEventName = names.changeEvent,
|
|
updateFn = function(me, value, oldValue, internalName) {
|
|
me[internalName] = value;
|
|
if (me[updateName]) {
|
|
me[updateName](value, oldValue);
|
|
}
|
|
},
|
|
setter;
|
|
// http://jsperf.com/method-call-apply-or-direct
|
|
// http://jsperf.com/method-detect-invoke
|
|
setter = function(value) {
|
|
var me = this,
|
|
internalName = me.$configPrefixed ? prefixedName : name,
|
|
oldValue = me[internalName];
|
|
// Remove the initGetter from the instance now that the value has been set.
|
|
delete me[getName];
|
|
if (!me[applyName] || (value = me[applyName](value, oldValue)) !== undefined) {
|
|
// The old value might have been changed at this point
|
|
// (after the apply call chain) so it should be read again
|
|
if (value !== (oldValue = me[internalName])) {
|
|
if (me.isConfiguring) {
|
|
me[internalName] = value;
|
|
if (me[updateName]) {
|
|
me[updateName](value, oldValue);
|
|
}
|
|
} else {
|
|
me.fireEventedAction(changeEventName, [
|
|
me,
|
|
value,
|
|
oldValue
|
|
], updateFn, me, [
|
|
me,
|
|
value,
|
|
oldValue,
|
|
internalName
|
|
]);
|
|
}
|
|
}
|
|
}
|
|
return me;
|
|
};
|
|
setter.$isDefault = true;
|
|
return setter;
|
|
}
|
|
};
|
|
|
|
/**
|
|
* @class Ext.Configurator
|
|
* This class manages the config properties for a class.
|
|
* @private
|
|
*/
|
|
(function() {
|
|
// see end of file (and please don't indent the whole file)
|
|
var ExtConfig = Ext.Config,
|
|
configPropMap = ExtConfig.map,
|
|
ExtObject = Ext.Object;
|
|
Ext.Configurator = function(cls) {
|
|
// @define Ext.class.Configurator
|
|
// @define Ext.Configurator
|
|
// @require Ext.Config
|
|
var me = this,
|
|
prototype = cls.prototype,
|
|
superCfg = cls.superclass ? cls.superclass.self.$config : null;
|
|
/**
|
|
* @property {Ext.Class} cls The class to which this instance is associated.
|
|
* @private
|
|
* @readonly
|
|
*/
|
|
me.cls = cls;
|
|
/**
|
|
* The super class `Configurator` instance or `null` if there is no super class.
|
|
*
|
|
* @property {Ext.Configurator} superCfg
|
|
* @private
|
|
* @readonly
|
|
*/
|
|
me.superCfg = superCfg;
|
|
if (superCfg) {
|
|
/**
|
|
* This object holds an `Ext.Config` value for each config property keyed by name.
|
|
* This object has as its prototype object the `configs` of its super class.
|
|
*
|
|
* This map is maintained as each property is added via the `add` method.
|
|
*
|
|
* @property {Object} configs
|
|
* @private
|
|
* @readonly
|
|
*/
|
|
me.configs = ExtObject.chain(superCfg.configs);
|
|
/**
|
|
* This object holds a bool value for each cachedConfig property keyed by name.
|
|
*
|
|
* This map is maintained as each property is added via the `add` method.
|
|
*
|
|
* @property {Object} cachedConfigs
|
|
* @private
|
|
* @readonly
|
|
*/
|
|
me.cachedConfigs = ExtObject.chain(superCfg.cachedConfigs);
|
|
/**
|
|
* This object holds a `Number` for each config property keyed by name. This object has
|
|
* as its prototype object the `initMap` of its super class. The value of each property
|
|
* has the following meaning:
|
|
*
|
|
* * `0` - initial value is `null` and requires no processing.
|
|
* * `1` - initial value must be set on each instance.
|
|
* * `2` - initial value can be cached on the prototype by the first instance.
|
|
*
|
|
* Any `null` values will either never be added to this map or (if added by a base
|
|
* class and set to `null` by a derived class) will cause the entry to be 0.
|
|
*
|
|
* This map is maintained as each property is added via the `add` method.
|
|
*
|
|
* @property {Object} initMap
|
|
* @private
|
|
* @readonly
|
|
*/
|
|
me.initMap = ExtObject.chain(superCfg.initMap);
|
|
/**
|
|
* This object holds the default value for each config property keyed by name. This
|
|
* object has as its prototype object the `values` of its super class.
|
|
*
|
|
* This map is maintained as each property is added via the `add` method.
|
|
*
|
|
* @property {Object} values
|
|
* @private
|
|
* @readonly
|
|
*/
|
|
me.values = ExtObject.chain(superCfg.values);
|
|
me.needsFork = superCfg.needsFork;
|
|
// The reason this feature is debug only is that we would have to create this
|
|
// map for all classes because deprecations could be added to bases after the
|
|
// derived class had created its Configurator.
|
|
me.deprecations = ExtObject.chain(superCfg.deprecations);
|
|
} else {
|
|
me.configs = {};
|
|
me.cachedConfigs = {};
|
|
me.initMap = {};
|
|
me.values = {};
|
|
me.deprecations = {};
|
|
}
|
|
prototype.config = prototype.defaultConfig = me.values;
|
|
cls.$config = me;
|
|
};
|
|
Ext.Configurator.prototype = {
|
|
self: Ext.Configurator,
|
|
needsFork: false,
|
|
/**
|
|
* This array holds the properties that need to be set on new instances.
|
|
*
|
|
* This array is populated when the first instance is passed to `configure` (basically
|
|
* when the first instance is created). The entries in `initMap` are iterated to find
|
|
* those configs needing per-instance processing.
|
|
*
|
|
* @property {Ext.Config[]} initList
|
|
* @private
|
|
*/
|
|
initList: null,
|
|
/**
|
|
* This method adds new config properties. This is called for classes when they are
|
|
* declared, then for any mixins that class may define and finally for any overrides
|
|
* defined that target the class.
|
|
*
|
|
* @param {Object} config The config object containing the new config properties.
|
|
* @param {Ext.Class} [mixinClass] The mixin class if the configs are from a mixin.
|
|
* @private
|
|
*/
|
|
add: function(config, mixinClass) {
|
|
var me = this,
|
|
Cls = me.cls,
|
|
configs = me.configs,
|
|
cachedConfigs = me.cachedConfigs,
|
|
initMap = me.initMap,
|
|
prototype = Cls.prototype,
|
|
mixinConfigs = mixinClass && mixinClass.$config.configs,
|
|
values = me.values,
|
|
isObject, meta, isCached, merge, cfg, currentValue, name, names, s, value;
|
|
for (name in config) {
|
|
value = config[name];
|
|
isObject = value && value.constructor === Object;
|
|
meta = isObject && '$value' in value ? value : null;
|
|
isCached = false;
|
|
if (meta) {
|
|
isCached = !!meta.cached;
|
|
value = meta.$value;
|
|
isObject = value && value.constructor === Object;
|
|
}
|
|
merge = meta && meta.merge;
|
|
cfg = configs[name];
|
|
if (cfg) {
|
|
// Only proceed with a mixin if we have a custom merge.
|
|
if (mixinClass) {
|
|
merge = cfg.merge;
|
|
if (!merge) {
|
|
|
|
continue;
|
|
}
|
|
// Don't want the mixin meta modifying our own
|
|
meta = null;
|
|
} else {
|
|
merge = merge || cfg.merge;
|
|
}
|
|
// This means that we've already declared this as a config in a superclass
|
|
// Let's not allow us to change it here.
|
|
if (!mixinClass && isCached && !cachedConfigs[name]) {
|
|
Ext.raise('Redefining config as cached: ' + name + ' in class: ' + Cls.$className);
|
|
}
|
|
// There is already a value for this config and we are not allowed to
|
|
// modify it. So, if it is an object and the new value is also an object,
|
|
// the result is a merge so we have to merge both on to a new object.
|
|
currentValue = values[name];
|
|
if (merge) {
|
|
value = merge.call(cfg, value, currentValue, Cls, mixinClass);
|
|
} else if (isObject) {
|
|
if (currentValue && currentValue.constructor === Object) {
|
|
// We favor moving the cost of an "extra" copy here because this
|
|
// is likely to be a rare thing two object values for the same
|
|
// property. The alternative would be to clone the initial value
|
|
// to make it safely modifiable even though it is likely to never
|
|
// need to be modified.
|
|
value = ExtObject.merge({}, currentValue, value);
|
|
}
|
|
}
|
|
} else // else "currentValue" is a primitive so "value" can just replace it
|
|
// else "value" is a primitive and it can just replace currentValue
|
|
{
|
|
// This is a new property value, so add it to the various maps "as is".
|
|
// In the majority of cases this value will not be overridden or need to
|
|
// be forked.
|
|
if (mixinConfigs) {
|
|
// Since this is a config from a mixin, we don't want to apply its
|
|
// meta-ness because it already has. Instead we want to use its cfg
|
|
// instance:
|
|
cfg = mixinConfigs[name];
|
|
meta = null;
|
|
} else {
|
|
cfg = ExtConfig.get(name);
|
|
}
|
|
configs[name] = cfg;
|
|
if (cfg.cached || isCached) {
|
|
cachedConfigs[name] = true;
|
|
}
|
|
// Ensure that the new config has a getter and setter. Because this method
|
|
// is called during class creation as the "config" (or "cachedConfig") is
|
|
// being processed, the user's methods will not be on the prototype yet.
|
|
//
|
|
// This has the following trade-offs:
|
|
//
|
|
// - Custom getters are rare so there is minimal waste generated by them.
|
|
//
|
|
// - Custom setters are more common but, by putting the default setter on
|
|
// the prototype prior to addMembers, when the user methods are added
|
|
// callParent can be used to call the generated setter. This is almost
|
|
// certainly desirable as the setter has some very important semantics
|
|
// that a custom setter would probably want to preserve by just adding
|
|
// logic before and/or after the callParent.
|
|
//
|
|
// - By not adding these to the class body we avoid all the "is function"
|
|
// tests that get applied to each class member thereby streamlining the
|
|
// downstream class creation process.
|
|
//
|
|
// We still check for getter and/or setter but primarily for reasons of
|
|
// backwards compatibility and "just in case" someone relied on inherited
|
|
// getter/setter even though the base did not have the property listed as
|
|
// a "config" (obscure case certainly).
|
|
//
|
|
names = cfg.names;
|
|
if (!prototype[s = names.get]) {
|
|
prototype[s] = cfg.getter || cfg.getGetter();
|
|
}
|
|
if (!prototype[s = names.set]) {
|
|
prototype[s] = (meta && meta.evented) ? (cfg.eventedSetter || cfg.getEventedSetter()) : (cfg.setter || cfg.getSetter());
|
|
}
|
|
}
|
|
if (meta) {
|
|
if (cfg.owner !== Cls) {
|
|
configs[name] = cfg = Ext.Object.chain(cfg);
|
|
cfg.owner = Cls;
|
|
}
|
|
Ext.apply(cfg, meta);
|
|
delete cfg.$value;
|
|
}
|
|
// Fork checks all the default values to see if they are arrays or objects
|
|
// Do this to save us from doing it on each run
|
|
if (!me.needsFork && value && (value.constructor === Object || value instanceof Array)) {
|
|
me.needsFork = true;
|
|
}
|
|
// If the value is non-null, we need to initialize it.
|
|
if (value !== null) {
|
|
initMap[name] = true;
|
|
} else {
|
|
if (prototype.$configPrefixed) {
|
|
prototype[configs[name].names.internal] = null;
|
|
} else {
|
|
prototype[configs[name].name] = null;
|
|
}
|
|
if (name in initMap) {
|
|
// Only set this to false if we already have it in the map, otherwise, just leave it out!
|
|
initMap[name] = false;
|
|
}
|
|
}
|
|
values[name] = value;
|
|
}
|
|
},
|
|
addDeprecations: function(configs) {
|
|
var me = this,
|
|
deprecations = me.deprecations,
|
|
className = (me.cls.$className || '') + '#',
|
|
message, newName, oldName;
|
|
for (oldName in configs) {
|
|
newName = configs[oldName];
|
|
// configs: {
|
|
// dead: null,
|
|
//
|
|
// renamed: 'newName',
|
|
//
|
|
// removed: {
|
|
// message: 'This config was replaced by pixie dust'
|
|
// }
|
|
// }
|
|
if (!newName) {
|
|
message = 'This config has been removed.';
|
|
} else if (!(message = newName.message)) {
|
|
message = 'This config has been renamed to "' + newName + '"';
|
|
}
|
|
deprecations[oldName] = className + oldName + ': ' + message;
|
|
}
|
|
},
|
|
/**
|
|
* This method configures the given `instance` using the specified `instanceConfig`.
|
|
* The given `instance` should have been created by this object's `cls`.
|
|
*
|
|
* @param {Object} instance The instance to configure.
|
|
* @param {Object} instanceConfig The configuration properties to apply to `instance`.
|
|
* @private
|
|
*/
|
|
configure: function(instance, instanceConfig) {
|
|
var me = this,
|
|
configs = me.configs,
|
|
deprecations = me.deprecations,
|
|
initMap = me.initMap,
|
|
initListMap = me.initListMap,
|
|
initList = me.initList,
|
|
prototype = me.cls.prototype,
|
|
values = me.values,
|
|
remaining = 0,
|
|
firstInstance = !initList,
|
|
cachedInitList, cfg, getter, i, internalName, ln, names, name, value, isCached, valuesKey, field;
|
|
values = me.needsFork ? ExtObject.fork(values) : ExtObject.chain(values);
|
|
// Let apply/update methods know that the initConfig is currently running.
|
|
instance.isConfiguring = true;
|
|
if (firstInstance) {
|
|
// When called to configure the first instance of the class to which we are
|
|
// bound we take a bit to plan for instance 2+.
|
|
me.initList = initList = [];
|
|
me.initListMap = initListMap = {};
|
|
instance.isFirstInstance = true;
|
|
for (name in initMap) {
|
|
cfg = configs[name];
|
|
isCached = cfg.cached;
|
|
if (initMap[name]) {
|
|
names = cfg.names;
|
|
value = values[name];
|
|
if (!prototype[names.set].$isDefault || prototype[names.apply] || prototype[names.update] || typeof value === 'object') {
|
|
if (isCached) {
|
|
// This is a cachedConfig, so it needs to be initialized with
|
|
// the default value and placed on the prototype... but the
|
|
// instanceConfig may have a different value so the value may
|
|
// need resetting. We have to defer the call to the setter so
|
|
// that all of the initGetters are set up first.
|
|
(cachedInitList || (cachedInitList = [])).push(cfg);
|
|
} else {
|
|
// Remember this config so that all instances (including this
|
|
// one) can invoke the setter to properly initialize it.
|
|
initList.push(cfg);
|
|
initListMap[name] = true;
|
|
}
|
|
// Point all getters to the initGetters. By doing this here we
|
|
// avoid creating initGetters for configs that don't need them
|
|
// and we can easily pick up the cached fn to save the call.
|
|
instance[names.get] = cfg.initGetter || cfg.getInitGetter();
|
|
} else {
|
|
// Non-object configs w/o custom setter, applier or updater can
|
|
// be simply stored on the prototype.
|
|
prototype[cfg.getInternalName(prototype)] = value;
|
|
}
|
|
} else if (isCached) {
|
|
prototype[cfg.getInternalName(prototype)] = undefined;
|
|
}
|
|
}
|
|
}
|
|
// TODO - we need to combine the cached loop with the instanceConfig loop to
|
|
// avoid duplication of init getter setups (for correctness if a cached cfg
|
|
// calls on a non-cached cfg)
|
|
ln = cachedInitList && cachedInitList.length;
|
|
if (ln) {
|
|
// This is only ever done on the first instance we configure. Any config in
|
|
// cachedInitList has to be set to the default value to allow any side-effects
|
|
// or transformations to occur. The resulting values can then be elevated to
|
|
// the prototype and this property need not be initialized on each instance.
|
|
for (i = 0; i < ln; ++i) {
|
|
internalName = cachedInitList[i].getInternalName(prototype);
|
|
// Since these are cached configs the base class will potentially have put
|
|
// its cached values on the prototype so we need to hide these while we
|
|
// run the inits for our cached configs.
|
|
instance[internalName] = null;
|
|
}
|
|
for (i = 0; i < ln; ++i) {
|
|
names = (cfg = cachedInitList[i]).names;
|
|
getter = names.get;
|
|
if (instance.hasOwnProperty(getter)) {
|
|
instance[names.set](values[cfg.name]);
|
|
delete instance[getter];
|
|
}
|
|
}
|
|
for (i = 0; i < ln; ++i) {
|
|
internalName = cachedInitList[i].getInternalName(prototype);
|
|
prototype[internalName] = instance[internalName];
|
|
delete instance[internalName];
|
|
}
|
|
}
|
|
// The cachedConfigs have all been set to the default values including any of
|
|
// those that may have been triggered by their getter.
|
|
// If the instanceConfig has a platformConfig in it, we need to merge the active
|
|
// rules of that object to make the actual instanceConfig.
|
|
if (instanceConfig && instanceConfig.platformConfig) {
|
|
instanceConfig = me.resolvePlatformConfig(instance, instanceConfig);
|
|
}
|
|
if (firstInstance) {
|
|
// Allow the class to do things once the cachedConfig has been processed.
|
|
// We need to call this method always when the first instance is configured
|
|
// whether or not it actually has cached configs
|
|
if (instance.afterCachedConfig && !instance.afterCachedConfig.$nullFn) {
|
|
instance.afterCachedConfig(instanceConfig);
|
|
}
|
|
}
|
|
// Now that the cachedConfigs have been processed we can apply the instanceConfig
|
|
// and hide the "configs" on the prototype. This will serve as the source for any
|
|
// configs that need to initialize from their initial getter call.
|
|
instance.config = values;
|
|
// There are 2 possibilities here:
|
|
// 1) If it's the first time in this function, we may have had cachedConfigs running.
|
|
// these configs may have called the getters for any of the normal getters, which
|
|
// means the initial getters have been clobbered on the instance and won't be able
|
|
// to be called below when we iterate over the initList. As such, we need to
|
|
// reinitialize them here, even though we've done it up above.
|
|
//
|
|
// 2) If this the second time in this function, the cachedConfigs won't be processed,
|
|
// so we don't need to worry about them clobbering config values. However, since
|
|
// we've already done all our setup, we won't enter into the block that sets the
|
|
// initGetter, so we need to do it here anyway.
|
|
//
|
|
// Also note, that lazy configs will appear in the initList because we need
|
|
// to spin up the initGetter.
|
|
for (i = 0 , ln = initList.length; i < ln; ++i) {
|
|
cfg = initList[i];
|
|
instance[cfg.names.get] = cfg.initGetter || cfg.getInitGetter();
|
|
}
|
|
// Give the class a chance to transform the configs.
|
|
if (instance.transformInstanceConfig) {
|
|
instanceConfig = instance.transformInstanceConfig(instanceConfig);
|
|
}
|
|
// Important: We are looping here twice on purpose. This first loop serves 2 purposes:
|
|
//
|
|
// 1) Ensure the values collection is fully populated before we call any setters. Since
|
|
// a setter may have an updater/applier, it could potentially call another getter() to grab
|
|
// the value for some other property, so this ensures they are all set on the config object.
|
|
//
|
|
// 2) Ensure that the initGetter is set as the getter for any config that doesn't appear in
|
|
// the initList. We need to ensure that the initGetter is pushed on for everything that we will
|
|
// be setting during init time.
|
|
//
|
|
// The merging in this loop cannot be completed by Ext.merge(), since we do NOT want to merge
|
|
// non-strict values, they should always just be assigned across without modification.
|
|
if (instanceConfig) {
|
|
for (name in instanceConfig) {
|
|
value = instanceConfig[name];
|
|
cfg = configs[name];
|
|
if (deprecations[name]) {
|
|
Ext.log.warn(deprecations[name]);
|
|
if (!cfg) {
|
|
// If there is a Config for this, perhaps the class is emulating
|
|
// the old config... If there is not a Config we don't want to
|
|
// proceed and put the property on the instance. That will likely
|
|
// hide the bug during development.
|
|
|
|
continue;
|
|
}
|
|
}
|
|
if (!cfg) {
|
|
field = instance.self.prototype[name];
|
|
if (instance.$configStrict && (typeof field === 'function') && !field.$nullFn) {
|
|
// In strict mode you cannot override functions
|
|
Ext.raise('Cannot override method ' + name + ' on ' + instance.$className + ' instance.');
|
|
}
|
|
// Not all "configs" use the config system so in this case simply put
|
|
// the value on the instance:
|
|
instance[name] = value;
|
|
} else {
|
|
// However we still need to create the initial value that needs
|
|
// to be used. We also need to spin up the initGetter.
|
|
if (!cfg.lazy) {
|
|
++remaining;
|
|
}
|
|
if (!initListMap[name]) {
|
|
instance[cfg.names.get] = cfg.initGetter || cfg.getInitGetter();
|
|
}
|
|
if (cfg.merge) {
|
|
value = cfg.merge(value, values[name], instance);
|
|
} else if (value && value.constructor === Object) {
|
|
valuesKey = values[name];
|
|
if (valuesKey && valuesKey.constructor === Object) {
|
|
value = ExtObject.merge(values[name], value);
|
|
} else {
|
|
value = Ext.clone(value, false);
|
|
}
|
|
}
|
|
}
|
|
values[name] = value;
|
|
}
|
|
}
|
|
// Give the class a chance to hook in prior to initializing the configs.
|
|
if (instance.beforeInitConfig && !instance.beforeInitConfig.$nullFn) {
|
|
if (instance.beforeInitConfig(instanceConfig) === false) {
|
|
return;
|
|
}
|
|
}
|
|
if (instanceConfig) {
|
|
for (name in instanceConfig) {
|
|
if (!remaining) {
|
|
// For classes that have few proper Config properties, this saves us
|
|
// from making the full 2 passes over the instanceConfig.
|
|
break;
|
|
}
|
|
// We can ignore deprecated configs here because we warned about them
|
|
// above. Further, since we only process proper Config's here we would
|
|
// not be skipping them anyway.
|
|
cfg = configs[name];
|
|
if (cfg && !cfg.lazy) {
|
|
--remaining;
|
|
// A proper "config" property so call the setter to set the value.
|
|
names = cfg.names;
|
|
getter = names.get;
|
|
// At this point the initGetter may have already been called and
|
|
// cleared if the getter was called from the applier or updater of a
|
|
// previously processed instance config. checking if the instance has
|
|
// its own getter ensures the setter does not get called twice.
|
|
if (instance.hasOwnProperty(getter)) {
|
|
instance[names.set](values[name]);
|
|
// The generated setter will remove the initGetter from the instance
|
|
// but the user may have provided their own setter so we have to do
|
|
// this here as well:
|
|
delete instance[names.get];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// Process configs declared on the class that need per-instance initialization.
|
|
for (i = 0 , ln = initList.length; i < ln; ++i) {
|
|
cfg = initList[i];
|
|
names = cfg.names;
|
|
getter = names.get;
|
|
if (!cfg.lazy && instance.hasOwnProperty(getter)) {
|
|
// Since the instance still hasOwn the getter, that means we've set an initGetter
|
|
// and it hasn't been cleared by calling any setter. Since we've never set the value
|
|
// because it wasn't passed in the instance, we go and set it here, taking the value
|
|
// from our definition config and passing it through finally clear off the getter.
|
|
instance[names.set](values[cfg.name]);
|
|
delete instance[getter];
|
|
}
|
|
}
|
|
// Expose the value from the prototype chain (false):
|
|
delete instance.isConfiguring;
|
|
},
|
|
getCurrentConfig: function(instance) {
|
|
var defaultConfig = instance.defaultConfig,
|
|
config = {},
|
|
name;
|
|
for (name in defaultConfig) {
|
|
config[name] = instance[configPropMap[name].names.get]();
|
|
}
|
|
return config;
|
|
},
|
|
/**
|
|
* Merges the values of a config object onto a base config.
|
|
* @param {Ext.Base} instance
|
|
* @param {Object} baseConfig
|
|
* @param {Object} config
|
|
* @return {Object} the merged config
|
|
* @private
|
|
*/
|
|
merge: function(instance, baseConfig, config) {
|
|
// Although this is a "private" method. It is used by Sencha Architect and so
|
|
// its api should remain stable.
|
|
var configs = this.configs,
|
|
name, value, baseValue, cfg;
|
|
for (name in config) {
|
|
value = config[name];
|
|
cfg = configs[name];
|
|
if (cfg) {
|
|
if (cfg.merge) {
|
|
value = cfg.merge(value, baseConfig[name], instance);
|
|
} else if (value && value.constructor === Object) {
|
|
baseValue = baseConfig[name];
|
|
if (baseValue && baseValue.constructor === Object) {
|
|
value = Ext.Object.merge(baseValue, value);
|
|
} else {
|
|
value = Ext.clone(value, false);
|
|
}
|
|
}
|
|
}
|
|
baseConfig[name] = value;
|
|
}
|
|
return baseConfig;
|
|
},
|
|
/**
|
|
* @private
|
|
*/
|
|
reconfigure: function(instance, instanceConfig, options) {
|
|
var currentConfig = instance.config,
|
|
configList = [],
|
|
strict = instance.$configStrict && !(options && options.strict === false),
|
|
configs = this.configs,
|
|
defaults = options && options.defaults,
|
|
cfg, getter, i, len, name, names, prop;
|
|
for (name in instanceConfig) {
|
|
if (defaults && instance.hasOwnProperty(name)) {
|
|
|
|
continue;
|
|
}
|
|
currentConfig[name] = instanceConfig[name];
|
|
cfg = configs[name];
|
|
if (this.deprecations[name]) {
|
|
// See similar logic doc in configure() method.
|
|
Ext.log.warn(this.deprecations[name]);
|
|
if (!cfg) {
|
|
|
|
continue;
|
|
}
|
|
}
|
|
if (cfg) {
|
|
// To ensure that configs being set here get processed in the proper order
|
|
// we must give them init getters just in case they depend upon each other
|
|
instance[cfg.names.get] = cfg.initGetter || cfg.getInitGetter();
|
|
} else {
|
|
// Check for existence of the property on the prototype before proceeding.
|
|
// If present on the prototype, and if the property is a function we
|
|
// do not allow it to be overridden by a property in the config object
|
|
// in strict mode (unless the function on the prototype is a emptyFn or
|
|
// identityFn). Note that we always check the prototype, not the instance
|
|
// because calling setConfig a second time should have the same results -
|
|
// the first call may have set a function on the instance.
|
|
prop = instance.self.prototype[name];
|
|
if (strict) {
|
|
if ((typeof prop === 'function') && !prop.$nullFn) {
|
|
Ext.Error.raise("Cannot override method " + name + " on " + instance.$className + " instance.");
|
|
|
|
continue;
|
|
} else {
|
|
if (name !== 'type') {
|
|
Ext.log.warn('No such config "' + name + '" for class ' + instance.$className);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
configList.push(name);
|
|
}
|
|
for (i = 0 , len = configList.length; i < len; i++) {
|
|
name = configList[i];
|
|
cfg = configs[name];
|
|
if (cfg) {
|
|
names = cfg.names;
|
|
getter = names.get;
|
|
if (instance.hasOwnProperty(getter)) {
|
|
// Since the instance still hasOwn the getter, that means we've set an initGetter
|
|
// and it hasn't been cleared by calling any setter. Since we've never set the value
|
|
// because it wasn't passed in the instance, we go and set it here, taking the value
|
|
// from our definition config and passing it through finally clear off the getter.
|
|
instance[names.set](instanceConfig[name]);
|
|
delete instance[getter];
|
|
}
|
|
} else {
|
|
cfg = configPropMap[name] || Ext.Config.get(name);
|
|
names = cfg.names;
|
|
if (instance[names.set]) {
|
|
instance[names.set](instanceConfig[name]);
|
|
} else {
|
|
// apply non-config props directly to the instance
|
|
instance[name] = instanceConfig[name];
|
|
}
|
|
}
|
|
}
|
|
},
|
|
/**
|
|
* This method accepts an instance config object containing a `platformConfig`
|
|
* property and merges the appropriate rules from that sub-object with the root object
|
|
* to create the final config object that should be used. This is method called by
|
|
* `{@link #configure}` when it receives an `instanceConfig` containing a
|
|
* `platformConfig` property.
|
|
*
|
|
* @param {Object} instanceConfig The instance config parameter.
|
|
* @return {Object} The new instance config object with platformConfig results applied.
|
|
* @private
|
|
* @since 5.1.0
|
|
*/
|
|
resolvePlatformConfig: function(instance, instanceConfig) {
|
|
var platformConfig = instanceConfig && instanceConfig.platformConfig,
|
|
ret = instanceConfig,
|
|
i, keys, n;
|
|
if (platformConfig) {
|
|
keys = Ext.getPlatformConfigKeys(platformConfig);
|
|
n = keys.length;
|
|
if (n) {
|
|
ret = Ext.merge({}, ret);
|
|
// this deep copies sub-objects
|
|
for (i = 0 , n = keys.length; i < n; ++i) {
|
|
this.merge(instance, ret, platformConfig[keys[i]]);
|
|
}
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
};
|
|
}());
|
|
// prototype
|
|
// closure on whole file
|
|
|
|
// @tag class
|
|
/**
|
|
* @class Ext.Base
|
|
*
|
|
* The root of all classes created with {@link Ext#define}.
|
|
*
|
|
* Ext.Base is the building block of all Ext classes. All classes in Ext inherit from Ext.Base.
|
|
* All prototype and static members of this class are inherited by all other classes.
|
|
*/
|
|
Ext.Base = (function(flexSetter) {
|
|
// @define Ext.Base
|
|
// @require Ext.Util
|
|
// @require Ext.Version
|
|
// @require Ext.Configurator
|
|
// @uses Ext.ClassManager
|
|
var noArgs = [],
|
|
baseStaticMember,
|
|
baseStaticMembers = [],
|
|
getConfig = function(name, peek) {
|
|
var me = this,
|
|
ret, cfg, getterName;
|
|
if (name) {
|
|
cfg = Ext.Config.map[name];
|
|
if (!cfg) {
|
|
Ext.Logger.error("Invalid property name for getter: '" + name + "' for '" + me.$className + "'.");
|
|
}
|
|
getterName = cfg.names.get;
|
|
if (peek && me.hasOwnProperty(getterName)) {
|
|
ret = me.config[name];
|
|
} else {
|
|
ret = me[getterName]();
|
|
}
|
|
} else {
|
|
ret = me.getCurrentConfig();
|
|
}
|
|
return ret;
|
|
},
|
|
makeDeprecatedMethod = function(oldName, newName, msg) {
|
|
var message = '"' + oldName + '" is deprecated.';
|
|
if (msg) {
|
|
message += ' ' + msg;
|
|
} else if (newName) {
|
|
message += ' Please use "' + newName + '" instead.';
|
|
}
|
|
return function() {
|
|
Ext.raise(message);
|
|
};
|
|
},
|
|
addDeprecatedProperty = function(object, oldName, newName, message) {
|
|
if (!message) {
|
|
message = '"' + oldName + '" is deprecated.';
|
|
}
|
|
if (newName) {
|
|
message += ' Please use "' + newName + '" instead.';
|
|
}
|
|
if (message) {
|
|
Ext.Object.defineProperty(object, oldName, {
|
|
get: function() {
|
|
Ext.raise(message);
|
|
},
|
|
set: function(value) {
|
|
Ext.raise(message);
|
|
},
|
|
configurable: true
|
|
});
|
|
}
|
|
},
|
|
makeAliasFn = function(name) {
|
|
return function() {
|
|
return this[name].apply(this, arguments);
|
|
};
|
|
},
|
|
Version = Ext.Version,
|
|
leadingDigitRe = /^\d/,
|
|
oneMember = {},
|
|
aliasOneMember = {},
|
|
Base = function() {},
|
|
BasePrototype = Base.prototype,
|
|
Reaper;
|
|
Ext.Reaper = Reaper = {
|
|
delay: 100,
|
|
queue: [],
|
|
timer: null,
|
|
add: function(obj) {
|
|
if (!Reaper.timer) {
|
|
Reaper.timer = Ext.defer(Reaper.tick, Reaper.delay);
|
|
}
|
|
Reaper.queue.push(obj);
|
|
},
|
|
flush: function() {
|
|
if (Reaper.timer) {
|
|
clearTimeout(Reaper.timer);
|
|
Reaper.timer = null;
|
|
}
|
|
var queue = Reaper.queue,
|
|
n = queue.length,
|
|
i, obj;
|
|
Reaper.queue = [];
|
|
for (i = 0; i < n; ++i) {
|
|
obj = queue[i];
|
|
if (obj && obj.$reap) {
|
|
obj.$reap();
|
|
}
|
|
}
|
|
},
|
|
tick: function() {
|
|
Reaper.timer = null;
|
|
Reaper.flush();
|
|
}
|
|
};
|
|
// These static properties will be copied to every newly created class with {@link Ext#define}
|
|
Ext.apply(Base, {
|
|
$className: 'Ext.Base',
|
|
$isClass: true,
|
|
/**
|
|
* Create a new instance of this Class.
|
|
*
|
|
* Ext.define('My.cool.Class', {
|
|
* ...
|
|
* });
|
|
*
|
|
* My.cool.Class.create({
|
|
* someConfig: true
|
|
* });
|
|
*
|
|
* All parameters are passed to the constructor of the class.
|
|
*
|
|
* @return {Object} the created instance.
|
|
* @static
|
|
* @inheritable
|
|
*/
|
|
create: function() {
|
|
return Ext.create.apply(Ext, [
|
|
this
|
|
].concat(Array.prototype.slice.call(arguments, 0)));
|
|
},
|
|
/**
|
|
* This method applies a versioned, deprecation declaration to this class. This
|
|
* is typically called by the `deprecated` config.
|
|
* @private
|
|
*/
|
|
addDeprecations: function(deprecations) {
|
|
var me = this,
|
|
all = [],
|
|
compatVersion = Ext.getCompatVersion(deprecations.name),
|
|
configurator = me.getConfigurator(),
|
|
displayName = (me.$className || '') + '#',
|
|
deprecate, versionSpec, index, message, target, enabled, existing, fn, names, oldName, newName, member, statics, version;
|
|
for (versionSpec in deprecations) {
|
|
if (leadingDigitRe.test(versionSpec)) {
|
|
version = new Ext.Version(versionSpec);
|
|
version.deprecations = deprecations[versionSpec];
|
|
all.push(version);
|
|
}
|
|
}
|
|
all.sort(Version.compare);
|
|
for (index = all.length; index--; ) {
|
|
deprecate = (version = all[index]).deprecations;
|
|
target = me.prototype;
|
|
statics = deprecate.statics;
|
|
// If user specifies, say 4.2 compatibility and we have a 5.0 deprecation
|
|
// then that block needs to be "enabled" to "revert" to behaviors prior
|
|
// to 5.0. By default, compatVersion === currentVersion, so there are no
|
|
// enabled blocks. In dev mode we still want to visit all the blocks and
|
|
// possibly add shims to detect use of deprecated methods, but in a build
|
|
// (if the deprecated block remains somehow) we just break the loop.
|
|
enabled = compatVersion && compatVersion.lt(version);
|
|
if (!enabled) {} else if (!enabled) {
|
|
// we won't get here in dev mode when !enabled
|
|
break;
|
|
}
|
|
while (deprecate) {
|
|
names = deprecate.methods;
|
|
if (names) {
|
|
for (oldName in names) {
|
|
member = names[oldName];
|
|
fn = null;
|
|
if (!member) {
|
|
/*
|
|
* Something like:
|
|
*
|
|
* '5.1': {
|
|
* methods: {
|
|
* removedMethod: null
|
|
* }
|
|
* }
|
|
*
|
|
* Since there is no recovering the method, we always put
|
|
* on a shim to catch abuse.
|
|
*/
|
|
// The class should not already have a method by the oldName
|
|
Ext.Assert.isNotDefinedProp(target, oldName);
|
|
fn = makeDeprecatedMethod(displayName + oldName);
|
|
} else if (Ext.isString(member)) {
|
|
/*
|
|
* Something like:
|
|
*
|
|
* '5.1': {
|
|
* methods: {
|
|
* oldName: 'newName'
|
|
* }
|
|
* }
|
|
*
|
|
* If this block is enabled, we just put an alias in place.
|
|
* Otherwise we need to inject a
|
|
*/
|
|
// The class should not already have a method by the oldName
|
|
Ext.Assert.isNotDefinedProp(target, oldName);
|
|
Ext.Assert.isDefinedProp(target, member);
|
|
if (enabled) {
|
|
// This call to the real method name must be late
|
|
// bound if it is to pick up overrides and such.
|
|
fn = makeAliasFn(member);
|
|
} else {
|
|
fn = makeDeprecatedMethod(displayName + oldName, member);
|
|
}
|
|
} else {
|
|
/*
|
|
* Something like:
|
|
*
|
|
* '5.1': {
|
|
* methods: {
|
|
* foo: function () { ... }
|
|
* }
|
|
* }
|
|
*
|
|
* Or this:
|
|
*
|
|
* '5.1': {
|
|
* methods: {
|
|
* foo: {
|
|
* fn: function () { ... },
|
|
* message: 'Please use "bar" instead.'
|
|
* }
|
|
* }
|
|
* }
|
|
*
|
|
* Or just this:
|
|
*
|
|
* '5.1': {
|
|
* methods: {
|
|
* foo: {
|
|
* message: 'Use something else instead.'
|
|
* }
|
|
* }
|
|
* }
|
|
*
|
|
* If this block is enabled, and "foo" is an existing
|
|
* method, than we apply the given method as an override.
|
|
* If "foo" is not existing, we simply add the method.
|
|
*
|
|
* If the block is not enabled and there is no existing
|
|
* method by that name, than we add a shim to prevent
|
|
* abuse.
|
|
*/
|
|
message = '';
|
|
if (member.message || member.fn) {
|
|
message = member.message;
|
|
member = member.fn;
|
|
}
|
|
existing = target.hasOwnProperty(oldName) && target[oldName];
|
|
if (enabled && member) {
|
|
member.$owner = me;
|
|
member.$name = oldName;
|
|
member.name = displayName + oldName;
|
|
if (existing) {
|
|
member.$previous = existing;
|
|
}
|
|
fn = member;
|
|
} else if (!existing) {
|
|
fn = makeDeprecatedMethod(displayName + oldName, null, message);
|
|
}
|
|
}
|
|
if (fn) {
|
|
target[oldName] = fn;
|
|
}
|
|
}
|
|
}
|
|
// for oldName
|
|
//-------------------------------------
|
|
// Debug only
|
|
names = deprecate.configs;
|
|
if (names) {
|
|
//
|
|
// '6.0': {
|
|
// configs: {
|
|
// dead: null,
|
|
//
|
|
// renamed: 'newName',
|
|
//
|
|
// removed: {
|
|
// message: 'This config was replaced by pixie dust'
|
|
// }
|
|
// }
|
|
// }
|
|
//
|
|
configurator.addDeprecations(names);
|
|
}
|
|
names = deprecate.properties;
|
|
if (names && !enabled) {
|
|
// For properties about the only thing we can do is (on Good
|
|
// Browsers), add warning shims for accessing them. So if the
|
|
// block is enabled, we don't want those.
|
|
for (oldName in names) {
|
|
newName = names[oldName];
|
|
if (Ext.isString(newName)) {
|
|
addDeprecatedProperty(target, displayName + oldName, newName);
|
|
} else if (newName && newName.message) {
|
|
addDeprecatedProperty(target, displayName + oldName, null, newName.message);
|
|
} else {
|
|
addDeprecatedProperty(target, displayName + oldName);
|
|
}
|
|
}
|
|
}
|
|
//-------------------------------------
|
|
// reset to handle statics and apply them to the class
|
|
deprecate = statics;
|
|
statics = null;
|
|
target = me;
|
|
}
|
|
}
|
|
},
|
|
/**
|
|
* @private
|
|
* @static
|
|
* @inheritable
|
|
* @param config
|
|
*/
|
|
extend: function(parent) {
|
|
var me = this,
|
|
parentPrototype = parent.prototype,
|
|
prototype, name, statics;
|
|
prototype = me.prototype = Ext.Object.chain(parentPrototype);
|
|
prototype.self = me;
|
|
me.superclass = prototype.superclass = parentPrototype;
|
|
if (!parent.$isClass) {
|
|
for (name in BasePrototype) {
|
|
if (name in prototype) {
|
|
prototype[name] = BasePrototype[name];
|
|
}
|
|
}
|
|
}
|
|
// Statics inheritance
|
|
statics = parentPrototype.$inheritableStatics;
|
|
if (statics) {
|
|
for (name in statics) {
|
|
if (!me.hasOwnProperty(name)) {
|
|
me[name] = parent[name];
|
|
}
|
|
}
|
|
}
|
|
if (parent.$onExtended) {
|
|
me.$onExtended = parent.$onExtended.slice();
|
|
}
|
|
me.getConfigurator();
|
|
},
|
|
/**
|
|
* @private
|
|
* @static
|
|
* @inheritable
|
|
*/
|
|
$onExtended: [],
|
|
/**
|
|
* @private
|
|
* @static
|
|
* @inheritable
|
|
*/
|
|
triggerExtended: function() {
|
|
Ext.classSystemMonitor && Ext.classSystemMonitor(this, 'Ext.Base#triggerExtended', arguments);
|
|
var callbacks = this.$onExtended,
|
|
ln = callbacks.length,
|
|
i, callback;
|
|
if (ln > 0) {
|
|
for (i = 0; i < ln; i++) {
|
|
callback = callbacks[i];
|
|
callback.fn.apply(callback.scope || this, arguments);
|
|
}
|
|
}
|
|
},
|
|
/**
|
|
* @private
|
|
* @static
|
|
* @inheritable
|
|
*/
|
|
onExtended: function(fn, scope) {
|
|
this.$onExtended.push({
|
|
fn: fn,
|
|
scope: scope
|
|
});
|
|
return this;
|
|
},
|
|
/**
|
|
* Add / override static properties of this class.
|
|
*
|
|
* Ext.define('My.cool.Class', {
|
|
* ...
|
|
* });
|
|
*
|
|
* My.cool.Class.addStatics({
|
|
* someProperty: 'someValue', // My.cool.Class.someProperty = 'someValue'
|
|
* method1: function() { ... }, // My.cool.Class.method1 = function() { ... };
|
|
* method2: function() { ... } // My.cool.Class.method2 = function() { ... };
|
|
* });
|
|
*
|
|
* @param {Object} members
|
|
* @return {Ext.Base} this
|
|
* @static
|
|
* @inheritable
|
|
*/
|
|
addStatics: function(members) {
|
|
this.addMembers(members, true);
|
|
return this;
|
|
},
|
|
/**
|
|
* @private
|
|
* @static
|
|
* @inheritable
|
|
* @param {Object} members
|
|
*/
|
|
addInheritableStatics: function(members) {
|
|
var me = this,
|
|
proto = me.prototype,
|
|
inheritableStatics = me.$inheritableStatics,
|
|
name, member, current;
|
|
if (!inheritableStatics) {
|
|
inheritableStatics = Ext.apply({}, proto.$inheritableStatics);
|
|
me.$inheritableStatics = proto.$inheritableStatics = inheritableStatics;
|
|
}
|
|
var className = Ext.getClassName(me) + '.';
|
|
for (name in members) {
|
|
if (members.hasOwnProperty(name)) {
|
|
member = members[name];
|
|
current = me[name];
|
|
if (typeof member == 'function') {
|
|
member.name = className + name;
|
|
}
|
|
if (typeof current === 'function' && !current.$isClass && !current.$nullFn) {
|
|
member.$previous = current;
|
|
}
|
|
me[name] = member;
|
|
inheritableStatics[name] = true;
|
|
}
|
|
}
|
|
return me;
|
|
},
|
|
/**
|
|
* Add methods / properties to the prototype of this class.
|
|
*
|
|
* Ext.define('My.awesome.Cat', {
|
|
* constructor: function() {
|
|
* ...
|
|
* }
|
|
* });
|
|
*
|
|
* My.awesome.Cat.addMembers({
|
|
* meow: function() {
|
|
* alert('Meowww...');
|
|
* }
|
|
* });
|
|
*
|
|
* var kitty = new My.awesome.Cat();
|
|
* kitty.meow();
|
|
*
|
|
* @param {Object} members The members to add to this class.
|
|
* @param {Boolean} [isStatic=false] Pass `true` if the members are static.
|
|
* @param {Boolean} [privacy=false] Pass `true` if the members are private. This
|
|
* only has meaning in debug mode and only for methods.
|
|
* @static
|
|
* @inheritable
|
|
*/
|
|
addMembers: function(members, isStatic, privacy) {
|
|
var me = this,
|
|
// this class
|
|
cloneFunction = Ext.Function.clone,
|
|
target = isStatic ? me : me.prototype,
|
|
defaultConfig = !isStatic && target.defaultConfig,
|
|
enumerables = Ext.enumerables,
|
|
privates = members.privates,
|
|
configs, i, ln, member, name, subPrivacy, privateStatics;
|
|
var displayName = (me.$className || '') + '#';
|
|
if (privates) {
|
|
// This won't run for normal class private members but will pick up all
|
|
// others (statics, overrides, etc).
|
|
delete members.privates;
|
|
if (!isStatic) {
|
|
privateStatics = privates.statics;
|
|
delete privates.statics;
|
|
}
|
|
subPrivacy = privates.privacy || privacy || 'framework';
|
|
me.addMembers(privates, isStatic, subPrivacy);
|
|
if (privateStatics) {
|
|
me.addMembers(privateStatics, true, subPrivacy);
|
|
}
|
|
}
|
|
for (name in members) {
|
|
if (members.hasOwnProperty(name)) {
|
|
member = members[name];
|
|
if (privacy === true) {
|
|
privacy = 'framework';
|
|
}
|
|
if (member && member.$nullFn && privacy !== member.$privacy) {
|
|
Ext.raise('Cannot use stock function for private method ' + (me.$className ? me.$className + '#' : '') + name);
|
|
}
|
|
if (typeof member === 'function' && !member.$isClass && !member.$nullFn) {
|
|
if (member.$owner) {
|
|
member = cloneFunction(member);
|
|
}
|
|
if (target.hasOwnProperty(name)) {
|
|
member.$previous = target[name];
|
|
}
|
|
// This information is needed by callParent() and callSuper() as
|
|
// well as statics() and even Ext.fly().
|
|
member.$owner = me;
|
|
member.$name = name;
|
|
member.name = displayName + name;
|
|
var existing = target[name];
|
|
if (privacy) {
|
|
member.$privacy = privacy;
|
|
// The general idea here is that an existing, non-private
|
|
// method can be marked private. This is because the other
|
|
// way is strictly forbidden (private method going public)
|
|
// so if a method is in that gray area it can only be made
|
|
// private in doc form which allows a derived class to make
|
|
// it public.
|
|
if (existing && existing.$privacy && existing.$privacy !== privacy) {
|
|
Ext.privacyViolation(me, existing, member, isStatic);
|
|
}
|
|
} else if (existing && existing.$privacy) {
|
|
Ext.privacyViolation(me, existing, member, isStatic);
|
|
}
|
|
}
|
|
// The last part of the check here resolves a conflict if we have the same property
|
|
// declared as both a config and a member on the class so that the config wins.
|
|
else if (defaultConfig && (name in defaultConfig) && !target.config.hasOwnProperty(name)) {
|
|
// This is a config property so it must be added to the configs
|
|
// collection not just smashed on the prototype...
|
|
(configs || (configs = {}))[name] = member;
|
|
|
|
continue;
|
|
}
|
|
target[name] = member;
|
|
}
|
|
}
|
|
if (configs) {
|
|
// Add any configs found in the normal members arena:
|
|
me.addConfig(configs);
|
|
}
|
|
if (enumerables) {
|
|
for (i = 0 , ln = enumerables.length; i < ln; ++i) {
|
|
if (members.hasOwnProperty(name = enumerables[i])) {
|
|
member = members[name];
|
|
// The enumerables are all functions...
|
|
if (member && !member.$nullFn) {
|
|
if (member.$owner) {
|
|
member = cloneFunction(member);
|
|
}
|
|
member.$owner = me;
|
|
member.$name = name;
|
|
member.name = displayName + name;
|
|
if (target.hasOwnProperty(name)) {
|
|
member.$previous = target[name];
|
|
}
|
|
}
|
|
target[name] = member;
|
|
}
|
|
}
|
|
}
|
|
return this;
|
|
},
|
|
/**
|
|
* @private
|
|
* @static
|
|
* @inheritable
|
|
* @param name
|
|
* @param member
|
|
*/
|
|
addMember: function(name, member) {
|
|
oneMember[name] = member;
|
|
this.addMembers(oneMember);
|
|
delete oneMember[name];
|
|
return this;
|
|
},
|
|
/**
|
|
* Borrow another class' members to the prototype of this class.
|
|
*
|
|
* Ext.define('Bank', {
|
|
* money: '$$$',
|
|
* printMoney: function() {
|
|
* alert('$$$$$$$');
|
|
* }
|
|
* });
|
|
*
|
|
* Ext.define('Thief', {
|
|
* ...
|
|
* });
|
|
*
|
|
* Thief.borrow(Bank, ['money', 'printMoney']);
|
|
*
|
|
* var steve = new Thief();
|
|
*
|
|
* alert(steve.money); // alerts '$$$'
|
|
* steve.printMoney(); // alerts '$$$$$$$'
|
|
*
|
|
* @param {Ext.Base} fromClass The class to borrow members from
|
|
* @param {Array/String} members The names of the members to borrow
|
|
* @return {Ext.Base} this
|
|
* @static
|
|
* @inheritable
|
|
* @private
|
|
*/
|
|
borrow: function(fromClass, members) {
|
|
Ext.classSystemMonitor && Ext.classSystemMonitor(this, 'Ext.Base#borrow', arguments);
|
|
var prototype = fromClass.prototype,
|
|
membersObj = {},
|
|
i, ln, name;
|
|
members = Ext.Array.from(members);
|
|
for (i = 0 , ln = members.length; i < ln; i++) {
|
|
name = members[i];
|
|
membersObj[name] = prototype[name];
|
|
}
|
|
return this.addMembers(membersObj);
|
|
},
|
|
/**
|
|
* Override members of this class. Overridden methods can be invoked via
|
|
* {@link Ext.Base#callParent}.
|
|
*
|
|
* Ext.define('My.Cat', {
|
|
* constructor: function() {
|
|
* alert("I'm a cat!");
|
|
* }
|
|
* });
|
|
*
|
|
* My.Cat.override({
|
|
* constructor: function() {
|
|
* alert("I'm going to be a cat!");
|
|
*
|
|
* this.callParent(arguments);
|
|
*
|
|
* alert("Meeeeoooowwww");
|
|
* }
|
|
* });
|
|
*
|
|
* var kitty = new My.Cat(); // alerts "I'm going to be a cat!"
|
|
* // alerts "I'm a cat!"
|
|
* // alerts "Meeeeoooowwww"
|
|
*
|
|
* Direct use of this method should be rare. Use {@link Ext#define Ext.define}
|
|
* instead:
|
|
*
|
|
* Ext.define('My.CatOverride', {
|
|
* override: 'My.Cat',
|
|
* constructor: function() {
|
|
* alert("I'm going to be a cat!");
|
|
*
|
|
* this.callParent(arguments);
|
|
*
|
|
* alert("Meeeeoooowwww");
|
|
* }
|
|
* });
|
|
*
|
|
* The above accomplishes the same result but can be managed by the {@link Ext.Loader}
|
|
* which can properly order the override and its target class and the build process
|
|
* can determine whether the override is needed based on the required state of the
|
|
* target class (My.Cat).
|
|
*
|
|
* @param {Object} members The properties to add to this class. This should be
|
|
* specified as an object literal containing one or more properties.
|
|
* @return {Ext.Base} this class
|
|
* @static
|
|
* @inheritable
|
|
*/
|
|
override: function(members) {
|
|
var me = this,
|
|
statics = members.statics,
|
|
inheritableStatics = members.inheritableStatics,
|
|
config = members.config,
|
|
mixins = members.mixins,
|
|
cachedConfig = members.cachedConfig;
|
|
if (statics || inheritableStatics || config) {
|
|
members = Ext.apply({}, members);
|
|
}
|
|
if (statics) {
|
|
me.addMembers(statics, true);
|
|
delete members.statics;
|
|
}
|
|
if (inheritableStatics) {
|
|
me.addInheritableStatics(inheritableStatics);
|
|
delete members.inheritableStatics;
|
|
}
|
|
if (members.platformConfig) {
|
|
me.addPlatformConfig(members);
|
|
}
|
|
if (config) {
|
|
me.addConfig(config);
|
|
delete members.config;
|
|
}
|
|
if (cachedConfig) {
|
|
me.addCachedConfig(cachedConfig);
|
|
delete members.cachedConfig;
|
|
}
|
|
delete members.mixins;
|
|
me.addMembers(members);
|
|
if (mixins) {
|
|
me.mixin(mixins);
|
|
}
|
|
return me;
|
|
},
|
|
addPlatformConfig: function(data) {
|
|
var me = this,
|
|
platformConfigs = data.platformConfig,
|
|
config = data.config,
|
|
added, classConfigs, configs, configurator, hoisted, keys, name, value, i, ln;
|
|
delete data.platformConfig;
|
|
if (platformConfigs instanceof Array) {
|
|
throw new Error('platformConfigs must be specified as an object.');
|
|
}
|
|
configurator = me.getConfigurator();
|
|
classConfigs = configurator.configs;
|
|
// Get the keys shortest to longest (ish).
|
|
keys = Ext.getPlatformConfigKeys(platformConfigs);
|
|
// To leverage the Configurator#add method, we want to generate potentially
|
|
// two objects to pass in: "added" and "hoisted". For any properties in an
|
|
// active platformConfig rule that set proper Configs in the base class, we
|
|
// need to put them in "added". If instead of the proper Config coming from
|
|
// a base class, it comes from this class's config block, we still need to
|
|
// put that config in "added" but we also need move the class-level config
|
|
// out of "config" and into "hoisted".
|
|
//
|
|
// This will ensure that the config defined at the class level is added to
|
|
// the Configurator first.
|
|
for (i = 0 , ln = keys.length; i < ln; ++i) {
|
|
configs = platformConfigs[keys[i]];
|
|
hoisted = added = null;
|
|
for (name in configs) {
|
|
value = configs[name];
|
|
// We have a few possibilities for each config name:
|
|
if (config && name in config) {
|
|
// It is a proper Config defined by this class.
|
|
(added || (added = {}))[name] = value;
|
|
(hoisted || (hoisted = {}))[name] = config[name];
|
|
delete config[name];
|
|
} else if (name in classConfigs) {
|
|
// It is a proper Config defined by a base class.
|
|
(added || (added = {}))[name] = value;
|
|
} else {
|
|
// It is just a property to put on the prototype.
|
|
data[name] = value;
|
|
}
|
|
}
|
|
if (hoisted) {
|
|
configurator.add(hoisted);
|
|
}
|
|
if (added) {
|
|
configurator.add(added);
|
|
}
|
|
}
|
|
},
|
|
/**
|
|
* @protected
|
|
* @static
|
|
* @inheritable
|
|
*/
|
|
callParent: function(args) {
|
|
var method;
|
|
// This code is intentionally inlined for the least amount of debugger stepping
|
|
return (method = this.callParent.caller) && (method.$previous || ((method = method.$owner ? method : method.caller) && method.$owner.superclass.self[method.$name])).apply(this, args || noArgs);
|
|
},
|
|
/**
|
|
* @protected
|
|
* @static
|
|
* @inheritable
|
|
*/
|
|
callSuper: function(args) {
|
|
var method;
|
|
// This code is intentionally inlined for the least amount of debugger stepping
|
|
return (method = this.callSuper.caller) && ((method = method.$owner ? method : method.caller) && method.$owner.superclass.self[method.$name]).apply(this, args || noArgs);
|
|
},
|
|
/**
|
|
* Used internally by the mixins pre-processor
|
|
* @private
|
|
* @static
|
|
* @inheritable
|
|
*/
|
|
mixin: function(name, mixinClass) {
|
|
var me = this,
|
|
mixin, prototype, key, statics, i, ln, mixinName, name, mixinValue, mixins, mixinStatics;
|
|
if (typeof name !== 'string') {
|
|
mixins = name;
|
|
if (mixins instanceof Array) {
|
|
for (i = 0 , ln = mixins.length; i < ln; i++) {
|
|
mixin = mixins[i];
|
|
me.mixin(mixin.prototype.mixinId || mixin.$className, mixin);
|
|
}
|
|
} else {
|
|
// Not a string or array - process the object form:
|
|
// mixins: {
|
|
// foo: ...
|
|
// }
|
|
for (mixinName in mixins) {
|
|
me.mixin(mixinName, mixins[mixinName]);
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
mixin = mixinClass.prototype;
|
|
prototype = me.prototype;
|
|
if (mixin.onClassMixedIn) {
|
|
mixin.onClassMixedIn.call(mixinClass, me);
|
|
}
|
|
if (!prototype.hasOwnProperty('mixins')) {
|
|
if ('mixins' in prototype) {
|
|
prototype.mixins = Ext.Object.chain(prototype.mixins);
|
|
} else {
|
|
prototype.mixins = {};
|
|
}
|
|
}
|
|
for (key in mixin) {
|
|
mixinValue = mixin[key];
|
|
if (key === 'mixins') {
|
|
// if 2 superclasses (e.g. a base class and a mixin) of this class both
|
|
// have a mixin with the same id, the first one wins, that is to say,
|
|
// the first mixin's methods to be applied to the prototype will not
|
|
// be overwritten by the second one. Since this is the case we also
|
|
// want to make sure we use the first mixin's prototype as the mixin
|
|
// reference, hence the "applyIf" below. A real world example of this
|
|
// is Ext.Widget which mixes in Ext.mixin.Observable. Ext.Widget can
|
|
// be mixed into subclasses of Ext.Component, which mixes in
|
|
// Ext.util.Observable. In this example, since the first "observable"
|
|
// mixin's methods win, we also want its reference to be preserved.
|
|
Ext.applyIf(prototype.mixins, mixinValue);
|
|
} else if (!(key === 'mixinId' || key === 'config' || key === '$inheritableStatics') && (prototype[key] === undefined)) {
|
|
prototype[key] = mixinValue;
|
|
}
|
|
}
|
|
// Mixin statics inheritance
|
|
statics = mixin.$inheritableStatics;
|
|
if (statics) {
|
|
mixinStatics = {};
|
|
for (name in statics) {
|
|
if (!me.hasOwnProperty(name)) {
|
|
mixinStatics[name] = mixinClass[name];
|
|
}
|
|
}
|
|
me.addInheritableStatics(mixinStatics);
|
|
}
|
|
if ('config' in mixin) {
|
|
me.addConfig(mixin.config, mixinClass);
|
|
}
|
|
prototype.mixins[name] = mixin;
|
|
if (mixin.afterClassMixedIn) {
|
|
mixin.afterClassMixedIn.call(mixinClass, me);
|
|
}
|
|
return me;
|
|
},
|
|
/**
|
|
* Adds new config properties to this class. This is called for classes when they
|
|
* are declared, then for any mixins that class may define and finally for any
|
|
* overrides defined that target the class.
|
|
*
|
|
* @param {Object} config
|
|
* @param {Ext.Class} [mixinClass] The mixin class if the configs are from a mixin.
|
|
* @private
|
|
* @static
|
|
* @inheritable
|
|
*/
|
|
addConfig: function(config, mixinClass) {
|
|
var cfg = this.$config || this.getConfigurator();
|
|
cfg.add(config, mixinClass);
|
|
},
|
|
addCachedConfig: function(config, isMixin) {
|
|
var cached = {},
|
|
key;
|
|
for (key in config) {
|
|
cached[key] = {
|
|
cached: true,
|
|
$value: config[key]
|
|
};
|
|
}
|
|
this.addConfig(cached, isMixin);
|
|
},
|
|
/**
|
|
* Returns the `Ext.Configurator` for this class.
|
|
*
|
|
* @return {Ext.Configurator}
|
|
* @private
|
|
* @static
|
|
* @inheritable
|
|
*/
|
|
getConfigurator: function() {
|
|
// the Ext.Configurator ctor will set $config so micro-opt out fn call:
|
|
return this.$config || new Ext.Configurator(this);
|
|
},
|
|
/**
|
|
* Get the current class' name in string format.
|
|
*
|
|
* Ext.define('My.cool.Class', {
|
|
* constructor: function() {
|
|
* alert(this.self.getName()); // alerts 'My.cool.Class'
|
|
* }
|
|
* });
|
|
*
|
|
* My.cool.Class.getName(); // 'My.cool.Class'
|
|
*
|
|
* @return {String} className
|
|
* @static
|
|
* @inheritable
|
|
*/
|
|
getName: function() {
|
|
return Ext.getClassName(this);
|
|
},
|
|
/**
|
|
* Create aliases for existing prototype methods. Example:
|
|
*
|
|
* Ext.define('My.cool.Class', {
|
|
* method1: function() { ... },
|
|
* method2: function() { ... }
|
|
* });
|
|
*
|
|
* var test = new My.cool.Class();
|
|
*
|
|
* My.cool.Class.createAlias({
|
|
* method3: 'method1',
|
|
* method4: 'method2'
|
|
* });
|
|
*
|
|
* test.method3(); // test.method1()
|
|
*
|
|
* My.cool.Class.createAlias('method5', 'method3');
|
|
*
|
|
* test.method5(); // test.method3() -> test.method1()
|
|
*
|
|
* @param {String/Object} alias The new method name, or an object to set multiple aliases. See
|
|
* {@link Ext.Function#flexSetter flexSetter}
|
|
* @param {String/Object} origin The original method name
|
|
* @static
|
|
* @inheritable
|
|
* @method
|
|
*/
|
|
createAlias: flexSetter(function(alias, origin) {
|
|
aliasOneMember[alias] = function() {
|
|
return this[origin].apply(this, arguments);
|
|
};
|
|
this.override(aliasOneMember);
|
|
delete aliasOneMember[alias];
|
|
})
|
|
});
|
|
// Capture the set of static members on Ext.Base that we want to copy to all
|
|
// derived classes. This array is used by Ext.Class as well as the optimizer.
|
|
for (baseStaticMember in Base) {
|
|
if (Base.hasOwnProperty(baseStaticMember)) {
|
|
baseStaticMembers.push(baseStaticMember);
|
|
}
|
|
}
|
|
Base.$staticMembers = baseStaticMembers;
|
|
Base.getConfigurator();
|
|
// lazily create now so as not capture in $staticMembers
|
|
Base.addMembers({
|
|
/** @private */
|
|
$className: 'Ext.Base',
|
|
/**
|
|
* @property {Boolean} isInstance
|
|
* This value is `true` and is used to identify plain objects from instances of
|
|
* a defined class.
|
|
* @protected
|
|
* @readonly
|
|
*/
|
|
isInstance: true,
|
|
/**
|
|
* @property {Boolean} [$configPrefixed]
|
|
* The value `true` causes `config` values to be stored on instances using a
|
|
* property name prefixed with an underscore ("_") character. A value of `false`
|
|
* stores `config` values as properties using their exact name (no prefix).
|
|
* @private
|
|
* @since 5.0.0
|
|
*/
|
|
$configPrefixed: true,
|
|
/**
|
|
* @property {Boolean} [$configStrict]
|
|
* The value `true` instructs the `initConfig` method to only honor values for
|
|
* properties declared in the `config` block of a class. When `false`, properties
|
|
* that are not declared in a `config` block will be placed on the instance.
|
|
* @private
|
|
* @since 5.0.0
|
|
*/
|
|
$configStrict: true,
|
|
/**
|
|
* @property {Boolean} isConfiguring
|
|
* This property is set to `true` during the call to `initConfig`.
|
|
* @protected
|
|
* @readonly
|
|
* @since 5.0.0
|
|
*/
|
|
isConfiguring: false,
|
|
/**
|
|
* @property {Boolean} isFirstInstance
|
|
* This property is set to `true` if this instance is the first of its class.
|
|
* @protected
|
|
* @readonly
|
|
* @since 5.0.0
|
|
*/
|
|
isFirstInstance: false,
|
|
/**
|
|
* @property {Boolean} destroyed
|
|
* This property is set to `true` after the `destroy` method is called.
|
|
* @protected
|
|
*/
|
|
destroyed: false,
|
|
/**
|
|
* @property {Boolean/"async"} [clearPropertiesOnDestroy=true]
|
|
* Setting this property to `false` will prevent nulling object references
|
|
* on a Class instance after destruction. Setting this to `"async"` will delay
|
|
* the clearing for approx 50ms.
|
|
* @protected
|
|
* @since 6.2.0
|
|
*/
|
|
clearPropertiesOnDestroy: true,
|
|
/**
|
|
* @property {Boolean} [clearPrototypeOnDestroy=false]
|
|
* Setting this property to `true` will result in setting the object's
|
|
* prototype to `null` after the destruction sequence is fully completed.
|
|
* After that, most attempts at calling methods on the object instance
|
|
* will result in "method not defined" exception. This can be very helpful
|
|
* with tracking down otherwise hard to find bugs like runaway Ajax requests,
|
|
* timed functions not cleared on destruction, etc.
|
|
*
|
|
* Note that this option can only work in browsers that support `Object.setPrototypeOf`
|
|
* method, and is only available in debugging mode.
|
|
* @private
|
|
* @since 6.2.0
|
|
*/
|
|
clearPrototypeOnDestroy: false,
|
|
/**
|
|
* Get the reference to the class from which this object was instantiated. Note that unlike {@link Ext.Base#self},
|
|
* `this.statics()` is scope-independent and it always returns the class from which it was called, regardless of what
|
|
* `this` points to during run-time
|
|
*
|
|
* Ext.define('My.Cat', {
|
|
* statics: {
|
|
* totalCreated: 0,
|
|
* speciesName: 'Cat' // My.Cat.speciesName = 'Cat'
|
|
* },
|
|
*
|
|
* constructor: function() {
|
|
* var statics = this.statics();
|
|
*
|
|
* alert(statics.speciesName); // always equals to 'Cat' no matter what 'this' refers to
|
|
* // equivalent to: My.Cat.speciesName
|
|
*
|
|
* alert(this.self.speciesName); // dependent on 'this'
|
|
*
|
|
* statics.totalCreated++;
|
|
* },
|
|
*
|
|
* clone: function() {
|
|
* var cloned = new this.self(); // dependent on 'this'
|
|
*
|
|
* cloned.groupName = this.statics().speciesName; // equivalent to: My.Cat.speciesName
|
|
*
|
|
* return cloned;
|
|
* }
|
|
* });
|
|
*
|
|
*
|
|
* Ext.define('My.SnowLeopard', {
|
|
* extend: 'My.Cat',
|
|
*
|
|
* statics: {
|
|
* speciesName: 'Snow Leopard' // My.SnowLeopard.speciesName = 'Snow Leopard'
|
|
* },
|
|
*
|
|
* constructor: function() {
|
|
* this.callParent();
|
|
* }
|
|
* });
|
|
*
|
|
* var cat = new My.Cat(); // alerts 'Cat', then alerts 'Cat'
|
|
*
|
|
* var snowLeopard = new My.SnowLeopard(); // alerts 'Cat', then alerts 'Snow Leopard'
|
|
*
|
|
* var clone = snowLeopard.clone();
|
|
* alert(Ext.getClassName(clone)); // alerts 'My.SnowLeopard'
|
|
* alert(clone.groupName); // alerts 'Cat'
|
|
*
|
|
* alert(My.Cat.totalCreated); // alerts 3
|
|
*
|
|
* @protected
|
|
* @return {Ext.Class}
|
|
*/
|
|
statics: function() {
|
|
var method = this.statics.caller,
|
|
self = this.self;
|
|
if (!method) {
|
|
return self;
|
|
}
|
|
return method.$owner;
|
|
},
|
|
/**
|
|
* Call the "parent" method of the current method. That is the method previously
|
|
* overridden by derivation or by an override (see {@link Ext#define}).
|
|
*
|
|
* Ext.define('My.Base', {
|
|
* constructor: function (x) {
|
|
* this.x = x;
|
|
* },
|
|
*
|
|
* statics: {
|
|
* method: function (x) {
|
|
* return x;
|
|
* }
|
|
* }
|
|
* });
|
|
*
|
|
* Ext.define('My.Derived', {
|
|
* extend: 'My.Base',
|
|
*
|
|
* constructor: function () {
|
|
* this.callParent([21]);
|
|
* }
|
|
* });
|
|
*
|
|
* var obj = new My.Derived();
|
|
*
|
|
* alert(obj.x); // alerts 21
|
|
*
|
|
* This can be used with an override as follows:
|
|
*
|
|
* Ext.define('My.DerivedOverride', {
|
|
* override: 'My.Derived',
|
|
*
|
|
* constructor: function (x) {
|
|
* this.callParent([x*2]); // calls original My.Derived constructor
|
|
* }
|
|
* });
|
|
*
|
|
* var obj = new My.Derived();
|
|
*
|
|
* alert(obj.x); // now alerts 42
|
|
*
|
|
* This also works with static and private methods.
|
|
*
|
|
* Ext.define('My.Derived2', {
|
|
* extend: 'My.Base',
|
|
*
|
|
* // privates: {
|
|
* statics: {
|
|
* method: function (x) {
|
|
* return this.callParent([x*2]); // calls My.Base.method
|
|
* }
|
|
* }
|
|
* });
|
|
*
|
|
* alert(My.Base.method(10)); // alerts 10
|
|
* alert(My.Derived2.method(10)); // alerts 20
|
|
*
|
|
* Lastly, it also works with overridden static methods.
|
|
*
|
|
* Ext.define('My.Derived2Override', {
|
|
* override: 'My.Derived2',
|
|
*
|
|
* // privates: {
|
|
* statics: {
|
|
* method: function (x) {
|
|
* return this.callParent([x*2]); // calls My.Derived2.method
|
|
* }
|
|
* }
|
|
* });
|
|
*
|
|
* alert(My.Derived2.method(10); // now alerts 40
|
|
*
|
|
* To override a method and replace it and also call the superclass method, use
|
|
* {@link #method-callSuper}. This is often done to patch a method to fix a bug.
|
|
*
|
|
* @protected
|
|
* @param {Array/Arguments} args The arguments, either an array or the `arguments` object
|
|
* from the current method, for example: `this.callParent(arguments)`
|
|
* @return {Object} Returns the result of calling the parent method
|
|
*/
|
|
callParent: function(args) {
|
|
// NOTE: this code is deliberately as few expressions (and no function calls)
|
|
// as possible so that a debugger can skip over this noise with the minimum number
|
|
// of steps. Basically, just hit Step Into until you are where you really wanted
|
|
// to be.
|
|
var method,
|
|
superMethod = (method = this.callParent.caller) && (method.$previous || ((method = method.$owner ? method : method.caller) && method.$owner.superclass[method.$name]));
|
|
if (!superMethod) {
|
|
method = this.callParent.caller;
|
|
var parentClass, methodName;
|
|
if (!method.$owner) {
|
|
if (!method.caller) {
|
|
throw new Error("Attempting to call a protected method from the public scope, which is not allowed");
|
|
}
|
|
method = method.caller;
|
|
}
|
|
parentClass = method.$owner.superclass;
|
|
methodName = method.$name;
|
|
if (!(methodName in parentClass)) {
|
|
throw new Error("this.callParent() was called but there's no such method (" + methodName + ") found in the parent class (" + (Ext.getClassName(parentClass) || 'Object') + ")");
|
|
}
|
|
}
|
|
return superMethod.apply(this, args || noArgs);
|
|
},
|
|
/**
|
|
* This method is used by an **override** to call the superclass method but
|
|
* bypass any overridden method. This is often done to "patch" a method that
|
|
* contains a bug but for whatever reason cannot be fixed directly.
|
|
*
|
|
* Consider:
|
|
*
|
|
* Ext.define('Ext.some.Class', {
|
|
* method: function () {
|
|
* console.log('Good');
|
|
* }
|
|
* });
|
|
*
|
|
* Ext.define('Ext.some.DerivedClass', {
|
|
* extend: 'Ext.some.Class',
|
|
*
|
|
* method: function () {
|
|
* console.log('Bad');
|
|
*
|
|
* // ... logic but with a bug ...
|
|
*
|
|
* this.callParent();
|
|
* }
|
|
* });
|
|
*
|
|
* To patch the bug in `Ext.some.DerivedClass.method`, the typical solution is to create an
|
|
* override:
|
|
*
|
|
* Ext.define('App.patches.DerivedClass', {
|
|
* override: 'Ext.some.DerivedClass',
|
|
*
|
|
* method: function () {
|
|
* console.log('Fixed');
|
|
*
|
|
* // ... logic but with bug fixed ...
|
|
*
|
|
* this.callSuper();
|
|
* }
|
|
* });
|
|
*
|
|
* The patch method cannot use {@link #method-callParent} to call the superclass
|
|
* `method` since that would call the overridden method containing the bug. In
|
|
* other words, the above patch would only produce "Fixed" then "Good" in the
|
|
* console log, whereas, using `callParent` would produce "Fixed" then "Bad"
|
|
* then "Good".
|
|
*
|
|
* @protected
|
|
* @param {Array/Arguments} args The arguments, either an array or the `arguments` object
|
|
* from the current method, for example: `this.callSuper(arguments)`
|
|
* @return {Object} Returns the result of calling the superclass method
|
|
*/
|
|
callSuper: function(args) {
|
|
// NOTE: this code is deliberately as few expressions (and no function calls)
|
|
// as possible so that a debugger can skip over this noise with the minimum number
|
|
// of steps. Basically, just hit Step Into until you are where you really wanted
|
|
// to be.
|
|
var method,
|
|
superMethod = (method = this.callSuper.caller) && ((method = method.$owner ? method : method.caller) && method.$owner.superclass[method.$name]);
|
|
if (!superMethod) {
|
|
method = this.callSuper.caller;
|
|
var parentClass, methodName;
|
|
if (!method.$owner) {
|
|
if (!method.caller) {
|
|
throw new Error("Attempting to call a protected method from the public scope, which is not allowed");
|
|
}
|
|
method = method.caller;
|
|
}
|
|
parentClass = method.$owner.superclass;
|
|
methodName = method.$name;
|
|
if (!(methodName in parentClass)) {
|
|
throw new Error("this.callSuper() was called but there's no such method (" + methodName + ") found in the parent class (" + (Ext.getClassName(parentClass) || 'Object') + ")");
|
|
}
|
|
}
|
|
return superMethod.apply(this, args || noArgs);
|
|
},
|
|
/**
|
|
* @property {Ext.Class} self
|
|
*
|
|
* Get the reference to the current class from which this object was instantiated. Unlike {@link Ext.Base#statics},
|
|
* `this.self` is scope-dependent and it's meant to be used for dynamic inheritance. See {@link Ext.Base#statics}
|
|
* for a detailed comparison
|
|
*
|
|
* Ext.define('My.Cat', {
|
|
* statics: {
|
|
* speciesName: 'Cat' // My.Cat.speciesName = 'Cat'
|
|
* },
|
|
*
|
|
* constructor: function() {
|
|
* alert(this.self.speciesName); // dependent on 'this'
|
|
* },
|
|
*
|
|
* clone: function() {
|
|
* return new this.self();
|
|
* }
|
|
* });
|
|
*
|
|
*
|
|
* Ext.define('My.SnowLeopard', {
|
|
* extend: 'My.Cat',
|
|
* statics: {
|
|
* speciesName: 'Snow Leopard' // My.SnowLeopard.speciesName = 'Snow Leopard'
|
|
* }
|
|
* });
|
|
*
|
|
* var cat = new My.Cat(); // alerts 'Cat'
|
|
* var snowLeopard = new My.SnowLeopard(); // alerts 'Snow Leopard'
|
|
*
|
|
* var clone = snowLeopard.clone();
|
|
* alert(Ext.getClassName(clone)); // alerts 'My.SnowLeopard'
|
|
*
|
|
* @protected
|
|
*/
|
|
self: Base,
|
|
// Default constructor, simply returns `this`
|
|
constructor: function() {
|
|
return this;
|
|
},
|
|
/**
|
|
* Initialize configuration for this class. a typical example:
|
|
*
|
|
* Ext.define('My.awesome.Class', {
|
|
* // The default config
|
|
* config: {
|
|
* name: 'Awesome',
|
|
* isAwesome: true
|
|
* },
|
|
*
|
|
* constructor: function(config) {
|
|
* this.initConfig(config);
|
|
* }
|
|
* });
|
|
*
|
|
* var awesome = new My.awesome.Class({
|
|
* name: 'Super Awesome'
|
|
* });
|
|
*
|
|
* alert(awesome.getName()); // 'Super Awesome'
|
|
*
|
|
* @protected
|
|
* @param {Object} config
|
|
* @return {Ext.Base} this
|
|
*/
|
|
initConfig: function(instanceConfig) {
|
|
var me = this,
|
|
cfg = me.self.getConfigurator();
|
|
me.initConfig = Ext.emptyFn;
|
|
// ignore subsequent calls to initConfig
|
|
me.initialConfig = instanceConfig || {};
|
|
cfg.configure(me, instanceConfig);
|
|
return me;
|
|
},
|
|
beforeInitConfig: Ext.emptyFn,
|
|
/**
|
|
* Returns a specified config property value. If the name parameter is not passed,
|
|
* all current configuration options will be returned as key value pairs.
|
|
* @method
|
|
* @param {String} [name] The name of the config property to get.
|
|
* @param {Boolean} [peek=false] `true` to peek at the raw value without calling the getter.
|
|
* @return {Object} The config property value.
|
|
*/
|
|
getConfig: getConfig,
|
|
/**
|
|
* Sets a single/multiple configuration options.
|
|
* @method
|
|
* @param {String/Object} name The name of the property to set, or a set of key value pairs to set.
|
|
* @param {Object} [value] The value to set for the name parameter.
|
|
* @return {Ext.Base} this
|
|
*/
|
|
setConfig: function(name, value, /* private */
|
|
options) {
|
|
// options can have the following properties:
|
|
// - defaults `true` to only set the config(s) that have not been already set on
|
|
// this instance.
|
|
// - strict `false` to apply properties to the instance that are not configs,
|
|
// and do not have setters.
|
|
var me = this,
|
|
config;
|
|
if (name) {
|
|
if (typeof name === 'string') {
|
|
config = {};
|
|
config[name] = value;
|
|
} else {
|
|
config = name;
|
|
}
|
|
me.self.getConfigurator().reconfigure(me, config, options);
|
|
}
|
|
return me;
|
|
},
|
|
/**
|
|
* @private
|
|
*/
|
|
getCurrentConfig: function() {
|
|
var cfg = this.self.getConfigurator();
|
|
return cfg.getCurrentConfig(this);
|
|
},
|
|
/**
|
|
* @private
|
|
* @param config
|
|
*/
|
|
hasConfig: function(name) {
|
|
return name in this.defaultConfig;
|
|
},
|
|
/**
|
|
* Returns the initial configuration passed to the constructor when
|
|
* instantiating this class.
|
|
*
|
|
* Given this example Ext.button.Button definition and instance:
|
|
*
|
|
* Ext.define('MyApp.view.Button', {
|
|
* extend: 'Ext.button.Button',
|
|
* xtype: 'mybutton',
|
|
*
|
|
* scale: 'large',
|
|
* enableToggle: true
|
|
* });
|
|
*
|
|
* var btn = Ext.create({
|
|
* xtype: 'mybutton',
|
|
* renderTo: Ext.getBody(),
|
|
* text: 'Test Button'
|
|
* });
|
|
*
|
|
* Calling `btn.getInitialConfig()` would return an object including the config
|
|
* options passed to the `create` method:
|
|
*
|
|
* xtype: 'mybutton',
|
|
* renderTo: // The document body itself
|
|
* text: 'Test Button'
|
|
*
|
|
* Calling `btn.getInitialConfig('text')`returns **'Test Button'**.
|
|
*
|
|
* @param {String} [name] Name of the config option to return.
|
|
* @return {Object/Mixed} The full config object or a single config value
|
|
* when `name` parameter specified.
|
|
*/
|
|
getInitialConfig: function(name) {
|
|
var config = this.config;
|
|
if (!name) {
|
|
return config;
|
|
}
|
|
return config[name];
|
|
},
|
|
$links: null,
|
|
/**
|
|
* Adds a "destroyable" object to an internal list of objects that will be destroyed
|
|
* when this instance is destroyed (via `{@link #destroy}`).
|
|
* @param {String} name
|
|
* @param {Object} value
|
|
* @return {Object} The `value` passed.
|
|
* @private
|
|
*/
|
|
link: function(name, value) {
|
|
var me = this,
|
|
links = me.$links || (me.$links = {});
|
|
links[name] = true;
|
|
me[name] = value;
|
|
return value;
|
|
},
|
|
/**
|
|
* Destroys a given set of `{@link #link linked}` objects. This is only needed if
|
|
* the linked object is being destroyed before this instance.
|
|
* @param {String[]} names The names of the linked objects to destroy.
|
|
* @return {Ext.Base} this
|
|
* @private
|
|
*/
|
|
unlink: function(names) {
|
|
var me = this,
|
|
i, ln, link, value;
|
|
if (!Ext.isArray(names)) {
|
|
Ext.raise('Invalid argument - expected array of strings');
|
|
}
|
|
for (i = 0 , ln = names.length; i < ln; i++) {
|
|
link = names[i];
|
|
value = me[link];
|
|
if (value) {
|
|
if (value.isInstance && !value.destroyed) {
|
|
value.destroy();
|
|
} else if (value.parentNode && 'nodeType' in value) {
|
|
value.parentNode.removeChild(value);
|
|
}
|
|
}
|
|
me[link] = null;
|
|
}
|
|
return me;
|
|
},
|
|
$reap: function() {
|
|
var me = this,
|
|
protectedProps = me.$noClearOnDestroy,
|
|
prop, value, type;
|
|
for (prop in me) {
|
|
if ((!protectedProps || !protectedProps[prop]) && me.hasOwnProperty(prop)) {
|
|
value = me[prop];
|
|
type = typeof value;
|
|
// Object may retain references to other objects. Functions can do too
|
|
// if they are closures, and most of the *own* function properties
|
|
// are closures indeed. We skip Ext.emptyFn and the like though,
|
|
// they're mostly harmless.
|
|
if (type === 'object' || (type === 'function' && !value.$noClearOnDestroy)) {
|
|
me[prop] = null;
|
|
}
|
|
}
|
|
}
|
|
// We also want to make sure no methods are called on the destroyed object,
|
|
// because that may lead to accessing nulled properties and resulting exceptions.
|
|
if (me.clearPrototypeOnDestroy && !me.$vetoClearingPrototypeOnDestroy && Object.setPrototypeOf) {
|
|
Object.setPrototypeOf(me, null);
|
|
}
|
|
},
|
|
/**
|
|
* This method is called to cleanup an object and its resources. After calling
|
|
* this method, the object should not be used any further in any way, including
|
|
* access to its methods and properties.
|
|
*
|
|
* To prevent potential memory leaks, all object references will be nulled
|
|
* at the end of destruction sequence, unless {@link #clearPropertiesOnDestroy}
|
|
* is set to `false`.
|
|
*/
|
|
destroy: function() {
|
|
var me = this,
|
|
links = me.$links,
|
|
clearPropertiesOnDestroy = me.clearPropertiesOnDestroy;
|
|
if (links) {
|
|
me.$links = null;
|
|
me.unlink(Ext.Object.getKeys(links));
|
|
}
|
|
me.destroy = Ext.emptyFn;
|
|
// isDestroyed added for compat reasons
|
|
me.isDestroyed = me.destroyed = true;
|
|
// By this time the destruction is complete. Now we can make sure
|
|
// no objects are retained by the husk of this ex-Instance.
|
|
if (clearPropertiesOnDestroy === true) {
|
|
me.$reap();
|
|
} else if (clearPropertiesOnDestroy) {
|
|
if (clearPropertiesOnDestroy !== 'async') {
|
|
Ext.raise('Invalid value for clearPropertiesOnDestroy');
|
|
}
|
|
Reaper.add(me);
|
|
}
|
|
}
|
|
});
|
|
/**
|
|
* Call the original method that was previously overridden with {@link Ext.Base#override}
|
|
*
|
|
* Ext.define('My.Cat', {
|
|
* constructor: function() {
|
|
* alert("I'm a cat!");
|
|
* }
|
|
* });
|
|
*
|
|
* My.Cat.override({
|
|
* constructor: function() {
|
|
* alert("I'm going to be a cat!");
|
|
*
|
|
* this.callOverridden();
|
|
*
|
|
* alert("Meeeeoooowwww");
|
|
* }
|
|
* });
|
|
*
|
|
* var kitty = new My.Cat(); // alerts "I'm going to be a cat!"
|
|
* // alerts "I'm a cat!"
|
|
* // alerts "Meeeeoooowwww"
|
|
*
|
|
* @param {Array/Arguments} args The arguments, either an array or the `arguments` object
|
|
* from the current method, for example: `this.callOverridden(arguments)`
|
|
* @return {Object} Returns the result of calling the overridden method
|
|
* @protected
|
|
* @deprecated Use {@link #callParent} instead.
|
|
*/
|
|
BasePrototype.callOverridden = BasePrototype.callParent;
|
|
Ext.privacyViolation = function(cls, existing, member, isStatic) {
|
|
var name = member.$name,
|
|
conflictCls = existing.$owner && existing.$owner.$className,
|
|
s = isStatic ? 'static ' : '',
|
|
msg = member.$privacy ? 'Private ' + s + member.$privacy + ' method "' + name + '"' : 'Public ' + s + 'method "' + name + '"';
|
|
if (cls.$className) {
|
|
msg = cls.$className + ': ' + msg;
|
|
}
|
|
if (!existing.$privacy) {
|
|
msg += conflictCls ? ' hides public method inherited from ' + conflictCls : ' hides inherited public method.';
|
|
} else {
|
|
msg += conflictCls ? ' conflicts with private ' + existing.$privacy + ' method declared by ' + conflictCls : ' conflicts with inherited private ' + existing.$privacy + ' method.';
|
|
}
|
|
var compat = Ext.getCompatVersion();
|
|
var ver = Ext.getVersion();
|
|
// When compatibility is enabled, log problems instead of throwing errors.
|
|
if (ver && compat && compat.lt(ver)) {
|
|
Ext.log.error(msg);
|
|
} else {
|
|
Ext.raise(msg);
|
|
}
|
|
};
|
|
return Base;
|
|
}(Ext.Function.flexSetter));
|
|
|
|
/**
|
|
* This class is used to manage simple, LRU caches. It provides an absolutely minimal
|
|
* container interface. It is created like this:
|
|
*
|
|
* this.itemCache = new Ext.util.Cache({
|
|
* miss: function (key) {
|
|
* return new CacheItem(key);
|
|
* }
|
|
* });
|
|
*
|
|
* The `{@link #miss}` abstract method must be implemented by either a derived class or
|
|
* at the instance level as shown above.
|
|
*
|
|
* Once the cache exists and it can handle cache misses, the cache is used like so:
|
|
*
|
|
* var item = this.itemCache.get(key);
|
|
*
|
|
* The `key` is some value that uniquely identifies the cached item.
|
|
*
|
|
* In some cases, creating the cache item may require more than just the lookup key. In
|
|
* that case, any extra arguments passed to `get` will be passed to `miss`.
|
|
*
|
|
* this.otherCache = new Ext.util.Cache({
|
|
* miss: function (key, extra) {
|
|
* return new CacheItem(key, extra);
|
|
* }
|
|
* });
|
|
*
|
|
* var item = this.otherCache.get(key, extra);
|
|
*
|
|
* To process items as they are removed, you can provide an `{@link #evict}` method. The
|
|
* stock method is `Ext.emptyFn` and so does nothing.
|
|
*
|
|
* For example:
|
|
*
|
|
* this.itemCache = new Ext.util.Cache({
|
|
* miss: function (key) {
|
|
* return new CacheItem(key);
|
|
* },
|
|
*
|
|
* evict: function (key, cacheItem) {
|
|
* cacheItem.destroy();
|
|
* }
|
|
* });
|
|
*
|
|
* @class Ext.util.Cache
|
|
* @private
|
|
* @since 5.1.0
|
|
*/
|
|
(function(Cache, prototype) {
|
|
// @define Ext.util.Cache
|
|
// NOTE: We have to implement this class old-school because it is used by the
|
|
// platformConfig class processor (so Ext.define is not yet ready for action).
|
|
(Ext.util || (Ext.util = {})).Cache = Cache = function(config) {
|
|
var me = this,
|
|
head;
|
|
if (config) {
|
|
Ext.apply(me, config);
|
|
}
|
|
// Give all entries the same object shape.
|
|
me.head = head = {
|
|
id: (me.seed = 0),
|
|
key: null,
|
|
value: null
|
|
};
|
|
me.map = {};
|
|
head.next = head.prev = head;
|
|
};
|
|
Cache.prototype = prototype = {
|
|
/**
|
|
* @cfg {Number} maxSize The maximum size the cache is allowed to grow to before
|
|
* further additions cause removal of the least recently used entry.
|
|
*/
|
|
maxSize: 100,
|
|
/**
|
|
* @property {Number} count
|
|
* The number of items in this cache.
|
|
* @readonly
|
|
*/
|
|
count: 0,
|
|
/**
|
|
* This method is called by `{@link #get}` when the key is not found in the cache.
|
|
* The implementation of this method should create the (expensive) value and return
|
|
* it. Whatever arguments were passed to `{@link #get}` will be passed on to this
|
|
* method.
|
|
*
|
|
* @param {String} key The cache lookup key for the item.
|
|
* @param {Object...} args Any other arguments originally passed to `{@link #get}`.
|
|
* @method miss
|
|
* @abstract
|
|
* @protected
|
|
*/
|
|
/**
|
|
* Removes all items from this cache.
|
|
*/
|
|
clear: function() {
|
|
var me = this,
|
|
head = me.head,
|
|
entry = head.next;
|
|
head.next = head.prev = head;
|
|
if (!me.evict.$nullFn) {
|
|
for (; entry !== head; entry = entry.next) {
|
|
me.evict(entry.key, entry.value);
|
|
}
|
|
}
|
|
me.count = 0;
|
|
},
|
|
/**
|
|
* Calls the given function `fn` for each item in the cache. The items will be passed
|
|
* to `fn` from most-to-least recently used.
|
|
* @param {Function} fn The function to call for each cache item.
|
|
* @param {String} fn.key The cache key for the item.
|
|
* @param {Object} fn.value The value in the cache for the item.
|
|
* @param {Object} [scope] The `this` pointer to use for `fn`.
|
|
*/
|
|
each: function(fn, scope) {
|
|
scope = scope || this;
|
|
for (var head = this.head,
|
|
ent = head.next; ent !== head; ent = ent.next) {
|
|
if (fn.call(scope, ent.key, ent.value)) {
|
|
break;
|
|
}
|
|
}
|
|
},
|
|
/**
|
|
* Finds an item in this cache and returns its value. If the item is present, it is
|
|
* shuffled into the MRU (most-recently-used) position as necessary. If the item is
|
|
* missing, the `{@link #miss}` method is called to create the item.
|
|
*
|
|
* @param {String} key The cache key of the item.
|
|
* @param {Object...} args Arguments for the `miss` method should it be needed.
|
|
* @return {Object} The cached object.
|
|
*/
|
|
get: function(key) {
|
|
var me = this,
|
|
head = me.head,
|
|
map = me.map,
|
|
entry = map[key];
|
|
if (entry) {
|
|
if (entry.prev !== head) {
|
|
// The entry is not at the front, so remove it and insert it at the front
|
|
// (to make it the MRU - Most Recently Used).
|
|
me.unlinkEntry(entry);
|
|
me.linkEntry(entry);
|
|
}
|
|
} else {
|
|
map[key] = entry = {
|
|
id: ++me.seed,
|
|
key: key,
|
|
value: me.miss.apply(me, arguments)
|
|
};
|
|
me.linkEntry(entry);
|
|
++me.count;
|
|
while (me.count > me.maxSize) {
|
|
me.unlinkEntry(head.prev, true);
|
|
--me.count;
|
|
}
|
|
}
|
|
return entry.value;
|
|
},
|
|
//-------------------------------------------------------------------------
|
|
// Internals
|
|
/**
|
|
* This method is called internally from `{@link #get}` when the cache is full and
|
|
* the least-recently-used (LRU) item has been removed.
|
|
*
|
|
* @param {String} key The cache lookup key for the item being removed.
|
|
* @param {Object} value The cache value (returned by `{@link #miss}`) for the item
|
|
* being removed.
|
|
* @method evict
|
|
* @template
|
|
* @protected
|
|
*/
|
|
evict: Ext.emptyFn,
|
|
/**
|
|
* Inserts the given entry at the front (MRU) end of the entry list.
|
|
* @param {Object} entry The cache item entry.
|
|
* @private
|
|
*/
|
|
linkEntry: function(entry) {
|
|
var head = this.head,
|
|
first = head.next;
|
|
entry.next = first;
|
|
entry.prev = head;
|
|
head.next = entry;
|
|
first.prev = entry;
|
|
},
|
|
/**
|
|
* Removes the given entry from the entry list.
|
|
* @param {Object} entry The cache item entry.
|
|
* @param {Boolean} evicted Pass `true` if `{@link #evict}` should be called.
|
|
* @private
|
|
*/
|
|
unlinkEntry: function(entry, evicted) {
|
|
var next = entry.next,
|
|
prev = entry.prev;
|
|
prev.next = next;
|
|
next.prev = prev;
|
|
if (evicted) {
|
|
this.evict(entry.key, entry.value);
|
|
}
|
|
}
|
|
};
|
|
prototype.destroy = prototype.clear;
|
|
}());
|
|
|
|
/**
|
|
* @class Ext.Class
|
|
*
|
|
* This is a low level factory that is used by {@link Ext#define Ext.define} and should not be used
|
|
* directly in application code.
|
|
*
|
|
* The configs of this class are intended to be used in `Ext.define` calls to describe the class you
|
|
* are declaring. For example:
|
|
*
|
|
* Ext.define('App.util.Thing', {
|
|
* extend: 'App.util.Other',
|
|
*
|
|
* alias: 'util.thing',
|
|
*
|
|
* config: {
|
|
* foo: 42
|
|
* }
|
|
* });
|
|
*
|
|
* Ext.Class is the factory and **not** the superclass of everything. For the base class that **all**
|
|
* classes inherit from, see {@link Ext.Base}.
|
|
*/
|
|
(function() {
|
|
// @tag class
|
|
// @define Ext.Class
|
|
// @require Ext.Base
|
|
// @require Ext.Util
|
|
// @require Ext.util.Cache
|
|
var ExtClass,
|
|
Base = Ext.Base,
|
|
baseStaticMembers = Base.$staticMembers,
|
|
ruleKeySortFn = function(a, b) {
|
|
// longest to shortest, by text if names are equal
|
|
return (a.length - b.length) || ((a < b) ? -1 : ((a > b) ? 1 : 0));
|
|
};
|
|
// Creates a constructor that has nothing extra in its scope chain.
|
|
function makeCtor(className) {
|
|
function constructor() {
|
|
// Opera has some problems returning from a constructor when Dragonfly isn't running. The || null seems to
|
|
// be sufficient to stop it misbehaving. Known to be required against 10.53, 11.51 and 11.61.
|
|
return this.constructor.apply(this, arguments) || null;
|
|
}
|
|
if (className) {
|
|
constructor.name = className;
|
|
}
|
|
return constructor;
|
|
}
|
|
/**
|
|
* @method constructor
|
|
* Create a new anonymous class.
|
|
*
|
|
* @param {Object} data An object represent the properties of this class
|
|
* @param {Function} onCreated Optional, the callback function to be executed when this class is fully created.
|
|
* Note that the creation process can be asynchronous depending on the pre-processors used.
|
|
*
|
|
* @return {Ext.Base} The newly created class
|
|
*/
|
|
Ext.Class = ExtClass = function(Class, data, onCreated) {
|
|
if (typeof Class != 'function') {
|
|
onCreated = data;
|
|
data = Class;
|
|
Class = null;
|
|
}
|
|
if (!data) {
|
|
data = {};
|
|
}
|
|
Class = ExtClass.create(Class, data);
|
|
ExtClass.process(Class, data, onCreated);
|
|
return Class;
|
|
};
|
|
Ext.apply(ExtClass, {
|
|
makeCtor: makeCtor,
|
|
/**
|
|
* @private
|
|
*/
|
|
onBeforeCreated: function(Class, data, hooks) {
|
|
Ext.classSystemMonitor && Ext.classSystemMonitor(Class, '>> Ext.Class#onBeforeCreated', arguments);
|
|
Class.addMembers(data);
|
|
hooks.onCreated.call(Class, Class);
|
|
Ext.classSystemMonitor && Ext.classSystemMonitor(Class, '<< Ext.Class#onBeforeCreated', arguments);
|
|
},
|
|
/**
|
|
* @private
|
|
*/
|
|
create: function(Class, data) {
|
|
var i = baseStaticMembers.length,
|
|
name;
|
|
if (!Class) {
|
|
Class = makeCtor(data.$className);
|
|
}
|
|
while (i--) {
|
|
name = baseStaticMembers[i];
|
|
Class[name] = Base[name];
|
|
}
|
|
return Class;
|
|
},
|
|
/**
|
|
* @private
|
|
*/
|
|
process: function(Class, data, onCreated) {
|
|
var preprocessorStack = data.preprocessors || ExtClass.defaultPreprocessors,
|
|
registeredPreprocessors = this.preprocessors,
|
|
hooks = {
|
|
onBeforeCreated: this.onBeforeCreated
|
|
},
|
|
preprocessors = [],
|
|
preprocessor, preprocessorsProperties, i, ln, j, subLn, preprocessorProperty;
|
|
delete data.preprocessors;
|
|
Class._classHooks = hooks;
|
|
for (i = 0 , ln = preprocessorStack.length; i < ln; i++) {
|
|
preprocessor = preprocessorStack[i];
|
|
if (typeof preprocessor == 'string') {
|
|
preprocessor = registeredPreprocessors[preprocessor];
|
|
preprocessorsProperties = preprocessor.properties;
|
|
if (preprocessorsProperties === true) {
|
|
preprocessors.push(preprocessor.fn);
|
|
} else if (preprocessorsProperties) {
|
|
for (j = 0 , subLn = preprocessorsProperties.length; j < subLn; j++) {
|
|
preprocessorProperty = preprocessorsProperties[j];
|
|
if (data.hasOwnProperty(preprocessorProperty)) {
|
|
preprocessors.push(preprocessor.fn);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
preprocessors.push(preprocessor);
|
|
}
|
|
}
|
|
hooks.onCreated = onCreated ? onCreated : Ext.emptyFn;
|
|
hooks.preprocessors = preprocessors;
|
|
this.doProcess(Class, data, hooks);
|
|
},
|
|
doProcess: function(Class, data, hooks) {
|
|
var me = this,
|
|
preprocessors = hooks.preprocessors,
|
|
preprocessor = preprocessors.shift(),
|
|
doProcess = me.doProcess;
|
|
for (; preprocessor; preprocessor = preprocessors.shift()) {
|
|
// Returning false signifies an asynchronous preprocessor - it will call doProcess when we can continue
|
|
if (preprocessor.call(me, Class, data, hooks, doProcess) === false) {
|
|
return;
|
|
}
|
|
}
|
|
hooks.onBeforeCreated.apply(me, arguments);
|
|
},
|
|
/**
|
|
* @private
|
|
* */
|
|
preprocessors: {},
|
|
/**
|
|
* Register a new pre-processor to be used during the class creation process
|
|
*
|
|
* @param {String} name The pre-processor's name
|
|
* @param {Function} fn The callback function to be executed. Typical format:
|
|
*
|
|
* function(cls, data, fn) {
|
|
* // Your code here
|
|
*
|
|
* // Execute this when the processing is finished.
|
|
* // Asynchronous processing is perfectly ok
|
|
* if (fn) {
|
|
* fn.call(this, cls, data);
|
|
* }
|
|
* });
|
|
*
|
|
* @param {Function} fn.cls The created class
|
|
* @param {Object} fn.data The set of properties passed in {@link Ext.Class} constructor
|
|
* @param {Function} fn.fn The callback function that **must** to be executed when this
|
|
* pre-processor finishes, regardless of whether the processing is synchronous or asynchronous.
|
|
* @return {Ext.Class} this
|
|
* @private
|
|
* @static
|
|
*/
|
|
registerPreprocessor: function(name, fn, properties, position, relativeTo) {
|
|
if (!position) {
|
|
position = 'last';
|
|
}
|
|
if (!properties) {
|
|
properties = [
|
|
name
|
|
];
|
|
}
|
|
this.preprocessors[name] = {
|
|
name: name,
|
|
properties: properties || false,
|
|
fn: fn
|
|
};
|
|
this.setDefaultPreprocessorPosition(name, position, relativeTo);
|
|
return this;
|
|
},
|
|
/**
|
|
* Retrieve a pre-processor callback function by its name, which has been registered before
|
|
*
|
|
* @param {String} name
|
|
* @return {Function} preprocessor
|
|
* @private
|
|
* @static
|
|
*/
|
|
getPreprocessor: function(name) {
|
|
return this.preprocessors[name];
|
|
},
|
|
/**
|
|
* @private
|
|
*/
|
|
getPreprocessors: function() {
|
|
return this.preprocessors;
|
|
},
|
|
/**
|
|
* @private
|
|
*/
|
|
defaultPreprocessors: [],
|
|
/**
|
|
* Retrieve the array stack of default pre-processors
|
|
* @return {Function[]} defaultPreprocessors
|
|
* @private
|
|
* @static
|
|
*/
|
|
getDefaultPreprocessors: function() {
|
|
return this.defaultPreprocessors;
|
|
},
|
|
/**
|
|
* Set the default array stack of default pre-processors
|
|
*
|
|
* @private
|
|
* @param {Array} preprocessors
|
|
* @return {Ext.Class} this
|
|
* @static
|
|
*/
|
|
setDefaultPreprocessors: function(preprocessors) {
|
|
this.defaultPreprocessors = Ext.Array.from(preprocessors);
|
|
return this;
|
|
},
|
|
/**
|
|
* Insert this pre-processor at a specific position in the stack, optionally relative to
|
|
* any existing pre-processor. For example:
|
|
*
|
|
* Ext.Class.registerPreprocessor('debug', function(cls, data, fn) {
|
|
* // Your code here
|
|
*
|
|
* if (fn) {
|
|
* fn.call(this, cls, data);
|
|
* }
|
|
* }).setDefaultPreprocessorPosition('debug', 'last');
|
|
*
|
|
* @private
|
|
* @param {String} name The pre-processor name. Note that it needs to be registered with
|
|
* {@link Ext.Class#registerPreprocessor registerPreprocessor} before this
|
|
* @param {String} offset The insertion position. Four possible values are:
|
|
* 'first', 'last', or: 'before', 'after' (relative to the name provided in the third argument)
|
|
* @param {String} relativeName
|
|
* @return {Ext.Class} this
|
|
* @static
|
|
*/
|
|
setDefaultPreprocessorPosition: function(name, offset, relativeName) {
|
|
var defaultPreprocessors = this.defaultPreprocessors,
|
|
index;
|
|
if (typeof offset == 'string') {
|
|
if (offset === 'first') {
|
|
defaultPreprocessors.unshift(name);
|
|
return this;
|
|
} else if (offset === 'last') {
|
|
defaultPreprocessors.push(name);
|
|
return this;
|
|
}
|
|
offset = (offset === 'after') ? 1 : -1;
|
|
}
|
|
index = Ext.Array.indexOf(defaultPreprocessors, relativeName);
|
|
if (index !== -1) {
|
|
Ext.Array.splice(defaultPreprocessors, Math.max(0, index + offset), 0, name);
|
|
}
|
|
return this;
|
|
}
|
|
});
|
|
/**
|
|
* @cfg {String} extend
|
|
* The parent class that this class extends. For example:
|
|
*
|
|
* Ext.define('Person', {
|
|
* say: function(text) { alert(text); }
|
|
* });
|
|
*
|
|
* Ext.define('Developer', {
|
|
* extend: 'Person',
|
|
* say: function(text) { this.callParent(["print "+text]); }
|
|
* });
|
|
*/
|
|
ExtClass.registerPreprocessor('extend', function(Class, data, hooks) {
|
|
Ext.classSystemMonitor && Ext.classSystemMonitor(Class, 'Ext.Class#extendPreProcessor', arguments);
|
|
var Base = Ext.Base,
|
|
basePrototype = Base.prototype,
|
|
extend = data.extend,
|
|
Parent, parentPrototype, i;
|
|
delete data.extend;
|
|
if (extend && extend !== Object) {
|
|
Parent = extend;
|
|
} else {
|
|
Parent = Base;
|
|
}
|
|
parentPrototype = Parent.prototype;
|
|
if (!Parent.$isClass) {
|
|
for (i in basePrototype) {
|
|
if (!parentPrototype[i]) {
|
|
parentPrototype[i] = basePrototype[i];
|
|
}
|
|
}
|
|
}
|
|
Class.extend(Parent);
|
|
Class.triggerExtended.apply(Class, arguments);
|
|
if (data.onClassExtended) {
|
|
Class.onExtended(data.onClassExtended, Class);
|
|
delete data.onClassExtended;
|
|
}
|
|
}, true);
|
|
// true to always run this preprocessor even w/o "extend" keyword
|
|
/**
|
|
* @cfg {Object} privates
|
|
* The `privates` config is a list of methods intended to be used internally by the
|
|
* framework. Methods are placed in a `privates` block to prevent developers from
|
|
* accidentally overriding framework methods in custom classes.
|
|
*
|
|
* Ext.define('Computer', {
|
|
* privates: {
|
|
* runFactory: function(brand) {
|
|
* // internal only processing of brand passed to factory
|
|
* this.factory(brand);
|
|
* }
|
|
* },
|
|
*
|
|
* factory: function (brand) {}
|
|
* });
|
|
*
|
|
* In order to override a method from a `privates` block, the overridden method must
|
|
* also be placed in a `privates` block within the override class.
|
|
*
|
|
* Ext.define('Override.Computer', {
|
|
* override: 'Computer',
|
|
* privates: {
|
|
* runFactory: function() {
|
|
* // overriding logic
|
|
* }
|
|
* }
|
|
* });
|
|
*/
|
|
ExtClass.registerPreprocessor('privates', function(Class, data) {
|
|
Ext.classSystemMonitor && Ext.classSystemMonitor(Class, 'Ext.Class#privatePreprocessor', arguments);
|
|
var privates = data.privates,
|
|
statics = privates.statics,
|
|
privacy = privates.privacy || true;
|
|
delete data.privates;
|
|
delete privates.statics;
|
|
// We have to add this preprocessor so that private getters/setters are picked up
|
|
// by the config system. This also catches duplication in the public part of the
|
|
// class since it is an error to override a private method with a public one.
|
|
Class.addMembers(privates, false, privacy);
|
|
if (statics) {
|
|
Class.addMembers(statics, true, privacy);
|
|
}
|
|
});
|
|
/**
|
|
* @cfg {Object} statics
|
|
* List of static methods for this class. For example:
|
|
*
|
|
* Ext.define('Computer', {
|
|
* statics: {
|
|
* factory: function(brand) {
|
|
* // 'this' in static methods refer to the class itself
|
|
* return new this(brand);
|
|
* }
|
|
* },
|
|
*
|
|
* constructor: function() { ... }
|
|
* });
|
|
*
|
|
* var dellComputer = Computer.factory('Dell');
|
|
*/
|
|
ExtClass.registerPreprocessor('statics', function(Class, data) {
|
|
Ext.classSystemMonitor && Ext.classSystemMonitor(Class, 'Ext.Class#staticsPreprocessor', arguments);
|
|
Class.addStatics(data.statics);
|
|
delete data.statics;
|
|
});
|
|
/**
|
|
* @cfg {Object} inheritableStatics
|
|
* List of inheritable static methods for this class.
|
|
* Otherwise just like {@link #statics} but subclasses inherit these methods.
|
|
*/
|
|
ExtClass.registerPreprocessor('inheritableStatics', function(Class, data) {
|
|
Ext.classSystemMonitor && Ext.classSystemMonitor(Class, 'Ext.Class#inheritableStaticsPreprocessor', arguments);
|
|
Class.addInheritableStatics(data.inheritableStatics);
|
|
delete data.inheritableStatics;
|
|
});
|
|
Ext.createRuleFn = function(code) {
|
|
return new Function('$c', 'with($c) { try { return (' + code + '); } catch(e) { return false;}}');
|
|
};
|
|
Ext.expressionCache = new Ext.util.Cache({
|
|
miss: Ext.createRuleFn
|
|
});
|
|
Ext.ruleKeySortFn = ruleKeySortFn;
|
|
Ext.getPlatformConfigKeys = function(platformConfig) {
|
|
var ret = [],
|
|
platform, rule;
|
|
for (platform in platformConfig) {
|
|
rule = Ext.expressionCache.get(platform);
|
|
if (rule(Ext.platformTags)) {
|
|
ret.push(platform);
|
|
}
|
|
}
|
|
ret.sort(ruleKeySortFn);
|
|
return ret;
|
|
};
|
|
/**
|
|
* @cfg {Object} platformConfig
|
|
* Allows setting config values for a class based on specific platforms. The value
|
|
* of this config is an object whose properties are "rules" and whose values are
|
|
* objects containing config values.
|
|
*
|
|
* For example:
|
|
*
|
|
* Ext.define('App.view.Foo', {
|
|
* extend: 'Ext.panel.Panel',
|
|
*
|
|
* platformConfig: {
|
|
* desktop: {
|
|
* title: 'Some Rather Descriptive Title'
|
|
* },
|
|
*
|
|
* '!desktop': {
|
|
* title: 'Short Title'
|
|
* }
|
|
* }
|
|
* });
|
|
*
|
|
* In the above, "desktop" and "!desktop" are (mutually exclusive) rules. Whichever
|
|
* evaluates to `true` will have its configs applied to the class. In this case, only
|
|
* the "title" property, but the object can contain any number of config properties.
|
|
* In this case, the `platformConfig` is evaluated as part of the class and there is
|
|
* no cost for each instance created.
|
|
*
|
|
* The rules are evaluated expressions in the context of the platform tags contained
|
|
* in `{@link Ext#platformTags Ext.platformTags}`. Any properties of that object are
|
|
* implicitly usable (as shown above).
|
|
*
|
|
* If a `platformConfig` specifies a config value, it will replace any values declared
|
|
* on the class itself.
|
|
*
|
|
* Use of `platformConfig` on instances is handled by the config system when classes
|
|
* call `{@link Ext.Base#initConfig initConfig}`. For example:
|
|
*
|
|
* Ext.create({
|
|
* xtype: 'panel',
|
|
*
|
|
* platformConfig: {
|
|
* desktop: {
|
|
* title: 'Some Rather Descriptive Title'
|
|
* },
|
|
*
|
|
* '!desktop': {
|
|
* title: 'Short Title'
|
|
* }
|
|
* }
|
|
* });
|
|
*
|
|
* The following is equivalent to the above:
|
|
*
|
|
* if (Ext.platformTags.desktop) {
|
|
* Ext.create({
|
|
* xtype: 'panel',
|
|
* title: 'Some Rather Descriptive Title'
|
|
* });
|
|
* } else {
|
|
* Ext.create({
|
|
* xtype: 'panel',
|
|
* title: 'Short Title'
|
|
* });
|
|
* }
|
|
*
|
|
* To adjust configs based on dynamic conditions, see `{@link Ext.mixin.Responsive}`.
|
|
*/
|
|
ExtClass.registerPreprocessor('platformConfig', function(Class, data, hooks) {
|
|
Class.addPlatformConfig(data);
|
|
});
|
|
/**
|
|
* @cfg {Object} config
|
|
*
|
|
* List of configuration options with their default values.
|
|
*
|
|
* __Note:__ You need to make sure {@link Ext.Base#initConfig} is called from your constructor if you are defining
|
|
* your own class or singleton, unless you are extending a Component. Otherwise the generated getter and setter
|
|
* methods will not be initialized.
|
|
*
|
|
* Each config item will have its own setter and getter method automatically generated inside the class prototype
|
|
* during class creation time, if the class does not have those methods explicitly defined.
|
|
*
|
|
* As an example, let's convert the name property of a Person class to be a config item, then add extra age and
|
|
* gender items.
|
|
*
|
|
* Ext.define('My.sample.Person', {
|
|
* config: {
|
|
* name: 'Mr. Unknown',
|
|
* age: 0,
|
|
* gender: 'Male'
|
|
* },
|
|
*
|
|
* constructor: function(config) {
|
|
* this.initConfig(config);
|
|
*
|
|
* return this;
|
|
* }
|
|
*
|
|
* // ...
|
|
* });
|
|
*
|
|
* Within the class, this.name still has the default value of "Mr. Unknown". However, it's now publicly accessible
|
|
* without sacrificing encapsulation, via setter and getter methods.
|
|
*
|
|
* var jacky = new Person({
|
|
* name: "Jacky",
|
|
* age: 35
|
|
* });
|
|
*
|
|
* alert(jacky.getAge()); // alerts 35
|
|
* alert(jacky.getGender()); // alerts "Male"
|
|
*
|
|
* jacky.walk(10); // alerts "Jacky is walking 10 steps"
|
|
*
|
|
* jacky.setName("Mr. Nguyen");
|
|
* alert(jacky.getName()); // alerts "Mr. Nguyen"
|
|
*
|
|
* jacky.walk(10); // alerts "Mr. Nguyen is walking 10 steps"
|
|
*
|
|
* Notice that we changed the class constructor to invoke this.initConfig() and pass in the provided config object.
|
|
* Two key things happened:
|
|
*
|
|
* - The provided config object when the class is instantiated is recursively merged with the default config object.
|
|
* - All corresponding setter methods are called with the merged values.
|
|
*
|
|
* Beside storing the given values, throughout the frameworks, setters generally have two key responsibilities:
|
|
*
|
|
* - Filtering / validation / transformation of the given value before it's actually stored within the instance.
|
|
* - Notification (such as firing events) / post-processing after the value has been set, or changed from a
|
|
* previous value.
|
|
*
|
|
* By standardize this common pattern, the default generated setters provide two extra template methods that you
|
|
* can put your own custom logics into, i.e: an "applyFoo" and "updateFoo" method for a "foo" config item, which are
|
|
* executed before and after the value is actually set, respectively. Back to the example class, let's validate that
|
|
* age must be a valid positive number, and fire an 'agechange' if the value is modified.
|
|
*
|
|
* Ext.define('My.sample.Person', {
|
|
* config: {
|
|
* // ...
|
|
* },
|
|
*
|
|
* constructor: {
|
|
* // ...
|
|
* },
|
|
*
|
|
* applyAge: function(age) {
|
|
* if (typeof age !== 'number' || age < 0) {
|
|
* console.warn("Invalid age, must be a positive number");
|
|
* return;
|
|
* }
|
|
*
|
|
* return age;
|
|
* },
|
|
*
|
|
* updateAge: function(newAge, oldAge) {
|
|
* // age has changed from "oldAge" to "newAge"
|
|
* this.fireEvent('agechange', this, newAge, oldAge);
|
|
* }
|
|
*
|
|
* // ...
|
|
* });
|
|
*
|
|
* var jacky = new Person({
|
|
* name: "Jacky",
|
|
* age: 'invalid'
|
|
* });
|
|
*
|
|
* alert(jacky.getAge()); // alerts 0
|
|
*
|
|
* alert(jacky.setAge(-100)); // alerts 0
|
|
* alert(jacky.getAge()); // alerts 0
|
|
*
|
|
* alert(jacky.setAge(35)); // alerts 0
|
|
* alert(jacky.getAge()); // alerts 35
|
|
*
|
|
* In other words, when leveraging the config feature, you mostly never need to define setter and getter methods
|
|
* explicitly. Instead, "apply*" and "update*" methods should be implemented where necessary. Your code will be
|
|
* consistent throughout and only contain the minimal logic that you actually care about.
|
|
*
|
|
* When it comes to inheritance, the default config of the parent class is automatically, recursively merged with
|
|
* the child's default config. The same applies for mixins.
|
|
*/
|
|
ExtClass.registerPreprocessor('config', function(Class, data) {
|
|
// Need to copy to the prototype here because that happens after preprocessors
|
|
if (data.hasOwnProperty('$configPrefixed')) {
|
|
Class.prototype.$configPrefixed = data.$configPrefixed;
|
|
}
|
|
Class.addConfig(data.config);
|
|
// We need to remove this or it will be applied by addMembers and smash the
|
|
// "config" placed on the prototype by Configurator (which includes *all* configs
|
|
// such as cachedConfigs).
|
|
delete data.config;
|
|
});
|
|
/**
|
|
* @cfg {Object} cachedConfig
|
|
*
|
|
* This configuration works in a very similar manner to the {@link #config} option.
|
|
* The difference is that the configurations are only ever processed when the first instance
|
|
* of that class is created. The processed value is then stored on the class prototype and
|
|
* will not be processed on subsequent instances of the class. Getters/setters will be generated
|
|
* in exactly the same way as {@link #config}.
|
|
*
|
|
* This option is useful for expensive objects that can be shared across class instances.
|
|
* The class itself ensures that the creation only occurs once.
|
|
*/
|
|
ExtClass.registerPreprocessor('cachedConfig', function(Class, data) {
|
|
// Need to copy to the prototype here because that happens after preprocessors
|
|
if (data.hasOwnProperty('$configPrefixed')) {
|
|
Class.prototype.$configPrefixed = data.$configPrefixed;
|
|
}
|
|
Class.addCachedConfig(data.cachedConfig);
|
|
// Remove this so it won't be placed on the prototype.
|
|
delete data.cachedConfig;
|
|
});
|
|
/**
|
|
* @cfg {String[]/Object} mixins
|
|
* List of classes to mix into this class. For example:
|
|
*
|
|
* Ext.define('CanSing', {
|
|
* sing: function() {
|
|
* alert("For he's a jolly good fellow...")
|
|
* }
|
|
* });
|
|
*
|
|
* Ext.define('Musician', {
|
|
* mixins: ['CanSing']
|
|
* })
|
|
*
|
|
* In this case the Musician class will get a `sing` method from CanSing mixin.
|
|
*
|
|
* But what if the Musician already has a `sing` method? Or you want to mix
|
|
* in two classes, both of which define `sing`? In such a cases it's good
|
|
* to define mixins as an object, where you assign a name to each mixin:
|
|
*
|
|
* Ext.define('Musician', {
|
|
* mixins: {
|
|
* canSing: 'CanSing'
|
|
* },
|
|
*
|
|
* sing: function() {
|
|
* // delegate singing operation to mixin
|
|
* this.mixins.canSing.sing.call(this);
|
|
* }
|
|
* })
|
|
*
|
|
* In this case the `sing` method of Musician will overwrite the
|
|
* mixed in `sing` method. But you can access the original mixed in method
|
|
* through special `mixins` property.
|
|
*/
|
|
ExtClass.registerPreprocessor('mixins', function(Class, data, hooks) {
|
|
Ext.classSystemMonitor && Ext.classSystemMonitor(Class, 'Ext.Class#mixinsPreprocessor', arguments);
|
|
var mixins = data.mixins,
|
|
onCreated = hooks.onCreated;
|
|
delete data.mixins;
|
|
hooks.onCreated = function() {
|
|
Ext.classSystemMonitor && Ext.classSystemMonitor(Class, 'Ext.Class#mixinsPreprocessor#beforeCreated', arguments);
|
|
// Put back the original onCreated before processing mixins. This allows a
|
|
// mixin to hook onCreated by access Class._classHooks.
|
|
hooks.onCreated = onCreated;
|
|
Class.mixin(mixins);
|
|
// We must go back to hooks.onCreated here because it may have changed during
|
|
// calls to onClassMixedIn.
|
|
return hooks.onCreated.apply(this, arguments);
|
|
};
|
|
});
|
|
// Backwards compatible
|
|
Ext.extend = function(Class, Parent, members) {
|
|
Ext.classSystemMonitor && Ext.classSystemMonitor(Class, 'Ext.Class#extend-backwards-compatible', arguments);
|
|
if (arguments.length === 2 && Ext.isObject(Parent)) {
|
|
members = Parent;
|
|
Parent = Class;
|
|
Class = null;
|
|
}
|
|
var cls;
|
|
if (!Parent) {
|
|
throw new Error("[Ext.extend] Attempting to extend from a class which has not been loaded on the page.");
|
|
}
|
|
members.extend = Parent;
|
|
members.preprocessors = [
|
|
'extend',
|
|
'statics',
|
|
'inheritableStatics',
|
|
'mixins',
|
|
'platformConfig',
|
|
'config'
|
|
];
|
|
if (Class) {
|
|
cls = new ExtClass(Class, members);
|
|
// The 'constructor' is given as 'Class' but also needs to be on prototype
|
|
cls.prototype.constructor = Class;
|
|
} else {
|
|
cls = new ExtClass(members);
|
|
}
|
|
cls.prototype.override = function(o) {
|
|
for (var m in o) {
|
|
if (o.hasOwnProperty(m)) {
|
|
this[m] = o[m];
|
|
}
|
|
}
|
|
};
|
|
return cls;
|
|
};
|
|
}());
|
|
/**
|
|
* This object contains properties that describe the current device or platform. These
|
|
* values can be used in `{@link Ext.Class#platformConfig platformConfig}` as well as
|
|
* `{@link Ext.mixin.Responsive#responsiveConfig responsiveConfig}` statements.
|
|
*
|
|
* This object can be modified to include tags that are useful for the application. To
|
|
* add custom properties, it is advisable to use a sub-object. For example:
|
|
*
|
|
* Ext.platformTags.app = {
|
|
* mobile: true
|
|
* };
|
|
*
|
|
* @property {Object} platformTags
|
|
* @property {Boolean} platformTags.phone
|
|
* @property {Boolean} platformTags.tablet
|
|
* @property {Boolean} platformTags.desktop
|
|
* @property {Boolean} platformTags.touch Indicates touch inputs are available.
|
|
* @property {Boolean} platformTags.safari
|
|
* @property {Boolean} platformTags.chrome
|
|
* @property {Boolean} platformTags.windows
|
|
* @property {Boolean} platformTags.firefox
|
|
* @property {Boolean} platformTags.ios True for iPad, iPhone and iPod.
|
|
* @property {Boolean} platformTags.android
|
|
* @property {Boolean} platformTags.blackberry
|
|
* @property {Boolean} platformTags.tizen
|
|
* @member Ext
|
|
*/
|
|
|
|
// @tag class
|
|
/**
|
|
* @class Ext.Inventory
|
|
* @private
|
|
*/
|
|
Ext.Inventory = function() {
|
|
// @define Ext.Script
|
|
// @define Ext.Inventory
|
|
// @require Ext.Function
|
|
var me = this;
|
|
me.names = [];
|
|
me.paths = {};
|
|
me.alternateToName = {};
|
|
me.aliasToName = {};
|
|
me.nameToAliases = {};
|
|
me.nameToAlternates = {};
|
|
me.nameToPrefix = {};
|
|
};
|
|
Ext.Inventory.prototype = {
|
|
_array1: [
|
|
0
|
|
],
|
|
prefixes: null,
|
|
dotRe: /\./g,
|
|
wildcardRe: /\*/g,
|
|
addAlias: function(className, alias, update) {
|
|
return this.addMapping(className, alias, this.aliasToName, this.nameToAliases, update);
|
|
},
|
|
addAlternate: function(className, alternate) {
|
|
return this.addMapping(className, alternate, this.alternateToName, this.nameToAlternates);
|
|
},
|
|
addMapping: function(className, alternate, toName, nameTo, update) {
|
|
var name = className.$className || className,
|
|
mappings = name,
|
|
array = this._array1,
|
|
a, aliases, cls, i, length, nameMapping;
|
|
if (Ext.isString(name)) {
|
|
mappings = {};
|
|
mappings[name] = alternate;
|
|
}
|
|
for (cls in mappings) {
|
|
aliases = mappings[cls];
|
|
if (Ext.isString(aliases)) {
|
|
array[0] = aliases;
|
|
aliases = array;
|
|
}
|
|
length = aliases.length;
|
|
nameMapping = nameTo[cls] || (nameTo[cls] = []);
|
|
for (i = 0; i < length; ++i) {
|
|
if (!(a = aliases[i])) {
|
|
|
|
continue;
|
|
}
|
|
if (toName[a] !== cls) {
|
|
if (!update && toName[a]) {
|
|
Ext.log.warn("Overriding existing mapping: '" + a + "' From '" + toName[a] + "' to '" + cls + "'. Is this intentional?");
|
|
}
|
|
toName[a] = cls;
|
|
nameMapping.push(a);
|
|
}
|
|
}
|
|
}
|
|
},
|
|
/**
|
|
* Get the aliases of a class by the class name
|
|
*
|
|
* @param {String} name
|
|
* @return {Array} aliases
|
|
*/
|
|
getAliasesByName: function(name) {
|
|
return this.nameToAliases[name] || null;
|
|
},
|
|
getAlternatesByName: function(name) {
|
|
return this.nameToAlternates[name] || null;
|
|
},
|
|
/**
|
|
* Get the name of a class by its alias.
|
|
*
|
|
* @param {String} alias
|
|
* @return {String} className
|
|
*/
|
|
getNameByAlias: function(alias) {
|
|
return this.aliasToName[alias] || '';
|
|
},
|
|
/**
|
|
* Get the name of a class by its alternate name.
|
|
*
|
|
* @param {String} alternate
|
|
* @return {String} className
|
|
*/
|
|
getNameByAlternate: function(alternate) {
|
|
return this.alternateToName[alternate] || '';
|
|
},
|
|
/**
|
|
* Converts a string expression to an array of matching class names. An expression can
|
|
* either refers to class aliases or class names. Expressions support wildcards:
|
|
*
|
|
* // returns ['Ext.window.Window']
|
|
* var window = Ext.ClassManager.getNamesByExpression('widget.window');
|
|
*
|
|
* // returns ['widget.panel', 'widget.window', ...]
|
|
* var allWidgets = Ext.ClassManager.getNamesByExpression('widget.*');
|
|
*
|
|
* // returns ['Ext.data.Store', 'Ext.data.ArrayProxy', ...]
|
|
* var allData = Ext.ClassManager.getNamesByExpression('Ext.data.*');
|
|
*
|
|
* @param {String/String[]} expression
|
|
* @param {Object} [exclude=null] An object keyed by class name containing classes to
|
|
* exclude from the returned classes. This must be provided if `accumulate` is set to
|
|
* `true`.
|
|
* @param {Boolean} [accumulate=false] Pass `true` to add matching classes to the
|
|
* specified `exclude` object.
|
|
* @return {String[]} An array of class names.
|
|
*/
|
|
getNamesByExpression: function(expression, exclude, accumulate) {
|
|
var me = this,
|
|
aliasToName = me.aliasToName,
|
|
alternateToName = me.alternateToName,
|
|
nameToAliases = me.nameToAliases,
|
|
nameToAlternates = me.nameToAlternates,
|
|
map = accumulate ? exclude : {},
|
|
names = [],
|
|
expressions = Ext.isString(expression) ? [
|
|
expression
|
|
] : expression,
|
|
length = expressions.length,
|
|
wildcardRe = me.wildcardRe,
|
|
expr, i, list, match, n, name, regex;
|
|
for (i = 0; i < length; ++i) {
|
|
if ((expr = expressions[i]).indexOf('*') < 0) {
|
|
// No wildcard
|
|
if (!(name = aliasToName[expr])) {
|
|
if (!(name = alternateToName[expr])) {
|
|
name = expr;
|
|
}
|
|
}
|
|
if (!(name in map) && !(exclude && (name in exclude))) {
|
|
map[name] = 1;
|
|
names.push(name);
|
|
}
|
|
} else {
|
|
regex = new RegExp('^' + expr.replace(wildcardRe, '(.*?)') + '$');
|
|
for (name in nameToAliases) {
|
|
if (!(name in map) && !(exclude && (name in exclude))) {
|
|
if (!(match = regex.test(name))) {
|
|
n = (list = nameToAliases[name]).length;
|
|
while (!match && n-- > 0) {
|
|
match = regex.test(list[n]);
|
|
}
|
|
list = nameToAlternates[name];
|
|
if (list && !match) {
|
|
n = list.length;
|
|
while (!match && n-- > 0) {
|
|
match = regex.test(list[n]);
|
|
}
|
|
}
|
|
}
|
|
if (match) {
|
|
map[name] = 1;
|
|
names.push(name);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return names;
|
|
},
|
|
getPath: function(className) {
|
|
var me = this,
|
|
paths = me.paths,
|
|
ret = '',
|
|
prefix;
|
|
if (className in paths) {
|
|
ret = paths[className];
|
|
} else {
|
|
prefix = me.nameToPrefix[className] || (me.nameToPrefix[className] = me.getPrefix(className));
|
|
if (prefix) {
|
|
className = className.substring(prefix.length + 1);
|
|
ret = paths[prefix];
|
|
if (ret) {
|
|
ret += '/';
|
|
}
|
|
}
|
|
ret += className.replace(me.dotRe, '/') + '.js';
|
|
}
|
|
return ret;
|
|
},
|
|
getPrefix: function(className) {
|
|
if (className in this.paths) {
|
|
return className;
|
|
} else if (className in this.nameToPrefix) {
|
|
return this.nameToPrefix[className];
|
|
}
|
|
var prefixes = this.getPrefixes(),
|
|
length = className.length,
|
|
items, currChar, currSubstr, prefix, j, jlen;
|
|
// Walk the prefixes backwards so we consider the longest ones first.
|
|
// Prefixes are kept in a sparse array grouped by length so we don't have to
|
|
// iterate over all of them, just the ones we need.
|
|
while (length-- > 0) {
|
|
items = prefixes[length];
|
|
if (items) {
|
|
currChar = className.charAt(length);
|
|
if (currChar !== '.') {
|
|
|
|
continue;
|
|
}
|
|
currSubstr = className.substring(0, length);
|
|
for (j = 0 , jlen = items.length; j < jlen; j++) {
|
|
prefix = items[j];
|
|
if (prefix === className.substring(0, length)) {
|
|
return prefix;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return '';
|
|
},
|
|
getPrefixes: function() {
|
|
var me = this,
|
|
prefixes = me.prefixes,
|
|
names, name, nameLength, items, i, len;
|
|
if (!prefixes) {
|
|
names = me.names.slice(0);
|
|
me.prefixes = prefixes = [];
|
|
for (i = 0 , len = names.length; i < len; i++) {
|
|
name = names[i];
|
|
nameLength = name.length;
|
|
items = prefixes[nameLength] || (prefixes[nameLength] = []);
|
|
items.push(name);
|
|
}
|
|
}
|
|
return prefixes;
|
|
},
|
|
removeName: function(name) {
|
|
var me = this,
|
|
aliasToName = me.aliasToName,
|
|
alternateToName = me.alternateToName,
|
|
nameToAliases = me.nameToAliases,
|
|
nameToAlternates = me.nameToAlternates,
|
|
aliases = nameToAliases[name],
|
|
alternates = nameToAlternates[name],
|
|
i, a;
|
|
delete nameToAliases[name];
|
|
delete nameToAlternates[name];
|
|
delete me.nameToPrefix[name];
|
|
if (aliases) {
|
|
for (i = aliases.length; i--; ) {
|
|
// Aliases can be reassigned so if this class is the current mapping of
|
|
// the alias, remove it. Since there is no chain to restore what was
|
|
// removed this is not perfect.
|
|
if (name === (a = aliases[i])) {
|
|
delete aliasToName[a];
|
|
}
|
|
}
|
|
}
|
|
if (alternates) {
|
|
for (i = alternates.length; i--; ) {
|
|
// Like aliases, alternate class names can also be remapped.
|
|
if (name === (a = alternates[i])) {
|
|
delete alternateToName[a];
|
|
}
|
|
}
|
|
}
|
|
},
|
|
resolveName: function(name) {
|
|
var me = this,
|
|
trueName;
|
|
// If the name has a registered alias, it is a true className (not an alternate)
|
|
// so we can stop now.
|
|
if (!(name in me.nameToAliases)) {
|
|
// The name is not a known class name, so check to see if it is a known alias:
|
|
if (!(trueName = me.aliasToName[name])) {
|
|
// The name does not correspond to a known alias, so check if it is a known
|
|
// alternateClassName:
|
|
trueName = me.alternateToName[name];
|
|
}
|
|
}
|
|
return trueName || name;
|
|
},
|
|
/**
|
|
* This method returns a selector object that produces a selection of classes and
|
|
* delivers them to the desired `receiver`.
|
|
*
|
|
* The returned selector object has the same methods as the given `receiver` object
|
|
* but these methods on the selector accept a first argument that expects a pattern
|
|
* or array of patterns. The actual method on the `receiver` will be called with an
|
|
* array of classes that match these patterns but with any patterns passed to an
|
|
* `exclude` call removed.
|
|
*
|
|
* For example:
|
|
*
|
|
* var sel = inventory.select({
|
|
* require: function (classes) {
|
|
* console.log('Classes: ' + classes.join(','));
|
|
* }
|
|
* });
|
|
*
|
|
* sel.exclude('Ext.chart.*').exclude('Ext.draw.*').require('*');
|
|
*
|
|
* // Logs all classes except those in the Ext.chart and Ext.draw namespaces.
|
|
*
|
|
* @param {Object} receiver
|
|
* @param {Object} [scope] Optional scope to use when calling `receiver` methods.
|
|
* @return {Object} An object with the same methods as `receiver` plus `exclude`.
|
|
*/
|
|
select: function(receiver, scope) {
|
|
var me = this,
|
|
excludes = {},
|
|
ret = {
|
|
excludes: excludes,
|
|
exclude: function() {
|
|
me.getNamesByExpression(arguments, excludes, true);
|
|
return this;
|
|
}
|
|
},
|
|
name;
|
|
for (name in receiver) {
|
|
ret[name] = me.selectMethod(excludes, receiver[name], scope || receiver);
|
|
}
|
|
return ret;
|
|
},
|
|
selectMethod: function(excludes, fn, scope) {
|
|
var me = this;
|
|
return function(include) {
|
|
var args = Ext.Array.slice(arguments, 1);
|
|
args.unshift(me.getNamesByExpression(include, excludes));
|
|
return fn.apply(scope, args);
|
|
};
|
|
},
|
|
/**
|
|
* Sets the path of a namespace.
|
|
* For Example:
|
|
*
|
|
* inventory.setPath('Ext', '.');
|
|
* inventory.setPath({
|
|
* Ext: '.'
|
|
* });
|
|
*
|
|
* @param {String/Object} name The name of a single mapping or an object of mappings.
|
|
* @param {String} [path] If `name` is a String, then this is the path for that name.
|
|
* Otherwise this parameter is ignored.
|
|
* @return {Ext.Inventory} this
|
|
* @method
|
|
*/
|
|
setPath: Ext.Function.flexSetter(function(name, path) {
|
|
var me = this;
|
|
me.paths[name] = path;
|
|
me.names.push(name);
|
|
me.prefixes = null;
|
|
me.nameToPrefix = {};
|
|
return me;
|
|
})
|
|
};
|
|
|
|
// @tag class
|
|
/**
|
|
* @class Ext.ClassManager
|
|
*
|
|
* Ext.ClassManager manages all classes and handles mapping from string class name to
|
|
* actual class objects throughout the whole framework. It is not generally accessed directly, rather through
|
|
* these convenient shorthands:
|
|
*
|
|
* - {@link Ext#define Ext.define}
|
|
* - {@link Ext#create Ext.create}
|
|
* - {@link Ext#widget Ext.widget}
|
|
* - {@link Ext#getClass Ext.getClass}
|
|
* - {@link Ext#getClassName Ext.getClassName}
|
|
*
|
|
* # Basic syntax:
|
|
*
|
|
* Ext.define(className, properties);
|
|
*
|
|
* in which `properties` is an object represent a collection of properties that apply to the class. See
|
|
* {@link Ext.ClassManager#create} for more detailed instructions.
|
|
*
|
|
* Ext.define('Person', {
|
|
* name: 'Unknown',
|
|
*
|
|
* constructor: function(name) {
|
|
* if (name) {
|
|
* this.name = name;
|
|
* }
|
|
* },
|
|
*
|
|
* eat: function(foodType) {
|
|
* alert("I'm eating: " + foodType);
|
|
*
|
|
* return this;
|
|
* }
|
|
* });
|
|
*
|
|
* var aaron = new Person("Aaron");
|
|
* aaron.eat("Sandwich"); // alert("I'm eating: Sandwich");
|
|
*
|
|
* Ext.Class has a powerful set of extensible {@link Ext.Class#registerPreprocessor pre-processors} which takes care of
|
|
* everything related to class creation, including but not limited to inheritance, mixins, configuration, statics, etc.
|
|
*
|
|
* # Inheritance:
|
|
*
|
|
* Ext.define('Developer', {
|
|
* extend: 'Person',
|
|
*
|
|
* constructor: function(name, isGeek) {
|
|
* this.isGeek = isGeek;
|
|
*
|
|
* // Apply a method from the parent class' prototype
|
|
* this.callParent([name]);
|
|
* },
|
|
*
|
|
* code: function(language) {
|
|
* alert("I'm coding in: " + language);
|
|
*
|
|
* this.eat("Bugs");
|
|
*
|
|
* return this;
|
|
* }
|
|
* });
|
|
*
|
|
* var jacky = new Developer("Jacky", true);
|
|
* jacky.code("JavaScript"); // alert("I'm coding in: JavaScript");
|
|
* // alert("I'm eating: Bugs");
|
|
*
|
|
* See {@link Ext.Base#callParent} for more details on calling superclass' methods
|
|
*
|
|
* # Mixins:
|
|
*
|
|
* Ext.define('CanPlayGuitar', {
|
|
* playGuitar: function() {
|
|
* alert("F#...G...D...A");
|
|
* }
|
|
* });
|
|
*
|
|
* Ext.define('CanComposeSongs', {
|
|
* composeSongs: function() { ... }
|
|
* });
|
|
*
|
|
* Ext.define('CanSing', {
|
|
* sing: function() {
|
|
* alert("For he's a jolly good fellow...")
|
|
* }
|
|
* });
|
|
*
|
|
* Ext.define('Musician', {
|
|
* extend: 'Person',
|
|
*
|
|
* mixins: {
|
|
* canPlayGuitar: 'CanPlayGuitar',
|
|
* canComposeSongs: 'CanComposeSongs',
|
|
* canSing: 'CanSing'
|
|
* }
|
|
* })
|
|
*
|
|
* Ext.define('CoolPerson', {
|
|
* extend: 'Person',
|
|
*
|
|
* mixins: {
|
|
* canPlayGuitar: 'CanPlayGuitar',
|
|
* canSing: 'CanSing'
|
|
* },
|
|
*
|
|
* sing: function() {
|
|
* alert("Ahem....");
|
|
*
|
|
* this.mixins.canSing.sing.call(this);
|
|
*
|
|
* alert("[Playing guitar at the same time...]");
|
|
*
|
|
* this.playGuitar();
|
|
* }
|
|
* });
|
|
*
|
|
* var me = new CoolPerson("Jacky");
|
|
*
|
|
* me.sing(); // alert("Ahem...");
|
|
* // alert("For he's a jolly good fellow...");
|
|
* // alert("[Playing guitar at the same time...]");
|
|
* // alert("F#...G...D...A");
|
|
*
|
|
* # Config:
|
|
*
|
|
* Ext.define('SmartPhone', {
|
|
* config: {
|
|
* hasTouchScreen: false,
|
|
* operatingSystem: 'Other',
|
|
* price: 500
|
|
* },
|
|
*
|
|
* isExpensive: false,
|
|
*
|
|
* constructor: function(config) {
|
|
* this.initConfig(config);
|
|
* },
|
|
*
|
|
* applyPrice: function(price) {
|
|
* this.isExpensive = (price > 500);
|
|
*
|
|
* return price;
|
|
* },
|
|
*
|
|
* applyOperatingSystem: function(operatingSystem) {
|
|
* if (!(/^(iOS|Android|BlackBerry)$/i).test(operatingSystem)) {
|
|
* return 'Other';
|
|
* }
|
|
*
|
|
* return operatingSystem;
|
|
* }
|
|
* });
|
|
*
|
|
* var iPhone = new SmartPhone({
|
|
* hasTouchScreen: true,
|
|
* operatingSystem: 'iOS'
|
|
* });
|
|
*
|
|
* iPhone.getPrice(); // 500;
|
|
* iPhone.getOperatingSystem(); // 'iOS'
|
|
* iPhone.getHasTouchScreen(); // true;
|
|
*
|
|
* iPhone.isExpensive; // false;
|
|
* iPhone.setPrice(600);
|
|
* iPhone.getPrice(); // 600
|
|
* iPhone.isExpensive; // true;
|
|
*
|
|
* iPhone.setOperatingSystem('AlienOS');
|
|
* iPhone.getOperatingSystem(); // 'Other'
|
|
*
|
|
* # Statics:
|
|
*
|
|
* Ext.define('Computer', {
|
|
* statics: {
|
|
* factory: function(brand) {
|
|
* // 'this' in static methods refer to the class itself
|
|
* return new this(brand);
|
|
* }
|
|
* },
|
|
*
|
|
* constructor: function() { ... }
|
|
* });
|
|
*
|
|
* var dellComputer = Computer.factory('Dell');
|
|
*
|
|
* Also see {@link Ext.Base#statics} and {@link Ext.Base#self} for more details on accessing
|
|
* static properties within class methods
|
|
*
|
|
* @singleton
|
|
*/
|
|
Ext.ClassManager = (function(Class, alias, arraySlice, arrayFrom, global) {
|
|
// @define Ext.ClassManager
|
|
// @require Ext.Inventory
|
|
// @require Ext.Class
|
|
// @require Ext.Function
|
|
// @require Ext.Array
|
|
var makeCtor = Ext.Class.makeCtor,
|
|
nameLookupStack = [],
|
|
namespaceCache = {
|
|
Ext: {
|
|
name: 'Ext',
|
|
value: Ext
|
|
}
|
|
},
|
|
// specially added for sandbox (Ext === global.Ext6)
|
|
/*
|
|
'Ext.grid': {
|
|
name: 'grid',
|
|
parent: namespaceCache['Ext']
|
|
},
|
|
'Ext.grid.Panel': {
|
|
name: 'Panel',
|
|
parent: namespaceCache['Ext.grid']
|
|
},
|
|
...
|
|
|
|
Also,
|
|
'MyApp': {
|
|
name: 'MyApp',
|
|
value: MyApp
|
|
}
|
|
*/
|
|
Manager = Ext.apply(new Ext.Inventory(), {
|
|
/**
|
|
* @property {Object} classes
|
|
* All classes which were defined through the ClassManager. Keys are the
|
|
* name of the classes and the values are references to the classes.
|
|
* @private
|
|
*/
|
|
classes: {},
|
|
classState: {},
|
|
/*
|
|
* 'Ext.foo.Bar': <state enum>
|
|
*
|
|
* 10 = Ext.define called
|
|
* 20 = Ext.define/override called
|
|
* 30 = Manager.existCache[<name>] == true for define
|
|
* 40 = Manager.existCache[<name>] == true for define/override
|
|
* 50 = Manager.isCreated(<name>) == true for define
|
|
* 60 = Manager.isCreated(<name>) == true for define/override
|
|
*
|
|
*/
|
|
/**
|
|
* @private
|
|
*/
|
|
existCache: {},
|
|
/** @private */
|
|
instantiators: [],
|
|
/**
|
|
* Checks if a class has already been created.
|
|
*
|
|
* @param {String} className
|
|
* @return {Boolean} exist
|
|
*/
|
|
isCreated: function(className) {
|
|
if (typeof className !== 'string' || className.length < 1) {
|
|
throw new Error("[Ext.ClassManager] Invalid classname, must be a string and must not be empty");
|
|
}
|
|
if (Manager.classes[className] || Manager.existCache[className]) {
|
|
return true;
|
|
}
|
|
if (!Manager.lookupName(className, false)) {
|
|
return false;
|
|
}
|
|
Manager.triggerCreated(className);
|
|
return true;
|
|
},
|
|
/**
|
|
* @private
|
|
*/
|
|
createdListeners: [],
|
|
/**
|
|
* @private
|
|
*/
|
|
nameCreatedListeners: {},
|
|
/**
|
|
* @private
|
|
*/
|
|
existsListeners: [],
|
|
/**
|
|
* @private
|
|
*/
|
|
nameExistsListeners: {},
|
|
/**
|
|
* @private
|
|
*/
|
|
overrideMap: {},
|
|
/**
|
|
* @private
|
|
*/
|
|
triggerCreated: function(className, state) {
|
|
Manager.existCache[className] = state || 1;
|
|
Manager.classState[className] += 40;
|
|
Manager.notify(className, Manager.createdListeners, Manager.nameCreatedListeners);
|
|
},
|
|
/**
|
|
* @private
|
|
*/
|
|
onCreated: function(fn, scope, className) {
|
|
Manager.addListener(fn, scope, className, Manager.createdListeners, Manager.nameCreatedListeners);
|
|
},
|
|
/**
|
|
* @private
|
|
*/
|
|
notify: function(className, listeners, nameListeners) {
|
|
var alternateNames = Manager.getAlternatesByName(className),
|
|
names = [
|
|
className
|
|
],
|
|
i, ln, j, subLn, listener, name;
|
|
for (i = 0 , ln = listeners.length; i < ln; i++) {
|
|
listener = listeners[i];
|
|
listener.fn.call(listener.scope, className);
|
|
}
|
|
while (names) {
|
|
for (i = 0 , ln = names.length; i < ln; i++) {
|
|
name = names[i];
|
|
listeners = nameListeners[name];
|
|
if (listeners) {
|
|
for (j = 0 , subLn = listeners.length; j < subLn; j++) {
|
|
listener = listeners[j];
|
|
listener.fn.call(listener.scope, name);
|
|
}
|
|
delete nameListeners[name];
|
|
}
|
|
}
|
|
names = alternateNames;
|
|
// for 2nd pass (if needed)
|
|
alternateNames = null;
|
|
}
|
|
},
|
|
// no 3rd pass
|
|
/**
|
|
* @private
|
|
*/
|
|
addListener: function(fn, scope, className, listeners, nameListeners) {
|
|
if (Ext.isArray(className)) {
|
|
fn = Ext.Function.createBarrier(className.length, fn, scope);
|
|
for (i = 0; i < className.length; i++) {
|
|
this.addListener(fn, null, className[i], listeners, nameListeners);
|
|
}
|
|
return;
|
|
}
|
|
var i,
|
|
listener = {
|
|
fn: fn,
|
|
scope: scope
|
|
};
|
|
if (className) {
|
|
if (this.isCreated(className)) {
|
|
fn.call(scope, className);
|
|
return;
|
|
}
|
|
if (!nameListeners[className]) {
|
|
nameListeners[className] = [];
|
|
}
|
|
nameListeners[className].push(listener);
|
|
} else {
|
|
listeners.push(listener);
|
|
}
|
|
},
|
|
/**
|
|
* Supports namespace rewriting.
|
|
* @private
|
|
*/
|
|
$namespaceCache: namespaceCache,
|
|
/**
|
|
* See `{@link Ext#addRootNamespaces Ext.addRootNamespaces}`.
|
|
* @since 6.0.0
|
|
* @private
|
|
*/
|
|
addRootNamespaces: function(namespaces) {
|
|
for (var name in namespaces) {
|
|
namespaceCache[name] = {
|
|
name: name,
|
|
value: namespaces[name]
|
|
};
|
|
}
|
|
},
|
|
/**
|
|
* Clears the namespace lookup cache. After application launch, this cache can
|
|
* often contain several hundred entries that are unlikely to be needed again.
|
|
* These will be rebuilt as needed, so it is harmless to clear this cache even
|
|
* if its results will be used again.
|
|
* @since 6.0.0
|
|
* @private
|
|
*/
|
|
clearNamespaceCache: function() {
|
|
nameLookupStack.length = 0;
|
|
for (var name in namespaceCache) {
|
|
if (!namespaceCache[name].value) {
|
|
delete namespaceCache[name];
|
|
}
|
|
}
|
|
},
|
|
/**
|
|
* Return the namespace cache entry for the given a class name or namespace (e.g.,
|
|
* "Ext.grid.Panel").
|
|
*
|
|
* @param {String} namespace The namespace or class name to lookup.
|
|
* @return {Object} The cache entry.
|
|
* @return {String} return.name The leaf name ("Panel" for "Ext.grid.Panel").
|
|
* @return {Object} return.parent The entry of the parent namespace (i.e., "Ext.grid").
|
|
* @return {Object} return.value The namespace object. This is only set for
|
|
* top-level namespace entries to support renaming them for sandboxing ("Ext6" vs
|
|
* "Ext").
|
|
* @since 6.0.0
|
|
* @private
|
|
*/
|
|
getNamespaceEntry: function(namespace) {
|
|
if (typeof namespace !== 'string') {
|
|
return namespace;
|
|
}
|
|
// assume we've been given an entry object
|
|
var entry = namespaceCache[namespace],
|
|
i;
|
|
if (!entry) {
|
|
i = namespace.lastIndexOf('.');
|
|
if (i < 0) {
|
|
entry = {
|
|
name: namespace
|
|
};
|
|
} else {
|
|
entry = {
|
|
name: namespace.substring(i + 1),
|
|
parent: Manager.getNamespaceEntry(namespace.substring(0, i))
|
|
};
|
|
}
|
|
namespaceCache[namespace] = entry;
|
|
}
|
|
return entry;
|
|
},
|
|
/**
|
|
* Return the value of the given "dot path" name. This supports remapping (for use
|
|
* in sandbox builds) as well as auto-creating of namespaces.
|
|
*
|
|
* @param {String} namespace The name of the namespace or class.
|
|
* @param {Boolean} [autoCreate] Pass `true` to create objects for undefined names.
|
|
* @return {Object} The object that is the namespace or class name.
|
|
* @since 6.0.0
|
|
* @private
|
|
*/
|
|
lookupName: function(namespace, autoCreate) {
|
|
var entry = Manager.getNamespaceEntry(namespace),
|
|
scope = Ext.global,
|
|
i = 0,
|
|
e, parent;
|
|
// Put entries on the stack in reverse order: [ 'Panel', 'grid', 'Ext' ]
|
|
for (e = entry; e; e = e.parent) {
|
|
// since we process only what we add to the array, and that always
|
|
// starts at index=0, we don't need to clean up the array (that would
|
|
// just encourage the GC to do something pointless).
|
|
nameLookupStack[i++] = e;
|
|
}
|
|
while (scope && i-- > 0) {
|
|
// We'll process entries in top-down order ('Ext', 'grid' then 'Panel').
|
|
e = nameLookupStack[i];
|
|
parent = scope;
|
|
scope = e.value || scope[e.name];
|
|
if (!scope && autoCreate) {
|
|
parent[e.name] = scope = {};
|
|
}
|
|
}
|
|
return scope;
|
|
},
|
|
/**
|
|
* Creates a namespace and assign the `value` to the created object.
|
|
*
|
|
* Ext.ClassManager.setNamespace('MyCompany.pkg.Example', someObject);
|
|
*
|
|
* alert(MyCompany.pkg.Example === someObject); // alerts true
|
|
*
|
|
* @param {String} name
|
|
* @param {Object} value
|
|
*/
|
|
setNamespace: function(namespace, value) {
|
|
var entry = Manager.getNamespaceEntry(namespace),
|
|
scope = Ext.global;
|
|
if (entry.parent) {
|
|
scope = Manager.lookupName(entry.parent, true);
|
|
}
|
|
scope[entry.name] = value;
|
|
return value;
|
|
},
|
|
/**
|
|
* Changes the mapping of an `xtype` to map to the specified component class.
|
|
* @param {String/Ext.Class} cls The class or class name to which `xtype` is mapped.
|
|
* @param {String} xtype The `xtype` to map or redefine as `cls`.
|
|
* @since 6.0.1
|
|
* @private
|
|
*/
|
|
setXType: function(cls, xtype) {
|
|
var className = cls.$className,
|
|
C = className ? cls : Manager.get(className = cls),
|
|
proto = C.prototype,
|
|
xtypes = proto.xtypes,
|
|
xtypesChain = proto.xtypesChain,
|
|
xtypesMap = proto.xtypesMap;
|
|
if (!proto.hasOwnProperty('xtypes')) {
|
|
proto.xtypes = xtypes = [];
|
|
proto.xtypesChain = xtypesChain = xtypesChain ? xtypesChain.slice(0) : [];
|
|
proto.xtypesMap = xtypesMap = Ext.apply({}, xtypesMap);
|
|
}
|
|
Manager.addAlias(className, 'widget.' + xtype, true);
|
|
xtypes.push(xtype);
|
|
xtypesChain.push(xtype);
|
|
xtypesMap[xtype] = true;
|
|
},
|
|
//TODO consider updating derived class xtypesChain / xtypesMap
|
|
/**
|
|
* Sets a name reference to a class.
|
|
*
|
|
* @param {String} name
|
|
* @param {Object} value
|
|
* @return {Ext.ClassManager} this
|
|
*/
|
|
set: function(name, value) {
|
|
var targetName = Manager.getName(value);
|
|
Manager.classes[name] = Manager.setNamespace(name, value);
|
|
if (targetName && targetName !== name) {
|
|
Manager.addAlternate(targetName, name);
|
|
}
|
|
return Manager;
|
|
},
|
|
/**
|
|
* Retrieve a class by its name.
|
|
*
|
|
* @param {String} name
|
|
* @return {Ext.Class} class
|
|
*/
|
|
get: function(name) {
|
|
return Manager.classes[name] || Manager.lookupName(name, false);
|
|
},
|
|
/**
|
|
* Adds a batch of class name to alias mappings.
|
|
* @param {Object} aliases The set of mappings of the form.
|
|
* className : [values...]
|
|
*/
|
|
addNameAliasMappings: function(aliases) {
|
|
Manager.addAlias(aliases);
|
|
},
|
|
/**
|
|
*
|
|
* @param {Object} alternates The set of mappings of the form
|
|
* className : [values...]
|
|
*/
|
|
addNameAlternateMappings: function(alternates) {
|
|
Manager.addAlternate(alternates);
|
|
},
|
|
/**
|
|
* Get a reference to the class by its alias.
|
|
*
|
|
* @param {String} alias
|
|
* @return {Ext.Class} class
|
|
*/
|
|
getByAlias: function(alias) {
|
|
return Manager.get(Manager.getNameByAlias(alias));
|
|
},
|
|
/**
|
|
* Get a component class name from a config object.
|
|
* @param {Object} config The config object.
|
|
* @param {String} [aliasPrefix] A prefix to use when getting
|
|
* a class name by alias.
|
|
* @return {Ext.Class} The class.
|
|
*
|
|
* @private
|
|
*/
|
|
getByConfig: function(config, aliasPrefix) {
|
|
var xclass = config.xclass,
|
|
name;
|
|
if (xclass) {
|
|
name = xclass;
|
|
} else {
|
|
name = config.xtype;
|
|
if (name) {
|
|
aliasPrefix = 'widget.';
|
|
} else {
|
|
name = config.type;
|
|
}
|
|
name = Manager.getNameByAlias(aliasPrefix + name);
|
|
}
|
|
return Manager.get(name);
|
|
},
|
|
/**
|
|
* Get the name of the class by its reference or its instance. This is
|
|
* usually invoked by the shorthand {@link Ext#getClassName}.
|
|
*
|
|
* Ext.ClassManager.getName(Ext.Action); // returns "Ext.Action"
|
|
*
|
|
* @param {Ext.Class/Object} object
|
|
* @return {String} className
|
|
*/
|
|
getName: function(object) {
|
|
return object && object.$className || '';
|
|
},
|
|
/**
|
|
* Get the class of the provided object; returns null if it's not an instance
|
|
* of any class created with Ext.define. This is usually invoked by the
|
|
* shorthand {@link Ext#getClass}.
|
|
*
|
|
* var component = new Ext.Component();
|
|
*
|
|
* Ext.getClass(component); // returns Ext.Component
|
|
*
|
|
* @param {Object} object
|
|
* @return {Ext.Class} class
|
|
*/
|
|
getClass: function(object) {
|
|
return object && object.self || null;
|
|
},
|
|
/**
|
|
* Defines a class.
|
|
* @deprecated Use {@link Ext#define} instead, as that also supports creating overrides.
|
|
* @private
|
|
*/
|
|
create: function(className, data, createdFn) {
|
|
if (className != null && typeof className !== 'string') {
|
|
throw new Error("[Ext.define] Invalid class name '" + className + "' specified, must be a non-empty string");
|
|
}
|
|
var ctor = makeCtor(className);
|
|
if (typeof data === 'function') {
|
|
data = data(ctor);
|
|
}
|
|
if (className) {
|
|
if (Manager.classes[className]) {
|
|
Ext.log.warn("[Ext.define] Duplicate class name '" + className + "' specified, must be a non-empty string");
|
|
}
|
|
ctor.name = className;
|
|
}
|
|
data.$className = className;
|
|
return new Class(ctor, data, function() {
|
|
var postprocessorStack = data.postprocessors || Manager.defaultPostprocessors,
|
|
registeredPostprocessors = Manager.postprocessors,
|
|
postprocessors = [],
|
|
postprocessor, i, ln, j, subLn, postprocessorProperties, postprocessorProperty;
|
|
delete data.postprocessors;
|
|
for (i = 0 , ln = postprocessorStack.length; i < ln; i++) {
|
|
postprocessor = postprocessorStack[i];
|
|
if (typeof postprocessor === 'string') {
|
|
postprocessor = registeredPostprocessors[postprocessor];
|
|
postprocessorProperties = postprocessor.properties;
|
|
if (postprocessorProperties === true) {
|
|
postprocessors.push(postprocessor.fn);
|
|
} else if (postprocessorProperties) {
|
|
for (j = 0 , subLn = postprocessorProperties.length; j < subLn; j++) {
|
|
postprocessorProperty = postprocessorProperties[j];
|
|
if (data.hasOwnProperty(postprocessorProperty)) {
|
|
postprocessors.push(postprocessor.fn);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
postprocessors.push(postprocessor);
|
|
}
|
|
}
|
|
data.postprocessors = postprocessors;
|
|
data.createdFn = createdFn;
|
|
Manager.processCreate(className, this, data);
|
|
});
|
|
},
|
|
processCreate: function(className, cls, clsData) {
|
|
var me = this,
|
|
postprocessor = clsData.postprocessors.shift(),
|
|
createdFn = clsData.createdFn;
|
|
if (!postprocessor) {
|
|
Ext.classSystemMonitor && Ext.classSystemMonitor(className, 'Ext.ClassManager#classCreated', arguments);
|
|
if (className) {
|
|
me.set(className, cls);
|
|
}
|
|
delete cls._classHooks;
|
|
if (createdFn) {
|
|
createdFn.call(cls, cls);
|
|
}
|
|
if (className) {
|
|
me.triggerCreated(className);
|
|
}
|
|
return;
|
|
}
|
|
if (postprocessor.call(me, className, cls, clsData, me.processCreate) !== false) {
|
|
me.processCreate(className, cls, clsData);
|
|
}
|
|
},
|
|
createOverride: function(className, data, createdFn) {
|
|
var me = this,
|
|
overriddenClassName = data.override,
|
|
requires = data.requires,
|
|
uses = data.uses,
|
|
mixins = data.mixins,
|
|
mixinsIsArray,
|
|
compat = 1,
|
|
// default if 'compatibility' is not specified
|
|
dependenciesLoaded,
|
|
classReady = function() {
|
|
var cls, dependencies, i, key, temp;
|
|
if (!dependenciesLoaded) {
|
|
dependencies = requires ? requires.slice(0) : [];
|
|
if (mixins) {
|
|
if (!(mixinsIsArray = mixins instanceof Array)) {
|
|
for (key in mixins) {
|
|
if (Ext.isString(cls = mixins[key])) {
|
|
dependencies.push(cls);
|
|
}
|
|
}
|
|
} else {
|
|
for (i = 0 , temp = mixins.length; i < temp; ++i) {
|
|
if (Ext.isString(cls = mixins[i])) {
|
|
dependencies.push(cls);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
dependenciesLoaded = true;
|
|
if (dependencies.length) {
|
|
// Since the override is going to be used (its target class is
|
|
// now created), we need to fetch the required classes for the
|
|
// override and call us back once they are loaded:
|
|
Ext.require(dependencies, classReady);
|
|
return;
|
|
}
|
|
}
|
|
// else we have no dependencies, so proceed
|
|
// transform mixin class names into class references, This
|
|
// loop can handle both the array and object forms of
|
|
// mixin definitions
|
|
if (mixinsIsArray) {
|
|
for (i = 0 , temp = mixins.length; i < temp; ++i) {
|
|
if (Ext.isString(cls = mixins[i])) {
|
|
mixins[i] = Ext.ClassManager.get(cls);
|
|
}
|
|
}
|
|
} else if (mixins) {
|
|
for (key in mixins) {
|
|
if (Ext.isString(cls = mixins[key])) {
|
|
mixins[key] = Ext.ClassManager.get(cls);
|
|
}
|
|
}
|
|
}
|
|
// The target class and the required classes for this override are
|
|
// ready, so we can apply the override now:
|
|
cls = overriddenClassName.$isClass ? overriddenClassName : me.get(overriddenClassName);
|
|
// We don't want to apply these:
|
|
delete data.override;
|
|
delete data.compatibility;
|
|
delete data.requires;
|
|
delete data.uses;
|
|
Ext.override(cls, data);
|
|
// This pushes the overriding file itself into Ext.Loader.history
|
|
// Hence if the target class never exists, the overriding file will
|
|
// never be included in the build.
|
|
Ext.Loader.history.push(className);
|
|
if (uses) {
|
|
// This "hides" from the Cmd auto-dependency scanner since
|
|
// the reference is circular (Loader requires us).
|
|
Ext['Loader'].addUsedClasses(uses);
|
|
}
|
|
// get these classes too!
|
|
if (createdFn) {
|
|
createdFn.call(cls, cls);
|
|
}
|
|
};
|
|
// last but not least!
|
|
if (className) {
|
|
Manager.overrideMap[className] = true;
|
|
}
|
|
// If specified, parse strings as versions, but otherwise treat as a
|
|
// boolean (maybe "compatibility: Ext.isIE8" or something).
|
|
//
|
|
if ('compatibility' in data) {
|
|
compat = data.compatibility;
|
|
if (!compat) {
|
|
// Cast '', null, undefined, 0 to false.
|
|
compat = false;
|
|
} else if (typeof compat === 'number') {
|
|
// By virtue of the condition above we must be a nonzero number.
|
|
compat = true;
|
|
} else if (typeof compat !== 'boolean') {
|
|
compat = Ext.checkVersion(compat);
|
|
}
|
|
}
|
|
if (compat) {
|
|
// override the target class right after it's created
|
|
if (overriddenClassName.$isClass) {
|
|
classReady();
|
|
} else {
|
|
me.onCreated(classReady, me, overriddenClassName);
|
|
}
|
|
}
|
|
me.triggerCreated(className, 2);
|
|
return me;
|
|
},
|
|
/**
|
|
* Instantiate a class by its alias. This is usually invoked by the
|
|
* shorthand {@link Ext#createByAlias}.
|
|
*
|
|
* If {@link Ext.Loader} is {@link Ext.Loader#setConfig enabled} and the class
|
|
* has not been defined yet, it will attempt to load the class via synchronous
|
|
* loading.
|
|
*
|
|
* var window = Ext.createByAlias('widget.window', { width: 600, height: 800 });
|
|
*
|
|
* @param {String} alias
|
|
* @param {Object...} args Additional arguments after the alias will be passed to the
|
|
* class constructor.
|
|
* @return {Object} instance
|
|
*/
|
|
instantiateByAlias: function() {
|
|
var alias = arguments[0],
|
|
args = arraySlice.call(arguments),
|
|
className = this.getNameByAlias(alias);
|
|
if (!className) {
|
|
throw new Error("[Ext.createByAlias] Unrecognized alias: " + alias);
|
|
}
|
|
args[0] = className;
|
|
return Ext.create.apply(Ext, args);
|
|
},
|
|
/**
|
|
* Instantiate a class by either full name, alias or alternate name
|
|
* @param {String} name
|
|
* @param {Mixed} args Additional arguments after the name will be passed to the class' constructor.
|
|
* @return {Object} instance
|
|
* @deprecated 5.0 Use Ext.create() instead.
|
|
*/
|
|
instantiate: function() {
|
|
Ext.log.warn('Ext.ClassManager.instantiate() is deprecated. Use Ext.create() instead.');
|
|
return Ext.create.apply(Ext, arguments);
|
|
},
|
|
/**
|
|
* @private
|
|
* @param name
|
|
* @param args
|
|
*/
|
|
dynInstantiate: function(name, args) {
|
|
args = arrayFrom(args, true);
|
|
args.unshift(name);
|
|
return Ext.create.apply(Ext, args);
|
|
},
|
|
/**
|
|
* @private
|
|
* @param length
|
|
*/
|
|
getInstantiator: function(length) {
|
|
var instantiators = this.instantiators,
|
|
instantiator, i, args;
|
|
instantiator = instantiators[length];
|
|
if (!instantiator) {
|
|
i = length;
|
|
args = [];
|
|
for (i = 0; i < length; i++) {
|
|
args.push('a[' + i + ']');
|
|
}
|
|
instantiator = instantiators[length] = new Function('c', 'a', 'return new c(' + args.join(',') + ')');
|
|
instantiator.name = "Ext.create" + length;
|
|
}
|
|
return instantiator;
|
|
},
|
|
/**
|
|
* @private
|
|
*/
|
|
postprocessors: {},
|
|
/**
|
|
* @private
|
|
*/
|
|
defaultPostprocessors: [],
|
|
/**
|
|
* Register a post-processor function.
|
|
*
|
|
* @private
|
|
* @param {String} name
|
|
* @param {Function} postprocessor
|
|
*/
|
|
registerPostprocessor: function(name, fn, properties, position, relativeTo) {
|
|
if (!position) {
|
|
position = 'last';
|
|
}
|
|
if (!properties) {
|
|
properties = [
|
|
name
|
|
];
|
|
}
|
|
this.postprocessors[name] = {
|
|
name: name,
|
|
properties: properties || false,
|
|
fn: fn
|
|
};
|
|
this.setDefaultPostprocessorPosition(name, position, relativeTo);
|
|
return this;
|
|
},
|
|
/**
|
|
* Set the default post processors array stack which are applied to every class.
|
|
*
|
|
* @private
|
|
* @param {String/Array} postprocessors The name of a registered post processor or an array of registered names.
|
|
* @return {Ext.ClassManager} this
|
|
*/
|
|
setDefaultPostprocessors: function(postprocessors) {
|
|
this.defaultPostprocessors = arrayFrom(postprocessors);
|
|
return this;
|
|
},
|
|
/**
|
|
* Insert this post-processor at a specific position in the stack, optionally relative to
|
|
* any existing post-processor
|
|
*
|
|
* @private
|
|
* @param {String} name The post-processor name. Note that it needs to be registered with
|
|
* {@link Ext.ClassManager#registerPostprocessor} before this
|
|
* @param {String} offset The insertion position. Four possible values are:
|
|
* 'first', 'last', or: 'before', 'after' (relative to the name provided in the third argument)
|
|
* @param {String} relativeName
|
|
* @return {Ext.ClassManager} this
|
|
*/
|
|
setDefaultPostprocessorPosition: function(name, offset, relativeName) {
|
|
var defaultPostprocessors = this.defaultPostprocessors,
|
|
index;
|
|
if (typeof offset === 'string') {
|
|
if (offset === 'first') {
|
|
defaultPostprocessors.unshift(name);
|
|
return this;
|
|
} else if (offset === 'last') {
|
|
defaultPostprocessors.push(name);
|
|
return this;
|
|
}
|
|
offset = (offset === 'after') ? 1 : -1;
|
|
}
|
|
index = Ext.Array.indexOf(defaultPostprocessors, relativeName);
|
|
if (index !== -1) {
|
|
Ext.Array.splice(defaultPostprocessors, Math.max(0, index + offset), 0, name);
|
|
}
|
|
return this;
|
|
}
|
|
});
|
|
/**
|
|
* @cfg xtype
|
|
* @member Ext.Class
|
|
* @inheritdoc Ext.Component#cfg-xtype
|
|
*/
|
|
/**
|
|
* @cfg {String} override
|
|
* @member Ext.Class
|
|
* Overrides members of the specified `target` class.
|
|
*
|
|
* **NOTE:** the overridden class must have been defined using
|
|
* {@link Ext#define Ext.define} in order to use the `override` config.
|
|
*
|
|
* Methods defined on the overriding class will not automatically call the methods of
|
|
* the same name in the ancestor class chain. To call the parent's method of the
|
|
* same name you must call {@link Ext.Base#callParent callParent}. To skip the
|
|
* method of the overridden class and call its parent you will instead call
|
|
* {@link Ext.Base#callSuper callSuper}.
|
|
*
|
|
* See {@link Ext#define Ext.define} for additional usage examples.
|
|
*/
|
|
/**
|
|
* @cfg {String/String[]} alias
|
|
* @member Ext.Class
|
|
* List of short aliases for class names. An alias consists of a namespace and a name
|
|
* concatenated by a period as <namespace>.<name>
|
|
*
|
|
* - **namespace** - The namespace describes what kind of alias this is and must be
|
|
* all lowercase.
|
|
* - **name** - The name of the alias which allows the lazy-instantiation via the
|
|
* alias. The name shouldn't contain any periods.
|
|
*
|
|
* A list of namespaces and the usages are:
|
|
*
|
|
* - **feature** - {@link Ext.grid.Panel Grid} features
|
|
* - **plugin** - Plugins
|
|
* - **store** - {@link Ext.data.Store}
|
|
* - **widget** - Components
|
|
*
|
|
* Most useful for defining xtypes for widgets:
|
|
*
|
|
* Ext.define('MyApp.CoolPanel', {
|
|
* extend: 'Ext.panel.Panel',
|
|
* alias: ['widget.coolpanel'],
|
|
* title: 'Yeah!'
|
|
* });
|
|
*
|
|
* // Using Ext.create
|
|
* Ext.create('widget.coolpanel');
|
|
*
|
|
* // Using the shorthand for defining widgets by xtype
|
|
* Ext.widget('panel', {
|
|
* items: [
|
|
* {xtype: 'coolpanel', html: 'Foo'},
|
|
* {xtype: 'coolpanel', html: 'Bar'}
|
|
* ]
|
|
* });
|
|
*/
|
|
Manager.registerPostprocessor('alias', function(name, cls, data) {
|
|
Ext.classSystemMonitor && Ext.classSystemMonitor(name, 'Ext.ClassManager#aliasPostProcessor', arguments);
|
|
var aliases = Ext.Array.from(data.alias),
|
|
i, ln;
|
|
for (i = 0 , ln = aliases.length; i < ln; i++) {
|
|
alias = aliases[i];
|
|
this.addAlias(cls, alias);
|
|
}
|
|
}, [
|
|
'xtype',
|
|
'alias'
|
|
]);
|
|
/**
|
|
* @cfg {Boolean} singleton
|
|
* @member Ext.Class
|
|
* When set to true, the class will be instantiated as singleton. For example:
|
|
*
|
|
* Ext.define('Logger', {
|
|
* singleton: true,
|
|
* log: function(msg) {
|
|
* console.log(msg);
|
|
* }
|
|
* });
|
|
*
|
|
* Logger.log('Hello');
|
|
*/
|
|
Manager.registerPostprocessor('singleton', function(name, cls, data, fn) {
|
|
Ext.classSystemMonitor && Ext.classSystemMonitor(name, 'Ext.ClassManager#singletonPostProcessor', arguments);
|
|
if (data.singleton) {
|
|
fn.call(this, name, new cls(), data);
|
|
} else {
|
|
return true;
|
|
}
|
|
return false;
|
|
});
|
|
/**
|
|
* @cfg {String/String[]} alternateClassName
|
|
* @member Ext.Class
|
|
* Defines alternate names for this class. For example:
|
|
*
|
|
* Ext.define('Developer', {
|
|
* alternateClassName: ['Coder', 'Hacker'],
|
|
* code: function(msg) {
|
|
* alert('Typing... ' + msg);
|
|
* }
|
|
* });
|
|
*
|
|
* var joe = Ext.create('Developer');
|
|
* joe.code('stackoverflow');
|
|
*
|
|
* var rms = Ext.create('Hacker');
|
|
* rms.code('hack hack');
|
|
*/
|
|
Manager.registerPostprocessor('alternateClassName', function(name, cls, data) {
|
|
Ext.classSystemMonitor && Ext.classSystemMonitor(name, 'Ext.ClassManager#alternateClassNamePostprocessor', arguments);
|
|
var alternates = data.alternateClassName,
|
|
i, ln, alternate;
|
|
if (!(alternates instanceof Array)) {
|
|
alternates = [
|
|
alternates
|
|
];
|
|
}
|
|
for (i = 0 , ln = alternates.length; i < ln; i++) {
|
|
alternate = alternates[i];
|
|
if (typeof alternate !== 'string') {
|
|
throw new Error("[Ext.define] Invalid alternate of: '" + alternate + "' for class: '" + name + "'; must be a valid string");
|
|
}
|
|
this.set(alternate, cls);
|
|
}
|
|
});
|
|
/**
|
|
* @cfg {Object} debugHooks
|
|
* A collection of diagnostic methods to decorate the real methods of the class. These
|
|
* methods are applied as an `override` if this class has debug enabled as defined by
|
|
* `Ext.isDebugEnabled`.
|
|
*
|
|
* These will be automatically removed by the Sencha Cmd compiler for production builds.
|
|
*
|
|
* Example usage:
|
|
*
|
|
* Ext.define('Foo.bar.Class', {
|
|
* foo: function (a, b, c) {
|
|
* ...
|
|
* },
|
|
*
|
|
* bar: function (a, b) {
|
|
* ...
|
|
* return 42;
|
|
* },
|
|
*
|
|
* debugHooks: {
|
|
* foo: function (a, b, c) {
|
|
* // check arguments...
|
|
* return this.callParent(arguments);
|
|
* }
|
|
* }
|
|
* });
|
|
*
|
|
* If you specify a `$enabled` property in the `debugHooks` object that will be used
|
|
* as the default enabled state for the hooks. If the `{@link Ext#manifest}` contains
|
|
* a `debug` object of if `{@link Ext#debugConfig}` is specified, the `$enabled` flag
|
|
* will override its "*" value.
|
|
*/
|
|
Manager.registerPostprocessor('debugHooks', function(name, Class, data) {
|
|
Ext.classSystemMonitor && Ext.classSystemMonitor(Class, 'Ext.Class#debugHooks', arguments);
|
|
if (Ext.isDebugEnabled(Class.$className, data.debugHooks.$enabled)) {
|
|
delete data.debugHooks.$enabled;
|
|
Ext.override(Class, data.debugHooks);
|
|
}
|
|
// may already have an instance here in the case of singleton
|
|
var target = Class.isInstance ? Class.self : Class;
|
|
delete target.prototype.debugHooks;
|
|
});
|
|
/**
|
|
* @cfg {Object} deprecated
|
|
* The object given has properties that describe the versions at which the deprecations
|
|
* apply.
|
|
*
|
|
* The purpose of the `deprecated` declaration is to enable development mode to give
|
|
* suitable error messages when deprecated methods or properties are used. Methods can
|
|
* always be injected to provide this feedback, but properties can only be handled on
|
|
* some browsers (those that support `Object.defineProperty`).
|
|
*
|
|
* In some cases, deprecated methods can be restored to their previous behavior or
|
|
* added back if they have been removed.
|
|
*
|
|
* The structure of a `deprecated` declaration is this:
|
|
*
|
|
* Ext.define('Foo.bar.Class', {
|
|
* ...
|
|
*
|
|
* deprecated: {
|
|
* // Optional package name - default is the framework (ext or touch)
|
|
* name: 'foobar',
|
|
*
|
|
* '5.0': {
|
|
* methods: {
|
|
* // Throws: '"removedMethod" is deprecated.'
|
|
* removedMethod: null,
|
|
*
|
|
* // Throws: '"oldMethod" is deprecated. Please use "newMethod" instead.'
|
|
* oldMethod: 'newMethod',
|
|
*
|
|
* // When this block is enabled, this method is applied as an
|
|
* // override. Otherwise you get same as "removeMethod".
|
|
* method: function () {
|
|
* // Do what v5 "method" did. If "method" exists in newer
|
|
* // versions callParent can call it. If 5.1 has "method"
|
|
* // then it would be next in line, otherwise 5.2 and last
|
|
* // would be the current class.
|
|
* },
|
|
*
|
|
* moreHelpful: {
|
|
* message: 'Something helpful to do instead.',
|
|
* fn: function () {
|
|
* // The v5 "moreHelpful" method to use when enabled.
|
|
* }
|
|
* }
|
|
* },
|
|
* properties: {
|
|
* // Throws: '"removedProp" is deprecated.'
|
|
* removedProp: null,
|
|
*
|
|
* // Throws: '"oldProp" is deprecated. Please use "newProp" instead.'
|
|
* oldProp: 'newProp',
|
|
*
|
|
* helpful: {
|
|
* message: 'Something helpful message about what to do.'
|
|
* }
|
|
* ...
|
|
* },
|
|
* statics: {
|
|
* methods: {
|
|
* ...
|
|
* },
|
|
* properties: {
|
|
* ...
|
|
* },
|
|
* }
|
|
* },
|
|
*
|
|
* '5.1': {
|
|
* ...
|
|
* },
|
|
*
|
|
* '5.2': {
|
|
* ...
|
|
* }
|
|
* }
|
|
* });
|
|
*
|
|
* The primary content of `deprecated` are the version number keys. These indicate
|
|
* a version number where methods or properties were deprecated. These versions are
|
|
* compared to the version reported by `Ext.getCompatVersion` to determine the action
|
|
* to take for each "block".
|
|
*
|
|
* When the compatibility version is set to a value less than a version number key,
|
|
* that block is said to be "enabled". For example, if a method was deprecated in
|
|
* version 5.0 but the desired compatibility level is 4.2 then the block is used to
|
|
* patch methods and (to some degree) restore pre-5.0 compatibility.
|
|
*
|
|
* When multiple active blocks have the same method name, each method is applied as
|
|
* an override in reverse order of version. In the above example, if a method appears
|
|
* in the "5.0", "5.1" and "5.2" blocks then the "5.2" method is applied as an override
|
|
* first, followed by the "5.1" method and finally the "5.0" method. This means that
|
|
* the `callParent` from the "5.0" method calls the "5.1" method which calls the
|
|
* "5.2" method which can (if applicable) call the current version.
|
|
*/
|
|
Manager.registerPostprocessor('deprecated', function(name, Class, data) {
|
|
Ext.classSystemMonitor && Ext.classSystemMonitor(Class, 'Ext.Class#deprecated', arguments);
|
|
// may already have an instance here in the case of singleton
|
|
var target = Class.isInstance ? Class.self : Class;
|
|
target.addDeprecations(data.deprecated);
|
|
delete target.prototype.deprecated;
|
|
});
|
|
Ext.apply(Ext, {
|
|
/**
|
|
* Instantiate a class by either full name, alias or alternate name.
|
|
*
|
|
* If {@link Ext.Loader} is {@link Ext.Loader#setConfig enabled} and the class has
|
|
* not been defined yet, it will attempt to load the class via synchronous loading.
|
|
*
|
|
* For example, all these three lines return the same result:
|
|
*
|
|
* // xtype
|
|
* var window = Ext.create({
|
|
* xtype: 'window',
|
|
* width: 600,
|
|
* height: 800,
|
|
* ...
|
|
* });
|
|
*
|
|
* // alias
|
|
* var window = Ext.create('widget.window', {
|
|
* width: 600,
|
|
* height: 800,
|
|
* ...
|
|
* });
|
|
*
|
|
* // alternate name
|
|
* var window = Ext.create('Ext.Window', {
|
|
* width: 600,
|
|
* height: 800,
|
|
* ...
|
|
* });
|
|
*
|
|
* // full class name
|
|
* var window = Ext.create('Ext.window.Window', {
|
|
* width: 600,
|
|
* height: 800,
|
|
* ...
|
|
* });
|
|
*
|
|
* // single object with xclass property:
|
|
* var window = Ext.create({
|
|
* xclass: 'Ext.window.Window', // any valid value for 'name' (above)
|
|
* width: 600,
|
|
* height: 800,
|
|
* ...
|
|
* });
|
|
*
|
|
* @param {String} [name] The class name or alias. Can be specified as `xclass`
|
|
* property if only one object parameter is specified.
|
|
* @param {Object...} [args] Additional arguments after the name will be passed to
|
|
* the class' constructor.
|
|
* @return {Object} instance
|
|
* @member Ext
|
|
* @method create
|
|
*/
|
|
create: function() {
|
|
var name = arguments[0],
|
|
nameType = typeof name,
|
|
args = arraySlice.call(arguments, 1),
|
|
cls;
|
|
if (nameType === 'function') {
|
|
cls = name;
|
|
} else {
|
|
if (nameType !== 'string' && args.length === 0) {
|
|
args = [
|
|
name
|
|
];
|
|
if (!(name = name.xclass)) {
|
|
name = args[0].xtype;
|
|
if (name) {
|
|
name = 'widget.' + name;
|
|
}
|
|
}
|
|
}
|
|
if (typeof name !== 'string' || name.length < 1) {
|
|
throw new Error("[Ext.create] Invalid class name or alias '" + name + "' specified, must be a non-empty string");
|
|
}
|
|
name = Manager.resolveName(name);
|
|
cls = Manager.get(name);
|
|
}
|
|
// Still not existing at this point, try to load it via synchronous mode as the last resort
|
|
if (!cls) {
|
|
Ext.log.warn("[Ext.Loader] Synchronously loading '" + name + "'; consider adding " + "Ext.require('" + name + "') above Ext.onReady");
|
|
Ext.syncRequire(name);
|
|
cls = Manager.get(name);
|
|
}
|
|
if (!cls) {
|
|
throw new Error("[Ext.create] Unrecognized class name / alias: " + name);
|
|
}
|
|
if (typeof cls !== 'function') {
|
|
throw new Error("[Ext.create] Singleton '" + name + "' cannot be instantiated.");
|
|
}
|
|
return Manager.getInstantiator(args.length)(cls, args);
|
|
},
|
|
/**
|
|
* Convenient shorthand to create a widget by its xtype or a config object.
|
|
*
|
|
* var button = Ext.widget('button'); // Equivalent to Ext.create('widget.button');
|
|
*
|
|
* var panel = Ext.widget('panel', { // Equivalent to Ext.create('widget.panel')
|
|
* title: 'Panel'
|
|
* });
|
|
*
|
|
* var grid = Ext.widget({
|
|
* xtype: 'grid',
|
|
* ...
|
|
* });
|
|
*
|
|
* If a {@link Ext.Component component} instance is passed, it is simply returned.
|
|
*
|
|
* @member Ext
|
|
* @param {String} [name] The xtype of the widget to create.
|
|
* @param {Object} [config] The configuration object for the widget constructor.
|
|
* @return {Object} The widget instance
|
|
*/
|
|
widget: function(name, config) {
|
|
// forms:
|
|
// 1: (xtype)
|
|
// 2: (xtype, config)
|
|
// 3: (config)
|
|
// 4: (xtype, component)
|
|
// 5: (component)
|
|
//
|
|
var xtype = name,
|
|
alias, className, T;
|
|
if (typeof xtype !== 'string') {
|
|
// if (form 3 or 5)
|
|
// first arg is config or component
|
|
config = name;
|
|
// arguments[0]
|
|
xtype = config.xtype;
|
|
className = config.xclass;
|
|
} else {
|
|
config = config || {};
|
|
}
|
|
if (config.isComponent) {
|
|
return config;
|
|
}
|
|
if (!className) {
|
|
alias = 'widget.' + xtype;
|
|
className = Manager.getNameByAlias(alias);
|
|
}
|
|
// this is needed to support demand loading of the class
|
|
if (className) {
|
|
T = Manager.get(className);
|
|
}
|
|
if (!T) {
|
|
return Ext.create(className || alias, config);
|
|
}
|
|
return new T(config);
|
|
},
|
|
/**
|
|
* @inheritdoc Ext.ClassManager#instantiateByAlias
|
|
* @member Ext
|
|
* @method createByAlias
|
|
*/
|
|
createByAlias: alias(Manager, 'instantiateByAlias'),
|
|
/**
|
|
* Defines a class or override. A basic class is defined like this:
|
|
*
|
|
* Ext.define('My.awesome.Class', {
|
|
* someProperty: 'something',
|
|
*
|
|
* someMethod: function(s) {
|
|
* alert(s + this.someProperty);
|
|
* }
|
|
*
|
|
* ...
|
|
* });
|
|
*
|
|
* var obj = new My.awesome.Class();
|
|
*
|
|
* obj.someMethod('Say '); // alerts 'Say something'
|
|
*
|
|
* To create an anonymous class, pass `null` for the `className`:
|
|
*
|
|
* Ext.define(null, {
|
|
* constructor: function () {
|
|
* // ...
|
|
* }
|
|
* });
|
|
*
|
|
* In some cases, it is helpful to create a nested scope to contain some private
|
|
* properties. The best way to do this is to pass a function instead of an object
|
|
* as the second parameter. This function will be called to produce the class
|
|
* body:
|
|
*
|
|
* Ext.define('MyApp.foo.Bar', function () {
|
|
* var id = 0;
|
|
*
|
|
* return {
|
|
* nextId: function () {
|
|
* return ++id;
|
|
* }
|
|
* };
|
|
* });
|
|
*
|
|
* _Note_ that when using override, the above syntax will not override successfully, because
|
|
* the passed function would need to be executed first to determine whether or not the result
|
|
* is an override or defining a new object. As such, an alternative syntax that immediately
|
|
* invokes the function can be used:
|
|
*
|
|
* Ext.define('MyApp.override.BaseOverride', function () {
|
|
* var counter = 0;
|
|
*
|
|
* return {
|
|
* override: 'Ext.Component',
|
|
* logId: function () {
|
|
* console.log(++counter, this.id);
|
|
* }
|
|
* };
|
|
* }());
|
|
*
|
|
*
|
|
* When using this form of `Ext.define`, the function is passed a reference to its
|
|
* class. This can be used as an efficient way to access any static properties you
|
|
* may have:
|
|
*
|
|
* Ext.define('MyApp.foo.Bar', function (Bar) {
|
|
* return {
|
|
* statics: {
|
|
* staticMethod: function () {
|
|
* // ...
|
|
* }
|
|
* },
|
|
*
|
|
* method: function () {
|
|
* return Bar.staticMethod();
|
|
* }
|
|
* };
|
|
* });
|
|
*
|
|
* To define an override, include the `override` property. The content of an
|
|
* override is aggregated with the specified class in order to extend or modify
|
|
* that class. This can be as simple as setting default property values or it can
|
|
* extend and/or replace methods. This can also extend the statics of the class.
|
|
*
|
|
* One use for an override is to break a large class into manageable pieces.
|
|
*
|
|
* // File: /src/app/Panel.js
|
|
*
|
|
* Ext.define('My.app.Panel', {
|
|
* extend: 'Ext.panel.Panel',
|
|
* requires: [
|
|
* 'My.app.PanelPart2',
|
|
* 'My.app.PanelPart3'
|
|
* ]
|
|
*
|
|
* constructor: function (config) {
|
|
* this.callParent(arguments); // calls Ext.panel.Panel's constructor
|
|
* //...
|
|
* },
|
|
*
|
|
* statics: {
|
|
* method: function () {
|
|
* return 'abc';
|
|
* }
|
|
* }
|
|
* });
|
|
*
|
|
* // File: /src/app/PanelPart2.js
|
|
* Ext.define('My.app.PanelPart2', {
|
|
* override: 'My.app.Panel',
|
|
*
|
|
* constructor: function (config) {
|
|
* this.callParent(arguments); // calls My.app.Panel's constructor
|
|
* //...
|
|
* }
|
|
* });
|
|
*
|
|
* Another use of overrides is to provide optional parts of classes that can be
|
|
* independently required. In this case, the class may even be unaware of the
|
|
* override altogether.
|
|
*
|
|
* Ext.define('My.ux.CoolTip', {
|
|
* override: 'Ext.tip.ToolTip',
|
|
*
|
|
* constructor: function (config) {
|
|
* this.callParent(arguments); // calls Ext.tip.ToolTip's constructor
|
|
* //...
|
|
* }
|
|
* });
|
|
*
|
|
* The above override can now be required as normal.
|
|
*
|
|
* Ext.define('My.app.App', {
|
|
* requires: [
|
|
* 'My.ux.CoolTip'
|
|
* ]
|
|
* });
|
|
*
|
|
* Overrides can also contain statics, inheritableStatics, or privates:
|
|
*
|
|
* Ext.define('My.app.BarMod', {
|
|
* override: 'Ext.foo.Bar',
|
|
*
|
|
* statics: {
|
|
* method: function (x) {
|
|
* return this.callParent([x * 2]); // call Ext.foo.Bar.method
|
|
* }
|
|
* }
|
|
* });
|
|
*
|
|
* Starting in version 4.2.2, overrides can declare their `compatibility` based
|
|
* on the framework version or on versions of other packages. For details on the
|
|
* syntax and options for these checks, see `Ext.checkVersion`.
|
|
*
|
|
* The simplest use case is to test framework version for compatibility:
|
|
*
|
|
* Ext.define('App.overrides.grid.Panel', {
|
|
* override: 'Ext.grid.Panel',
|
|
*
|
|
* compatibility: '4.2.2', // only if framework version is 4.2.2
|
|
*
|
|
* //...
|
|
* });
|
|
*
|
|
* An array is treated as an OR, so if any specs match, the override is
|
|
* compatible.
|
|
*
|
|
* Ext.define('App.overrides.some.Thing', {
|
|
* override: 'Foo.some.Thing',
|
|
*
|
|
* compatibility: [
|
|
* '4.2.2',
|
|
* 'foo@1.0.1-1.0.2'
|
|
* ],
|
|
*
|
|
* //...
|
|
* });
|
|
*
|
|
* To require that all specifications match, an object can be provided:
|
|
*
|
|
* Ext.define('App.overrides.some.Thing', {
|
|
* override: 'Foo.some.Thing',
|
|
*
|
|
* compatibility: {
|
|
* and: [
|
|
* '4.2.2',
|
|
* 'foo@1.0.1-1.0.2'
|
|
* ]
|
|
* },
|
|
*
|
|
* //...
|
|
* });
|
|
*
|
|
* Because the object form is just a recursive check, these can be nested:
|
|
*
|
|
* Ext.define('App.overrides.some.Thing', {
|
|
* override: 'Foo.some.Thing',
|
|
*
|
|
* compatibility: {
|
|
* and: [
|
|
* '4.2.2', // exactly version 4.2.2 of the framework *AND*
|
|
* {
|
|
* // either (or both) of these package specs:
|
|
* or: [
|
|
* 'foo@1.0.1-1.0.2',
|
|
* 'bar@3.0+'
|
|
* ]
|
|
* }
|
|
* ]
|
|
* },
|
|
*
|
|
* //...
|
|
* });
|
|
*
|
|
* IMPORTANT: An override is only included in a build if the class it overrides is
|
|
* required. Otherwise, the override, like the target class, is not included. In
|
|
* Sencha Cmd v4, the `compatibility` declaration can likewise be used to remove
|
|
* incompatible overrides from a build.
|
|
*
|
|
* @param {String} className The class name to create in string dot-namespaced format, for example:
|
|
* 'My.very.awesome.Class', 'FeedViewer.plugin.CoolPager'
|
|
* It is highly recommended to follow this simple convention:
|
|
* - The root and the class name are 'CamelCased'
|
|
* - Everything else is lower-cased
|
|
* Pass `null` to create an anonymous class.
|
|
* @param {Object} data The key - value pairs of properties to apply to this class. Property names can be of any valid
|
|
* strings, except those in the reserved listed below:
|
|
*
|
|
* - {@link Ext.Class#cfg-alias alias}
|
|
* - {@link Ext.Class#cfg-alternateClassName alternateClassName}
|
|
* - {@link Ext.Class#cfg-cachedConfig cachedConfig}
|
|
* - {@link Ext.Class#cfg-config config}
|
|
* - {@link Ext.Class#cfg-extend extend}
|
|
* - {@link Ext.Class#cfg-inheritableStatics inheritableStatics}
|
|
* - {@link Ext.Class#cfg-mixins mixins}
|
|
* - {@link Ext.Class#cfg-override override}
|
|
* - {@link Ext.Class#cfg-platformConfig platformConfig}
|
|
* - {@link Ext.Class#cfg-privates privates}
|
|
* - {@link Ext.Class#cfg-requires requires}
|
|
* - `self`
|
|
* - {@link Ext.Class#cfg-singleton singleton}
|
|
* - {@link Ext.Class#cfg-statics statics}
|
|
* - {@link Ext.Class#cfg-uses uses}
|
|
* - {@link Ext.Class#cfg-xtype xtype} (for {@link Ext.Component Components} only)
|
|
*
|
|
* @param {Function} [createdFn] Callback to execute after the class is created, the execution scope of which
|
|
* (`this`) will be the newly created class itself.
|
|
* @return {Ext.Base}
|
|
* @member Ext
|
|
*/
|
|
define: function(className, data, createdFn) {
|
|
Ext.classSystemMonitor && Ext.classSystemMonitor(className, 'ClassManager#define', arguments);
|
|
if (data.override) {
|
|
Manager.classState[className] = 20;
|
|
return Manager.createOverride.apply(Manager, arguments);
|
|
}
|
|
Manager.classState[className] = 10;
|
|
return Manager.create.apply(Manager, arguments);
|
|
},
|
|
/**
|
|
* Undefines a class defined using the #define method. Typically used
|
|
* for unit testing where setting up and tearing down a class multiple
|
|
* times is required. For example:
|
|
*
|
|
* // define a class
|
|
* Ext.define('Foo', {
|
|
* ...
|
|
* });
|
|
*
|
|
* // run test
|
|
*
|
|
* // undefine the class
|
|
* Ext.undefine('Foo');
|
|
* @param {String} className The class name to undefine in string dot-namespaced format.
|
|
* @private
|
|
*/
|
|
undefine: function(className) {
|
|
Ext.classSystemMonitor && Ext.classSystemMonitor(className, 'Ext.ClassManager#undefine', arguments);
|
|
var classes = Manager.classes;
|
|
delete classes[className];
|
|
delete Manager.existCache[className];
|
|
delete Manager.classState[className];
|
|
Manager.removeName(className);
|
|
var entry = Manager.getNamespaceEntry(className),
|
|
scope = entry.parent ? Manager.lookupName(entry.parent, false) : Ext.global;
|
|
if (scope) {
|
|
// Old IE blows up on attempt to delete window property
|
|
try {
|
|
delete scope[entry.name];
|
|
} catch (e) {
|
|
scope[entry.name] = undefined;
|
|
}
|
|
}
|
|
},
|
|
/**
|
|
* @inheritdoc Ext.ClassManager#getName
|
|
* @member Ext
|
|
* @method getClassName
|
|
*/
|
|
getClassName: alias(Manager, 'getName'),
|
|
/**
|
|
* Returns the displayName property or className or object. When all else fails, returns "Anonymous".
|
|
* @param {Object} object
|
|
* @return {String}
|
|
*/
|
|
getDisplayName: function(object) {
|
|
if (object) {
|
|
if (object.displayName) {
|
|
return object.displayName;
|
|
}
|
|
if (object.$name && object.$class) {
|
|
return Ext.getClassName(object.$class) + '#' + object.$name;
|
|
}
|
|
if (object.$className) {
|
|
return object.$className;
|
|
}
|
|
}
|
|
return 'Anonymous';
|
|
},
|
|
/**
|
|
* @inheritdoc Ext.ClassManager#getClass
|
|
* @member Ext
|
|
* @method getClass
|
|
*/
|
|
getClass: alias(Manager, 'getClass'),
|
|
/**
|
|
* Creates namespaces to be used for scoping variables and classes so that they are not global.
|
|
* Specifying the last node of a namespace implicitly creates all other nodes. Usage:
|
|
*
|
|
* Ext.namespace('Company', 'Company.data');
|
|
*
|
|
* // equivalent and preferable to the above syntax
|
|
* Ext.ns('Company.data');
|
|
*
|
|
* Company.Widget = function() { ... };
|
|
*
|
|
* Company.data.CustomStore = function(config) { ... };
|
|
*
|
|
* @param {String...} namespaces
|
|
* @return {Object} The (last) namespace object created.
|
|
* @member Ext
|
|
* @method namespace
|
|
*/
|
|
namespace: function() {
|
|
var root = global,
|
|
i;
|
|
for (i = arguments.length; i-- > 0; ) {
|
|
root = Manager.lookupName(arguments[i], true);
|
|
}
|
|
return root;
|
|
}
|
|
});
|
|
/**
|
|
* This function registers top-level (root) namespaces. This is needed for "sandbox"
|
|
* builds.
|
|
*
|
|
* Ext.addRootNamespaces({
|
|
* MyApp: MyApp,
|
|
* Common: Common
|
|
* });
|
|
*
|
|
* In the above example, `MyApp` and `Common` are top-level namespaces that happen
|
|
* to also be included in the sandbox closure. Something like this:
|
|
*
|
|
* (function(Ext) {
|
|
*
|
|
* Ext.sandboxName = 'Ext6';
|
|
* Ext.isSandboxed = true;
|
|
* Ext.buildSettings = { baseCSSPrefix: "x6-", scopeResetCSS: true };
|
|
*
|
|
* var MyApp = MyApp || {};
|
|
* Ext.addRootNamespaces({ MyApp: MyApp );
|
|
*
|
|
* ... normal app.js goes here ...
|
|
*
|
|
* })(this.Ext6 || (this.Ext6 = {}));
|
|
*
|
|
* The sandbox wrapper around the normally built `app.js` content has to take care
|
|
* of introducing top-level namespaces as well as call this method.
|
|
*
|
|
* @param {Object} namespaces
|
|
* @method addRootNamespaces
|
|
* @member Ext
|
|
* @since 6.0.0
|
|
* @private
|
|
*/
|
|
Ext.addRootNamespaces = Manager.addRootNamespaces;
|
|
/**
|
|
* Old name for {@link Ext#widget}.
|
|
* @deprecated Use {@link Ext#widget} instead.
|
|
* @method createWidget
|
|
* @member Ext
|
|
* @private
|
|
*/
|
|
Ext.createWidget = Ext.widget;
|
|
/**
|
|
* Convenient alias for {@link Ext#namespace Ext.namespace}.
|
|
* @inheritdoc Ext#namespace
|
|
* @member Ext
|
|
* @method ns
|
|
*/
|
|
Ext.ns = Ext.namespace;
|
|
Class.registerPreprocessor('className', function(cls, data) {
|
|
if ('$className' in data) {
|
|
cls.$className = data.$className;
|
|
cls.displayName = cls.$className;
|
|
}
|
|
Ext.classSystemMonitor && Ext.classSystemMonitor(cls, 'Ext.ClassManager#classNamePreprocessor', arguments);
|
|
}, true, 'first');
|
|
Class.registerPreprocessor('alias', function(cls, data) {
|
|
Ext.classSystemMonitor && Ext.classSystemMonitor(cls, 'Ext.ClassManager#aliasPreprocessor', arguments);
|
|
var prototype = cls.prototype,
|
|
xtypes = arrayFrom(data.xtype),
|
|
aliases = arrayFrom(data.alias),
|
|
widgetPrefix = 'widget.',
|
|
widgetPrefixLength = widgetPrefix.length,
|
|
xtypesChain = Array.prototype.slice.call(prototype.xtypesChain || []),
|
|
xtypesMap = Ext.merge({}, prototype.xtypesMap || {}),
|
|
i, ln, alias, xtype;
|
|
for (i = 0 , ln = aliases.length; i < ln; i++) {
|
|
alias = aliases[i];
|
|
if (typeof alias !== 'string' || alias.length < 1) {
|
|
throw new Error("[Ext.define] Invalid alias of: '" + alias + "' for class: '" + name + "'; must be a valid string");
|
|
}
|
|
if (alias.substring(0, widgetPrefixLength) === widgetPrefix) {
|
|
xtype = alias.substring(widgetPrefixLength);
|
|
Ext.Array.include(xtypes, xtype);
|
|
}
|
|
}
|
|
cls.xtype = data.xtype = xtypes[0];
|
|
data.xtypes = xtypes;
|
|
for (i = 0 , ln = xtypes.length; i < ln; i++) {
|
|
xtype = xtypes[i];
|
|
if (!xtypesMap[xtype]) {
|
|
xtypesMap[xtype] = true;
|
|
xtypesChain.push(xtype);
|
|
}
|
|
}
|
|
data.xtypesChain = xtypesChain;
|
|
data.xtypesMap = xtypesMap;
|
|
// Class is already extended at this point
|
|
Ext.Function.interceptAfterOnce(cls, 'onClassCreated', function() {
|
|
var cls = this,
|
|
prototype = cls.prototype,
|
|
mixins = prototype.mixins,
|
|
key, mixin;
|
|
Ext.classSystemMonitor && Ext.classSystemMonitor(cls, 'Ext.ClassManager#aliasPreprocessor#afterClassCreated', arguments);
|
|
for (key in mixins) {
|
|
if (mixins.hasOwnProperty(key)) {
|
|
mixin = mixins[key];
|
|
xtypes = mixin.xtypes;
|
|
if (xtypes) {
|
|
for (i = 0 , ln = xtypes.length; i < ln; i++) {
|
|
xtype = xtypes[i];
|
|
if (!xtypesMap[xtype]) {
|
|
xtypesMap[xtype] = true;
|
|
xtypesChain.push(xtype);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
});
|
|
for (i = 0 , ln = xtypes.length; i < ln; i++) {
|
|
xtype = xtypes[i];
|
|
if (typeof xtype !== 'string' || xtype.length < 1) {
|
|
throw new Error("[Ext.define] Invalid xtype of: '" + xtype + "' for class: '" + name + "'; must be a valid non-empty string");
|
|
}
|
|
Ext.Array.include(aliases, widgetPrefix + xtype);
|
|
}
|
|
data.alias = aliases;
|
|
}, [
|
|
'xtype',
|
|
'alias'
|
|
]);
|
|
// load the cmd-5 style app manifest metadata now, if available...
|
|
if (Ext.manifest) {
|
|
var manifest = Ext.manifest,
|
|
classes = manifest.classes,
|
|
paths = manifest.paths,
|
|
aliases = {},
|
|
alternates = {},
|
|
className, obj, name, path, baseUrl;
|
|
if (paths) {
|
|
// if the manifest paths were calculated as relative to the
|
|
// bootstrap file, then we need to prepend Boot.baseUrl to the
|
|
// paths before processing
|
|
if (manifest.bootRelative) {
|
|
baseUrl = Ext.Boot.baseUrl;
|
|
for (path in paths) {
|
|
if (paths.hasOwnProperty(path)) {
|
|
paths[path] = baseUrl + paths[path];
|
|
}
|
|
}
|
|
}
|
|
Manager.setPath(paths);
|
|
}
|
|
if (classes) {
|
|
for (className in classes) {
|
|
alternates[className] = [];
|
|
aliases[className] = [];
|
|
obj = classes[className];
|
|
if (obj.alias) {
|
|
aliases[className] = obj.alias;
|
|
}
|
|
if (obj.alternates) {
|
|
alternates[className] = obj.alternates;
|
|
}
|
|
}
|
|
}
|
|
Manager.addAlias(aliases);
|
|
Manager.addAlternate(alternates);
|
|
}
|
|
return Manager;
|
|
}(Ext.Class, Ext.Function.alias, Array.prototype.slice, Ext.Array.from, Ext.global));
|
|
|
|
/**
|
|
* @class Ext.env.Browser
|
|
* Provides information about browser.
|
|
*
|
|
* Should not be manually instantiated unless for unit-testing.
|
|
* Access the global instance stored in {@link Ext.browser} instead.
|
|
* @private
|
|
*/
|
|
(Ext.env || (Ext.env = {})).Browser = function(userAgent, publish) {
|
|
// @define Ext.env.Browser
|
|
// @define Ext.browser
|
|
// @require Ext.Object
|
|
// @require Ext.Version
|
|
var me = this,
|
|
browserPrefixes = Ext.Boot.browserPrefixes,
|
|
browserNames = Ext.Boot.browserNames,
|
|
enginePrefixes = me.enginePrefixes,
|
|
engineNames = me.engineNames,
|
|
browserMatch = userAgent.match(new RegExp('((?:' + Ext.Object.getValues(browserPrefixes).join(')|(?:') + '))([\\w\\._]+)')),
|
|
engineMatch = userAgent.match(new RegExp('((?:' + Ext.Object.getValues(enginePrefixes).join(')|(?:') + '))([\\w\\._]+)')),
|
|
browserName = browserNames.other,
|
|
engineName = engineNames.other,
|
|
browserVersion = '',
|
|
engineVersion = '',
|
|
majorVer = '',
|
|
isWebView = false,
|
|
i, prefix, mode, name, maxIEVersion;
|
|
/**
|
|
* @property {String}
|
|
* Browser User Agent string.
|
|
*/
|
|
me.userAgent = userAgent;
|
|
/**
|
|
* A "hybrid" property, can be either accessed as a method call, for example:
|
|
*
|
|
* if (Ext.browser.is('IE')) {
|
|
* // ...
|
|
* }
|
|
*
|
|
* Or as an object with Boolean properties, for example:
|
|
*
|
|
* if (Ext.browser.is.IE) {
|
|
* // ...
|
|
* }
|
|
*
|
|
* Versions can be conveniently checked as well. For example:
|
|
*
|
|
* if (Ext.browser.is.IE10) {
|
|
* // Equivalent to (Ext.browser.is.IE && Ext.browser.version.equals(10))
|
|
* }
|
|
*
|
|
* __Note:__ Only {@link Ext.Version#getMajor major component} and {@link Ext.Version#getShortVersion simplified}
|
|
* value of the version are available via direct property checking.
|
|
*
|
|
* Supported values are:
|
|
*
|
|
* - IE
|
|
* - Firefox
|
|
* - Safari
|
|
* - Chrome
|
|
* - Opera
|
|
* - WebKit
|
|
* - Gecko
|
|
* - Presto
|
|
* - Trident
|
|
* - WebView
|
|
* - Other
|
|
*
|
|
* @param {String} name The OS name to check.
|
|
* @return {Boolean}
|
|
*/
|
|
this.is = function(name) {
|
|
// Since this function reference also acts as a map, we do not want it to be
|
|
// shared between instances, so it is defined here, not on the prototype.
|
|
return !!this.is[name];
|
|
};
|
|
// Edge has a userAgent with All browsers so we manage it separately
|
|
// "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.135 Safari/537.36 Edge/12.10240"
|
|
if (/Edge\//.test(userAgent)) {
|
|
browserMatch = userAgent.match(/(Edge\/)([\w.]+)/);
|
|
}
|
|
if (browserMatch) {
|
|
browserName = browserNames[Ext.Object.getKey(browserPrefixes, browserMatch[1])];
|
|
if (browserName === 'Safari' && /^Opera/.test(userAgent)) {
|
|
// Prevent Opera 12 and earlier from being incorrectly reported as Safari
|
|
browserName = 'Opera';
|
|
}
|
|
browserVersion = new Ext.Version(browserMatch[2]);
|
|
}
|
|
if (engineMatch) {
|
|
engineName = engineNames[Ext.Object.getKey(enginePrefixes, engineMatch[1])];
|
|
engineVersion = new Ext.Version(engineMatch[2]);
|
|
}
|
|
if (engineName === 'Trident' && browserName !== 'IE') {
|
|
browserName = 'IE';
|
|
var version = userAgent.match(/.*rv:(\d+.\d+)/);
|
|
if (version && version.length) {
|
|
version = version[1];
|
|
browserVersion = new Ext.Version(version);
|
|
}
|
|
}
|
|
if (browserName && browserVersion) {
|
|
Ext.setVersion(browserName, browserVersion);
|
|
}
|
|
/**
|
|
* @property chromeVersion
|
|
* The current version of Chrome (0 if the browser is not Chrome).
|
|
* @readonly
|
|
* @type Number
|
|
* @member Ext
|
|
*/
|
|
/**
|
|
* @property firefoxVersion
|
|
* The current version of Firefox (0 if the browser is not Firefox).
|
|
* @readonly
|
|
* @type Number
|
|
* @member Ext
|
|
*/
|
|
/**
|
|
* @property ieVersion
|
|
* The current version of IE (0 if the browser is not IE). This does not account
|
|
* for the documentMode of the current page, which is factored into {@link #isIE8},
|
|
* and {@link #isIE9}. Thus this is not always true:
|
|
*
|
|
* Ext.isIE8 == (Ext.ieVersion == 8)
|
|
*
|
|
* @readonly
|
|
* @type Number
|
|
* @member Ext
|
|
*/
|
|
/**
|
|
* @property isChrome
|
|
* True if the detected browser is Chrome.
|
|
* @readonly
|
|
* @type Boolean
|
|
* @member Ext
|
|
*/
|
|
/**
|
|
* @property isGecko
|
|
* True if the detected browser uses the Gecko layout engine (e.g. Mozilla, Firefox).
|
|
* @readonly
|
|
* @type Boolean
|
|
* @member Ext
|
|
*/
|
|
/**
|
|
* @property isIE
|
|
* True if the detected browser is Internet Explorer.
|
|
* @readonly
|
|
* @type Boolean
|
|
* @member Ext
|
|
*/
|
|
/**
|
|
* @property isIE8
|
|
* True if the detected browser is Internet Explorer 8.x.
|
|
* @readonly
|
|
* @type Boolean
|
|
* @member Ext
|
|
*/
|
|
/**
|
|
* @property isIE8m
|
|
* True if the detected browser is Internet Explorer 8.x or lower.
|
|
* @readonly
|
|
* @type Boolean
|
|
* @member Ext
|
|
*/
|
|
/**
|
|
* @property isIE8p
|
|
* True if the detected browser is Internet Explorer 8.x or higher.
|
|
* @readonly
|
|
* @type Boolean
|
|
* @member Ext
|
|
*/
|
|
/**
|
|
* @property isIE9
|
|
* True if the detected browser is Internet Explorer 9.x.
|
|
* @readonly
|
|
* @type Boolean
|
|
* @member Ext
|
|
*/
|
|
/**
|
|
* @property isIE9m
|
|
* True if the detected browser is Internet Explorer 9.x or lower.
|
|
* @readonly
|
|
* @type Boolean
|
|
* @member Ext
|
|
*/
|
|
/**
|
|
* @property isIE9p
|
|
* True if the detected browser is Internet Explorer 9.x or higher.
|
|
* @readonly
|
|
* @type Boolean
|
|
* @member Ext
|
|
*/
|
|
/**
|
|
* @property isIE10
|
|
* True if the detected browser is Internet Explorer 10.x.
|
|
* @readonly
|
|
* @type Boolean
|
|
* @member Ext
|
|
*/
|
|
/**
|
|
* @property isIE10m
|
|
* True if the detected browser is Internet Explorer 10.x or lower.
|
|
* @readonly
|
|
* @type Boolean
|
|
* @member Ext
|
|
*/
|
|
/**
|
|
* @property isIE10p
|
|
* True if the detected browser is Internet Explorer 10.x or higher.
|
|
* @readonly
|
|
* @type Boolean
|
|
* @member Ext
|
|
*/
|
|
/**
|
|
* @property isIE11
|
|
* True if the detected browser is Internet Explorer 11.x.
|
|
* @readonly
|
|
* @type Boolean
|
|
* @member Ext
|
|
*/
|
|
/**
|
|
* @property isIE11m
|
|
* True if the detected browser is Internet Explorer 11.x or lower.
|
|
* @readonly
|
|
* @type Boolean
|
|
* @member Ext
|
|
*/
|
|
/**
|
|
* @property isIE11p
|
|
* True if the detected browser is Internet Explorer 11.x or higher.
|
|
* @readonly
|
|
* @type Boolean
|
|
* @member Ext
|
|
*/
|
|
/**
|
|
* @property isEdge
|
|
* True if the detected browser is Edge.
|
|
* @readonly
|
|
* @type Boolean
|
|
* @member Ext
|
|
*/
|
|
/**
|
|
* @property isLinux
|
|
* True if the detected platform is Linux.
|
|
* @readonly
|
|
* @type Boolean
|
|
* @member Ext
|
|
*/
|
|
/**
|
|
* @property isMac
|
|
* True if the detected platform is Mac OS.
|
|
* @readonly
|
|
* @type Boolean
|
|
* @member Ext
|
|
*/
|
|
/**
|
|
* @property isOpera
|
|
* True if the detected browser is Opera.
|
|
* @readonly
|
|
* @type Boolean
|
|
* @member Ext
|
|
*/
|
|
/**
|
|
* @property isSafari
|
|
* True if the detected browser is Safari.
|
|
* @readonly
|
|
* @type Boolean
|
|
* @member Ext
|
|
*/
|
|
/**
|
|
* @property isWebKit
|
|
* True if the detected browser uses WebKit.
|
|
* @readonly
|
|
* @type Boolean
|
|
* @member Ext
|
|
*/
|
|
/**
|
|
* @property isWindows
|
|
* True if the detected platform is Windows.
|
|
* @readonly
|
|
* @type Boolean
|
|
* @member Ext
|
|
*/
|
|
/**
|
|
* @property operaVersion
|
|
* The current version of Opera (0 if the browser is not Opera).
|
|
* @readonly
|
|
* @type Number
|
|
* @member Ext
|
|
*/
|
|
/**
|
|
* @property safariVersion
|
|
* The current version of Safari (0 if the browser is not Safari).
|
|
* @readonly
|
|
* @type Number
|
|
* @member Ext
|
|
*/
|
|
/**
|
|
* @property webKitVersion
|
|
* The current version of WebKit (0 if the browser does not use WebKit).
|
|
* @readonly
|
|
* @type Number
|
|
* @member Ext
|
|
*/
|
|
// Facebook changes the userAgent when you view a website within their iOS app. For some reason, the strip out information
|
|
// about the browser, so we have to detect that and fake it...
|
|
if (userAgent.match(/FB/) && browserName === "Other") {
|
|
browserName = browserNames.safari;
|
|
engineName = engineNames.webkit;
|
|
}
|
|
if (userAgent.match(/Android.*Chrome/g)) {
|
|
browserName = 'ChromeMobile';
|
|
}
|
|
if (userAgent.match(/OPR/)) {
|
|
browserName = 'Opera';
|
|
browserMatch = userAgent.match(/OPR\/(\d+.\d+)/);
|
|
browserVersion = new Ext.Version(browserMatch[1]);
|
|
}
|
|
Ext.apply(this, {
|
|
engineName: engineName,
|
|
engineVersion: engineVersion,
|
|
name: browserName,
|
|
version: browserVersion
|
|
});
|
|
this.setFlag(browserName, true, publish);
|
|
// e.g., Ext.isIE
|
|
if (browserVersion) {
|
|
majorVer = browserVersion.getMajor() || '';
|
|
if (me.is.IE) {
|
|
majorVer = parseInt(majorVer, 10);
|
|
mode = document.documentMode;
|
|
// IE's Developer Tools allows switching of Browser Mode (userAgent) and
|
|
// Document Mode (actual behavior) independently. While this makes no real
|
|
// sense, the bottom line is that document.documentMode holds the key to
|
|
// getting the proper "version" determined. That value is always 5 when in
|
|
// Quirks Mode.
|
|
if (mode === 7 || (majorVer === 7 && mode !== 8 && mode !== 9 && mode !== 10)) {
|
|
majorVer = 7;
|
|
} else if (mode === 8 || (majorVer === 8 && mode !== 8 && mode !== 9 && mode !== 10)) {
|
|
majorVer = 8;
|
|
} else if (mode === 9 || (majorVer === 9 && mode !== 7 && mode !== 8 && mode !== 10)) {
|
|
majorVer = 9;
|
|
} else if (mode === 10 || (majorVer === 10 && mode !== 7 && mode !== 8 && mode !== 9)) {
|
|
majorVer = 10;
|
|
} else if (mode === 11 || (majorVer === 11 && mode !== 7 && mode !== 8 && mode !== 9 && mode !== 10)) {
|
|
majorVer = 11;
|
|
}
|
|
maxIEVersion = Math.max(majorVer, Ext.Boot.maxIEVersion);
|
|
for (i = 7; i <= maxIEVersion; ++i) {
|
|
prefix = 'isIE' + i;
|
|
if (majorVer <= i) {
|
|
Ext[prefix + 'm'] = true;
|
|
}
|
|
if (majorVer === i) {
|
|
Ext[prefix] = true;
|
|
}
|
|
if (majorVer >= i) {
|
|
Ext[prefix + 'p'] = true;
|
|
}
|
|
}
|
|
}
|
|
if (me.is.Opera && parseInt(majorVer, 10) <= 12) {
|
|
Ext.isOpera12m = true;
|
|
}
|
|
Ext.chromeVersion = Ext.isChrome ? majorVer : 0;
|
|
Ext.firefoxVersion = Ext.isFirefox ? majorVer : 0;
|
|
Ext.ieVersion = Ext.isIE ? majorVer : 0;
|
|
Ext.operaVersion = Ext.isOpera ? majorVer : 0;
|
|
Ext.safariVersion = Ext.isSafari ? majorVer : 0;
|
|
Ext.webKitVersion = Ext.isWebKit ? majorVer : 0;
|
|
this.setFlag(browserName + majorVer, true, publish);
|
|
// Ext.isIE10
|
|
this.setFlag(browserName + browserVersion.getShortVersion());
|
|
}
|
|
for (i in browserNames) {
|
|
if (browserNames.hasOwnProperty(i)) {
|
|
name = browserNames[i];
|
|
this.setFlag(name, browserName === name);
|
|
}
|
|
}
|
|
this.setFlag(name);
|
|
if (engineVersion) {
|
|
this.setFlag(engineName + (engineVersion.getMajor() || ''));
|
|
this.setFlag(engineName + engineVersion.getShortVersion());
|
|
}
|
|
for (i in engineNames) {
|
|
if (engineNames.hasOwnProperty(i)) {
|
|
name = engineNames[i];
|
|
this.setFlag(name, engineName === name, publish);
|
|
}
|
|
}
|
|
this.setFlag('Standalone', !!navigator.standalone);
|
|
this.setFlag('Ripple', !!document.getElementById("tinyhippos-injected") && !Ext.isEmpty(window.top.ripple));
|
|
this.setFlag('WebWorks', !!window.blackberry);
|
|
if (window.PhoneGap !== undefined || window.Cordova !== undefined || window.cordova !== undefined) {
|
|
isWebView = true;
|
|
this.setFlag('PhoneGap');
|
|
this.setFlag('Cordova');
|
|
}
|
|
// Check if running in UIWebView
|
|
if (/(iPhone|iPod|iPad).*AppleWebKit(?!.*Safari)(?!.*FBAN)/i.test(userAgent)) {
|
|
isWebView = true;
|
|
}
|
|
// Flag to check if it we are in the WebView
|
|
this.setFlag('WebView', isWebView);
|
|
/**
|
|
* @property {Boolean}
|
|
* `true` if browser is using strict mode.
|
|
*/
|
|
this.isStrict = Ext.isStrict = document.compatMode === "CSS1Compat";
|
|
/**
|
|
* @property {Boolean}
|
|
* `true` if page is running over SSL.
|
|
*/
|
|
this.isSecure = Ext.isSecure;
|
|
// IE10Quirks, Chrome26Strict, etc.
|
|
this.identity = browserName + majorVer + (this.isStrict ? 'Strict' : 'Quirks');
|
|
};
|
|
Ext.env.Browser.prototype = {
|
|
constructor: Ext.env.Browser,
|
|
engineNames: {
|
|
webkit: 'WebKit',
|
|
gecko: 'Gecko',
|
|
presto: 'Presto',
|
|
trident: 'Trident',
|
|
other: 'Other'
|
|
},
|
|
enginePrefixes: {
|
|
webkit: 'AppleWebKit/',
|
|
gecko: 'Gecko/',
|
|
presto: 'Presto/',
|
|
trident: 'Trident/'
|
|
},
|
|
styleDashPrefixes: {
|
|
WebKit: '-webkit-',
|
|
Gecko: '-moz-',
|
|
Trident: '-ms-',
|
|
Presto: '-o-',
|
|
Other: ''
|
|
},
|
|
stylePrefixes: {
|
|
WebKit: 'Webkit',
|
|
Gecko: 'Moz',
|
|
Trident: 'ms',
|
|
Presto: 'O',
|
|
Other: ''
|
|
},
|
|
propertyPrefixes: {
|
|
WebKit: 'webkit',
|
|
Gecko: 'moz',
|
|
Trident: 'ms',
|
|
Presto: 'o',
|
|
Other: ''
|
|
},
|
|
// scope: Ext.env.Browser.prototype
|
|
/**
|
|
* The full name of the current browser.
|
|
* Possible values are:
|
|
*
|
|
* - IE
|
|
* - Firefox
|
|
* - Safari
|
|
* - Chrome
|
|
* - Opera
|
|
* - Other
|
|
* @type String
|
|
* @readonly
|
|
*/
|
|
name: null,
|
|
/**
|
|
* Refer to {@link Ext.Version}.
|
|
* @type Ext.Version
|
|
* @readonly
|
|
*/
|
|
version: null,
|
|
/**
|
|
* The full name of the current browser's engine.
|
|
* Possible values are:
|
|
*
|
|
* - WebKit
|
|
* - Gecko
|
|
* - Presto
|
|
* - Trident
|
|
* - Other
|
|
* @type String
|
|
* @readonly
|
|
*/
|
|
engineName: null,
|
|
/**
|
|
* Refer to {@link Ext.Version}.
|
|
* @type Ext.Version
|
|
* @readonly
|
|
*/
|
|
engineVersion: null,
|
|
setFlag: function(name, value, publish) {
|
|
if (value === undefined) {
|
|
value = true;
|
|
}
|
|
this.is[name] = value;
|
|
this.is[name.toLowerCase()] = value;
|
|
if (publish) {
|
|
Ext['is' + name] = value;
|
|
}
|
|
return this;
|
|
},
|
|
getStyleDashPrefix: function() {
|
|
return this.styleDashPrefixes[this.engineName];
|
|
},
|
|
getStylePrefix: function() {
|
|
return this.stylePrefixes[this.engineName];
|
|
},
|
|
getVendorProperyName: function(name) {
|
|
var prefix = this.propertyPrefixes[this.engineName];
|
|
if (prefix.length > 0) {
|
|
return prefix + Ext.String.capitalize(name);
|
|
}
|
|
return name;
|
|
},
|
|
getPreferredTranslationMethod: function(config) {
|
|
if (typeof config === 'object' && 'translationMethod' in config && config.translationMethod !== 'auto') {
|
|
return config.translationMethod;
|
|
} else {
|
|
return 'csstransform';
|
|
}
|
|
}
|
|
};
|
|
/**
|
|
* @class Ext.browser
|
|
* @extends Ext.env.Browser
|
|
* @singleton
|
|
* Provides useful information about the current browser.
|
|
*
|
|
* Example:
|
|
*
|
|
* if (Ext.browser.is.IE) {
|
|
* // IE specific code here
|
|
* }
|
|
*
|
|
* if (Ext.browser.is.WebKit) {
|
|
* // WebKit specific code here
|
|
* }
|
|
*
|
|
* console.log("Version " + Ext.browser.version);
|
|
*
|
|
* For a full list of supported values, refer to {@link #is} property/method.
|
|
*
|
|
*/
|
|
(function(userAgent) {
|
|
Ext.browser = new Ext.env.Browser(userAgent, true);
|
|
Ext.userAgent = userAgent.toLowerCase();
|
|
/**
|
|
* @property {String} SSL_SECURE_URL
|
|
* URL to a blank file used by Ext when in secure mode for iframe src and onReady src
|
|
* to prevent the IE insecure content warning (`'about:blank'`, except for IE
|
|
* in secure mode, which is `'javascript:""'`).
|
|
* @member Ext
|
|
*/
|
|
Ext.SSL_SECURE_URL = Ext.isSecure && Ext.isIE ? 'javascript:\'\'' : 'about:blank';
|
|
}(// jshint ignore:line
|
|
Ext.global.navigator.userAgent));
|
|
|
|
/**
|
|
* @class Ext.env.OS
|
|
*
|
|
* Provides information about operating system environment.
|
|
*
|
|
* Should not be manually instantiated unless for unit-testing.
|
|
* Access the global instance stored in {@link Ext.os} instead.
|
|
* @private
|
|
*/
|
|
Ext.env.OS = function(userAgent, platform, browserScope) {
|
|
// @define Ext.env.OS
|
|
// @define Ext.os
|
|
// @require Ext.Version
|
|
// @require Ext.env.Browser
|
|
var me = this,
|
|
names = Ext.Boot.osNames,
|
|
prefixes = Ext.Boot.osPrefixes,
|
|
name,
|
|
version = '',
|
|
is = me.is,
|
|
i, prefix, match, item, match1;
|
|
browserScope = browserScope || Ext.browser;
|
|
for (i in prefixes) {
|
|
if (prefixes.hasOwnProperty(i)) {
|
|
prefix = prefixes[i];
|
|
match = userAgent.match(new RegExp('(?:' + prefix + ')([^\\s;]+)'));
|
|
if (match) {
|
|
name = names[i];
|
|
match1 = match[1];
|
|
// This is here because some HTC android devices show an OSX Snow Leopard userAgent by default.
|
|
// And the Kindle Fire doesn't have any indicator of Android as the OS in its User Agent
|
|
if (match1 && match1 === "HTC_") {
|
|
version = new Ext.Version("2.3");
|
|
} else if (match1 && match1 === "Silk/") {
|
|
version = new Ext.Version("2.3");
|
|
} else {
|
|
version = new Ext.Version(match[match.length - 1]);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (!name) {
|
|
name = names[(userAgent.toLowerCase().match(/mac|win|linux/) || [
|
|
'other'
|
|
])[0]];
|
|
version = new Ext.Version('');
|
|
}
|
|
this.name = name;
|
|
this.version = version;
|
|
// This is added as a workaround for Chrome iPad emulation mode
|
|
// it will report the platform of the machine (MacIntel, Win32, etc) instead
|
|
// of an emulated platform
|
|
if (userAgent.match(/ipad/i)) {
|
|
platform = 'iPad';
|
|
}
|
|
if (platform) {
|
|
this.setFlag(platform.replace(/ simulator$/i, ''));
|
|
}
|
|
this.setFlag(name);
|
|
if (version) {
|
|
this.setFlag(name + (version.getMajor() || ''));
|
|
this.setFlag(name + version.getShortVersion());
|
|
}
|
|
for (i in names) {
|
|
if (names.hasOwnProperty(i)) {
|
|
item = names[i];
|
|
if (!is.hasOwnProperty(name)) {
|
|
this.setFlag(item, (name === item));
|
|
}
|
|
}
|
|
}
|
|
// Detect if the device is the iPhone 5.
|
|
if (this.name === "iOS" && window.screen.height === 568) {
|
|
this.setFlag('iPhone5');
|
|
}
|
|
if (browserScope.is.Safari || browserScope.is.Silk) {
|
|
// Ext.browser.version.shortVersion == 501 is for debugging off device
|
|
if (this.is.Android2 || this.is.Android3 || browserScope.version.shortVersion === 501) {
|
|
browserScope.setFlag("AndroidStock");
|
|
}
|
|
if (this.is.Android4) {
|
|
browserScope.setFlag("AndroidStock");
|
|
browserScope.setFlag("AndroidStock4");
|
|
}
|
|
}
|
|
};
|
|
Ext.env.OS.prototype = {
|
|
constructor: Ext.env.OS,
|
|
/**
|
|
* A "hybrid" property, can be either accessed as a method call, i.e:
|
|
*
|
|
* if (Ext.os.is('Android')) {
|
|
* // ...
|
|
* }
|
|
*
|
|
* or as an object with boolean properties, i.e:
|
|
*
|
|
* if (Ext.os.is.Android) {
|
|
* // ...
|
|
* }
|
|
*
|
|
* Versions can be conveniently checked as well. For example:
|
|
*
|
|
* if (Ext.os.is.Android2) {
|
|
* // Equivalent to (Ext.os.is.Android && Ext.os.version.equals(2))
|
|
* }
|
|
*
|
|
* if (Ext.os.is.iOS32) {
|
|
* // Equivalent to (Ext.os.is.iOS && Ext.os.version.equals(3.2))
|
|
* }
|
|
*
|
|
* Note that only {@link Ext.Version#getMajor major component} and {@link Ext.Version#getShortVersion simplified}
|
|
* value of the version are available via direct property checking. Supported values are:
|
|
*
|
|
* - iOS
|
|
* - iPad
|
|
* - iPhone
|
|
* - iPhone5 (also true for 4in iPods).
|
|
* - iPod
|
|
* - Android
|
|
* - WebOS
|
|
* - BlackBerry
|
|
* - Bada
|
|
* - MacOS
|
|
* - Windows
|
|
* - Linux
|
|
* - Other
|
|
* @member Ext.os
|
|
* @param {String} name The OS name to check.
|
|
* @return {Boolean}
|
|
*/
|
|
is: function(name) {
|
|
return !!this[name];
|
|
},
|
|
/**
|
|
* @property {String} [name=null]
|
|
* @readonly
|
|
* @member Ext.os
|
|
* The full name of the current operating system. Possible values are:
|
|
*
|
|
* - iOS
|
|
* - Android
|
|
* - WebOS
|
|
* - BlackBerry,
|
|
* - MacOS
|
|
* - Windows
|
|
* - Linux
|
|
* - Other
|
|
*/
|
|
name: null,
|
|
/**
|
|
* @property {Ext.Version} [version=null]
|
|
* Refer to {@link Ext.Version}
|
|
* @member Ext.os
|
|
* @readonly
|
|
*/
|
|
version: null,
|
|
setFlag: function(name, value) {
|
|
if (value === undefined) {
|
|
value = true;
|
|
}
|
|
if (this.flags) {
|
|
this.flags[name] = value;
|
|
}
|
|
this.is[name] = value;
|
|
this.is[name.toLowerCase()] = value;
|
|
return this;
|
|
}
|
|
};
|
|
(function() {
|
|
var navigation = Ext.global.navigator,
|
|
userAgent = navigation.userAgent,
|
|
OS = Ext.env.OS,
|
|
is = (Ext.is || (Ext.is = {})),
|
|
osEnv, osName, deviceType;
|
|
OS.prototype.flags = is;
|
|
/**
|
|
* @class Ext.os
|
|
* @extends Ext.env.OS
|
|
* @singleton
|
|
* Provides useful information about the current operating system environment.
|
|
*
|
|
* Example:
|
|
*
|
|
* if (Ext.os.is.Windows) {
|
|
* // Windows specific code here
|
|
* }
|
|
*
|
|
* if (Ext.os.is.iOS) {
|
|
* // iPad, iPod, iPhone, etc.
|
|
* }
|
|
*
|
|
* console.log("Version " + Ext.os.version);
|
|
*
|
|
* For a full list of supported values, refer to the {@link #is} property/method.
|
|
*
|
|
*/
|
|
Ext.os = osEnv = new OS(userAgent, navigation.platform);
|
|
osName = osEnv.name;
|
|
// A couple compatible flavors:
|
|
Ext['is' + osName] = true;
|
|
// e.g., Ext.isWindows
|
|
Ext.isMac = is.Mac = is.MacOS;
|
|
var search = window.location.search.match(/deviceType=(Tablet|Phone)/),
|
|
nativeDeviceType = window.deviceType;
|
|
// Override deviceType by adding a get variable of deviceType. NEEDED FOR DOCS APP.
|
|
// E.g: example/kitchen-sink.html?deviceType=Phone
|
|
if (search && search[1]) {
|
|
deviceType = search[1];
|
|
} else if (nativeDeviceType === 'iPhone') {
|
|
deviceType = 'Phone';
|
|
} else if (nativeDeviceType === 'iPad') {
|
|
deviceType = 'Tablet';
|
|
} else {
|
|
if (!osEnv.is.Android && !osEnv.is.iOS && !osEnv.is.WindowsPhone && /Windows|Linux|MacOS/.test(osName)) {
|
|
deviceType = 'Desktop';
|
|
// always set it to false when you are on a desktop not using Ripple Emulation
|
|
Ext.browser.is.WebView = !!Ext.browser.is.Ripple;
|
|
} else if (osEnv.is.iPad || osEnv.is.RIMTablet || osEnv.is.Android3 || Ext.browser.is.Silk || (osEnv.is.Android && userAgent.search(/mobile/i) === -1)) {
|
|
deviceType = 'Tablet';
|
|
} else {
|
|
deviceType = 'Phone';
|
|
}
|
|
}
|
|
/**
|
|
* @property {String} deviceType
|
|
* The generic type of the current device.
|
|
*
|
|
* Possible values:
|
|
*
|
|
* - Phone
|
|
* - Tablet
|
|
* - Desktop
|
|
*
|
|
* For testing purposes the deviceType can be overridden by adding
|
|
* a deviceType parameter to the URL of the page, like so:
|
|
*
|
|
* http://localhost/mypage.html?deviceType=Tablet
|
|
*
|
|
* @member Ext.os
|
|
*/
|
|
osEnv.setFlag(deviceType, true);
|
|
osEnv.deviceType = deviceType;
|
|
delete OS.prototype.flags;
|
|
}());
|
|
|
|
/**
|
|
* @class Ext.feature
|
|
* @singleton
|
|
*
|
|
* A simple class to verify if a browser feature exists or not on the current device.
|
|
*
|
|
* if (Ext.feature.has.Canvas) {
|
|
* // do some cool things with canvas here
|
|
* }
|
|
*
|
|
* See the {@link #has} property/method for details of the features that can be detected.
|
|
*
|
|
*/
|
|
Ext.feature = {
|
|
// @define Ext.env.Feature
|
|
// @define Ext.feature
|
|
// @define Ext.supports
|
|
// @require Ext.String
|
|
// @require Ext.env.Browser
|
|
// @require Ext.env.OS
|
|
/**
|
|
* @method has
|
|
* @member Ext.feature
|
|
* Verifies if a browser feature exists or not on the current device.
|
|
*
|
|
* A "hybrid" property, can be either accessed as a method call, i.e:
|
|
*
|
|
* if (Ext.feature.has('Canvas')) {
|
|
* // ...
|
|
* }
|
|
*
|
|
* or as an object with boolean properties, i.e:
|
|
*
|
|
* if (Ext.feature.has.Canvas) {
|
|
* // ...
|
|
* }
|
|
*
|
|
* For possible properties/parameter values see `Ext.supports`.
|
|
*
|
|
* @param {String} name The feature name to check.
|
|
* @return {Boolean}
|
|
*/
|
|
has: function(name) {
|
|
return !!this.has[name];
|
|
},
|
|
testElements: {},
|
|
getTestElement: function(tag, createNew) {
|
|
if (tag === undefined) {
|
|
tag = 'div';
|
|
} else if (typeof tag !== 'string') {
|
|
return tag;
|
|
}
|
|
if (createNew) {
|
|
return document.createElement(tag);
|
|
}
|
|
if (!this.testElements[tag]) {
|
|
this.testElements[tag] = document.createElement(tag);
|
|
}
|
|
return this.testElements[tag];
|
|
},
|
|
isStyleSupported: function(name, tag) {
|
|
var elementStyle = this.getTestElement(tag).style,
|
|
cName = Ext.String.capitalize(name);
|
|
if (typeof elementStyle[name] !== 'undefined' || typeof elementStyle[Ext.browser.getStylePrefix(name) + cName] !== 'undefined') {
|
|
return true;
|
|
}
|
|
return false;
|
|
},
|
|
isStyleSupportedWithoutPrefix: function(name, tag) {
|
|
var elementStyle = this.getTestElement(tag).style;
|
|
if (typeof elementStyle[name] !== 'undefined') {
|
|
return true;
|
|
}
|
|
return false;
|
|
},
|
|
isEventSupported: function(name, tag) {
|
|
if (tag === undefined) {
|
|
tag = window;
|
|
}
|
|
var element = this.getTestElement(tag),
|
|
eventName = 'on' + name.toLowerCase(),
|
|
isSupported = (eventName in element);
|
|
if (!isSupported) {
|
|
if (element.setAttribute && element.removeAttribute) {
|
|
element.setAttribute(eventName, '');
|
|
isSupported = typeof element[eventName] === 'function';
|
|
if (typeof element[eventName] !== 'undefined') {
|
|
element[eventName] = undefined;
|
|
}
|
|
element.removeAttribute(eventName);
|
|
}
|
|
}
|
|
return isSupported;
|
|
},
|
|
// This is a local copy of certain logic from Element.getStyle
|
|
// to break a dependancy between the supports mechanism and Element
|
|
// use this instead of element references to check for styling info
|
|
getStyle: function(element, styleName) {
|
|
var view = element.ownerDocument.defaultView,
|
|
style = (view ? view.getComputedStyle(element, null) : element.currentStyle);
|
|
return (style || element.style)[styleName];
|
|
},
|
|
getSupportedPropertyName: function(object, name) {
|
|
var vendorName = Ext.browser.getVendorProperyName(name);
|
|
if (vendorName in object) {
|
|
return vendorName;
|
|
} else if (name in object) {
|
|
return name;
|
|
}
|
|
return null;
|
|
},
|
|
/**
|
|
* Runs feature detection routines and sets the various flags. This is called when
|
|
* the scripts loads (very early) and again at {@link Ext#onReady}. Some detections
|
|
* can be run immediately. Others that require the document body will not run until
|
|
* domready (these have the `ready` flag set).
|
|
*
|
|
* Each test is run only once, so calling this method from an onReady function is safe
|
|
* and ensures that all flags have been set.
|
|
* @private
|
|
*/
|
|
detect: function(isReady) {
|
|
var me = this,
|
|
doc = document,
|
|
toRun = me.toRun || me.tests,
|
|
n = toRun.length,
|
|
div = doc.createElement('div'),
|
|
notRun = [],
|
|
supports = Ext.supports,
|
|
has = me.has,
|
|
name, names, test, vector, value;
|
|
// Only the legacy browser tests use this div so clip this out if we don't need
|
|
// to use it.
|
|
div.innerHTML = '<div style="height:30px;width:50px;">' + '<div style="height:20px;width:20px;"></div>' + '</div>' + '<div style="width: 200px; height: 200px; position: relative; padding: 5px;">' + '<div style="position: absolute; top: 0; left: 0; width: 100%; height: 100%;"></div>' + '</div>' + '<div style="position: absolute; left: 10%; top: 10%;"></div>' + '<div style="float:left; background-color:transparent;"></div>';
|
|
if (isReady) {
|
|
doc.body.appendChild(div);
|
|
}
|
|
vector = me.preDetected[Ext.browser.identity] || [];
|
|
while (n--) {
|
|
test = toRun[n];
|
|
value = vector[n];
|
|
name = test.name;
|
|
names = test.names;
|
|
if (value === undefined) {
|
|
if (!isReady && test.ready) {
|
|
// test requires domready state
|
|
notRun.push(test);
|
|
|
|
continue;
|
|
}
|
|
value = test.fn.call(me, doc, div);
|
|
}
|
|
// Store test results on Ext.supports and Ext.feature.has
|
|
if (name) {
|
|
supports[name] = has[name] = value;
|
|
} else if (names) {
|
|
while (names.length) {
|
|
name = names.pop();
|
|
supports[name] = has[name] = value;
|
|
}
|
|
}
|
|
}
|
|
if (isReady) {
|
|
doc.body.removeChild(div);
|
|
}
|
|
me.toRun = notRun;
|
|
},
|
|
//</debug>
|
|
report: function() {
|
|
var values = [],
|
|
len = this.tests.length,
|
|
i;
|
|
for (i = 0; i < len; ++i) {
|
|
values.push(this.has[this.tests[i].name] ? 1 : 0);
|
|
}
|
|
Ext.log(Ext.browser.identity + ': [' + values.join(',') + ']');
|
|
},
|
|
//</debug>
|
|
preDetected: {},
|
|
// TODO
|
|
/**
|
|
* @class Ext.supports
|
|
*
|
|
* Contains information about features supported in the current environment as well
|
|
* as bugs detected.
|
|
*
|
|
* @singleton
|
|
*/
|
|
tests: [
|
|
{
|
|
/**
|
|
* @property CloneNodeCopiesExpando `true` if the native DOM cloneNode method copies
|
|
* expando properties to the newly cloned node.
|
|
*
|
|
* This property is available at application boot time, before document ready.
|
|
* @type {Boolean}
|
|
*/
|
|
name: 'CloneNodeCopiesExpando',
|
|
fn: function() {
|
|
var el = document.createElement('div');
|
|
el.expandoProp = {};
|
|
return el.cloneNode().expandoProp === el.expandoProp;
|
|
}
|
|
},
|
|
{
|
|
/**
|
|
* @property CSSPointerEvents `true` if document environment supports the CSS3
|
|
* pointer-events style.
|
|
*
|
|
* This property is available at application boot time, before document ready.
|
|
* @type {Boolean}
|
|
*/
|
|
name: 'CSSPointerEvents',
|
|
fn: function(doc) {
|
|
return 'pointerEvents' in doc.documentElement.style;
|
|
}
|
|
},
|
|
{
|
|
/**
|
|
* @property CSS3BoxShadow `true` if document environment supports the CSS3
|
|
* box-shadow style.
|
|
*
|
|
* This property is available at application boot time, before document ready.
|
|
* @type {Boolean}
|
|
*/
|
|
name: 'CSS3BoxShadow',
|
|
fn: function(doc) {
|
|
return 'boxShadow' in doc.documentElement.style || 'WebkitBoxShadow' in doc.documentElement.style || 'MozBoxShadow' in doc.documentElement.style;
|
|
}
|
|
},
|
|
{
|
|
name: 'CSS3NegationSelector',
|
|
fn: function(doc) {
|
|
try {
|
|
doc.querySelectorAll("foo:not(bar)");
|
|
} catch (e) {
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
},
|
|
{
|
|
/**
|
|
* @property ClassList `true` if document environment supports the HTML5
|
|
* classList API.
|
|
*
|
|
* This property is available at application boot time, before document ready.
|
|
* @type {Boolean}
|
|
*/
|
|
name: 'ClassList',
|
|
fn: function(doc) {
|
|
return !!doc.documentElement.classList;
|
|
}
|
|
},
|
|
{
|
|
/**
|
|
* @property Canvas `true` if the device supports Canvas.
|
|
*
|
|
* This property is available at application boot time, before document ready.
|
|
* @type {Boolean}
|
|
*/
|
|
name: 'Canvas',
|
|
fn: function() {
|
|
var element = this.getTestElement('canvas');
|
|
return !!(element && element.getContext && element.getContext('2d'));
|
|
}
|
|
},
|
|
{
|
|
/**
|
|
* @property Svg `true` if the device supports SVG.
|
|
*
|
|
* This property is available at application boot time, before document ready.
|
|
* @type {Boolean}
|
|
*/
|
|
name: 'Svg',
|
|
fn: function(doc) {
|
|
return !!(doc.createElementNS && !!doc.createElementNS("http:/" + "/www.w3.org/2000/svg", "svg").createSVGRect);
|
|
}
|
|
},
|
|
{
|
|
/**
|
|
* @property Vml `true` if the device supports VML.
|
|
* @type {Boolean}
|
|
*
|
|
* This property is available at application boot time, before document ready.
|
|
*/
|
|
name: 'Vml',
|
|
fn: function() {
|
|
var element = this.getTestElement(),
|
|
ret = false;
|
|
element.innerHTML = "<!--[if vml]><br><![endif]-->";
|
|
ret = (element.childNodes.length === 1);
|
|
element.innerHTML = "";
|
|
return ret;
|
|
}
|
|
},
|
|
{
|
|
/**
|
|
* @property Touch `true` if the browser supports touch input.
|
|
*
|
|
* This property is available at application boot time, before document ready.
|
|
* @type {Boolean}
|
|
*/
|
|
name: 'Touch',
|
|
fn: function() {
|
|
// IE10 uses a vendor-prefixed maxTouchPoints property
|
|
var maxTouchPoints = navigator.msMaxTouchPoints || navigator.maxTouchPoints;
|
|
// if the browser has touch events we can be reasonably sure the device has
|
|
// a touch screen
|
|
// browsers that use pointer event have maxTouchPoints > 1 if the
|
|
// device supports touch input
|
|
// Chrome Desktop < 39 reports maxTouchPoints === 1 even if there is no
|
|
// touch support on the device
|
|
// http://www.w3.org/TR/pointerevents/#widl-Navigator-maxTouchPoints
|
|
// Chrome Desktop > 39 properly reports maxTouchPoints === 0 and
|
|
// Chrome Desktop Device Emulation mode reports maxTouchPoints === 1
|
|
if (Ext.browser.is.Chrome && Ext.browser.version.isLessThanOrEqual(39)) {
|
|
return (Ext.supports.TouchEvents && maxTouchPoints !== 1) || maxTouchPoints > 1;
|
|
} else {
|
|
return Ext.supports.TouchEvents || maxTouchPoints > 0;
|
|
}
|
|
}
|
|
},
|
|
{
|
|
/**
|
|
* @property TouchEvents `true` if the device supports touch events (`touchstart`,
|
|
* `touchmove`, `touchend`).
|
|
*
|
|
* This property is available at application boot time, before document ready.
|
|
* @type {Boolean}
|
|
*/
|
|
name: 'TouchEvents',
|
|
fn: function() {
|
|
return this.isEventSupported('touchend');
|
|
}
|
|
},
|
|
{
|
|
name: 'PointerEvents',
|
|
fn: function() {
|
|
return navigator.pointerEnabled;
|
|
}
|
|
},
|
|
{
|
|
name: 'MSPointerEvents',
|
|
fn: function() {
|
|
return navigator.msPointerEnabled;
|
|
}
|
|
},
|
|
{
|
|
/**
|
|
* @property Orientation `true` if the device supports different orientations.
|
|
* @type {Boolean}
|
|
*
|
|
* This property is available at application boot time, before document ready.
|
|
*/
|
|
name: 'Orientation',
|
|
fn: function() {
|
|
return ('orientation' in window) && this.isEventSupported('orientationchange');
|
|
}
|
|
},
|
|
{
|
|
/**
|
|
* @property OrientationChange `true` if the device supports the `orientationchange`
|
|
* event.
|
|
*
|
|
* This property is available at application boot time, before document ready.
|
|
* @type {Boolean}
|
|
*/
|
|
name: 'OrientationChange',
|
|
fn: function() {
|
|
return this.isEventSupported('orientationchange');
|
|
}
|
|
},
|
|
{
|
|
/**
|
|
* @property DeviceMotion `true` if the device supports device motion (acceleration
|
|
* and rotation rate).
|
|
*
|
|
* This property is available at application boot time, before document ready.
|
|
* @type {Boolean}
|
|
*/
|
|
name: 'DeviceMotion',
|
|
fn: function() {
|
|
return this.isEventSupported('devicemotion');
|
|
}
|
|
},
|
|
{
|
|
/**
|
|
* @property Geolocation `true` if the device supports GeoLocation.
|
|
* @type {Boolean}
|
|
*
|
|
* This property is available at application boot time, before document ready.
|
|
*/
|
|
/**
|
|
* @property GeoLocation `true` if the device supports Geo-location.
|
|
* @type {Boolean}
|
|
* @deprecated Use `Geolocation` instead (notice the lower-casing of 'L').
|
|
*/
|
|
names: [
|
|
'Geolocation',
|
|
'GeoLocation'
|
|
],
|
|
fn: function() {
|
|
return 'geolocation' in window.navigator;
|
|
}
|
|
},
|
|
{
|
|
name: 'SqlDatabase',
|
|
fn: function() {
|
|
return 'openDatabase' in window;
|
|
}
|
|
},
|
|
{
|
|
name: 'WebSockets',
|
|
fn: function() {
|
|
return 'WebSocket' in window;
|
|
}
|
|
},
|
|
{
|
|
/**
|
|
* @property Range `true` if browser support document.createRange native method.
|
|
* See https://developer.mozilla.org/en/DOM/range.
|
|
*
|
|
* This property is available at application boot time, before document ready.
|
|
* @type {Boolean}
|
|
*/
|
|
name: 'Range',
|
|
fn: function() {
|
|
return !!document.createRange;
|
|
}
|
|
},
|
|
{
|
|
/**
|
|
* @property CreateContextualFragment `true` if browser support CreateContextualFragment
|
|
* range native methods.
|
|
* See https://developer.mozilla.org/en/DOM/range.createContextualFragment
|
|
*
|
|
* This property is available at application boot time, before document ready.
|
|
* @type {Boolean}
|
|
*/
|
|
name: 'CreateContextualFragment',
|
|
fn: function() {
|
|
var range = !!document.createRange ? document.createRange() : false;
|
|
return range && !!range.createContextualFragment;
|
|
}
|
|
},
|
|
{
|
|
/**
|
|
* @property History `true` if the device supports HTML5 history. See
|
|
* https://developer.mozilla.org/en/DOM/Manipulating_the_browser_history
|
|
*
|
|
* This property is available at application boot time, before document ready.
|
|
* @type {Boolean}
|
|
*/
|
|
name: 'History',
|
|
fn: function() {
|
|
return ('history' in window && 'pushState' in window.history);
|
|
}
|
|
},
|
|
{
|
|
/**
|
|
* @property Css3DTransforms `true` if the device supports CSS3DTransform.
|
|
* @type {Boolean}
|
|
*
|
|
* This property is available at application boot time, before document ready.
|
|
*/
|
|
name: 'Css3dTransforms',
|
|
fn: function() {
|
|
// See https://sencha.jira.com/browse/TOUCH-1544
|
|
return this.has('CssTransforms') && this.isStyleSupported('perspective');
|
|
}
|
|
},
|
|
// TODO - double check vs Ext JS flavor:
|
|
//return (typeof WebKitCSSMatrix != 'undefined' && new WebKitCSSMatrix().hasOwnProperty('m41'));
|
|
{
|
|
// Important that this goes after Css3dTransforms, since tests are run in reverse order
|
|
name: 'CssTransforms',
|
|
fn: function() {
|
|
return this.isStyleSupported('transform');
|
|
}
|
|
},
|
|
{
|
|
name: 'CssTransformNoPrefix',
|
|
fn: function() {
|
|
return this.isStyleSupportedWithoutPrefix('transform');
|
|
}
|
|
},
|
|
{
|
|
name: 'CssAnimations',
|
|
fn: function() {
|
|
return this.isStyleSupported('animationName');
|
|
}
|
|
},
|
|
{
|
|
/**
|
|
* @property Transitions `true` if the device supports CSS3 Transitions.
|
|
*
|
|
* This property is available at application boot time, before document ready.
|
|
* @type {Boolean}
|
|
*/
|
|
names: [
|
|
'CssTransitions',
|
|
'Transitions'
|
|
],
|
|
fn: function() {
|
|
return this.isStyleSupported('transitionProperty');
|
|
}
|
|
},
|
|
{
|
|
/**
|
|
* @property Audio `true` if the device supports the HTML5 `audio` tag.
|
|
*
|
|
* This property is available at application boot time, before document ready.
|
|
* @type {Boolean}
|
|
*/
|
|
/**
|
|
* @property AudioTag `true` if the device supports the HTML5 `audio` tag.
|
|
* @type {Boolean}
|
|
* @deprecated Use `Audio` instead.
|
|
*/
|
|
names: [
|
|
'Audio',
|
|
'AudioTag'
|
|
],
|
|
fn: function() {
|
|
return !!this.getTestElement('audio').canPlayType;
|
|
}
|
|
},
|
|
{
|
|
/**
|
|
* @property Video `true` if the device supports the HTML5 `video` tag.
|
|
*
|
|
* This property is available at application boot time, before document ready.
|
|
* @type {Boolean}
|
|
*/
|
|
name: 'Video',
|
|
fn: function() {
|
|
return !!this.getTestElement('video').canPlayType;
|
|
}
|
|
},
|
|
{
|
|
/**
|
|
* @property LocalStorage `true` if localStorage is supported.
|
|
*
|
|
* This property is available at application boot time, before document ready.
|
|
* @type {Boolean}
|
|
*/
|
|
name: 'LocalStorage',
|
|
fn: function() {
|
|
try {
|
|
// IE10/Win8 throws "Access Denied" accessing window.localStorage, so
|
|
// this test needs to have a try/catch
|
|
if ('localStorage' in window && window['localStorage'] !== null) {
|
|
// jshint ignore:line
|
|
//this should throw an error in private browsing mode in iOS as well
|
|
localStorage.setItem('sencha-localstorage-test', 'test success');
|
|
//clean up if setItem worked
|
|
localStorage.removeItem('sencha-localstorage-test');
|
|
return true;
|
|
}
|
|
} catch (e) {}
|
|
// ignore
|
|
return false;
|
|
}
|
|
},
|
|
{
|
|
/**
|
|
* @property XHR2 `true` if the browser supports XMLHttpRequest
|
|
*
|
|
* This property is available at application boot time, before document ready.
|
|
* @type {Boolean}
|
|
*/
|
|
name: 'XHR2',
|
|
fn: function() {
|
|
return window.ProgressEvent && window.FormData && window.XMLHttpRequest && ('withCredentials' in new XMLHttpRequest());
|
|
}
|
|
},
|
|
{
|
|
/**
|
|
* @property XHRUploadProgress `true` if the browser supports XMLHttpRequest
|
|
* upload progress info
|
|
*
|
|
* This property is available at application boot time, before document ready.
|
|
* @type {Boolean}
|
|
*/
|
|
name: 'XHRUploadProgress',
|
|
fn: function() {
|
|
if (window.XMLHttpRequest && !Ext.browser.is.AndroidStock) {
|
|
var xhr = new XMLHttpRequest();
|
|
return xhr && ('upload' in xhr) && ('onprogress' in xhr.upload);
|
|
}
|
|
return false;
|
|
}
|
|
},
|
|
{
|
|
/**
|
|
* @property NumericInputPlaceHolder `true` if the browser supports placeholders
|
|
* on numeric input fields
|
|
*
|
|
* This property is available at application boot time, before document ready.
|
|
* @type {Boolean}
|
|
*/
|
|
name: 'NumericInputPlaceHolder',
|
|
fn: function() {
|
|
return !(Ext.browser.is.AndroidStock4 && Ext.os.version.getMinor() < 2);
|
|
}
|
|
},
|
|
/**
|
|
* @property {String} matchesSelector
|
|
* The method name which matches an element against a selector if implemented in this environment.
|
|
*
|
|
* This property is available at application boot time, before document ready.
|
|
*/
|
|
{
|
|
name: 'matchesSelector',
|
|
fn: function() {
|
|
var el = document.documentElement,
|
|
w3 = 'matches',
|
|
wk = 'webkitMatchesSelector',
|
|
ms = 'msMatchesSelector',
|
|
mz = 'mozMatchesSelector';
|
|
return el[w3] ? w3 : el[wk] ? wk : el[ms] ? ms : el[mz] ? mz : null;
|
|
}
|
|
},
|
|
/**
|
|
* @property RightMargin `true` if the device supports right margin.
|
|
* See https://bugs.webkit.org/show_bug.cgi?id=13343 for why this is needed.
|
|
*
|
|
* This property is *NOT* available at application boot time. Only after the document ready event.
|
|
* @type {Boolean}
|
|
*/
|
|
{
|
|
name: 'RightMargin',
|
|
ready: true,
|
|
fn: function(doc, div) {
|
|
var view = doc.defaultView;
|
|
return !(view && view.getComputedStyle(div.firstChild.firstChild, null).marginRight !== '0px');
|
|
}
|
|
},
|
|
/**
|
|
* @property DisplayChangeInputSelectionBug `true` if INPUT elements lose their
|
|
* selection when their display style is changed. Essentially, if a text input
|
|
* has focus and its display style is changed, the I-beam disappears.
|
|
*
|
|
* This bug is encountered due to the work around in place for the {@link #RightMargin}
|
|
* bug. This has been observed in Safari 4.0.4 and older, and appears to be fixed
|
|
* in Safari 5. It's not clear if Safari 4.1 has the bug, but it has the same WebKit
|
|
* version number as Safari 5 (according to http://unixpapa.com/js/gecko.html).
|
|
*
|
|
* This property is available at application boot time, before document ready.
|
|
*/
|
|
{
|
|
name: 'DisplayChangeInputSelectionBug',
|
|
fn: function() {
|
|
var webKitVersion = Ext.webKitVersion;
|
|
// WebKit but older than Safari 5 or Chrome 6:
|
|
return 0 < webKitVersion && webKitVersion < 533;
|
|
}
|
|
},
|
|
/**
|
|
* @property DisplayChangeTextAreaSelectionBug `true` if TEXTAREA elements lose their
|
|
* selection when their display style is changed. Essentially, if a text area has
|
|
* focus and its display style is changed, the I-beam disappears.
|
|
*
|
|
* This bug is encountered due to the work around in place for the {@link #RightMargin}
|
|
* bug. This has been observed in Chrome 10 and Safari 5 and older, and appears to
|
|
* be fixed in Chrome 11.
|
|
*
|
|
* This property is available at application boot time, before document ready.
|
|
*/
|
|
{
|
|
name: 'DisplayChangeTextAreaSelectionBug',
|
|
fn: function() {
|
|
var webKitVersion = Ext.webKitVersion;
|
|
/*
|
|
Has bug w/textarea:
|
|
|
|
(Chrome) Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_7; en-US)
|
|
AppleWebKit/534.16 (KHTML, like Gecko) Chrome/10.0.648.127
|
|
Safari/534.16
|
|
(Safari) Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_7; en-us)
|
|
AppleWebKit/533.21.1 (KHTML, like Gecko) Version/5.0.5
|
|
Safari/533.21.1
|
|
|
|
No bug:
|
|
|
|
(Chrome) Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_7)
|
|
AppleWebKit/534.24 (KHTML, like Gecko) Chrome/11.0.696.57
|
|
Safari/534.24
|
|
*/
|
|
return 0 < webKitVersion && webKitVersion < 534.24;
|
|
}
|
|
},
|
|
/**
|
|
* @property TransparentColor `true` if the device supports transparent color.
|
|
* @type {Boolean}
|
|
*
|
|
* This property is *NOT* available at application boot time. Only after the document ready event.
|
|
*/
|
|
{
|
|
name: 'TransparentColor',
|
|
ready: true,
|
|
fn: function(doc, div, view) {
|
|
view = doc.defaultView;
|
|
return !(view && view.getComputedStyle(div.lastChild, null).backgroundColor !== 'transparent');
|
|
}
|
|
},
|
|
/**
|
|
* @property ComputedStyle `true` if the browser supports document.defaultView.getComputedStyle().
|
|
* @type {Boolean}
|
|
*
|
|
* This property is *NOT* available at application boot time. Only after the document ready event.
|
|
*/
|
|
{
|
|
name: 'ComputedStyle',
|
|
ready: true,
|
|
fn: function(doc, div, view) {
|
|
view = doc.defaultView;
|
|
return view && view.getComputedStyle;
|
|
}
|
|
},
|
|
/**
|
|
* @property Float `true` if the device supports CSS float.
|
|
* @type {Boolean}
|
|
*
|
|
* This property is available at application boot time, before document ready.
|
|
*/
|
|
{
|
|
name: 'Float',
|
|
fn: function(doc) {
|
|
return 'cssFloat' in doc.documentElement.style;
|
|
}
|
|
},
|
|
/**
|
|
* @property CSS3BorderRadius `true` if the device supports CSS3 border radius.
|
|
* @type {Boolean}
|
|
*
|
|
* This property is *NOT* available at application boot time. Only after the document ready event.
|
|
*/
|
|
{
|
|
name: 'CSS3BorderRadius',
|
|
ready: true,
|
|
fn: function(doc) {
|
|
var domPrefixes = [
|
|
'borderRadius',
|
|
'BorderRadius',
|
|
'MozBorderRadius',
|
|
'WebkitBorderRadius',
|
|
'OBorderRadius',
|
|
'KhtmlBorderRadius'
|
|
],
|
|
pass = false,
|
|
i;
|
|
for (i = 0; i < domPrefixes.length; i++) {
|
|
if (doc.documentElement.style[domPrefixes[i]] !== undefined) {
|
|
pass = true;
|
|
}
|
|
}
|
|
return pass && !Ext.isIE9;
|
|
}
|
|
},
|
|
/**
|
|
* @property CSS3LinearGradient `true` if the device supports CSS3 linear gradients.
|
|
* @type {Boolean}
|
|
*
|
|
* This property is available at application boot time, before document ready.
|
|
*/
|
|
{
|
|
name: 'CSS3LinearGradient',
|
|
fn: function(doc, div) {
|
|
var property = 'background-image:',
|
|
webkit = '-webkit-gradient(linear, left top, right bottom, from(black), to(white))',
|
|
w3c = 'linear-gradient(left top, black, white)',
|
|
moz = '-moz-' + w3c,
|
|
ms = '-ms-' + w3c,
|
|
opera = '-o-' + w3c,
|
|
options = [
|
|
property + webkit,
|
|
property + w3c,
|
|
property + moz,
|
|
property + ms,
|
|
property + opera
|
|
];
|
|
div.style.cssText = options.join(';');
|
|
return (("" + div.style.backgroundImage).indexOf('gradient') !== -1) && !Ext.isIE9;
|
|
}
|
|
},
|
|
/**
|
|
* @property MouseEnterLeave `true` if the browser supports mouseenter and mouseleave events
|
|
* @type {Boolean}
|
|
*
|
|
* This property is available at application boot time, before document ready.
|
|
*/
|
|
{
|
|
name: 'MouseEnterLeave',
|
|
fn: function(doc) {
|
|
return ('onmouseenter' in doc.documentElement && 'onmouseleave' in doc.documentElement);
|
|
}
|
|
},
|
|
/**
|
|
* @property MouseWheel `true` if the browser supports the mousewheel event
|
|
* @type {Boolean}
|
|
*
|
|
* This property is available at application boot time, before document ready.
|
|
*/
|
|
{
|
|
name: 'MouseWheel',
|
|
fn: function(doc) {
|
|
return ('onmousewheel' in doc.documentElement);
|
|
}
|
|
},
|
|
/**
|
|
* @property Opacity `true` if the browser supports normal css opacity
|
|
* @type {Boolean}
|
|
*
|
|
* This property is available at application boot time, before document ready.
|
|
*/
|
|
{
|
|
name: 'Opacity',
|
|
fn: function(doc, div) {
|
|
// Not a strict equal comparison in case opacity can be converted to a number.
|
|
if (Ext.isIE8) {
|
|
return false;
|
|
}
|
|
div.firstChild.style.cssText = 'opacity:0.73';
|
|
return div.firstChild.style.opacity == '0.73';
|
|
}
|
|
},
|
|
// jshint ignore:line
|
|
/**
|
|
* @property Placeholder `true` if the browser supports the HTML5 placeholder attribute on inputs
|
|
* @type {Boolean}
|
|
*
|
|
* This property is available at application boot time, before document ready.
|
|
*/
|
|
{
|
|
name: 'Placeholder',
|
|
fn: function(doc) {
|
|
return 'placeholder' in doc.createElement('input');
|
|
}
|
|
},
|
|
/**
|
|
* @property Direct2DBug `true` if when asking for an element's dimension via offsetWidth or offsetHeight,
|
|
* getBoundingClientRect, etc. the browser returns the subpixel width rounded to the nearest pixel.
|
|
*
|
|
* This property is available at application boot time, before document ready.
|
|
* @type {Boolean}
|
|
*/
|
|
{
|
|
name: 'Direct2DBug',
|
|
fn: function(doc) {
|
|
return Ext.isString(doc.documentElement.style.msTransformOrigin) && Ext.isIE9m;
|
|
}
|
|
},
|
|
/**
|
|
* @property BoundingClientRect `true` if the browser supports the getBoundingClientRect method on elements
|
|
* @type {Boolean}
|
|
*
|
|
* This property is available at application boot time, before document ready.
|
|
*/
|
|
{
|
|
name: 'BoundingClientRect',
|
|
fn: function(doc) {
|
|
return 'getBoundingClientRect' in doc.documentElement;
|
|
}
|
|
},
|
|
/**
|
|
* @property RotatedBoundingClientRect `true` if the BoundingClientRect is
|
|
* rotated when the element is rotated using a CSS transform.
|
|
* @type {Boolean}
|
|
*
|
|
* This property is *NOT* available at application boot time. Only after the document ready event.
|
|
*/
|
|
{
|
|
name: 'RotatedBoundingClientRect',
|
|
ready: true,
|
|
fn: function(doc) {
|
|
var body = doc.body,
|
|
supports = false,
|
|
el = doc.createElement('div'),
|
|
style = el.style;
|
|
if (el.getBoundingClientRect) {
|
|
// If the document body already has child nodes (text nodes etc) we can end
|
|
// up with subpixel rounding errors in IE11 when measuring the height.
|
|
// Absolute positioning prevents this.
|
|
style.position = 'absolute';
|
|
style.top = "0";
|
|
style.WebkitTransform = style.MozTransform = style.msTransform = style.OTransform = style.transform = 'rotate(90deg)';
|
|
style.width = '100px';
|
|
style.height = '30px';
|
|
body.appendChild(el);
|
|
supports = el.getBoundingClientRect().height !== 100;
|
|
body.removeChild(el);
|
|
}
|
|
return supports;
|
|
}
|
|
},
|
|
/**
|
|
* @property ChildContentClearedWhenSettingInnerHTML `true` if created child elements
|
|
* lose their innerHTML when modifying the innerHTML of the parent element.
|
|
* @type {Boolean}
|
|
*
|
|
* This property is *NOT* available at application boot time. Only after the document ready event.
|
|
*/
|
|
{
|
|
name: 'ChildContentClearedWhenSettingInnerHTML',
|
|
ready: true,
|
|
fn: function() {
|
|
var el = this.getTestElement(),
|
|
child;
|
|
el.innerHTML = '<div>a</div>';
|
|
child = el.firstChild;
|
|
el.innerHTML = '<div>b</div>';
|
|
return child.innerHTML !== 'a';
|
|
}
|
|
},
|
|
{
|
|
name: 'IncludePaddingInWidthCalculation',
|
|
ready: true,
|
|
fn: function(doc, div) {
|
|
return div.childNodes[1].firstChild.offsetWidth === 210;
|
|
}
|
|
},
|
|
{
|
|
name: 'IncludePaddingInHeightCalculation',
|
|
ready: true,
|
|
fn: function(doc, div) {
|
|
return div.childNodes[1].firstChild.offsetHeight === 210;
|
|
}
|
|
},
|
|
/**
|
|
* @property TextAreaMaxLength `true` if the browser supports maxlength on textareas.
|
|
* @type {Boolean}
|
|
*
|
|
* This property is available at application boot time, before document ready.
|
|
*/
|
|
{
|
|
name: 'TextAreaMaxLength',
|
|
fn: function(doc) {
|
|
return ('maxlength' in doc.createElement('textarea'));
|
|
}
|
|
},
|
|
/**
|
|
* @property GetPositionPercentage `true` if the browser will return the left/top/right/bottom
|
|
* position as a percentage when explicitly set as a percentage value.
|
|
*
|
|
* This property is *NOT* available at application boot time. Only after the document ready event.
|
|
* @type {Boolean}
|
|
*/
|
|
// Related bug: https://bugzilla.mozilla.org/show_bug.cgi?id=707691#c7
|
|
{
|
|
name: 'GetPositionPercentage',
|
|
ready: true,
|
|
fn: function(doc, div) {
|
|
return Ext.feature.getStyle(div.childNodes[2], 'left') === '10%';
|
|
}
|
|
},
|
|
/**
|
|
* @property {Boolean} PercentageHeightOverflowBug
|
|
* In some browsers (IE quirks, IE6, IE7, IE9, chrome, safari and opera at the time
|
|
* of this writing) a percentage-height element ignores the horizontal scrollbar
|
|
* of its parent element. This method returns true if the browser is affected
|
|
* by this bug.
|
|
*
|
|
* This property is *NOT* available at application boot time. Only after the document ready event.
|
|
* @private
|
|
*/
|
|
{
|
|
name: 'PercentageHeightOverflowBug',
|
|
ready: true,
|
|
fn: function(doc) {
|
|
var hasBug = false,
|
|
style, el;
|
|
if (Ext.getScrollbarSize().height) {
|
|
// must have space-consuming scrollbars for bug to be possible
|
|
el = this.getTestElement();
|
|
style = el.style;
|
|
style.height = '50px';
|
|
style.width = '50px';
|
|
style.overflow = 'auto';
|
|
style.position = 'absolute';
|
|
el.innerHTML = [
|
|
'<div style="display:table;height:100%;">',
|
|
// The element that causes the horizontal overflow must be
|
|
// a child of the element with the 100% height, otherwise
|
|
// horizontal overflow is not triggered in webkit quirks mode
|
|
'<div style="width:51px;"></div>',
|
|
'</div>'
|
|
].join('');
|
|
doc.body.appendChild(el);
|
|
if (el.firstChild.offsetHeight === 50) {
|
|
hasBug = true;
|
|
}
|
|
doc.body.removeChild(el);
|
|
}
|
|
return hasBug;
|
|
}
|
|
},
|
|
/**
|
|
* @property {Boolean} xOriginBug
|
|
* In Chrome 24.0, an RTL element which has vertical overflow positions its right X origin incorrectly.
|
|
* It skips a non-existent scrollbar which has been moved to the left edge due to the RTL setting.
|
|
*
|
|
* http://code.google.com/p/chromium/issues/detail?id=174656
|
|
*
|
|
* This method returns true if the browser is affected by this bug.
|
|
*
|
|
* This property is *NOT* available at application boot time. Only after the document ready event.
|
|
* @private
|
|
*/
|
|
{
|
|
name: 'xOriginBug',
|
|
ready: true,
|
|
fn: function(doc, div) {
|
|
div.innerHTML = '<div id="b1" style="height:100px;width:100px;direction:rtl;position:relative;overflow:scroll">' + '<div id="b2" style="position:relative;width:100%;height:20px;"></div>' + '<div id="b3" style="position:absolute;width:20px;height:20px;top:0px;right:0px"></div>' + '</div>';
|
|
var outerBox = document.getElementById('b1').getBoundingClientRect(),
|
|
b2 = document.getElementById('b2').getBoundingClientRect(),
|
|
b3 = document.getElementById('b3').getBoundingClientRect();
|
|
return (b2.left !== outerBox.left && b3.right !== outerBox.right);
|
|
}
|
|
},
|
|
/**
|
|
* @property {Boolean} ScrollWidthInlinePaddingBug
|
|
* In some browsers the right padding of an overflowing element is not accounted
|
|
* for in its scrollWidth. The result can vary depending on whether or not
|
|
* The element contains block-level children. This method tests the effect
|
|
* of padding on scrollWidth when there are no block-level children inside the
|
|
* overflowing element.
|
|
*
|
|
* This method returns true if the browser is affected by this bug.
|
|
*
|
|
* This property is *NOT* available at application boot time. Only after the document ready event.
|
|
*/
|
|
{
|
|
name: 'ScrollWidthInlinePaddingBug',
|
|
ready: true,
|
|
fn: function(doc) {
|
|
var hasBug = false,
|
|
style, el;
|
|
el = doc.createElement('div');
|
|
style = el.style;
|
|
style.height = '50px';
|
|
style.width = '50px';
|
|
style.padding = '10px';
|
|
style.overflow = 'hidden';
|
|
style.position = 'absolute';
|
|
el.innerHTML = '<span style="display:inline-block;zoom:1;height:60px;width:60px;"></span>';
|
|
doc.body.appendChild(el);
|
|
if (el.scrollWidth === 70) {
|
|
hasBug = true;
|
|
}
|
|
doc.body.removeChild(el);
|
|
return hasBug;
|
|
}
|
|
},
|
|
/**
|
|
* @property {Boolean} rtlVertScrollbarOnRight
|
|
* Safari, in RTL mode keeps the scrollbar at the right side.
|
|
* This means that when two elements must keep their left/right positions synched, if one has no vert
|
|
* scrollbar, it must have some extra padding.
|
|
* See https://sencha.jira.com/browse/EXTJSIV-11245
|
|
*
|
|
* This property is *NOT* available at application boot time. Only after the document ready event.
|
|
* @private
|
|
*/
|
|
{
|
|
name: 'rtlVertScrollbarOnRight',
|
|
ready: true,
|
|
fn: function(doc, div) {
|
|
div.innerHTML = '<div style="height:100px;width:100px;direction:rtl;overflow:scroll">' + '<div style="width:20px;height:200px;"></div>' + '</div>';
|
|
var outerBox = div.firstChild,
|
|
innerBox = outerBox.firstChild;
|
|
return (innerBox.offsetLeft + innerBox.offsetWidth !== outerBox.offsetLeft + outerBox.offsetWidth);
|
|
}
|
|
},
|
|
/**
|
|
* @property {Boolean} rtlVertScrollbarOverflowBug
|
|
* In Chrome, in RTL mode, horizontal overflow only into the vertical scrollbar does NOT trigger horizontal scrollability.
|
|
* See https://code.google.com/p/chromium/issues/detail?id=179332
|
|
* We need to detect this for when a grid header needs to have exactly the same horizontal scrolling range as its table view.
|
|
* See {@link Ext.grid.ColumnLayout#publishInnerCtSize}
|
|
* TODO: Remove this when all supported Chrome versions are fixed.
|
|
*
|
|
* This property is *NOT* available at application boot time. Only after the document ready event.
|
|
* @private
|
|
*/
|
|
{
|
|
name: 'rtlVertScrollbarOverflowBug',
|
|
ready: true,
|
|
fn: function(doc, div) {
|
|
div.innerHTML = '<div style="height:100px;width:100px;direction:rtl;overflow:auto">' + '<div style="width:95px;height:200px;"></div>' + '</div>';
|
|
// If the bug is present, the 95 pixel wide inner div, encroaches into the
|
|
// vertical scrollbar, but does NOT trigger horizontal overflow, so the clientHeight remains
|
|
// equal to the offset height.
|
|
var outerBox = div.firstChild;
|
|
return outerBox.clientHeight === outerBox.offsetHeight;
|
|
}
|
|
},
|
|
{
|
|
identity: 'defineProperty',
|
|
fn: function() {
|
|
if (Ext.isIE8m) {
|
|
Ext.Object.defineProperty = Ext.emptyFn;
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
},
|
|
{
|
|
identify: 'nativeXhr',
|
|
fn: function() {
|
|
if (typeof XMLHttpRequest !== 'undefined') {
|
|
return true;
|
|
}
|
|
// Apply a polyfill:
|
|
XMLHttpRequest = function() {
|
|
// jshint ignore:line
|
|
try {
|
|
return new ActiveXObject('MSXML2.XMLHTTP.3.0');
|
|
} // jshint ignore:line
|
|
catch (ex) {
|
|
return null;
|
|
}
|
|
};
|
|
return false;
|
|
}
|
|
},
|
|
/**
|
|
* @property {Boolean} SpecialKeyDownRepeat
|
|
* True if the browser fires the keydown event on specialkey autorepeat
|
|
*
|
|
* note 1: IE fires ONLY the keydown event on specialkey autorepeat
|
|
* note 2: Safari < 3.1, Gecko (Mac/Linux) & Opera fire only the keypress event on
|
|
* specialkey autorepeat (research done by Jan Wolter at
|
|
* http://unixpapa.com/js/key.html)
|
|
* note 3: Opera 12 behaves like other modern browsers so this workaround does not
|
|
* work anymore
|
|
*
|
|
* This property is available at application boot time, before document ready.
|
|
*/
|
|
{
|
|
name: 'SpecialKeyDownRepeat',
|
|
fn: function() {
|
|
return Ext.isWebKit ? parseInt(navigator.userAgent.match(/AppleWebKit\/(\d+)/)[1], 10) >= 525 : !(!(Ext.isGecko || Ext.isIE) || (Ext.isOpera && Ext.operaVersion < 12));
|
|
}
|
|
},
|
|
/**
|
|
* @property {Boolean} EmulatedMouseOver
|
|
* True if the browser emulates a mouseover event on tap (mobile safari)
|
|
*
|
|
* This property is available at application boot time, before document ready.
|
|
*/
|
|
{
|
|
name: 'EmulatedMouseOver',
|
|
fn: function() {
|
|
// TODO: is it possible to feature detect this?
|
|
return Ext.os.is.iOS;
|
|
}
|
|
},
|
|
/**
|
|
* @property Hashchange True if the user agent supports the hashchange event
|
|
*
|
|
* This property is available at application boot time, before document ready.
|
|
* @type {Boolean}
|
|
*/
|
|
{
|
|
// support Vector 12
|
|
name: 'Hashchange',
|
|
fn: function() {
|
|
// Note that IE8 in IE7 compatibility mode reports true for 'onhashchange' in window, so also test documentMode
|
|
var docMode = document.documentMode;
|
|
return 'onhashchange' in window && (docMode === undefined || docMode > 7);
|
|
}
|
|
},
|
|
/**
|
|
* @property FixedTableWidthBug
|
|
* @private
|
|
* @type {Boolean}
|
|
* `true` if the browser has this bug: https://bugs.webkit.org/show_bug.cgi?id=130239
|
|
*
|
|
* This property is *NOT* available at application boot time. Only after the document ready event.
|
|
*/
|
|
{
|
|
name: 'FixedTableWidthBug',
|
|
ready: true,
|
|
fn: function() {
|
|
if (Ext.isIE8) {
|
|
// IE8 incorrectly detects that we have this bug.
|
|
return false;
|
|
}
|
|
var outer = document.createElement('div'),
|
|
inner = document.createElement('div'),
|
|
width;
|
|
outer.setAttribute('style', 'display:table;table-layout:fixed;');
|
|
inner.setAttribute('style', 'display:table-cell;min-width:50px;');
|
|
outer.appendChild(inner);
|
|
document.body.appendChild(outer);
|
|
// must poke offsetWidth to trigger a reflow before setting width
|
|
outer.offsetWidth;
|
|
// jshint ignore:line
|
|
outer.style.width = '25px';
|
|
width = outer.offsetWidth;
|
|
document.body.removeChild(outer);
|
|
return width === 50;
|
|
}
|
|
},
|
|
/**
|
|
* @property FocusinFocusoutEvents
|
|
* @private
|
|
* @type {Boolean}
|
|
* `true` if the browser supports focusin and focusout events:
|
|
* https://developer.mozilla.org/en-US/docs/Web/Events/focusin
|
|
* At this point, only Firefox does not, see this bug:
|
|
* https://bugzilla.mozilla.org/show_bug.cgi?id=687787
|
|
*
|
|
* This property is available at application boot time, before document ready.
|
|
*/
|
|
{
|
|
name: 'FocusinFocusoutEvents',
|
|
fn: function() {
|
|
// There is no reliable way to feature detect focusin/focusout event support.
|
|
// window.onfocusin will return undefined both in Chrome (where it is supported)
|
|
// and in Firefox (where it is not supported); adding an element and trying to
|
|
// focus it will fail when the browser window itself is not focused.
|
|
return !Ext.isGecko;
|
|
}
|
|
},
|
|
/**
|
|
* @property {Boolean} AsyncFocusEvents
|
|
* `true` if the browser fires focus events (focus, blur, focusin, focusout)
|
|
* asynchronously, i.e. in a separate event loop invocation. This is only true
|
|
* for all versions Internet Explorer; Microsoft Edge and other browsers fire
|
|
* focus events synchronously.
|
|
*/
|
|
{
|
|
name: 'AsyncFocusEvents',
|
|
fn: function() {
|
|
// The sad part is that we can't feature detect this because the focus
|
|
// event won't be fired when the browser window itself is not focused.
|
|
// Private shortcut for brevity
|
|
return Ext.asyncFocus = !!Ext.isIE;
|
|
}
|
|
},
|
|
/**
|
|
* @property {Boolean} HighContrastMode `true` if the browser is currently
|
|
* running in Windows High Contrast accessibility mode.
|
|
*
|
|
* @property {Object} accessibility Accessibility features.
|
|
*
|
|
* @property {Boolean} accessibility.Images `true` if the browser is configured
|
|
* to display images.
|
|
*
|
|
* @property {Boolean} accessibility.BackgroundImages `true` if the browser
|
|
* is configured to display background images.
|
|
*
|
|
* @property {Boolean} accessibility.BorderColors `true` if the browser
|
|
* is configured to honor CSS styling for border colors.
|
|
*
|
|
* @property {Boolean} accessibility.LightOnDark `true` if the browser
|
|
* is currently using reverse colors in light-on-dark accessibility mode.
|
|
*/
|
|
{
|
|
name: 'accessibility',
|
|
ready: true,
|
|
fn: function(doc) {
|
|
var body = doc.body,
|
|
div, img, style, supports, bgImg;
|
|
function getColor(colorTxt) {
|
|
var values = [],
|
|
colorValue = 0,
|
|
regex, match;
|
|
if (colorTxt.indexOf('rgb(') !== -1) {
|
|
values = colorTxt.replace('rgb(', '').replace(')', '').split(', ');
|
|
} else if (colorTxt.indexOf('#') !== -1) {
|
|
regex = colorTxt.length === 7 ? /^#(\S\S)(\S\S)(\S\S)$/ : /^#(\S)(\S)(\S)$/;
|
|
match = colorTxt.match(regex);
|
|
if (match) {
|
|
values = [
|
|
'0x' + match[1],
|
|
'0x' + match[2],
|
|
'0x' + match[3]
|
|
];
|
|
}
|
|
}
|
|
for (var i = 0; i < values.length; i++) {
|
|
colorValue += parseInt(values[i]);
|
|
}
|
|
return colorValue;
|
|
}
|
|
div = doc.createElement('div');
|
|
img = doc.createElement('img');
|
|
style = div.style;
|
|
Ext.apply(style, {
|
|
width: '2px',
|
|
position: 'absolute',
|
|
clip: 'rect(1px,1px,1px,1px)',
|
|
borderWidth: '1px',
|
|
borderStyle: 'solid',
|
|
borderTopTolor: '#f00',
|
|
borderRightColor: '#ff0',
|
|
backgroundColor: '#fff',
|
|
backgroundImage: 'url(' + Ext.BLANK_IMAGE_URL + ')'
|
|
});
|
|
img.alt = '';
|
|
img.src = Ext.BLANK_IMAGE_URL;
|
|
div.appendChild(img);
|
|
body.appendChild(div);
|
|
// Now check if the styles were indeed honored
|
|
style = div.currentStyle || div.style;
|
|
bgImg = style.backgroundImage;
|
|
supports = {
|
|
// In IE it is possible to untick "Show pictures" option in Advanced
|
|
// settings; this will result in img element reporting its readyState
|
|
// as 'uninitialized'.
|
|
// See http://www.paciellogroup.com/blog/2011/10/detecting-if-images-are-disabled-in-browsers/
|
|
Images: img.offsetWidth === 1 && img.readyState !== 'uninitialized',
|
|
BackgroundImages: !(bgImg !== null && (bgImg === "none" || bgImg === "url(invalid-url:)")),
|
|
BorderColors: style.borderTopColor !== style.borderRightColor,
|
|
LightOnDark: getColor(style.color) - getColor(style.backgroundColor) > 0
|
|
};
|
|
Ext.supports.HighContrastMode = !supports.BackgroundImages;
|
|
body.removeChild(div);
|
|
div = img = null;
|
|
return supports;
|
|
}
|
|
},
|
|
{
|
|
/**
|
|
* @property ViewportUnits `true` if the device supports ViewportUnits.
|
|
* @type {Boolean}
|
|
*
|
|
*/
|
|
name: 'ViewportUnits',
|
|
ready: true,
|
|
fn: function(doc) {
|
|
// Even attempting to detect the feature throws a fatal error on IE8
|
|
if (Ext.isIE8) {
|
|
return false;
|
|
}
|
|
var body = doc.body,
|
|
div = document.createElement('div'),
|
|
style = div.currentStyle || div.style,
|
|
width, divWidth;
|
|
body.appendChild(div);
|
|
Ext.apply(style, {
|
|
width: '50vw'
|
|
});
|
|
width = parseInt(window.innerWidth / 2, 10);
|
|
divWidth = parseInt((window.getComputedStyle ? getComputedStyle(div, null) : div.currentStyle).width, 10);
|
|
body.removeChild(div);
|
|
div = null;
|
|
return width === divWidth;
|
|
}
|
|
},
|
|
{
|
|
name: 'CSSVariables',
|
|
ready: false,
|
|
fn: function(doc) {
|
|
// Legacy browsers do not have this method.
|
|
if (!window.getComputedStyle) {
|
|
return false;
|
|
}
|
|
var style = window.getComputedStyle(doc.documentElement);
|
|
return style.getPropertyValue && !!style.getPropertyValue('--x-supports-variables');
|
|
}
|
|
},
|
|
{
|
|
/**
|
|
* @property Selectors2 `true` if the browser supports the CSS selector API level 2.
|
|
* https://dev.w3.org/2006/webapi/selectors-api2/
|
|
* @type {Boolean}
|
|
*
|
|
*/
|
|
name: 'Selectors2',
|
|
ready: false,
|
|
fn: function(doc) {
|
|
try {
|
|
return !!doc.querySelectorAll(':scope');
|
|
} catch (e) {
|
|
return false;
|
|
}
|
|
}
|
|
},
|
|
{
|
|
/**
|
|
* @property CSSScrollSnap
|
|
* @private
|
|
* @type {Boolean}
|
|
*/
|
|
name: 'CSSScrollSnap',
|
|
ready: false,
|
|
fn: function(doc) {
|
|
var style = doc.documentElement.style;
|
|
return 'scrollSnapType' in style || 'webkitScrollSnapType' in style || 'msScrollSnapType' in style;
|
|
}
|
|
},
|
|
0
|
|
]
|
|
};
|
|
// placeholder so legacy browser detectors can come/go cleanly
|
|
Ext.feature.tests.pop();
|
|
// remove the placeholder
|
|
Ext.supports = {};
|
|
Ext.feature.detect();
|
|
|
|
/**
|
|
* This class manages ready detection and handling. Direct use of this class is not
|
|
* recommended. Instead use `Ext.onReady`:
|
|
*
|
|
* Ext.onReady(function () {
|
|
* // DOM and Framework are ready...
|
|
* });
|
|
*
|
|
* ## DOM Ready
|
|
*
|
|
* The lowest-level of readiness is DOM readiness. This level implies only that the document
|
|
* body exists. Many things require the DOM to be ready for manipulation. If that is all
|
|
* that is required, the `Ext.onDocumentReady` method can be called to register a callback
|
|
* to be called as soon as the DOM is ready:
|
|
*
|
|
* Ext.onDocumentReady(function () {
|
|
* // the document body is ready
|
|
* });
|
|
*
|
|
* ## Framework Ready
|
|
*
|
|
* In production builds of applications it is common to have all of the code loaded before
|
|
* DOM ready, so the need to wait for "onReady" is often confused with only that concern.
|
|
* This is easy to understand, at least in part because historically `Ext.onReady` only
|
|
* waited for DOM ready.
|
|
*
|
|
* With the introduction of `Ext.Loader`, however, it became common for DOM ready to occur
|
|
* in the middle of dynamically loading code. If application code were executed at that
|
|
* time, any use of the yet-to-be-loaded classes would throw errors. As a consequence of
|
|
* this, the `Ext.onReady` mechanism was extended to wait for both DOM ready *and* all of
|
|
* the required classes to be loaded.
|
|
*
|
|
* When the framework enters or leaves a state where it is not ready (for example, the
|
|
* first dynamic load is requested or last load completes), `Ext.env.Ready` is informed.
|
|
* For example:
|
|
*
|
|
* Ext.env.Ready.block();
|
|
*
|
|
* //...
|
|
*
|
|
* Ext.env.Ready.unblock();
|
|
*
|
|
* When there are no blocks and the DOM is ready, the Framework is ready and the "onReady"
|
|
* callbacks are called.
|
|
*
|
|
* Priority can be used to control the ordering of onReady listeners, for example:
|
|
*
|
|
* Ext.onReady(function() {
|
|
*
|
|
* }, null, {
|
|
* priority: 100
|
|
* });
|
|
*
|
|
* Ready listeners with higher priorities will run sooner than those with lower priorities,
|
|
* the default priority being `0`. Internally the framework reserves priorities of 1000
|
|
* or greater, and -1000 or lesser for onReady handlers that must run before or after
|
|
* any application code. Applications should stick to using priorities in the -999 - 999
|
|
* range. The following priorities are currently in use by the framework:
|
|
*
|
|
* - Element_scroll rtl override: `1001`
|
|
* - Event system initialization: `2000`
|
|
* - Ext.dom.Element: `1500`
|
|
*
|
|
* @class Ext.env.Ready
|
|
* @singleton
|
|
* @private
|
|
* @since 5.0.0
|
|
*/
|
|
Ext.env.Ready = {
|
|
// @define Ext.env.Ready
|
|
// @require Ext.env.Browser
|
|
// @require Ext.env.OS
|
|
// @require Ext.env.Feature
|
|
/**
|
|
* @property {Number} blocks The number of Framework readiness blocks.
|
|
* @private
|
|
*/
|
|
blocks: (location.search || '').indexOf('ext-pauseReadyFire') > 0 ? 1 : 0,
|
|
/**
|
|
* @property {Number} bound This property stores the state of event listeners bound
|
|
* to the document or window to detect ready state.
|
|
* @private
|
|
*/
|
|
bound: 0,
|
|
/**
|
|
* @property {Number} [delay=1]
|
|
* This allows the DOM listener thread to complete (usually desirable with mobWebkit,
|
|
* Gecko) before firing the entire onReady chain (high stack load on Loader). For mobile
|
|
* devices when running from Home Screen, the splash screen will not disappear until
|
|
* all external resource requests finish. This delay clears the splash screen.
|
|
* @private
|
|
*/
|
|
delay: 1,
|
|
/**
|
|
* @property {Event[]} events An array of events that have triggered ready state. This
|
|
* is for diagnostic purposes only and is only available in debug builds.
|
|
* An array
|
|
* @private
|
|
*/
|
|
events: [],
|
|
/**
|
|
* @property {Boolean} firing This property is `true` when we currently calling the
|
|
* listeners.
|
|
* @private
|
|
*/
|
|
firing: false,
|
|
/**
|
|
* @property {Number} generation A counter of the number of mutations of `listeners`.
|
|
* @private
|
|
*/
|
|
generation: 0,
|
|
/**
|
|
* @property {Object[]} listeners The set of listeners waiting for ready.
|
|
* @private
|
|
*/
|
|
listeners: [],
|
|
/**
|
|
* @property {Number} nextId A counter so we can assign listeners an `id` to keep
|
|
* them in FIFO order.
|
|
* @private
|
|
*/
|
|
nextId: 0,
|
|
/**
|
|
* @property {Number} sortGeneration A captured value of `generation` that indicates
|
|
* when the `listeners` were last sorted.
|
|
* @private
|
|
*/
|
|
sortGeneration: 0,
|
|
/**
|
|
* @property {Number} state
|
|
* Holds the current ready state as managed by this class. The values possible are:
|
|
*
|
|
* * 0 - Not ready.
|
|
* * 1 - Ready detected but listeners are not yet notified.
|
|
* * 2 - Ready detected and listeners are notified. See also `firing`.
|
|
*
|
|
* @private
|
|
*/
|
|
state: 0,
|
|
/**
|
|
* @property {Object} timer The handle from `setTimeout` for the delayed notification
|
|
* of ready.
|
|
* @private
|
|
*/
|
|
timer: null,
|
|
/**
|
|
* Binds the appropriate browser event for checking if the DOM has loaded.
|
|
* @private
|
|
*/
|
|
bind: function() {
|
|
var me = Ext.env.Ready,
|
|
doc = document;
|
|
if (!me.bound) {
|
|
// Test scenario where load is dynamic AFTER window.load
|
|
if (doc.readyState === 'complete') {
|
|
// Firefox4+ got support for this state, others already do.
|
|
me.onReadyEvent({
|
|
type: doc.readyState || 'body'
|
|
});
|
|
} else {
|
|
me.bound = 1;
|
|
if (Ext.browser.is.PhoneGap && !Ext.os.is.Desktop) {
|
|
me.bound = 2;
|
|
doc.addEventListener('deviceready', me.onReadyEvent, false);
|
|
}
|
|
doc.addEventListener('DOMContentLoaded', me.onReadyEvent, false);
|
|
window.addEventListener('load', me.onReadyEvent, false);
|
|
}
|
|
}
|
|
},
|
|
block: function() {
|
|
++this.blocks;
|
|
Ext.isReady = false;
|
|
},
|
|
/**
|
|
* This method starts the process of firing the ready event. This may be delayed based
|
|
* on the `delay` property.
|
|
* @private
|
|
*/
|
|
fireReady: function() {
|
|
var me = Ext.env.Ready;
|
|
if (!me.state) {
|
|
Ext._readyTime = Ext.ticks();
|
|
Ext.isDomReady = true;
|
|
me.state = 1;
|
|
// As soon as we transition to domready, complete the feature detection:
|
|
Ext.feature.detect(true);
|
|
if (!me.delay) {
|
|
me.handleReady();
|
|
} else if (navigator.standalone) {
|
|
// When running from Home Screen, the splash screen will not disappear
|
|
// until all external resource requests finish.
|
|
// The first timeout clears the splash screen
|
|
// The second timeout allows inital HTML content to be displayed
|
|
me.timer = Ext.defer(function() {
|
|
me.timer = null;
|
|
me.handleReadySoon();
|
|
}, 1);
|
|
} else {
|
|
me.handleReadySoon();
|
|
}
|
|
}
|
|
},
|
|
/**
|
|
* This method iterates over the `listeners` and invokes them. This advances the
|
|
* `state` from 1 to 2 and ensure the proper subset of `listeners` are invoked.
|
|
* @private
|
|
*/
|
|
handleReady: function() {
|
|
var me = this;
|
|
if (me.state === 1) {
|
|
me.state = 2;
|
|
Ext._beforeReadyTime = Ext.ticks();
|
|
me.invokeAll();
|
|
Ext._afterReadyTime = Ext.ticks();
|
|
}
|
|
},
|
|
/**
|
|
* This method is called to schedule a call to `handleReady` using a `setTimeout`. It
|
|
* ensures that only one timer is pending.
|
|
* @param {Number} [delay] If passed, this overrides the `delay` property.
|
|
* @private
|
|
*/
|
|
handleReadySoon: function(delay) {
|
|
var me = this;
|
|
if (!me.timer) {
|
|
me.timer = Ext.defer(function() {
|
|
me.timer = null;
|
|
me.handleReady();
|
|
}, delay || me.delay);
|
|
}
|
|
},
|
|
/**
|
|
* This method invokes the given `listener` instance based on its options.
|
|
* @param {Object} listener
|
|
*/
|
|
invoke: function(listener) {
|
|
var delay = listener.delay;
|
|
if (delay) {
|
|
Ext.defer(listener.fn, delay, listener.scope);
|
|
} else {
|
|
if (Ext.elevateFunction) {
|
|
Ext.elevateFunction(listener.fn, listener.scope);
|
|
} else {
|
|
listener.fn.call(listener.scope);
|
|
}
|
|
}
|
|
},
|
|
/**
|
|
* Invokes as many listeners as are appropriate given the current state. This should
|
|
* only be called when DOM ready is achieved. The remaining business of `blocks` is
|
|
* handled here.
|
|
*/
|
|
invokeAll: function() {
|
|
if (Ext.elevateFunction) {
|
|
Ext.elevateFunction(this.doInvokeAll, this);
|
|
} else {
|
|
this.doInvokeAll();
|
|
}
|
|
},
|
|
doInvokeAll: function() {
|
|
var me = this,
|
|
listeners = me.listeners,
|
|
listener;
|
|
if (!me.blocks) {
|
|
// Since DOM is ready and we have no blocks, we mark the framework as ready.
|
|
Ext.isReady = true;
|
|
}
|
|
me.firing = true;
|
|
// NOTE: We cannot cache this length because each time through the loop a callback
|
|
// may have added new callbacks.
|
|
while (listeners.length) {
|
|
if (me.sortGeneration !== me.generation) {
|
|
me.sortGeneration = me.generation;
|
|
// This will happen just once on the first pass... if nothing is being
|
|
// added as we call the callbacks. This sorts the listeners such that the
|
|
// highest priority listener is at the *end* of the array ... so we can
|
|
// use pop (as opposed to shift) to extract it.
|
|
listeners.sort(me.sortFn);
|
|
}
|
|
listener = listeners.pop();
|
|
if (me.blocks && !listener.dom) {
|
|
// If we are blocked (i.e., only DOM ready) and this listener is not a
|
|
// DOM-ready listener we have reached the end of the line. The remaining
|
|
// listeners are Framework ready listeners.
|
|
listeners.push(listener);
|
|
break;
|
|
}
|
|
me.invoke(listener);
|
|
}
|
|
me.firing = false;
|
|
},
|
|
/**
|
|
* This method wraps the given listener pieces in a proper object for the `listeners`
|
|
* array and `invoke` methods.
|
|
* @param {Function} fn The method to call.
|
|
* @param {Object} [scope] The scope (`this` reference) in which the `fn` executes.
|
|
* Defaults to the browser window.
|
|
* @param {Object} [options] An object with extra options.
|
|
* @param {Number} [options.delay=0] A number of milliseconds to delay.
|
|
* @param {Number} [options.priority=0] Relative priority of this callback. A larger
|
|
* number will result in the callback being sorted before the others. Priorities
|
|
* 1000 or greater and -1000 or lesser are reserved for internal framework use only.
|
|
* @param {Boolean} [options.dom=false] Pass `true` to only wait for DOM ready, `false`
|
|
* means full Framework and DOM readiness.
|
|
* @return {Object} The listener instance.
|
|
* @private
|
|
*/
|
|
makeListener: function(fn, scope, options) {
|
|
var ret = {
|
|
fn: fn,
|
|
id: ++this.nextId,
|
|
// so sortFn can respect FIFO
|
|
scope: scope,
|
|
dom: false,
|
|
priority: 0
|
|
};
|
|
if (options) {
|
|
Ext.apply(ret, options);
|
|
}
|
|
ret.phase = ret.dom ? 0 : 1;
|
|
// to simplify the sortFn
|
|
return ret;
|
|
},
|
|
/**
|
|
* Adds a listener to be notified when the document is ready (before onload and before
|
|
* images are loaded).
|
|
*
|
|
* @param {Function} fn The method to call.
|
|
* @param {Object} [scope] The scope (`this` reference) in which the `fn` executes.
|
|
* Defaults to the browser window.
|
|
* @param {Object} [options] An object with extra options.
|
|
* @param {Number} [options.delay=0] A number of milliseconds to delay.
|
|
* @param {Number} [options.priority=0] Relative priority of this callback. A larger
|
|
* number will result in the callback being sorted before the others. Priorities
|
|
* 1000 or greater and -1000 or lesser are reserved for internal framework use only.
|
|
* @param {Boolean} [options.dom=false] Pass `true` to only wait for DOM ready, `false`
|
|
* means full Framework and DOM readiness.
|
|
* @private
|
|
*/
|
|
on: function(fn, scope, options) {
|
|
var me = Ext.env.Ready,
|
|
listener = me.makeListener(fn, scope, options);
|
|
if (me.state === 2 && !me.firing && (listener.dom || !me.blocks)) {
|
|
// If we are DOM ready (state === 2) and not currently in invokeAll (!firing)
|
|
// and this listener is ready to call (either a DOM ready listener or there
|
|
// are no blocks), then we need to invoke the listener now.
|
|
//
|
|
// Otherwise we can fall to the else block and push the listener. The eventual
|
|
// (or currently executing) call to handleReady or unblock will trigger its
|
|
// delivery in proper priority order.
|
|
me.invoke(listener);
|
|
} else {
|
|
me.listeners.push(listener);
|
|
++me.generation;
|
|
if (!me.bound) {
|
|
// If we have never bound then bind the ready event now. If we have unbound
|
|
// the event then me.bound == -1 and we don't want to rebind it as the DOM
|
|
// is ready.
|
|
me.bind();
|
|
}
|
|
}
|
|
},
|
|
/**
|
|
* This is a generic event handler method attached to all of the various events that
|
|
* may indicate ready state. The first call to this method indicates ready state has
|
|
* been achieved.
|
|
* @param {Event} [ev] The event instance.
|
|
* @private
|
|
*/
|
|
onReadyEvent: function(ev) {
|
|
var me = Ext.env.Ready;
|
|
if (Ext.elevateFunction) {
|
|
Ext.elevateFunction(me.doReadyEvent, me, arguments);
|
|
} else {
|
|
me.doReadyEvent(ev);
|
|
}
|
|
},
|
|
doReadyEvent: function(ev) {
|
|
var me = this;
|
|
if (ev && ev.type) {
|
|
me.events.push(ev);
|
|
}
|
|
if (me.bound > 0) {
|
|
me.unbind();
|
|
me.bound = -1;
|
|
}
|
|
// NOTE: *not* 0 or false - we never want to rebind!
|
|
if (!me.state) {
|
|
me.fireReady();
|
|
}
|
|
},
|
|
/**
|
|
* Sorts the `listeners` array by `phase` and `priority` such that the first listener
|
|
* to fire can be determined using `pop` on the `listeners` array.
|
|
* @private
|
|
*/
|
|
sortFn: function(a, b) {
|
|
return -((a.phase - b.phase) || (b.priority - a.priority) || (a.id - b.id));
|
|
},
|
|
unblock: function() {
|
|
var me = this;
|
|
if (me.blocks) {
|
|
if (!--me.blocks) {
|
|
if (me.state === 2 && !me.firing) {
|
|
// We have already finished handleReady (the DOM ready handler) so
|
|
// this trigger just needs to dispatch all the remaining listeners.
|
|
me.invokeAll();
|
|
}
|
|
}
|
|
}
|
|
},
|
|
// if we are currently firing then invokeAll will pick up the Framework
|
|
// ready listeners automatically.
|
|
//
|
|
// If me.state < 2 then we are waiting for DOM ready so it will eventually
|
|
// call handleReady and invokeAll when everything is ready.
|
|
/**
|
|
* This method is called to remove all event listeners that may have been set up to
|
|
* detect ready state.
|
|
* @private
|
|
*/
|
|
unbind: function() {
|
|
var me = this,
|
|
doc = document;
|
|
if (me.bound > 1) {
|
|
doc.removeEventListener('deviceready', me.onReadyEvent, false);
|
|
}
|
|
doc.removeEventListener('DOMContentLoaded', me.onReadyEvent, false);
|
|
window.removeEventListener('load', me.onReadyEvent, false);
|
|
}
|
|
};
|
|
(function() {
|
|
var Ready = Ext.env.Ready;
|
|
/*
|
|
* EXTJS-13522
|
|
* Although IE 9 has the DOMContentLoaded event available, usage of that causes
|
|
* timing issues when attempting to access document.namespaces (VmlCanvas.js).
|
|
* Consequently, even in IE 9 we need to use the legacy bind override for ready
|
|
* detection. This defers ready firing enough to allow access to the
|
|
* document.namespaces property.
|
|
*
|
|
* NOTE: this issue is very timing sensitive, and typically only displays itself
|
|
* when there is a large amount of latency between the browser and the server, and
|
|
* when testing against a built page (ext-all.js) and not a dev mode page.
|
|
*/
|
|
if (Ext.isIE9m) {
|
|
/* Customized implementation for Legacy IE. The default implementation is
|
|
* configured for use with all other 'standards compliant' agents.
|
|
* References: http://javascript.nwbox.com/IEContentLoaded/
|
|
* licensed courtesy of http://developer.yahoo.com/yui/license.html
|
|
*/
|
|
Ext.apply(Ready, {
|
|
/**
|
|
* Timer for doScroll polling
|
|
* @private
|
|
*/
|
|
scrollTimer: null,
|
|
/**
|
|
* @private
|
|
*/
|
|
readyStatesRe: /complete/i,
|
|
/**
|
|
* This strategy has minimal benefits for Sencha solutions that build
|
|
* themselves (ie. minimal initial page markup). However, progressively-enhanced
|
|
* pages (with image content and/or embedded frames) will benefit the most
|
|
* from it. Browser timer resolution is too poor to ensure a doScroll check
|
|
* more than once on a page loaded with minimal assets (the readystatechange
|
|
* event 'complete' usually beats the doScroll timer on a 'lightly-loaded'
|
|
* initial document).
|
|
* @private
|
|
*/
|
|
pollScroll: function() {
|
|
var scrollable = true;
|
|
try {
|
|
document.documentElement.doScroll('left');
|
|
} catch (e) {
|
|
scrollable = false;
|
|
}
|
|
// on IE8, when running within an iFrame, document.body is not immediately
|
|
// available
|
|
if (scrollable && document.body) {
|
|
Ready.onReadyEvent({
|
|
type: 'doScroll'
|
|
});
|
|
} else {
|
|
// Minimize thrashing --
|
|
// adjusted for setTimeout's close-to-minimums (not too low),
|
|
// as this method SHOULD always be called once initially
|
|
Ready.scrollTimer = Ext.defer(Ready.pollScroll, 20);
|
|
}
|
|
return scrollable;
|
|
},
|
|
bind: function() {
|
|
if (Ready.bound) {
|
|
return;
|
|
}
|
|
var doc = document,
|
|
topContext;
|
|
// See if we are in an IFRAME? (doScroll ineffective here)
|
|
try {
|
|
topContext = window.frameElement === undefined;
|
|
} catch (e) {}
|
|
// If we throw an exception, it means we're probably getting access
|
|
// denied, which means we're in an iframe cross domain.
|
|
if (!topContext || !doc.documentElement.doScroll) {
|
|
Ready.pollScroll = Ext.emptyFn;
|
|
}
|
|
//then noop this test altogether
|
|
else if (Ready.pollScroll()) {
|
|
// starts scroll polling if necessary
|
|
return;
|
|
}
|
|
if (doc.readyState === 'complete') {
|
|
// Loaded AFTER initial document write/load...
|
|
Ready.onReadyEvent({
|
|
type: 'already ' + (doc.readyState || 'body')
|
|
});
|
|
} else {
|
|
doc.attachEvent('onreadystatechange', Ready.onReadyStateChange);
|
|
window.attachEvent('onload', Ready.onReadyEvent);
|
|
Ready.bound = 1;
|
|
}
|
|
},
|
|
unbind: function() {
|
|
document.detachEvent('onreadystatechange', Ready.onReadyStateChange);
|
|
window.detachEvent('onload', Ready.onReadyEvent);
|
|
if (Ext.isNumber(Ready.scrollTimer)) {
|
|
clearTimeout(Ready.scrollTimer);
|
|
Ready.scrollTimer = null;
|
|
}
|
|
},
|
|
/**
|
|
* This event handler is called when the readyState changes.
|
|
* @private
|
|
*/
|
|
onReadyStateChange: function() {
|
|
var state = document.readyState;
|
|
if (Ready.readyStatesRe.test(state)) {
|
|
Ready.onReadyEvent({
|
|
type: state
|
|
});
|
|
}
|
|
}
|
|
});
|
|
}
|
|
/**
|
|
* @property {Boolean} isDomReady
|
|
* `true` when the document body is ready for use.
|
|
* @member Ext
|
|
* @readonly
|
|
*/
|
|
/**
|
|
* @property {Boolean} isReady
|
|
* `true` when `isDomReady` is true and the Framework is ready for use.
|
|
* @member Ext
|
|
* @readonly
|
|
*/
|
|
/**
|
|
* @method onDocumentReady
|
|
* @member Ext
|
|
* Adds a listener to be notified when the document is ready (before onload and before
|
|
* images are loaded).
|
|
*
|
|
* @param {Function} fn The method to call.
|
|
* @param {Object} [scope] The scope (`this` reference) in which the handler function
|
|
* executes. Defaults to the browser window.
|
|
* @param {Object} [options] An object with extra options.
|
|
* @param {Number} [options.delay=0] A number of milliseconds to delay.
|
|
* @param {Number} [options.priority=0] Relative priority of this callback. A larger
|
|
* number will result in the callback being sorted before the others. Priorities
|
|
* 1000 or greater and -1000 or lesser are reserved for internal framework use only.
|
|
* @private
|
|
*/
|
|
Ext.onDocumentReady = function(fn, scope, options) {
|
|
var opt = {
|
|
dom: true
|
|
};
|
|
if (options) {
|
|
Ext.apply(opt, options);
|
|
}
|
|
Ready.on(fn, scope, opt);
|
|
};
|
|
/**
|
|
* @method onReady
|
|
* @member Ext
|
|
* Adds a listener to be notified when the document is ready (before onload and before
|
|
* images are loaded).
|
|
*
|
|
* @param {Function} fn The method to call.
|
|
* @param {Object} [scope] The scope (`this` reference) in which the handler function
|
|
* executes. Defaults to the browser window.
|
|
* @param {Object} [options] An object with extra options.
|
|
* @param {Number} [options.delay=0] A number of milliseconds to delay.
|
|
* @param {Number} [options.priority=0] Relative priority of this callback. A larger
|
|
* number will result in the callback being sorted before the others. Priorities
|
|
* 1000 or greater and -1000 or lesser are reserved for internal framework use only.
|
|
* @param {Boolean} [options.dom=false] Pass `true` to only wait for DOM ready, `false`
|
|
* means full Framework and DOM readiness.
|
|
* numbers are reserved.
|
|
*/
|
|
Ext.onReady = function(fn, scope, options) {
|
|
Ready.on(fn, scope, options);
|
|
};
|
|
// A shortcut method for onReady with a high priority
|
|
Ext.onInternalReady = function(fn, scope, options) {
|
|
Ready.on(fn, scope, Ext.apply({
|
|
priority: 1000
|
|
}, options));
|
|
};
|
|
Ready.bind();
|
|
}());
|
|
|
|
// @tag class
|
|
/**
|
|
* This class provides dynamic loading support for JavaScript classes. Application code
|
|
* does not typically need to call `Ext.Loader` except perhaps to configure path mappings
|
|
* when not using [Sencha Cmd](http://www.sencha.com/products/sencha-cmd/).
|
|
*
|
|
* Ext.Loader.setPath('MyApp', 'app');
|
|
*
|
|
* When using Sencha Cmd, this is handled by the "bootstrap" provided by the application
|
|
* build script and such configuration is not necessary.
|
|
*
|
|
* # Typical Usage
|
|
*
|
|
* The `Ext.Loader` is most often used behind the scenes to satisfy class references in
|
|
* class declarations. Like so:
|
|
*
|
|
* Ext.define('MyApp.view.Main', {
|
|
* extend: 'Ext.panel.Panel',
|
|
*
|
|
* mixins: [
|
|
* 'MyApp.util.Mixin'
|
|
* ],
|
|
*
|
|
* requires: [
|
|
* 'Ext.grid.Panel'
|
|
* ],
|
|
*
|
|
* uses: [
|
|
* 'MyApp.util.Stuff'
|
|
* ]
|
|
* });
|
|
*
|
|
* In all of these cases, `Ext.Loader` is used internally to resolve these class names
|
|
* and ensure that the necessary class files are loaded.
|
|
*
|
|
* During development, these files are loaded individually for optimal debugging. For a
|
|
* production use, [Sencha Cmd](http://www.sencha.com/products/sencha-cmd/) will replace
|
|
* all of these strings with the actual resolved class references because it ensures that
|
|
* the classes are all contained in the build in the correct order. In development, these
|
|
* files will not be loaded until the `MyApp.view.Main` class indicates they are needed
|
|
* as shown above.
|
|
*
|
|
* # Loading Classes
|
|
*
|
|
* You can also use `Ext.Loader` directly to load classes or files. The simplest form of
|
|
* use is `{@link Ext#require}`.
|
|
*
|
|
* For example:
|
|
*
|
|
* Ext.require('MyApp.view.Main', function () {
|
|
* // On callback, the MyApp.view.Main class is now loaded
|
|
*
|
|
* var view = new MyApp.view.Main();
|
|
* });
|
|
*
|
|
* You can alternatively require classes by alias or wildcard.
|
|
*
|
|
* Ext.require('widget.window');
|
|
*
|
|
* Ext.require(['widget.window', 'layout.border', 'Ext.data.Connection']);
|
|
*
|
|
* Ext.require(['widget.*', 'layout.*', 'Ext.data.*']);
|
|
*
|
|
* The callback function is optional.
|
|
*
|
|
* **Note** Using `Ext.require` at global scope will cause `{@link Ext#onReady}` and
|
|
* `{@link Ext.app.Application#launch}` methods to be deferred until the required classes
|
|
* are loaded. It is these cases where the callback function is most often unnecessary.
|
|
*
|
|
* ## Using Excludes
|
|
*
|
|
* Alternatively, you can exclude what you don't need:
|
|
*
|
|
* // Include everything except Ext.tree.*
|
|
* Ext.exclude('Ext.tree.*').require('*');
|
|
*
|
|
* // Include all widgets except widget.checkbox* (this will exclude
|
|
* // widget.checkbox, widget.checkboxfield, widget.checkboxgroup, etc.)
|
|
* Ext.exclude('widget.checkbox*').require('widget.*');
|
|
*
|
|
* # Dynamic Instantiation
|
|
*
|
|
* Another feature enabled by `Ext.Loader` is instantiation using class names or aliases.
|
|
*
|
|
* For example:
|
|
*
|
|
* var win = Ext.create({
|
|
* xtype: 'window',
|
|
*
|
|
* // or
|
|
* // xclass: 'Ext.window.Window'
|
|
*
|
|
* title: 'Hello'
|
|
* });
|
|
*
|
|
* This form of creation can be useful if the type to create (`window` in the above) is
|
|
* not known statically. Internally, `{@link Ext#create}` may need to *synchronously*
|
|
* load the desired class and its requirements. Doing this will generate a warning in
|
|
* the console:
|
|
*
|
|
* [Ext.Loader] Synchronously loading 'Ext.window.Window'...
|
|
*
|
|
* If you see these in your debug console, you should add the indicated class(es) to the
|
|
* appropriate `requires` array (as above) or make an `{@link Ext#require}` call.
|
|
*
|
|
*
|
|
* **Note** Using `{@link Ext#create}` has some performance overhead and is best reserved
|
|
* for cases where the target class is not known until run-time.
|
|
*
|
|
* @class Ext.Loader
|
|
* @singleton
|
|
*/
|
|
Ext.Loader = (new function() {
|
|
// jshint ignore:line
|
|
// @define Ext.Loader
|
|
// @require Ext.Base
|
|
// @require Ext.Class
|
|
// @require Ext.ClassManager
|
|
// @require Ext.Function
|
|
// @require Ext.Array
|
|
// @require Ext.env.Ready
|
|
var Loader = this,
|
|
Manager = Ext.ClassManager,
|
|
// this is an instance of Ext.Inventory
|
|
Boot = Ext.Boot,
|
|
Class = Ext.Class,
|
|
Ready = Ext.env.Ready,
|
|
alias = Ext.Function.alias,
|
|
dependencyProperties = [
|
|
'extend',
|
|
'mixins',
|
|
'requires'
|
|
],
|
|
isInHistory = {},
|
|
history = [],
|
|
readyListeners = [],
|
|
usedClasses = [],
|
|
_requiresMap = {},
|
|
_config = {
|
|
/**
|
|
* @cfg {Boolean} [enabled=true]
|
|
* Whether or not to enable the dynamic dependency loading feature.
|
|
*/
|
|
enabled: true,
|
|
/**
|
|
* @cfg {Boolean} [scriptChainDelay=false]
|
|
* millisecond delay between asynchronous script injection (prevents stack
|
|
* overflow on some user agents) 'false' disables delay but potentially
|
|
* increases stack load.
|
|
*/
|
|
scriptChainDelay: false,
|
|
/**
|
|
* @cfg {Boolean} [disableCaching=true]
|
|
* Appends current timestamp to script files to prevent caching.
|
|
*/
|
|
disableCaching: true,
|
|
/**
|
|
* @cfg {String} [disableCachingParam="_dc"]
|
|
* The get parameter name for the cache buster's timestamp.
|
|
*/
|
|
disableCachingParam: '_dc',
|
|
/**
|
|
* @cfg {Object} paths
|
|
* The mapping from namespaces to file paths
|
|
*
|
|
* {
|
|
* 'Ext': '.', // This is set by default, Ext.layout.container.Container will be
|
|
* // loaded from ./layout/Container.js
|
|
*
|
|
* 'My': './src/my_own_folder' // My.layout.Container will be loaded from
|
|
* // ./src/my_own_folder/layout/Container.js
|
|
* }
|
|
*
|
|
* Note that all relative paths are relative to the current HTML document.
|
|
* If not being specified, for example, `Other.awesome.Class` will simply be
|
|
* loaded from `"./Other/awesome/Class.js"`.
|
|
*/
|
|
paths: Manager.paths,
|
|
/**
|
|
* @cfg {Boolean} preserveScripts
|
|
* `false` to remove asynchronously loaded scripts, `true` to retain script
|
|
* element for browser debugger compatibility and improved load performance.
|
|
*/
|
|
preserveScripts: true,
|
|
/**
|
|
* @cfg {String} scriptCharset
|
|
* Optional charset to specify encoding of dynamic script content.
|
|
*/
|
|
scriptCharset: undefined
|
|
},
|
|
// These configs are delegated to Ext.Script and may need different names:
|
|
delegatedConfigs = {
|
|
disableCaching: true,
|
|
disableCachingParam: true,
|
|
preserveScripts: true,
|
|
scriptChainDelay: 'loadDelay'
|
|
};
|
|
Ext.apply(Loader, {
|
|
/**
|
|
* @private
|
|
*/
|
|
isInHistory: isInHistory,
|
|
/**
|
|
* Flag indicating whether there are still files being loaded
|
|
* @private
|
|
*/
|
|
isLoading: false,
|
|
/**
|
|
* An array of class names to keep track of the dependency loading order.
|
|
* This is not guaranteed to be the same everytime due to the asynchronous
|
|
* nature of the Loader.
|
|
*
|
|
* @property {Array} history
|
|
*/
|
|
history: history,
|
|
/**
|
|
* Configuration
|
|
* @private
|
|
*/
|
|
config: _config,
|
|
/**
|
|
* Maintain the list of listeners to execute when all required scripts are fully loaded
|
|
* @private
|
|
*/
|
|
readyListeners: readyListeners,
|
|
/**
|
|
* Contains classes referenced in `uses` properties.
|
|
* @private
|
|
*/
|
|
optionalRequires: usedClasses,
|
|
/**
|
|
* Map of fully qualified class names to an array of dependent classes.
|
|
* @private
|
|
*/
|
|
requiresMap: _requiresMap,
|
|
/** @private */
|
|
hasFileLoadError: false,
|
|
/**
|
|
* The number of scripts loading via loadScript.
|
|
* @private
|
|
*/
|
|
scriptsLoading: 0,
|
|
/**
|
|
* @private
|
|
*/
|
|
classesLoading: {},
|
|
missingCount: 0,
|
|
missingQueue: {},
|
|
/**
|
|
* @private
|
|
*/
|
|
syncModeEnabled: false,
|
|
init: function() {
|
|
// initalize the default path of the framework
|
|
var scripts = document.getElementsByTagName('script'),
|
|
src = scripts[scripts.length - 1].src,
|
|
path = src.substring(0, src.lastIndexOf('/') + 1),
|
|
meta = Ext._classPathMetadata,
|
|
microloader = Ext.Microloader,
|
|
manifest = Ext.manifest,
|
|
loadOrder, classes, className, idx, baseUrl, loadlen, l, loadItem;
|
|
if (src.indexOf("packages/core/src/") !== -1) {
|
|
path = path + "../../";
|
|
} else if (src.indexOf("/core/src/class/") !== -1) {
|
|
path = path + "../../../";
|
|
}
|
|
if (!Manager.getPath("Ext")) {
|
|
Manager.setPath('Ext', path + 'src');
|
|
}
|
|
// Pull in Cmd generated metadata if available.
|
|
if (meta) {
|
|
Ext._classPathMetadata = null;
|
|
Loader.addClassPathMappings(meta);
|
|
}
|
|
if (manifest) {
|
|
loadOrder = manifest.loadOrder;
|
|
// if the manifest paths were calculated as relative to the
|
|
// bootstrap file, then we need to prepend Boot.baseUrl to the
|
|
// paths before processing
|
|
baseUrl = Ext.Boot.baseUrl;
|
|
if (loadOrder && manifest.bootRelative) {
|
|
for (loadlen = loadOrder.length , l = 0; l < loadlen; l++) {
|
|
loadItem = loadOrder[l];
|
|
loadItem.path = baseUrl + loadItem.path;
|
|
loadItem.canonicalPath = true;
|
|
}
|
|
}
|
|
}
|
|
if (microloader) {
|
|
Ready.block();
|
|
microloader.onMicroloaderReady(function() {
|
|
Ready.unblock();
|
|
});
|
|
}
|
|
},
|
|
/**
|
|
* Set the configuration for the loader. This should be called right after ext-(debug).js
|
|
* is included in the page, and before Ext.onReady. i.e:
|
|
*
|
|
* <script type="text/javascript" src="ext-core-debug.js"></script>
|
|
* <script type="text/javascript">
|
|
* Ext.Loader.setConfig({
|
|
* enabled: true,
|
|
* paths: {
|
|
* 'My': 'my_own_path'
|
|
* }
|
|
* });
|
|
* </script>
|
|
* <script type="text/javascript">
|
|
* Ext.require(...);
|
|
*
|
|
* Ext.onReady(function() {
|
|
* // application code here
|
|
* });
|
|
* </script>
|
|
*
|
|
* Refer to config options of {@link Ext.Loader} for the list of possible properties
|
|
*
|
|
* @param {Object} config The config object to override the default values
|
|
* @return {Ext.Loader} this
|
|
*/
|
|
setConfig: Ext.Function.flexSetter(function(name, value) {
|
|
if (name === 'paths') {
|
|
Loader.setPath(value);
|
|
} else {
|
|
_config[name] = value;
|
|
var delegated = delegatedConfigs[name];
|
|
if (delegated) {
|
|
Boot.setConfig((delegated === true) ? name : delegated, value);
|
|
}
|
|
}
|
|
return Loader;
|
|
}),
|
|
/**
|
|
* Get the config value corresponding to the specified name. If no name is given,
|
|
* will return the config object
|
|
*
|
|
* @param {String} name The config property name
|
|
* @return {Object}
|
|
*/
|
|
getConfig: function(name) {
|
|
return name ? _config[name] : _config;
|
|
},
|
|
/**
|
|
* Sets the path of a namespace.
|
|
* For Example:
|
|
*
|
|
* Ext.Loader.setPath('Ext', '.');
|
|
*
|
|
* @param {String/Object} name See {@link Ext.Function#flexSetter flexSetter}
|
|
* @param {String} [path] See {@link Ext.Function#flexSetter flexSetter}
|
|
* @return {Ext.Loader} this
|
|
* @method
|
|
*/
|
|
setPath: function() {
|
|
// Paths are an Ext.Inventory thing and ClassManager is an instance of that:
|
|
Manager.setPath.apply(Manager, arguments);
|
|
return Loader;
|
|
},
|
|
/**
|
|
* Sets a batch of path entries
|
|
*
|
|
* @param {Object} paths a set of className: path mappings
|
|
* @return {Ext.Loader} this
|
|
*/
|
|
addClassPathMappings: function(paths) {
|
|
// Paths are an Ext.Inventory thing and ClassManager is an instance of that:
|
|
Manager.setPath(paths);
|
|
return Loader;
|
|
},
|
|
/**
|
|
* fixes up loader path configs by prepending Ext.Boot#baseUrl to the beginning
|
|
* of the path, then delegates to Ext.Loader#addClassPathMappings
|
|
* @param pathConfig
|
|
*/
|
|
addBaseUrlClassPathMappings: function(pathConfig) {
|
|
for (var name in pathConfig) {
|
|
pathConfig[name] = Boot.baseUrl + pathConfig[name];
|
|
}
|
|
Ext.Loader.addClassPathMappings(pathConfig);
|
|
},
|
|
/**
|
|
* Translates a className to a file path by adding the
|
|
* the proper prefix and converting the .'s to /'s. For example:
|
|
*
|
|
* Ext.Loader.setPath('My', '/path/to/My');
|
|
*
|
|
* alert(Ext.Loader.getPath('My.awesome.Class')); // alerts '/path/to/My/awesome/Class.js'
|
|
*
|
|
* Note that the deeper namespace levels, if explicitly set, are always resolved first.
|
|
* For example:
|
|
*
|
|
* Ext.Loader.setPath({
|
|
* 'My': '/path/to/lib',
|
|
* 'My.awesome': '/other/path/for/awesome/stuff',
|
|
* 'My.awesome.more': '/more/awesome/path'
|
|
* });
|
|
*
|
|
* alert(Ext.Loader.getPath('My.awesome.Class')); // alerts '/other/path/for/awesome/stuff/Class.js'
|
|
*
|
|
* alert(Ext.Loader.getPath('My.awesome.more.Class')); // alerts '/more/awesome/path/Class.js'
|
|
*
|
|
* alert(Ext.Loader.getPath('My.cool.Class')); // alerts '/path/to/lib/cool/Class.js'
|
|
*
|
|
* alert(Ext.Loader.getPath('Unknown.strange.Stuff')); // alerts 'Unknown/strange/Stuff.js'
|
|
*
|
|
* @param {String} className
|
|
* @return {String} path
|
|
*/
|
|
getPath: function(className) {
|
|
// Paths are an Ext.Inventory thing and ClassManager is an instance of that:
|
|
return Manager.getPath(className);
|
|
},
|
|
require: function(expressions, fn, scope, excludes) {
|
|
if (excludes) {
|
|
return Loader.exclude(excludes).require(expressions, fn, scope);
|
|
}
|
|
var classNames = Manager.getNamesByExpression(expressions);
|
|
return Loader.load(classNames, fn, scope);
|
|
},
|
|
syncRequire: function() {
|
|
var wasEnabled = Loader.syncModeEnabled;
|
|
Loader.syncModeEnabled = true;
|
|
var ret = Loader.require.apply(Loader, arguments);
|
|
Loader.syncModeEnabled = wasEnabled;
|
|
return ret;
|
|
},
|
|
exclude: function(excludes) {
|
|
var selector = Manager.select({
|
|
require: function(classNames, fn, scope) {
|
|
return Loader.load(classNames, fn, scope);
|
|
},
|
|
syncRequire: function(classNames, fn, scope) {
|
|
var wasEnabled = Loader.syncModeEnabled;
|
|
Loader.syncModeEnabled = true;
|
|
var ret = Loader.load(classNames, fn, scope);
|
|
Loader.syncModeEnabled = wasEnabled;
|
|
return ret;
|
|
}
|
|
});
|
|
selector.exclude(excludes);
|
|
return selector;
|
|
},
|
|
load: function(classNames, callback, scope) {
|
|
if (callback) {
|
|
if (callback.length) {
|
|
// If callback expects arguments, shim it with a function that will map
|
|
// the requires class(es) from the names we are given.
|
|
callback = Loader.makeLoadCallback(classNames, callback);
|
|
}
|
|
callback = callback.bind(scope || Ext.global);
|
|
}
|
|
var state = Manager.classState,
|
|
missingClassNames = [],
|
|
urls = [],
|
|
urlByClass = {},
|
|
numClasses = classNames.length,
|
|
url, className, i, numMissing;
|
|
for (i = 0; i < numClasses; ++i) {
|
|
className = Manager.resolveName(classNames[i]);
|
|
if (!Manager.isCreated(className)) {
|
|
missingClassNames.push(className);
|
|
if (!state[className]) {
|
|
urlByClass[className] = Loader.getPath(className);
|
|
urls.push(urlByClass[className]);
|
|
}
|
|
}
|
|
}
|
|
// If the dynamic dependency feature is not being used, throw an error
|
|
// if the dependencies are not defined
|
|
numMissing = missingClassNames.length;
|
|
if (numMissing) {
|
|
Loader.missingCount += numMissing;
|
|
Manager.onCreated(function() {
|
|
if (callback) {
|
|
Ext.callback(callback, scope, arguments);
|
|
}
|
|
Loader.checkReady();
|
|
}, Loader, missingClassNames);
|
|
if (!_config.enabled) {
|
|
Ext.raise("Ext.Loader is not enabled, so dependencies cannot be resolved dynamically. " + "Missing required class" + ((missingClassNames.length > 1) ? "es" : "") + ": " + missingClassNames.join(', '));
|
|
}
|
|
if (urls.length) {
|
|
Loader.loadScripts({
|
|
url: urls,
|
|
// scope will be this options object so we can pass these along:
|
|
_classNames: missingClassNames,
|
|
_urlByClass: urlByClass
|
|
});
|
|
} else {
|
|
// need to call checkReady here, as the _missingCoun
|
|
// may have transitioned from 0 to > 0, meaning we
|
|
// need to block ready
|
|
Loader.checkReady();
|
|
}
|
|
} else {
|
|
if (callback) {
|
|
callback.call(scope);
|
|
}
|
|
// need to call checkReady here, as the _missingCoun
|
|
// may have transitioned from 0 to > 0, meaning we
|
|
// need to block ready
|
|
Loader.checkReady();
|
|
}
|
|
if (Loader.syncModeEnabled) {
|
|
// Class may have been just loaded or was already loaded
|
|
if (numClasses === 1) {
|
|
return Manager.get(classNames[0]);
|
|
}
|
|
}
|
|
return Loader;
|
|
},
|
|
makeLoadCallback: function(classNames, callback) {
|
|
return function() {
|
|
var classes = [],
|
|
i = classNames.length;
|
|
while (i-- > 0) {
|
|
classes[i] = Manager.get(classNames[i]);
|
|
}
|
|
return callback.apply(this, classes);
|
|
};
|
|
},
|
|
onLoadFailure: function() {
|
|
var options = this,
|
|
onError = options.onError;
|
|
Loader.hasFileLoadError = true;
|
|
--Loader.scriptsLoading;
|
|
if (onError) {
|
|
//TODO: need an adapter to convert to v4 onError signatures
|
|
onError.call(options.userScope, options);
|
|
} else {
|
|
Ext.log.error("[Ext.Loader] Some requested files failed to load.");
|
|
}
|
|
Loader.checkReady();
|
|
},
|
|
onLoadSuccess: function() {
|
|
var options = this,
|
|
onLoad = options.onLoad,
|
|
classNames = options._classNames,
|
|
urlByClass = options._urlByClass,
|
|
state = Manager.classState,
|
|
missingQueue = Loader.missingQueue,
|
|
className, i, len;
|
|
--Loader.scriptsLoading;
|
|
if (onLoad) {
|
|
//TODO: need an adapter to convert to v4 onLoad signatures
|
|
onLoad.call(options.userScope, options);
|
|
}
|
|
// onLoad can cause more loads to start, so it must run first
|
|
// classNames is the array of *all* classes that load() was asked to load,
|
|
// including those that might have been already loaded but not yet created.
|
|
// urlByClass is a map of only those classes that we asked Boot to load.
|
|
for (i = 0 , len = classNames.length; i < len; i++) {
|
|
className = classNames[i];
|
|
// When a script is loaded and executed, we should have Ext.define() called
|
|
// for at least one of the classes in the list, which will set the state
|
|
// for that class. That by itself does not mean that the class is available
|
|
// *now* but it means that ClassManager is tracking it and will fire the
|
|
// onCreated callback that we set back in load().
|
|
// However if there is no state for the class, that may mean two things:
|
|
// either it is not a Ext class, or it is truly missing. In any case we need
|
|
// to watch for that thing ourselves, which we will do every checkReady().
|
|
if (!state[className]) {
|
|
missingQueue[className] = urlByClass[className];
|
|
}
|
|
}
|
|
Loader.checkReady();
|
|
},
|
|
// TODO: this timing of this needs to be deferred until all classes have had
|
|
// a chance to be created
|
|
reportMissingClasses: function() {
|
|
if (!Loader.syncModeEnabled && !Loader.scriptsLoading && Loader.isLoading && !Loader.hasFileLoadError) {
|
|
var missingQueue = Loader.missingQueue,
|
|
missingClasses = [],
|
|
missingPaths = [];
|
|
for (var missingClassName in missingQueue) {
|
|
missingClasses.push(missingClassName);
|
|
missingPaths.push(missingQueue[missingClassName]);
|
|
}
|
|
if (missingClasses.length) {
|
|
throw new Error("The following classes are not declared even if their files have been " + "loaded: '" + missingClasses.join("', '") + "'. Please check the source code of their " + "corresponding files for possible typos: '" + missingPaths.join("', '"));
|
|
}
|
|
}
|
|
},
|
|
/**
|
|
* Add a new listener to be executed when all required scripts are fully loaded
|
|
*
|
|
* @param {Function} fn The function callback to be executed
|
|
* @param {Object} scope The execution scope (`this`) of the callback function.
|
|
* @param {Boolean} [withDomReady=true] Pass `false` to not also wait for document
|
|
* dom ready.
|
|
* @param {Object} [options] Additional callback options.
|
|
* @param {Number} [options.delay=0] A number of milliseconds to delay.
|
|
* @param {Number} [options.priority=0] Relative priority of this callback. Negative
|
|
* numbers are reserved.
|
|
*/
|
|
onReady: function(fn, scope, withDomReady, options) {
|
|
if (withDomReady) {
|
|
Ready.on(fn, scope, options);
|
|
} else {
|
|
var listener = Ready.makeListener(fn, scope, options);
|
|
if (Loader.isLoading) {
|
|
readyListeners.push(listener);
|
|
} else {
|
|
Ready.invoke(listener);
|
|
}
|
|
}
|
|
},
|
|
/**
|
|
* @private
|
|
* Ensure that any classes referenced in the `uses` property are loaded.
|
|
*/
|
|
addUsedClasses: function(classes) {
|
|
var cls, i, ln;
|
|
if (classes) {
|
|
classes = (typeof classes === 'string') ? [
|
|
classes
|
|
] : classes;
|
|
for (i = 0 , ln = classes.length; i < ln; i++) {
|
|
cls = classes[i];
|
|
if (typeof cls === 'string' && !Ext.Array.contains(usedClasses, cls)) {
|
|
usedClasses.push(cls);
|
|
}
|
|
}
|
|
}
|
|
return Loader;
|
|
},
|
|
/**
|
|
* @private
|
|
*/
|
|
triggerReady: function() {
|
|
var listener,
|
|
refClasses = usedClasses;
|
|
if (Loader.isLoading && refClasses.length) {
|
|
// Empty the array to eliminate potential recursive loop issue
|
|
usedClasses = [];
|
|
// this may immediately call us back if all 'uses' classes
|
|
// have been loaded
|
|
Loader.require(refClasses);
|
|
} else {
|
|
// Must clear this before calling callbacks. This will cause any new loads
|
|
// to call Ready.block() again. See below for more on this.
|
|
Loader.isLoading = false;
|
|
// These listeners are just those attached directly to Loader to wait for
|
|
// class loading only.
|
|
readyListeners.sort(Ready.sortFn);
|
|
// this method can be called with Loader.isLoading either true or false
|
|
// (can be called with false when all 'uses' classes are already loaded)
|
|
// this may bypass the above if condition
|
|
while (readyListeners.length && !Loader.isLoading) {
|
|
// we may re-enter triggerReady so we cannot necessarily iterate the
|
|
// readyListeners array
|
|
listener = readyListeners.pop();
|
|
Ready.invoke(listener);
|
|
}
|
|
// If the DOM is also ready, this will fire the normal onReady listeners.
|
|
// An astute observer would note that we may now be back to isLoading and
|
|
// so ask "Why you call unblock?". The reason is that we must match the
|
|
// calls to block and since we transitioned from isLoading to !isLoading
|
|
// here we must call unblock. If we have transitioned back to isLoading in
|
|
// the above loop it will have called block again so the counter will be
|
|
// increased and this call will not reduce the block count to 0. This is
|
|
// done by loadScripts.
|
|
Ready.unblock();
|
|
}
|
|
},
|
|
/**
|
|
* @private
|
|
* @param {String} className
|
|
*/
|
|
historyPush: function(className) {
|
|
if (className && !isInHistory[className] && !Manager.overrideMap[className]) {
|
|
isInHistory[className] = true;
|
|
history.push(className);
|
|
}
|
|
return Loader;
|
|
},
|
|
/**
|
|
* This is an internal method that delegate content loading to the
|
|
* bootstrap layer.
|
|
* @private
|
|
* @param params
|
|
*/
|
|
loadScripts: function(params) {
|
|
var manifest = Ext.manifest,
|
|
loadOrder = manifest && manifest.loadOrder,
|
|
loadOrderMap = manifest && manifest.loadOrderMap,
|
|
options;
|
|
++Loader.scriptsLoading;
|
|
// if the load order map hasn't been created, create it now
|
|
// and cache on the manifest
|
|
if (loadOrder && !loadOrderMap) {
|
|
manifest.loadOrderMap = loadOrderMap = Boot.createLoadOrderMap(loadOrder);
|
|
}
|
|
// verify the loading state, as this may have transitioned us from
|
|
// not loading to loading
|
|
Loader.checkReady();
|
|
options = Ext.apply({
|
|
loadOrder: loadOrder,
|
|
loadOrderMap: loadOrderMap,
|
|
charset: _config.scriptCharset,
|
|
success: Loader.onLoadSuccess,
|
|
failure: Loader.onLoadFailure,
|
|
sync: Loader.syncModeEnabled,
|
|
_classNames: []
|
|
}, params);
|
|
options.userScope = options.scope;
|
|
options.scope = options;
|
|
Boot.load(options);
|
|
},
|
|
/**
|
|
* This method is provide for use by the bootstrap layer.
|
|
* @private
|
|
* @param {String[]} urls
|
|
*/
|
|
loadScriptsSync: function(urls) {
|
|
var syncwas = Loader.syncModeEnabled;
|
|
Loader.syncModeEnabled = true;
|
|
Loader.loadScripts({
|
|
url: urls
|
|
});
|
|
Loader.syncModeEnabled = syncwas;
|
|
},
|
|
/**
|
|
* This method is provide for use by the bootstrap layer.
|
|
* @private
|
|
* @param {String[]} urls
|
|
*/
|
|
loadScriptsSyncBasePrefix: function(urls) {
|
|
var syncwas = Loader.syncModeEnabled;
|
|
Loader.syncModeEnabled = true;
|
|
Loader.loadScripts({
|
|
url: urls,
|
|
prependBaseUrl: true
|
|
});
|
|
Loader.syncModeEnabled = syncwas;
|
|
},
|
|
/**
|
|
* Loads the specified script URL and calls the supplied callbacks. If this method
|
|
* is called before {@link Ext#isReady}, the script's load will delay the transition
|
|
* to ready. This can be used to load arbitrary scripts that may contain further
|
|
* {@link Ext#require Ext.require} calls.
|
|
*
|
|
* @param {Object/String/String[]} options The options object or simply the URL(s) to load.
|
|
* @param {String} options.url The URL from which to load the script.
|
|
* @param {Function} [options.onLoad] The callback to call on successful load.
|
|
* @param {Function} [options.onError] The callback to call on failure to load.
|
|
* @param {Object} [options.scope] The scope (`this`) for the supplied callbacks.
|
|
*/
|
|
loadScript: function(options) {
|
|
var isString = typeof options === 'string',
|
|
isArray = options instanceof Array,
|
|
isObject = !isArray && !isString,
|
|
url = isObject ? options.url : options,
|
|
onError = isObject && options.onError,
|
|
onLoad = isObject && options.onLoad,
|
|
scope = isObject && options.scope,
|
|
request = {
|
|
url: url,
|
|
scope: scope,
|
|
onLoad: onLoad,
|
|
onError: onError,
|
|
_classNames: []
|
|
};
|
|
Loader.loadScripts(request);
|
|
},
|
|
/**
|
|
* @private
|
|
*/
|
|
checkMissingQueue: function() {
|
|
var missingQueue = Loader.missingQueue,
|
|
newQueue = {},
|
|
name,
|
|
missing = 0;
|
|
for (name in missingQueue) {
|
|
// If class state is available for the name, that means ClassManager
|
|
// is tracking it and will fire callback when it is created.
|
|
// We only need to track non-class things in the Loader.
|
|
if (!(Manager.classState[name] || Manager.isCreated(name))) {
|
|
newQueue[name] = missingQueue[name];
|
|
missing++;
|
|
}
|
|
}
|
|
Loader.missingCount = missing;
|
|
Loader.missingQueue = newQueue;
|
|
},
|
|
/**
|
|
* @private
|
|
*/
|
|
checkReady: function() {
|
|
var wasLoading = Loader.isLoading,
|
|
isLoading;
|
|
Loader.checkMissingQueue();
|
|
isLoading = Loader.missingCount + Loader.scriptsLoading;
|
|
if (isLoading && !wasLoading) {
|
|
Ready.block();
|
|
Loader.isLoading = !!isLoading;
|
|
} else if (!isLoading && wasLoading) {
|
|
Loader.triggerReady();
|
|
}
|
|
if (!Loader.scriptsLoading && Loader.missingCount) {
|
|
// Things look bad, but since load requests may come later, defer this
|
|
// for a bit then check if things are still stuck.
|
|
Ext.defer(function() {
|
|
if (!Loader.scriptsLoading && Loader.missingCount) {
|
|
Ext.log.error('[Loader] The following classes failed to load:');
|
|
for (var name in Loader.missingQueue) {
|
|
Ext.log.error('[Loader] ' + name + ' from ' + Loader.missingQueue[name]);
|
|
}
|
|
}
|
|
}, 1000);
|
|
}
|
|
}
|
|
});
|
|
/**
|
|
* Loads all classes by the given names and all their direct dependencies; optionally
|
|
* executes the given callback function when finishes, within the optional scope.
|
|
*
|
|
* @param {String/String[]} expressions The class, classes or wildcards to load.
|
|
* @param {Function} [fn] The callback function.
|
|
* @param {Object} [scope] The execution scope (`this`) of the callback function.
|
|
* @member Ext
|
|
* @method require
|
|
*/
|
|
Ext.require = alias(Loader, 'require');
|
|
/**
|
|
* Synchronously loads all classes by the given names and all their direct dependencies; optionally
|
|
* executes the given callback function when finishes, within the optional scope.
|
|
*
|
|
* @param {String/String[]} expressions The class, classes or wildcards to load.
|
|
* @param {Function} [fn] The callback function.
|
|
* @param {Object} [scope] The execution scope (`this`) of the callback function.
|
|
* @member Ext
|
|
* @method syncRequire
|
|
*/
|
|
Ext.syncRequire = alias(Loader, 'syncRequire');
|
|
/**
|
|
* Explicitly exclude files from being loaded. Useful when used in conjunction with a
|
|
* broad include expression. Can be chained with more `require` and `exclude` methods,
|
|
* for example:
|
|
*
|
|
* Ext.exclude('Ext.data.*').require('*');
|
|
*
|
|
* Ext.exclude('widget.button*').require('widget.*');
|
|
*
|
|
* @param {String/String[]} excludes
|
|
* @return {Object} Contains `exclude`, `require` and `syncRequire` methods for chaining.
|
|
* @member Ext
|
|
* @method exclude
|
|
*/
|
|
Ext.exclude = alias(Loader, 'exclude');
|
|
/**
|
|
* @cfg {String[]} requires
|
|
* @member Ext.Class
|
|
* List of classes that have to be loaded before instantiating this class.
|
|
* For example:
|
|
*
|
|
* Ext.define('Mother', {
|
|
* requires: ['Child'],
|
|
* giveBirth: function() {
|
|
* // we can be sure that child class is available.
|
|
* return new Child();
|
|
* }
|
|
* });
|
|
*/
|
|
Class.registerPreprocessor('loader', function(cls, data, hooks, continueFn) {
|
|
Ext.classSystemMonitor && Ext.classSystemMonitor(cls, 'Ext.Loader#loaderPreprocessor', arguments);
|
|
// jshint ignore:line
|
|
var me = this,
|
|
dependencies = [],
|
|
dependency,
|
|
className = Manager.getName(cls),
|
|
i, j, ln, subLn, value, propertyName, propertyValue, requiredMap;
|
|
/*
|
|
Loop through the dependencyProperties, look for string class names and push
|
|
them into a stack, regardless of whether the property's value is a string, array or object. For example:
|
|
{
|
|
extend: 'Ext.MyClass',
|
|
requires: ['Ext.some.OtherClass'],
|
|
mixins: {
|
|
thing: 'Foo.bar.Thing';
|
|
}
|
|
}
|
|
which will later be transformed into:
|
|
{
|
|
extend: Ext.MyClass,
|
|
requires: [Ext.some.OtherClass],
|
|
mixins: {
|
|
thing: Foo.bar.Thing;
|
|
}
|
|
}
|
|
*/
|
|
for (i = 0 , ln = dependencyProperties.length; i < ln; i++) {
|
|
propertyName = dependencyProperties[i];
|
|
if (data.hasOwnProperty(propertyName)) {
|
|
propertyValue = data[propertyName];
|
|
if (typeof propertyValue === 'string') {
|
|
dependencies.push(propertyValue);
|
|
} else if (propertyValue instanceof Array) {
|
|
for (j = 0 , subLn = propertyValue.length; j < subLn; j++) {
|
|
value = propertyValue[j];
|
|
if (typeof value === 'string') {
|
|
dependencies.push(value);
|
|
}
|
|
}
|
|
} else if (typeof propertyValue !== 'function') {
|
|
for (j in propertyValue) {
|
|
if (propertyValue.hasOwnProperty(j)) {
|
|
value = propertyValue[j];
|
|
if (typeof value === 'string') {
|
|
dependencies.push(value);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (dependencies.length === 0) {
|
|
return;
|
|
}
|
|
if (className) {
|
|
_requiresMap[className] = dependencies;
|
|
}
|
|
var manifestClasses = Ext.manifest && Ext.manifest.classes,
|
|
deadlockPath = [],
|
|
detectDeadlock;
|
|
/*
|
|
* Automatically detect deadlocks before-hand,
|
|
* will throw an error with detailed path for ease of debugging. Examples
|
|
* of deadlock cases:
|
|
*
|
|
* - A extends B, then B extends A
|
|
* - A requires B, B requires C, then C requires A
|
|
*
|
|
* The detectDeadlock function will recursively transverse till the leaf, hence
|
|
* it can detect deadlocks no matter how deep the path is. However we don't need
|
|
* to run this check if the class name is in the manifest: that means Cmd has
|
|
* already resolved all dependencies for this class with no deadlocks.
|
|
*/
|
|
if (className && (!manifestClasses || !manifestClasses[className])) {
|
|
requiredMap = Loader.requiredByMap || (Loader.requiredByMap = {});
|
|
for (i = 0 , ln = dependencies.length; i < ln; i++) {
|
|
dependency = dependencies[i];
|
|
(requiredMap[dependency] || (requiredMap[dependency] = [])).push(className);
|
|
}
|
|
detectDeadlock = function(cls) {
|
|
deadlockPath.push(cls);
|
|
var requires = _requiresMap[cls],
|
|
dep, i, ln;
|
|
if (requires) {
|
|
if (Ext.Array.contains(requires, className)) {
|
|
Ext.Error.raise("Circular requirement detected! '" + className + "' and '" + deadlockPath[1] + "' mutually require each other. Path: " + deadlockPath.join(' -> ') + " -> " + deadlockPath[0]);
|
|
}
|
|
for (i = 0 , ln = requires.length; i < ln; i++) {
|
|
dep = requires[i];
|
|
if (!isInHistory[dep]) {
|
|
detectDeadlock(requires[i]);
|
|
}
|
|
}
|
|
}
|
|
};
|
|
detectDeadlock(className);
|
|
}
|
|
(className ? Loader.exclude(className) : Loader).require(dependencies, function() {
|
|
for (i = 0 , ln = dependencyProperties.length; i < ln; i++) {
|
|
propertyName = dependencyProperties[i];
|
|
if (data.hasOwnProperty(propertyName)) {
|
|
propertyValue = data[propertyName];
|
|
if (typeof propertyValue === 'string') {
|
|
data[propertyName] = Manager.get(propertyValue);
|
|
} else if (propertyValue instanceof Array) {
|
|
for (j = 0 , subLn = propertyValue.length; j < subLn; j++) {
|
|
value = propertyValue[j];
|
|
if (typeof value === 'string') {
|
|
data[propertyName][j] = Manager.get(value);
|
|
}
|
|
}
|
|
} else if (typeof propertyValue !== 'function') {
|
|
for (var k in propertyValue) {
|
|
if (propertyValue.hasOwnProperty(k)) {
|
|
value = propertyValue[k];
|
|
if (typeof value === 'string') {
|
|
data[propertyName][k] = Manager.get(value);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
continueFn.call(me, cls, data, hooks);
|
|
});
|
|
return false;
|
|
}, true, 'after', 'className');
|
|
/**
|
|
* @cfg {String[]} uses
|
|
* @member Ext.Class
|
|
* List of optional classes to load together with this class. These aren't neccessarily loaded before
|
|
* this class is created, but are guaranteed to be available before Ext.onReady listeners are
|
|
* invoked. For example:
|
|
*
|
|
* Ext.define('Mother', {
|
|
* uses: ['Child'],
|
|
* giveBirth: function() {
|
|
* // This code might, or might not work:
|
|
* // return new Child();
|
|
*
|
|
* // Instead use Ext.create() to load the class at the spot if not loaded already:
|
|
* return Ext.create('Child');
|
|
* }
|
|
* });
|
|
*/
|
|
Manager.registerPostprocessor('uses', function(name, cls, data) {
|
|
Ext.classSystemMonitor && Ext.classSystemMonitor(cls, 'Ext.Loader#usesPostprocessor', arguments);
|
|
// jshint ignore:line
|
|
var uses = data.uses,
|
|
classNames;
|
|
if (uses) {
|
|
classNames = Manager.getNamesByExpression(data.uses);
|
|
Loader.addUsedClasses(classNames);
|
|
}
|
|
});
|
|
Manager.onCreated(Loader.historyPush);
|
|
Loader.init();
|
|
}());
|
|
//-----------------------------------------------------------------------------
|
|
// Use performance.now when available to keep timestamps consistent.
|
|
Ext._endTime = Ext.ticks();
|
|
// This hook is to allow tools like DynaTrace to deterministically detect the availability
|
|
// of Ext.onReady. Since Loader takes over Ext.onReady this must be done here and not in
|
|
// Ext.env.Ready.
|
|
if (Ext._beforereadyhandler) {
|
|
Ext._beforereadyhandler();
|
|
}
|
|
|
|
/**
|
|
* @class Ext.util.Positionable
|
|
*/
|
|
Ext.define('Ext.overrides.util.Positionable', {
|
|
override: 'Ext.util.Positionable',
|
|
/**
|
|
* @method alignTo
|
|
* @param {Ext.util.Positionable/HTMLElement/String} anchorToEl The Positionable,
|
|
* HTMLElement, or id of the element to align to.
|
|
* @param {String} [alignment="tl-bl?"] The position to align to
|
|
* @param {Number[]} [offsets] Offset the positioning by [x, y]
|
|
* @param {Boolean/Object} [animate] true for the default animation or a standard
|
|
* Element animation config object
|
|
* @return {Ext.util.Positionable} this
|
|
*/
|
|
/**
|
|
* @method anchorTo
|
|
* Anchors an element to another element and realigns it when the window is resized.
|
|
* @param {Ext.util.Positionable/HTMLElement/String} anchorToEl The Positionable,
|
|
* HTMLElement, or id of the element to align to.
|
|
* @param {String} [alignment="tl-bl?"] The position to align to
|
|
* @param {Number[]} [offsets] Offset the positioning by [x, y]
|
|
* @param {Boolean/Object} [animate] true for the default animation or a standard
|
|
* Element animation config object
|
|
* @param {Boolean/Number} [monitorScroll=50] True to monitor body scroll and
|
|
* reposition. If this parameter is a number, it is used as the buffer delay in
|
|
* milliseconds.
|
|
* @param {Function} [callback] The function to call after the animation finishes
|
|
* @return {Ext.util.Positionable} this
|
|
*/
|
|
anchorTo: function(anchorToEl, alignment, offsets, animate, monitorScroll, callback) {
|
|
var me = this,
|
|
scroll = !Ext.isEmpty(monitorScroll),
|
|
action = function() {
|
|
me.mixins.positionable.alignTo.call(me, anchorToEl, alignment, offsets, animate);
|
|
Ext.callback(callback, me);
|
|
},
|
|
anchor = me.getAnchor();
|
|
// previous listener anchor, remove it
|
|
me.removeAnchor();
|
|
Ext.apply(anchor, {
|
|
fn: action,
|
|
scroll: scroll
|
|
});
|
|
Ext.on('resize', action, null);
|
|
if (scroll) {
|
|
Ext.getWin().on('scroll', action, null, {
|
|
buffer: !isNaN(monitorScroll) ? monitorScroll : 50
|
|
});
|
|
}
|
|
action();
|
|
// align immediately
|
|
return me;
|
|
},
|
|
getAnchor: function() {
|
|
var el = this.el,
|
|
data, anchor;
|
|
if (!el || !el.dom) {
|
|
return;
|
|
}
|
|
data = el.getData();
|
|
anchor = data._anchor;
|
|
if (!anchor) {
|
|
anchor = data._anchor = {};
|
|
}
|
|
return anchor;
|
|
},
|
|
alignTo: function(element, position, offsets, /* private (documented in ext) */
|
|
animate) {
|
|
var me = this,
|
|
el = me.el,
|
|
newMaxHeight, newRegion;
|
|
// Release any height constraint prior to aligning if we are shrinkwrap height.
|
|
if (me.isComponent && me.getSizeModel().height.shrinkWrap) {
|
|
if (me.maxHeight) {
|
|
me.setMaxHeight(null);
|
|
}
|
|
newMaxHeight = true;
|
|
}
|
|
newRegion = me.getAlignToRegion(element, position, offsets, me.minHeight || 150);
|
|
me.setXY([
|
|
newRegion.x,
|
|
newRegion.y
|
|
], el.anim && !!animate ? el.anim(animate) : false);
|
|
// Impose calculated height constraint.
|
|
if (newMaxHeight && (newMaxHeight = newRegion.getHeight()) !== me.getHeight()) {
|
|
me.setMaxHeight(newMaxHeight);
|
|
}
|
|
return me;
|
|
},
|
|
/**
|
|
* @method move
|
|
* Move the element relative to its current position.
|
|
* @param {String} direction Possible values are:
|
|
*
|
|
* - `"l"` (or `"left"`)
|
|
* - `"r"` (or `"right"`)
|
|
* - `"t"` (or `"top"`, or `"up"`)
|
|
* - `"b"` (or `"bottom"`, or `"down"`)
|
|
*
|
|
* @param {Number} distance How far to move the element in pixels
|
|
* @param {Boolean/Object} [animate] true for the default animation or a standard
|
|
* Element animation config object
|
|
*/
|
|
/**
|
|
* Remove any anchor to this element. See {@link #anchorTo}.
|
|
* @return {Ext.util.Positionable} this
|
|
*/
|
|
removeAnchor: function() {
|
|
var anchor = this.getAnchor();
|
|
if (anchor && anchor.fn) {
|
|
Ext.un('resize', anchor.fn);
|
|
if (anchor.scroll) {
|
|
Ext.getWin().on('scroll', anchor.fn);
|
|
}
|
|
delete anchor.fn;
|
|
}
|
|
return this;
|
|
},
|
|
/**
|
|
* @method setBox
|
|
* Sets the element's box. If animate is true then x, y, width, and height will be
|
|
* animated concurrently.
|
|
* @param {Object} box The box to fill {x, y, width, height}
|
|
* @param {Boolean/Object} [animate] true for the default animation or a standard
|
|
* Element animation config object
|
|
* @return {Ext.util.Positionable} this
|
|
*/
|
|
setBox: function(box, animate) {
|
|
var me = this;
|
|
if (box.isRegion) {
|
|
box = {
|
|
x: box.left,
|
|
y: box.top,
|
|
width: box.right - box.left,
|
|
height: box.bottom - box.top
|
|
};
|
|
}
|
|
if (animate) {
|
|
me.constrainBox(box);
|
|
me.animate(Ext.applyIf({
|
|
to: box,
|
|
listeners: {
|
|
afteranimate: Ext.Function.bind(me.afterSetPosition, me, [
|
|
box.x,
|
|
box.y
|
|
])
|
|
}
|
|
}, animate));
|
|
} else {
|
|
me.callParent([
|
|
box
|
|
]);
|
|
}
|
|
return me;
|
|
}
|
|
});
|
|
/**
|
|
* @method setX
|
|
* Sets the X position of the DOM element based on page coordinates.
|
|
* @param {Number} x The X position
|
|
* @param {Boolean/Object} [animate] True for the default animation, or a standard
|
|
* Element animation config object
|
|
* @return {Ext.util.Positionable} this
|
|
*/
|
|
/**
|
|
* @method setXY
|
|
* Sets the position of the DOM element in page coordinates.
|
|
* @param {Number[]} pos Contains X & Y [x, y] values for new position (coordinates
|
|
* are page-based)
|
|
* @param {Boolean/Object} [animate] True for the default animation, or a standard
|
|
* Element animation config object
|
|
* @return {Ext.util.Positionable} this
|
|
*/
|
|
/**
|
|
* @method setY
|
|
* Sets the Y position of the DOM element based on page coordinates.
|
|
* @param {Number} y The Y position
|
|
* @param {Boolean/Object} [animate] True for the default animation, or a standard
|
|
* Element animation config object
|
|
* @return {Ext.util.Positionable} this
|
|
*/
|
|
|
|
/**
|
|
* @class Ext.event.Event
|
|
*/
|
|
Ext.define('Ext.overrides.event.Event', {
|
|
override: 'Ext.event.Event',
|
|
// map of events that should fire global mousedown even if stopped
|
|
mousedownEvents: {
|
|
mousedown: 1,
|
|
pointerdown: 1,
|
|
touchstart: 1
|
|
},
|
|
/**
|
|
* @method injectEvent
|
|
* @member Ext.event.Event
|
|
* Injects a DOM event using the data in this object and (optionally) a new target.
|
|
* This is a low-level technique and not likely to be used by application code. The
|
|
* currently supported event types are:
|
|
* <p><b>HTMLEvents</b></p>
|
|
* <ul>
|
|
* <li>load</li>
|
|
* <li>unload</li>
|
|
* <li>select</li>
|
|
* <li>change</li>
|
|
* <li>submit</li>
|
|
* <li>reset</li>
|
|
* <li>resize</li>
|
|
* <li>scroll</li>
|
|
* </ul>
|
|
* <p><b>MouseEvents</b></p>
|
|
* <ul>
|
|
* <li>click</li>
|
|
* <li>dblclick</li>
|
|
* <li>mousedown</li>
|
|
* <li>mouseup</li>
|
|
* <li>mouseover</li>
|
|
* <li>mousemove</li>
|
|
* <li>mouseout</li>
|
|
* </ul>
|
|
* <p><b>UIEvents</b></p>
|
|
* <ul>
|
|
* <li>focusin</li>
|
|
* <li>focusout</li>
|
|
* <li>activate</li>
|
|
* <li>focus</li>
|
|
* <li>blur</li>
|
|
* </ul>
|
|
* @param {Ext.Element/HTMLElement} target (optional) If specified, the target for the event. This
|
|
* is likely to be used when relaying a DOM event. If not specified, {@link #getTarget}
|
|
* is used to determine the target.
|
|
*/
|
|
injectEvent: (function() {
|
|
var API,
|
|
dispatchers = {},
|
|
// keyed by event type (e.g., 'mousedown')
|
|
crazyIEButtons;
|
|
// Good reference: http://developer.yahoo.com/yui/docs/UserAction.js.html
|
|
// IE9 has createEvent, but this code causes major problems with htmleditor (it
|
|
// blocks all mouse events and maybe more). TODO
|
|
if (!Ext.isIE9m && document.createEvent) {
|
|
// if (DOM compliant)
|
|
API = {
|
|
createHtmlEvent: function(doc, type, bubbles, cancelable) {
|
|
var event = doc.createEvent('HTMLEvents');
|
|
event.initEvent(type, bubbles, cancelable);
|
|
return event;
|
|
},
|
|
createMouseEvent: function(doc, type, bubbles, cancelable, detail, clientX, clientY, ctrlKey, altKey, shiftKey, metaKey, button, relatedTarget) {
|
|
var event = doc.createEvent('MouseEvents'),
|
|
view = doc.defaultView || window;
|
|
if (event.initMouseEvent) {
|
|
event.initMouseEvent(type, bubbles, cancelable, view, detail, clientX, clientY, clientX, clientY, ctrlKey, altKey, shiftKey, metaKey, button, relatedTarget);
|
|
} else {
|
|
// old Safari
|
|
event = doc.createEvent('UIEvents');
|
|
event.initEvent(type, bubbles, cancelable);
|
|
event.view = view;
|
|
event.detail = detail;
|
|
event.screenX = clientX;
|
|
event.screenY = clientY;
|
|
event.clientX = clientX;
|
|
event.clientY = clientY;
|
|
event.ctrlKey = ctrlKey;
|
|
event.altKey = altKey;
|
|
event.metaKey = metaKey;
|
|
event.shiftKey = shiftKey;
|
|
event.button = button;
|
|
event.relatedTarget = relatedTarget;
|
|
}
|
|
return event;
|
|
},
|
|
createUIEvent: function(doc, type, bubbles, cancelable, detail) {
|
|
var event = doc.createEvent('UIEvents'),
|
|
view = doc.defaultView || window;
|
|
event.initUIEvent(type, bubbles, cancelable, view, detail);
|
|
return event;
|
|
},
|
|
fireEvent: function(target, type, event) {
|
|
target.dispatchEvent(event);
|
|
}
|
|
};
|
|
} else if (document.createEventObject) {
|
|
// else if (IE)
|
|
crazyIEButtons = {
|
|
0: 1,
|
|
1: 4,
|
|
2: 2
|
|
};
|
|
API = {
|
|
createHtmlEvent: function(doc, type, bubbles, cancelable) {
|
|
var event = doc.createEventObject();
|
|
event.bubbles = bubbles;
|
|
event.cancelable = cancelable;
|
|
return event;
|
|
},
|
|
createMouseEvent: function(doc, type, bubbles, cancelable, detail, clientX, clientY, ctrlKey, altKey, shiftKey, metaKey, button, relatedTarget) {
|
|
var event = doc.createEventObject();
|
|
event.bubbles = bubbles;
|
|
event.cancelable = cancelable;
|
|
event.detail = detail;
|
|
event.screenX = clientX;
|
|
event.screenY = clientY;
|
|
event.clientX = clientX;
|
|
event.clientY = clientY;
|
|
event.ctrlKey = ctrlKey;
|
|
event.altKey = altKey;
|
|
event.shiftKey = shiftKey;
|
|
event.metaKey = metaKey;
|
|
event.button = crazyIEButtons[button] || button;
|
|
event.relatedTarget = relatedTarget;
|
|
// cannot assign to/fromElement
|
|
return event;
|
|
},
|
|
createUIEvent: function(doc, type, bubbles, cancelable, detail) {
|
|
var event = doc.createEventObject();
|
|
event.bubbles = bubbles;
|
|
event.cancelable = cancelable;
|
|
return event;
|
|
},
|
|
fireEvent: function(target, type, event) {
|
|
target.fireEvent('on' + type, event);
|
|
}
|
|
};
|
|
}
|
|
//----------------
|
|
// HTMLEvents
|
|
Ext.Object.each({
|
|
load: [
|
|
false,
|
|
false
|
|
],
|
|
unload: [
|
|
false,
|
|
false
|
|
],
|
|
select: [
|
|
true,
|
|
false
|
|
],
|
|
change: [
|
|
true,
|
|
false
|
|
],
|
|
submit: [
|
|
true,
|
|
true
|
|
],
|
|
reset: [
|
|
true,
|
|
false
|
|
],
|
|
resize: [
|
|
true,
|
|
false
|
|
],
|
|
scroll: [
|
|
true,
|
|
false
|
|
]
|
|
}, function(name, value) {
|
|
var bubbles = value[0],
|
|
cancelable = value[1];
|
|
dispatchers[name] = function(targetEl, srcEvent) {
|
|
var e = API.createHtmlEvent(name, bubbles, cancelable);
|
|
API.fireEvent(targetEl, name, e);
|
|
};
|
|
});
|
|
//----------------
|
|
// MouseEvents
|
|
function createMouseEventDispatcher(type, detail) {
|
|
var cancelable = (type !== 'mousemove');
|
|
return function(targetEl, srcEvent) {
|
|
var xy = srcEvent.getXY(),
|
|
e = API.createMouseEvent(targetEl.ownerDocument, type, true, cancelable, detail, xy[0], xy[1], srcEvent.ctrlKey, srcEvent.altKey, srcEvent.shiftKey, srcEvent.metaKey, srcEvent.button, srcEvent.relatedTarget);
|
|
API.fireEvent(targetEl, type, e);
|
|
};
|
|
}
|
|
Ext.each([
|
|
'click',
|
|
'dblclick',
|
|
'mousedown',
|
|
'mouseup',
|
|
'mouseover',
|
|
'mousemove',
|
|
'mouseout'
|
|
], function(eventName) {
|
|
dispatchers[eventName] = createMouseEventDispatcher(eventName, 1);
|
|
});
|
|
//----------------
|
|
// UIEvents
|
|
Ext.Object.each({
|
|
focusin: [
|
|
true,
|
|
false
|
|
],
|
|
focusout: [
|
|
true,
|
|
false
|
|
],
|
|
activate: [
|
|
true,
|
|
true
|
|
],
|
|
focus: [
|
|
false,
|
|
false
|
|
],
|
|
blur: [
|
|
false,
|
|
false
|
|
]
|
|
}, function(name, value) {
|
|
var bubbles = value[0],
|
|
cancelable = value[1];
|
|
dispatchers[name] = function(targetEl, srcEvent) {
|
|
var e = API.createUIEvent(targetEl.ownerDocument, name, bubbles, cancelable, 1);
|
|
API.fireEvent(targetEl, name, e);
|
|
};
|
|
});
|
|
//---------
|
|
if (!API) {
|
|
// not even sure what ancient browsers fall into this category...
|
|
dispatchers = {};
|
|
// never mind all those we just built :P
|
|
API = {};
|
|
}
|
|
function cannotInject(target, srcEvent) {}
|
|
// TODO log something
|
|
return function(target) {
|
|
var me = this,
|
|
dispatcher = dispatchers[me.type] || cannotInject,
|
|
t = target ? (target.dom || target) : me.getTarget();
|
|
dispatcher(t, me);
|
|
};
|
|
}()),
|
|
// call to produce method
|
|
preventDefault: function(browserOnly) {
|
|
var me = this,
|
|
event = me.browserEvent,
|
|
parentEvent = me.parentEvent,
|
|
unselectable, target;
|
|
// This check is for IE8/9. The event object may have been
|
|
// invalidated, so we can't delve into the details of it. If so,
|
|
// just fall out gracefully and don't attempt to do anything.
|
|
if (typeof event.type !== 'unknown') {
|
|
// In some cases we want to prevent default on the browser event
|
|
// but keep propagating it through our event system. For example,
|
|
// in Checkbox selection where the cells with checkboxes should
|
|
// prevent focusing on mousedown but still fire the click event.
|
|
if (!browserOnly) {
|
|
me.defaultPrevented = true;
|
|
}
|
|
// if the event was created by prototype-chaining a new object to an existing event
|
|
// instance, we need to make sure the parent event is defaultPrevented as well.
|
|
if (parentEvent) {
|
|
parentEvent.defaultPrevented = true;
|
|
}
|
|
if (event.preventDefault) {
|
|
event.preventDefault();
|
|
} else {
|
|
// The purpose of the code below is for preventDefault to stop focus from
|
|
// occurring like it does in other modern browsers. This only happens in
|
|
// IE8/9 when using attachEvent. The use of unselectable seems the most reliable
|
|
// way to prevent this from happening. We need to use a timeout to restore the
|
|
// unselectable state because if we don't setting it has no effect. It's important
|
|
// to set the atrribute to 'on' as opposed to just setting the property on the DOM element.
|
|
// See the link below for a discussion on the issue:
|
|
// http://bugs.jquery.com/ticket/10345
|
|
if (event.type === 'mousedown') {
|
|
target = event.target;
|
|
unselectable = target.getAttribute('unselectable');
|
|
if (unselectable !== 'on') {
|
|
target.setAttribute('unselectable', 'on');
|
|
Ext.defer(function() {
|
|
target.setAttribute('unselectable', unselectable);
|
|
}, 1);
|
|
}
|
|
}
|
|
// IE9 and earlier do not support preventDefault
|
|
event.returnValue = false;
|
|
// Some keys events require setting the keyCode to -1 to be prevented
|
|
// all ctrl + X and F1 -> F12
|
|
if (event.ctrlKey || event.keyCode > 111 && event.keyCode < 124) {
|
|
event.keyCode = -1;
|
|
}
|
|
}
|
|
}
|
|
return me;
|
|
},
|
|
stopPropagation: function() {
|
|
var me = this,
|
|
event = me.browserEvent;
|
|
// This check is for IE8/9. The event object may have been
|
|
// invalidated, so we can't delve into the details of it. If so,
|
|
// just fall out gracefully and don't attempt to do anything.
|
|
if (typeof event.type !== 'unknown') {
|
|
if (me.mousedownEvents[me.type]) {
|
|
// Fire the "unstoppable" global mousedown event
|
|
// (used for menu hiding, etc)
|
|
Ext.GlobalEvents.fireMouseDown(me);
|
|
}
|
|
me.callParent();
|
|
}
|
|
return me;
|
|
},
|
|
deprecated: {
|
|
'5.0': {
|
|
methods: {
|
|
/**
|
|
* @method clone
|
|
* @member Ext.event.Event
|
|
* Clones this event.
|
|
* @return {Ext.event.Event} The cloned copy
|
|
* @deprecated 5.0.0
|
|
*/
|
|
clone: function() {
|
|
return new this.self(this.browserEvent, this);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}, function() {
|
|
var Event = this,
|
|
btnMap,
|
|
onKeyDown = function(e) {
|
|
if (e.keyCode === 9) {
|
|
Event.forwardTab = !e.shiftKey;
|
|
}
|
|
},
|
|
onKeyUp = function(e) {
|
|
if (e.keyCode === 9) {
|
|
delete Event.forwardTab;
|
|
}
|
|
};
|
|
if (Ext.isIE9m) {
|
|
btnMap = {
|
|
0: 0,
|
|
1: 0,
|
|
4: 1,
|
|
2: 2
|
|
};
|
|
Event.override({
|
|
statics: {
|
|
/**
|
|
* @member Ext.event.Event
|
|
* When events are attached using IE's attachEvent API instead of
|
|
* addEventListener accessing any members of an event object asynchronously
|
|
* results in "Member not found" error. To work around this we fabricate
|
|
* our own event object by copying all of its members to a new object.
|
|
* @param {Event} browserEvent The native browser event object
|
|
* @private
|
|
* @static
|
|
*/
|
|
enableIEAsync: function(browserEvent) {
|
|
var name,
|
|
fakeEvent = {};
|
|
for (name in browserEvent) {
|
|
fakeEvent[name] = browserEvent[name];
|
|
}
|
|
return fakeEvent;
|
|
}
|
|
},
|
|
constructor: function(event, info, touchesMap, identifiers) {
|
|
var me = this;
|
|
me.callParent([
|
|
event,
|
|
info,
|
|
touchesMap,
|
|
identifiers
|
|
]);
|
|
me.button = btnMap[event.button];
|
|
if (event.type === 'contextmenu') {
|
|
me.button = 2;
|
|
}
|
|
// IE8/9 reports click as 0, so we can at least attempt to infer here
|
|
// IE8 can throw an error when trying to access properties on a browserEvent
|
|
// object when the event has been buffered or delayed. Cache them here
|
|
// so we can access them later.
|
|
me.toElement = event.toElement;
|
|
me.fromElement = event.fromElement;
|
|
},
|
|
mouseLeaveRe: /(mouseout|mouseleave)/,
|
|
mouseEnterRe: /(mouseover|mouseenter)/,
|
|
/**
|
|
* @member Ext.event.Event
|
|
* @inheritdoc Ext.event.Event#static-enableIEAsync
|
|
* @private
|
|
*/
|
|
enableIEAsync: function(browserEvent) {
|
|
this.browserEvent = this.self.enableIEAsync(browserEvent);
|
|
},
|
|
getRelatedTarget: function(selector, maxDepth, returnEl) {
|
|
var me = this,
|
|
type, target;
|
|
if (!me.relatedTarget) {
|
|
type = me.type;
|
|
if (me.mouseLeaveRe.test(type)) {
|
|
target = me.toElement;
|
|
} else if (me.mouseEnterRe.test(type)) {
|
|
target = me.fromElement;
|
|
}
|
|
if (target) {
|
|
me.relatedTarget = me.self.resolveTextNode(target);
|
|
}
|
|
}
|
|
return me.callParent([
|
|
selector,
|
|
maxDepth,
|
|
returnEl
|
|
]);
|
|
}
|
|
});
|
|
// We place these listeners to capture Tab and Shift-Tab key strokes
|
|
// and pass this information in the focus/blur event if it happens
|
|
// between keydown/keyup pair.
|
|
document.attachEvent('onkeydown', onKeyDown);
|
|
document.attachEvent('onkeyup', onKeyUp);
|
|
window.attachEvent('onunload', function() {
|
|
document.detachEvent('onkeydown', onKeyDown);
|
|
document.detachEvent('onkeyup', onKeyUp);
|
|
});
|
|
} else if (document.addEventListener) {
|
|
document.addEventListener('keydown', onKeyDown, true);
|
|
document.addEventListener('keyup', onKeyUp, true);
|
|
}
|
|
});
|
|
|
|
Ext.define('Ext.overrides.event.publisher.Dom', {
|
|
override: 'Ext.event.publisher.Dom'
|
|
}, function(DomPublisher) {
|
|
if (Ext.isIE9m) {
|
|
var docElement = document.documentElement,
|
|
docBody = document.body,
|
|
prototype = DomPublisher.prototype,
|
|
onDirectEvent, onDirectCaptureEvent;
|
|
prototype.target = document;
|
|
prototype.directBoundListeners = {};
|
|
// This method gets bound to the element scope in addDirectListener so that
|
|
// the currentTarget can be captured using "this".
|
|
onDirectEvent = function(e, publisher, capture) {
|
|
e.target = e.srcElement || window;
|
|
e.currentTarget = this;
|
|
if (capture) {
|
|
// Although directly attached capture listeners are not supported in IE9m
|
|
// we still need to call the handler so at least the event fires.
|
|
publisher.onDirectCaptureEvent(e);
|
|
} else {
|
|
publisher.onDirectEvent(e);
|
|
}
|
|
};
|
|
onDirectCaptureEvent = function(e, publisher) {
|
|
e.target = e.srcElement || window;
|
|
e.currentTarget = this;
|
|
// this, not DomPublisher
|
|
publisher.onDirectCaptureEvent(e);
|
|
};
|
|
DomPublisher.override({
|
|
addDelegatedListener: function(eventName) {
|
|
this.delegatedListeners[eventName] = 1;
|
|
// Use attachEvent for IE9 and below. Even though IE9 strict supports
|
|
// addEventListener, it has issues with using synthetic events.
|
|
this.target.attachEvent('on' + eventName, this.onDelegatedEvent);
|
|
},
|
|
removeDelegatedListener: function(eventName) {
|
|
delete this.delegatedListeners[eventName];
|
|
this.target.detachEvent('on' + eventName, this.onDelegatedEvent);
|
|
},
|
|
addDirectListener: function(eventName, element, capture) {
|
|
var me = this,
|
|
dom = element.dom,
|
|
// binding the listener to the element allows us to capture the
|
|
// "currentTarget" (see onDirectEvent)
|
|
boundFn = Ext.Function.bind(onDirectEvent, dom, [
|
|
me,
|
|
capture
|
|
], true),
|
|
directBoundListeners = me.directBoundListeners,
|
|
handlers = directBoundListeners[eventName] || (directBoundListeners[eventName] = {});
|
|
handlers[dom.id] = boundFn;
|
|
// may be called with an SVG element here, which
|
|
// does not have the attachEvent method on IE 9 strict
|
|
if (dom.attachEvent) {
|
|
dom.attachEvent('on' + eventName, boundFn);
|
|
} else {
|
|
me.callParent([
|
|
eventName,
|
|
element,
|
|
capture
|
|
]);
|
|
}
|
|
},
|
|
removeDirectListener: function(eventName, element, capture) {
|
|
var dom = element.dom;
|
|
if (dom.detachEvent) {
|
|
dom.detachEvent('on' + eventName, this.directBoundListeners[eventName][dom.id]);
|
|
} else {
|
|
this.callParent([
|
|
eventName,
|
|
element,
|
|
capture
|
|
]);
|
|
}
|
|
},
|
|
doDelegatedEvent: function(e) {
|
|
e.target = e.srcElement || window;
|
|
if (e.type === 'focusin') {
|
|
// IE8 sometimes happen to focus <html> element instead of the body
|
|
e.relatedTarget = e.fromElement === docBody || e.fromElement === docElement ? null : e.fromElement;
|
|
} else if (e.type === 'focusout') {
|
|
e.relatedTarget = e.toElement === docBody || e.toElement === docElement ? null : e.toElement;
|
|
}
|
|
return this.callParent([
|
|
e
|
|
]);
|
|
}
|
|
});
|
|
// can't capture any events without addEventListener. Have to have direct
|
|
// listeners for every event that does not bubble.
|
|
Ext.apply(prototype.directEvents, prototype.captureEvents);
|
|
// These do not bubble in IE9m so have to attach direct listeners as well.
|
|
Ext.apply(prototype.directEvents, {
|
|
change: 1,
|
|
input: 1,
|
|
paste: 1
|
|
});
|
|
prototype.captureEvents = {};
|
|
}
|
|
});
|
|
|
|
Ext.define('Ext.overrides.event.publisher.Gesture', {
|
|
override: 'Ext.event.publisher.Gesture'
|
|
}, function() {
|
|
if (Ext.isIE9m) {
|
|
this.override({
|
|
updateTouches: function(e, isEnd) {
|
|
var browserEvent = e.browserEvent,
|
|
xy = e.getXY();
|
|
// I don't always set pageX and pageY on the event object, but when I do
|
|
// it's because the Gesture publisher expects an event object that has them.
|
|
browserEvent.pageX = xy[0];
|
|
browserEvent.pageY = xy[1];
|
|
this.callParent([
|
|
e,
|
|
isEnd
|
|
]);
|
|
},
|
|
doDelegatedEvent: function(e) {
|
|
// Workaround IE's "Member not found" errors when accessing an event
|
|
// object asynchronously. Needed for all gesture handlers because
|
|
// they use requestAnimationFrame (see enableIEAsync for more details)
|
|
this.callParent([
|
|
Ext.event.Event.enableIEAsync(e)
|
|
]);
|
|
}
|
|
});
|
|
}
|
|
});
|
|
|
|
/**
|
|
* @class Ext.dom.Element
|
|
* @override Ext.dom.Element
|
|
*/
|
|
Ext.define('Ext.overrides.dom.Element', (function() {
|
|
var Element,
|
|
// we cannot do this yet "= Ext.dom.Element"
|
|
WIN = window,
|
|
DOC = document,
|
|
HIDDEN = 'hidden',
|
|
ISCLIPPED = 'isClipped',
|
|
OVERFLOW = 'overflow',
|
|
OVERFLOWX = 'overflow-x',
|
|
OVERFLOWY = 'overflow-y',
|
|
ORIGINALCLIP = 'originalClip',
|
|
HEIGHT = 'height',
|
|
WIDTH = 'width',
|
|
VISIBILITY = 'visibility',
|
|
DISPLAY = 'display',
|
|
NONE = 'none',
|
|
OFFSETS = 'offsets',
|
|
CLIP = 'clip',
|
|
ORIGINALDISPLAY = 'originalDisplay',
|
|
VISMODE = 'visibilityMode',
|
|
ISVISIBLE = 'isVisible',
|
|
OFFSETCLASS = Ext.baseCSSPrefix + 'hidden-offsets',
|
|
CLIPCLASS = Ext.baseCSSPrefix + 'hidden-clip',
|
|
boxMarkup = [
|
|
'<div class="{0}-tl" role="presentation">',
|
|
'<div class="{0}-tr" role="presentation">',
|
|
'<div class="{0}-tc" role="presentation"></div>',
|
|
'</div>',
|
|
'</div>',
|
|
'<div class="{0}-ml" role="presentation">',
|
|
'<div class="{0}-mr" role="presentation">',
|
|
'<div class="{0}-mc" role="presentation"></div>',
|
|
'</div>',
|
|
'</div>',
|
|
'<div class="{0}-bl" role="presentation">',
|
|
'<div class="{0}-br" role="presentation">',
|
|
'<div class="{0}-bc" role="presentation"></div>',
|
|
'</div>',
|
|
'</div>'
|
|
].join(''),
|
|
scriptTagRe = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig,
|
|
replaceScriptTagRe = /(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig,
|
|
srcRe = /\ssrc=([\'\"])(.*?)\1/i,
|
|
nonSpaceRe = /\S/,
|
|
typeRe = /\stype=([\'\"])(.*?)\1/i,
|
|
msRe = /^-ms-/,
|
|
camelRe = /(-[a-z])/gi,
|
|
camelReplaceFn = function(m, a) {
|
|
return a.charAt(1).toUpperCase();
|
|
},
|
|
XMASKED = Ext.baseCSSPrefix + "masked",
|
|
XMASKEDRELATIVE = Ext.baseCSSPrefix + "masked-relative",
|
|
EXTELMASKMSG = Ext.baseCSSPrefix + "mask-msg",
|
|
bodyRe = /^body/i,
|
|
propertyCache = {},
|
|
getVisMode = function(el) {
|
|
var data = el.getData(),
|
|
visMode = data[VISMODE];
|
|
if (visMode === undefined) {
|
|
data[VISMODE] = visMode = Element.VISIBILITY;
|
|
}
|
|
return visMode;
|
|
},
|
|
emptyRange = DOC.createRange ? DOC.createRange() : null,
|
|
inputTags = {
|
|
INPUT: true,
|
|
TEXTAREA: true
|
|
};
|
|
if (Ext.isIE8) {
|
|
var garbageBin = DOC.createElement('div'),
|
|
destroyQueue = [],
|
|
// prevent memory leaks in IE8
|
|
// see http://social.msdn.microsoft.com/Forums/ie/en-US/c76967f0-dcf8-47d0-8984-8fe1282a94f5/ie-appendchildremovechild-memory-problem?forum=iewebdevelopment
|
|
// This function is called to fully destroy an element on a timer so that code following the
|
|
// remove call can still access the element.
|
|
clearGarbage = Ext.Function.createBuffered(function() {
|
|
var len = destroyQueue.length,
|
|
i;
|
|
for (i = 0; i < len; i++) {
|
|
garbageBin.appendChild(destroyQueue[i]);
|
|
}
|
|
garbageBin.innerHTML = '';
|
|
destroyQueue.length = 0;
|
|
}, 10);
|
|
}
|
|
return {
|
|
override: 'Ext.dom.Element',
|
|
mixins: [
|
|
'Ext.util.Animate'
|
|
],
|
|
uses: [
|
|
'Ext.dom.GarbageCollector',
|
|
'Ext.dom.Fly',
|
|
'Ext.event.publisher.MouseEnterLeave',
|
|
'Ext.fx.Manager',
|
|
'Ext.fx.Anim'
|
|
],
|
|
skipGarbageCollection: false,
|
|
_init: function(E) {
|
|
Element = E;
|
|
// now we can poke this into closure scope
|
|
// We want to expose destroyQueue on the prototype for testing purposes
|
|
if (WIN.__UNIT_TESTING__) {
|
|
E.destroyQueue = destroyQueue;
|
|
}
|
|
// Allow overriding the attribute name and/or selector; this is
|
|
// done only once for performance reasons
|
|
E.tabbableSelector += ',[' + E.tabbableSavedCounterAttribute + ']';
|
|
},
|
|
statics: {
|
|
selectableCls: Ext.baseCSSPrefix + 'selectable',
|
|
unselectableCls: Ext.baseCSSPrefix + 'unselectable',
|
|
// This selector will be modified at runtime in the _init() method above
|
|
// to include the elements with saved tabindex in the returned set
|
|
tabbableSelector: Ext.supports.CSS3NegationSelector ? 'a[href],button,iframe,input,select,textarea,[tabindex]:not([tabindex="-1"]),[contenteditable="true"]' : 'a[href],button,iframe,input,select,textarea,[tabindex],[contenteditable="true"]',
|
|
// Anchor and link tags are special; they are only naturally focusable (and tabbable)
|
|
// if they have href attribute, and tabbabledness is further platform/browser specific.
|
|
// Thus we check it separately in the code.
|
|
naturallyFocusableTags: {
|
|
BUTTON: true,
|
|
IFRAME: true,
|
|
EMBED: true,
|
|
INPUT: true,
|
|
OBJECT: true,
|
|
SELECT: true,
|
|
TEXTAREA: true,
|
|
HTML: Ext.isIE ? true : false,
|
|
BODY: Ext.isIE ? false : true
|
|
},
|
|
// <object> element is naturally tabbable only in IE8 and below
|
|
naturallyTabbableTags: {
|
|
BUTTON: true,
|
|
IFRAME: true,
|
|
INPUT: true,
|
|
SELECT: true,
|
|
TEXTAREA: true,
|
|
OBJECT: Ext.isIE8m ? true : false
|
|
},
|
|
tabbableSavedCounterAttribute: 'data-tabindex-counter',
|
|
tabbableSavedValueAttribute: 'data-tabindex-value',
|
|
normalize: function(prop) {
|
|
if (prop === 'float') {
|
|
prop = Ext.supports.Float ? 'cssFloat' : 'styleFloat';
|
|
}
|
|
// For '-ms-foo' we need msFoo
|
|
return propertyCache[prop] || (propertyCache[prop] = prop.replace(msRe, 'ms-').replace(camelRe, camelReplaceFn));
|
|
}
|
|
},
|
|
/**
|
|
* Convenience method for constructing a KeyMap
|
|
* @param {String/Number/Number[]/Object} key Either a string with the keys to listen for, the numeric key code,
|
|
* array of key codes or an object with the following options:
|
|
* @param {Number/Array} key.key
|
|
* @param {Boolean} key.shift
|
|
* @param {Boolean} key.ctrl
|
|
* @param {Boolean} key.alt
|
|
* @param {Function} fn The function to call
|
|
* @param {Object} [scope] The scope (`this` reference) in which the specified function is executed. Defaults to this Element.
|
|
* @return {Ext.util.KeyMap} The KeyMap created
|
|
*/
|
|
addKeyListener: function(key, fn, scope) {
|
|
var config;
|
|
if (typeof key !== 'object' || Ext.isArray(key)) {
|
|
config = {
|
|
target: this,
|
|
key: key,
|
|
fn: fn,
|
|
scope: scope
|
|
};
|
|
} else {
|
|
config = {
|
|
target: this,
|
|
key: key.key,
|
|
shift: key.shift,
|
|
ctrl: key.ctrl,
|
|
alt: key.alt,
|
|
fn: fn,
|
|
scope: scope
|
|
};
|
|
}
|
|
return new Ext.util.KeyMap(config);
|
|
},
|
|
/**
|
|
* Creates a KeyMap for this element
|
|
* @param {Object} config The KeyMap config. See {@link Ext.util.KeyMap} for more details
|
|
* @return {Ext.util.KeyMap} The KeyMap created
|
|
*/
|
|
addKeyMap: function(config) {
|
|
return new Ext.util.KeyMap(Ext.apply({
|
|
target: this
|
|
}, config));
|
|
},
|
|
/**
|
|
* @private
|
|
*/
|
|
afterAnimate: function() {
|
|
var shadow = this.shadow;
|
|
if (shadow && !shadow.disabled && !shadow.animate) {
|
|
shadow.show();
|
|
}
|
|
},
|
|
/**
|
|
* @private
|
|
*/
|
|
anchorAnimX: function(anchor) {
|
|
var xName = (anchor === 'l') ? 'right' : 'left';
|
|
this.dom.style[xName] = '0px';
|
|
},
|
|
/**
|
|
* @private
|
|
* process the passed fx configuration.
|
|
*/
|
|
anim: function(config) {
|
|
if (!Ext.isObject(config)) {
|
|
return (config) ? {} : false;
|
|
}
|
|
var me = this,
|
|
duration = config.duration || Ext.fx.Anim.prototype.duration,
|
|
easing = config.easing || 'ease',
|
|
animConfig;
|
|
if (config.stopAnimation) {
|
|
me.stopAnimation();
|
|
}
|
|
Ext.applyIf(config, Ext.fx.Manager.getFxDefaults(me.id));
|
|
// Clear any 'paused' defaults.
|
|
Ext.fx.Manager.setFxDefaults(me.id, {
|
|
delay: 0
|
|
});
|
|
animConfig = {
|
|
// Pass the DOM reference. That's tested first so will be converted to an Ext.fx.Target fastest.
|
|
target: me.dom,
|
|
remove: config.remove,
|
|
alternate: config.alternate || false,
|
|
duration: duration,
|
|
easing: easing,
|
|
callback: config.callback,
|
|
listeners: config.listeners,
|
|
iterations: config.iterations || 1,
|
|
scope: config.scope,
|
|
block: config.block,
|
|
concurrent: config.concurrent,
|
|
delay: config.delay || 0,
|
|
paused: true,
|
|
keyframes: config.keyframes,
|
|
from: config.from || {},
|
|
to: Ext.apply({}, config),
|
|
userConfig: config
|
|
};
|
|
Ext.apply(animConfig.to, config.to);
|
|
// Anim API properties - backward compat
|
|
delete animConfig.to.to;
|
|
delete animConfig.to.from;
|
|
delete animConfig.to.remove;
|
|
delete animConfig.to.alternate;
|
|
delete animConfig.to.keyframes;
|
|
delete animConfig.to.iterations;
|
|
delete animConfig.to.listeners;
|
|
delete animConfig.to.target;
|
|
delete animConfig.to.paused;
|
|
delete animConfig.to.callback;
|
|
delete animConfig.to.scope;
|
|
delete animConfig.to.duration;
|
|
delete animConfig.to.easing;
|
|
delete animConfig.to.concurrent;
|
|
delete animConfig.to.block;
|
|
delete animConfig.to.stopAnimation;
|
|
delete animConfig.to.delay;
|
|
return animConfig;
|
|
},
|
|
/**
|
|
* Calls `{@link #addAnimation}` and returns this Element (for call chaining). For
|
|
* details, see `{@link #addAnimation}`.
|
|
*
|
|
* @param {Object} config Configuration for {@link Ext.fx.Anim}.
|
|
* Note that the {@link Ext.fx.Anim#to to} config is required.
|
|
* @return {Ext.dom.Element} this
|
|
*/
|
|
animate: function(config) {
|
|
this.addAnimation(config);
|
|
return this;
|
|
},
|
|
/**
|
|
* Starts a custom animation on this Element.
|
|
*
|
|
* The following properties may be specified in `from`, `to`, and `keyframe` objects:
|
|
*
|
|
* - `x` - The page X position in pixels.
|
|
* - `y` - The page Y position in pixels
|
|
* - `left` - The element's CSS `left` value. Units must be supplied.
|
|
* - `top` - The element's CSS `top` value. Units must be supplied.
|
|
* - `width` - The element's CSS `width` value. Units must be supplied.
|
|
* - `height` - The element's CSS `height` value. Units must be supplied.
|
|
* - `scrollLeft` - The element's `scrollLeft` value.
|
|
* - `scrollTop` - The element's `scrollTop` value.
|
|
* - `opacity` - The element's `opacity` value (between `0` and `1`).
|
|
*
|
|
* **Be aware** that animating an Element which is being used by an Ext Component
|
|
* without in some way informing the Component about the changed element state will
|
|
* result in incorrect Component behaviour. This is because the Component will be
|
|
* using the old state of the element. To avoid this problem, it is now possible
|
|
* to directly animate certain properties of Components.
|
|
*
|
|
* @param {Object} config Configuration for {@link Ext.fx.Anim}.
|
|
* Note that the {@link Ext.fx.Anim#to to} config is required.
|
|
* @return {Ext.fx.Anim} The new animation.
|
|
*/
|
|
addAnimation: function(config) {
|
|
var me = this,
|
|
animId = me.dom.id || Ext.id(me.dom),
|
|
listeners, anim, end;
|
|
if (!Ext.fx.Manager.hasFxBlock(animId)) {
|
|
// Bit of gymnastics here to ensure our internal listeners get bound first
|
|
if (config.listeners) {
|
|
listeners = config.listeners;
|
|
delete config.listeners;
|
|
}
|
|
if (config.internalListeners) {
|
|
config.listeners = config.internalListeners;
|
|
delete config.internalListeners;
|
|
}
|
|
end = config.autoEnd;
|
|
delete config.autoEnd;
|
|
anim = new Ext.fx.Anim(me.anim(config));
|
|
anim.on({
|
|
afteranimate: 'afterAnimate',
|
|
beforeanimate: 'beforeAnimate',
|
|
scope: me,
|
|
single: true
|
|
});
|
|
if (listeners) {
|
|
anim.on(listeners);
|
|
}
|
|
Ext.fx.Manager.queueFx(anim);
|
|
if (end) {
|
|
anim.jumpToEnd();
|
|
}
|
|
}
|
|
return anim;
|
|
},
|
|
/**
|
|
* @private
|
|
*/
|
|
beforeAnimate: function() {
|
|
var shadow = this.shadow;
|
|
if (shadow && !shadow.disabled && !shadow.animate) {
|
|
shadow.hide();
|
|
}
|
|
},
|
|
/**
|
|
* Wraps the specified element with a special 9 element markup/CSS block that renders by default as
|
|
* a gray container with a gradient background, rounded corners and a 4-way shadow.
|
|
*
|
|
* This special markup is used throughout Ext when box wrapping elements ({@link Ext.button.Button},
|
|
* {@link Ext.panel.Panel} when {@link Ext.panel.Panel#frame frame=true}, {@link Ext.window.Window}).
|
|
* The markup is of this form:
|
|
*
|
|
* <div class="{0}-tl"><div class="{0}-tr"><div class="{0}-tc"></div></div></div>
|
|
* <div class="{0}-ml"><div class="{0}-mr"><div class="{0}-mc"></div></div></div>
|
|
* <div class="{0}-bl"><div class="{0}-br"><div class="{0}-bc"></div></div></div>
|
|
*
|
|
* Example usage:
|
|
*
|
|
* // Basic box wrap
|
|
* Ext.get("foo").boxWrap();
|
|
*
|
|
* // You can also add a custom class and use CSS inheritance rules to customize the box look.
|
|
* // 'x-box-blue' is a built-in alternative -- look at the related CSS definitions as an example
|
|
* // for how to create a custom box wrap style.
|
|
* Ext.get("foo").boxWrap().addCls("x-box-blue");
|
|
*
|
|
* @param {String} [class='x-box'] A base CSS class to apply to the containing wrapper element.
|
|
* Note that there are a number of CSS rules that are dependent on this name to make the overall effect work,
|
|
* so if you supply an alternate base class, make sure you also supply all of the necessary rules.
|
|
* @return {Ext.dom.Element} The outermost wrapping element of the created box structure.
|
|
*/
|
|
boxWrap: function(cls) {
|
|
cls = cls || Ext.baseCSSPrefix + 'box';
|
|
var el = Ext.get(this.insertHtml("beforeBegin", "<div class='" + cls + "' role='presentation'>" + Ext.String.format(boxMarkup, cls) + "</div>"));
|
|
el.selectNode('.' + cls + '-mc').appendChild(this.dom);
|
|
return el;
|
|
},
|
|
/**
|
|
* Removes Empty, or whitespace filled text nodes. Combines adjacent text nodes.
|
|
* @param {Boolean} [forceReclean=false] By default the element keeps track if it has been cleaned already
|
|
* so you can call this over and over. However, if you update the element and need to force a re-clean, you
|
|
* can pass true.
|
|
*/
|
|
clean: function(forceReclean) {
|
|
var me = this,
|
|
dom = me.dom,
|
|
data = me.getData(),
|
|
n = dom.firstChild,
|
|
ni = -1,
|
|
nx;
|
|
if (data.isCleaned && forceReclean !== true) {
|
|
return me;
|
|
}
|
|
while (n) {
|
|
nx = n.nextSibling;
|
|
if (n.nodeType === 3) {
|
|
// Remove empty/whitespace text nodes
|
|
if (!(nonSpaceRe.test(n.nodeValue))) {
|
|
dom.removeChild(n);
|
|
}
|
|
// Combine adjacent text nodes
|
|
else if (nx && nx.nodeType === 3) {
|
|
n.appendData(Ext.String.trim(nx.data));
|
|
dom.removeChild(nx);
|
|
nx = n.nextSibling;
|
|
n.nodeIndex = ++ni;
|
|
}
|
|
} else {
|
|
// Recursively clean
|
|
Ext.fly(n, '_clean').clean();
|
|
n.nodeIndex = ++ni;
|
|
}
|
|
n = nx;
|
|
}
|
|
data.isCleaned = true;
|
|
return me;
|
|
},
|
|
/**
|
|
* Empties this element. Removes all child nodes.
|
|
*/
|
|
empty: emptyRange ? function() {
|
|
var dom = this.dom;
|
|
if (dom.firstChild) {
|
|
emptyRange.setStartBefore(dom.firstChild);
|
|
emptyRange.setEndAfter(dom.lastChild);
|
|
emptyRange.deleteContents();
|
|
}
|
|
} : function() {
|
|
var dom = this.dom;
|
|
while (dom.lastChild) {
|
|
dom.removeChild(dom.lastChild);
|
|
}
|
|
},
|
|
clearListeners: function() {
|
|
this.removeAnchor();
|
|
this.callParent();
|
|
},
|
|
/**
|
|
* Clears positioning back to the default when the document was loaded.
|
|
* @param {String} [value=''] The value to use for the left, right, top, bottom.
|
|
* You could use 'auto'.
|
|
* @return {Ext.dom.Element} this
|
|
*/
|
|
clearPositioning: function(value) {
|
|
value = value || '';
|
|
return this.setStyle({
|
|
left: value,
|
|
right: value,
|
|
top: value,
|
|
bottom: value,
|
|
'z-index': '',
|
|
position: 'static'
|
|
});
|
|
},
|
|
/**
|
|
* Creates a proxy element of this element
|
|
* @param {String/Object} config The class name of the proxy element or a DomHelper config object
|
|
* @param {String/HTMLElement} [renderTo] The element or element id to render the proxy to. Defaults to: document.body.
|
|
* @param {Boolean} [matchBox=false] True to align and size the proxy to this element now.
|
|
* @return {Ext.dom.Element} The new proxy element
|
|
*/
|
|
createProxy: function(config, renderTo, matchBox) {
|
|
config = (typeof config === 'object') ? config : {
|
|
tag: "div",
|
|
role: 'presentation',
|
|
cls: config
|
|
};
|
|
var me = this,
|
|
proxy = renderTo ? Ext.DomHelper.append(renderTo, config, true) : Ext.DomHelper.insertBefore(me.dom, config, true);
|
|
proxy.setVisibilityMode(Element.DISPLAY);
|
|
proxy.hide();
|
|
if (matchBox && me.setBox && me.getBox) {
|
|
// check to make sure Element_position.js is loaded
|
|
proxy.setBox(me.getBox());
|
|
}
|
|
return proxy;
|
|
},
|
|
/**
|
|
* Clears any opacity settings from this element. Required in some cases for IE.
|
|
* @return {Ext.dom.Element} this
|
|
*/
|
|
clearOpacity: function() {
|
|
return this.setOpacity('');
|
|
},
|
|
/**
|
|
* Store the current overflow setting and clip overflow on the element - use {@link #unclip} to remove
|
|
* @return {Ext.dom.Element} this
|
|
*/
|
|
clip: function() {
|
|
var me = this,
|
|
data = me.getData(),
|
|
style;
|
|
if (!data[ISCLIPPED]) {
|
|
data[ISCLIPPED] = true;
|
|
style = me.getStyle([
|
|
OVERFLOW,
|
|
OVERFLOWX,
|
|
OVERFLOWY
|
|
]);
|
|
data[ORIGINALCLIP] = {
|
|
o: style[OVERFLOW],
|
|
x: style[OVERFLOWX],
|
|
y: style[OVERFLOWY]
|
|
};
|
|
me.setStyle(OVERFLOW, HIDDEN);
|
|
me.setStyle(OVERFLOWX, HIDDEN);
|
|
me.setStyle(OVERFLOWY, HIDDEN);
|
|
}
|
|
return me;
|
|
},
|
|
destroy: function() {
|
|
var me = this,
|
|
dom = me.dom,
|
|
data = me.getData(),
|
|
maskEl, maskMsg;
|
|
if (dom) {
|
|
if (me.isAnimate) {
|
|
me.stopAnimation();
|
|
}
|
|
me.removeAnchor();
|
|
}
|
|
me.callParent();
|
|
// prevent memory leaks in IE8
|
|
// see http://social.msdn.microsoft.com/Forums/ie/en-US/c76967f0-dcf8-47d0-8984-8fe1282a94f5/ie-appendchildremovechild-memory-problem?forum=iewebdevelopment
|
|
// must not be document, documentElement, body or window object
|
|
// Have to use != instead of !== for IE8 or it will not recognize that the window
|
|
// objects are equal
|
|
if (dom && Ext.isIE8 && (dom.window != dom) && (dom.nodeType !== 9) && (dom.tagName !== 'BODY') && (dom.tagName !== 'HTML')) {
|
|
destroyQueue[destroyQueue.length] = dom;
|
|
// Will perform extra IE8 cleanup in 10 milliseconds
|
|
// see http://social.msdn.microsoft.com/Forums/ie/en-US/c76967f0-dcf8-47d0-8984-8fe1282a94f5/ie-appendchildremovechild-memory-problem?forum=iewebdevelopment
|
|
clearGarbage();
|
|
}
|
|
if (data) {
|
|
maskEl = data.maskEl;
|
|
maskMsg = data.maskMsg;
|
|
if (maskEl) {
|
|
maskEl.destroy();
|
|
}
|
|
if (maskMsg) {
|
|
maskMsg.destroy();
|
|
}
|
|
}
|
|
},
|
|
/**
|
|
* Convenience method for setVisibilityMode(Element.DISPLAY).
|
|
* @param {String} [display] What to set display to when visible
|
|
* @return {Ext.dom.Element} this
|
|
*/
|
|
enableDisplayMode: function(display) {
|
|
var me = this;
|
|
me.setVisibilityMode(Element.DISPLAY);
|
|
if (display !== undefined) {
|
|
me.getData()[ORIGINALDISPLAY] = display;
|
|
}
|
|
return me;
|
|
},
|
|
/**
|
|
* Fade an element in (from transparent to opaque). The ending opacity can be specified using the `opacity`
|
|
* config option. Usage:
|
|
*
|
|
* // default: fade in from opacity 0 to 100%
|
|
* el.fadeIn();
|
|
*
|
|
* // custom: fade in from opacity 0 to 75% over 2 seconds
|
|
* el.fadeIn({ opacity: .75, duration: 2000});
|
|
*
|
|
* // common config options shown with default values
|
|
* el.fadeIn({
|
|
* opacity: 1, //can be any value between 0 and 1 (e.g. .5)
|
|
* easing: 'easeOut',
|
|
* duration: 500
|
|
* });
|
|
*
|
|
* @param {Object} options (optional) Object literal with any of the {@link Ext.fx.Anim} config options
|
|
* @return {Ext.dom.Element} The Element
|
|
*/
|
|
fadeIn: function(o) {
|
|
var me = this,
|
|
dom = me.dom;
|
|
me.animate(Ext.apply({}, o, {
|
|
opacity: 1,
|
|
internalListeners: {
|
|
beforeanimate: function(anim) {
|
|
// restore any visibility/display that may have
|
|
// been applied by a fadeout animation
|
|
var el = Ext.fly(dom, '_anim');
|
|
if (el.isStyle('display', 'none')) {
|
|
el.setDisplayed('');
|
|
} else {
|
|
el.show();
|
|
}
|
|
}
|
|
}
|
|
}));
|
|
return this;
|
|
},
|
|
/**
|
|
* Fade an element out (from opaque to transparent). The ending opacity can be specified using the `opacity`
|
|
* config option. Note that IE may require `useDisplay:true` in order to redisplay correctly.
|
|
* Usage:
|
|
*
|
|
* // default: fade out from the element's current opacity to 0
|
|
* el.fadeOut();
|
|
*
|
|
* // custom: fade out from the element's current opacity to 25% over 2 seconds
|
|
* el.fadeOut({ opacity: .25, duration: 2000});
|
|
*
|
|
* // common config options shown with default values
|
|
* el.fadeOut({
|
|
* opacity: 0, //can be any value between 0 and 1 (e.g. .5)
|
|
* easing: 'easeOut',
|
|
* duration: 500,
|
|
* remove: false,
|
|
* useDisplay: false
|
|
* });
|
|
*
|
|
* @param {Object} options (optional) Object literal with any of the {@link Ext.fx.Anim} config options
|
|
* @return {Ext.dom.Element} The Element
|
|
*/
|
|
fadeOut: function(o) {
|
|
var me = this,
|
|
dom = me.dom;
|
|
o = Ext.apply({
|
|
opacity: 0,
|
|
internalListeners: {
|
|
afteranimate: function(anim) {
|
|
if (dom && anim.to.opacity === 0) {
|
|
var el = Ext.fly(dom, '_anim');
|
|
if (o.useDisplay) {
|
|
el.setDisplayed(false);
|
|
} else {
|
|
el.hide();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}, o);
|
|
me.animate(o);
|
|
return me;
|
|
},
|
|
/**
|
|
* @private
|
|
*/
|
|
fixDisplay: function() {
|
|
var me = this;
|
|
if (me.isStyle(DISPLAY, NONE)) {
|
|
me.setStyle(VISIBILITY, HIDDEN);
|
|
me.setStyle(DISPLAY, me._getDisplay());
|
|
// first try reverting to default
|
|
if (me.isStyle(DISPLAY, NONE)) {
|
|
// if that fails, default to block
|
|
me.setStyle(DISPLAY, "block");
|
|
}
|
|
}
|
|
},
|
|
/**
|
|
* Shows a ripple of exploding, attenuating borders to draw attention to an Element. Usage:
|
|
*
|
|
* // default: a single light blue ripple
|
|
* el.frame();
|
|
*
|
|
* // custom: 3 red ripples lasting 3 seconds total
|
|
* el.frame("#ff0000", 3, { duration: 3000 });
|
|
*
|
|
* // common config options shown with default values
|
|
* el.frame("#C3DAF9", 1, {
|
|
* duration: 1000 // duration of each individual ripple.
|
|
* // Note: Easing is not configurable and will be ignored if included
|
|
* });
|
|
*
|
|
* @param {String} [color='#C3DAF9'] The hex color value for the border.
|
|
* @param {Number} [count=1] The number of ripples to display.
|
|
* @param {Object} [options] Object literal with any of the {@link Ext.fx.Anim} config options
|
|
* @return {Ext.dom.Element} The Element
|
|
*/
|
|
frame: function(color, count, obj) {
|
|
var me = this,
|
|
dom = me.dom,
|
|
beforeAnim;
|
|
color = color || '#C3DAF9';
|
|
count = count || 1;
|
|
obj = obj || {};
|
|
beforeAnim = function() {
|
|
var el = Ext.fly(dom, '_anim'),
|
|
animScope = this,
|
|
box, proxy, proxyAnim;
|
|
el.show();
|
|
box = el.getBox();
|
|
proxy = Ext.getBody().createChild({
|
|
role: 'presentation',
|
|
id: el.dom.id + '-anim-proxy',
|
|
style: {
|
|
position: 'absolute',
|
|
'pointer-events': 'none',
|
|
'z-index': 35000,
|
|
border: '0px solid ' + color
|
|
}
|
|
});
|
|
proxyAnim = new Ext.fx.Anim({
|
|
target: proxy,
|
|
duration: obj.duration || 1000,
|
|
iterations: count,
|
|
from: {
|
|
top: box.y,
|
|
left: box.x,
|
|
borderWidth: 0,
|
|
opacity: 1,
|
|
height: box.height,
|
|
width: box.width
|
|
},
|
|
to: {
|
|
top: box.y - 20,
|
|
left: box.x - 20,
|
|
borderWidth: 10,
|
|
opacity: 0,
|
|
height: box.height + 40,
|
|
width: box.width + 40
|
|
}
|
|
});
|
|
proxyAnim.on('afteranimate', function() {
|
|
proxy.destroy();
|
|
// kill the no-op element animation created below
|
|
animScope.end();
|
|
});
|
|
};
|
|
me.animate({
|
|
// See "A Note About Wrapped Animations" at the top of this class:
|
|
duration: (Math.max(obj.duration, 500) * 2) || 2000,
|
|
listeners: {
|
|
beforeanimate: {
|
|
fn: beforeAnim
|
|
}
|
|
},
|
|
callback: obj.callback,
|
|
scope: obj.scope
|
|
});
|
|
return me;
|
|
},
|
|
/**
|
|
* Return the CSS color for the specified CSS attribute. rgb, 3 digit (like `#fff`)
|
|
* and valid values are convert to standard 6 digit hex color.
|
|
* @param {String} attr The css attribute
|
|
* @param {String} defaultValue The default value to use when a valid color isn't found
|
|
* @param {String} [prefix] defaults to #. Use an empty string when working with
|
|
* color anims.
|
|
* @private
|
|
*/
|
|
getColor: function(attr, defaultValue, prefix) {
|
|
var v = this.getStyle(attr),
|
|
color = prefix || prefix === '' ? prefix : '#',
|
|
h, len,
|
|
i = 0;
|
|
if (!v || (/transparent|inherit/.test(v))) {
|
|
return defaultValue;
|
|
}
|
|
if (/^r/.test(v)) {
|
|
v = v.slice(4, v.length - 1).split(',');
|
|
len = v.length;
|
|
for (; i < len; i++) {
|
|
h = parseInt(v[i], 10);
|
|
color += (h < 16 ? '0' : '') + h.toString(16);
|
|
}
|
|
} else {
|
|
v = v.replace('#', '');
|
|
color += v.length === 3 ? v.replace(/^(\w)(\w)(\w)$/, '$1$1$2$2$3$3') : v;
|
|
}
|
|
return (color.length > 5 ? color.toLowerCase() : defaultValue);
|
|
},
|
|
/**
|
|
* Gets this element's {@link Ext.ElementLoader ElementLoader}
|
|
* @return {Ext.ElementLoader} The loader
|
|
*/
|
|
getLoader: function() {
|
|
var me = this,
|
|
data = me.getData(),
|
|
loader = data.loader;
|
|
if (!loader) {
|
|
data.loader = loader = new Ext.ElementLoader({
|
|
target: me
|
|
});
|
|
}
|
|
return loader;
|
|
},
|
|
/**
|
|
* Gets an object with all CSS positioning properties. Useful along with
|
|
* `setPostioning` to get snapshot before performing an update and then restoring
|
|
* the element.
|
|
* @param {Boolean} [autoPx=false] true to return pixel values for "auto" styles.
|
|
* @return {Object}
|
|
*/
|
|
getPositioning: function(autoPx) {
|
|
var styles = this.getStyle([
|
|
'left',
|
|
'top',
|
|
'position',
|
|
'z-index'
|
|
]),
|
|
dom = this.dom;
|
|
if (autoPx) {
|
|
if (styles.left === 'auto') {
|
|
styles.left = dom.offsetLeft + 'px';
|
|
}
|
|
if (styles.top === 'auto') {
|
|
styles.top = dom.offsetTop + 'px';
|
|
}
|
|
}
|
|
return styles;
|
|
},
|
|
/**
|
|
* Slides the element while fading it out of view. An anchor point can be optionally passed to set the ending point
|
|
* of the effect. Usage:
|
|
*
|
|
* // default: slide the element downward while fading out
|
|
* el.ghost();
|
|
*
|
|
* // custom: slide the element out to the right with a 2-second duration
|
|
* el.ghost('r', { duration: 2000 });
|
|
*
|
|
* // common config options shown with default values
|
|
* el.ghost('b', {
|
|
* easing: 'easeOut',
|
|
* duration: 500
|
|
* });
|
|
*
|
|
* @param {String} anchor (optional) One of the valid {@link Ext.fx.Anim} anchor positions (defaults to bottom: 'b')
|
|
* @param {Object} options (optional) Object literal with any of the {@link Ext.fx.Anim} config options
|
|
* @return {Ext.dom.Element} The Element
|
|
*/
|
|
ghost: function(anchor, obj) {
|
|
var me = this,
|
|
dom = me.dom,
|
|
beforeAnim;
|
|
anchor = anchor || "b";
|
|
beforeAnim = function() {
|
|
var el = Ext.fly(dom, '_anim'),
|
|
width = el.getWidth(),
|
|
height = el.getHeight(),
|
|
xy = el.getXY(),
|
|
position = el.getPositioning(),
|
|
to = {
|
|
opacity: 0
|
|
};
|
|
switch (anchor) {
|
|
case 't':
|
|
to.y = xy[1] - height;
|
|
break;
|
|
case 'l':
|
|
to.x = xy[0] - width;
|
|
break;
|
|
case 'r':
|
|
to.x = xy[0] + width;
|
|
break;
|
|
case 'b':
|
|
to.y = xy[1] + height;
|
|
break;
|
|
case 'tl':
|
|
to.x = xy[0] - width;
|
|
to.y = xy[1] - height;
|
|
break;
|
|
case 'bl':
|
|
to.x = xy[0] - width;
|
|
to.y = xy[1] + height;
|
|
break;
|
|
case 'br':
|
|
to.x = xy[0] + width;
|
|
to.y = xy[1] + height;
|
|
break;
|
|
case 'tr':
|
|
to.x = xy[0] + width;
|
|
to.y = xy[1] - height;
|
|
break;
|
|
}
|
|
this.to = to;
|
|
this.on('afteranimate', function() {
|
|
var el = Ext.fly(dom, '_anim');
|
|
if (el) {
|
|
el.hide();
|
|
el.clearOpacity();
|
|
el.setPositioning(position);
|
|
}
|
|
});
|
|
};
|
|
me.animate(Ext.applyIf(obj || {}, {
|
|
duration: 500,
|
|
easing: 'ease-out',
|
|
listeners: {
|
|
beforeanimate: beforeAnim
|
|
}
|
|
}));
|
|
return me;
|
|
},
|
|
/**
|
|
* @override
|
|
* Hide this element - Uses display mode to determine whether to use "display",
|
|
* "visibility", "offsets", or "clip". See {@link #setVisible}.
|
|
* @param {Boolean/Object} [animate] true for the default animation or a standard
|
|
* Element animation config object
|
|
* @return {Ext.dom.Element} this
|
|
*/
|
|
hide: function(animate) {
|
|
// hideMode override
|
|
if (typeof animate === 'string') {
|
|
this.setVisible(false, animate);
|
|
return this;
|
|
}
|
|
this.setVisible(false, this.anim(animate));
|
|
return this;
|
|
},
|
|
/**
|
|
* Highlights the Element by setting a color (applies to the background-color by default, but can be changed using
|
|
* the "attr" config option) and then fading back to the original color. If no original color is available, you
|
|
* should provide the "endColor" config option which will be cleared after the animation. Usage:
|
|
*
|
|
* // default: highlight background to yellow
|
|
* el.highlight();
|
|
*
|
|
* // custom: highlight foreground text to blue for 2 seconds
|
|
* el.highlight("0000ff", { attr: 'color', duration: 2000 });
|
|
*
|
|
* // common config options shown with default values
|
|
* el.highlight("ffff9c", {
|
|
* attr: "backgroundColor", //can be any valid CSS property (attribute) that supports a color value
|
|
* endColor: (current color) or "ffffff",
|
|
* easing: 'easeIn',
|
|
* duration: 1000
|
|
* });
|
|
*
|
|
* @param {String} color (optional) The highlight color. Should be a 6 char hex color without the leading #
|
|
* (defaults to yellow: 'ffff9c')
|
|
* @param {Object} options (optional) Object literal with any of the {@link Ext.fx.Anim} config options
|
|
* @return {Ext.dom.Element} The Element
|
|
*/
|
|
highlight: function(color, o) {
|
|
var me = this,
|
|
dom = me.dom,
|
|
from = {},
|
|
restore, to, attr, lns, event, fn;
|
|
o = o || {};
|
|
lns = o.listeners || {};
|
|
attr = o.attr || 'backgroundColor';
|
|
from[attr] = color || 'ffff9c';
|
|
if (!o.to) {
|
|
to = {};
|
|
to[attr] = o.endColor || me.getColor(attr, 'ffffff', '');
|
|
} else {
|
|
to = o.to;
|
|
}
|
|
// Don't apply directly on lns, since we reference it in our own callbacks below
|
|
o.listeners = Ext.apply(Ext.apply({}, lns), {
|
|
beforeanimate: function() {
|
|
restore = dom.style[attr];
|
|
var el = Ext.fly(dom, '_anim');
|
|
el.clearOpacity();
|
|
el.show();
|
|
event = lns.beforeanimate;
|
|
if (event) {
|
|
fn = event.fn || event;
|
|
return fn.apply(event.scope || lns.scope || WIN, arguments);
|
|
}
|
|
},
|
|
afteranimate: function() {
|
|
if (dom) {
|
|
dom.style[attr] = restore;
|
|
}
|
|
event = lns.afteranimate;
|
|
if (event) {
|
|
fn = event.fn || event;
|
|
fn.apply(event.scope || lns.scope || WIN, arguments);
|
|
}
|
|
}
|
|
});
|
|
me.animate(Ext.apply({}, o, {
|
|
duration: 1000,
|
|
easing: 'ease-in',
|
|
from: from,
|
|
to: to
|
|
}));
|
|
return me;
|
|
},
|
|
/**
|
|
* Sets up event handlers to call the passed functions when the mouse is moved into and out of the Element.
|
|
* @param {Function} overFn The function to call when the mouse enters the Element.
|
|
* @param {Function} outFn The function to call when the mouse leaves the Element.
|
|
* @param {Object} [scope] The scope (`this` reference) in which the functions are executed. Defaults
|
|
* to the Element's DOM element.
|
|
* @param {Object} [options] Options for the listener. See {@link Ext.util.Observable#addListener the
|
|
* options parameter}.
|
|
* @return {Ext.dom.Element} this
|
|
*/
|
|
hover: function(overFn, outFn, scope, options) {
|
|
var me = this;
|
|
me.on('mouseenter', overFn, scope || me.dom, options);
|
|
me.on('mouseleave', outFn, scope || me.dom, options);
|
|
return me;
|
|
},
|
|
/**
|
|
* Initializes a {@link Ext.dd.DD} drag drop object for this element.
|
|
* @param {String} group The group the DD object is member of
|
|
* @param {Object} config The DD config object
|
|
* @param {Object} overrides An object containing methods to override/implement on the DD object
|
|
* @return {Ext.dd.DD} The DD object
|
|
*/
|
|
initDD: function(group, config, overrides) {
|
|
var dd = new Ext.dd.DD(Ext.id(this.dom), group, config);
|
|
return Ext.apply(dd, overrides);
|
|
},
|
|
/**
|
|
* Initializes a {@link Ext.dd.DDProxy} object for this element.
|
|
* @param {String} group The group the DDProxy object is member of
|
|
* @param {Object} config The DDProxy config object
|
|
* @param {Object} overrides An object containing methods to override/implement on the DDProxy object
|
|
* @return {Ext.dd.DDProxy} The DDProxy object
|
|
*/
|
|
initDDProxy: function(group, config, overrides) {
|
|
var dd = new Ext.dd.DDProxy(Ext.id(this.dom), group, config);
|
|
return Ext.apply(dd, overrides);
|
|
},
|
|
/**
|
|
* Initializes a {@link Ext.dd.DDTarget} object for this element.
|
|
* @param {String} group The group the DDTarget object is member of
|
|
* @param {Object} config The DDTarget config object
|
|
* @param {Object} overrides An object containing methods to override/implement on the DDTarget object
|
|
* @return {Ext.dd.DDTarget} The DDTarget object
|
|
*/
|
|
initDDTarget: function(group, config, overrides) {
|
|
var dd = new Ext.dd.DDTarget(Ext.id(this.dom), group, config);
|
|
return Ext.apply(dd, overrides);
|
|
},
|
|
/**
|
|
* Checks whether this element can be focused programmatically or by clicking.
|
|
* To check if an element is in the document tab flow, use {@link #isTabbable}.
|
|
*
|
|
* @return {Boolean} True if the element is focusable
|
|
*/
|
|
isFocusable: function() {
|
|
var dom = this.dom,
|
|
focusable = false,
|
|
nodeName;
|
|
if (dom && !dom.disabled) {
|
|
nodeName = dom.nodeName;
|
|
/*
|
|
* An element is focusable if:
|
|
* - It is naturally focusable, or
|
|
* - It is an anchor or link with href attribute, or
|
|
* - It has a tabIndex, or
|
|
* - It is an editing host (contenteditable="true")
|
|
*
|
|
* Also note that we can't check dom.tabIndex because IE will return 0
|
|
* for elements that have no tabIndex attribute defined, regardless of
|
|
* whether they are naturally focusable or not.
|
|
*/
|
|
focusable = !!Ext.Element.naturallyFocusableTags[nodeName] || ((nodeName === 'A' || nodeName === 'LINK') && !!dom.href) || dom.getAttribute('tabIndex') != null || dom.contentEditable === 'true';
|
|
// In IE8, <input type="hidden"> does not have a corresponding style
|
|
// so isVisible() will assume that it's not hidden.
|
|
if (Ext.isIE8 && nodeName === 'INPUT' && dom.type === 'hidden') {
|
|
focusable = false;
|
|
}
|
|
// Invisible elements cannot be focused, so check that as well
|
|
focusable = focusable && this.isVisible(true);
|
|
}
|
|
return focusable;
|
|
},
|
|
/**
|
|
* Returns `true` if this Element is an input field, or is editable in any way.
|
|
* @return {Boolean} `true` if this Element is an input field, or is editable in any way.
|
|
*/
|
|
isInputField: function() {
|
|
var dom = this.dom,
|
|
contentEditable = dom.contentEditable;
|
|
// contentEditable will default to inherit if not specified, only check if the
|
|
// attribute has been set or explicitly set to true
|
|
// http://html5doctor.com/the-contenteditable-attribute/
|
|
// Also skip <input> tags of type="button", we use them for checkboxes
|
|
// and radio buttons
|
|
if ((inputTags[dom.tagName] && dom.type !== 'button') || (contentEditable === '' || contentEditable === 'true')) {
|
|
return true;
|
|
}
|
|
return false;
|
|
},
|
|
/**
|
|
* Checks whether this element participates in the sequential focus navigation,
|
|
* and can be reached by using Tab key.
|
|
*
|
|
* @param {Boolean} [includeHidden=false] pass `true` if hidden, or unattached elements should be returned.
|
|
* @return {Boolean} True if the element is tabbable.
|
|
*/
|
|
isTabbable: function(includeHidden) {
|
|
var dom = this.dom,
|
|
tabbable = false,
|
|
nodeName, hasIndex, tabIndex;
|
|
if (dom && !dom.disabled) {
|
|
nodeName = dom.nodeName;
|
|
// Can't use dom.tabIndex here because IE will return 0 for elements
|
|
// that have no tabindex attribute defined, regardless of whether they are
|
|
// naturally tabbable or not.
|
|
tabIndex = dom.getAttribute('tabIndex');
|
|
hasIndex = tabIndex != null;
|
|
tabIndex -= 0;
|
|
// Anchors and links are only naturally tabbable if they have href attribute
|
|
// See http://www.w3.org/TR/html5/editing.html#specially-focusable
|
|
if (nodeName === 'A' || nodeName === 'LINK') {
|
|
if (dom.href) {
|
|
// It is also possible to make an anchor untabbable by setting
|
|
// tabIndex < 0 on it
|
|
tabbable = hasIndex && tabIndex < 0 ? false : true;
|
|
} else // Anchor w/o href is tabbable if it has tabIndex >= 0,
|
|
// or if it's editable
|
|
{
|
|
if (dom.contentEditable === 'true') {
|
|
tabbable = !hasIndex || (hasIndex && tabIndex >= 0) ? true : false;
|
|
} else {
|
|
tabbable = hasIndex && tabIndex >= 0 ? true : false;
|
|
}
|
|
}
|
|
}
|
|
// If an element has contenteditable="true" or is naturally tabbable,
|
|
// then it is a potential candidate unless its tabIndex is < 0.
|
|
else if (dom.contentEditable === 'true' || Ext.Element.naturallyTabbableTags[nodeName]) {
|
|
tabbable = hasIndex && tabIndex < 0 ? false : true;
|
|
} else // That leaves non-editable elements that can only be made tabbable
|
|
// by slapping tabIndex >= 0 on them
|
|
{
|
|
if (hasIndex && tabIndex >= 0) {
|
|
tabbable = true;
|
|
}
|
|
}
|
|
// In IE8, <input type="hidden"> does not have a corresponding style
|
|
// so isVisible() will assume that it's not hidden.
|
|
if (Ext.isIE8 && nodeName === 'INPUT' && dom.type === 'hidden') {
|
|
tabbable = false;
|
|
}
|
|
// Invisible elements can't be tabbed into. If we have a component ref
|
|
// we'll also check if the component itself is visible before incurring
|
|
// the expense of DOM style reads.
|
|
// Allow caller to specify that hiddens should be included.
|
|
tabbable = tabbable && (includeHidden || ((!this.component || this.component.isVisible(true)) && this.isVisible(true)));
|
|
}
|
|
return tabbable;
|
|
},
|
|
/**
|
|
* Returns true if this element is masked. Also re-centers any displayed message
|
|
* within the mask.
|
|
*
|
|
* @param {Boolean} [deep] Go up the DOM hierarchy to determine if any parent
|
|
* element is masked.
|
|
*
|
|
* @return {Boolean}
|
|
*/
|
|
isMasked: function(deep) {
|
|
var me = this,
|
|
data = me.getData(),
|
|
maskEl = data.maskEl,
|
|
maskMsg = data.maskMsg,
|
|
hasMask = false,
|
|
parent;
|
|
if (maskEl && maskEl.isVisible()) {
|
|
if (maskMsg) {
|
|
maskMsg.center(me);
|
|
}
|
|
hasMask = true;
|
|
} else if (deep) {
|
|
parent = me.findParentNode();
|
|
if (parent) {
|
|
return Ext.fly(parent).isMasked(deep);
|
|
}
|
|
}
|
|
return hasMask;
|
|
},
|
|
/**
|
|
* Direct access to the Ext.ElementLoader {@link Ext.ElementLoader#method-load} method.
|
|
* The method takes the same object parameter as {@link Ext.ElementLoader#method-load}
|
|
* @param {Object} options a options object for Ext.ElementLoader {@link Ext.ElementLoader#method-load}
|
|
* @return {Ext.dom.Element} this
|
|
*/
|
|
load: function(options) {
|
|
this.getLoader().load(options);
|
|
return this;
|
|
},
|
|
/**
|
|
* Puts a mask over this element to disable user interaction.
|
|
* This method can only be applied to elements which accept child nodes. Use
|
|
* {@link #unmask} to remove the mask.
|
|
*
|
|
* @param {String} [msg] A message to display in the mask
|
|
* @param {String} [msgCls] A css class to apply to the msg element
|
|
* @return {Ext.dom.Element} The mask element
|
|
*/
|
|
mask: function(msg, msgCls, /* private - passed by AbstractComponent.mask to avoid the need to interrogate the DOM to get the height*/
|
|
elHeight) {
|
|
var me = this,
|
|
dom = me.dom,
|
|
data = me.getData(),
|
|
maskEl = data.maskEl,
|
|
maskMsg;
|
|
if (!(bodyRe.test(dom.tagName) && me.getStyle('position') === 'static')) {
|
|
me.addCls(XMASKEDRELATIVE);
|
|
}
|
|
// We always needs to recreate the mask since the DOM element may have been re-created
|
|
if (maskEl) {
|
|
maskEl.destroy();
|
|
}
|
|
maskEl = Ext.DomHelper.append(dom, {
|
|
role: 'presentation',
|
|
cls: Ext.baseCSSPrefix + "mask " + Ext.baseCSSPrefix + "border-box",
|
|
children: {
|
|
role: 'presentation',
|
|
cls: msgCls ? EXTELMASKMSG + " " + msgCls : EXTELMASKMSG,
|
|
cn: {
|
|
tag: 'div',
|
|
role: 'presentation',
|
|
cls: Ext.baseCSSPrefix + 'mask-msg-inner',
|
|
cn: {
|
|
tag: 'div',
|
|
role: 'presentation',
|
|
cls: Ext.baseCSSPrefix + 'mask-msg-text',
|
|
html: msg || ''
|
|
}
|
|
}
|
|
}
|
|
}, true);
|
|
maskMsg = Ext.get(maskEl.dom.firstChild);
|
|
data.maskEl = maskEl;
|
|
me.addCls(XMASKED);
|
|
maskEl.setDisplayed(true);
|
|
if (typeof msg === 'string') {
|
|
maskMsg.setDisplayed(true);
|
|
maskMsg.center(me);
|
|
} else {
|
|
maskMsg.setDisplayed(false);
|
|
}
|
|
if (dom === DOC.body) {
|
|
maskEl.addCls(Ext.baseCSSPrefix + 'mask-fixed');
|
|
}
|
|
// When masking the body, don't touch its tabbable state
|
|
me.saveTabbableState({
|
|
skipSelf: dom === DOC.body
|
|
});
|
|
// ie will not expand full height automatically
|
|
if (Ext.isIE9m && dom !== DOC.body && me.isStyle('height', 'auto')) {
|
|
maskEl.setSize(undefined, elHeight || me.getHeight());
|
|
}
|
|
return maskEl;
|
|
},
|
|
/**
|
|
* Fades the element out while slowly expanding it in all directions. When the effect is completed, the element will
|
|
* be hidden (visibility = 'hidden') but block elements will still take up space in the document. Usage:
|
|
*
|
|
* // default
|
|
* el.puff();
|
|
*
|
|
* // common config options shown with default values
|
|
* el.puff({
|
|
* easing: 'easeOut',
|
|
* duration: 500,
|
|
* useDisplay: false
|
|
* });
|
|
*
|
|
* @param {Object} options (optional) Object literal with any of the {@link Ext.fx.Anim} config options
|
|
* @return {Ext.dom.Element} The Element
|
|
*/
|
|
puff: function(obj) {
|
|
var me = this,
|
|
dom = me.dom,
|
|
beforeAnim,
|
|
box = me.getBox(),
|
|
originalStyles = me.getStyle([
|
|
'width',
|
|
'height',
|
|
'left',
|
|
'right',
|
|
'top',
|
|
'bottom',
|
|
'position',
|
|
'z-index',
|
|
'font-size',
|
|
'opacity'
|
|
], true);
|
|
obj = Ext.applyIf(obj || {}, {
|
|
easing: 'ease-out',
|
|
duration: 500,
|
|
useDisplay: false
|
|
});
|
|
beforeAnim = function() {
|
|
var el = Ext.fly(dom, '_anim');
|
|
el.clearOpacity();
|
|
el.show();
|
|
this.to = {
|
|
width: box.width * 2,
|
|
height: box.height * 2,
|
|
x: box.x - (box.width / 2),
|
|
y: box.y - (box.height / 2),
|
|
opacity: 0,
|
|
fontSize: '200%'
|
|
};
|
|
this.on('afteranimate', function() {
|
|
var el = Ext.fly(dom, '_anim');
|
|
if (el) {
|
|
if (obj.useDisplay) {
|
|
el.setDisplayed(false);
|
|
} else {
|
|
el.hide();
|
|
}
|
|
el.setStyle(originalStyles);
|
|
Ext.callback(obj.callback, obj.scope);
|
|
}
|
|
});
|
|
};
|
|
me.animate({
|
|
duration: obj.duration,
|
|
easing: obj.easing,
|
|
listeners: {
|
|
beforeanimate: {
|
|
fn: beforeAnim
|
|
}
|
|
}
|
|
});
|
|
return me;
|
|
},
|
|
/**
|
|
* Enable text selection for this element (normalized across browsers)
|
|
* @return {Ext.dom.Element} this
|
|
*/
|
|
selectable: function() {
|
|
var me = this;
|
|
// We clear this property for all browsers, not just Opera. This is so that rendering templates don't need to
|
|
// condition on Opera when making elements unselectable.
|
|
me.dom.unselectable = '';
|
|
me.removeCls(Element.unselectableCls);
|
|
me.addCls(Element.selectableCls);
|
|
return me;
|
|
},
|
|
// private
|
|
// used to ensure the mouseup event is captured if it occurs outside of the
|
|
// window in IE9m. The only reason this method exists, (vs just calling
|
|
// el.dom.setCapture() directly) is so that we can override it to emptyFn
|
|
// during testing because setCapture() can wreak havoc on emulated mouse events
|
|
// http://msdn.microsoft.com/en-us/library/windows/desktop/ms646262(v=vs.85).aspx
|
|
setCapture: function() {
|
|
var dom = this.dom;
|
|
if (Ext.isIE9m && dom.setCapture) {
|
|
dom.setCapture();
|
|
}
|
|
},
|
|
/**
|
|
* Set the height of this Element.
|
|
*
|
|
* // change the height to 200px and animate with default configuration
|
|
* Ext.fly('elementId').setHeight(200, true);
|
|
*
|
|
* // change the height to 150px and animate with a custom configuration
|
|
* Ext.fly('elId').setHeight(150, {
|
|
* duration : 500, // animation will have a duration of .5 seconds
|
|
* // will change the content to "finished"
|
|
* callback: function(){ this.setHtml("finished"); }
|
|
* });
|
|
*
|
|
* @param {Number/String} height The new height. This may be one of:
|
|
*
|
|
* - A Number specifying the new height in pixels.
|
|
* - A String used to set the CSS height style. Animation may **not** be used.
|
|
*
|
|
* @param {Boolean/Object} [animate] a standard Element animation config object or `true` for
|
|
* the default animation (`{duration: 350, easing: 'ease-in'}`)
|
|
* @return {Ext.dom.Element} this
|
|
*/
|
|
setHeight: function(height, animate) {
|
|
var me = this;
|
|
if (!animate || !me.anim) {
|
|
me.callParent(arguments);
|
|
} else {
|
|
if (!Ext.isObject(animate)) {
|
|
animate = {};
|
|
}
|
|
me.animate(Ext.applyIf({
|
|
to: {
|
|
height: height
|
|
}
|
|
}, animate));
|
|
}
|
|
return me;
|
|
},
|
|
/**
|
|
* Removes "vertical" state from this element (reverses everything done
|
|
* by {@link #setVertical}).
|
|
* @private
|
|
*/
|
|
setHorizontal: function() {
|
|
var me = this,
|
|
cls = me.verticalCls;
|
|
delete me.vertical;
|
|
if (cls) {
|
|
delete me.verticalCls;
|
|
me.removeCls(cls);
|
|
}
|
|
// delete the inverted methods and revert to inheriting from the prototype
|
|
delete me.setWidth;
|
|
delete me.setHeight;
|
|
if (!Ext.isIE8) {
|
|
delete me.getWidth;
|
|
delete me.getHeight;
|
|
}
|
|
// revert to inheriting styleHooks from the prototype
|
|
delete me.styleHooks;
|
|
},
|
|
/**
|
|
* Updates the *text* value of this element.
|
|
* Replaces the content of this element with a *single text node* containing the passed text.
|
|
* @param {String} text The text to display in this Element.
|
|
*/
|
|
updateText: function(text) {
|
|
var me = this,
|
|
dom, textNode;
|
|
if (dom) {
|
|
textNode = dom.firstChild;
|
|
if (!textNode || (textNode.nodeType !== 3 || textNode.nextSibling)) {
|
|
textNode = DOC.createTextNode();
|
|
me.empty();
|
|
dom.appendChild(textNode);
|
|
}
|
|
if (text) {
|
|
textNode.data = text;
|
|
}
|
|
}
|
|
},
|
|
/**
|
|
* Updates the innerHTML of this element, optionally searching for and processing scripts.
|
|
* @param {String} html The new HTML
|
|
* @param {Boolean} [loadScripts] Pass `true` to look for and process scripts.
|
|
* @param {Function} [callback] For async script loading you can be notified when the update completes.
|
|
* @param {Object} [scope=`this`] The scope (`this` reference) in which to execute the callback.
|
|
*
|
|
* Also used as the scope for any *inline* script source if the `loadScripts` parameter is `true`.
|
|
* Scripts with a `src` attribute cannot be executed in this scope.
|
|
*
|
|
* Defaults to this Element.
|
|
* @return {Ext.dom.Element} this
|
|
*/
|
|
setHtml: function(html, loadScripts, callback, scope) {
|
|
var me = this,
|
|
id, dom, interval;
|
|
if (!me.dom) {
|
|
return me;
|
|
}
|
|
html = html || '';
|
|
dom = me.dom;
|
|
if (loadScripts !== true) {
|
|
dom.innerHTML = html;
|
|
Ext.callback(callback, me);
|
|
return me;
|
|
}
|
|
id = Ext.id();
|
|
html += '<span id="' + id + '" role="presentation"></span>';
|
|
interval = Ext.interval(function() {
|
|
var hd, match, attrs, srcMatch, typeMatch, el, s;
|
|
if (!(el = DOC.getElementById(id))) {
|
|
return false;
|
|
}
|
|
clearInterval(interval);
|
|
Ext.removeNode(el);
|
|
hd = Ext.getHead().dom;
|
|
while ((match = scriptTagRe.exec(html))) {
|
|
attrs = match[1];
|
|
srcMatch = attrs ? attrs.match(srcRe) : false;
|
|
if (srcMatch && srcMatch[2]) {
|
|
s = DOC.createElement("script");
|
|
s.src = srcMatch[2];
|
|
typeMatch = attrs.match(typeRe);
|
|
if (typeMatch && typeMatch[2]) {
|
|
s.type = typeMatch[2];
|
|
}
|
|
hd.appendChild(s);
|
|
} else if (match[2] && match[2].length > 0) {
|
|
if (scope) {
|
|
Ext.functionFactory(match[2]).call(scope);
|
|
} else {
|
|
Ext.globalEval(match[2]);
|
|
}
|
|
}
|
|
}
|
|
Ext.callback(callback, scope || me);
|
|
}, 20);
|
|
dom.innerHTML = html.replace(replaceScriptTagRe, '');
|
|
return me;
|
|
},
|
|
/**
|
|
* Set the opacity of the element
|
|
* @param {Number} opacity The new opacity. 0 = transparent, .5 = 50% visible, 1 = fully visible, etc
|
|
* @param {Boolean/Object} [animate] a standard Element animation config object or `true` for
|
|
* the default animation (`{duration: 350, easing: 'ease-in'}`)
|
|
* @return {Ext.dom.Element} this
|
|
*/
|
|
setOpacity: function(opacity, animate) {
|
|
var me = this;
|
|
if (!me.dom) {
|
|
return me;
|
|
}
|
|
if (!animate || !me.anim) {
|
|
me.setStyle('opacity', opacity);
|
|
} else {
|
|
if (typeof animate != 'object') {
|
|
animate = {
|
|
duration: 350,
|
|
easing: 'ease-in'
|
|
};
|
|
}
|
|
me.animate(Ext.applyIf({
|
|
to: {
|
|
opacity: opacity
|
|
}
|
|
}, animate));
|
|
}
|
|
return me;
|
|
},
|
|
/**
|
|
* Set positioning with an object returned by `getPositioning`.
|
|
* @param {Object} posCfg
|
|
* @return {Ext.dom.Element} this
|
|
*/
|
|
setPositioning: function(pc) {
|
|
return this.setStyle(pc);
|
|
},
|
|
/**
|
|
* Changes this Element's state to "vertical" (rotated 90 or 270 degrees).
|
|
* This involves inverting the getters and setters for height and width,
|
|
* and applying hooks for rotating getters and setters for border/margin/padding.
|
|
* (getWidth becomes getHeight and vice versa), setStyle and getStyle will
|
|
* also return the inverse when height or width are being operated on.
|
|
*
|
|
* @param {Number} angle the angle of rotation - either 90 or 270
|
|
* @param {String} cls an optional css class that contains the required
|
|
* styles for switching the element to vertical orientation. Omit this if
|
|
* the element already contains vertical styling. If cls is provided,
|
|
* it will be removed from the element when {@link #setHorizontal} is called.
|
|
* @private
|
|
*/
|
|
setVertical: function(angle, cls) {
|
|
var me = this,
|
|
proto = Element.prototype;
|
|
me.vertical = true;
|
|
if (cls) {
|
|
me.addCls(me.verticalCls = cls);
|
|
}
|
|
me.setWidth = proto.setHeight;
|
|
me.setHeight = proto.setWidth;
|
|
if (!Ext.isIE8) {
|
|
// In browsers that use CSS3 transforms we must invert getHeight and
|
|
// get Width. In IE8 no adjustment is needed because we use
|
|
// a BasicImage filter to rotate the element and the element's
|
|
// offsetWidth and offsetHeight are automatically inverted.
|
|
me.getWidth = proto.getHeight;
|
|
me.getHeight = proto.getWidth;
|
|
}
|
|
// Switch to using the appropriate vertical style hooks
|
|
me.styleHooks = (angle === 270) ? proto.verticalStyleHooks270 : proto.verticalStyleHooks90;
|
|
},
|
|
/**
|
|
* Set the size of this Element. If animation is true, both width and height will be animated concurrently.
|
|
* @param {Number/String} width The new width. This may be one of:
|
|
*
|
|
* - A Number specifying the new width in pixels.
|
|
* - A String used to set the CSS width style. Animation may **not** be used.
|
|
* - A size object in the format `{width: widthValue, height: heightValue}`.
|
|
*
|
|
* @param {Number/String} height The new height. This may be one of:
|
|
*
|
|
* - A Number specifying the new height in pixels.
|
|
* - A String used to set the CSS height style. Animation may **not** be used.
|
|
*
|
|
* @param {Boolean/Object} [animate] a standard Element animation config object or `true` for
|
|
* the default animation (`{duration: 350, easing: 'ease-in'}`)
|
|
*
|
|
* @return {Ext.dom.Element} this
|
|
*/
|
|
setSize: function(width, height, animate) {
|
|
var me = this;
|
|
if (Ext.isObject(width)) {
|
|
// in case of object from getSize()
|
|
animate = height;
|
|
height = width.height;
|
|
width = width.width;
|
|
}
|
|
if (!animate || !me.anim) {
|
|
me.dom.style.width = Element.addUnits(width);
|
|
me.dom.style.height = Element.addUnits(height);
|
|
if (me.shadow || me.shim) {
|
|
me.syncUnderlays();
|
|
}
|
|
} else {
|
|
if (animate === true) {
|
|
animate = {};
|
|
}
|
|
me.animate(Ext.applyIf({
|
|
to: {
|
|
width: width,
|
|
height: height
|
|
}
|
|
}, animate));
|
|
}
|
|
return me;
|
|
},
|
|
/**
|
|
* Sets the visibility of the element (see details). If the visibilityMode is set
|
|
* to Element.DISPLAY, it will use the display property to hide the element,
|
|
* otherwise it uses visibility. The default is to hide and show using the
|
|
* visibility property.
|
|
*
|
|
* @param {Boolean} visible Whether the element is visible
|
|
* @param {Boolean/Object} [animate] True for the default animation,
|
|
* or a standard Element animation config object.
|
|
*
|
|
* @return {Ext.dom.Element} this
|
|
*/
|
|
setVisible: function(visible, animate) {
|
|
var me = this,
|
|
dom = me.dom,
|
|
visMode = getVisMode(me);
|
|
// hideMode string override
|
|
if (typeof animate === 'string') {
|
|
switch (animate) {
|
|
case DISPLAY:
|
|
visMode = Element.DISPLAY;
|
|
break;
|
|
case VISIBILITY:
|
|
visMode = Element.VISIBILITY;
|
|
break;
|
|
case OFFSETS:
|
|
visMode = Element.OFFSETS;
|
|
break;
|
|
case CLIP:
|
|
visMode = Element.CLIP;
|
|
break;
|
|
}
|
|
me.setVisibilityMode(visMode);
|
|
animate = false;
|
|
}
|
|
if (!animate || !me.anim) {
|
|
if (visMode === Element.DISPLAY) {
|
|
return me.setDisplayed(visible);
|
|
} else if (visMode === Element.OFFSETS) {
|
|
me[visible ? 'removeCls' : 'addCls'](OFFSETCLASS);
|
|
} else if (visMode === Element.CLIP) {
|
|
me[visible ? 'removeCls' : 'addCls'](CLIPCLASS);
|
|
} else if (visMode === Element.VISIBILITY) {
|
|
me.fixDisplay();
|
|
// Show by clearing visibility style. Explicitly setting to "visible" overrides parent visibility setting
|
|
dom.style.visibility = visible ? '' : HIDDEN;
|
|
}
|
|
} else {
|
|
// closure for composites
|
|
if (visible) {
|
|
me.setOpacity(0.01);
|
|
me.setVisible(true);
|
|
}
|
|
if (!Ext.isObject(animate)) {
|
|
animate = {
|
|
duration: 350,
|
|
easing: 'ease-in'
|
|
};
|
|
}
|
|
me.animate(Ext.applyIf({
|
|
callback: function() {
|
|
if (!visible) {
|
|
// Grab the dom again, since the reference may have changed if we use fly
|
|
Ext.fly(dom).setVisible(false).setOpacity(1);
|
|
}
|
|
},
|
|
to: {
|
|
opacity: (visible) ? 1 : 0
|
|
}
|
|
}, animate));
|
|
}
|
|
me.getData()[ISVISIBLE] = visible;
|
|
if (me.shadow || me.shim) {
|
|
me.setUnderlaysVisible(visible);
|
|
}
|
|
return me;
|
|
},
|
|
/**
|
|
* Set the width of this Element.
|
|
*
|
|
* // change the width to 200px and animate with default configuration
|
|
* Ext.fly('elementId').setWidth(200, true);
|
|
*
|
|
* // change the width to 150px and animate with a custom configuration
|
|
* Ext.fly('elId').setWidth(150, {
|
|
* duration : 500, // animation will have a duration of .5 seconds
|
|
* // will change the content to "finished"
|
|
* callback: function(){ this.setHtml("finished"); }
|
|
* });
|
|
*
|
|
* @param {Number/String} width The new width. This may be one of:
|
|
*
|
|
* - A Number specifying the new width in pixels.
|
|
* - A String used to set the CSS width style. Animation may **not** be used.
|
|
*
|
|
* @param {Boolean/Object} [animate] a standard Element animation config object or `true` for
|
|
* the default animation (`{duration: 350, easing: 'ease-in'}`)
|
|
* @return {Ext.dom.Element} this
|
|
*/
|
|
setWidth: function(width, animate) {
|
|
var me = this;
|
|
if (!animate || !me.anim) {
|
|
me.callParent(arguments);
|
|
} else {
|
|
if (!Ext.isObject(animate)) {
|
|
animate = {};
|
|
}
|
|
me.animate(Ext.applyIf({
|
|
to: {
|
|
width: width
|
|
}
|
|
}, animate));
|
|
}
|
|
return me;
|
|
},
|
|
setX: function(x, animate) {
|
|
return this.setXY([
|
|
x,
|
|
this.getY()
|
|
], animate);
|
|
},
|
|
setXY: function(xy, animate) {
|
|
var me = this;
|
|
if (!animate || !me.anim) {
|
|
me.callParent([
|
|
xy
|
|
]);
|
|
} else {
|
|
if (!Ext.isObject(animate)) {
|
|
animate = {};
|
|
}
|
|
me.animate(Ext.applyIf({
|
|
to: {
|
|
x: xy[0],
|
|
y: xy[1]
|
|
}
|
|
}, animate));
|
|
}
|
|
return this;
|
|
},
|
|
setY: function(y, animate) {
|
|
return this.setXY([
|
|
this.getX(),
|
|
y
|
|
], animate);
|
|
},
|
|
/**
|
|
* Show this element - Uses display mode to determine whether to use "display",
|
|
* "visibility", "offsets", or "clip". See {@link #setVisible}.
|
|
*
|
|
* @param {Boolean/Object} [animate] true for the default animation or a standard
|
|
* Element animation config object.
|
|
*
|
|
* @return {Ext.dom.Element} this
|
|
*/
|
|
show: function(animate) {
|
|
// hideMode override
|
|
if (typeof animate === 'string') {
|
|
this.setVisible(true, animate);
|
|
return this;
|
|
}
|
|
this.setVisible(true, this.anim(animate));
|
|
return this;
|
|
},
|
|
/**
|
|
* Slides the element into view. An anchor point can be optionally passed to set the point of origin for the slide
|
|
* effect. This function automatically handles wrapping the element with a fixed-size container if needed. See the
|
|
* {@link Ext.fx.Anim} class overview for valid anchor point options. Usage:
|
|
*
|
|
* // default: slide the element in from the top
|
|
* el.slideIn();
|
|
*
|
|
* // custom: slide the element in from the right with a 2-second duration
|
|
* el.slideIn('r', { duration: 2000 });
|
|
*
|
|
* // common config options shown with default values
|
|
* el.slideIn('t', {
|
|
* easing: 'easeOut',
|
|
* duration: 500
|
|
* });
|
|
*
|
|
* @param {String} anchor (optional) One of the valid {@link Ext.fx.Anim} anchor positions (defaults to top: 't')
|
|
* @param {Object} options (optional) Object literal with any of the {@link Ext.fx.Anim} config options
|
|
* @param {Boolean} options.preserveScroll Set to true if preservation of any descendant elements'
|
|
* `scrollTop` values is required. By default the DOM wrapping operation performed by `slideIn` and
|
|
* `slideOut` causes the browser to lose all scroll positions.
|
|
* @return {Ext.dom.Element} The Element
|
|
*/
|
|
slideIn: function(anchor, obj, slideOut) {
|
|
var me = this,
|
|
dom = me.dom,
|
|
elStyle = dom.style,
|
|
beforeAnim, wrapAnim, restoreScroll, wrapDomParentNode;
|
|
anchor = anchor || "t";
|
|
obj = obj || {};
|
|
beforeAnim = function() {
|
|
var animScope = this,
|
|
listeners = obj.listeners,
|
|
el = Ext.fly(dom, '_anim'),
|
|
box, originalStyles, anim, wrap;
|
|
if (!slideOut) {
|
|
el.fixDisplay();
|
|
}
|
|
box = el.getBox();
|
|
if ((anchor == 't' || anchor == 'b') && box.height === 0) {
|
|
box.height = dom.scrollHeight;
|
|
} else if ((anchor == 'l' || anchor == 'r') && box.width === 0) {
|
|
box.width = dom.scrollWidth;
|
|
}
|
|
originalStyles = el.getStyle([
|
|
'width',
|
|
'height',
|
|
'left',
|
|
'right',
|
|
'top',
|
|
'bottom',
|
|
'position',
|
|
'z-index'
|
|
], true);
|
|
el.setSize(box.width, box.height);
|
|
// Cache all descendants' scrollTop & scrollLeft values if configured to preserve scroll.
|
|
if (obj.preserveScroll) {
|
|
restoreScroll = el.cacheScrollValues();
|
|
}
|
|
wrap = el.wrap({
|
|
role: 'presentation',
|
|
id: Ext.id() + '-anim-wrap-for-' + el.dom.id,
|
|
style: {
|
|
visibility: slideOut ? 'visible' : 'hidden'
|
|
}
|
|
});
|
|
wrapDomParentNode = wrap.dom.parentNode;
|
|
wrap.setPositioning(el.getPositioning());
|
|
if (wrap.isStyle('position', 'static')) {
|
|
wrap.position('relative');
|
|
}
|
|
el.clearPositioning('auto');
|
|
wrap.clip();
|
|
// The wrap will have reset all descendant scrollTops. Restore them if we cached them.
|
|
if (restoreScroll) {
|
|
restoreScroll();
|
|
}
|
|
// This element is temporarily positioned absolute within its wrapper.
|
|
// Restore to its default, CSS-inherited visibility setting.
|
|
// We cannot explicitly poke visibility:visible into its style because that overrides the visibility of the wrap.
|
|
el.setStyle({
|
|
visibility: '',
|
|
position: 'absolute'
|
|
});
|
|
if (slideOut) {
|
|
wrap.setSize(box.width, box.height);
|
|
}
|
|
switch (anchor) {
|
|
case 't':
|
|
anim = {
|
|
from: {
|
|
width: box.width + 'px',
|
|
height: '0px'
|
|
},
|
|
to: {
|
|
width: box.width + 'px',
|
|
height: box.height + 'px'
|
|
}
|
|
};
|
|
elStyle.bottom = '0px';
|
|
break;
|
|
case 'l':
|
|
anim = {
|
|
from: {
|
|
width: '0px',
|
|
height: box.height + 'px'
|
|
},
|
|
to: {
|
|
width: box.width + 'px',
|
|
height: box.height + 'px'
|
|
}
|
|
};
|
|
me.anchorAnimX(anchor);
|
|
break;
|
|
case 'r':
|
|
anim = {
|
|
from: {
|
|
x: box.x + box.width,
|
|
width: '0px',
|
|
height: box.height + 'px'
|
|
},
|
|
to: {
|
|
x: box.x,
|
|
width: box.width + 'px',
|
|
height: box.height + 'px'
|
|
}
|
|
};
|
|
me.anchorAnimX(anchor);
|
|
break;
|
|
case 'b':
|
|
anim = {
|
|
from: {
|
|
y: box.y + box.height,
|
|
width: box.width + 'px',
|
|
height: '0px'
|
|
},
|
|
to: {
|
|
y: box.y,
|
|
width: box.width + 'px',
|
|
height: box.height + 'px'
|
|
}
|
|
};
|
|
break;
|
|
case 'tl':
|
|
anim = {
|
|
from: {
|
|
x: box.x,
|
|
y: box.y,
|
|
width: '0px',
|
|
height: '0px'
|
|
},
|
|
to: {
|
|
width: box.width + 'px',
|
|
height: box.height + 'px'
|
|
}
|
|
};
|
|
elStyle.bottom = '0px';
|
|
me.anchorAnimX('l');
|
|
break;
|
|
case 'bl':
|
|
anim = {
|
|
from: {
|
|
y: box.y + box.height,
|
|
width: '0px',
|
|
height: '0px'
|
|
},
|
|
to: {
|
|
y: box.y,
|
|
width: box.width + 'px',
|
|
height: box.height + 'px'
|
|
}
|
|
};
|
|
me.anchorAnimX('l');
|
|
break;
|
|
case 'br':
|
|
anim = {
|
|
from: {
|
|
x: box.x + box.width,
|
|
y: box.y + box.height,
|
|
width: '0px',
|
|
height: '0px'
|
|
},
|
|
to: {
|
|
x: box.x,
|
|
y: box.y,
|
|
width: box.width + 'px',
|
|
height: box.height + 'px'
|
|
}
|
|
};
|
|
me.anchorAnimX('r');
|
|
break;
|
|
case 'tr':
|
|
anim = {
|
|
from: {
|
|
x: box.x + box.width,
|
|
width: '0px',
|
|
height: '0px'
|
|
},
|
|
to: {
|
|
x: box.x,
|
|
width: box.width + 'px',
|
|
height: box.height + 'px'
|
|
}
|
|
};
|
|
elStyle.bottom = '0px';
|
|
me.anchorAnimX('r');
|
|
break;
|
|
}
|
|
wrap.show();
|
|
wrapAnim = Ext.apply({}, obj);
|
|
delete wrapAnim.listeners;
|
|
wrapAnim = new Ext.fx.Anim(Ext.applyIf(wrapAnim, {
|
|
target: wrap,
|
|
duration: 500,
|
|
easing: 'ease-out',
|
|
from: slideOut ? anim.to : anim.from,
|
|
to: slideOut ? anim.from : anim.to
|
|
}));
|
|
// In the absence of a callback, this listener MUST be added first
|
|
wrapAnim.on('afteranimate', function() {
|
|
var el = Ext.fly(dom, '_anim');
|
|
el.setStyle(originalStyles);
|
|
if (slideOut) {
|
|
if (obj.useDisplay) {
|
|
el.setDisplayed(false);
|
|
} else {
|
|
el.hide();
|
|
}
|
|
}
|
|
if (wrap.dom) {
|
|
if (wrap.dom.parentNode) {
|
|
wrap.dom.parentNode.insertBefore(el.dom, wrap.dom);
|
|
} else {
|
|
wrapDomParentNode.appendChild(el.dom);
|
|
}
|
|
wrap.destroy();
|
|
}
|
|
// The unwrap will have reset all descendant scrollTops. Restore them if we cached them.
|
|
if (restoreScroll) {
|
|
restoreScroll();
|
|
}
|
|
// kill the no-op element animation created below
|
|
animScope.end();
|
|
});
|
|
// Add configured listeners after
|
|
if (listeners) {
|
|
wrapAnim.on(listeners);
|
|
}
|
|
};
|
|
me.animate({
|
|
// See "A Note About Wrapped Animations" at the top of this class:
|
|
duration: obj.duration ? Math.max(obj.duration, 500) * 2 : 1000,
|
|
listeners: {
|
|
beforeanimate: beforeAnim
|
|
}
|
|
});
|
|
// kick off the wrap animation
|
|
return me;
|
|
},
|
|
/**
|
|
* Slides the element out of view. An anchor point can be optionally passed to set the end point for the slide
|
|
* effect. When the effect is completed, the element will be hidden (visibility = 'hidden') but block elements will
|
|
* still take up space in the document. The element must be removed from the DOM using the 'remove' config option if
|
|
* desired. This function automatically handles wrapping the element with a fixed-size container if needed. See the
|
|
* {@link Ext.fx.Anim} class overview for valid anchor point options. Usage:
|
|
*
|
|
* // default: slide the element out to the top
|
|
* el.slideOut();
|
|
*
|
|
* // custom: slide the element out to the right with a 2-second duration
|
|
* el.slideOut('r', { duration: 2000 });
|
|
*
|
|
* // common config options shown with default values
|
|
* el.slideOut('t', {
|
|
* easing: 'easeOut',
|
|
* duration: 500,
|
|
* remove: false,
|
|
* useDisplay: false
|
|
* });
|
|
*
|
|
* @param {String} anchor (optional) One of the valid {@link Ext.fx.Anim} anchor positions (defaults to top: 't')
|
|
* @param {Object} options (optional) Object literal with any of the {@link Ext.fx.Anim} config options
|
|
* @return {Ext.dom.Element} The Element
|
|
*/
|
|
slideOut: function(anchor, options) {
|
|
return this.slideIn(anchor, options, true);
|
|
},
|
|
/**
|
|
* Stops the specified event(s) from bubbling and optionally prevents the default action
|
|
*
|
|
* var store = Ext.create('Ext.data.Store', {
|
|
* fields: ['name', 'email'],
|
|
* data: [{
|
|
* 'name': 'Finn',
|
|
* "email": "finn@adventuretime.com"
|
|
* }]
|
|
* });
|
|
*
|
|
* Ext.create('Ext.grid.Panel', {
|
|
* title: 'Land of Ooo',
|
|
* store: store,
|
|
* columns: [{
|
|
* text: 'Name',
|
|
* dataIndex: 'name'
|
|
* }, {
|
|
* text: 'Email <img style="vertical-align:middle;" src="{some-help-image-src}" />',
|
|
* dataIndex: 'email',
|
|
* flex: 1,
|
|
* listeners: {
|
|
* render: function(col) {
|
|
* // Swallow the click event when the click occurs on the
|
|
* // help icon - preventing the sorting of data by that
|
|
* // column and instead performing an action specific to
|
|
* // the help icon
|
|
* var img = col.getEl().down('img');
|
|
* img.swallowEvent(['click', 'mousedown'], true);
|
|
* col.on('click', function() {
|
|
* // logic to show a help dialog
|
|
* console.log('image click handler');
|
|
* }, col);
|
|
* }
|
|
* }
|
|
* }],
|
|
* height: 200,
|
|
* width: 400,
|
|
* renderTo: document.body
|
|
* });
|
|
*
|
|
* @param {String/String[]} eventName an event / array of events to stop from bubbling
|
|
* @param {Boolean} [preventDefault] true to prevent the default action too
|
|
* @return {Ext.dom.Element} this
|
|
*/
|
|
swallowEvent: function(eventName, preventDefault) {
|
|
var me = this,
|
|
e, eLen,
|
|
fn = function(e) {
|
|
e.stopPropagation();
|
|
if (preventDefault) {
|
|
e.preventDefault();
|
|
}
|
|
};
|
|
if (Ext.isArray(eventName)) {
|
|
eLen = eventName.length;
|
|
for (e = 0; e < eLen; e++) {
|
|
me.on(eventName[e], fn);
|
|
}
|
|
return me;
|
|
}
|
|
me.on(eventName, fn);
|
|
return me;
|
|
},
|
|
/**
|
|
* Blinks the element as if it was clicked and then collapses on its center (similar to switching off a television).
|
|
* When the effect is completed, the element will be hidden (visibility = 'hidden') but block elements will still
|
|
* take up space in the document. The element must be removed from the DOM using the 'remove' config option if
|
|
* desired. Usage:
|
|
*
|
|
* // default
|
|
* el.switchOff();
|
|
*
|
|
* // all config options shown with default values
|
|
* el.switchOff({
|
|
* easing: 'easeIn',
|
|
* duration: .3,
|
|
* remove: false,
|
|
* useDisplay: false
|
|
* });
|
|
*
|
|
* @param {Object} options (optional) Object literal with any of the {@link Ext.fx.Anim} config options
|
|
* @return {Ext.dom.Element} The Element
|
|
*/
|
|
switchOff: function(options) {
|
|
var me = this,
|
|
dom = me.dom,
|
|
beforeAnim;
|
|
options = Ext.applyIf(options || {}, {
|
|
easing: 'ease-in',
|
|
duration: 500,
|
|
remove: false,
|
|
useDisplay: false
|
|
});
|
|
beforeAnim = function() {
|
|
var el = Ext.fly(dom, '_anim'),
|
|
animScope = this,
|
|
size = el.getSize(),
|
|
xy = el.getXY(),
|
|
keyframe, position;
|
|
el.clearOpacity();
|
|
el.clip();
|
|
position = el.getPositioning();
|
|
keyframe = new Ext.fx.Animator({
|
|
target: dom,
|
|
duration: options.duration,
|
|
easing: options.easing,
|
|
keyframes: {
|
|
33: {
|
|
opacity: 0.3
|
|
},
|
|
66: {
|
|
height: 1,
|
|
y: xy[1] + size.height / 2
|
|
},
|
|
100: {
|
|
width: 1,
|
|
x: xy[0] + size.width / 2
|
|
}
|
|
}
|
|
});
|
|
keyframe.on('afteranimate', function() {
|
|
var el = Ext.fly(dom, '_anim');
|
|
if (options.useDisplay) {
|
|
el.setDisplayed(false);
|
|
} else {
|
|
el.hide();
|
|
}
|
|
el.clearOpacity();
|
|
el.setPositioning(position);
|
|
el.setSize(size);
|
|
// kill the no-op element animation created below
|
|
animScope.end();
|
|
});
|
|
};
|
|
me.animate({
|
|
// See "A Note About Wrapped Animations" at the top of this class:
|
|
duration: (Math.max(options.duration, 500) * 2),
|
|
listeners: {
|
|
beforeanimate: {
|
|
fn: beforeAnim
|
|
}
|
|
},
|
|
callback: options.callback,
|
|
scope: options.scope
|
|
});
|
|
return me;
|
|
},
|
|
/**
|
|
* @private
|
|
* Currently used for updating grid cells without modifying DOM structure
|
|
*
|
|
* Synchronizes content of this Element with the content of the passed element.
|
|
*
|
|
* Style and CSS class are copied from source into this Element, and contents are synced
|
|
* recursively. If a child node is a text node, the textual data is copied.
|
|
*/
|
|
syncContent: function(source) {
|
|
source = Ext.getDom(source);
|
|
var sourceNodes = source.childNodes,
|
|
sourceLen = sourceNodes.length,
|
|
dest = this.dom,
|
|
destNodes = dest.childNodes,
|
|
destLen = destNodes.length,
|
|
i, destNode, sourceNode, nodeType, newAttrs, attLen, attName,
|
|
elData = dest._extData;
|
|
// Copy top node's attributes across. Use IE-specific method if possible.
|
|
// In IE10, there is a problem where the className will not get updated
|
|
// in the view, even though the className on the dom element is correct.
|
|
// See EXTJSIV-9462
|
|
if (Ext.isIE9m && dest.mergeAttributes) {
|
|
dest.mergeAttributes(source, true);
|
|
// EXTJSIV-6803. IE's mergeAttributes appears not to make the source's "src" value available until after the image is ready.
|
|
// So programmatically copy any src attribute.
|
|
dest.src = source.src;
|
|
} else {
|
|
newAttrs = source.attributes;
|
|
attLen = newAttrs.length;
|
|
for (i = 0; i < attLen; i++) {
|
|
attName = newAttrs[i].name;
|
|
if (attName !== 'id') {
|
|
dest.setAttribute(attName, newAttrs[i].value);
|
|
}
|
|
}
|
|
}
|
|
// The element's data is no longer synchronized. We just overwrite it in the DOM
|
|
if (elData) {
|
|
elData.isSynchronized = false;
|
|
}
|
|
// If the number of child nodes does not match, fall back to replacing innerHTML
|
|
if (sourceLen !== destLen) {
|
|
dest.innerHTML = source.innerHTML;
|
|
return;
|
|
}
|
|
// Loop through source nodes.
|
|
// If there are fewer, we must remove excess
|
|
for (i = 0; i < sourceLen; i++) {
|
|
sourceNode = sourceNodes[i];
|
|
destNode = destNodes[i];
|
|
nodeType = sourceNode.nodeType;
|
|
// If node structure is out of sync, just drop innerHTML in and return
|
|
if (nodeType !== destNode.nodeType || (nodeType === 1 && sourceNode.tagName !== destNode.tagName)) {
|
|
dest.innerHTML = source.innerHTML;
|
|
return;
|
|
}
|
|
// Update text node
|
|
if (nodeType === 3) {
|
|
destNode.data = sourceNode.data;
|
|
} else // Sync element content
|
|
{
|
|
if (sourceNode.id && destNode.id !== sourceNode.id) {
|
|
destNode.id = sourceNode.id;
|
|
}
|
|
destNode.style.cssText = sourceNode.style.cssText;
|
|
destNode.className = sourceNode.className;
|
|
Ext.fly(destNode, '_syncContent').syncContent(sourceNode);
|
|
}
|
|
}
|
|
},
|
|
/**
|
|
* Toggles the element's visibility, depending on visibility mode.
|
|
* @param {Boolean/Object} [animate] True for the default animation, or a standard Element animation config object
|
|
* @return {Ext.dom.Element} this
|
|
*/
|
|
toggle: function(animate) {
|
|
var me = this;
|
|
me.setVisible(!me.isVisible(), me.anim(animate));
|
|
return me;
|
|
},
|
|
/**
|
|
* Hides a previously applied mask.
|
|
*/
|
|
unmask: function() {
|
|
var me = this,
|
|
data = me.getData(),
|
|
maskEl = data.maskEl,
|
|
style;
|
|
if (maskEl) {
|
|
style = maskEl.dom.style;
|
|
// Remove resource-intensive CSS expressions as soon as they are not required.
|
|
if (style.clearExpression) {
|
|
style.clearExpression('width');
|
|
style.clearExpression('height');
|
|
}
|
|
if (maskEl) {
|
|
maskEl.destroy();
|
|
delete data.maskEl;
|
|
}
|
|
me.removeCls([
|
|
XMASKED,
|
|
XMASKEDRELATIVE
|
|
]);
|
|
}
|
|
me.restoreTabbableState(me.dom === DOC.body);
|
|
},
|
|
/**
|
|
* Return clipping (overflow) to original clipping before {@link #clip} was called
|
|
* @return {Ext.dom.Element} this
|
|
*/
|
|
unclip: function() {
|
|
var me = this,
|
|
data = me.getData(),
|
|
clip;
|
|
if (data[ISCLIPPED]) {
|
|
data[ISCLIPPED] = false;
|
|
clip = data[ORIGINALCLIP];
|
|
if (clip.o) {
|
|
me.setStyle(OVERFLOW, clip.o);
|
|
}
|
|
if (clip.x) {
|
|
me.setStyle(OVERFLOWX, clip.x);
|
|
}
|
|
if (clip.y) {
|
|
me.setStyle(OVERFLOWY, clip.y);
|
|
}
|
|
}
|
|
return me;
|
|
},
|
|
translate: function(x, y, z) {
|
|
if (Ext.supports.CssTransforms && !Ext.isIE9m) {
|
|
this.callParent(arguments);
|
|
} else {
|
|
if (x != null) {
|
|
this.dom.style.left = x + 'px';
|
|
}
|
|
if (y != null) {
|
|
this.dom.style.top = y + 'px';
|
|
}
|
|
}
|
|
},
|
|
/**
|
|
* Disables text selection for this element (normalized across browsers)
|
|
* @return {Ext.dom.Element} this
|
|
*/
|
|
unselectable: function() {
|
|
// The approach used to disable text selection combines CSS, HTML attributes and DOM events. Importantly the
|
|
// strategy is designed to be expressible in markup, so that elements can be rendered unselectable without
|
|
// needing modifications post-render. e.g.:
|
|
//
|
|
// <div class="x-unselectable" unselectable="on"></div>
|
|
//
|
|
// Changes to this method may need to be reflected elsewhere, e.g. ProtoElement.
|
|
var me = this;
|
|
// The unselectable property (or similar) is supported by various browsers but Opera is the only browser that
|
|
// doesn't support any of the other techniques. The problem with it is that it isn't inherited by child
|
|
// elements. Theoretically we could add it to all children but the performance would be terrible. In certain
|
|
// key locations (e.g. panel headers) we add unselectable="on" to extra elements during rendering just for
|
|
// Opera's benefit.
|
|
if (Ext.isOpera) {
|
|
me.dom.unselectable = 'on';
|
|
}
|
|
// In Mozilla and WebKit the CSS properties -moz-user-select and -webkit-user-select prevent a selection
|
|
// originating in an element. These are inherited, which is what we want.
|
|
//
|
|
// In IE we rely on a listener for the selectstart event instead. We don't need to register a listener on the
|
|
// individual element, instead we use a single listener and rely on event propagation to listen for the event at
|
|
// the document level. That listener will walk up the DOM looking for nodes that have either of the classes
|
|
// x-selectable or x-unselectable. This simulates the CSS inheritance approach.
|
|
//
|
|
// IE 10 is expected to support -ms-user-select so the listener may not be required.
|
|
me.removeCls(Element.selectableCls);
|
|
me.addCls(Element.unselectableCls);
|
|
return me;
|
|
},
|
|
privates: {
|
|
/**
|
|
* @private
|
|
*/
|
|
findTabbableElements: function(options) {
|
|
var skipSelf, skipChildren, excludeRoot, includeSaved, includeHidden,
|
|
dom = this.dom,
|
|
cAttr = Ext.Element.tabbableSavedCounterAttribute,
|
|
selection = [],
|
|
idx = 0,
|
|
nodes, node, fly, i, len, tabIndex;
|
|
if (!dom) {
|
|
return selection;
|
|
}
|
|
if (options) {
|
|
skipSelf = options.skipSelf;
|
|
skipChildren = options.skipChildren;
|
|
excludeRoot = options.excludeRoot;
|
|
includeSaved = options.includeSaved;
|
|
includeHidden = options.includeHidden;
|
|
}
|
|
excludeRoot = excludeRoot && Ext.getDom(excludeRoot);
|
|
if (excludeRoot && excludeRoot.contains(dom)) {
|
|
return selection;
|
|
}
|
|
if (!skipSelf && ((includeSaved && dom.hasAttribute(cAttr)) || this.isTabbable(includeHidden))) {
|
|
selection[idx++] = dom;
|
|
}
|
|
if (skipChildren) {
|
|
return selection;
|
|
}
|
|
nodes = dom.querySelectorAll(Ext.Element.tabbableSelector);
|
|
len = nodes.length;
|
|
if (!len) {
|
|
return selection;
|
|
}
|
|
fly = new Ext.dom.Fly();
|
|
// We're only interested in the elements that an user can *tab into*,
|
|
// not all programmatically focusable elements. So we have to filter
|
|
// these out.
|
|
for (i = 0; i < len; i++) {
|
|
node = nodes[i];
|
|
// A node with tabIndex < 0 absolutely can't be tabbable
|
|
// so we can save a function call if that is the case.
|
|
// Note that we can't use node.tabIndex here because IE
|
|
// will return 0 for elements that have no tabindex
|
|
// attribute defined, regardless of whether they are
|
|
// tabbable or not.
|
|
tabIndex = +node.getAttribute('tabIndex');
|
|
// quicker than parseInt
|
|
// tabIndex value may be null for nodes with no tabIndex defined;
|
|
// most of those may be naturally tabbable. We don't want to
|
|
// check this here, that's isTabbable()'s job and it's not trivial.
|
|
// We explicitly check that tabIndex is not negative. The expression
|
|
// below is purposeful if hairy; this is a very hot code path so care
|
|
// is taken to minimize the amount of DOM calls that could be avoided.
|
|
// A node may have its tabindex saved by previous calls to
|
|
// saveTabbableState(); in that case we need to return that node
|
|
// so that its saved counter could be properly incremented or
|
|
// decremented.
|
|
if (((includeSaved && node.hasAttribute(cAttr)) || (!(tabIndex < 0) && fly.attach(node).isTabbable(includeHidden))) && !(excludeRoot && (excludeRoot === node || excludeRoot.contains(node)))) {
|
|
selection[idx++] = node;
|
|
}
|
|
}
|
|
return selection;
|
|
},
|
|
/**
|
|
* @private
|
|
*/
|
|
saveTabbableState: function(options) {
|
|
var counterAttr = Ext.Element.tabbableSavedCounterAttribute,
|
|
savedAttr = Ext.Element.tabbableSavedValueAttribute,
|
|
counter, nodes, node, i, len;
|
|
// By default include already saved tabbables, and just increase their save counter.
|
|
// For example, if a View with saved tabbables is covered by a modal Window, saveTabbableState
|
|
// Must disable tabbability for the whole document. But upon unmask, the View must not
|
|
// be restored to tabbability. It must only have its save level decremented.
|
|
// AbstractView#toggleChildrenTabbability however pases this as false so that
|
|
// it may be called upon row add and it does not increment save levels on already saved tabbables.
|
|
if (!options || options.includeSaved == null) {
|
|
options = Ext.Object.chain(options || null);
|
|
options.includeSaved = true;
|
|
}
|
|
nodes = this.findTabbableElements(options);
|
|
for (i = 0 , len = nodes.length; i < len; i++) {
|
|
node = nodes[i];
|
|
counter = +node.getAttribute(counterAttr);
|
|
if (counter > 0) {
|
|
node.setAttribute(counterAttr, ++counter);
|
|
} else {
|
|
// tabIndex could be set on both naturally tabbable and generic elements.
|
|
// Either way we need to save it to restore later.
|
|
if (node.hasAttribute('tabIndex')) {
|
|
node.setAttribute(savedAttr, node.getAttribute('tabIndex'));
|
|
} else // When no tabIndex is specified, that means a naturally tabbable element.
|
|
{
|
|
node.setAttribute(savedAttr, 'none');
|
|
}
|
|
// We disable the tabbable state by setting tabIndex to -1.
|
|
// The element can still be focused programmatically though.
|
|
node.setAttribute('tabIndex', '-1');
|
|
node.setAttribute(counterAttr, '1');
|
|
}
|
|
}
|
|
return nodes;
|
|
},
|
|
/**
|
|
* @private
|
|
*/
|
|
restoreTabbableState: function(skipSelf, skipChildren) {
|
|
var dom = this.dom,
|
|
counterAttr = Ext.Element.tabbableSavedCounterAttribute,
|
|
savedAttr = Ext.Element.tabbableSavedValueAttribute,
|
|
nodes = [],
|
|
idx, counter, nodes, node, i, len;
|
|
if (!dom) {
|
|
return this;
|
|
}
|
|
if (!skipChildren) {
|
|
nodes = Ext.Array.from(dom.querySelectorAll('[' + counterAttr + ']'));
|
|
}
|
|
if (!skipSelf) {
|
|
nodes.unshift(dom);
|
|
}
|
|
for (i = 0 , len = nodes.length; i < len; i++) {
|
|
node = nodes[i];
|
|
if (!node.hasAttribute(counterAttr) || !node.hasAttribute(savedAttr)) {
|
|
|
|
continue;
|
|
}
|
|
counter = +node.getAttribute(counterAttr);
|
|
if (counter > 1) {
|
|
node.setAttribute(counterAttr, --counter);
|
|
|
|
continue;
|
|
}
|
|
idx = node.getAttribute(savedAttr);
|
|
// That is a naturally tabbable element
|
|
if (idx === 'none') {
|
|
node.removeAttribute('tabIndex');
|
|
} else {
|
|
node.setAttribute('tabIndex', idx);
|
|
}
|
|
node.removeAttribute(savedAttr);
|
|
node.removeAttribute(counterAttr);
|
|
}
|
|
return nodes;
|
|
}
|
|
},
|
|
deprecated: {
|
|
'4.0': {
|
|
methods: {
|
|
/**
|
|
* Creates a pause before any subsequent queued effects begin. If there are no effects queued after the pause it will
|
|
* have no effect. Usage:
|
|
*
|
|
* el.pause(1);
|
|
*
|
|
* @deprecated 4.0 Use the `delay` config to {@link #animate} instead.
|
|
* @param {Number} seconds The length of time to pause (in seconds)
|
|
* @return {Ext.dom.Element} The Element
|
|
*/
|
|
pause: function(ms) {
|
|
var me = this;
|
|
Ext.fx.Manager.setFxDefaults(me.id, {
|
|
delay: ms
|
|
});
|
|
return me;
|
|
},
|
|
/**
|
|
* Animates the transition of an element's dimensions from a starting height/width to an ending height/width. This
|
|
* method is a convenience implementation of {@link #shift}. Usage:
|
|
*
|
|
* // change height and width to 100x100 pixels
|
|
* el.scale(100, 100);
|
|
*
|
|
* // common config options shown with default values. The height and width will default to
|
|
* // the element's existing values if passed as null.
|
|
* el.scale(
|
|
* [element's width],
|
|
* [element's height], {
|
|
* easing: 'easeOut',
|
|
* duration: 350
|
|
* }
|
|
* );
|
|
*
|
|
* @deprecated 4.0 Just use {@link #animate} instead.
|
|
* @param {Number} width The new width (pass undefined to keep the original width)
|
|
* @param {Number} height The new height (pass undefined to keep the original height)
|
|
* @param {Object} options (optional) Object literal with any of the {@link Ext.fx.Anim} config options
|
|
* @return {Ext.dom.Element} The Element
|
|
*/
|
|
scale: function(w, h, o) {
|
|
this.animate(Ext.apply({}, o, {
|
|
width: w,
|
|
height: h
|
|
}));
|
|
return this;
|
|
},
|
|
/**
|
|
* Animates the transition of any combination of an element's dimensions, xy position and/or opacity. Any of these
|
|
* properties not specified in the config object will not be changed. This effect requires that at least one new
|
|
* dimension, position or opacity setting must be passed in on the config object in order for the function to have
|
|
* any effect. Usage:
|
|
*
|
|
* // slide the element horizontally to x position 200 while changing the height and opacity
|
|
* el.shift({ x: 200, height: 50, opacity: .8 });
|
|
*
|
|
* // common config options shown with default values.
|
|
* el.shift({
|
|
* width: [element's width],
|
|
* height: [element's height],
|
|
* x: [element's x position],
|
|
* y: [element's y position],
|
|
* opacity: [element's opacity],
|
|
* easing: 'easeOut',
|
|
* duration: 350
|
|
* });
|
|
*
|
|
* @deprecated 4.0 Just use {@link #animate} instead.
|
|
* @param {Object} options Object literal with any of the {@link Ext.fx.Anim} config options
|
|
* @return {Ext.dom.Element} The Element
|
|
*/
|
|
shift: function(config) {
|
|
this.animate(config);
|
|
return this;
|
|
}
|
|
}
|
|
},
|
|
'4.2': {
|
|
methods: {
|
|
/**
|
|
* Sets the position of the element in page coordinates.
|
|
* @param {Number} x X value for new position (coordinates are page-based)
|
|
* @param {Number} y Y value for new position (coordinates are page-based)
|
|
* @param {Boolean/Object} [animate] True for the default animation, or a standard
|
|
* Element animation config object
|
|
* @return {Ext.dom.Element} this
|
|
* @deprecated 4.2.0 Use {@link Ext.dom.Element#setXY} instead.
|
|
*/
|
|
moveTo: function(x, y, animate) {
|
|
return this.setXY([
|
|
x,
|
|
y
|
|
], animate);
|
|
},
|
|
/**
|
|
* Sets the element's position and size in one shot. If animation is true then
|
|
* width, height, x and y will be animated concurrently.
|
|
*
|
|
* @param {Number} x X value for new position (coordinates are page-based)
|
|
* @param {Number} y Y value for new position (coordinates are page-based)
|
|
* @param {Number/String} width The new width. This may be one of:
|
|
*
|
|
* - A Number specifying the new width in pixels
|
|
* - A String used to set the CSS width style. Animation may **not** be used.
|
|
*
|
|
* @param {Number/String} height The new height. This may be one of:
|
|
*
|
|
* - A Number specifying the new height in pixels
|
|
* - A String used to set the CSS height style. Animation may **not** be used.
|
|
*
|
|
* @param {Boolean/Object} [animate] true for the default animation or
|
|
* a standard Element animation config object
|
|
*
|
|
* @return {Ext.dom.Element} this
|
|
* @deprecated 4.2.0 Use {@link Ext.util.Positionable#setBox} instead.
|
|
*/
|
|
setBounds: function(x, y, width, height, animate) {
|
|
return this.setBox({
|
|
x: x,
|
|
y: y,
|
|
width: width,
|
|
height: height
|
|
}, animate);
|
|
},
|
|
/**
|
|
* Sets the element's left and top positions directly using CSS style
|
|
* @param {Number/String} left Number of pixels or CSS string value to
|
|
* set as the left CSS property value
|
|
* @param {Number/String} top Number of pixels or CSS string value to
|
|
* set as the top CSS property value
|
|
* @return {Ext.dom.Element} this
|
|
* @deprecated 4.2.0 Use {@link Ext.dom.Element#setLocalXY} instead
|
|
*/
|
|
setLeftTop: function(left, top) {
|
|
var me = this,
|
|
style = me.dom.style;
|
|
style.left = Element.addUnits(left);
|
|
style.top = Element.addUnits(top);
|
|
if (me.shadow || me.shim) {
|
|
me.syncUnderlays();
|
|
}
|
|
return me;
|
|
},
|
|
/**
|
|
* Sets the position of the element in page coordinates.
|
|
* @param {Number} x X value for new position
|
|
* @param {Number} y Y value for new position
|
|
* @param {Boolean/Object} [animate] True for the default animation, or a standard
|
|
* Element animation config object
|
|
* @return {Ext.dom.Element} this
|
|
* @deprecated 4.2.0 Use {@link Ext.dom.Element#setXY} instead.
|
|
*/
|
|
setLocation: function(x, y, animate) {
|
|
return this.setXY([
|
|
x,
|
|
y
|
|
], animate);
|
|
}
|
|
}
|
|
},
|
|
'5.0': {
|
|
methods: {
|
|
/**
|
|
* Returns the value of a namespaced attribute from the element's underlying DOM node.
|
|
* @param {String} namespace The namespace in which to look for the attribute
|
|
* @param {String} name The attribute name
|
|
* @return {String} The attribute value
|
|
* @deprecated 5.0.0 Please use {@link Ext.dom.Element#getAttribute} instead.
|
|
*/
|
|
getAttributeNS: function(namespace, name) {
|
|
return this.getAttribute(name, namespace);
|
|
},
|
|
/**
|
|
* Calculates the x, y to center this element on the screen
|
|
* @return {Number[]} The x, y values [x, y]
|
|
* @deprecated 5.0.0 Use {@link Ext.dom.Element#getAlignToXY} instead.
|
|
* el.getAlignToXY(document, 'c-c');
|
|
*/
|
|
getCenterXY: function() {
|
|
return this.getAlignToXY(DOC, 'c-c');
|
|
},
|
|
/**
|
|
* Returns either the offsetHeight or the height of this element based on CSS height adjusted by padding or borders
|
|
* when needed to simulate offsetHeight when offsets aren't available. This may not work on display:none elements
|
|
* if a height has not been set using CSS.
|
|
* @return {Number}
|
|
* @deprecated 5.0.0 use {@link Ext.dom.Element#getHeight} instead
|
|
*/
|
|
getComputedHeight: function() {
|
|
return Math.max(this.dom.offsetHeight, this.dom.clientHeight) || parseFloat(this.getStyle(HEIGHT)) || 0;
|
|
},
|
|
/**
|
|
* Returns either the offsetWidth or the width of this element based on CSS width adjusted by padding or borders
|
|
* when needed to simulate offsetWidth when offsets aren't available. This may not work on display:none elements
|
|
* if a width has not been set using CSS.
|
|
* @return {Number}
|
|
* @deprecated 5.0.0 use {@link Ext.dom.Element#getWidth} instead.
|
|
*/
|
|
getComputedWidth: function() {
|
|
return Math.max(this.dom.offsetWidth, this.dom.clientWidth) || parseFloat(this.getStyle(WIDTH)) || 0;
|
|
},
|
|
/**
|
|
* Returns the dimensions of the element available to lay content out in.
|
|
*
|
|
* getStyleSize utilizes prefers style sizing if present, otherwise it chooses the larger of offsetHeight/clientHeight and
|
|
* offsetWidth/clientWidth. To obtain the size excluding scrollbars, use getViewSize.
|
|
*
|
|
* Sizing of the document body is handled at the adapter level which handles special cases for IE and strict modes, etc.
|
|
*
|
|
* @return {Object} Object describing width and height.
|
|
* @return {Number} return.width
|
|
* @return {Number} return.height
|
|
* @deprecated 5.0.0 Use {@link Ext.dom.Element#getSize} instead.
|
|
*/
|
|
getStyleSize: function() {
|
|
var me = this,
|
|
d = this.dom,
|
|
isDoc = (d === DOC || d === DOC.body),
|
|
s, w, h;
|
|
// If the body, use static methods
|
|
if (isDoc) {
|
|
return {
|
|
width: Element.getViewportWidth(),
|
|
height: Element.getViewportHeight()
|
|
};
|
|
}
|
|
s = me.getStyle([
|
|
'height',
|
|
'width'
|
|
], true);
|
|
//seek inline
|
|
// Use Styles if they are set
|
|
if (s.width && s.width !== 'auto') {
|
|
w = parseFloat(s.width);
|
|
}
|
|
// Use Styles if they are set
|
|
if (s.height && s.height !== 'auto') {
|
|
h = parseFloat(s.height);
|
|
}
|
|
// Use getWidth/getHeight if style not set.
|
|
return {
|
|
width: w || me.getWidth(true),
|
|
height: h || me.getHeight(true)
|
|
};
|
|
},
|
|
/**
|
|
* Returns true if this element uses the border-box-sizing model. This method is
|
|
* deprecated as of version 5.0 because border-box sizing is forced upon all elements
|
|
* via a style sheet rule, and the browsers that do not support border-box (IE6/7 strict
|
|
* mode) are no longer supported.
|
|
* @deprecated 5.0.0
|
|
* @return {Boolean}
|
|
*/
|
|
isBorderBox: function() {
|
|
return true;
|
|
},
|
|
/**
|
|
* Returns true if display is not "none"
|
|
* @return {Boolean}
|
|
* @deprecated 5.0.0 use element.isStyle('display', 'none');
|
|
*/
|
|
isDisplayed: function() {
|
|
return !this.isStyle('display', 'none');
|
|
},
|
|
/**
|
|
* Checks whether this element can be focused.
|
|
* @return {Boolean} True if the element is focusable
|
|
* @deprecated 5.0.0 use {@link #isFocusable} instead
|
|
*/
|
|
focusable: 'isFocusable'
|
|
}
|
|
}
|
|
}
|
|
};
|
|
})(), function() {
|
|
var Element = Ext.dom.Element,
|
|
proto = Element.prototype,
|
|
useDocForId = !Ext.isIE8,
|
|
DOC = document,
|
|
view = DOC.defaultView,
|
|
opacityRe = /alpha\(opacity=(.*)\)/i,
|
|
trimRe = /^\s+|\s+$/g,
|
|
styleHooks = proto.styleHooks,
|
|
supports = Ext.supports,
|
|
verticalStyleHooks90, verticalStyleHooks270, edges, k, edge, borderWidth, getBorderWidth;
|
|
proto._init(Element);
|
|
delete proto._init;
|
|
Ext.plainTableCls = Ext.baseCSSPrefix + 'table-plain';
|
|
Ext.plainListCls = Ext.baseCSSPrefix + 'list-plain';
|
|
// ensure that any methods added by this override are also added to Ext.CompositeElementLite
|
|
if (Ext.CompositeElementLite) {
|
|
Ext.CompositeElementLite.importElementMethods();
|
|
}
|
|
if (!supports.Opacity && Ext.isIE) {
|
|
Ext.apply(styleHooks.opacity, {
|
|
get: function(dom) {
|
|
var filter = dom.style.filter,
|
|
match, opacity;
|
|
if (filter.match) {
|
|
match = filter.match(opacityRe);
|
|
if (match) {
|
|
opacity = parseFloat(match[1]);
|
|
if (!isNaN(opacity)) {
|
|
return opacity ? opacity / 100 : 0;
|
|
}
|
|
}
|
|
}
|
|
return 1;
|
|
},
|
|
set: function(dom, value) {
|
|
var style = dom.style,
|
|
val = style.filter.replace(opacityRe, '').replace(trimRe, '');
|
|
style.zoom = 1;
|
|
// ensure dom.hasLayout
|
|
// value can be a number or '' or null... so treat falsey as no opacity
|
|
if (typeof (value) === 'number' && value >= 0 && value < 1) {
|
|
value *= 100;
|
|
style.filter = val + (val.length ? ' ' : '') + 'alpha(opacity=' + value + ')';
|
|
} else {
|
|
style.filter = val;
|
|
}
|
|
}
|
|
});
|
|
}
|
|
if (!supports.matchesSelector) {
|
|
// Match basic tagName.ClassName selector syntax for is implementation
|
|
var simpleSelectorRe = /^([a-z]+|\*)?(?:\.([a-z][a-z\-_0-9]*))?$/i,
|
|
dashRe = /\-/g,
|
|
fragment,
|
|
classMatcher = function(tag, cls) {
|
|
var classRe = new RegExp('(?:^|\\s+)' + cls.replace(dashRe, '\\-') + '(?:\\s+|$)');
|
|
if (tag && tag !== '*') {
|
|
tag = tag.toUpperCase();
|
|
return function(el) {
|
|
return el.tagName === tag && classRe.test(el.className);
|
|
};
|
|
}
|
|
return function(el) {
|
|
return classRe.test(el.className);
|
|
};
|
|
},
|
|
tagMatcher = function(tag) {
|
|
tag = tag.toUpperCase();
|
|
return function(el) {
|
|
return el.tagName === tag;
|
|
};
|
|
},
|
|
cache = {};
|
|
proto.matcherCache = cache;
|
|
proto.is = function(selector) {
|
|
// Empty selector always matches
|
|
if (!selector) {
|
|
return true;
|
|
}
|
|
var dom = this.dom,
|
|
cls, match, testFn, root, isOrphan, is, tag;
|
|
// Only Element node types can be matched.
|
|
if (dom.nodeType !== 1) {
|
|
return false;
|
|
}
|
|
if (!(testFn = Ext.isFunction(selector) ? selector : cache[selector])) {
|
|
if (!(match = selector.match(simpleSelectorRe))) {
|
|
// Not a simple tagName.className selector, do it the hard way
|
|
root = dom.parentNode;
|
|
if (!root) {
|
|
isOrphan = true;
|
|
root = fragment || (fragment = DOC.createDocumentFragment());
|
|
fragment.appendChild(dom);
|
|
}
|
|
is = Ext.Array.indexOf(Ext.fly(root, '_is').query(selector), dom) !== -1;
|
|
if (isOrphan) {
|
|
fragment.removeChild(dom);
|
|
}
|
|
return is;
|
|
}
|
|
tag = match[1];
|
|
cls = match[2];
|
|
cache[selector] = testFn = cls ? classMatcher(tag, cls) : tagMatcher(tag);
|
|
}
|
|
return testFn(dom);
|
|
};
|
|
}
|
|
// IE8 needs its own implementation of getStyle because it doesn't support getComputedStyle
|
|
if (!view || !view.getComputedStyle) {
|
|
proto.getStyle = function(property, inline) {
|
|
var me = this,
|
|
dom = me.dom,
|
|
multiple = typeof property !== 'string',
|
|
prop = property,
|
|
props = prop,
|
|
len = 1,
|
|
isInline = inline,
|
|
styleHooks = me.styleHooks,
|
|
camel, domStyle, values, hook, out, style, i;
|
|
if (multiple) {
|
|
values = {};
|
|
prop = props[0];
|
|
i = 0;
|
|
if (!(len = props.length)) {
|
|
return values;
|
|
}
|
|
}
|
|
if (!dom || dom.documentElement) {
|
|
return values || '';
|
|
}
|
|
domStyle = dom.style;
|
|
if (inline) {
|
|
style = domStyle;
|
|
} else {
|
|
style = dom.currentStyle;
|
|
// fallback to inline style if rendering context not available
|
|
if (!style) {
|
|
isInline = true;
|
|
style = domStyle;
|
|
}
|
|
}
|
|
do {
|
|
hook = styleHooks[prop];
|
|
if (!hook) {
|
|
styleHooks[prop] = hook = {
|
|
name: Element.normalize(prop)
|
|
};
|
|
}
|
|
if (hook.get) {
|
|
out = hook.get(dom, me, isInline, style);
|
|
} else {
|
|
camel = hook.name;
|
|
out = style[camel];
|
|
}
|
|
if (!multiple) {
|
|
return out;
|
|
}
|
|
values[prop] = out;
|
|
prop = props[++i];
|
|
} while (i < len);
|
|
return values;
|
|
};
|
|
}
|
|
// override getStyle for border-*-width
|
|
if (Ext.isIE8) {
|
|
getBorderWidth = function(dom, el, inline, style) {
|
|
if (style[this.styleName] === 'none') {
|
|
return '0px';
|
|
}
|
|
return style[this.name];
|
|
};
|
|
edges = [
|
|
'Top',
|
|
'Right',
|
|
'Bottom',
|
|
'Left'
|
|
];
|
|
k = edges.length;
|
|
while (k--) {
|
|
edge = edges[k];
|
|
borderWidth = 'border' + edge + 'Width';
|
|
styleHooks['border-' + edge.toLowerCase() + '-width'] = styleHooks[borderWidth] = {
|
|
name: borderWidth,
|
|
styleName: 'border' + edge + 'Style',
|
|
get: getBorderWidth
|
|
};
|
|
}
|
|
// IE8 has an odd bug with handling font icons in pseudo elements;
|
|
// it will render the icon once and not update it when something
|
|
// like text color is changed via style addition or removal.
|
|
// We have to force icon repaint by adding a style with forced empty
|
|
// pseudo element content, (x-sync-repaint) and removing it back to work
|
|
// around this issue.
|
|
// See this: https://github.com/FortAwesome/Font-Awesome/issues/954
|
|
// and this: https://github.com/twbs/bootstrap/issues/13863
|
|
var syncRepaintCls = Ext.baseCSSPrefix + 'sync-repaint';
|
|
proto.syncRepaint = function() {
|
|
this.addCls(syncRepaintCls);
|
|
// Measuring element width will make the browser to repaint it
|
|
this.getWidth();
|
|
// Removing empty content makes the icon to appear again and be redrawn
|
|
this.removeCls(syncRepaintCls);
|
|
};
|
|
}
|
|
if (Ext.isIE10m) {
|
|
Ext.override(Element, {
|
|
focus: function(defer, dom) {
|
|
var me = this,
|
|
ex;
|
|
dom = dom || me.dom;
|
|
if (Number(defer)) {
|
|
Ext.defer(me.focus, defer, me, [
|
|
null,
|
|
dom
|
|
]);
|
|
} else {
|
|
Ext.GlobalEvents.fireEvent('beforefocus', dom);
|
|
// IE10m has an acute problem with focusing input elements;
|
|
// when the element was just shown and did not have enough
|
|
// time to initialize, focusing it might fail. The problem
|
|
// is somewhat random in nature; most of the time focusing
|
|
// an input element will succeed, failing only occasionally.
|
|
// When it fails, the focus will be thrown to the document
|
|
// body element, with subsequent focusout/focusin event pair
|
|
// on the body, which throws off our focusenter/focusleave
|
|
// processing.
|
|
// Fortunately for us, when this focus failure happens, the
|
|
// resulting focusout event will happen *synchronously*
|
|
// unlike the normal focusing events which IE will fire
|
|
// asynchronously. Also fortunately for us, in most cases
|
|
// trying to focus the given element the second time
|
|
// immediately after it failed to focus the first time
|
|
// seems to do the trick; however when second focus attempt
|
|
// succeeds, it will result in focusout on the body and
|
|
// focusin on the given element, which again wreaks havoc
|
|
// on our focusenter/focusleave handling.
|
|
// The only workable solution we have is to pretend that
|
|
// focus never went to the document body and ignore the
|
|
// focusout and focusin caused by failed first focus attempt.
|
|
// To this end, we fudge the event stream in Focus publisher
|
|
// override.
|
|
if (dom && (dom.tagName === 'INPUT' || dom.tagname === 'TEXTAREA')) {
|
|
Ext.synchronouslyFocusing = document.activeElement;
|
|
}
|
|
// Also note that trying to focus an unfocusable element
|
|
// might throw an exception in IE8. What a cute idea, MS. :(
|
|
try {
|
|
dom.focus();
|
|
} catch (xcpt) {
|
|
ex = xcpt;
|
|
}
|
|
// Ok so now we have this situation when we tried to focus
|
|
// the first time but did not succeed. Let's try again but
|
|
// not if there was an exception the first time - when the
|
|
// "focus failure" happens it does so silently. :(
|
|
if (Ext.synchronouslyFocusing && document.activeElement !== dom && !ex) {
|
|
dom.focus();
|
|
}
|
|
Ext.synchronouslyFocusing = null;
|
|
}
|
|
return me;
|
|
}
|
|
});
|
|
}
|
|
Ext.apply(Ext, {
|
|
/**
|
|
* `true` to automatically uncache orphaned Ext.Elements periodically. If set to
|
|
* `false`, the application will be required to clean up orphaned Ext.Elements and
|
|
* it's listeners as to not cause memory leakage.
|
|
* @member Ext
|
|
*/
|
|
enableGarbageCollector: true,
|
|
// In sencha v5 isBorderBox is no longer needed since all supported browsers
|
|
// support border-box, but it is hard coded to true for backward compatibility
|
|
isBorderBox: true,
|
|
/**
|
|
* @property {Boolean} useShims
|
|
* @member Ext
|
|
* Set to `true` to use a {@link Ext.util.Floating#shim shim} on all floating Components
|
|
* and {@link Ext.LoadMask LoadMasks}
|
|
*/
|
|
useShims: false,
|
|
getElementById: function(id) {
|
|
var el = DOC.getElementById(id),
|
|
detachedBodyEl;
|
|
if (!el && (detachedBodyEl = Ext.detachedBodyEl)) {
|
|
el = detachedBodyEl.dom.querySelector(Ext.makeIdSelector(id));
|
|
}
|
|
return el;
|
|
},
|
|
/**
|
|
* Applies event listeners to elements by selectors when the document is ready.
|
|
* The event name is specified with an `@` suffix.
|
|
*
|
|
* Ext.addBehaviors({
|
|
* // add a listener for click on all anchors in element with id foo
|
|
* '#foo a@click': function(e, t){
|
|
* // do something
|
|
* },
|
|
*
|
|
* // add the same listener to multiple selectors (separated by comma BEFORE the @)
|
|
* '#foo a, #bar span.some-class@mouseover': function(){
|
|
* // do something
|
|
* }
|
|
* });
|
|
*
|
|
* @param {Object} obj The list of behaviors to apply
|
|
* @member Ext
|
|
*/
|
|
addBehaviors: function(o) {
|
|
if (!Ext.isReady) {
|
|
Ext.onInternalReady(function() {
|
|
Ext.addBehaviors(o);
|
|
});
|
|
} else {
|
|
var cache = {},
|
|
// simple cache for applying multiple behaviors to same selector does query multiple times
|
|
parts, b, s;
|
|
for (b in o) {
|
|
if ((parts = b.split('@'))[1]) {
|
|
// for Object prototype breakers
|
|
s = parts[0];
|
|
if (!cache[s]) {
|
|
cache[s] = Ext.fly(document).select(s, true);
|
|
}
|
|
cache[s].on(parts[1], o[b]);
|
|
}
|
|
}
|
|
cache = null;
|
|
}
|
|
}
|
|
});
|
|
if (Ext.isIE9m) {
|
|
Ext.getElementById = function(id) {
|
|
var el = DOC.getElementById(id),
|
|
detachedBodyEl;
|
|
if (!el && (detachedBodyEl = Ext.detachedBodyEl)) {
|
|
el = detachedBodyEl.dom.all[id];
|
|
}
|
|
return el;
|
|
};
|
|
proto.getById = function(id, asDom) {
|
|
var dom = this.dom,
|
|
ret = null,
|
|
entry, el;
|
|
if (dom) {
|
|
// for normal elements getElementById is the best solution, but if the el is
|
|
// not part of the document.body, we need to use all[]
|
|
el = (useDocForId && DOC.getElementById(id)) || dom.all[id];
|
|
if (el) {
|
|
if (asDom) {
|
|
ret = el;
|
|
} else {
|
|
// calling Element.get here is a real hit (2x slower) because it has to
|
|
// redetermine that we are giving it a dom el.
|
|
entry = Ext.cache[id];
|
|
if (entry) {
|
|
if (entry.skipGarbageCollection || !Ext.isGarbage(entry.dom)) {
|
|
ret = entry;
|
|
} else {
|
|
Ext.raise("Stale Element with id '" + el.id + "' found in Element cache. " + "Make sure to clean up Element instances using destroy()");
|
|
entry.destroy();
|
|
}
|
|
}
|
|
ret = ret || new Ext.Element(el);
|
|
}
|
|
}
|
|
}
|
|
return ret;
|
|
};
|
|
} else if (!DOC.querySelector) {
|
|
Ext.getDetachedBody = Ext.getBody;
|
|
Ext.getElementById = function(id) {
|
|
return DOC.getElementById(id);
|
|
};
|
|
proto.getById = function(id, asDom) {
|
|
var dom = DOC.getElementById(id);
|
|
return asDom ? dom : (dom ? Ext.get(dom) : null);
|
|
};
|
|
}
|
|
if (Ext.isIE && !(Ext.isIE9p && DOC.documentMode >= 9)) {
|
|
// Essentially all web browsers (Firefox, Internet Explorer, recent versions of Opera, Safari, Konqueror, and iCab,
|
|
// as a non-exhaustive list) return null when the specified attribute does not exist on the specified element.
|
|
// The DOM specification says that the correct return value in this case is actually the empty string, and some
|
|
// DOM implementations implement this behavior. The implementation of getAttribute in XUL (Gecko) actually follows
|
|
// the specification and returns an empty string. Consequently, you should use hasAttribute to check for an attribute's
|
|
// existence prior to calling getAttribute() if it is possible that the requested attribute does not exist on the specified element.
|
|
//
|
|
// https://developer.mozilla.org/en-US/docs/DOM/element.getAttribute
|
|
// http://www.w3.org/TR/DOM-Level-2-Core/core.html#ID-745549614
|
|
proto.getAttribute = function(name, ns) {
|
|
var d = this.dom,
|
|
type;
|
|
if (ns) {
|
|
type = typeof d[ns + ":" + name];
|
|
if (type !== 'undefined' && type !== 'unknown') {
|
|
return d[ns + ":" + name] || null;
|
|
}
|
|
return null;
|
|
}
|
|
if (name === "for") {
|
|
name = "htmlFor";
|
|
}
|
|
return d[name] || null;
|
|
};
|
|
}
|
|
Ext.onInternalReady(function() {
|
|
var transparentRe = /^(?:transparent|(?:rgba[(](?:\s*\d+\s*[,]){3}\s*0\s*[)]))$/i,
|
|
bodyCls = [],
|
|
//htmlCls = [],
|
|
origSetWidth = proto.setWidth,
|
|
origSetHeight = proto.setHeight,
|
|
origSetSize = proto.setSize,
|
|
pxRe = /^\d+(?:\.\d*)?px$/i,
|
|
colorStyles, i, name, camel;
|
|
if (supports.FixedTableWidthBug) {
|
|
// EXTJSIV-12665
|
|
// https://bugs.webkit.org/show_bug.cgi?id=130239
|
|
// Webkit browsers fail to layout correctly when a form field's width is less
|
|
// than the min-width of the body element. The only way to fix it seems to be
|
|
// to toggle the display style of the field's element before and after setting
|
|
// the width. Note: once the bug has been corrected by toggling the element's
|
|
// display, successive calls to setWidth will work without the hack. It's only
|
|
// when going from naturally widthed to having an explicit width that the bug
|
|
// occurs.
|
|
styleHooks.width = {
|
|
name: 'width',
|
|
set: function(dom, value, el) {
|
|
var style = dom.style,
|
|
needsFix = el._needsTableWidthFix,
|
|
origDisplay = style.display;
|
|
if (needsFix) {
|
|
style.display = 'none';
|
|
}
|
|
style.width = value;
|
|
if (needsFix) {
|
|
// repaint
|
|
dom.scrollWidth;
|
|
// jshint ignore:line
|
|
style.display = origDisplay;
|
|
}
|
|
}
|
|
};
|
|
proto.setWidth = function(width, animate) {
|
|
var me = this,
|
|
dom = me.dom,
|
|
style = dom.style,
|
|
needsFix = me._needsTableWidthFix,
|
|
origDisplay = style.display;
|
|
if (needsFix && !animate) {
|
|
style.display = 'none';
|
|
}
|
|
origSetWidth.call(me, width, animate);
|
|
if (needsFix && !animate) {
|
|
// repaint
|
|
dom.scrollWidth;
|
|
// jshint ignore:line
|
|
style.display = origDisplay;
|
|
}
|
|
return me;
|
|
};
|
|
proto.setSize = function(width, height, animate) {
|
|
var me = this,
|
|
dom = me.dom,
|
|
style = dom.style,
|
|
needsFix = me._needsTableWidthFix,
|
|
origDisplay = style.display;
|
|
if (needsFix && !animate) {
|
|
style.display = 'none';
|
|
}
|
|
origSetSize.call(me, width, height, animate);
|
|
if (needsFix && !animate) {
|
|
// repaint
|
|
dom.scrollWidth;
|
|
// jshint ignore:line
|
|
style.display = origDisplay;
|
|
}
|
|
return me;
|
|
};
|
|
}
|
|
if (Ext.isIE8) {
|
|
styleHooks.height = {
|
|
name: 'height',
|
|
set: function(dom, value, el) {
|
|
var component = el.component,
|
|
frameInfo, frameBodyStyle;
|
|
if (component && component._syncFrameHeight && el === component.el) {
|
|
frameBodyStyle = component.frameBody.dom.style;
|
|
if (pxRe.test(value)) {
|
|
frameInfo = component.getFrameInfo();
|
|
if (frameInfo) {
|
|
frameBodyStyle.height = (parseInt(value, 10) - frameInfo.height) + 'px';
|
|
}
|
|
} else if (!value || value === 'auto') {
|
|
frameBodyStyle.height = '';
|
|
}
|
|
}
|
|
dom.style.height = value;
|
|
}
|
|
};
|
|
proto.setHeight = function(height, animate) {
|
|
var component = this.component,
|
|
frameInfo, frameBodyStyle;
|
|
if (component && component._syncFrameHeight && this === component.el) {
|
|
frameBodyStyle = component.frameBody.dom.style;
|
|
if (!height || height === 'auto') {
|
|
frameBodyStyle.height = '';
|
|
} else {
|
|
frameInfo = component.getFrameInfo();
|
|
if (frameInfo) {
|
|
frameBodyStyle.height = (height - frameInfo.height) + 'px';
|
|
}
|
|
}
|
|
}
|
|
return origSetHeight.call(this, height, animate);
|
|
};
|
|
proto.setSize = function(width, height, animate) {
|
|
var component = this.component,
|
|
frameInfo, frameBodyStyle;
|
|
if (component && component._syncFrameHeight && this === component.el) {
|
|
frameBodyStyle = component.frameBody.dom.style;
|
|
if (!height || height === 'auto') {
|
|
frameBodyStyle.height = '';
|
|
} else {
|
|
frameInfo = component.getFrameInfo();
|
|
if (frameInfo) {
|
|
frameBodyStyle.height = (height - frameInfo.height) + 'px';
|
|
}
|
|
}
|
|
}
|
|
return origSetSize.call(this, width, height, animate);
|
|
};
|
|
}
|
|
// Element.unselectable relies on this listener to prevent selection in IE. Some other browsers support the event too
|
|
// but it is only strictly required for IE. In WebKit this listener causes subtle differences to how the browser handles
|
|
// the non-selection, e.g. whether or not the mouse cursor changes when attempting to select text.
|
|
Ext.getDoc().on('selectstart', function(ev, dom) {
|
|
var selectableCls = Element.selectableCls,
|
|
unselectableCls = Element.unselectableCls,
|
|
tagName = dom && dom.tagName;
|
|
tagName = tagName && tagName.toLowerCase();
|
|
// Element.unselectable is not really intended to handle selection within text fields and it is important that
|
|
// fields inside menus or panel headers don't inherit the unselectability. In most browsers this is automatic but in
|
|
// IE 9 the selectstart event can bubble up from text fields so we have to explicitly handle that case.
|
|
if (tagName === 'input' || tagName === 'textarea') {
|
|
return;
|
|
}
|
|
// Walk up the DOM checking the nodes. This may be 'slow' but selectstart events don't fire very often
|
|
while (dom && dom.nodeType === 1 && dom !== DOC.documentElement) {
|
|
var el = Ext.fly(dom);
|
|
// If the node has the class x-selectable then stop looking, the text selection is allowed
|
|
if (el.hasCls(selectableCls)) {
|
|
return;
|
|
}
|
|
// If the node has class x-unselectable then the text selection needs to be stopped
|
|
if (el.hasCls(unselectableCls)) {
|
|
ev.stopEvent();
|
|
return;
|
|
}
|
|
dom = dom.parentNode;
|
|
}
|
|
});
|
|
function fixTransparent(dom, el, inline, style) {
|
|
var value = style[this.name] || '';
|
|
return transparentRe.test(value) ? 'transparent' : value;
|
|
}
|
|
/*
|
|
* Helper function to create the function that will restore the selection.
|
|
*/
|
|
function makeSelectionRestoreFn(activeEl, start, end) {
|
|
return function() {
|
|
activeEl.selectionStart = start;
|
|
activeEl.selectionEnd = end;
|
|
};
|
|
}
|
|
/**
|
|
* Creates a function to call to clean up problems with the work-around for the
|
|
* WebKit RightMargin bug. The work-around is to add "display: 'inline-block'" to
|
|
* the element before calling getComputedStyle and then to restore its original
|
|
* display value. The problem with this is that it corrupts the selection of an
|
|
* INPUT or TEXTAREA element (as in the "I-beam" goes away but the focus remains).
|
|
* To cleanup after this, we need to capture the selection of any such element and
|
|
* then restore it after we have restored the display style.
|
|
*
|
|
* @param {HTMLElement} target The top-most element being adjusted.
|
|
* @private
|
|
*/
|
|
function getRightMarginFixCleaner(target) {
|
|
var hasInputBug = supports.DisplayChangeInputSelectionBug,
|
|
hasTextAreaBug = supports.DisplayChangeTextAreaSelectionBug,
|
|
activeEl, tag, start, end;
|
|
if (hasInputBug || hasTextAreaBug) {
|
|
activeEl = Element.getActiveElement();
|
|
tag = activeEl && activeEl.tagName;
|
|
if ((hasTextAreaBug && tag === 'TEXTAREA') || (hasInputBug && tag === 'INPUT' && activeEl.type === 'text')) {
|
|
if (Ext.fly(target).isAncestor(activeEl)) {
|
|
start = activeEl.selectionStart;
|
|
end = activeEl.selectionEnd;
|
|
if (Ext.isNumber(start) && Ext.isNumber(end)) {
|
|
// to be safe...
|
|
// We don't create the raw closure here inline because that
|
|
// will be costly even if we don't want to return it (nested
|
|
// function decls and exprs are often instantiated on entry
|
|
// regardless of whether execution ever reaches them):
|
|
return makeSelectionRestoreFn(activeEl, start, end);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return Ext.emptyFn;
|
|
}
|
|
// avoid special cases, just return a nop
|
|
function fixRightMargin(dom, el, inline, style) {
|
|
var result = style.marginRight,
|
|
domStyle, display;
|
|
// Ignore cases when the margin is correctly reported as 0, the bug only shows
|
|
// numbers larger.
|
|
if (result !== '0px') {
|
|
domStyle = dom.style;
|
|
display = domStyle.display;
|
|
domStyle.display = 'inline-block';
|
|
result = (inline ? style : dom.ownerDocument.defaultView.getComputedStyle(dom, null)).marginRight;
|
|
domStyle.display = display;
|
|
}
|
|
return result;
|
|
}
|
|
function fixRightMarginAndInputFocus(dom, el, inline, style) {
|
|
var result = style.marginRight,
|
|
domStyle, cleaner, display;
|
|
if (result !== '0px') {
|
|
domStyle = dom.style;
|
|
cleaner = getRightMarginFixCleaner(dom);
|
|
display = domStyle.display;
|
|
domStyle.display = 'inline-block';
|
|
result = (inline ? style : dom.ownerDocument.defaultView.getComputedStyle(dom, '')).marginRight;
|
|
domStyle.display = display;
|
|
cleaner();
|
|
}
|
|
return result;
|
|
}
|
|
// Fix bug caused by this: https://bugs.webkit.org/show_bug.cgi?id=13343
|
|
if (!supports.RightMargin) {
|
|
styleHooks.marginRight = styleHooks['margin-right'] = {
|
|
name: 'marginRight',
|
|
// TODO - Touch should use conditional compilation here or ensure that the
|
|
// underlying Ext.supports flags are set correctly...
|
|
get: (supports.DisplayChangeInputSelectionBug || supports.DisplayChangeTextAreaSelectionBug) ? fixRightMarginAndInputFocus : fixRightMargin
|
|
};
|
|
}
|
|
if (!supports.TransparentColor) {
|
|
colorStyles = [
|
|
'background-color',
|
|
'border-color',
|
|
'color',
|
|
'outline-color'
|
|
];
|
|
for (i = colorStyles.length; i--; ) {
|
|
name = colorStyles[i];
|
|
camel = Element.normalize(name);
|
|
styleHooks[name] = styleHooks[camel] = {
|
|
name: camel,
|
|
get: fixTransparent
|
|
};
|
|
}
|
|
}
|
|
// When elements are rotated 80 or 270 degrees, their border, margin and padding hooks
|
|
// need to be rotated as well.
|
|
proto.verticalStyleHooks90 = verticalStyleHooks90 = Ext.Object.chain(styleHooks);
|
|
proto.verticalStyleHooks270 = verticalStyleHooks270 = Ext.Object.chain(styleHooks);
|
|
verticalStyleHooks90.width = styleHooks.height || {
|
|
name: 'height'
|
|
};
|
|
verticalStyleHooks90.height = styleHooks.width || {
|
|
name: 'width'
|
|
};
|
|
verticalStyleHooks90['margin-top'] = {
|
|
name: 'marginLeft'
|
|
};
|
|
verticalStyleHooks90['margin-right'] = {
|
|
name: 'marginTop'
|
|
};
|
|
verticalStyleHooks90['margin-bottom'] = {
|
|
name: 'marginRight'
|
|
};
|
|
verticalStyleHooks90['margin-left'] = {
|
|
name: 'marginBottom'
|
|
};
|
|
verticalStyleHooks90['padding-top'] = {
|
|
name: 'paddingLeft'
|
|
};
|
|
verticalStyleHooks90['padding-right'] = {
|
|
name: 'paddingTop'
|
|
};
|
|
verticalStyleHooks90['padding-bottom'] = {
|
|
name: 'paddingRight'
|
|
};
|
|
verticalStyleHooks90['padding-left'] = {
|
|
name: 'paddingBottom'
|
|
};
|
|
verticalStyleHooks90['border-top'] = {
|
|
name: 'borderLeft'
|
|
};
|
|
verticalStyleHooks90['border-right'] = {
|
|
name: 'borderTop'
|
|
};
|
|
verticalStyleHooks90['border-bottom'] = {
|
|
name: 'borderRight'
|
|
};
|
|
verticalStyleHooks90['border-left'] = {
|
|
name: 'borderBottom'
|
|
};
|
|
verticalStyleHooks270.width = styleHooks.height || {
|
|
name: 'height'
|
|
};
|
|
verticalStyleHooks270.height = styleHooks.width || {
|
|
name: 'width'
|
|
};
|
|
verticalStyleHooks270['margin-top'] = {
|
|
name: 'marginRight'
|
|
};
|
|
verticalStyleHooks270['margin-right'] = {
|
|
name: 'marginBottom'
|
|
};
|
|
verticalStyleHooks270['margin-bottom'] = {
|
|
name: 'marginLeft'
|
|
};
|
|
verticalStyleHooks270['margin-left'] = {
|
|
name: 'marginTop'
|
|
};
|
|
verticalStyleHooks270['padding-top'] = {
|
|
name: 'paddingRight'
|
|
};
|
|
verticalStyleHooks270['padding-right'] = {
|
|
name: 'paddingBottom'
|
|
};
|
|
verticalStyleHooks270['padding-bottom'] = {
|
|
name: 'paddingLeft'
|
|
};
|
|
verticalStyleHooks270['padding-left'] = {
|
|
name: 'paddingTop'
|
|
};
|
|
verticalStyleHooks270['border-top'] = {
|
|
name: 'borderRight'
|
|
};
|
|
verticalStyleHooks270['border-right'] = {
|
|
name: 'borderBottom'
|
|
};
|
|
verticalStyleHooks270['border-bottom'] = {
|
|
name: 'borderLeft'
|
|
};
|
|
verticalStyleHooks270['border-left'] = {
|
|
name: 'borderTop'
|
|
};
|
|
/**
|
|
* @property {Boolean} scopeCss
|
|
* @member Ext
|
|
* Set this to true before onReady to prevent any styling from being added to
|
|
* the body element. By default a few styles such as font-family, and color
|
|
* are added to the body element via a "x-body" class. When this is set to
|
|
* `true` the "x-body" class is not added to the body element, but is added
|
|
* to the elements of root-level containers instead.
|
|
*/
|
|
if (!Ext.scopeCss) {
|
|
bodyCls.push(Ext.baseCSSPrefix + 'body');
|
|
}
|
|
if (supports.Touch) {
|
|
bodyCls.push(Ext.baseCSSPrefix + 'touch');
|
|
}
|
|
if (Ext.isIE && Ext.isIE9m) {
|
|
bodyCls.push(Ext.baseCSSPrefix + 'ie', Ext.baseCSSPrefix + 'ie9m');
|
|
// very often CSS needs to do checks like "IE7+" or "IE6 or 7". To help
|
|
// reduce the clutter (since CSS/SCSS cannot do these tests), we add some
|
|
// additional classes:
|
|
//
|
|
// x-ie7p : IE7+ : 7 <= ieVer
|
|
// x-ie7m : IE7- : ieVer <= 7
|
|
// x-ie8p : IE8+ : 8 <= ieVer
|
|
// x-ie8m : IE8- : ieVer <= 8
|
|
// x-ie9p : IE9+ : 9 <= ieVer
|
|
// x-ie78 : IE7 or 8 : 7 <= ieVer <= 8
|
|
//
|
|
bodyCls.push(Ext.baseCSSPrefix + 'ie8p');
|
|
if (Ext.isIE8) {
|
|
bodyCls.push(Ext.baseCSSPrefix + 'ie8');
|
|
} else {
|
|
bodyCls.push(Ext.baseCSSPrefix + 'ie9', Ext.baseCSSPrefix + 'ie9p');
|
|
}
|
|
if (Ext.isIE8m) {
|
|
bodyCls.push(Ext.baseCSSPrefix + 'ie8m');
|
|
}
|
|
}
|
|
if (Ext.isIE10) {
|
|
bodyCls.push(Ext.baseCSSPrefix + 'ie10');
|
|
}
|
|
if (Ext.isIE10p) {
|
|
bodyCls.push(Ext.baseCSSPrefix + 'ie10p');
|
|
}
|
|
if (Ext.isIE11) {
|
|
bodyCls.push(Ext.baseCSSPrefix + 'ie11');
|
|
}
|
|
if (Ext.isEdge) {
|
|
bodyCls.push(Ext.baseCSSPrefix + 'edge');
|
|
}
|
|
if (Ext.isGecko) {
|
|
bodyCls.push(Ext.baseCSSPrefix + 'gecko');
|
|
}
|
|
if (Ext.isOpera) {
|
|
bodyCls.push(Ext.baseCSSPrefix + 'opera');
|
|
}
|
|
if (Ext.isOpera12m) {
|
|
bodyCls.push(Ext.baseCSSPrefix + 'opera12m');
|
|
}
|
|
if (Ext.isWebKit) {
|
|
bodyCls.push(Ext.baseCSSPrefix + 'webkit');
|
|
}
|
|
if (Ext.isSafari) {
|
|
bodyCls.push(Ext.baseCSSPrefix + 'safari');
|
|
}
|
|
if (Ext.isChrome) {
|
|
bodyCls.push(Ext.baseCSSPrefix + 'chrome');
|
|
}
|
|
if (Ext.isMac) {
|
|
bodyCls.push(Ext.baseCSSPrefix + 'mac');
|
|
}
|
|
if (Ext.isLinux) {
|
|
bodyCls.push(Ext.baseCSSPrefix + 'linux');
|
|
}
|
|
if (!supports.CSS3BorderRadius) {
|
|
bodyCls.push(Ext.baseCSSPrefix + 'nbr');
|
|
}
|
|
if (!supports.CSS3LinearGradient) {
|
|
bodyCls.push(Ext.baseCSSPrefix + 'nlg');
|
|
}
|
|
if (supports.Touch) {
|
|
bodyCls.push(Ext.baseCSSPrefix + 'touch');
|
|
}
|
|
if (Ext.os.deviceType) {
|
|
bodyCls.push(Ext.baseCSSPrefix + Ext.os.deviceType.toLowerCase());
|
|
}
|
|
//Ext.fly(document.documentElement).addCls(htmlCls);
|
|
Ext.getBody().addCls(bodyCls);
|
|
}, null, {
|
|
priority: 1500
|
|
});
|
|
});
|
|
// onReady
|
|
|
|
// @tag core
|
|
/**
|
|
* @class Ext.GlobalEvents
|
|
*/
|
|
Ext.define('Ext.overrides.GlobalEvents', {
|
|
override: 'Ext.GlobalEvents',
|
|
/**
|
|
* @event resumelayouts
|
|
* Fires after global layout processing has been resumed in {@link
|
|
* Ext.Component#resumeLayouts}.
|
|
*/
|
|
deprecated: {
|
|
5: {
|
|
methods: {
|
|
addListener: function(ename, fn, scope, options, order, caller, eventOptions) {
|
|
var name, readyFn;
|
|
// The "ready" event was removed from Ext.globalEvents in 5.0 in favor of
|
|
// Ext.onReady(). This function adds compatibility for the ready event
|
|
if (ename === 'ready') {
|
|
readyFn = fn;
|
|
} else if (typeof ename !== 'string') {
|
|
for (name in ename) {
|
|
if (name === 'ready') {
|
|
readyFn = ename[name];
|
|
}
|
|
}
|
|
}
|
|
if (readyFn) {
|
|
Ext.log.warn("Ext.on('ready', fn) is deprecated. Please use Ext.onReady(fn) instead.");
|
|
Ext.onReady(readyFn);
|
|
}
|
|
this.callParent([
|
|
ename,
|
|
fn,
|
|
scope,
|
|
options,
|
|
order,
|
|
caller,
|
|
eventOptions
|
|
]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
});
|
|
|
|
/**
|
|
* @class Ext.Widget
|
|
*/
|
|
Ext.define('Ext.overrides.Widget', {
|
|
override: 'Ext.Widget',
|
|
uses: [
|
|
'Ext.Component'
|
|
],
|
|
$configStrict: false,
|
|
isComponent: true,
|
|
liquidLayout: true,
|
|
// in Ext JS the rendered flag is set as soon as a component has its element. Since
|
|
// widgets always have an element when constructed, they are always considered to be
|
|
// "rendered"
|
|
rendered: true,
|
|
rendering: true,
|
|
config: {
|
|
renderTo: null
|
|
},
|
|
constructor: function(config) {
|
|
var me = this,
|
|
renderTo;
|
|
me.callParent([
|
|
config
|
|
]);
|
|
// initialize the component layout
|
|
me.getComponentLayout();
|
|
renderTo = me.getRenderTo();
|
|
if (renderTo) {
|
|
me.render(renderTo);
|
|
}
|
|
},
|
|
addClsWithUI: function(cls) {
|
|
this.el.addCls(cls);
|
|
},
|
|
afterComponentLayout: Ext.emptyFn,
|
|
updateLayout: function() {
|
|
var owner = this.getRefOwner();
|
|
if (owner) {
|
|
owner.updateLayout();
|
|
}
|
|
},
|
|
destroy: function() {
|
|
var me = this,
|
|
ownerCt = me.ownerCt;
|
|
if (ownerCt && ownerCt.remove) {
|
|
ownerCt.remove(me, false);
|
|
}
|
|
me.callParent();
|
|
},
|
|
finishRender: function() {
|
|
this.rendering = false;
|
|
this.initBindable();
|
|
},
|
|
getAnimationProps: function() {
|
|
// see Ext.util.Animate mixin
|
|
return {};
|
|
},
|
|
getComponentLayout: function() {
|
|
var me = this,
|
|
layout = me.componentLayout;
|
|
if (!layout) {
|
|
layout = me.componentLayout = new Ext.layout.component.Auto();
|
|
layout.setOwner(me);
|
|
}
|
|
return layout;
|
|
},
|
|
getEl: function() {
|
|
return this.element;
|
|
},
|
|
/**
|
|
* @private
|
|
* Needed for when widget is rendered into a grid cell. The class to add to the cell element.
|
|
* @member Ext.Widget
|
|
*/
|
|
getTdCls: function() {
|
|
return Ext.baseCSSPrefix + this.getTdType() + '-' + (this.ui || 'default') + '-cell';
|
|
},
|
|
/**
|
|
* @private
|
|
* Partner method to {@link #getTdCls}.
|
|
*
|
|
* Returns the base type for the component. Defaults to return `this.xtype`, but
|
|
* All derived classes of {@link Ext.form.field.Text TextField} can return the type 'textfield',
|
|
* and all derived classes of {@link Ext.button.Button Button} can return the type 'button'
|
|
* @member Ext.Widget
|
|
*/
|
|
getTdType: function() {
|
|
return this.xtype;
|
|
},
|
|
getItemId: function() {
|
|
// needed by ComponentQuery
|
|
return this.itemId || this.id;
|
|
},
|
|
getSizeModel: function() {
|
|
return Ext.Component.prototype.getSizeModel.apply(this, arguments);
|
|
},
|
|
onAdded: function(container, pos, instanced) {
|
|
var me = this;
|
|
me.ownerCt = container;
|
|
me.onInheritedAdd(me, instanced);
|
|
},
|
|
onRemoved: function(destroying) {
|
|
var me = this;
|
|
if (!destroying) {
|
|
me.removeBindings();
|
|
}
|
|
me.onInheritedRemove(destroying);
|
|
me.ownerCt = me.ownerLayout = null;
|
|
},
|
|
parseBox: function(box) {
|
|
return Ext.Element.parseBox(box);
|
|
},
|
|
removeClsWithUI: function(cls) {
|
|
this.el.removeCls(cls);
|
|
},
|
|
render: function(container, position) {
|
|
var me = this,
|
|
element = me.element,
|
|
proto = Ext.Component.prototype,
|
|
nextSibling;
|
|
if (!me.ownerCt || me.floating) {
|
|
if (Ext.scopeCss) {
|
|
element.addCls(proto.rootCls);
|
|
}
|
|
element.addCls(proto.borderBoxCls);
|
|
}
|
|
if (position) {
|
|
nextSibling = container.childNodes[position];
|
|
if (nextSibling) {
|
|
Ext.fly(container).insertBefore(element, nextSibling);
|
|
return;
|
|
}
|
|
}
|
|
Ext.fly(container).appendChild(element);
|
|
},
|
|
setPosition: function(x, y) {
|
|
this.el.setLocalXY(x, y);
|
|
},
|
|
up: function() {
|
|
return Ext.Component.prototype.up.apply(this, arguments);
|
|
},
|
|
isAncestor: function() {
|
|
return Ext.Component.prototype.isAncestor.apply(this, arguments);
|
|
},
|
|
onFocusEnter: function() {
|
|
return Ext.Component.prototype.onFocusEnter.apply(this, arguments);
|
|
},
|
|
onFocusLeave: function() {
|
|
return Ext.Component.prototype.onFocusLeave.apply(this, arguments);
|
|
},
|
|
isLayoutChild: function(candidate) {
|
|
var ownerCt = this.ownerCt;
|
|
return ownerCt ? (ownerCt === candidate || ownerCt.isLayoutChild(candidate)) : false;
|
|
},
|
|
privates: {
|
|
doAddListener: function(name, fn, scope, options, order, caller, manager) {
|
|
if (name == 'painted' || name == 'resize') {
|
|
this.element.doAddListener(name, fn, scope || this, options, order);
|
|
}
|
|
this.callParent([
|
|
name,
|
|
fn,
|
|
scope,
|
|
options,
|
|
order,
|
|
caller,
|
|
manager
|
|
]);
|
|
},
|
|
doRemoveListener: function(name, fn, scope) {
|
|
if (name == 'painted' || name == 'resize') {
|
|
this.element.doRemoveListener(name, fn, scope);
|
|
}
|
|
this.callParent([
|
|
name,
|
|
fn,
|
|
scope
|
|
]);
|
|
}
|
|
}
|
|
}, function(Cls) {
|
|
var prototype = Cls.prototype;
|
|
if (Ext.isIE9m) {
|
|
// Since IE8/9 don't not support Object.defineProperty correctly we can't add the reference
|
|
// nodes on demand, so we just fall back to adding all references up front.
|
|
prototype.addElementReferenceOnDemand = prototype.addElementReference;
|
|
}
|
|
});
|
|
|
|
/**
|
|
* @class Ext.Progress
|
|
*/
|
|
Ext.define('Ext.overrides.Progress', {
|
|
override: 'Ext.Progress',
|
|
config: {
|
|
ui: 'default'
|
|
},
|
|
updateWidth: function(width, oldWidth) {
|
|
var me = this;
|
|
me.callParent([
|
|
width,
|
|
oldWidth
|
|
]);
|
|
width -= me.element.getBorderWidth('lr');
|
|
me.backgroundEl.setWidth(width);
|
|
me.textEl.setWidth(width);
|
|
}
|
|
});
|
|
|
|
Ext.define('Ext.overrides.app.domain.Component', {
|
|
override: 'Ext.app.domain.Component',
|
|
requires: [
|
|
'Ext.Component'
|
|
]
|
|
}, function(ComponentDomain) {
|
|
// The core Component domain monitors events on the Ext.Widget class
|
|
// in Ext Components are not widgets so we need to monitor Ext.Component as well.
|
|
ComponentDomain.monitor(Ext.Component);
|
|
});
|
|
|
|
// This is an override because it must be loaded very early, possibly before Ext.app.Application
|
|
// in dev mode so that Ext.application() can be called.
|
|
// Being an override also ensures that it is only included in a built app if Ext.app.Application
|
|
// is present.
|
|
//
|
|
// @override Ext.app.Application
|
|
/**
|
|
* @method application
|
|
* @member Ext
|
|
* Loads Ext.app.Application class and starts it up with given configuration after the
|
|
* page is ready.
|
|
*
|
|
* See `Ext.app.Application` for details.
|
|
*
|
|
* @param {Object/String} config Application config object or name of a class derived
|
|
* from Ext.app.Application.
|
|
*/
|
|
Ext.application = function(config) {
|
|
var createApp = function(App) {
|
|
// This won't be called until App class has been created.
|
|
Ext.onReady(function() {
|
|
var Viewport = Ext.viewport;
|
|
Viewport = Viewport && Viewport['Viewport'];
|
|
if (Viewport && Viewport.setup) {
|
|
Viewport.setup(App.prototype.config.viewport);
|
|
}
|
|
Ext.app.Application.instance = new App();
|
|
});
|
|
};
|
|
if (typeof config === "string") {
|
|
Ext.require(config, function() {
|
|
createApp(Ext.ClassManager.get(config));
|
|
});
|
|
} else {
|
|
config = Ext.apply({
|
|
extend: 'Ext.app.Application'
|
|
}, // can be replaced by config!
|
|
config);
|
|
// We have to process "paths" before creating Application class,
|
|
// or `requires` won't work.
|
|
Ext.app.setupPaths(config.name, config.appFolder, config.paths);
|
|
config['paths processed'] = true;
|
|
// Let Ext.define do the hard work but don't assign a class name.
|
|
Ext.define(config.name + ".$application", config, function() {
|
|
createApp(this);
|
|
});
|
|
}
|
|
};
|
|
|
|
/**
|
|
* @class Ext.app.Application
|
|
*/
|
|
Ext.define('Ext.overrides.app.Application', {
|
|
override: 'Ext.app.Application',
|
|
uses: [
|
|
'Ext.tip.QuickTipManager'
|
|
],
|
|
// @cmd-auto-dependency {aliasPrefix: "view.", mvc: true, requires: ["Ext.plugin.Viewport"]}
|
|
/**
|
|
* @cfg {Boolean/String} [autoCreateViewport=false]
|
|
* @deprecated 5.1 Instead use {@link #mainView}
|
|
* @member Ext.app.Application
|
|
*/
|
|
autoCreateViewport: false,
|
|
config: {
|
|
/**
|
|
* @cfg {Boolean} enableQuickTips
|
|
* @deprecated 6.2.0 Use {@link #quickTips}.
|
|
*/
|
|
enableQuickTips: null
|
|
},
|
|
/**
|
|
* @cfg {Boolean} quickTips
|
|
* True to automatically set up Ext.tip.QuickTip support.
|
|
*
|
|
* @since 6.2.0
|
|
*/
|
|
quickTips: true,
|
|
updateEnableQuickTips: function(enableQuickTips) {
|
|
this.setQuickTips(enableQuickTips);
|
|
},
|
|
applyMainView: function(mainView) {
|
|
var view, proto, config, plugins;
|
|
if (typeof mainView === 'string') {
|
|
view = this.getView(mainView);
|
|
} else {
|
|
view = Ext.ClassManager.getByConfig(mainView);
|
|
}
|
|
proto = view.prototype;
|
|
if (!proto.isViewport) {
|
|
plugins = proto.plugins;
|
|
// Need to copy over any plugins defined on the prototype.
|
|
plugins = [
|
|
'viewport'
|
|
].concat(plugins ? Ext.Array.from(plugins, true) : []);
|
|
config = {
|
|
plugins: plugins
|
|
};
|
|
}
|
|
return view.create(config);
|
|
},
|
|
getDependencies: function(cls, data, requires) {
|
|
var Controller = Ext.app.Controller,
|
|
proto = cls.prototype,
|
|
namespace = data.$namespace,
|
|
viewportClass = data.autoCreateViewport;
|
|
if (viewportClass) {
|
|
if (!namespace) {
|
|
Ext.raise("[Ext.app.Application] Can't resolve namespace for " + data.$className + ", did you forget to specify 'name' property?");
|
|
}
|
|
if (viewportClass === true) {
|
|
viewportClass = 'Viewport';
|
|
} else {
|
|
requires.push('Ext.plugin.Viewport');
|
|
}
|
|
Controller.processDependencies(proto, requires, namespace, 'view', viewportClass);
|
|
}
|
|
},
|
|
onBeforeLaunch: function() {
|
|
var me = this,
|
|
autoCreateViewport = me.autoCreateViewport;
|
|
if (me.getQuickTips()) {
|
|
me.initQuickTips();
|
|
}
|
|
if (autoCreateViewport) {
|
|
me.initViewport();
|
|
}
|
|
this.callParent(arguments);
|
|
},
|
|
getViewportName: function() {
|
|
var name = null,
|
|
autoCreate = this.autoCreateViewport;
|
|
if (autoCreate) {
|
|
name = (autoCreate === true) ? 'Viewport' : autoCreate;
|
|
}
|
|
return name;
|
|
},
|
|
initViewport: function() {
|
|
this.setMainView(this.getViewportName());
|
|
},
|
|
initQuickTips: function() {
|
|
Ext.tip.QuickTipManager.init();
|
|
}
|
|
});
|
|
|
|
Ext.define('Ext.overrides.app.domain.View', {
|
|
override: 'Ext.app.domain.View',
|
|
requires: [
|
|
'Ext.Component'
|
|
],
|
|
constructor: function(controller) {
|
|
this.callParent([
|
|
controller
|
|
]);
|
|
// The base class handles Ext.Widget, which encompasses
|
|
// component for modern, so we only need the override here.
|
|
this.monitoredClasses.push(Ext.Component);
|
|
}
|
|
});
|
|
|
|
/**
|
|
* @class Ext.dom.Helper
|
|
*/
|
|
Ext.define('Ext.overrides.dom.Helper', (function() {
|
|
var tableRe = /^(?:table|thead|tbody|tr|td)$/i,
|
|
tableElRe = /td|tr|tbody|thead/i,
|
|
ts = '<table>',
|
|
te = '</table>',
|
|
tbs = ts + '<tbody>',
|
|
tbe = '</tbody>' + te,
|
|
trs = tbs + '<tr>',
|
|
tre = '</tr>' + tbe;
|
|
return {
|
|
override: 'Ext.dom.Helper',
|
|
ieInsertHtml: function(where, el, html) {
|
|
var frag = null;
|
|
// IE's incomplete table implementation: http://www.ericvasilik.com/2006/07/code-karma.html
|
|
if (Ext.isIE9m && tableRe.test(el.tagName)) {
|
|
frag = this.insertIntoTable(el.tagName.toLowerCase(), where, el, html);
|
|
}
|
|
return frag;
|
|
},
|
|
ieOverwrite: function(el, html) {
|
|
// IE Inserting HTML into a table/tbody/tr requires extra processing:
|
|
// http://www.ericvasilik.com/2006/07/code-karma.html
|
|
if (Ext.isIE9m && tableRe.test(el.tagName)) {
|
|
// Clearing table elements requires removal of all elements.
|
|
while (el.firstChild) {
|
|
el.removeChild(el.firstChild);
|
|
}
|
|
if (html) {
|
|
return this.insertHtml('afterbegin', el, html);
|
|
}
|
|
}
|
|
},
|
|
ieTable: function(depth, openingTags, htmlContent, closingTags) {
|
|
var i = -1,
|
|
el = this.detachedDiv,
|
|
ns, nx;
|
|
el.innerHTML = [
|
|
openingTags,
|
|
htmlContent,
|
|
closingTags
|
|
].join('');
|
|
while (++i < depth) {
|
|
el = el.firstChild;
|
|
}
|
|
// If the result is multiple siblings, then encapsulate them into one fragment.
|
|
ns = el.nextSibling;
|
|
if (ns) {
|
|
ns = el;
|
|
el = document.createDocumentFragment();
|
|
while (ns) {
|
|
nx = ns.nextSibling;
|
|
el.appendChild(ns);
|
|
ns = nx;
|
|
}
|
|
}
|
|
return el;
|
|
},
|
|
/**
|
|
* @private
|
|
* @method insertIntoTable
|
|
* @member Ext.dom.Helper
|
|
* workaround for broken table implementation in IE9m
|
|
* http://www.ericvasilik.com/2006/07/code-karma.html
|
|
*/
|
|
insertIntoTable: function(tag, where, destinationEl, html) {
|
|
var node, before,
|
|
bb = where === 'beforebegin',
|
|
ab = where === 'afterbegin',
|
|
be = where === 'beforeend',
|
|
ae = where === 'afterend';
|
|
if (tag === 'td' && (ab || be) || !tableElRe.test(tag) && (bb || ae)) {
|
|
return null;
|
|
}
|
|
before = bb ? destinationEl : ae ? destinationEl.nextSibling : ab ? destinationEl.firstChild : null;
|
|
if (bb || ae) {
|
|
destinationEl = destinationEl.parentNode;
|
|
}
|
|
if (tag === 'td' || (tag === 'tr' && (be || ab))) {
|
|
node = this.ieTable(4, trs, html, tre);
|
|
} else if (((tag === 'tbody' || tag === 'thead') && (be || ab)) || (tag === 'tr' && (bb || ae))) {
|
|
node = this.ieTable(3, tbs, html, tbe);
|
|
} else {
|
|
node = this.ieTable(2, ts, html, te);
|
|
}
|
|
destinationEl.insertBefore(node, before);
|
|
return node;
|
|
}
|
|
};
|
|
})());
|
|
|
|
/**
|
|
* @class Ext.list.TreeItem
|
|
*/
|
|
Ext.define('Ext.overrides.list.TreeItem', {
|
|
override: 'Ext.list.TreeItem',
|
|
config: {
|
|
floated: null
|
|
},
|
|
// Implement a setter.
|
|
// There *is* no "floated" config in Classic.
|
|
// We're still an inner item, we just get put inside a Container.
|
|
setFloated: function(floated) {
|
|
var me = this,
|
|
el = me.element,
|
|
placeholder = me.placeholder,
|
|
node, wasExpanded;
|
|
if (me.treeItemFloated !== floated) {
|
|
if (floated) {
|
|
placeholder = el.clone(false, true);
|
|
// shallow, asDom
|
|
placeholder.id += '-placeholder';
|
|
// avoid duplicate id
|
|
me.placeholder = Ext.get(placeholder);
|
|
me.wasExpanded = me.getExpanded();
|
|
me.setExpanded(true);
|
|
el.addCls(me.floatedCls);
|
|
el.dom.parentNode.insertBefore(placeholder, el.dom);
|
|
me.floater = me.createFloater();
|
|
}
|
|
// toolkit-specific
|
|
else if (placeholder) {
|
|
wasExpanded = me.wasExpanded;
|
|
node = me.getNode();
|
|
me.setExpanded(wasExpanded);
|
|
if (!wasExpanded && node.isExpanded()) {
|
|
// If we have been floating and expanded a child, we may have been
|
|
// expanded as part of the ancestors. Attempt to restore state.
|
|
me.preventAnimation = true;
|
|
node.collapse();
|
|
me.preventAnimation = false;
|
|
}
|
|
me.floater.remove(me, false);
|
|
// don't destroy
|
|
el.removeCls(me.floatedCls);
|
|
placeholder.dom.parentNode.insertBefore(el.dom, placeholder.dom);
|
|
placeholder.destroy();
|
|
me.floater.destroy();
|
|
me.placeholder = me.floater = null;
|
|
}
|
|
// Use an internal property name. We are NOT really floated
|
|
me.treeItemFloated = floated;
|
|
}
|
|
},
|
|
getFloated: function() {
|
|
return this.treeItemFloated;
|
|
},
|
|
runAnimation: function(animation) {
|
|
return this.itemContainer.addAnimation(animation);
|
|
},
|
|
stopAnimation: function(animation) {
|
|
animation.jumpToEnd();
|
|
},
|
|
privates: {
|
|
createFloater: function() {
|
|
var me = this,
|
|
owner = me.getOwner(),
|
|
ownerTree = me.up('treelist'),
|
|
floater,
|
|
toolElement = me.getToolElement();
|
|
me.floater = floater = new Ext.container.Container({
|
|
cls: ownerTree.self.prototype.element.cls + ' ' + ownerTree.uiPrefix + ownerTree.getUi() + ' ' + Ext.baseCSSPrefix + 'treelist-floater',
|
|
floating: true,
|
|
// We do not get element resize events on IE8
|
|
// so fall back to 6.0.1 sizing to 200 wide.
|
|
width: Ext.isIE8 ? 200 : (ownerTree.expandedWidth - toolElement.getWidth()),
|
|
shadow: false,
|
|
renderTo: Ext.getBody(),
|
|
listeners: {
|
|
element: 'el',
|
|
click: function(e) {
|
|
return owner.onClick(e);
|
|
}
|
|
}
|
|
});
|
|
floater.add(me);
|
|
floater.show();
|
|
floater.el.alignTo(toolElement, 'tr?');
|
|
return floater;
|
|
}
|
|
}
|
|
});
|
|
|
|
/**
|
|
* @class Ext.plugin.Abstract
|
|
*/
|
|
Ext.define('Ext.overrides.plugin.Abstract', {
|
|
override: 'Ext.plugin.Abstract',
|
|
$configStrict: false,
|
|
$configPrefixed: false,
|
|
disabled: false,
|
|
/**
|
|
* @cfg {String|Array} stateEvents
|
|
* The configured list of stateEvents used to (optionally) participate in Owner Component's state management.
|
|
* @member Ext.plugin.Abstract
|
|
*/
|
|
/**
|
|
* @method
|
|
* The getState method is invoked by the client Component's State mixin when one or more of the the specified {@link #stateEvents} are raised.
|
|
*
|
|
* The supplied implementation is empty. If plugin Subclasses are to (optionally) participate in the client Component's
|
|
* state management, implementers should provide a suitable method which returns a state object.
|
|
* @return {Object} state
|
|
* @member Ext.plugin.Abstract
|
|
*/
|
|
getState: null,
|
|
/**
|
|
* @method
|
|
* The applyState method is invoked by the client Component's State mixin after initComponent method has been run for the client.
|
|
*
|
|
* The supplied implementation is empty. If plugin Subclasses are to (optionally) participate in the client Component's
|
|
* state management, implementers should provide a suitable method to utilize it.
|
|
* @param {Object} state The current plugin state object to be applied.
|
|
* @param {Object} allState The current aggregate state of the Component and all plugins.
|
|
* @member Ext.plugin.Abstract
|
|
*/
|
|
applyState: null,
|
|
/**
|
|
* The base implementation just sets the plugin's `disabled` flag to `false`
|
|
*
|
|
* Plugin subclasses which need more complex processing may implement an overriding implementation.
|
|
* @member Ext.plugin.Abstract
|
|
*/
|
|
enable: function() {
|
|
this.disabled = false;
|
|
},
|
|
/**
|
|
* The base implementation just sets the plugin's `disabled` flag to `true`
|
|
*
|
|
* Plugin subclasses which need more complex processing may implement an overriding implementation.
|
|
* @member Ext.plugin.Abstract
|
|
*/
|
|
disable: function() {
|
|
this.disabled = true;
|
|
}
|
|
});
|
|
|
|
/**
|
|
* @class Ext.sparkline.Base
|
|
*/
|
|
Ext.define('Ext.override.sparkline.Base', {
|
|
override: 'Ext.sparkline.Base',
|
|
statics: {
|
|
constructTip: function() {
|
|
return new Ext.tip['ToolTip']({
|
|
id: 'sparklines-tooltip',
|
|
showDelay: 0,
|
|
dismissDelay: 0,
|
|
hideDelay: 400
|
|
});
|
|
}
|
|
},
|
|
onMouseMove: function(e) {
|
|
this.tooltip.triggerEvent = e;
|
|
this.callParent([
|
|
e
|
|
]);
|
|
},
|
|
onMouseLeave: function(e) {
|
|
this.callParent([
|
|
e
|
|
]);
|
|
this.tooltip.target = null;
|
|
},
|
|
privates: {
|
|
hideTip: function() {
|
|
var tip = this.tooltip;
|
|
tip.target = null;
|
|
tip.hide();
|
|
},
|
|
showTip: function() {
|
|
var tip = this.tooltip;
|
|
tip.target = this.el;
|
|
tip.onTargetOver(tip.triggerEvent);
|
|
}
|
|
}
|
|
});
|
|
|
|
/**
|
|
* @class Ext.app.ViewController
|
|
*/
|
|
/**
|
|
* @method beforeRender
|
|
* @template
|
|
* Template method called by the owning component's
|
|
* {@link Ext.Component#method-beforeRender beforeRender} method.
|
|
* @param {Ext.Component} component The owner component attached to the
|
|
* ViewController
|
|
*/
|
|
/**
|
|
* @method afterRender
|
|
* @template
|
|
* Template method called by the owning component's
|
|
* {@link Ext.Component#method-afterRender afterRender} method.
|
|
* @param {Ext.Component} component The owner component attached to the
|
|
* ViewController
|
|
*/
|
|
/**
|
|
* @method boxReady
|
|
* @template
|
|
* Template method called by the owning component's
|
|
* {@link Ext.Component#method-onBoxReady onBoxReady} method.
|
|
* @param {Ext.Component} component The owner component attached to the
|
|
* ViewController
|
|
*/
|
|
|
|
Ext.define(null, {
|
|
override: 'Ext.event.publisher.Focus',
|
|
compatibility: Ext.isIE10m,
|
|
publishDelegatedDomEvent: function(e) {
|
|
var body = document.body,
|
|
el = Ext.synchronouslyFocusing;
|
|
// This horrid hack is necessary to work around the issue with input elements
|
|
// in IE10m that can fail to focus under certain conditions. See comment in
|
|
// Ext.dom.Element override.
|
|
if (el && ((e.type === 'focusout' && (e.srcElement === el || e.srcElement === window) && e.toElement === body) || (e.type === 'focusin' && (e.srcElement === body || e.srcElement === window) && e.fromElement === el && e.toElement === null))) {
|
|
return;
|
|
}
|
|
this.callParent([
|
|
e
|
|
]);
|
|
}
|
|
});
|
|
|
|
Ext.define(null, {
|
|
override: 'Ext.form.field.Checkbox',
|
|
compatibility: Ext.isIE8,
|
|
// IE8 does not support change event but it has propertychange which is even better
|
|
changeEventName: 'propertychange',
|
|
onChangeEvent: function(e) {
|
|
// IE8 propertychange fires for *any* property change but we're only interested in checked
|
|
// We also don't want to react to propertychange fired as the result of assigning
|
|
// checked property in setRawValue().
|
|
if (this.duringSetRawValue || e.browserEvent.propertyName !== 'checked') {
|
|
return;
|
|
}
|
|
this.callParent([
|
|
e
|
|
]);
|
|
},
|
|
updateCheckedCls: function(checked) {
|
|
var me = this,
|
|
displayEl = me.displayEl;
|
|
me.callParent([
|
|
checked
|
|
]);
|
|
// IE8 has a bug with font icons and pseudo-elements
|
|
if (displayEl && checked !== me.lastValue) {
|
|
displayEl.repaint();
|
|
}
|
|
}
|
|
});
|
|
|
|
Ext.define(null, {
|
|
override: 'Ext.form.field.Radio',
|
|
compatibility: Ext.isIE8,
|
|
getSubTplData: function(fieldData) {
|
|
var data = this.callParent([
|
|
fieldData
|
|
]);
|
|
// Rendering a radio button with checked attribute
|
|
// will have a curious side effect in IE8: the DOM
|
|
// node will have checked property set to `true` but
|
|
// radio group (radios with the same name attribute)
|
|
// will behave as if no radio is checked in the group;
|
|
// tabbing into the group will select first or last
|
|
// button instead of the checked one.
|
|
// So instead of rendering the attribute we will set
|
|
// checked value in the DOM after rendering. Apparently
|
|
// such a tiny nudge is enough for the browser to behave.
|
|
delete data.checked;
|
|
return data;
|
|
},
|
|
afterRender: function() {
|
|
this.callParent();
|
|
if (this.checked) {
|
|
this.inputEl.dom.checked = true;
|
|
}
|
|
},
|
|
onChange: function(newValue, oldValue) {
|
|
// We don't need to bother updating other radio buttons in IE8
|
|
// since it will fire propertychange event on any change, not only false -> true.
|
|
// This is unlike standard compliant browsers, see main class.
|
|
this.callSuper([
|
|
newValue,
|
|
oldValue
|
|
]);
|
|
}
|
|
});
|
|
|
|
Ext.define(null, {
|
|
override: 'Ext.scroll.Scroller',
|
|
compatibility: Ext.isIE8,
|
|
privates: {
|
|
// Important note: this code had to be copied as a whole
|
|
// because the scrollLeft assignment trickery only works
|
|
// reliably when it is done within the same function context.
|
|
doScrollTo: function(x, y, animate) {
|
|
var me = this,
|
|
element = me.getElement(),
|
|
maxPosition, dom, to, xInf, yInf;
|
|
if (element && !element.destroyed) {
|
|
dom = this.getElement().dom;
|
|
xInf = (x === Infinity);
|
|
yInf = (y === Infinity);
|
|
if (xInf || yInf) {
|
|
maxPosition = me.getMaxPosition();
|
|
if (xInf) {
|
|
x = maxPosition.x;
|
|
}
|
|
if (yInf) {
|
|
y = maxPosition.y;
|
|
}
|
|
}
|
|
x = me.convertX(x);
|
|
if (animate) {
|
|
to = {};
|
|
if (y != null) {
|
|
to.scrollTop = y;
|
|
}
|
|
if (x != null) {
|
|
to.scrollLeft = x;
|
|
}
|
|
element.animate(Ext.mergeIf({
|
|
to: {
|
|
scrollTop: y,
|
|
scrollLeft: x
|
|
}
|
|
}, animate));
|
|
} else {
|
|
// When we need to assign both scrollTop and scrollLeft,
|
|
// IE8 might fire scroll event on the first assignment
|
|
// but not on the second; that behavior is unlike the other
|
|
// browsers which will wait for the second assignment
|
|
// to happen before firing the event. This leads to our
|
|
// scrollstart event firing prematurely, when the scrolling
|
|
// has not actually finished yet.
|
|
// To work around that, we ignore the first event and then
|
|
// force another one by assigning scrollLeft the second time.
|
|
if (x != null && y != null) {
|
|
me.deferDomScroll = true;
|
|
}
|
|
if (y != null) {
|
|
dom.scrollTop = y;
|
|
}
|
|
if (x != null) {
|
|
dom.scrollLeft = x;
|
|
}
|
|
if (me.deferDomScroll) {
|
|
me.deferDomScroll = false;
|
|
// Reading the DOM makes sure the second assignment
|
|
// will fire the event.
|
|
+dom.scrollLeft;
|
|
dom.scrollLeft = x;
|
|
}
|
|
}
|
|
// Our position object will need refreshing before returning.
|
|
me.positionDirty = true;
|
|
}
|
|
},
|
|
onDomScroll: function() {
|
|
var me = this;
|
|
if (me.deferDomScroll) {
|
|
return;
|
|
}
|
|
me.callParent();
|
|
}
|
|
}
|
|
});
|
|
|