extjs-rails 4.1.0.alpha1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +18 -0
- data/Gemfile +4 -0
- data/LICENSE +36 -0
- data/README.md +29 -0
- data/Rakefile +2 -0
- data/app/assets/javascripts/extjs-rails/extjs-rails.js +1 -0
- data/app/assets/javascripts/extjs-rails/index.js.erb +9 -0
- data/app/assets/javascripts/extjs-rails/sdk.jsb3 +2017 -0
- data/app/assets/javascripts/extjs-rails/src/AbstractComponent.js +3290 -0
- data/app/assets/javascripts/extjs-rails/src/AbstractManager.js +144 -0
- data/app/assets/javascripts/extjs-rails/src/AbstractPlugin.js +72 -0
- data/app/assets/javascripts/extjs-rails/src/Action.js +276 -0
- data/app/assets/javascripts/extjs-rails/src/Ajax.js +99 -0
- data/app/assets/javascripts/extjs-rails/src/Component.js +1344 -0
- data/app/assets/javascripts/extjs-rails/src/ComponentLoader.js +202 -0
- data/app/assets/javascripts/extjs-rails/src/ComponentManager.js +47 -0
- data/app/assets/javascripts/extjs-rails/src/ComponentQuery.js +521 -0
- data/app/assets/javascripts/extjs-rails/src/Editor.js +494 -0
- data/app/assets/javascripts/extjs-rails/src/ElementLoader.js +404 -0
- data/app/assets/javascripts/extjs-rails/src/FocusManager.js +712 -0
- data/app/assets/javascripts/extjs-rails/src/Img.js +111 -0
- data/app/assets/javascripts/extjs-rails/src/Layer.js +543 -0
- data/app/assets/javascripts/extjs-rails/src/LoadMask.js +432 -0
- data/app/assets/javascripts/extjs-rails/src/ModelManager.js +186 -0
- data/app/assets/javascripts/extjs-rails/src/PluginManager.js +110 -0
- data/app/assets/javascripts/extjs-rails/src/ProgressBar.js +336 -0
- data/app/assets/javascripts/extjs-rails/src/Shadow.js +233 -0
- data/app/assets/javascripts/extjs-rails/src/ShadowPool.js +43 -0
- data/app/assets/javascripts/extjs-rails/src/Template.js +331 -0
- data/app/assets/javascripts/extjs-rails/src/XTemplate.js +365 -0
- data/app/assets/javascripts/extjs-rails/src/XTemplateCompiler.js +450 -0
- data/app/assets/javascripts/extjs-rails/src/XTemplateParser.js +249 -0
- data/app/assets/javascripts/extjs-rails/src/ZIndexManager.js +519 -0
- data/app/assets/javascripts/extjs-rails/src/app/Application.js +271 -0
- data/app/assets/javascripts/extjs-rails/src/app/Controller.js +458 -0
- data/app/assets/javascripts/extjs-rails/src/app/EventBus.js +112 -0
- data/app/assets/javascripts/extjs-rails/src/button/Button.js +1483 -0
- data/app/assets/javascripts/extjs-rails/src/button/Cycle.js +215 -0
- data/app/assets/javascripts/extjs-rails/src/button/Split.js +99 -0
- data/app/assets/javascripts/extjs-rails/src/chart/Callout.js +140 -0
- data/app/assets/javascripts/extjs-rails/src/chart/Chart.js +966 -0
- data/app/assets/javascripts/extjs-rails/src/chart/Highlight.js +172 -0
- data/app/assets/javascripts/extjs-rails/src/chart/Label.js +241 -0
- data/app/assets/javascripts/extjs-rails/src/chart/Legend.js +474 -0
- data/app/assets/javascripts/extjs-rails/src/chart/LegendItem.js +217 -0
- data/app/assets/javascripts/extjs-rails/src/chart/Mask.js +230 -0
- data/app/assets/javascripts/extjs-rails/src/chart/MaskLayer.js +48 -0
- data/app/assets/javascripts/extjs-rails/src/chart/Navigation.js +79 -0
- data/app/assets/javascripts/extjs-rails/src/chart/Shape.js +106 -0
- data/app/assets/javascripts/extjs-rails/src/chart/Tip.js +98 -0
- data/app/assets/javascripts/extjs-rails/src/chart/TipSurface.js +42 -0
- data/app/assets/javascripts/extjs-rails/src/chart/axis/Abstract.js +73 -0
- data/app/assets/javascripts/extjs-rails/src/chart/axis/Axis.js +961 -0
- data/app/assets/javascripts/extjs-rails/src/chart/axis/Category.js +130 -0
- data/app/assets/javascripts/extjs-rails/src/chart/axis/Gauge.js +203 -0
- data/app/assets/javascripts/extjs-rails/src/chart/axis/Numeric.js +235 -0
- data/app/assets/javascripts/extjs-rails/src/chart/axis/Radial.js +204 -0
- data/app/assets/javascripts/extjs-rails/src/chart/axis/Time.js +135 -0
- data/app/assets/javascripts/extjs-rails/src/chart/series/Area.js +803 -0
- data/app/assets/javascripts/extjs-rails/src/chart/series/Bar.js +853 -0
- data/app/assets/javascripts/extjs-rails/src/chart/series/Cartesian.js +328 -0
- data/app/assets/javascripts/extjs-rails/src/chart/series/Column.js +104 -0
- data/app/assets/javascripts/extjs-rails/src/chart/series/Gauge.js +490 -0
- data/app/assets/javascripts/extjs-rails/src/chart/series/Line.js +1104 -0
- data/app/assets/javascripts/extjs-rails/src/chart/series/Pie.js +1072 -0
- data/app/assets/javascripts/extjs-rails/src/chart/series/Radar.js +440 -0
- data/app/assets/javascripts/extjs-rails/src/chart/series/Scatter.js +668 -0
- data/app/assets/javascripts/extjs-rails/src/chart/series/Series.js +443 -0
- data/app/assets/javascripts/extjs-rails/src/chart/theme/Base.js +175 -0
- data/app/assets/javascripts/extjs-rails/src/chart/theme/Theme.js +253 -0
- data/app/assets/javascripts/extjs-rails/src/container/AbstractContainer.js +1062 -0
- data/app/assets/javascripts/extjs-rails/src/container/ButtonGroup.js +143 -0
- data/app/assets/javascripts/extjs-rails/src/container/Container.js +212 -0
- data/app/assets/javascripts/extjs-rails/src/container/DockingContainer.js +265 -0
- data/app/assets/javascripts/extjs-rails/src/container/Viewport.js +184 -0
- data/app/assets/javascripts/extjs-rails/src/core/dom/Element.form.js +50 -0
- data/app/assets/javascripts/extjs-rails/src/core/dom/Element.static-more.js +159 -0
- data/app/assets/javascripts/extjs-rails/src/core/examples/index.html +321 -0
- data/app/assets/javascripts/extjs-rails/src/core/examples/index.js +6 -0
- data/app/assets/javascripts/extjs-rails/src/core/examples/src/Sample/CTO.js +25 -0
- data/app/assets/javascripts/extjs-rails/src/core/examples/src/Sample/CoolGuy.js +20 -0
- data/app/assets/javascripts/extjs-rails/src/core/examples/src/Sample/Developer.js +43 -0
- data/app/assets/javascripts/extjs-rails/src/core/examples/src/Sample/Gun.js +3 -0
- data/app/assets/javascripts/extjs-rails/src/core/examples/src/Sample/HumanResource.js +23 -0
- data/app/assets/javascripts/extjs-rails/src/core/examples/src/Sample/Musician.js +20 -0
- data/app/assets/javascripts/extjs-rails/src/core/examples/src/Sample/Person.js +50 -0
- data/app/assets/javascripts/extjs-rails/src/core/examples/src/Sample/ability/CanComposeSongs.js +9 -0
- data/app/assets/javascripts/extjs-rails/src/core/examples/src/Sample/ability/CanPlayGuitar.js +9 -0
- data/app/assets/javascripts/extjs-rails/src/core/examples/src/Sample/ability/CanSing.js +18 -0
- data/app/assets/javascripts/extjs-rails/src/core/examples/src/Sample/deadlock/A.js +3 -0
- data/app/assets/javascripts/extjs-rails/src/core/examples/src/Sample/deadlock/B.js +3 -0
- data/app/assets/javascripts/extjs-rails/src/core/examples/src/Sample/deadlock/C.js +3 -0
- data/app/assets/javascripts/extjs-rails/src/core/examples/src/Sample/deadlock/D.js +3 -0
- data/app/assets/javascripts/extjs-rails/src/core/examples/src/Sample/deadlock/E.js +3 -0
- data/app/assets/javascripts/extjs-rails/src/core/examples/src/Sample/notdeadlock/A.js +3 -0
- data/app/assets/javascripts/extjs-rails/src/core/examples/src/Sample/notdeadlock/B.js +4 -0
- data/app/assets/javascripts/extjs-rails/src/core/examples/src/Sample/notdeadlock/C.js +3 -0
- data/app/assets/javascripts/extjs-rails/src/core/src/EventManager.js +1167 -0
- data/app/assets/javascripts/extjs-rails/src/core/src/EventObject.js +883 -0
- data/app/assets/javascripts/extjs-rails/src/core/src/Ext-more.js +1283 -0
- data/app/assets/javascripts/extjs-rails/src/core/src/Ext.js +736 -0
- data/app/assets/javascripts/extjs-rails/src/core/src/Support.js +662 -0
- data/app/assets/javascripts/extjs-rails/src/core/src/class/Base.js +1085 -0
- data/app/assets/javascripts/extjs-rails/src/core/src/class/Class.js +676 -0
- data/app/assets/javascripts/extjs-rails/src/core/src/class/ClassManager.js +1591 -0
- data/app/assets/javascripts/extjs-rails/src/core/src/class/Loader.js +1423 -0
- data/app/assets/javascripts/extjs-rails/src/core/src/dom/AbstractElement.alignment.js +173 -0
- data/app/assets/javascripts/extjs-rails/src/core/src/dom/AbstractElement.insertion.js +193 -0
- data/app/assets/javascripts/extjs-rails/src/core/src/dom/AbstractElement.js +681 -0
- data/app/assets/javascripts/extjs-rails/src/core/src/dom/AbstractElement.position.js +356 -0
- data/app/assets/javascripts/extjs-rails/src/core/src/dom/AbstractElement.static.js +474 -0
- data/app/assets/javascripts/extjs-rails/src/core/src/dom/AbstractElement.style.js +851 -0
- data/app/assets/javascripts/extjs-rails/src/core/src/dom/AbstractElement.traversal.js +180 -0
- data/app/assets/javascripts/extjs-rails/src/core/src/dom/AbstractHelper.js +291 -0
- data/app/assets/javascripts/extjs-rails/src/core/src/dom/AbstractQuery.js +72 -0
- data/app/assets/javascripts/extjs-rails/src/core/src/dom/CompositeElement.js +75 -0
- data/app/assets/javascripts/extjs-rails/src/core/src/dom/CompositeElementLite.js +436 -0
- data/app/assets/javascripts/extjs-rails/src/core/src/dom/DomQuery-aria.js +1049 -0
- data/app/assets/javascripts/extjs-rails/src/core/src/env/Browser.js +186 -0
- data/app/assets/javascripts/extjs-rails/src/core/src/env/FeatureDetector.js +274 -0
- data/app/assets/javascripts/extjs-rails/src/core/src/env/OS.js +141 -0
- data/app/assets/javascripts/extjs-rails/src/core/src/lang/Array.js +1205 -0
- data/app/assets/javascripts/extjs-rails/src/core/src/lang/Date.js +1463 -0
- data/app/assets/javascripts/extjs-rails/src/core/src/lang/Error.js +326 -0
- data/app/assets/javascripts/extjs-rails/src/core/src/lang/Function.js +485 -0
- data/app/assets/javascripts/extjs-rails/src/core/src/lang/Number.js +175 -0
- data/app/assets/javascripts/extjs-rails/src/core/src/lang/Object.js +606 -0
- data/app/assets/javascripts/extjs-rails/src/core/src/lang/String.js +333 -0
- data/app/assets/javascripts/extjs-rails/src/core/src/misc/JSON.js +236 -0
- data/app/assets/javascripts/extjs-rails/src/core/src/perf/Accumulator.js +244 -0
- data/app/assets/javascripts/extjs-rails/src/core/src/perf/Monitor.js +197 -0
- data/app/assets/javascripts/extjs-rails/src/core/src/util/DelayedTask.js +71 -0
- data/app/assets/javascripts/extjs-rails/src/core/src/util/Event.js +215 -0
- data/app/assets/javascripts/extjs-rails/src/core/src/util/Format.js +551 -0
- data/app/assets/javascripts/extjs-rails/src/core/src/util/TaskManager.js +417 -0
- data/app/assets/javascripts/extjs-rails/src/core/src/version/Version.js +364 -0
- data/app/assets/javascripts/extjs-rails/src/core/test/unit/README.MD +91 -0
- data/app/assets/javascripts/extjs-rails/src/core/test/unit/bootstrap.js +39 -0
- data/app/assets/javascripts/extjs-rails/src/core/test/unit/build/build-data.js +34 -0
- data/app/assets/javascripts/extjs-rails/src/core/test/unit/build/build.sh +2 -0
- data/app/assets/javascripts/extjs-rails/src/core/test/unit/data.js +27 -0
- data/app/assets/javascripts/extjs-rails/src/core/test/unit/index.html +15 -0
- data/app/assets/javascripts/extjs-rails/src/core/test/unit/other_specs/dom.html +40 -0
- data/app/assets/javascripts/extjs-rails/src/core/test/unit/other_specs/dom/extjs-api.js +12 -0
- data/app/assets/javascripts/extjs-rails/src/core/test/unit/other_specs/dom/platform-api.js +134 -0
- data/app/assets/javascripts/extjs-rails/src/core/test/unit/other_specs/dom/sanity.js +4 -0
- data/app/assets/javascripts/extjs-rails/src/core/test/unit/other_specs/dom/touch-api-out.js +128 -0
- data/app/assets/javascripts/extjs-rails/src/core/test/unit/other_specs/dom/touch-api.js +89 -0
- data/app/assets/javascripts/extjs-rails/src/core/test/unit/other_specs/env/Environment.js +357 -0
- data/app/assets/javascripts/extjs-rails/src/core/test/unit/resources/APITest.js +37 -0
- data/app/assets/javascripts/extjs-rails/src/core/test/unit/resources/jsb3.js +14 -0
- data/app/assets/javascripts/extjs-rails/src/core/test/unit/resources/test-setup.js +137 -0
- data/app/assets/javascripts/extjs-rails/src/core/test/unit/spec/EventManager.js +629 -0
- data/app/assets/javascripts/extjs-rails/src/core/test/unit/spec/Ext-mess.backup +198 -0
- data/app/assets/javascripts/extjs-rails/src/core/test/unit/spec/Ext-more.js +520 -0
- data/app/assets/javascripts/extjs-rails/src/core/test/unit/spec/Ext.js +1550 -0
- data/app/assets/javascripts/extjs-rails/src/core/test/unit/spec/Support.js +250 -0
- data/app/assets/javascripts/extjs-rails/src/core/test/unit/spec/class/Base.js +47 -0
- data/app/assets/javascripts/extjs-rails/src/core/test/unit/spec/class/Class.js +561 -0
- data/app/assets/javascripts/extjs-rails/src/core/test/unit/spec/class/ClassManager.js +555 -0
- data/app/assets/javascripts/extjs-rails/src/core/test/unit/spec/dom/CompositeElementLite.js +409 -0
- data/app/assets/javascripts/extjs-rails/src/core/test/unit/spec/dom/DomHelper.js +444 -0
- data/app/assets/javascripts/extjs-rails/src/core/test/unit/spec/dom/Element.insertion.js +342 -0
- data/app/assets/javascripts/extjs-rails/src/core/test/unit/spec/dom/Element.js +731 -0
- data/app/assets/javascripts/extjs-rails/src/core/test/unit/spec/dom/Element.static.js +201 -0
- data/app/assets/javascripts/extjs-rails/src/core/test/unit/spec/dom/Element.style.js +118 -0
- data/app/assets/javascripts/extjs-rails/src/core/test/unit/spec/dom/Element.traversal.js +336 -0
- data/app/assets/javascripts/extjs-rails/src/core/test/unit/spec/lang/Array.js +1229 -0
- data/app/assets/javascripts/extjs-rails/src/core/test/unit/spec/lang/Date.js +697 -0
- data/app/assets/javascripts/extjs-rails/src/core/test/unit/spec/lang/Error.js +277 -0
- data/app/assets/javascripts/extjs-rails/src/core/test/unit/spec/lang/Function.js +536 -0
- data/app/assets/javascripts/extjs-rails/src/core/test/unit/spec/lang/Number.js +323 -0
- data/app/assets/javascripts/extjs-rails/src/core/test/unit/spec/lang/Object.js +591 -0
- data/app/assets/javascripts/extjs-rails/src/core/test/unit/spec/lang/String.js +451 -0
- data/app/assets/javascripts/extjs-rails/src/core/test/unit/spec/misc/JSON.js +252 -0
- data/app/assets/javascripts/extjs-rails/src/core/test/unit/spec/util/Format.js +521 -0
- data/app/assets/javascripts/extjs-rails/src/core/test/unit/spec/version/Version.js +148 -0
- data/app/assets/javascripts/extjs-rails/src/core/test/unit/specs.html +19 -0
- data/app/assets/javascripts/extjs-rails/src/data/AbstractStore.js +887 -0
- data/app/assets/javascripts/extjs-rails/src/data/ArrayStore.js +74 -0
- data/app/assets/javascripts/extjs-rails/src/data/Batch.js +236 -0
- data/app/assets/javascripts/extjs-rails/src/data/BufferStore.js +13 -0
- data/app/assets/javascripts/extjs-rails/src/data/Connection.js +969 -0
- data/app/assets/javascripts/extjs-rails/src/data/DirectStore.js +50 -0
- data/app/assets/javascripts/extjs-rails/src/data/Errors.js +52 -0
- data/app/assets/javascripts/extjs-rails/src/data/Field.js +341 -0
- data/app/assets/javascripts/extjs-rails/src/data/IdGenerator.js +198 -0
- data/app/assets/javascripts/extjs-rails/src/data/JsonP.js +253 -0
- data/app/assets/javascripts/extjs-rails/src/data/JsonPStore.js +51 -0
- data/app/assets/javascripts/extjs-rails/src/data/JsonStore.js +60 -0
- data/app/assets/javascripts/extjs-rails/src/data/Model.js +1673 -0
- data/app/assets/javascripts/extjs-rails/src/data/NodeInterface.js +1294 -0
- data/app/assets/javascripts/extjs-rails/src/data/NodeStore.js +254 -0
- data/app/assets/javascripts/extjs-rails/src/data/Operation.js +331 -0
- data/app/assets/javascripts/extjs-rails/src/data/Request.js +40 -0
- data/app/assets/javascripts/extjs-rails/src/data/ResultSet.js +56 -0
- data/app/assets/javascripts/extjs-rails/src/data/SequentialIdGenerator.js +61 -0
- data/app/assets/javascripts/extjs-rails/src/data/SortTypes.js +125 -0
- data/app/assets/javascripts/extjs-rails/src/data/Store.js +2609 -0
- data/app/assets/javascripts/extjs-rails/src/data/StoreManager.js +156 -0
- data/app/assets/javascripts/extjs-rails/src/data/Tree.js +290 -0
- data/app/assets/javascripts/extjs-rails/src/data/TreeStore.js +655 -0
- data/app/assets/javascripts/extjs-rails/src/data/Types.js +190 -0
- data/app/assets/javascripts/extjs-rails/src/data/UuidGenerator.js +215 -0
- data/app/assets/javascripts/extjs-rails/src/data/XmlStore.js +76 -0
- data/app/assets/javascripts/extjs-rails/src/data/association/Association.js +243 -0
- data/app/assets/javascripts/extjs-rails/src/data/association/BelongsTo.js +291 -0
- data/app/assets/javascripts/extjs-rails/src/data/association/HasMany.js +289 -0
- data/app/assets/javascripts/extjs-rails/src/data/association/HasOne.js +304 -0
- data/app/assets/javascripts/extjs-rails/src/data/proxy/Ajax.js +282 -0
- data/app/assets/javascripts/extjs-rails/src/data/proxy/Client.js +21 -0
- data/app/assets/javascripts/extjs-rails/src/data/proxy/Direct.js +181 -0
- data/app/assets/javascripts/extjs-rails/src/data/proxy/JsonP.js +313 -0
- data/app/assets/javascripts/extjs-rails/src/data/proxy/LocalStorage.js +69 -0
- data/app/assets/javascripts/extjs-rails/src/data/proxy/Memory.js +156 -0
- data/app/assets/javascripts/extjs-rails/src/data/proxy/Proxy.js +433 -0
- data/app/assets/javascripts/extjs-rails/src/data/proxy/Rest.js +173 -0
- data/app/assets/javascripts/extjs-rails/src/data/proxy/Server.js +460 -0
- data/app/assets/javascripts/extjs-rails/src/data/proxy/SessionStorage.js +39 -0
- data/app/assets/javascripts/extjs-rails/src/data/proxy/WebStorage.js +546 -0
- data/app/assets/javascripts/extjs-rails/src/data/reader/Array.js +68 -0
- data/app/assets/javascripts/extjs-rails/src/data/reader/Json.js +383 -0
- data/app/assets/javascripts/extjs-rails/src/data/reader/Reader.js +735 -0
- data/app/assets/javascripts/extjs-rails/src/data/reader/Xml.js +292 -0
- data/app/assets/javascripts/extjs-rails/src/data/validations.js +149 -0
- data/app/assets/javascripts/extjs-rails/src/data/writer/Json.js +81 -0
- data/app/assets/javascripts/extjs-rails/src/data/writer/Writer.js +147 -0
- data/app/assets/javascripts/extjs-rails/src/data/writer/Xml.js +88 -0
- data/app/assets/javascripts/extjs-rails/src/dd/DD.js +300 -0
- data/app/assets/javascripts/extjs-rails/src/dd/DDProxy.js +204 -0
- data/app/assets/javascripts/extjs-rails/src/dd/DDTarget.js +171 -0
- data/app/assets/javascripts/extjs-rails/src/dd/DragDrop.js +1101 -0
- data/app/assets/javascripts/extjs-rails/src/dd/DragDropManager.js +1264 -0
- data/app/assets/javascripts/extjs-rails/src/dd/DragSource.js +392 -0
- data/app/assets/javascripts/extjs-rails/src/dd/DragTracker.js +562 -0
- data/app/assets/javascripts/extjs-rails/src/dd/DragZone.js +137 -0
- data/app/assets/javascripts/extjs-rails/src/dd/DropTarget.js +118 -0
- data/app/assets/javascripts/extjs-rails/src/dd/DropZone.js +254 -0
- data/app/assets/javascripts/extjs-rails/src/dd/Registry.js +117 -0
- data/app/assets/javascripts/extjs-rails/src/dd/ScrollManager.js +218 -0
- data/app/assets/javascripts/extjs-rails/src/dd/StatusProxy.js +179 -0
- data/app/assets/javascripts/extjs-rails/src/diag/layout/Context.js +523 -0
- data/app/assets/javascripts/extjs-rails/src/diag/layout/ContextItem.js +179 -0
- data/app/assets/javascripts/extjs-rails/src/direct/Event.js +35 -0
- data/app/assets/javascripts/extjs-rails/src/direct/ExceptionEvent.js +16 -0
- data/app/assets/javascripts/extjs-rails/src/direct/JsonProvider.js +82 -0
- data/app/assets/javascripts/extjs-rails/src/direct/Manager.js +263 -0
- data/app/assets/javascripts/extjs-rails/src/direct/PollingProvider.js +156 -0
- data/app/assets/javascripts/extjs-rails/src/direct/Provider.js +96 -0
- data/app/assets/javascripts/extjs-rails/src/direct/RemotingEvent.js +24 -0
- data/app/assets/javascripts/extjs-rails/src/direct/RemotingMethod.js +100 -0
- data/app/assets/javascripts/extjs-rails/src/direct/RemotingProvider.js +510 -0
- data/app/assets/javascripts/extjs-rails/src/direct/Transaction.js +41 -0
- data/app/assets/javascripts/extjs-rails/src/dom/Element.alignment.js +378 -0
- data/app/assets/javascripts/extjs-rails/src/dom/Element.anim.js +962 -0
- data/app/assets/javascripts/extjs-rails/src/dom/Element.dd.js +40 -0
- data/app/assets/javascripts/extjs-rails/src/dom/Element.fx.js +194 -0
- data/app/assets/javascripts/extjs-rails/src/dom/Element.js +1407 -0
- data/app/assets/javascripts/extjs-rails/src/dom/Element.position.js +501 -0
- data/app/assets/javascripts/extjs-rails/src/dom/Element.scroll.js +214 -0
- data/app/assets/javascripts/extjs-rails/src/dom/Element.style.js +792 -0
- data/app/assets/javascripts/extjs-rails/src/dom/Element.traversal.js +8 -0
- data/app/assets/javascripts/extjs-rails/src/dom/Helper.js +466 -0
- data/app/assets/javascripts/extjs-rails/src/dom/Query.js +1067 -0
- data/app/assets/javascripts/extjs-rails/src/draw/Color.js +303 -0
- data/app/assets/javascripts/extjs-rails/src/draw/Component.js +245 -0
- data/app/assets/javascripts/extjs-rails/src/draw/CompositeSprite.js +299 -0
- data/app/assets/javascripts/extjs-rails/src/draw/Draw.js +1217 -0
- data/app/assets/javascripts/extjs-rails/src/draw/Matrix.js +183 -0
- data/app/assets/javascripts/extjs-rails/src/draw/Sprite.js +554 -0
- data/app/assets/javascripts/extjs-rails/src/draw/SpriteDD.js +87 -0
- data/app/assets/javascripts/extjs-rails/src/draw/Surface.js +1001 -0
- data/app/assets/javascripts/extjs-rails/src/draw/Text.js +175 -0
- data/app/assets/javascripts/extjs-rails/src/draw/engine/ImageExporter.js +106 -0
- data/app/assets/javascripts/extjs-rails/src/draw/engine/Svg.js +734 -0
- data/app/assets/javascripts/extjs-rails/src/draw/engine/SvgExporter.js +280 -0
- data/app/assets/javascripts/extjs-rails/src/draw/engine/Vml.js +916 -0
- data/app/assets/javascripts/extjs-rails/src/flash/Component.js +248 -0
- data/app/assets/javascripts/extjs-rails/src/form/Basic.js +1018 -0
- data/app/assets/javascripts/extjs-rails/src/form/CheckboxGroup.js +441 -0
- data/app/assets/javascripts/extjs-rails/src/form/CheckboxManager.js +26 -0
- data/app/assets/javascripts/extjs-rails/src/form/FieldAncestor.js +210 -0
- data/app/assets/javascripts/extjs-rails/src/form/FieldContainer.js +290 -0
- data/app/assets/javascripts/extjs-rails/src/form/FieldSet.js +506 -0
- data/app/assets/javascripts/extjs-rails/src/form/Label.js +110 -0
- data/app/assets/javascripts/extjs-rails/src/form/Labelable.js +764 -0
- data/app/assets/javascripts/extjs-rails/src/form/Panel.js +335 -0
- data/app/assets/javascripts/extjs-rails/src/form/RadioGroup.js +124 -0
- data/app/assets/javascripts/extjs-rails/src/form/RadioManager.js +26 -0
- data/app/assets/javascripts/extjs-rails/src/form/action/Action.js +307 -0
- data/app/assets/javascripts/extjs-rails/src/form/action/DirectLoad.js +107 -0
- data/app/assets/javascripts/extjs-rails/src/form/action/DirectSubmit.js +119 -0
- data/app/assets/javascripts/extjs-rails/src/form/action/Load.js +120 -0
- data/app/assets/javascripts/extjs-rails/src/form/action/StandardSubmit.js +34 -0
- data/app/assets/javascripts/extjs-rails/src/form/action/Submit.js +257 -0
- data/app/assets/javascripts/extjs-rails/src/form/field/Base.js +813 -0
- data/app/assets/javascripts/extjs-rails/src/form/field/Checkbox.js +505 -0
- data/app/assets/javascripts/extjs-rails/src/form/field/ComboBox.js +1427 -0
- data/app/assets/javascripts/extjs-rails/src/form/field/Date.js +578 -0
- data/app/assets/javascripts/extjs-rails/src/form/field/Display.js +155 -0
- data/app/assets/javascripts/extjs-rails/src/form/field/Field.js +430 -0
- data/app/assets/javascripts/extjs-rails/src/form/field/File.js +265 -0
- data/app/assets/javascripts/extjs-rails/src/form/field/Hidden.js +75 -0
- data/app/assets/javascripts/extjs-rails/src/form/field/HtmlEditor.js +1439 -0
- data/app/assets/javascripts/extjs-rails/src/form/field/Number.js +380 -0
- data/app/assets/javascripts/extjs-rails/src/form/field/Picker.js +321 -0
- data/app/assets/javascripts/extjs-rails/src/form/field/Radio.js +279 -0
- data/app/assets/javascripts/extjs-rails/src/form/field/Spinner.js +321 -0
- data/app/assets/javascripts/extjs-rails/src/form/field/Text.js +727 -0
- data/app/assets/javascripts/extjs-rails/src/form/field/TextArea.js +228 -0
- data/app/assets/javascripts/extjs-rails/src/form/field/Time.js +459 -0
- data/app/assets/javascripts/extjs-rails/src/form/field/Trigger.js +469 -0
- data/app/assets/javascripts/extjs-rails/src/form/field/VTypes.js +172 -0
- data/app/assets/javascripts/extjs-rails/src/fx/Anim.js +472 -0
- data/app/assets/javascripts/extjs-rails/src/fx/Animator.js +410 -0
- data/app/assets/javascripts/extjs-rails/src/fx/CubicBezier.js +77 -0
- data/app/assets/javascripts/extjs-rails/src/fx/Easing.js +136 -0
- data/app/assets/javascripts/extjs-rails/src/fx/Manager.js +353 -0
- data/app/assets/javascripts/extjs-rails/src/fx/PropertyHandler.js +381 -0
- data/app/assets/javascripts/extjs-rails/src/fx/Queue.js +123 -0
- data/app/assets/javascripts/extjs-rails/src/fx/target/Component.js +118 -0
- data/app/assets/javascripts/extjs-rails/src/fx/target/CompositeElement.js +46 -0
- data/app/assets/javascripts/extjs-rails/src/fx/target/CompositeElementCSS.js +22 -0
- data/app/assets/javascripts/extjs-rails/src/fx/target/CompositeSprite.js +34 -0
- data/app/assets/javascripts/extjs-rails/src/fx/target/Element.js +83 -0
- data/app/assets/javascripts/extjs-rails/src/fx/target/ElementCSS.js +77 -0
- data/app/assets/javascripts/extjs-rails/src/fx/target/Sprite.js +128 -0
- data/app/assets/javascripts/extjs-rails/src/fx/target/Target.js +36 -0
- data/app/assets/javascripts/extjs-rails/src/grid/CellEditor.js +172 -0
- data/app/assets/javascripts/extjs-rails/src/grid/ColumnComponentLayout.js +34 -0
- data/app/assets/javascripts/extjs-rails/src/grid/ColumnLayout.js +201 -0
- data/app/assets/javascripts/extjs-rails/src/grid/Lockable.js +863 -0
- data/app/assets/javascripts/extjs-rails/src/grid/LockingView.js +169 -0
- data/app/assets/javascripts/extjs-rails/src/grid/PagingScroller.js +539 -0
- data/app/assets/javascripts/extjs-rails/src/grid/Panel.js +393 -0
- data/app/assets/javascripts/extjs-rails/src/grid/RowEditor.js +731 -0
- data/app/assets/javascripts/extjs-rails/src/grid/RowNumberer.js +76 -0
- data/app/assets/javascripts/extjs-rails/src/grid/Scroller.js +5 -0
- data/app/assets/javascripts/extjs-rails/src/grid/View.js +44 -0
- data/app/assets/javascripts/extjs-rails/src/grid/ViewDropZone.js +41 -0
- data/app/assets/javascripts/extjs-rails/src/grid/column/Action.js +318 -0
- data/app/assets/javascripts/extjs-rails/src/grid/column/Boolean.js +82 -0
- data/app/assets/javascripts/extjs-rails/src/grid/column/Column.js +835 -0
- data/app/assets/javascripts/extjs-rails/src/grid/column/Date.js +63 -0
- data/app/assets/javascripts/extjs-rails/src/grid/column/Number.js +52 -0
- data/app/assets/javascripts/extjs-rails/src/grid/column/Template.js +58 -0
- data/app/assets/javascripts/extjs-rails/src/grid/feature/AbstractSummary.js +154 -0
- data/app/assets/javascripts/extjs-rails/src/grid/feature/Chunking.js +77 -0
- data/app/assets/javascripts/extjs-rails/src/grid/feature/Feature.js +158 -0
- data/app/assets/javascripts/extjs-rails/src/grid/feature/Grouping.js +822 -0
- data/app/assets/javascripts/extjs-rails/src/grid/feature/GroupingSummary.js +243 -0
- data/app/assets/javascripts/extjs-rails/src/grid/feature/RowBody.js +116 -0
- data/app/assets/javascripts/extjs-rails/src/grid/feature/RowWrap.js +120 -0
- data/app/assets/javascripts/extjs-rails/src/grid/feature/Summary.js +167 -0
- data/app/assets/javascripts/extjs-rails/src/grid/header/Container.js +965 -0
- data/app/assets/javascripts/extjs-rails/src/grid/header/DragZone.js +69 -0
- data/app/assets/javascripts/extjs-rails/src/grid/header/DropZone.js +265 -0
- data/app/assets/javascripts/extjs-rails/src/grid/plugin/CellEditing.js +453 -0
- data/app/assets/javascripts/extjs-rails/src/grid/plugin/DragDrop.js +254 -0
- data/app/assets/javascripts/extjs-rails/src/grid/plugin/Editing.js +561 -0
- data/app/assets/javascripts/extjs-rails/src/grid/plugin/HeaderReorderer.js +49 -0
- data/app/assets/javascripts/extjs-rails/src/grid/plugin/HeaderResizer.js +292 -0
- data/app/assets/javascripts/extjs-rails/src/grid/plugin/RowEditing.js +339 -0
- data/app/assets/javascripts/extjs-rails/src/grid/property/Grid.js +351 -0
- data/app/assets/javascripts/extjs-rails/src/grid/property/HeaderContainer.js +109 -0
- data/app/assets/javascripts/extjs-rails/src/grid/property/Property.js +36 -0
- data/app/assets/javascripts/extjs-rails/src/grid/property/Store.js +141 -0
- data/app/assets/javascripts/extjs-rails/src/layout/ClassList.js +90 -0
- data/app/assets/javascripts/extjs-rails/src/layout/Context.js +1232 -0
- data/app/assets/javascripts/extjs-rails/src/layout/ContextItem.js +1470 -0
- data/app/assets/javascripts/extjs-rails/src/layout/Layout.js +761 -0
- data/app/assets/javascripts/extjs-rails/src/layout/component/Auto.js +220 -0
- data/app/assets/javascripts/extjs-rails/src/layout/component/Body.js +80 -0
- data/app/assets/javascripts/extjs-rails/src/layout/component/BoundList.js +95 -0
- data/app/assets/javascripts/extjs-rails/src/layout/component/Button.js +261 -0
- data/app/assets/javascripts/extjs-rails/src/layout/component/Component.js +427 -0
- data/app/assets/javascripts/extjs-rails/src/layout/component/Dock.js +1132 -0
- data/app/assets/javascripts/extjs-rails/src/layout/component/Draw.js +79 -0
- data/app/assets/javascripts/extjs-rails/src/layout/component/FieldSet.js +62 -0
- data/app/assets/javascripts/extjs-rails/src/layout/component/ProgressBar.js +54 -0
- data/app/assets/javascripts/extjs-rails/src/layout/component/Tab.js +23 -0
- data/app/assets/javascripts/extjs-rails/src/layout/component/field/ComboBox.js +52 -0
- data/app/assets/javascripts/extjs-rails/src/layout/component/field/Field.js +372 -0
- data/app/assets/javascripts/extjs-rails/src/layout/component/field/FieldContainer.js +48 -0
- data/app/assets/javascripts/extjs-rails/src/layout/component/field/HtmlEditor.js +54 -0
- data/app/assets/javascripts/extjs-rails/src/layout/component/field/Slider.js +58 -0
- data/app/assets/javascripts/extjs-rails/src/layout/component/field/Text.js +75 -0
- data/app/assets/javascripts/extjs-rails/src/layout/component/field/TextArea.js +51 -0
- data/app/assets/javascripts/extjs-rails/src/layout/component/field/Trigger.js +132 -0
- data/app/assets/javascripts/extjs-rails/src/layout/container/Absolute.js +121 -0
- data/app/assets/javascripts/extjs-rails/src/layout/container/Accordion.js +308 -0
- data/app/assets/javascripts/extjs-rails/src/layout/container/Anchor.js +403 -0
- data/app/assets/javascripts/extjs-rails/src/layout/container/Auto.js +70 -0
- data/app/assets/javascripts/extjs-rails/src/layout/container/Border-old-js +1079 -0
- data/app/assets/javascripts/extjs-rails/src/layout/container/Border.js +816 -0
- data/app/assets/javascripts/extjs-rails/src/layout/container/Box.js +929 -0
- data/app/assets/javascripts/extjs-rails/src/layout/container/Card.js +361 -0
- data/app/assets/javascripts/extjs-rails/src/layout/container/CheckboxGroup.js +376 -0
- data/app/assets/javascripts/extjs-rails/src/layout/container/Column.js +234 -0
- data/app/assets/javascripts/extjs-rails/src/layout/container/Container.js +961 -0
- data/app/assets/javascripts/extjs-rails/src/layout/container/Editor.js +74 -0
- data/app/assets/javascripts/extjs-rails/src/layout/container/Fit.js +287 -0
- data/app/assets/javascripts/extjs-rails/src/layout/container/Form.js +157 -0
- data/app/assets/javascripts/extjs-rails/src/layout/container/HBox.js +134 -0
- data/app/assets/javascripts/extjs-rails/src/layout/container/Table.js +412 -0
- data/app/assets/javascripts/extjs-rails/src/layout/container/VBox.js +139 -0
- data/app/assets/javascripts/extjs-rails/src/layout/container/boxOverflow/Menu.js +365 -0
- data/app/assets/javascripts/extjs-rails/src/layout/container/boxOverflow/None.js +83 -0
- data/app/assets/javascripts/extjs-rails/src/layout/container/boxOverflow/Scroller.js +475 -0
- data/app/assets/javascripts/extjs-rails/src/menu/CheckItem.js +169 -0
- data/app/assets/javascripts/extjs-rails/src/menu/ColorPicker.js +110 -0
- data/app/assets/javascripts/extjs-rails/src/menu/DatePicker.js +100 -0
- data/app/assets/javascripts/extjs-rails/src/menu/Item.js +553 -0
- data/app/assets/javascripts/extjs-rails/src/menu/KeyNav.js +134 -0
- data/app/assets/javascripts/extjs-rails/src/menu/Manager.js +219 -0
- data/app/assets/javascripts/extjs-rails/src/menu/Menu.js +579 -0
- data/app/assets/javascripts/extjs-rails/src/menu/Separator.js +126 -0
- data/app/assets/javascripts/extjs-rails/src/panel/AbstractPanel.js +323 -0
- data/app/assets/javascripts/extjs-rails/src/panel/DD.js +99 -0
- data/app/assets/javascripts/extjs-rails/src/panel/Header.js +518 -0
- data/app/assets/javascripts/extjs-rails/src/panel/Panel.js +2150 -0
- data/app/assets/javascripts/extjs-rails/src/panel/Proxy.js +131 -0
- data/app/assets/javascripts/extjs-rails/src/panel/Table.js +1018 -0
- data/app/assets/javascripts/extjs-rails/src/panel/Tool.js +304 -0
- data/app/assets/javascripts/extjs-rails/src/picker/Color.js +219 -0
- data/app/assets/javascripts/extjs-rails/src/picker/Date.js +1140 -0
- data/app/assets/javascripts/extjs-rails/src/picker/Month.js +490 -0
- data/app/assets/javascripts/extjs-rails/src/picker/Time.js +165 -0
- data/app/assets/javascripts/extjs-rails/src/resizer/BorderSplitter.js +22 -0
- data/app/assets/javascripts/extjs-rails/src/resizer/BorderSplitterTracker.js +210 -0
- data/app/assets/javascripts/extjs-rails/src/resizer/Handle.js +29 -0
- data/app/assets/javascripts/extjs-rails/src/resizer/ResizeTracker.js +346 -0
- data/app/assets/javascripts/extjs-rails/src/resizer/Resizer.js +477 -0
- data/app/assets/javascripts/extjs-rails/src/resizer/Splitter.js +242 -0
- data/app/assets/javascripts/extjs-rails/src/resizer/SplitterTracker.js +230 -0
- data/app/assets/javascripts/extjs-rails/src/selection/CellModel.js +395 -0
- data/app/assets/javascripts/extjs-rails/src/selection/CheckboxModel.js +234 -0
- data/app/assets/javascripts/extjs-rails/src/selection/DataViewModel.js +160 -0
- data/app/assets/javascripts/extjs-rails/src/selection/Model.js +646 -0
- data/app/assets/javascripts/extjs-rails/src/selection/RowModel.js +499 -0
- data/app/assets/javascripts/extjs-rails/src/selection/TreeModel.js +78 -0
- data/app/assets/javascripts/extjs-rails/src/slider/Multi.js +835 -0
- data/app/assets/javascripts/extjs-rails/src/slider/Single.js +56 -0
- data/app/assets/javascripts/extjs-rails/src/slider/Thumb.js +259 -0
- data/app/assets/javascripts/extjs-rails/src/slider/Tip.js +130 -0
- data/app/assets/javascripts/extjs-rails/src/state/CookieProvider.js +120 -0
- data/app/assets/javascripts/extjs-rails/src/state/LocalStorageProvider.js +72 -0
- data/app/assets/javascripts/extjs-rails/src/state/Manager.js +70 -0
- data/app/assets/javascripts/extjs-rails/src/state/Provider.js +182 -0
- data/app/assets/javascripts/extjs-rails/src/state/Stateful.js +364 -0
- data/app/assets/javascripts/extjs-rails/src/tab/Bar.js +258 -0
- data/app/assets/javascripts/extjs-rails/src/tab/Panel.js +654 -0
- data/app/assets/javascripts/extjs-rails/src/tab/Tab.js +358 -0
- data/app/assets/javascripts/extjs-rails/src/tail.js +10 -0
- data/app/assets/javascripts/extjs-rails/src/tip/QuickTip.js +335 -0
- data/app/assets/javascripts/extjs-rails/src/tip/QuickTipManager.js +239 -0
- data/app/assets/javascripts/extjs-rails/src/tip/Tip.js +160 -0
- data/app/assets/javascripts/extjs-rails/src/tip/ToolTip.js +691 -0
- data/app/assets/javascripts/extjs-rails/src/toolbar/Fill.js +28 -0
- data/app/assets/javascripts/extjs-rails/src/toolbar/Item.js +16 -0
- data/app/assets/javascripts/extjs-rails/src/toolbar/Paging.js +600 -0
- data/app/assets/javascripts/extjs-rails/src/toolbar/Separator.js +23 -0
- data/app/assets/javascripts/extjs-rails/src/toolbar/Spacer.js +33 -0
- data/app/assets/javascripts/extjs-rails/src/toolbar/TextItem.js +57 -0
- data/app/assets/javascripts/extjs-rails/src/toolbar/Toolbar-legacy.js +123 -0
- data/app/assets/javascripts/extjs-rails/src/toolbar/Toolbar.js +447 -0
- data/app/assets/javascripts/extjs-rails/src/tree/Column.js +90 -0
- data/app/assets/javascripts/extjs-rails/src/tree/Panel.js +505 -0
- data/app/assets/javascripts/extjs-rails/src/tree/View.js +658 -0
- data/app/assets/javascripts/extjs-rails/src/tree/ViewDragZone.js +49 -0
- data/app/assets/javascripts/extjs-rails/src/tree/ViewDropZone.js +287 -0
- data/app/assets/javascripts/extjs-rails/src/tree/plugin/TreeViewDragDrop.js +244 -0
- data/app/assets/javascripts/extjs-rails/src/util/AbstractMixedCollection.js +772 -0
- data/app/assets/javascripts/extjs-rails/src/util/Animate.js +426 -0
- data/app/assets/javascripts/extjs-rails/src/util/Bindable.js +102 -0
- data/app/assets/javascripts/extjs-rails/src/util/CSS.js +185 -0
- data/app/assets/javascripts/extjs-rails/src/util/ClickRepeater.js +238 -0
- data/app/assets/javascripts/extjs-rails/src/util/ComponentDragger.js +126 -0
- data/app/assets/javascripts/extjs-rails/src/util/Cookies.js +91 -0
- data/app/assets/javascripts/extjs-rails/src/util/ElementContainer.js +293 -0
- data/app/assets/javascripts/extjs-rails/src/util/Filter.js +159 -0
- data/app/assets/javascripts/extjs-rails/src/util/Floating.js +321 -0
- data/app/assets/javascripts/extjs-rails/src/util/Grouper.js +26 -0
- data/app/assets/javascripts/extjs-rails/src/util/HashMap.js +356 -0
- data/app/assets/javascripts/extjs-rails/src/util/History.js +285 -0
- data/app/assets/javascripts/extjs-rails/src/util/Inflector.js +297 -0
- data/app/assets/javascripts/extjs-rails/src/util/KeyMap.js +427 -0
- data/app/assets/javascripts/extjs-rails/src/util/KeyNav.js +239 -0
- data/app/assets/javascripts/extjs-rails/src/util/LruCache.js +257 -0
- data/app/assets/javascripts/extjs-rails/src/util/Memento.js +131 -0
- data/app/assets/javascripts/extjs-rails/src/util/MixedCollection.js +239 -0
- data/app/assets/javascripts/extjs-rails/src/util/Observable.js +1003 -0
- data/app/assets/javascripts/extjs-rails/src/util/Offset.js +60 -0
- data/app/assets/javascripts/extjs-rails/src/util/Point.js +93 -0
- data/app/assets/javascripts/extjs-rails/src/util/ProtoElement.js +205 -0
- data/app/assets/javascripts/extjs-rails/src/util/Queue.js +76 -0
- data/app/assets/javascripts/extjs-rails/src/util/Region.js +388 -0
- data/app/assets/javascripts/extjs-rails/src/util/Renderable.js +1079 -0
- data/app/assets/javascripts/extjs-rails/src/util/Sortable.js +248 -0
- data/app/assets/javascripts/extjs-rails/src/util/Sorter.js +179 -0
- data/app/assets/javascripts/extjs-rails/src/util/TextMetrics.js +148 -0
- data/app/assets/javascripts/extjs-rails/src/view/AbstractView.js +1103 -0
- data/app/assets/javascripts/extjs-rails/src/view/BoundList.js +207 -0
- data/app/assets/javascripts/extjs-rails/src/view/BoundListKeyNav.js +92 -0
- data/app/assets/javascripts/extjs-rails/src/view/DragZone.js +106 -0
- data/app/assets/javascripts/extjs-rails/src/view/DropZone.js +240 -0
- data/app/assets/javascripts/extjs-rails/src/view/Table.js +1229 -0
- data/app/assets/javascripts/extjs-rails/src/view/TableChunker.js +139 -0
- data/app/assets/javascripts/extjs-rails/src/view/View.js +636 -0
- data/app/assets/javascripts/extjs-rails/src/window/MessageBox.js +880 -0
- data/app/assets/javascripts/extjs-rails/src/window/Window-legacy.js +56 -0
- data/app/assets/javascripts/extjs-rails/src/window/Window.js +793 -0
- data/extjs-rails.gemspec +24 -0
- data/lib/extjs-rails.rb +7 -0
- data/lib/extjs-rails/engine.rb +7 -0
- data/lib/extjs-rails/version.rb +5 -0
- metadata +660 -0
|
@@ -0,0 +1,253 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @class Ext.data.JsonP
|
|
3
|
+
* @singleton
|
|
4
|
+
* This class is used to create JSONP requests. JSONP is a mechanism that allows for making
|
|
5
|
+
* requests for data cross domain. More information is available <a href="http://en.wikipedia.org/wiki/JSONP">here</a>.
|
|
6
|
+
*/
|
|
7
|
+
Ext.define('Ext.data.JsonP', {
|
|
8
|
+
|
|
9
|
+
/* Begin Definitions */
|
|
10
|
+
|
|
11
|
+
singleton: true,
|
|
12
|
+
|
|
13
|
+
statics: {
|
|
14
|
+
requestCount: 0,
|
|
15
|
+
requests: {}
|
|
16
|
+
},
|
|
17
|
+
|
|
18
|
+
/* End Definitions */
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* @property timeout
|
|
22
|
+
* @type Number
|
|
23
|
+
* A default timeout for any JsonP requests. If the request has not completed in this time the
|
|
24
|
+
* failure callback will be fired. The timeout is in ms. Defaults to <tt>30000</tt>.
|
|
25
|
+
*/
|
|
26
|
+
timeout: 30000,
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* @property disableCaching
|
|
30
|
+
* @type Boolean
|
|
31
|
+
* True to add a unique cache-buster param to requests. Defaults to <tt>true</tt>.
|
|
32
|
+
*/
|
|
33
|
+
disableCaching: true,
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* @property disableCachingParam
|
|
37
|
+
* @type String
|
|
38
|
+
* Change the parameter which is sent went disabling caching through a cache buster. Defaults to <tt>'_dc'</tt>.
|
|
39
|
+
*/
|
|
40
|
+
disableCachingParam: '_dc',
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* @property callbackKey
|
|
44
|
+
* @type String
|
|
45
|
+
* Specifies the GET parameter that will be sent to the server containing the function name to be executed when
|
|
46
|
+
* the request completes. Defaults to <tt>callback</tt>. Thus, a common request will be in the form of
|
|
47
|
+
* url?callback=Ext.data.JsonP.callback1
|
|
48
|
+
*/
|
|
49
|
+
callbackKey: 'callback',
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Makes a JSONP request.
|
|
53
|
+
* @param {Object} options An object which may contain the following properties. Note that options will
|
|
54
|
+
* take priority over any defaults that are specified in the class.
|
|
55
|
+
* <ul>
|
|
56
|
+
* <li><b>url</b> : String <div class="sub-desc">The URL to request.</div></li>
|
|
57
|
+
* <li><b>params</b> : Object (Optional)<div class="sub-desc">An object containing a series of
|
|
58
|
+
* key value pairs that will be sent along with the request.</div></li>
|
|
59
|
+
* <li><b>timeout</b> : Number (Optional) <div class="sub-desc">See {@link #timeout}</div></li>
|
|
60
|
+
* <li><b>callbackKey</b> : String (Optional) <div class="sub-desc">See {@link #callbackKey}</div></li>
|
|
61
|
+
* <li><b>callbackName</b> : String (Optional) <div class="sub-desc">The function name to use for this request.
|
|
62
|
+
* By default this name will be auto-generated: Ext.data.JsonP.callback1, Ext.data.JsonP.callback2, etc.
|
|
63
|
+
* Setting this option to "my_name" will force the function name to be Ext.data.JsonP.my_name.
|
|
64
|
+
* Use this if you want deterministic behavior, but be careful - the callbackName should be different
|
|
65
|
+
* in each JsonP request that you make.</div></li>
|
|
66
|
+
* <li><b>disableCaching</b> : Boolean (Optional) <div class="sub-desc">See {@link #disableCaching}</div></li>
|
|
67
|
+
* <li><b>disableCachingParam</b> : String (Optional) <div class="sub-desc">See {@link #disableCachingParam}</div></li>
|
|
68
|
+
* <li><b>success</b> : Function (Optional) <div class="sub-desc">A function to execute if the request succeeds.</div></li>
|
|
69
|
+
* <li><b>failure</b> : Function (Optional) <div class="sub-desc">A function to execute if the request fails.</div></li>
|
|
70
|
+
* <li><b>callback</b> : Function (Optional) <div class="sub-desc">A function to execute when the request
|
|
71
|
+
* completes, whether it is a success or failure.</div></li>
|
|
72
|
+
* <li><b>scope</b> : Object (Optional)<div class="sub-desc">The scope in
|
|
73
|
+
* which to execute the callbacks: The "this" object for the callback function. Defaults to the browser window.</div></li>
|
|
74
|
+
* </ul>
|
|
75
|
+
* @return {Object} request An object containing the request details.
|
|
76
|
+
*/
|
|
77
|
+
request: function(options){
|
|
78
|
+
options = Ext.apply({}, options);
|
|
79
|
+
|
|
80
|
+
//<debug>
|
|
81
|
+
if (!options.url) {
|
|
82
|
+
Ext.Error.raise('A url must be specified for a JSONP request.');
|
|
83
|
+
}
|
|
84
|
+
//</debug>
|
|
85
|
+
|
|
86
|
+
var me = this,
|
|
87
|
+
disableCaching = Ext.isDefined(options.disableCaching) ? options.disableCaching : me.disableCaching,
|
|
88
|
+
cacheParam = options.disableCachingParam || me.disableCachingParam,
|
|
89
|
+
id = ++me.statics().requestCount,
|
|
90
|
+
callbackName = options.callbackName || 'callback' + id,
|
|
91
|
+
callbackKey = options.callbackKey || me.callbackKey,
|
|
92
|
+
timeout = Ext.isDefined(options.timeout) ? options.timeout : me.timeout,
|
|
93
|
+
params = Ext.apply({}, options.params),
|
|
94
|
+
url = options.url,
|
|
95
|
+
name = Ext.name,
|
|
96
|
+
request,
|
|
97
|
+
script;
|
|
98
|
+
|
|
99
|
+
params[callbackKey] = name + '.data.JsonP.' + callbackName;
|
|
100
|
+
if (disableCaching) {
|
|
101
|
+
params[cacheParam] = new Date().getTime();
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
script = me.createScript(url, params, options);
|
|
105
|
+
|
|
106
|
+
me.statics().requests[id] = request = {
|
|
107
|
+
url: url,
|
|
108
|
+
params: params,
|
|
109
|
+
script: script,
|
|
110
|
+
id: id,
|
|
111
|
+
scope: options.scope,
|
|
112
|
+
success: options.success,
|
|
113
|
+
failure: options.failure,
|
|
114
|
+
callback: options.callback,
|
|
115
|
+
callbackKey: callbackKey,
|
|
116
|
+
callbackName: callbackName
|
|
117
|
+
};
|
|
118
|
+
|
|
119
|
+
if (timeout > 0) {
|
|
120
|
+
request.timeout = setTimeout(Ext.bind(me.handleTimeout, me, [request]), timeout);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
me.setupErrorHandling(request);
|
|
124
|
+
me[callbackName] = Ext.bind(me.handleResponse, me, [request], true);
|
|
125
|
+
me.loadScript(request);
|
|
126
|
+
return request;
|
|
127
|
+
},
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Abort a request. If the request parameter is not specified all open requests will
|
|
131
|
+
* be aborted.
|
|
132
|
+
* @param {Object/String} request (Optional) The request to abort
|
|
133
|
+
*/
|
|
134
|
+
abort: function(request){
|
|
135
|
+
var me = this,
|
|
136
|
+
requests = me.statics().requests,
|
|
137
|
+
key;
|
|
138
|
+
|
|
139
|
+
if (request) {
|
|
140
|
+
if (!request.id) {
|
|
141
|
+
request = requests[request];
|
|
142
|
+
}
|
|
143
|
+
me.handleAbort(request);
|
|
144
|
+
} else {
|
|
145
|
+
for (key in requests) {
|
|
146
|
+
if (requests.hasOwnProperty(key)) {
|
|
147
|
+
me.abort(requests[key]);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
},
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* Sets up error handling for the script
|
|
155
|
+
* @private
|
|
156
|
+
* @param {Object} request The request
|
|
157
|
+
*/
|
|
158
|
+
setupErrorHandling: function(request){
|
|
159
|
+
request.script.onerror = Ext.bind(this.handleError, this, [request]);
|
|
160
|
+
},
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Handles any aborts when loading the script
|
|
164
|
+
* @private
|
|
165
|
+
* @param {Object} request The request
|
|
166
|
+
*/
|
|
167
|
+
handleAbort: function(request){
|
|
168
|
+
request.errorType = 'abort';
|
|
169
|
+
this.handleResponse(null, request);
|
|
170
|
+
},
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* Handles any script errors when loading the script
|
|
174
|
+
* @private
|
|
175
|
+
* @param {Object} request The request
|
|
176
|
+
*/
|
|
177
|
+
handleError: function(request){
|
|
178
|
+
request.errorType = 'error';
|
|
179
|
+
this.handleResponse(null, request);
|
|
180
|
+
},
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* Cleans up anu script handling errors
|
|
184
|
+
* @private
|
|
185
|
+
* @param {Object} request The request
|
|
186
|
+
*/
|
|
187
|
+
cleanupErrorHandling: function(request){
|
|
188
|
+
request.script.onerror = null;
|
|
189
|
+
},
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* Handle any script timeouts
|
|
193
|
+
* @private
|
|
194
|
+
* @param {Object} request The request
|
|
195
|
+
*/
|
|
196
|
+
handleTimeout: function(request){
|
|
197
|
+
request.errorType = 'timeout';
|
|
198
|
+
this.handleResponse(null, request);
|
|
199
|
+
},
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* Handle a successful response
|
|
203
|
+
* @private
|
|
204
|
+
* @param {Object} result The result from the request
|
|
205
|
+
* @param {Object} request The request
|
|
206
|
+
*/
|
|
207
|
+
handleResponse: function(result, request){
|
|
208
|
+
|
|
209
|
+
var success = true;
|
|
210
|
+
|
|
211
|
+
if (request.timeout) {
|
|
212
|
+
clearTimeout(request.timeout);
|
|
213
|
+
}
|
|
214
|
+
delete this[request.callbackName];
|
|
215
|
+
delete this.statics().requests[request.id];
|
|
216
|
+
this.cleanupErrorHandling(request);
|
|
217
|
+
Ext.fly(request.script).remove();
|
|
218
|
+
|
|
219
|
+
if (request.errorType) {
|
|
220
|
+
success = false;
|
|
221
|
+
Ext.callback(request.failure, request.scope, [request.errorType]);
|
|
222
|
+
} else {
|
|
223
|
+
Ext.callback(request.success, request.scope, [result]);
|
|
224
|
+
}
|
|
225
|
+
Ext.callback(request.callback, request.scope, [success, result, request.errorType]);
|
|
226
|
+
},
|
|
227
|
+
|
|
228
|
+
/**
|
|
229
|
+
* Create the script tag given the specified url, params and options. The options
|
|
230
|
+
* parameter is passed to allow an override to access it.
|
|
231
|
+
* @private
|
|
232
|
+
* @param {String} url The url of the request
|
|
233
|
+
* @param {Object} params Any extra params to be sent
|
|
234
|
+
* @param {Object} options The object passed to {@link #request}.
|
|
235
|
+
*/
|
|
236
|
+
createScript: function(url, params, options) {
|
|
237
|
+
var script = document.createElement('script');
|
|
238
|
+
script.setAttribute("src", Ext.urlAppend(url, Ext.Object.toQueryString(params)));
|
|
239
|
+
script.setAttribute("async", true);
|
|
240
|
+
script.setAttribute("type", "text/javascript");
|
|
241
|
+
return script;
|
|
242
|
+
},
|
|
243
|
+
|
|
244
|
+
/**
|
|
245
|
+
* Loads the script for the given request by appending it to the HEAD element. This is
|
|
246
|
+
* its own method so that users can override it (as well as {@link #createScript}).
|
|
247
|
+
* @private
|
|
248
|
+
* @param request The request object.
|
|
249
|
+
*/
|
|
250
|
+
loadScript: function (request) {
|
|
251
|
+
Ext.getHead().appendChild(request.script);
|
|
252
|
+
}
|
|
253
|
+
});
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @class Ext.data.JsonPStore
|
|
3
|
+
* @extends Ext.data.Store
|
|
4
|
+
* <p>Small helper class to make creating {@link Ext.data.Store}s from different domain JSON data easier.
|
|
5
|
+
* A JsonPStore will be automatically configured with a {@link Ext.data.reader.Json} and a {@link Ext.data.proxy.JsonP JsonPProxy}.</p>
|
|
6
|
+
* <p>A store configuration would be something like:<pre><code>
|
|
7
|
+
var store = new Ext.data.JsonPStore({
|
|
8
|
+
// store configs
|
|
9
|
+
autoDestroy: true,
|
|
10
|
+
storeId: 'myStore',
|
|
11
|
+
|
|
12
|
+
// proxy configs
|
|
13
|
+
url: 'get-images.php',
|
|
14
|
+
|
|
15
|
+
// reader configs
|
|
16
|
+
root: 'images',
|
|
17
|
+
idProperty: 'name',
|
|
18
|
+
fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
|
|
19
|
+
});
|
|
20
|
+
* </code></pre></p>
|
|
21
|
+
* <p>This store is configured to consume a returned object of the form:<pre><code>
|
|
22
|
+
stcCallback({
|
|
23
|
+
images: [
|
|
24
|
+
{name: 'Image one', url:'/GetImage.php?id=1', size:46.5, lastmod: new Date(2007, 10, 29)},
|
|
25
|
+
{name: 'Image Two', url:'/GetImage.php?id=2', size:43.2, lastmod: new Date(2007, 10, 30)}
|
|
26
|
+
]
|
|
27
|
+
})
|
|
28
|
+
* </code></pre>
|
|
29
|
+
* <p>Where stcCallback is the callback name passed in the request to the remote domain. See {@link Ext.data.proxy.JsonP JsonPProxy}
|
|
30
|
+
* for details of how this works.</p>
|
|
31
|
+
* An object literal of this form could also be used as the {@link #cfg-data} config option.</p>
|
|
32
|
+
* @xtype jsonpstore
|
|
33
|
+
*/
|
|
34
|
+
Ext.define('Ext.data.JsonPStore', {
|
|
35
|
+
extend: 'Ext.data.Store',
|
|
36
|
+
alias : 'store.jsonp',
|
|
37
|
+
requires: [
|
|
38
|
+
'Ext.data.proxy.JsonP',
|
|
39
|
+
'Ext.data.reader.Json'
|
|
40
|
+
],
|
|
41
|
+
|
|
42
|
+
constructor: function(config) {
|
|
43
|
+
config = Ext.apply({
|
|
44
|
+
proxy: {
|
|
45
|
+
type: 'jsonp',
|
|
46
|
+
reader: 'json'
|
|
47
|
+
}
|
|
48
|
+
}, config);
|
|
49
|
+
this.callParent([config]);
|
|
50
|
+
}
|
|
51
|
+
});
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @author Ed Spencer
|
|
3
|
+
*
|
|
4
|
+
* <p>Small helper class to make creating {@link Ext.data.Store}s from JSON data easier.
|
|
5
|
+
* A JsonStore will be automatically configured with a {@link Ext.data.reader.Json}.</p>
|
|
6
|
+
*
|
|
7
|
+
* <p>A store configuration would be something like:</p>
|
|
8
|
+
*
|
|
9
|
+
<pre><code>
|
|
10
|
+
var store = new Ext.data.JsonStore({
|
|
11
|
+
// store configs
|
|
12
|
+
autoDestroy: true,
|
|
13
|
+
storeId: 'myStore',
|
|
14
|
+
|
|
15
|
+
proxy: {
|
|
16
|
+
type: 'ajax',
|
|
17
|
+
url: 'get-images.php',
|
|
18
|
+
reader: {
|
|
19
|
+
type: 'json',
|
|
20
|
+
root: 'images',
|
|
21
|
+
idProperty: 'name'
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
|
|
25
|
+
//alternatively, a {@link Ext.data.Model} name can be given (see {@link Ext.data.Store} for an example)
|
|
26
|
+
fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
|
|
27
|
+
});
|
|
28
|
+
</code></pre>
|
|
29
|
+
*
|
|
30
|
+
* <p>This store is configured to consume a returned object of the form:<pre><code>
|
|
31
|
+
{
|
|
32
|
+
images: [
|
|
33
|
+
{name: 'Image one', url:'/GetImage.php?id=1', size:46.5, lastmod: new Date(2007, 10, 29)},
|
|
34
|
+
{name: 'Image Two', url:'/GetImage.php?id=2', size:43.2, lastmod: new Date(2007, 10, 30)}
|
|
35
|
+
]
|
|
36
|
+
}
|
|
37
|
+
</code></pre>
|
|
38
|
+
*
|
|
39
|
+
* <p>An object literal of this form could also be used as the {@link #cfg-data} config option.</p>
|
|
40
|
+
*/
|
|
41
|
+
Ext.define('Ext.data.JsonStore', {
|
|
42
|
+
extend: 'Ext.data.Store',
|
|
43
|
+
alias: 'store.json',
|
|
44
|
+
requires: [
|
|
45
|
+
'Ext.data.proxy.Ajax',
|
|
46
|
+
'Ext.data.reader.Json',
|
|
47
|
+
'Ext.data.writer.Json'
|
|
48
|
+
],
|
|
49
|
+
|
|
50
|
+
constructor: function(config) {
|
|
51
|
+
config = Ext.apply({
|
|
52
|
+
proxy: {
|
|
53
|
+
type : 'ajax',
|
|
54
|
+
reader: 'json',
|
|
55
|
+
writer: 'json'
|
|
56
|
+
}
|
|
57
|
+
}, config);
|
|
58
|
+
this.callParent([config]);
|
|
59
|
+
}
|
|
60
|
+
});
|
|
@@ -0,0 +1,1673 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @author Ed Spencer
|
|
3
|
+
*
|
|
4
|
+
* A Model represents some object that your application manages. For example, one might define a Model for Users,
|
|
5
|
+
* Products, Cars, or any other real-world object that we want to model in the system. Models are registered via the
|
|
6
|
+
* {@link Ext.ModelManager model manager}, and are used by {@link Ext.data.Store stores}, which are in turn used by many
|
|
7
|
+
* of the data-bound components in Ext.
|
|
8
|
+
*
|
|
9
|
+
* Models are defined as a set of fields and any arbitrary methods and properties relevant to the model. For example:
|
|
10
|
+
*
|
|
11
|
+
* Ext.define('User', {
|
|
12
|
+
* extend: 'Ext.data.Model',
|
|
13
|
+
* fields: [
|
|
14
|
+
* {name: 'name', type: 'string'},
|
|
15
|
+
* {name: 'age', type: 'int', convert: null},
|
|
16
|
+
* {name: 'phone', type: 'string'},
|
|
17
|
+
* {name: 'alive', type: 'boolean', defaultValue: true, convert: null}
|
|
18
|
+
* ],
|
|
19
|
+
*
|
|
20
|
+
* changeName: function() {
|
|
21
|
+
* var oldName = this.get('name'),
|
|
22
|
+
* newName = oldName + " The Barbarian";
|
|
23
|
+
*
|
|
24
|
+
* this.set('name', newName);
|
|
25
|
+
* }
|
|
26
|
+
* });
|
|
27
|
+
*
|
|
28
|
+
* The fields array is turned into a {@link Ext.util.MixedCollection MixedCollection} automatically by the {@link
|
|
29
|
+
* Ext.ModelManager ModelManager}, and all other functions and properties are copied to the new Model's prototype.
|
|
30
|
+
*
|
|
31
|
+
* By default, the built in numeric and boolean field types have a (@link Ext.data.Field#convert} function which coerces string
|
|
32
|
+
* values in raw data into the field's type. For better performance with {@link Ext.data.reader.Json Json} or {@link Ext.data.reader.Array Array}
|
|
33
|
+
* readers *if you are in control of the data fed into this Model*, you can null out the default convert function which will cause
|
|
34
|
+
* the raw property to be copied directly into the Field's value.
|
|
35
|
+
*
|
|
36
|
+
* Now we can create instances of our User model and call any model logic we defined:
|
|
37
|
+
*
|
|
38
|
+
* var user = Ext.create('User', {
|
|
39
|
+
* name : 'Conan',
|
|
40
|
+
* age : 24,
|
|
41
|
+
* phone: '555-555-5555'
|
|
42
|
+
* });
|
|
43
|
+
*
|
|
44
|
+
* user.changeName();
|
|
45
|
+
* user.get('name'); //returns "Conan The Barbarian"
|
|
46
|
+
*
|
|
47
|
+
* # Validations
|
|
48
|
+
*
|
|
49
|
+
* Models have built-in support for validations, which are executed against the validator functions in {@link
|
|
50
|
+
* Ext.data.validations} ({@link Ext.data.validations see all validation functions}). Validations are easy to add to
|
|
51
|
+
* models:
|
|
52
|
+
*
|
|
53
|
+
* Ext.define('User', {
|
|
54
|
+
* extend: 'Ext.data.Model',
|
|
55
|
+
* fields: [
|
|
56
|
+
* {name: 'name', type: 'string'},
|
|
57
|
+
* {name: 'age', type: 'int'},
|
|
58
|
+
* {name: 'phone', type: 'string'},
|
|
59
|
+
* {name: 'gender', type: 'string'},
|
|
60
|
+
* {name: 'username', type: 'string'},
|
|
61
|
+
* {name: 'alive', type: 'boolean', defaultValue: true}
|
|
62
|
+
* ],
|
|
63
|
+
*
|
|
64
|
+
* validations: [
|
|
65
|
+
* {type: 'presence', field: 'age'},
|
|
66
|
+
* {type: 'length', field: 'name', min: 2},
|
|
67
|
+
* {type: 'inclusion', field: 'gender', list: ['Male', 'Female']},
|
|
68
|
+
* {type: 'exclusion', field: 'username', list: ['Admin', 'Operator']},
|
|
69
|
+
* {type: 'format', field: 'username', matcher: /([a-z]+)[0-9]{2,3}/}
|
|
70
|
+
* ]
|
|
71
|
+
* });
|
|
72
|
+
*
|
|
73
|
+
* The validations can be run by simply calling the {@link #validate} function, which returns a {@link Ext.data.Errors}
|
|
74
|
+
* object:
|
|
75
|
+
*
|
|
76
|
+
* var instance = Ext.create('User', {
|
|
77
|
+
* name: 'Ed',
|
|
78
|
+
* gender: 'Male',
|
|
79
|
+
* username: 'edspencer'
|
|
80
|
+
* });
|
|
81
|
+
*
|
|
82
|
+
* var errors = instance.validate();
|
|
83
|
+
*
|
|
84
|
+
* # Associations
|
|
85
|
+
*
|
|
86
|
+
* Models can have associations with other Models via {@link Ext.data.association.HasOne},
|
|
87
|
+
* {@link Ext.data.association.BelongsTo belongsTo} and {@link Ext.data.association.HasMany hasMany} associations.
|
|
88
|
+
* For example, let's say we're writing a blog administration application which deals with Users, Posts and Comments.
|
|
89
|
+
* We can express the relationships between these models like this:
|
|
90
|
+
*
|
|
91
|
+
* Ext.define('Post', {
|
|
92
|
+
* extend: 'Ext.data.Model',
|
|
93
|
+
* fields: ['id', 'user_id'],
|
|
94
|
+
*
|
|
95
|
+
* belongsTo: 'User',
|
|
96
|
+
* hasMany : {model: 'Comment', name: 'comments'}
|
|
97
|
+
* });
|
|
98
|
+
*
|
|
99
|
+
* Ext.define('Comment', {
|
|
100
|
+
* extend: 'Ext.data.Model',
|
|
101
|
+
* fields: ['id', 'user_id', 'post_id'],
|
|
102
|
+
*
|
|
103
|
+
* belongsTo: 'Post'
|
|
104
|
+
* });
|
|
105
|
+
*
|
|
106
|
+
* Ext.define('User', {
|
|
107
|
+
* extend: 'Ext.data.Model',
|
|
108
|
+
* fields: ['id'],
|
|
109
|
+
*
|
|
110
|
+
* hasMany: [
|
|
111
|
+
* 'Post',
|
|
112
|
+
* {model: 'Comment', name: 'comments'}
|
|
113
|
+
* ]
|
|
114
|
+
* });
|
|
115
|
+
*
|
|
116
|
+
* See the docs for {@link Ext.data.association.HasOne}, {@link Ext.data.association.BelongsTo} and
|
|
117
|
+
* {@link Ext.data.association.HasMany} for details on the usage and configuration of associations.
|
|
118
|
+
* Note that associations can also be specified like this:
|
|
119
|
+
*
|
|
120
|
+
* Ext.define('User', {
|
|
121
|
+
* extend: 'Ext.data.Model',
|
|
122
|
+
* fields: ['id'],
|
|
123
|
+
*
|
|
124
|
+
* associations: [
|
|
125
|
+
* {type: 'hasMany', model: 'Post', name: 'posts'},
|
|
126
|
+
* {type: 'hasMany', model: 'Comment', name: 'comments'}
|
|
127
|
+
* ]
|
|
128
|
+
* });
|
|
129
|
+
*
|
|
130
|
+
* # Using a Proxy
|
|
131
|
+
*
|
|
132
|
+
* Models are great for representing types of data and relationships, but sooner or later we're going to want to load or
|
|
133
|
+
* save that data somewhere. All loading and saving of data is handled via a {@link Ext.data.proxy.Proxy Proxy}, which
|
|
134
|
+
* can be set directly on the Model:
|
|
135
|
+
*
|
|
136
|
+
* Ext.define('User', {
|
|
137
|
+
* extend: 'Ext.data.Model',
|
|
138
|
+
* fields: ['id', 'name', 'email'],
|
|
139
|
+
*
|
|
140
|
+
* proxy: {
|
|
141
|
+
* type: 'rest',
|
|
142
|
+
* url : '/users'
|
|
143
|
+
* }
|
|
144
|
+
* });
|
|
145
|
+
*
|
|
146
|
+
* Here we've set up a {@link Ext.data.proxy.Rest Rest Proxy}, which knows how to load and save data to and from a
|
|
147
|
+
* RESTful backend. Let's see how this works:
|
|
148
|
+
*
|
|
149
|
+
* var user = Ext.create('User', {name: 'Ed Spencer', email: 'ed@sencha.com'});
|
|
150
|
+
*
|
|
151
|
+
* user.save(); //POST /users
|
|
152
|
+
*
|
|
153
|
+
* Calling {@link #save} on the new Model instance tells the configured RestProxy that we wish to persist this Model's
|
|
154
|
+
* data onto our server. RestProxy figures out that this Model hasn't been saved before because it doesn't have an id,
|
|
155
|
+
* and performs the appropriate action - in this case issuing a POST request to the url we configured (/users). We
|
|
156
|
+
* configure any Proxy on any Model and always follow this API - see {@link Ext.data.proxy.Proxy} for a full list.
|
|
157
|
+
*
|
|
158
|
+
* Loading data via the Proxy is equally easy:
|
|
159
|
+
*
|
|
160
|
+
* //get a reference to the User model class
|
|
161
|
+
* var User = Ext.ModelManager.getModel('User');
|
|
162
|
+
*
|
|
163
|
+
* //Uses the configured RestProxy to make a GET request to /users/123
|
|
164
|
+
* User.load(123, {
|
|
165
|
+
* success: function(user) {
|
|
166
|
+
* console.log(user.getId()); //logs 123
|
|
167
|
+
* }
|
|
168
|
+
* });
|
|
169
|
+
*
|
|
170
|
+
* Models can also be updated and destroyed easily:
|
|
171
|
+
*
|
|
172
|
+
* //the user Model we loaded in the last snippet:
|
|
173
|
+
* user.set('name', 'Edward Spencer');
|
|
174
|
+
*
|
|
175
|
+
* //tells the Proxy to save the Model. In this case it will perform a PUT request to /users/123 as this Model already has an id
|
|
176
|
+
* user.save({
|
|
177
|
+
* success: function() {
|
|
178
|
+
* console.log('The User was updated');
|
|
179
|
+
* }
|
|
180
|
+
* });
|
|
181
|
+
*
|
|
182
|
+
* //tells the Proxy to destroy the Model. Performs a DELETE request to /users/123
|
|
183
|
+
* user.destroy({
|
|
184
|
+
* success: function() {
|
|
185
|
+
* console.log('The User was destroyed!');
|
|
186
|
+
* }
|
|
187
|
+
* });
|
|
188
|
+
*
|
|
189
|
+
* # Usage in Stores
|
|
190
|
+
*
|
|
191
|
+
* It is very common to want to load a set of Model instances to be displayed and manipulated in the UI. We do this by
|
|
192
|
+
* creating a {@link Ext.data.Store Store}:
|
|
193
|
+
*
|
|
194
|
+
* var store = Ext.create('Ext.data.Store', {
|
|
195
|
+
* model: 'User'
|
|
196
|
+
* });
|
|
197
|
+
*
|
|
198
|
+
* //uses the Proxy we set up on Model to load the Store data
|
|
199
|
+
* store.load();
|
|
200
|
+
*
|
|
201
|
+
* A Store is just a collection of Model instances - usually loaded from a server somewhere. Store can also maintain a
|
|
202
|
+
* set of added, updated and removed Model instances to be synchronized with the server via the Proxy. See the {@link
|
|
203
|
+
* Ext.data.Store Store docs} for more information on Stores.
|
|
204
|
+
*
|
|
205
|
+
* @constructor
|
|
206
|
+
* Creates new Model instance.
|
|
207
|
+
* @param {Object} data An object containing keys corresponding to this model's fields, and their associated values
|
|
208
|
+
*/
|
|
209
|
+
|
|
210
|
+
Ext.define('Ext.data.Model', {
|
|
211
|
+
alternateClassName: 'Ext.data.Record',
|
|
212
|
+
|
|
213
|
+
mixins: {
|
|
214
|
+
observable: 'Ext.util.Observable'
|
|
215
|
+
},
|
|
216
|
+
|
|
217
|
+
requires: [
|
|
218
|
+
'Ext.ModelManager',
|
|
219
|
+
'Ext.data.IdGenerator',
|
|
220
|
+
'Ext.data.Field',
|
|
221
|
+
'Ext.data.Errors',
|
|
222
|
+
'Ext.data.Operation',
|
|
223
|
+
'Ext.data.validations',
|
|
224
|
+
'Ext.util.MixedCollection'
|
|
225
|
+
],
|
|
226
|
+
|
|
227
|
+
compareConvertFields: function(f1, f2) {
|
|
228
|
+
var f1SpecialConvert = f1.convert && f1.type && f1.convert !== f1.type.convert,
|
|
229
|
+
f2SpecialConvert = f2.convert && f2.type && f2.convert !== f2.type.convert;
|
|
230
|
+
|
|
231
|
+
if (f1SpecialConvert && !f2SpecialConvert) {
|
|
232
|
+
return 1;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
if (!f1SpecialConvert && f2SpecialConvert) {
|
|
236
|
+
return -1;
|
|
237
|
+
}
|
|
238
|
+
return 0;
|
|
239
|
+
},
|
|
240
|
+
|
|
241
|
+
itemNameFn: function(item) {
|
|
242
|
+
return item.name;
|
|
243
|
+
},
|
|
244
|
+
|
|
245
|
+
onClassExtended: function(cls, data, hooks) {
|
|
246
|
+
var onBeforeClassCreated = hooks.onBeforeCreated;
|
|
247
|
+
|
|
248
|
+
hooks.onBeforeCreated = function(cls, data) {
|
|
249
|
+
var me = this,
|
|
250
|
+
name = Ext.getClassName(cls),
|
|
251
|
+
prototype = cls.prototype,
|
|
252
|
+
superCls = cls.prototype.superclass,
|
|
253
|
+
|
|
254
|
+
validations = data.validations || [],
|
|
255
|
+
fields = data.fields || [],
|
|
256
|
+
associations = data.associations || [],
|
|
257
|
+
addAssociations = function(items, type) {
|
|
258
|
+
var i = 0,
|
|
259
|
+
len,
|
|
260
|
+
item;
|
|
261
|
+
|
|
262
|
+
if (items) {
|
|
263
|
+
items = Ext.Array.from(items);
|
|
264
|
+
|
|
265
|
+
for (len = items.length; i < len; ++i) {
|
|
266
|
+
item = items[i];
|
|
267
|
+
|
|
268
|
+
if (!Ext.isObject(item)) {
|
|
269
|
+
item = {model: item};
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
item.type = type;
|
|
273
|
+
associations.push(item);
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
},
|
|
277
|
+
idgen = data.idgen,
|
|
278
|
+
|
|
279
|
+
fieldsMixedCollection = new Ext.util.MixedCollection(false, prototype.itemNameFn),
|
|
280
|
+
|
|
281
|
+
associationsMixedCollection = new Ext.util.MixedCollection(false, prototype.itemNameFn),
|
|
282
|
+
|
|
283
|
+
superValidations = superCls.validations,
|
|
284
|
+
superFields = superCls.fields,
|
|
285
|
+
superAssociations = superCls.associations,
|
|
286
|
+
|
|
287
|
+
association, i, ln,
|
|
288
|
+
dependencies = [],
|
|
289
|
+
idProperty = data.idProperty || cls.prototype.idProperty,
|
|
290
|
+
|
|
291
|
+
// Process each Field upon add into the collection
|
|
292
|
+
onFieldAddReplace = function(arg0, arg1, arg2) {
|
|
293
|
+
var newField,
|
|
294
|
+
pos;
|
|
295
|
+
|
|
296
|
+
if (fieldsMixedCollection.events.add.firing) {
|
|
297
|
+
// Add event signature is (position, value, key);
|
|
298
|
+
pos = arg0;
|
|
299
|
+
newField = arg1;
|
|
300
|
+
} else {
|
|
301
|
+
// Replace event signature is (key, oldValue, newValue);
|
|
302
|
+
newField = arg2;
|
|
303
|
+
pos = arg1.originalIndex;
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
// Set the originalIndex for ArrayReader to get the default mapping from in case
|
|
307
|
+
// compareConvertFields changes the order due to some fields having custom convert functions.
|
|
308
|
+
newField.originalIndex = pos;
|
|
309
|
+
|
|
310
|
+
// The field(s) which encapsulates the idProperty must never have a default value set
|
|
311
|
+
// if no value arrives from the server side. So override any possible prototype-provided
|
|
312
|
+
// defaultValue with undefined which will inhibit generation of defaulting code in Reader.buildRecordDataExtractor
|
|
313
|
+
if (newField.mapping === idProperty || (newField.mapping == null && newField.name === idProperty)) {
|
|
314
|
+
newField.defaultValue = undefined;
|
|
315
|
+
}
|
|
316
|
+
},
|
|
317
|
+
|
|
318
|
+
// Use the proxy from the class definition object if present, otherwise fall back to the inherited one, or the default
|
|
319
|
+
clsProxy = data.proxy || cls.prototype.proxy || cls.prototype.defaultProxyType,
|
|
320
|
+
|
|
321
|
+
// Sort upon add function to be used in case of dynamically added Fields
|
|
322
|
+
fieldConvertSortFn = function() {
|
|
323
|
+
fieldsMixedCollection.sortBy(prototype.compareConvertFields);
|
|
324
|
+
};
|
|
325
|
+
|
|
326
|
+
// Save modelName on class and its prototype
|
|
327
|
+
cls.modelName = name;
|
|
328
|
+
prototype.modelName = name;
|
|
329
|
+
|
|
330
|
+
// Merge the validations of the superclass and the new subclass
|
|
331
|
+
if (superValidations) {
|
|
332
|
+
validations = superValidations.concat(validations);
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
data.validations = validations;
|
|
336
|
+
|
|
337
|
+
// Merge the fields of the superclass and the new subclass
|
|
338
|
+
if (superFields) {
|
|
339
|
+
fields = superFields.items.concat(fields);
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
fieldsMixedCollection.on({
|
|
343
|
+
add: onFieldAddReplace,
|
|
344
|
+
replace: onFieldAddReplace
|
|
345
|
+
});
|
|
346
|
+
|
|
347
|
+
for (i = 0, ln = fields.length; i < ln; ++i) {
|
|
348
|
+
fieldsMixedCollection.add(new Ext.data.Field(fields[i]));
|
|
349
|
+
}
|
|
350
|
+
if (!fieldsMixedCollection.get(idProperty)) {
|
|
351
|
+
fieldsMixedCollection.add(new Ext.data.Field(idProperty));
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
// Ensure the Fields are on correct order: Fields with custom convert function last
|
|
355
|
+
fieldConvertSortFn();
|
|
356
|
+
fieldsMixedCollection.on({
|
|
357
|
+
add: fieldConvertSortFn,
|
|
358
|
+
replace: fieldConvertSortFn
|
|
359
|
+
});
|
|
360
|
+
|
|
361
|
+
data.fields = fieldsMixedCollection;
|
|
362
|
+
|
|
363
|
+
if (idgen) {
|
|
364
|
+
data.idgen = Ext.data.IdGenerator.get(idgen);
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
//associations can be specified in the more convenient format (e.g. not inside an 'associations' array).
|
|
368
|
+
//we support that here
|
|
369
|
+
addAssociations(data.belongsTo, 'belongsTo');
|
|
370
|
+
delete data.belongsTo;
|
|
371
|
+
addAssociations(data.hasMany, 'hasMany');
|
|
372
|
+
delete data.hasMany;
|
|
373
|
+
addAssociations(data.hasOne, 'hasOne');
|
|
374
|
+
delete data.hasOne;
|
|
375
|
+
|
|
376
|
+
if (superAssociations) {
|
|
377
|
+
associations = superAssociations.items.concat(associations);
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
for (i = 0, ln = associations.length; i < ln; ++i) {
|
|
381
|
+
dependencies.push('association.' + associations[i].type.toLowerCase());
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
// If we have not been supplied with a Proxy *instance*, then add the proxy type to our dependency list
|
|
385
|
+
if (clsProxy && !clsProxy.isProxy) {
|
|
386
|
+
dependencies.push('proxy.' + (typeof clsProxy === 'string' ? clsProxy : clsProxy.type));
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
Ext.require(dependencies, function() {
|
|
390
|
+
Ext.ModelManager.registerType(name, cls);
|
|
391
|
+
|
|
392
|
+
for (i = 0, ln = associations.length; i < ln; ++i) {
|
|
393
|
+
association = associations[i];
|
|
394
|
+
|
|
395
|
+
Ext.apply(association, {
|
|
396
|
+
ownerModel: name,
|
|
397
|
+
associatedModel: association.model
|
|
398
|
+
});
|
|
399
|
+
|
|
400
|
+
if (Ext.ModelManager.getModel(association.model) === undefined) {
|
|
401
|
+
Ext.ModelManager.registerDeferredAssociation(association);
|
|
402
|
+
} else {
|
|
403
|
+
associationsMixedCollection.add(Ext.data.association.Association.create(association));
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
data.associations = associationsMixedCollection;
|
|
408
|
+
|
|
409
|
+
// onBeforeCreated may get called *asynchronously* if any of those required classes caused
|
|
410
|
+
// an asynchronous script load. This would mean that the class definition object
|
|
411
|
+
// has not been applied to the prototype when the Model definition has returned.
|
|
412
|
+
// The Reader constructor does not attempt to buildExtractors if the fields MixedCollection
|
|
413
|
+
// has not yet been set. The cls.setProxy call triggers a build of extractor methods.
|
|
414
|
+
onBeforeClassCreated.call(me, cls, data, hooks);
|
|
415
|
+
|
|
416
|
+
cls.setProxy(clsProxy);
|
|
417
|
+
|
|
418
|
+
// Fire the onModelDefined template method on ModelManager
|
|
419
|
+
Ext.ModelManager.onModelDefined(cls);
|
|
420
|
+
});
|
|
421
|
+
};
|
|
422
|
+
},
|
|
423
|
+
|
|
424
|
+
inheritableStatics: {
|
|
425
|
+
/**
|
|
426
|
+
* Sets the Proxy to use for this model. Accepts any options that can be accepted by
|
|
427
|
+
* {@link Ext#createByAlias Ext.createByAlias}.
|
|
428
|
+
* @param {String/Object/Ext.data.proxy.Proxy} proxy The proxy
|
|
429
|
+
* @return {Ext.data.proxy.Proxy}
|
|
430
|
+
* @static
|
|
431
|
+
* @inheritable
|
|
432
|
+
*/
|
|
433
|
+
setProxy: function(proxy) {
|
|
434
|
+
//make sure we have an Ext.data.proxy.Proxy object
|
|
435
|
+
if (!proxy.isProxy) {
|
|
436
|
+
if (typeof proxy == "string") {
|
|
437
|
+
proxy = {
|
|
438
|
+
type: proxy
|
|
439
|
+
};
|
|
440
|
+
}
|
|
441
|
+
proxy = Ext.createByAlias("proxy." + proxy.type, proxy);
|
|
442
|
+
}
|
|
443
|
+
proxy.setModel(this);
|
|
444
|
+
this.proxy = this.prototype.proxy = proxy;
|
|
445
|
+
|
|
446
|
+
return proxy;
|
|
447
|
+
},
|
|
448
|
+
|
|
449
|
+
/**
|
|
450
|
+
* Returns the configured Proxy for this Model
|
|
451
|
+
* @return {Ext.data.proxy.Proxy} The proxy
|
|
452
|
+
* @static
|
|
453
|
+
* @inheritable
|
|
454
|
+
*/
|
|
455
|
+
getProxy: function() {
|
|
456
|
+
return this.proxy;
|
|
457
|
+
},
|
|
458
|
+
|
|
459
|
+
/**
|
|
460
|
+
* Apply a new set of field and/or property definitions to the existing model. This will replace any existing
|
|
461
|
+
* fields, including fields inherited from superclasses. Mainly for reconfiguring the
|
|
462
|
+
* model based on changes in meta data (called from Reader's onMetaChange method).
|
|
463
|
+
* @static
|
|
464
|
+
* @inheritable
|
|
465
|
+
*/
|
|
466
|
+
setFields: function(fields, idProperty, clientIdProperty) {
|
|
467
|
+
var me = this,
|
|
468
|
+
proto = me.prototype,
|
|
469
|
+
prototypeFields = proto.fields,
|
|
470
|
+
len = fields ? fields.length : 0,
|
|
471
|
+
i = 0;
|
|
472
|
+
|
|
473
|
+
|
|
474
|
+
if (idProperty) {
|
|
475
|
+
proto.idProperty = idProperty;
|
|
476
|
+
}
|
|
477
|
+
if (clientIdProperty) {
|
|
478
|
+
proto.clientIdProperty = clientIdProperty;
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
if (prototypeFields) {
|
|
482
|
+
prototypeFields.clear();
|
|
483
|
+
}
|
|
484
|
+
else {
|
|
485
|
+
prototypeFields = me.prototype.fields = new Ext.util.MixedCollection(false, function(field) {
|
|
486
|
+
return field.name;
|
|
487
|
+
});
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
for (; i < len; i++) {
|
|
491
|
+
prototypeFields.add(new Ext.data.Field(fields[i]));
|
|
492
|
+
}
|
|
493
|
+
if (!prototypeFields.get(proto.idProperty)) {
|
|
494
|
+
prototypeFields.add(new Ext.data.Field(proto.idProperty));
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
me.fields = prototypeFields;
|
|
498
|
+
|
|
499
|
+
return prototypeFields;
|
|
500
|
+
},
|
|
501
|
+
|
|
502
|
+
/**
|
|
503
|
+
* Returns an Array of {@link Ext.data.Field Field} definitions which define this Model's structure
|
|
504
|
+
*
|
|
505
|
+
* Fields are sorted upon Model class definition. Fields with custom {@link Ext.data.Field#convert convert} functions
|
|
506
|
+
* are moved to *after* fields with no convert functions. This is so that convert functions which rely on existing
|
|
507
|
+
* field values will be able to read those field values.
|
|
508
|
+
*
|
|
509
|
+
* @return {Ext.data.Field[]} The defined Fields for this Model.
|
|
510
|
+
*
|
|
511
|
+
*/
|
|
512
|
+
getFields: function() {
|
|
513
|
+
return this.prototype.fields.items;
|
|
514
|
+
},
|
|
515
|
+
|
|
516
|
+
/**
|
|
517
|
+
* Asynchronously loads a model instance by id. Sample usage:
|
|
518
|
+
*
|
|
519
|
+
* Ext.define('MyApp.User', {
|
|
520
|
+
* extend: 'Ext.data.Model',
|
|
521
|
+
* fields: [
|
|
522
|
+
* {name: 'id', type: 'int'},
|
|
523
|
+
* {name: 'name', type: 'string'}
|
|
524
|
+
* ]
|
|
525
|
+
* });
|
|
526
|
+
*
|
|
527
|
+
* MyApp.User.load(10, {
|
|
528
|
+
* scope: this,
|
|
529
|
+
* failure: function(record, operation) {
|
|
530
|
+
* //do something if the load failed
|
|
531
|
+
* },
|
|
532
|
+
* success: function(record, operation) {
|
|
533
|
+
* //do something if the load succeeded
|
|
534
|
+
* },
|
|
535
|
+
* callback: function(record, operation) {
|
|
536
|
+
* //do something whether the load succeeded or failed
|
|
537
|
+
* }
|
|
538
|
+
* });
|
|
539
|
+
*
|
|
540
|
+
* @param {Number/String} id The id of the model to load
|
|
541
|
+
* @param {Object} config (optional) config object containing success, failure and callback functions, plus
|
|
542
|
+
* optional scope
|
|
543
|
+
* @static
|
|
544
|
+
* @inheritable
|
|
545
|
+
*/
|
|
546
|
+
load: function(id, config) {
|
|
547
|
+
config = Ext.apply({}, config);
|
|
548
|
+
config = Ext.applyIf(config, {
|
|
549
|
+
action: 'read',
|
|
550
|
+
id : id
|
|
551
|
+
});
|
|
552
|
+
|
|
553
|
+
var operation = new Ext.data.Operation(config),
|
|
554
|
+
scope = config.scope || this,
|
|
555
|
+
record = null,
|
|
556
|
+
callback;
|
|
557
|
+
|
|
558
|
+
callback = function(operation) {
|
|
559
|
+
if (operation.wasSuccessful()) {
|
|
560
|
+
record = operation.getRecords()[0];
|
|
561
|
+
Ext.callback(config.success, scope, [record, operation]);
|
|
562
|
+
} else {
|
|
563
|
+
Ext.callback(config.failure, scope, [record, operation]);
|
|
564
|
+
}
|
|
565
|
+
Ext.callback(config.callback, scope, [record, operation]);
|
|
566
|
+
};
|
|
567
|
+
|
|
568
|
+
this.proxy.read(operation, callback, this);
|
|
569
|
+
}
|
|
570
|
+
},
|
|
571
|
+
|
|
572
|
+
statics: {
|
|
573
|
+
PREFIX : 'ext-record',
|
|
574
|
+
AUTO_ID: 1,
|
|
575
|
+
EDIT : 'edit',
|
|
576
|
+
REJECT : 'reject',
|
|
577
|
+
COMMIT : 'commit',
|
|
578
|
+
|
|
579
|
+
/**
|
|
580
|
+
* Generates a sequential id. This method is typically called when a record is {@link Ext#create
|
|
581
|
+
* create}d and {@link #constructor no id has been specified}. The id will automatically be assigned to the
|
|
582
|
+
* record. The returned id takes the form: {PREFIX}-{AUTO_ID}.
|
|
583
|
+
*
|
|
584
|
+
* - **PREFIX** : String - Ext.data.Model.PREFIX (defaults to 'ext-record')
|
|
585
|
+
* - **AUTO_ID** : String - Ext.data.Model.AUTO_ID (defaults to 1 initially)
|
|
586
|
+
*
|
|
587
|
+
* @param {Ext.data.Model} rec The record being created. The record does not exist, it's a {@link #phantom}.
|
|
588
|
+
* @return {String} auto-generated string id, `"ext-record-i++"`;
|
|
589
|
+
* @static
|
|
590
|
+
*/
|
|
591
|
+
id: function(rec) {
|
|
592
|
+
var id = [this.PREFIX, '-', this.AUTO_ID++].join('');
|
|
593
|
+
rec.phantom = true;
|
|
594
|
+
rec.internalId = id;
|
|
595
|
+
return id;
|
|
596
|
+
}
|
|
597
|
+
},
|
|
598
|
+
|
|
599
|
+
/**
|
|
600
|
+
* @cfg {String/Object} idgen
|
|
601
|
+
* The id generator to use for this model. The default id generator does not generate
|
|
602
|
+
* values for the {@link #idProperty}.
|
|
603
|
+
*
|
|
604
|
+
* This can be overridden at the model level to provide a custom generator for a model.
|
|
605
|
+
* The simplest form of this would be:
|
|
606
|
+
*
|
|
607
|
+
* Ext.define('MyApp.data.MyModel', {
|
|
608
|
+
* extend: 'Ext.data.Model',
|
|
609
|
+
* requires: ['Ext.data.SequentialIdGenerator'],
|
|
610
|
+
* idgen: 'sequential',
|
|
611
|
+
* ...
|
|
612
|
+
* });
|
|
613
|
+
*
|
|
614
|
+
* The above would generate {@link Ext.data.SequentialIdGenerator sequential} id's such
|
|
615
|
+
* as 1, 2, 3 etc..
|
|
616
|
+
*
|
|
617
|
+
* Another useful id generator is {@link Ext.data.UuidGenerator}:
|
|
618
|
+
*
|
|
619
|
+
* Ext.define('MyApp.data.MyModel', {
|
|
620
|
+
* extend: 'Ext.data.Model',
|
|
621
|
+
* requires: ['Ext.data.UuidGenerator'],
|
|
622
|
+
* idgen: 'uuid',
|
|
623
|
+
* ...
|
|
624
|
+
* });
|
|
625
|
+
*
|
|
626
|
+
* An id generation can also be further configured:
|
|
627
|
+
*
|
|
628
|
+
* Ext.define('MyApp.data.MyModel', {
|
|
629
|
+
* extend: 'Ext.data.Model',
|
|
630
|
+
* idgen: {
|
|
631
|
+
* type: 'sequential',
|
|
632
|
+
* seed: 1000,
|
|
633
|
+
* prefix: 'ID_'
|
|
634
|
+
* }
|
|
635
|
+
* });
|
|
636
|
+
*
|
|
637
|
+
* The above would generate id's such as ID_1000, ID_1001, ID_1002 etc..
|
|
638
|
+
*
|
|
639
|
+
* If multiple models share an id space, a single generator can be shared:
|
|
640
|
+
*
|
|
641
|
+
* Ext.define('MyApp.data.MyModelX', {
|
|
642
|
+
* extend: 'Ext.data.Model',
|
|
643
|
+
* idgen: {
|
|
644
|
+
* type: 'sequential',
|
|
645
|
+
* id: 'xy'
|
|
646
|
+
* }
|
|
647
|
+
* });
|
|
648
|
+
*
|
|
649
|
+
* Ext.define('MyApp.data.MyModelY', {
|
|
650
|
+
* extend: 'Ext.data.Model',
|
|
651
|
+
* idgen: {
|
|
652
|
+
* type: 'sequential',
|
|
653
|
+
* id: 'xy'
|
|
654
|
+
* }
|
|
655
|
+
* });
|
|
656
|
+
*
|
|
657
|
+
* For more complex, shared id generators, a custom generator is the best approach.
|
|
658
|
+
* See {@link Ext.data.IdGenerator} for details on creating custom id generators.
|
|
659
|
+
*
|
|
660
|
+
* @markdown
|
|
661
|
+
*/
|
|
662
|
+
idgen: {
|
|
663
|
+
isGenerator: true,
|
|
664
|
+
type: 'default',
|
|
665
|
+
|
|
666
|
+
generate: function () {
|
|
667
|
+
return null;
|
|
668
|
+
},
|
|
669
|
+
getRecId: function (rec) {
|
|
670
|
+
return rec.modelName + '-' + rec.internalId;
|
|
671
|
+
}
|
|
672
|
+
},
|
|
673
|
+
|
|
674
|
+
/**
|
|
675
|
+
* @property {Boolean} editing
|
|
676
|
+
* Internal flag used to track whether or not the model instance is currently being edited.
|
|
677
|
+
* @readonly
|
|
678
|
+
*/
|
|
679
|
+
editing : false,
|
|
680
|
+
|
|
681
|
+
/**
|
|
682
|
+
* @property {Boolean} dirty
|
|
683
|
+
* True if this Record has been modified.
|
|
684
|
+
* @readonly
|
|
685
|
+
*/
|
|
686
|
+
dirty : false,
|
|
687
|
+
|
|
688
|
+
/**
|
|
689
|
+
* @cfg {String} persistenceProperty
|
|
690
|
+
* The name of the property on this Persistable object that its data is saved to. Defaults to 'data'
|
|
691
|
+
* (i.e: all persistable data resides in `this.data`.)
|
|
692
|
+
*/
|
|
693
|
+
persistenceProperty: 'data',
|
|
694
|
+
|
|
695
|
+
evented: false,
|
|
696
|
+
|
|
697
|
+
/**
|
|
698
|
+
* @property {Boolean} isModel
|
|
699
|
+
* `true` in this class to identify an object as an instantiated Model, or subclass thereof.
|
|
700
|
+
*/
|
|
701
|
+
isModel: true,
|
|
702
|
+
|
|
703
|
+
/**
|
|
704
|
+
* @property {Boolean} phantom
|
|
705
|
+
* True when the record does not yet exist in a server-side database (see {@link #setDirty}).
|
|
706
|
+
* Any record which has a real database pk set as its id property is NOT a phantom -- it's real.
|
|
707
|
+
*/
|
|
708
|
+
phantom : false,
|
|
709
|
+
|
|
710
|
+
/**
|
|
711
|
+
* @cfg {String} idProperty
|
|
712
|
+
* The name of the field treated as this Model's unique id. Defaults to 'id'.
|
|
713
|
+
*/
|
|
714
|
+
idProperty: 'id',
|
|
715
|
+
|
|
716
|
+
/**
|
|
717
|
+
* @cfg {String} [clientIdProperty]
|
|
718
|
+
* The name of a property that is used for submitting this Model's unique client-side identifier
|
|
719
|
+
* to the server when multiple phantom records are saved as part of the same {@link Ext.data.Operation Operation}.
|
|
720
|
+
* In such a case, the server response should include the client id for each record
|
|
721
|
+
* so that the server response data can be used to update the client-side records if necessary.
|
|
722
|
+
* This property cannot have the same name as any of this Model's fields.
|
|
723
|
+
*/
|
|
724
|
+
clientIdProperty: null,
|
|
725
|
+
|
|
726
|
+
/**
|
|
727
|
+
* @cfg {String} defaultProxyType
|
|
728
|
+
* The string type of the default Model Proxy. Defaults to 'ajax'.
|
|
729
|
+
*/
|
|
730
|
+
defaultProxyType: 'ajax',
|
|
731
|
+
|
|
732
|
+
// Fields config and property
|
|
733
|
+
/**
|
|
734
|
+
* @cfg {Object[]/String[]} fields
|
|
735
|
+
* The fields for this model. This is an Array of **{@link Ext.data.Field Field}** definition objects. A Field
|
|
736
|
+
* definition may simply be the *name* of the Field, but a Field encapsulates {@link Ext.data.Field#type data type},
|
|
737
|
+
* {@link Ext.data.Field#convert custom conversion} of raw data, and a {@link Ext.data.Field#mapping mapping}
|
|
738
|
+
* property to specify by name of index, how to extract a field's value from a raw data object, so it is best practice
|
|
739
|
+
* to specify a full set of {@link Ext.data.Field Field} config objects.
|
|
740
|
+
*/
|
|
741
|
+
/**
|
|
742
|
+
* @property {Ext.util.MixedCollection} fields
|
|
743
|
+
* A {@link Ext.util.MixedCollection Collection} of the fields defined for this Model (including fields defined in superclasses)
|
|
744
|
+
*
|
|
745
|
+
* This is a collection of {@link Ext.data.Field} instances, each of which encapsulates information that the field was configured with.
|
|
746
|
+
* By default, you can specify a field as simply a String, representing the *name* of the field, but a Field encapsulates
|
|
747
|
+
* {@link Ext.data.Field#type data type}, {@link Ext.data.Field#convert custom conversion} of raw data, and a {@link Ext.data.Field#mapping mapping}
|
|
748
|
+
* property to specify by name of index, how to extract a field's value from a raw data object.
|
|
749
|
+
*/
|
|
750
|
+
|
|
751
|
+
/**
|
|
752
|
+
* @cfg {Object[]} validations
|
|
753
|
+
* An array of {@link Ext.data.validations validations} for this model.
|
|
754
|
+
*/
|
|
755
|
+
|
|
756
|
+
// Associations configs and properties
|
|
757
|
+
/**
|
|
758
|
+
* @cfg {Object[]} associations
|
|
759
|
+
* An array of {@link Ext.data.Association associations} for this model.
|
|
760
|
+
*/
|
|
761
|
+
/**
|
|
762
|
+
* @cfg {String/Object/String[]/Object[]} hasMany
|
|
763
|
+
* One or more {@link Ext.data.HasManyAssociation HasMany associations} for this model.
|
|
764
|
+
*/
|
|
765
|
+
/**
|
|
766
|
+
* @cfg {String/Object/String[]/Object[]} belongsTo
|
|
767
|
+
* One or more {@link Ext.data.BelongsToAssociation BelongsTo associations} for this model.
|
|
768
|
+
*/
|
|
769
|
+
/**
|
|
770
|
+
* @cfg {String/Object/Ext.data.proxy.Proxy} proxy
|
|
771
|
+
* The {@link Ext.data.proxy.Proxy proxy} to use for this model.
|
|
772
|
+
*/
|
|
773
|
+
|
|
774
|
+
/**
|
|
775
|
+
* @event idchanged
|
|
776
|
+
* Fired when this model's id changes
|
|
777
|
+
* @param {Ext.data.Model} this
|
|
778
|
+
* @param {Number/String} oldId The old id
|
|
779
|
+
* @param {Number/String} newId The new id
|
|
780
|
+
*/
|
|
781
|
+
|
|
782
|
+
// id, raw and convertedData not documented intentionally, meant to be used internally.
|
|
783
|
+
constructor: function(data, id, raw, convertedData) {
|
|
784
|
+
data = data || {};
|
|
785
|
+
|
|
786
|
+
var me = this,
|
|
787
|
+
fields,
|
|
788
|
+
length,
|
|
789
|
+
field,
|
|
790
|
+
name,
|
|
791
|
+
value,
|
|
792
|
+
newId,
|
|
793
|
+
persistenceProperty,
|
|
794
|
+
i;
|
|
795
|
+
|
|
796
|
+
|
|
797
|
+
/**
|
|
798
|
+
* @property {Number/String} internalId
|
|
799
|
+
* An internal unique ID for each Model instance, used to identify Models that don't have an ID yet
|
|
800
|
+
* @private
|
|
801
|
+
*/
|
|
802
|
+
me.internalId = (id || id === 0) ? id : Ext.data.Model.id(me);
|
|
803
|
+
|
|
804
|
+
/**
|
|
805
|
+
* @property {Object} raw The raw data used to create this model if created via a reader.
|
|
806
|
+
*/
|
|
807
|
+
me.raw = raw;
|
|
808
|
+
|
|
809
|
+
if (!me.data) {
|
|
810
|
+
me.data = {};
|
|
811
|
+
}
|
|
812
|
+
|
|
813
|
+
/**
|
|
814
|
+
* @property {Object} modified Key: value pairs of all fields whose values have changed
|
|
815
|
+
*/
|
|
816
|
+
me.modified = {};
|
|
817
|
+
|
|
818
|
+
// Deal with spelling error in previous releases
|
|
819
|
+
if (me.persistanceProperty) {
|
|
820
|
+
//<debug>
|
|
821
|
+
if (Ext.isDefined(Ext.global.console)) {
|
|
822
|
+
Ext.global.console.warn('Ext.data.Model: persistanceProperty has been deprecated. Use persistenceProperty instead.');
|
|
823
|
+
}
|
|
824
|
+
//</debug>
|
|
825
|
+
me.persistenceProperty = me.persistanceProperty;
|
|
826
|
+
}
|
|
827
|
+
|
|
828
|
+
me[me.persistenceProperty] = convertedData || {};
|
|
829
|
+
|
|
830
|
+
me.mixins.observable.constructor.call(me);
|
|
831
|
+
|
|
832
|
+
if (!convertedData) {
|
|
833
|
+
//add default field values if present
|
|
834
|
+
fields = me.fields.items;
|
|
835
|
+
length = fields.length;
|
|
836
|
+
i = 0;
|
|
837
|
+
persistenceProperty = me[me.persistenceProperty];
|
|
838
|
+
|
|
839
|
+
if (Ext.isArray(data)) {
|
|
840
|
+
for (; i < length; i++) {
|
|
841
|
+
field = fields[i];
|
|
842
|
+
name = field.name;
|
|
843
|
+
value = data[i];
|
|
844
|
+
|
|
845
|
+
if (value === undefined) {
|
|
846
|
+
value = field.defaultValue;
|
|
847
|
+
}
|
|
848
|
+
// Have to map array data so the values get assigned to the named fields
|
|
849
|
+
// rather than getting set as the field names with undefined values.
|
|
850
|
+
if (field.convert) {
|
|
851
|
+
value = field.convert(value, me);
|
|
852
|
+
}
|
|
853
|
+
// On instance construction, do not create data properties based on undefined input properties
|
|
854
|
+
if (value !== undefined) {
|
|
855
|
+
persistenceProperty[name] = value;
|
|
856
|
+
}
|
|
857
|
+
}
|
|
858
|
+
|
|
859
|
+
} else {
|
|
860
|
+
for (; i < length; i++) {
|
|
861
|
+
field = fields[i];
|
|
862
|
+
name = field.name;
|
|
863
|
+
value = data[name];
|
|
864
|
+
if (value === undefined) {
|
|
865
|
+
value = field.defaultValue;
|
|
866
|
+
}
|
|
867
|
+
if (field.convert) {
|
|
868
|
+
value = field.convert(value, me);
|
|
869
|
+
}
|
|
870
|
+
// On instance construction, do not create data properties based on undefined input properties
|
|
871
|
+
if (value !== undefined) {
|
|
872
|
+
persistenceProperty[name] = value;
|
|
873
|
+
}
|
|
874
|
+
}
|
|
875
|
+
}
|
|
876
|
+
}
|
|
877
|
+
|
|
878
|
+
/**
|
|
879
|
+
* @property {Ext.data.Store[]} stores
|
|
880
|
+
* The {@link Ext.data.Store Stores} to which this instance is bound.
|
|
881
|
+
*/
|
|
882
|
+
me.stores = [];
|
|
883
|
+
|
|
884
|
+
if (me.getId()) {
|
|
885
|
+
me.phantom = false;
|
|
886
|
+
} else if (me.phantom) {
|
|
887
|
+
newId = me.idgen.generate();
|
|
888
|
+
if (newId !== null) {
|
|
889
|
+
me.setId(newId);
|
|
890
|
+
}
|
|
891
|
+
}
|
|
892
|
+
|
|
893
|
+
// clear any dirty/modified since we're initializing
|
|
894
|
+
me.dirty = false;
|
|
895
|
+
me.modified = {};
|
|
896
|
+
|
|
897
|
+
if (typeof me.init == 'function') {
|
|
898
|
+
me.init();
|
|
899
|
+
}
|
|
900
|
+
|
|
901
|
+
me.id = me.idgen.getRecId(me);
|
|
902
|
+
},
|
|
903
|
+
|
|
904
|
+
/**
|
|
905
|
+
* Returns the value of the given field
|
|
906
|
+
* @param {String} fieldName The field to fetch the value for
|
|
907
|
+
* @return {Object} The value
|
|
908
|
+
*/
|
|
909
|
+
get: function(field) {
|
|
910
|
+
return this[this.persistenceProperty][field];
|
|
911
|
+
},
|
|
912
|
+
|
|
913
|
+
// This object is used whenever the set() method is called and given a string as the
|
|
914
|
+
// first argument. This approach saves memory (and GC costs) since we could be called
|
|
915
|
+
// a lot.
|
|
916
|
+
_singleProp: {},
|
|
917
|
+
|
|
918
|
+
/**
|
|
919
|
+
* Sets the given field to the given value, marks the instance as dirty
|
|
920
|
+
* @param {String/Object} fieldName The field to set, or an object containing key/value pairs
|
|
921
|
+
* @param {Object} newValue The value to set
|
|
922
|
+
* @return {String[]} The array of modified field names or null if nothing was modified.
|
|
923
|
+
*/
|
|
924
|
+
set: function (fieldName, newValue) {
|
|
925
|
+
var me = this,
|
|
926
|
+
data = me[me.persistenceProperty],
|
|
927
|
+
fields = me.fields,
|
|
928
|
+
modified = me.modified,
|
|
929
|
+
single = (typeof fieldName == 'string'),
|
|
930
|
+
currentValue, field, idChanged, key, modifiedFieldNames, name, oldId,
|
|
931
|
+
newId, value, values;
|
|
932
|
+
|
|
933
|
+
if (single) {
|
|
934
|
+
values = me._singleProp;
|
|
935
|
+
values[fieldName] = newValue;
|
|
936
|
+
} else {
|
|
937
|
+
values = fieldName;
|
|
938
|
+
}
|
|
939
|
+
|
|
940
|
+
for (name in values) {
|
|
941
|
+
if (values.hasOwnProperty(name)) {
|
|
942
|
+
value = values[name];
|
|
943
|
+
|
|
944
|
+
if (fields && (field = fields.get(name)) && field.convert) {
|
|
945
|
+
value = field.convert(value, me);
|
|
946
|
+
}
|
|
947
|
+
|
|
948
|
+
currentValue = data[name];
|
|
949
|
+
if (me.isEqual(currentValue, value)) {
|
|
950
|
+
continue; // new value is the same, so no change...
|
|
951
|
+
}
|
|
952
|
+
|
|
953
|
+
data[name] = value;
|
|
954
|
+
(modifiedFieldNames || (modifiedFieldNames = [])).push(name);
|
|
955
|
+
|
|
956
|
+
if (field && field.persist) {
|
|
957
|
+
if (modified.hasOwnProperty(name)) {
|
|
958
|
+
if (me.isEqual(modified[name], value)) {
|
|
959
|
+
// The original value in me.modified equals the new value, so
|
|
960
|
+
// the field is no longer modified:
|
|
961
|
+
delete modified[name];
|
|
962
|
+
|
|
963
|
+
// We might have removed the last modified field, so check to
|
|
964
|
+
// see if there are any modified fields remaining and correct
|
|
965
|
+
// me.dirty:
|
|
966
|
+
me.dirty = false;
|
|
967
|
+
for (key in modified) {
|
|
968
|
+
if (modified.hasOwnProperty(key)){
|
|
969
|
+
me.dirty = true;
|
|
970
|
+
break;
|
|
971
|
+
}
|
|
972
|
+
}
|
|
973
|
+
}
|
|
974
|
+
} else {
|
|
975
|
+
me.dirty = true;
|
|
976
|
+
modified[name] = currentValue;
|
|
977
|
+
}
|
|
978
|
+
}
|
|
979
|
+
|
|
980
|
+
if (name == me.idProperty) {
|
|
981
|
+
idChanged = true;
|
|
982
|
+
oldId = currentValue;
|
|
983
|
+
newId = value;
|
|
984
|
+
}
|
|
985
|
+
}
|
|
986
|
+
}
|
|
987
|
+
|
|
988
|
+
if (single) {
|
|
989
|
+
// cleanup our reused object for next time... important to do this before
|
|
990
|
+
// we fire any events or call anyone else (like afterEdit)!
|
|
991
|
+
delete values[fieldName];
|
|
992
|
+
}
|
|
993
|
+
|
|
994
|
+
if (idChanged) {
|
|
995
|
+
me.fireEvent('idchanged', me, oldId, newId);
|
|
996
|
+
}
|
|
997
|
+
|
|
998
|
+
if (!me.editing && modifiedFieldNames) {
|
|
999
|
+
me.afterEdit(modifiedFieldNames);
|
|
1000
|
+
}
|
|
1001
|
+
|
|
1002
|
+
return modifiedFieldNames || null;
|
|
1003
|
+
},
|
|
1004
|
+
|
|
1005
|
+
/**
|
|
1006
|
+
* @private
|
|
1007
|
+
* Copies data from the passed record into this record. If the passed record is undefined, does nothing.
|
|
1008
|
+
*
|
|
1009
|
+
* If this is a phantom record (represented only in the client, with no corresponding database entry), and
|
|
1010
|
+
* the source record is not a phantom, then this record acquires the id of the source record.
|
|
1011
|
+
*
|
|
1012
|
+
* @param {Ext.data.Model} sourceRecord The record to copy data from.
|
|
1013
|
+
*/
|
|
1014
|
+
copyFrom: function(sourceRecord) {
|
|
1015
|
+
if (sourceRecord) {
|
|
1016
|
+
|
|
1017
|
+
var me = this,
|
|
1018
|
+
fields = me.fields.items,
|
|
1019
|
+
fieldCount = fields.length,
|
|
1020
|
+
field, i = 0,
|
|
1021
|
+
myData = me[me.persistenceProperty],
|
|
1022
|
+
sourceData = sourceRecord[sourceRecord.persistenceProperty],
|
|
1023
|
+
value;
|
|
1024
|
+
|
|
1025
|
+
for (; i < fieldCount; i++) {
|
|
1026
|
+
field = fields[i];
|
|
1027
|
+
|
|
1028
|
+
// Do not use setters.
|
|
1029
|
+
// Copy returned values in directly from the data object.
|
|
1030
|
+
// Converters have already been called because new Records
|
|
1031
|
+
// have been created to copy from.
|
|
1032
|
+
// This is a direct record-to-record value copy operation.
|
|
1033
|
+
value = sourceData[field.name];
|
|
1034
|
+
if (value !== undefined) {
|
|
1035
|
+
myData[field.name] = value;
|
|
1036
|
+
}
|
|
1037
|
+
}
|
|
1038
|
+
|
|
1039
|
+
// If this is a phantom record being updated from a concrete record, copy the ID in.
|
|
1040
|
+
if (me.phantom && !sourceRecord.phantom) {
|
|
1041
|
+
me.setId(sourceRecord.getId());
|
|
1042
|
+
}
|
|
1043
|
+
}
|
|
1044
|
+
},
|
|
1045
|
+
|
|
1046
|
+
/**
|
|
1047
|
+
* Checks if two values are equal, taking into account certain
|
|
1048
|
+
* special factors, for example dates.
|
|
1049
|
+
* @private
|
|
1050
|
+
* @param {Object} a The first value
|
|
1051
|
+
* @param {Object} b The second value
|
|
1052
|
+
* @return {Boolean} True if the values are equal
|
|
1053
|
+
*/
|
|
1054
|
+
isEqual: function(a, b){
|
|
1055
|
+
if (Ext.isDate(a) && Ext.isDate(b)) {
|
|
1056
|
+
return Ext.Date.isEqual(a, b);
|
|
1057
|
+
}
|
|
1058
|
+
return a === b;
|
|
1059
|
+
},
|
|
1060
|
+
|
|
1061
|
+
/**
|
|
1062
|
+
* Begins an edit. While in edit mode, no events (e.g.. the `update` event) are relayed to the containing store.
|
|
1063
|
+
* When an edit has begun, it must be followed by either {@link #endEdit} or {@link #cancelEdit}.
|
|
1064
|
+
*/
|
|
1065
|
+
beginEdit : function(){
|
|
1066
|
+
var me = this;
|
|
1067
|
+
if (!me.editing) {
|
|
1068
|
+
me.editing = true;
|
|
1069
|
+
me.dirtySave = me.dirty;
|
|
1070
|
+
me.dataSave = Ext.apply({}, me[me.persistenceProperty]);
|
|
1071
|
+
me.modifiedSave = Ext.apply({}, me.modified);
|
|
1072
|
+
}
|
|
1073
|
+
},
|
|
1074
|
+
|
|
1075
|
+
/**
|
|
1076
|
+
* Cancels all changes made in the current edit operation.
|
|
1077
|
+
*/
|
|
1078
|
+
cancelEdit : function(){
|
|
1079
|
+
var me = this;
|
|
1080
|
+
if (me.editing) {
|
|
1081
|
+
me.editing = false;
|
|
1082
|
+
// reset the modified state, nothing changed since the edit began
|
|
1083
|
+
me.modified = me.modifiedSave;
|
|
1084
|
+
me[me.persistenceProperty] = me.dataSave;
|
|
1085
|
+
me.dirty = me.dirtySave;
|
|
1086
|
+
delete me.modifiedSave;
|
|
1087
|
+
delete me.dataSave;
|
|
1088
|
+
delete me.dirtySave;
|
|
1089
|
+
}
|
|
1090
|
+
},
|
|
1091
|
+
|
|
1092
|
+
/**
|
|
1093
|
+
* Ends an edit. If any data was modified, the containing store is notified (ie, the store's `update` event will
|
|
1094
|
+
* fire).
|
|
1095
|
+
* @param {Boolean} silent True to not notify the store of the change
|
|
1096
|
+
* @param {String[]} modifiedFieldNames Array of field names changed during edit.
|
|
1097
|
+
*/
|
|
1098
|
+
endEdit : function(silent, modifiedFieldNames){
|
|
1099
|
+
var me = this,
|
|
1100
|
+
changed;
|
|
1101
|
+
if (me.editing) {
|
|
1102
|
+
me.editing = false;
|
|
1103
|
+
if(!modifiedFieldNames) {
|
|
1104
|
+
modifiedFieldNames = me.getModifiedFieldNames();
|
|
1105
|
+
}
|
|
1106
|
+
changed = me.dirty || modifiedFieldNames.length > 0;
|
|
1107
|
+
delete me.modifiedSave;
|
|
1108
|
+
delete me.dataSave;
|
|
1109
|
+
delete me.dirtySave;
|
|
1110
|
+
if (changed && silent !== true) {
|
|
1111
|
+
me.afterEdit(modifiedFieldNames);
|
|
1112
|
+
}
|
|
1113
|
+
}
|
|
1114
|
+
},
|
|
1115
|
+
|
|
1116
|
+
/**
|
|
1117
|
+
* Gets the names of all the fields that were modified during an edit
|
|
1118
|
+
* @private
|
|
1119
|
+
* @return {String[]} An array of modified field names
|
|
1120
|
+
*/
|
|
1121
|
+
getModifiedFieldNames: function(){
|
|
1122
|
+
var me = this,
|
|
1123
|
+
saved = me.dataSave,
|
|
1124
|
+
data = me[me.persistenceProperty],
|
|
1125
|
+
modified = [],
|
|
1126
|
+
key;
|
|
1127
|
+
|
|
1128
|
+
for (key in data) {
|
|
1129
|
+
if (data.hasOwnProperty(key)) {
|
|
1130
|
+
if (!me.isEqual(data[key], saved[key])) {
|
|
1131
|
+
modified.push(key);
|
|
1132
|
+
}
|
|
1133
|
+
}
|
|
1134
|
+
}
|
|
1135
|
+
return modified;
|
|
1136
|
+
},
|
|
1137
|
+
|
|
1138
|
+
/**
|
|
1139
|
+
* Gets a hash of only the fields that have been modified since this Model was created or commited.
|
|
1140
|
+
* @return {Object}
|
|
1141
|
+
*/
|
|
1142
|
+
getChanges : function(){
|
|
1143
|
+
var modified = this.modified,
|
|
1144
|
+
changes = {},
|
|
1145
|
+
field;
|
|
1146
|
+
|
|
1147
|
+
for (field in modified) {
|
|
1148
|
+
if (modified.hasOwnProperty(field)){
|
|
1149
|
+
changes[field] = this.get(field);
|
|
1150
|
+
}
|
|
1151
|
+
}
|
|
1152
|
+
|
|
1153
|
+
return changes;
|
|
1154
|
+
},
|
|
1155
|
+
|
|
1156
|
+
/**
|
|
1157
|
+
* Returns true if the passed field name has been `{@link #modified}` since the load or last commit.
|
|
1158
|
+
* @param {String} fieldName {@link Ext.data.Field#name}
|
|
1159
|
+
* @return {Boolean}
|
|
1160
|
+
*/
|
|
1161
|
+
isModified : function(fieldName) {
|
|
1162
|
+
return this.modified.hasOwnProperty(fieldName);
|
|
1163
|
+
},
|
|
1164
|
+
|
|
1165
|
+
/**
|
|
1166
|
+
* Marks this **Record** as `{@link #dirty}`. This method is used interally when adding `{@link #phantom}` records
|
|
1167
|
+
* to a {@link Ext.data.proxy.Server#writer writer enabled store}.
|
|
1168
|
+
*
|
|
1169
|
+
* Marking a record `{@link #dirty}` causes the phantom to be returned by {@link Ext.data.Store#getUpdatedRecords}
|
|
1170
|
+
* where it will have a create action composed for it during {@link Ext.data.Model#save model save} operations.
|
|
1171
|
+
*/
|
|
1172
|
+
setDirty : function() {
|
|
1173
|
+
var me = this,
|
|
1174
|
+
fields = me.fields.items,
|
|
1175
|
+
fLen = fields.length,
|
|
1176
|
+
field, name, f;
|
|
1177
|
+
|
|
1178
|
+
me.dirty = true;
|
|
1179
|
+
|
|
1180
|
+
for (f = 0; f < fLen; f++) {
|
|
1181
|
+
field = fields[f];
|
|
1182
|
+
|
|
1183
|
+
if (field.persist) {
|
|
1184
|
+
name = field.name;
|
|
1185
|
+
me.modified[name] = me.get(name);
|
|
1186
|
+
}
|
|
1187
|
+
}
|
|
1188
|
+
},
|
|
1189
|
+
|
|
1190
|
+
//<debug>
|
|
1191
|
+
markDirty : function() {
|
|
1192
|
+
if (Ext.isDefined(Ext.global.console)) {
|
|
1193
|
+
Ext.global.console.warn('Ext.data.Model: markDirty has been deprecated. Use setDirty instead.');
|
|
1194
|
+
}
|
|
1195
|
+
return this.setDirty.apply(this, arguments);
|
|
1196
|
+
},
|
|
1197
|
+
//</debug>
|
|
1198
|
+
|
|
1199
|
+
/**
|
|
1200
|
+
* Usually called by the {@link Ext.data.Store} to which this model instance has been {@link #join joined}. Rejects
|
|
1201
|
+
* all changes made to the model instance since either creation, or the last commit operation. Modified fields are
|
|
1202
|
+
* reverted to their original values.
|
|
1203
|
+
*
|
|
1204
|
+
* Developers should subscribe to the {@link Ext.data.Store#update} event to have their code notified of reject
|
|
1205
|
+
* operations.
|
|
1206
|
+
*
|
|
1207
|
+
* @param {Boolean} silent (optional) True to skip notification of the owning store of the change.
|
|
1208
|
+
* Defaults to false.
|
|
1209
|
+
*/
|
|
1210
|
+
reject : function(silent) {
|
|
1211
|
+
var me = this,
|
|
1212
|
+
modified = me.modified,
|
|
1213
|
+
field;
|
|
1214
|
+
|
|
1215
|
+
for (field in modified) {
|
|
1216
|
+
if (modified.hasOwnProperty(field)) {
|
|
1217
|
+
if (typeof modified[field] != "function") {
|
|
1218
|
+
me[me.persistenceProperty][field] = modified[field];
|
|
1219
|
+
}
|
|
1220
|
+
}
|
|
1221
|
+
}
|
|
1222
|
+
|
|
1223
|
+
me.dirty = false;
|
|
1224
|
+
me.editing = false;
|
|
1225
|
+
me.modified = {};
|
|
1226
|
+
|
|
1227
|
+
if (silent !== true) {
|
|
1228
|
+
me.afterReject();
|
|
1229
|
+
}
|
|
1230
|
+
},
|
|
1231
|
+
|
|
1232
|
+
/**
|
|
1233
|
+
* Usually called by the {@link Ext.data.Store} which owns the model instance. Commits all changes made to the
|
|
1234
|
+
* instance since either creation or the last commit operation.
|
|
1235
|
+
*
|
|
1236
|
+
* Developers should subscribe to the {@link Ext.data.Store#update} event to have their code notified of commit
|
|
1237
|
+
* operations.
|
|
1238
|
+
*
|
|
1239
|
+
* @param {Boolean} silent (optional) True to skip notification of the owning store of the change.
|
|
1240
|
+
* Defaults to false.
|
|
1241
|
+
*/
|
|
1242
|
+
commit : function(silent) {
|
|
1243
|
+
var me = this;
|
|
1244
|
+
|
|
1245
|
+
me.phantom = me.dirty = me.editing = false;
|
|
1246
|
+
me.modified = {};
|
|
1247
|
+
|
|
1248
|
+
if (silent !== true) {
|
|
1249
|
+
me.afterCommit();
|
|
1250
|
+
}
|
|
1251
|
+
},
|
|
1252
|
+
|
|
1253
|
+
/**
|
|
1254
|
+
* Creates a copy (clone) of this Model instance.
|
|
1255
|
+
*
|
|
1256
|
+
* @param {String} [id] A new id, defaults to the id of the instance being copied.
|
|
1257
|
+
* See `{@link Ext.data.Model#id id}`. To generate a phantom instance with a new id use:
|
|
1258
|
+
*
|
|
1259
|
+
* var rec = record.copy(); // clone the record
|
|
1260
|
+
* Ext.data.Model.id(rec); // automatically generate a unique sequential id
|
|
1261
|
+
*
|
|
1262
|
+
* @return {Ext.data.Model}
|
|
1263
|
+
*/
|
|
1264
|
+
copy : function(newId) {
|
|
1265
|
+
var me = this;
|
|
1266
|
+
|
|
1267
|
+
return new me.self(Ext.apply({}, me[me.persistenceProperty]), newId);
|
|
1268
|
+
},
|
|
1269
|
+
|
|
1270
|
+
/**
|
|
1271
|
+
* Sets the Proxy to use for this model. Accepts any options that can be accepted by
|
|
1272
|
+
* {@link Ext#createByAlias Ext.createByAlias}.
|
|
1273
|
+
*
|
|
1274
|
+
* @param {String/Object/Ext.data.proxy.Proxy} proxy The proxy
|
|
1275
|
+
* @return {Ext.data.proxy.Proxy}
|
|
1276
|
+
*/
|
|
1277
|
+
setProxy: function(proxy) {
|
|
1278
|
+
//make sure we have an Ext.data.proxy.Proxy object
|
|
1279
|
+
if (!proxy.isProxy) {
|
|
1280
|
+
if (typeof proxy === "string") {
|
|
1281
|
+
proxy = {
|
|
1282
|
+
type: proxy
|
|
1283
|
+
};
|
|
1284
|
+
}
|
|
1285
|
+
proxy = Ext.createByAlias("proxy." + proxy.type, proxy);
|
|
1286
|
+
}
|
|
1287
|
+
proxy.setModel(this.self);
|
|
1288
|
+
this.proxy = proxy;
|
|
1289
|
+
|
|
1290
|
+
return proxy;
|
|
1291
|
+
},
|
|
1292
|
+
|
|
1293
|
+
/**
|
|
1294
|
+
* Returns the configured Proxy for this Model.
|
|
1295
|
+
* @return {Ext.data.proxy.Proxy} The proxy
|
|
1296
|
+
*/
|
|
1297
|
+
getProxy: function() {
|
|
1298
|
+
return this.proxy;
|
|
1299
|
+
},
|
|
1300
|
+
|
|
1301
|
+
/**
|
|
1302
|
+
* Validates the current data against all of its configured {@link #validations}.
|
|
1303
|
+
* @return {Ext.data.Errors} The errors object
|
|
1304
|
+
*/
|
|
1305
|
+
validate: function() {
|
|
1306
|
+
var errors = new Ext.data.Errors(),
|
|
1307
|
+
validations = this.validations,
|
|
1308
|
+
validators = Ext.data.validations,
|
|
1309
|
+
length, validation, field, valid, type, i;
|
|
1310
|
+
|
|
1311
|
+
if (validations) {
|
|
1312
|
+
length = validations.length;
|
|
1313
|
+
|
|
1314
|
+
for (i = 0; i < length; i++) {
|
|
1315
|
+
validation = validations[i];
|
|
1316
|
+
field = validation.field || validation.name;
|
|
1317
|
+
type = validation.type;
|
|
1318
|
+
valid = validators[type](validation, this.get(field));
|
|
1319
|
+
|
|
1320
|
+
if (!valid) {
|
|
1321
|
+
errors.add({
|
|
1322
|
+
field : field,
|
|
1323
|
+
message: validation.message || validators[type + 'Message']
|
|
1324
|
+
});
|
|
1325
|
+
}
|
|
1326
|
+
}
|
|
1327
|
+
}
|
|
1328
|
+
|
|
1329
|
+
return errors;
|
|
1330
|
+
},
|
|
1331
|
+
|
|
1332
|
+
/**
|
|
1333
|
+
* Checks if the model is valid. See {@link #validate}.
|
|
1334
|
+
* @return {Boolean} True if the model is valid.
|
|
1335
|
+
*/
|
|
1336
|
+
isValid: function(){
|
|
1337
|
+
return this.validate().isValid();
|
|
1338
|
+
},
|
|
1339
|
+
|
|
1340
|
+
/**
|
|
1341
|
+
* Saves the model instance using the configured proxy.
|
|
1342
|
+
* @param {Object} options Options to pass to the proxy. Config object for {@link Ext.data.Operation}.
|
|
1343
|
+
* @return {Ext.data.Model} The Model instance
|
|
1344
|
+
*/
|
|
1345
|
+
save: function(options) {
|
|
1346
|
+
options = Ext.apply({}, options);
|
|
1347
|
+
|
|
1348
|
+
var me = this,
|
|
1349
|
+
action = me.phantom ? 'create' : 'update',
|
|
1350
|
+
scope = options.scope || me,
|
|
1351
|
+
stores = me.stores,
|
|
1352
|
+
i = 0,
|
|
1353
|
+
storeCount,
|
|
1354
|
+
store,
|
|
1355
|
+
args,
|
|
1356
|
+
operation,
|
|
1357
|
+
callback;
|
|
1358
|
+
|
|
1359
|
+
Ext.apply(options, {
|
|
1360
|
+
records: [me],
|
|
1361
|
+
action : action
|
|
1362
|
+
});
|
|
1363
|
+
|
|
1364
|
+
operation = new Ext.data.Operation(options);
|
|
1365
|
+
|
|
1366
|
+
callback = function(operation) {
|
|
1367
|
+
args = [me, operation];
|
|
1368
|
+
if (operation.wasSuccessful()) {
|
|
1369
|
+
for(storeCount = stores.length; i < storeCount; i++) {
|
|
1370
|
+
store = stores[i];
|
|
1371
|
+
store.fireEvent('write', store, operation);
|
|
1372
|
+
store.fireEvent('datachanged', store);
|
|
1373
|
+
// Not firing refresh here, since it's a single record
|
|
1374
|
+
}
|
|
1375
|
+
Ext.callback(options.success, scope, args);
|
|
1376
|
+
} else {
|
|
1377
|
+
Ext.callback(options.failure, scope, args);
|
|
1378
|
+
}
|
|
1379
|
+
|
|
1380
|
+
Ext.callback(options.callback, scope, args);
|
|
1381
|
+
};
|
|
1382
|
+
|
|
1383
|
+
me.getProxy()[action](operation, callback, me);
|
|
1384
|
+
|
|
1385
|
+
return me;
|
|
1386
|
+
},
|
|
1387
|
+
|
|
1388
|
+
/**
|
|
1389
|
+
* Destroys the model using the configured proxy.
|
|
1390
|
+
* @param {Object} options Options to pass to the proxy. Config object for {@link Ext.data.Operation}.
|
|
1391
|
+
* @return {Ext.data.Model} The Model instance
|
|
1392
|
+
*/
|
|
1393
|
+
destroy: function(options){
|
|
1394
|
+
options = Ext.apply({}, options);
|
|
1395
|
+
|
|
1396
|
+
var me = this,
|
|
1397
|
+
scope = options.scope || me,
|
|
1398
|
+
stores = me.stores,
|
|
1399
|
+
i = 0,
|
|
1400
|
+
storeCount,
|
|
1401
|
+
store,
|
|
1402
|
+
args,
|
|
1403
|
+
operation,
|
|
1404
|
+
callback;
|
|
1405
|
+
|
|
1406
|
+
Ext.apply(options, {
|
|
1407
|
+
records: [me],
|
|
1408
|
+
action : 'destroy'
|
|
1409
|
+
});
|
|
1410
|
+
|
|
1411
|
+
operation = new Ext.data.Operation(options);
|
|
1412
|
+
callback = function(operation) {
|
|
1413
|
+
args = [me, operation];
|
|
1414
|
+
if (operation.wasSuccessful()) {
|
|
1415
|
+
for(storeCount = stores.length; i < storeCount; i++) {
|
|
1416
|
+
store = stores[i];
|
|
1417
|
+
store.fireEvent('write', store, operation);
|
|
1418
|
+
store.fireEvent('datachanged', store);
|
|
1419
|
+
// Not firing refresh here, since it's a single record
|
|
1420
|
+
}
|
|
1421
|
+
me.clearListeners();
|
|
1422
|
+
Ext.callback(options.success, scope, args);
|
|
1423
|
+
} else {
|
|
1424
|
+
Ext.callback(options.failure, scope, args);
|
|
1425
|
+
}
|
|
1426
|
+
Ext.callback(options.callback, scope, args);
|
|
1427
|
+
};
|
|
1428
|
+
|
|
1429
|
+
me.getProxy().destroy(operation, callback, me);
|
|
1430
|
+
return me;
|
|
1431
|
+
},
|
|
1432
|
+
|
|
1433
|
+
/**
|
|
1434
|
+
* Returns the unique ID allocated to this model instance as defined by {@link #idProperty}.
|
|
1435
|
+
* @return {Number/String} The id
|
|
1436
|
+
*/
|
|
1437
|
+
getId: function() {
|
|
1438
|
+
return this.get(this.idProperty);
|
|
1439
|
+
},
|
|
1440
|
+
|
|
1441
|
+
/**
|
|
1442
|
+
* @private
|
|
1443
|
+
*/
|
|
1444
|
+
getObservableId: function() {
|
|
1445
|
+
return this.id;
|
|
1446
|
+
},
|
|
1447
|
+
|
|
1448
|
+
/**
|
|
1449
|
+
* Sets the model instance's id field to the given id.
|
|
1450
|
+
* @param {Number/String} id The new id
|
|
1451
|
+
*/
|
|
1452
|
+
setId: function(id) {
|
|
1453
|
+
this.set(this.idProperty, id);
|
|
1454
|
+
this.phantom = !(id || id === 0);
|
|
1455
|
+
},
|
|
1456
|
+
|
|
1457
|
+
/**
|
|
1458
|
+
* Tells this model instance that it has been added to a store.
|
|
1459
|
+
* @param {Ext.data.Store} store The store to which this model has been added.
|
|
1460
|
+
*/
|
|
1461
|
+
join : function(store) {
|
|
1462
|
+
Ext.Array.include(this.stores, store);
|
|
1463
|
+
|
|
1464
|
+
/**
|
|
1465
|
+
* @property {Ext.data.Store} store
|
|
1466
|
+
* The {@link Ext.data.Store Store} to which this instance belongs. NOTE: If this
|
|
1467
|
+
* instance is bound to multiple stores, this property will reference only the
|
|
1468
|
+
* first. To examine all the stores, use the {@link #stores} property instead.
|
|
1469
|
+
*/
|
|
1470
|
+
this.store = this.stores[0]; // compat w/all releases ever
|
|
1471
|
+
},
|
|
1472
|
+
|
|
1473
|
+
/**
|
|
1474
|
+
* Tells this model instance that it has been removed from the store.
|
|
1475
|
+
* @param {Ext.data.Store} store The store from which this model has been removed.
|
|
1476
|
+
*/
|
|
1477
|
+
unjoin: function(store) {
|
|
1478
|
+
Ext.Array.remove(this.stores, store);
|
|
1479
|
+
this.store = this.stores[0] || null; // compat w/all releases ever
|
|
1480
|
+
},
|
|
1481
|
+
|
|
1482
|
+
/**
|
|
1483
|
+
* @private
|
|
1484
|
+
* If this Model instance has been {@link #join joined} to a {@link Ext.data.Store store}, the store's
|
|
1485
|
+
* afterEdit method is called
|
|
1486
|
+
* @param {String[]} modifiedFieldNames Array of field names changed during edit.
|
|
1487
|
+
*/
|
|
1488
|
+
afterEdit : function(modifiedFieldNames) {
|
|
1489
|
+
this.callStore('afterEdit', modifiedFieldNames);
|
|
1490
|
+
},
|
|
1491
|
+
|
|
1492
|
+
/**
|
|
1493
|
+
* @private
|
|
1494
|
+
* If this Model instance has been {@link #join joined} to a {@link Ext.data.Store store}, the store's
|
|
1495
|
+
* afterReject method is called
|
|
1496
|
+
*/
|
|
1497
|
+
afterReject : function() {
|
|
1498
|
+
this.callStore("afterReject");
|
|
1499
|
+
},
|
|
1500
|
+
|
|
1501
|
+
/**
|
|
1502
|
+
* @private
|
|
1503
|
+
* If this Model instance has been {@link #join joined} to a {@link Ext.data.Store store}, the store's
|
|
1504
|
+
* afterCommit method is called
|
|
1505
|
+
*/
|
|
1506
|
+
afterCommit: function() {
|
|
1507
|
+
this.callStore('afterCommit');
|
|
1508
|
+
},
|
|
1509
|
+
|
|
1510
|
+
/**
|
|
1511
|
+
* @private
|
|
1512
|
+
* Helper function used by afterEdit, afterReject and afterCommit. Calls the given method on the
|
|
1513
|
+
* {@link Ext.data.Store store} that this instance has {@link #join joined}, if any. The store function
|
|
1514
|
+
* will always be called with the model instance as its single argument. If this model is joined to
|
|
1515
|
+
* a Ext.data.NodeStore, then this method calls the given method on the NodeStore and the associated Ext.data.TreeStore
|
|
1516
|
+
* @param {String} fn The function to call on the store
|
|
1517
|
+
*/
|
|
1518
|
+
callStore: function(fn) {
|
|
1519
|
+
var args = Ext.Array.clone(arguments),
|
|
1520
|
+
stores = this.stores,
|
|
1521
|
+
i = 0,
|
|
1522
|
+
len = stores.length,
|
|
1523
|
+
store, treeStore;
|
|
1524
|
+
|
|
1525
|
+
args[0] = this;
|
|
1526
|
+
for (; i < len; ++i) {
|
|
1527
|
+
store = stores[i];
|
|
1528
|
+
if (store && typeof store[fn] == "function") {
|
|
1529
|
+
store[fn].apply(store, args);
|
|
1530
|
+
}
|
|
1531
|
+
// if the record is bound to a NodeStore call the TreeStore's method as well
|
|
1532
|
+
treeStore = store.treeStore;
|
|
1533
|
+
if (treeStore && typeof treeStore[fn] == "function") {
|
|
1534
|
+
treeStore[fn].apply(treeStore, args);
|
|
1535
|
+
}
|
|
1536
|
+
}
|
|
1537
|
+
},
|
|
1538
|
+
|
|
1539
|
+
/**
|
|
1540
|
+
* Gets all values for each field in this model and returns an object
|
|
1541
|
+
* containing the current data.
|
|
1542
|
+
* @param {Boolean} includeAssociated True to also include associated data. Defaults to false.
|
|
1543
|
+
* @return {Object} An object hash containing all the values in this model
|
|
1544
|
+
*/
|
|
1545
|
+
getData: function(includeAssociated){
|
|
1546
|
+
var me = this,
|
|
1547
|
+
fields = me.fields.items,
|
|
1548
|
+
fLen = fields.length,
|
|
1549
|
+
data = {},
|
|
1550
|
+
name, f;
|
|
1551
|
+
|
|
1552
|
+
for (f = 0; f < fLen; f++) {
|
|
1553
|
+
name = fields[f].name;
|
|
1554
|
+
data[name] = me.get(name);
|
|
1555
|
+
}
|
|
1556
|
+
|
|
1557
|
+
if (includeAssociated === true) {
|
|
1558
|
+
Ext.apply(data, me.getAssociatedData());
|
|
1559
|
+
}
|
|
1560
|
+
return data;
|
|
1561
|
+
},
|
|
1562
|
+
|
|
1563
|
+
/**
|
|
1564
|
+
* Gets all of the data from this Models *loaded* associations. It does this recursively - for example if we have a
|
|
1565
|
+
* User which hasMany Orders, and each Order hasMany OrderItems, it will return an object like this:
|
|
1566
|
+
*
|
|
1567
|
+
* {
|
|
1568
|
+
* orders: [
|
|
1569
|
+
* {
|
|
1570
|
+
* id: 123,
|
|
1571
|
+
* status: 'shipped',
|
|
1572
|
+
* orderItems: [
|
|
1573
|
+
* ...
|
|
1574
|
+
* ]
|
|
1575
|
+
* }
|
|
1576
|
+
* ]
|
|
1577
|
+
* }
|
|
1578
|
+
*
|
|
1579
|
+
* @return {Object} The nested data set for the Model's loaded associations
|
|
1580
|
+
*/
|
|
1581
|
+
getAssociatedData: function(){
|
|
1582
|
+
return this.prepareAssociatedData({}, 1);
|
|
1583
|
+
},
|
|
1584
|
+
|
|
1585
|
+
/**
|
|
1586
|
+
* @private
|
|
1587
|
+
* This complex-looking method takes a given Model instance and returns an object containing all data from
|
|
1588
|
+
* all of that Model's *loaded* associations. See {@link #getAssociatedData}
|
|
1589
|
+
* @param {Object} seenKeys A hash of all the associations we've already seen
|
|
1590
|
+
* @param {Number} depth The current depth
|
|
1591
|
+
* @return {Object} The nested data set for the Model's loaded associations
|
|
1592
|
+
*/
|
|
1593
|
+
prepareAssociatedData: function(seenKeys, depth) {
|
|
1594
|
+
/**
|
|
1595
|
+
* In this method we use a breadth first strategy instead of depth
|
|
1596
|
+
* first. The reason for doing so is that it prevents messy & difficult
|
|
1597
|
+
* issues when figuring out which associations we've already processed
|
|
1598
|
+
* & at what depths.
|
|
1599
|
+
*/
|
|
1600
|
+
var me = this,
|
|
1601
|
+
associations = me.associations.items,
|
|
1602
|
+
associationCount = associations.length,
|
|
1603
|
+
associationData = {},
|
|
1604
|
+
// We keep 3 lists at the same index instead of using an array of objects.
|
|
1605
|
+
// The reasoning behind this is that this method gets called a lot
|
|
1606
|
+
// So we want to minimize the amount of objects we create for GC.
|
|
1607
|
+
toRead = [],
|
|
1608
|
+
toReadKey = [],
|
|
1609
|
+
toReadIndex = [],
|
|
1610
|
+
associatedStore, associatedRecords, associatedRecord, o, index, result, seenDepth,
|
|
1611
|
+
associationId, associatedRecordCount, association, i, j, type, name;
|
|
1612
|
+
|
|
1613
|
+
for (i = 0; i < associationCount; i++) {
|
|
1614
|
+
association = associations[i];
|
|
1615
|
+
associationId = association.associationId;
|
|
1616
|
+
|
|
1617
|
+
seenDepth = seenKeys[associationId];
|
|
1618
|
+
if (seenDepth && seenDepth !== depth) {
|
|
1619
|
+
continue;
|
|
1620
|
+
}
|
|
1621
|
+
seenKeys[associationId] = depth;
|
|
1622
|
+
|
|
1623
|
+
type = association.type;
|
|
1624
|
+
name = association.name;
|
|
1625
|
+
if (type == 'hasMany') {
|
|
1626
|
+
//this is the hasMany store filled with the associated data
|
|
1627
|
+
associatedStore = me[association.storeName];
|
|
1628
|
+
|
|
1629
|
+
//we will use this to contain each associated record's data
|
|
1630
|
+
associationData[name] = [];
|
|
1631
|
+
|
|
1632
|
+
//if it's loaded, put it into the association data
|
|
1633
|
+
if (associatedStore && associatedStore.getCount() > 0) {
|
|
1634
|
+
associatedRecords = associatedStore.data.items;
|
|
1635
|
+
associatedRecordCount = associatedRecords.length;
|
|
1636
|
+
|
|
1637
|
+
//now we're finally iterating over the records in the association. Get
|
|
1638
|
+
// all the records so we can process them
|
|
1639
|
+
for (j = 0; j < associatedRecordCount; j++) {
|
|
1640
|
+
associatedRecord = associatedRecords[j];
|
|
1641
|
+
associationData[name][j] = associatedRecord.getData();
|
|
1642
|
+
toRead.push(associatedRecord);
|
|
1643
|
+
toReadKey.push(name);
|
|
1644
|
+
toReadIndex.push(j);
|
|
1645
|
+
}
|
|
1646
|
+
}
|
|
1647
|
+
} else if (type == 'belongsTo' || type == 'hasOne') {
|
|
1648
|
+
associatedRecord = me[association.instanceName];
|
|
1649
|
+
// If we have a record, put it onto our list
|
|
1650
|
+
if (associatedRecord !== undefined) {
|
|
1651
|
+
associationData[name] = associatedRecord.getData();
|
|
1652
|
+
toRead.push(associatedRecord);
|
|
1653
|
+
toReadKey.push(name);
|
|
1654
|
+
toReadIndex.push(-1);
|
|
1655
|
+
}
|
|
1656
|
+
}
|
|
1657
|
+
}
|
|
1658
|
+
|
|
1659
|
+
for (i = 0, associatedRecordCount = toRead.length; i < associatedRecordCount; ++i) {
|
|
1660
|
+
associatedRecord = toRead[i];
|
|
1661
|
+
o = associationData[toReadKey[i]];
|
|
1662
|
+
index = toReadIndex[i];
|
|
1663
|
+
result = associatedRecord.prepareAssociatedData(seenKeys, depth + 1);
|
|
1664
|
+
if (index === -1) {
|
|
1665
|
+
Ext.apply(o, result);
|
|
1666
|
+
} else {
|
|
1667
|
+
Ext.apply(o[index], result);
|
|
1668
|
+
}
|
|
1669
|
+
}
|
|
1670
|
+
|
|
1671
|
+
return associationData;
|
|
1672
|
+
}
|
|
1673
|
+
});
|