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,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @author Ed Spencer
|
|
3
|
+
*
|
|
4
|
+
* Simple class that represents a Request that will be made by any {@link Ext.data.proxy.Server} subclass.
|
|
5
|
+
* All this class does is standardize the representation of a Request as used by any ServerProxy subclass,
|
|
6
|
+
* it does not contain any actual logic or perform the request itself.
|
|
7
|
+
*/
|
|
8
|
+
Ext.define('Ext.data.Request', {
|
|
9
|
+
/**
|
|
10
|
+
* @cfg {String} action
|
|
11
|
+
* The name of the action this Request represents. Usually one of 'create', 'read', 'update' or 'destroy'.
|
|
12
|
+
*/
|
|
13
|
+
action: undefined,
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* @cfg {Object} params
|
|
17
|
+
* HTTP request params. The Proxy and its Writer have access to and can modify this object.
|
|
18
|
+
*/
|
|
19
|
+
params: undefined,
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* @cfg {String} method
|
|
23
|
+
* The HTTP method to use on this Request. Should be one of 'GET', 'POST', 'PUT' or 'DELETE'.
|
|
24
|
+
*/
|
|
25
|
+
method: 'GET',
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* @cfg {String} url
|
|
29
|
+
* The url to access on this Request
|
|
30
|
+
*/
|
|
31
|
+
url: undefined,
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Creates the Request object.
|
|
35
|
+
* @param {Object} [config] Config object.
|
|
36
|
+
*/
|
|
37
|
+
constructor: function(config) {
|
|
38
|
+
Ext.apply(this, config);
|
|
39
|
+
}
|
|
40
|
+
});
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @author Ed Spencer
|
|
3
|
+
*
|
|
4
|
+
* Simple wrapper class that represents a set of records returned by a Proxy.
|
|
5
|
+
*/
|
|
6
|
+
Ext.define('Ext.data.ResultSet', {
|
|
7
|
+
/**
|
|
8
|
+
* @cfg {Boolean} loaded
|
|
9
|
+
* True if the records have already been loaded. This is only meaningful when dealing with
|
|
10
|
+
* SQL-backed proxies.
|
|
11
|
+
*/
|
|
12
|
+
loaded: true,
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* @cfg {Number} count
|
|
16
|
+
* The number of records in this ResultSet. Note that total may differ from this number.
|
|
17
|
+
*/
|
|
18
|
+
count: 0,
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* @cfg {Number} total
|
|
22
|
+
* The total number of records reported by the data source. This ResultSet may form a subset of
|
|
23
|
+
* those records (see {@link #count}).
|
|
24
|
+
*/
|
|
25
|
+
total: 0,
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* @cfg {Boolean} success
|
|
29
|
+
* True if the ResultSet loaded successfully, false if any errors were encountered.
|
|
30
|
+
*/
|
|
31
|
+
success: false,
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* @cfg {Ext.data.Model[]} records (required)
|
|
35
|
+
* The array of record instances.
|
|
36
|
+
*/
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Creates the resultSet
|
|
40
|
+
* @param {Object} [config] Config object.
|
|
41
|
+
*/
|
|
42
|
+
constructor: function(config) {
|
|
43
|
+
Ext.apply(this, config);
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* @property {Number} totalRecords
|
|
47
|
+
* Copy of this.total.
|
|
48
|
+
* @deprecated Will be removed in Ext JS 5.0. Use {@link #total} instead.
|
|
49
|
+
*/
|
|
50
|
+
this.totalRecords = this.total;
|
|
51
|
+
|
|
52
|
+
if (config.count === undefined) {
|
|
53
|
+
this.count = this.records.length;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
});
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @author Don Griffin
|
|
3
|
+
*
|
|
4
|
+
* This class is a sequential id generator. A simple use of this class would be like so:
|
|
5
|
+
*
|
|
6
|
+
* Ext.define('MyApp.data.MyModel', {
|
|
7
|
+
* extend: 'Ext.data.Model',
|
|
8
|
+
* idgen: 'sequential'
|
|
9
|
+
* });
|
|
10
|
+
* // assign id's of 1, 2, 3, etc.
|
|
11
|
+
*
|
|
12
|
+
* An example of a configured generator would be:
|
|
13
|
+
*
|
|
14
|
+
* Ext.define('MyApp.data.MyModel', {
|
|
15
|
+
* extend: 'Ext.data.Model',
|
|
16
|
+
* idgen: {
|
|
17
|
+
* type: 'sequential',
|
|
18
|
+
* prefix: 'ID_',
|
|
19
|
+
* seed: 1000
|
|
20
|
+
* }
|
|
21
|
+
* });
|
|
22
|
+
* // assign id's of ID_1000, ID_1001, ID_1002, etc.
|
|
23
|
+
*
|
|
24
|
+
*/
|
|
25
|
+
Ext.define('Ext.data.SequentialIdGenerator', {
|
|
26
|
+
extend: 'Ext.data.IdGenerator',
|
|
27
|
+
alias: 'idgen.sequential',
|
|
28
|
+
|
|
29
|
+
constructor: function() {
|
|
30
|
+
var me = this;
|
|
31
|
+
|
|
32
|
+
me.callParent(arguments);
|
|
33
|
+
|
|
34
|
+
me.parts = [ me.prefix, ''];
|
|
35
|
+
},
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* @cfg {String} prefix
|
|
39
|
+
* The string to place in front of the sequential number for each generated id. The
|
|
40
|
+
* default is blank.
|
|
41
|
+
*/
|
|
42
|
+
prefix: '',
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* @cfg {Number} seed
|
|
46
|
+
* The number at which to start generating sequential id's. The default is 1.
|
|
47
|
+
*/
|
|
48
|
+
seed: 1,
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Generates and returns the next id.
|
|
52
|
+
* @return {String} The next id.
|
|
53
|
+
*/
|
|
54
|
+
generate: function () {
|
|
55
|
+
var me = this,
|
|
56
|
+
parts = me.parts;
|
|
57
|
+
|
|
58
|
+
parts[1] = me.seed++;
|
|
59
|
+
return parts.join('');
|
|
60
|
+
}
|
|
61
|
+
});
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @class Ext.data.SortTypes
|
|
3
|
+
* This class defines a series of static methods that are used on a
|
|
4
|
+
* {@link Ext.data.Field} for performing sorting. The methods cast the
|
|
5
|
+
* underlying values into a data type that is appropriate for sorting on
|
|
6
|
+
* that particular field. If a {@link Ext.data.Field#type} is specified,
|
|
7
|
+
* the sortType will be set to a sane default if the sortType is not
|
|
8
|
+
* explicitly defined on the field. The sortType will make any necessary
|
|
9
|
+
* modifications to the value and return it.
|
|
10
|
+
* <ul>
|
|
11
|
+
* <li><b>asText</b> - Removes any tags and converts the value to a string</li>
|
|
12
|
+
* <li><b>asUCText</b> - Removes any tags and converts the value to an uppercase string</li>
|
|
13
|
+
* <li><b>asUCText</b> - Converts the value to an uppercase string</li>
|
|
14
|
+
* <li><b>asDate</b> - Converts the value into Unix epoch time</li>
|
|
15
|
+
* <li><b>asFloat</b> - Converts the value to a floating point number</li>
|
|
16
|
+
* <li><b>asInt</b> - Converts the value to an integer number</li>
|
|
17
|
+
* </ul>
|
|
18
|
+
* <p>
|
|
19
|
+
* It is also possible to create a custom sortType that can be used throughout
|
|
20
|
+
* an application.
|
|
21
|
+
* <pre><code>
|
|
22
|
+
Ext.apply(Ext.data.SortTypes, {
|
|
23
|
+
asPerson: function(person){
|
|
24
|
+
// expects an object with a first and last name property
|
|
25
|
+
return person.lastName.toUpperCase() + person.firstName.toLowerCase();
|
|
26
|
+
}
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
Ext.define('Employee', {
|
|
30
|
+
extend: 'Ext.data.Model',
|
|
31
|
+
fields: [{
|
|
32
|
+
name: 'person',
|
|
33
|
+
sortType: 'asPerson'
|
|
34
|
+
}, {
|
|
35
|
+
name: 'salary',
|
|
36
|
+
type: 'float' // sortType set to asFloat
|
|
37
|
+
}]
|
|
38
|
+
});
|
|
39
|
+
* </code></pre>
|
|
40
|
+
* </p>
|
|
41
|
+
* @singleton
|
|
42
|
+
* @docauthor Evan Trimboli <evan@sencha.com>
|
|
43
|
+
*/
|
|
44
|
+
Ext.define('Ext.data.SortTypes', {
|
|
45
|
+
|
|
46
|
+
singleton: true,
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Default sort that does nothing
|
|
50
|
+
* @param {Object} s The value being converted
|
|
51
|
+
* @return {Object} The comparison value
|
|
52
|
+
*/
|
|
53
|
+
none : function(s) {
|
|
54
|
+
return s;
|
|
55
|
+
},
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* The regular expression used to strip tags
|
|
59
|
+
* @type {RegExp}
|
|
60
|
+
* @property
|
|
61
|
+
*/
|
|
62
|
+
stripTagsRE : /<\/?[^>]+>/gi,
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Strips all HTML tags to sort on text only
|
|
66
|
+
* @param {Object} s The value being converted
|
|
67
|
+
* @return {String} The comparison value
|
|
68
|
+
*/
|
|
69
|
+
asText : function(s) {
|
|
70
|
+
return String(s).replace(this.stripTagsRE, "");
|
|
71
|
+
},
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Strips all HTML tags to sort on text only - Case insensitive
|
|
75
|
+
* @param {Object} s The value being converted
|
|
76
|
+
* @return {String} The comparison value
|
|
77
|
+
*/
|
|
78
|
+
asUCText : function(s) {
|
|
79
|
+
return String(s).toUpperCase().replace(this.stripTagsRE, "");
|
|
80
|
+
},
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Case insensitive string
|
|
84
|
+
* @param {Object} s The value being converted
|
|
85
|
+
* @return {String} The comparison value
|
|
86
|
+
*/
|
|
87
|
+
asUCString : function(s) {
|
|
88
|
+
return String(s).toUpperCase();
|
|
89
|
+
},
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Date sorting
|
|
93
|
+
* @param {Object} s The value being converted
|
|
94
|
+
* @return {Number} The comparison value
|
|
95
|
+
*/
|
|
96
|
+
asDate : function(s) {
|
|
97
|
+
if(!s){
|
|
98
|
+
return 0;
|
|
99
|
+
}
|
|
100
|
+
if(Ext.isDate(s)){
|
|
101
|
+
return s.getTime();
|
|
102
|
+
}
|
|
103
|
+
return Date.parse(String(s));
|
|
104
|
+
},
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Float sorting
|
|
108
|
+
* @param {Object} s The value being converted
|
|
109
|
+
* @return {Number} The comparison value
|
|
110
|
+
*/
|
|
111
|
+
asFloat : function(s) {
|
|
112
|
+
var val = parseFloat(String(s).replace(/,/g, ""));
|
|
113
|
+
return isNaN(val) ? 0 : val;
|
|
114
|
+
},
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Integer sorting
|
|
118
|
+
* @param {Object} s The value being converted
|
|
119
|
+
* @return {Number} The comparison value
|
|
120
|
+
*/
|
|
121
|
+
asInt : function(s) {
|
|
122
|
+
var val = parseInt(String(s).replace(/,/g, ""), 10);
|
|
123
|
+
return isNaN(val) ? 0 : val;
|
|
124
|
+
}
|
|
125
|
+
});
|
|
@@ -0,0 +1,2609 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The Store class encapsulates a client side cache of {@link Ext.data.Model Model} objects. Stores load data via a
|
|
3
|
+
* {@link Ext.data.proxy.Proxy Proxy}, and also provide functions for {@link #sort sorting}, {@link #filter filtering}
|
|
4
|
+
* and querying the {@link Ext.data.Model model} instances contained within it.
|
|
5
|
+
*
|
|
6
|
+
* Creating a Store is easy - we just tell it the Model and the Proxy to use to load and save its data:
|
|
7
|
+
*
|
|
8
|
+
* // Set up a {@link Ext.data.Model model} to use in our Store
|
|
9
|
+
* Ext.define('User', {
|
|
10
|
+
* extend: 'Ext.data.Model',
|
|
11
|
+
* fields: [
|
|
12
|
+
* {name: 'firstName', type: 'string'},
|
|
13
|
+
* {name: 'lastName', type: 'string'},
|
|
14
|
+
* {name: 'age', type: 'int'},
|
|
15
|
+
* {name: 'eyeColor', type: 'string'}
|
|
16
|
+
* ]
|
|
17
|
+
* });
|
|
18
|
+
*
|
|
19
|
+
* var myStore = Ext.create('Ext.data.Store', {
|
|
20
|
+
* model: 'User',
|
|
21
|
+
* proxy: {
|
|
22
|
+
* type: 'ajax',
|
|
23
|
+
* url: '/users.json',
|
|
24
|
+
* reader: {
|
|
25
|
+
* type: 'json',
|
|
26
|
+
* root: 'users'
|
|
27
|
+
* }
|
|
28
|
+
* },
|
|
29
|
+
* autoLoad: true
|
|
30
|
+
* });
|
|
31
|
+
*
|
|
32
|
+
* In the example above we configured an AJAX proxy to load data from the url '/users.json'. We told our Proxy to use a
|
|
33
|
+
* {@link Ext.data.reader.Json JsonReader} to parse the response from the server into Model object - {@link
|
|
34
|
+
* Ext.data.reader.Json see the docs on JsonReader} for details.
|
|
35
|
+
*
|
|
36
|
+
* ## Inline data
|
|
37
|
+
*
|
|
38
|
+
* Stores can also load data inline. Internally, Store converts each of the objects we pass in as {@link #cfg-data} into
|
|
39
|
+
* Model instances:
|
|
40
|
+
*
|
|
41
|
+
* Ext.create('Ext.data.Store', {
|
|
42
|
+
* model: 'User',
|
|
43
|
+
* data : [
|
|
44
|
+
* {firstName: 'Ed', lastName: 'Spencer'},
|
|
45
|
+
* {firstName: 'Tommy', lastName: 'Maintz'},
|
|
46
|
+
* {firstName: 'Aaron', lastName: 'Conran'},
|
|
47
|
+
* {firstName: 'Jamie', lastName: 'Avins'}
|
|
48
|
+
* ]
|
|
49
|
+
* });
|
|
50
|
+
*
|
|
51
|
+
* Loading inline data using the method above is great if the data is in the correct format already (e.g. it doesn't
|
|
52
|
+
* need to be processed by a {@link Ext.data.reader.Reader reader}). If your inline data requires processing to decode
|
|
53
|
+
* the data structure, use a {@link Ext.data.proxy.Memory MemoryProxy} instead (see the {@link Ext.data.proxy.Memory
|
|
54
|
+
* MemoryProxy} docs for an example).
|
|
55
|
+
*
|
|
56
|
+
* Additional data can also be loaded locally using {@link #method-add}.
|
|
57
|
+
*
|
|
58
|
+
* ## Loading Nested Data
|
|
59
|
+
*
|
|
60
|
+
* Applications often need to load sets of associated data - for example a CRM system might load a User and her Orders.
|
|
61
|
+
* Instead of issuing an AJAX request for the User and a series of additional AJAX requests for each Order, we can load
|
|
62
|
+
* a nested dataset and allow the Reader to automatically populate the associated models. Below is a brief example, see
|
|
63
|
+
* the {@link Ext.data.reader.Reader} intro docs for a full explanation:
|
|
64
|
+
*
|
|
65
|
+
* var store = Ext.create('Ext.data.Store', {
|
|
66
|
+
* autoLoad: true,
|
|
67
|
+
* model: "User",
|
|
68
|
+
* proxy: {
|
|
69
|
+
* type: 'ajax',
|
|
70
|
+
* url: 'users.json',
|
|
71
|
+
* reader: {
|
|
72
|
+
* type: 'json',
|
|
73
|
+
* root: 'users'
|
|
74
|
+
* }
|
|
75
|
+
* }
|
|
76
|
+
* });
|
|
77
|
+
*
|
|
78
|
+
* Which would consume a response like this:
|
|
79
|
+
*
|
|
80
|
+
* {
|
|
81
|
+
* "users": [{
|
|
82
|
+
* "id": 1,
|
|
83
|
+
* "name": "Ed",
|
|
84
|
+
* "orders": [{
|
|
85
|
+
* "id": 10,
|
|
86
|
+
* "total": 10.76,
|
|
87
|
+
* "status": "invoiced"
|
|
88
|
+
* },{
|
|
89
|
+
* "id": 11,
|
|
90
|
+
* "total": 13.45,
|
|
91
|
+
* "status": "shipped"
|
|
92
|
+
* }]
|
|
93
|
+
* }]
|
|
94
|
+
* }
|
|
95
|
+
*
|
|
96
|
+
* See the {@link Ext.data.reader.Reader} intro docs for a full explanation.
|
|
97
|
+
*
|
|
98
|
+
* ## Filtering and Sorting
|
|
99
|
+
*
|
|
100
|
+
* Stores can be sorted and filtered - in both cases either remotely or locally. The {@link #sorters} and {@link #cfg-
|
|
101
|
+
* filters} are held inside {@link Ext.util.MixedCollection MixedCollection} instances to make them easy to manage.
|
|
102
|
+
* Usually it is sufficient to either just specify sorters and filters in the Store configuration or call {@link #sort}
|
|
103
|
+
* or {@link #filter}:
|
|
104
|
+
*
|
|
105
|
+
* var store = Ext.create('Ext.data.Store', {
|
|
106
|
+
* model: 'User',
|
|
107
|
+
* sorters: [{
|
|
108
|
+
* property: 'age',
|
|
109
|
+
* direction: 'DESC'
|
|
110
|
+
* }, {
|
|
111
|
+
* property: 'firstName',
|
|
112
|
+
* direction: 'ASC'
|
|
113
|
+
* }],
|
|
114
|
+
*
|
|
115
|
+
* filters: [{
|
|
116
|
+
* property: 'firstName',
|
|
117
|
+
* value: /Ed/
|
|
118
|
+
* }]
|
|
119
|
+
* });
|
|
120
|
+
*
|
|
121
|
+
* The new Store will keep the configured sorters and filters in the MixedCollection instances mentioned above. By
|
|
122
|
+
* default, sorting and filtering are both performed locally by the Store - see {@link #remoteSort} and {@link
|
|
123
|
+
* #remoteFilter} to allow the server to perform these operations instead.
|
|
124
|
+
*
|
|
125
|
+
* Filtering and sorting after the Store has been instantiated is also easy. Calling {@link #filter} adds another filter
|
|
126
|
+
* to the Store and automatically filters the dataset (calling {@link #filter} with no arguments simply re-applies all
|
|
127
|
+
* existing filters). Note that by default {@link #sortOnFilter} is set to true, which means that your sorters are
|
|
128
|
+
* automatically reapplied if using local sorting.
|
|
129
|
+
*
|
|
130
|
+
* store.filter('eyeColor', 'Brown');
|
|
131
|
+
*
|
|
132
|
+
* Change the sorting at any time by calling {@link #sort}:
|
|
133
|
+
*
|
|
134
|
+
* store.sort('height', 'ASC');
|
|
135
|
+
*
|
|
136
|
+
* Note that all existing sorters will be removed in favor of the new sorter data (if {@link #sort} is called with no
|
|
137
|
+
* arguments, the existing sorters are just reapplied instead of being removed). To keep existing sorters and add new
|
|
138
|
+
* ones, just add them to the MixedCollection:
|
|
139
|
+
*
|
|
140
|
+
* store.sorters.add(new Ext.util.Sorter({
|
|
141
|
+
* property : 'shoeSize',
|
|
142
|
+
* direction: 'ASC'
|
|
143
|
+
* }));
|
|
144
|
+
*
|
|
145
|
+
* store.sort();
|
|
146
|
+
*
|
|
147
|
+
* ## Registering with StoreManager
|
|
148
|
+
*
|
|
149
|
+
* Any Store that is instantiated with a {@link #storeId} will automatically be registed with the {@link
|
|
150
|
+
* Ext.data.StoreManager StoreManager}. This makes it easy to reuse the same store in multiple views:
|
|
151
|
+
*
|
|
152
|
+
* //this store can be used several times
|
|
153
|
+
* Ext.create('Ext.data.Store', {
|
|
154
|
+
* model: 'User',
|
|
155
|
+
* storeId: 'usersStore'
|
|
156
|
+
* });
|
|
157
|
+
*
|
|
158
|
+
* new Ext.List({
|
|
159
|
+
* store: 'usersStore',
|
|
160
|
+
* //other config goes here
|
|
161
|
+
* });
|
|
162
|
+
*
|
|
163
|
+
* new Ext.view.View({
|
|
164
|
+
* store: 'usersStore',
|
|
165
|
+
* //other config goes here
|
|
166
|
+
* });
|
|
167
|
+
*
|
|
168
|
+
* ## Further Reading
|
|
169
|
+
*
|
|
170
|
+
* Stores are backed up by an ecosystem of classes that enables their operation. To gain a full understanding of these
|
|
171
|
+
* pieces and how they fit together, see:
|
|
172
|
+
*
|
|
173
|
+
* - {@link Ext.data.proxy.Proxy Proxy} - overview of what Proxies are and how they are used
|
|
174
|
+
* - {@link Ext.data.Model Model} - the core class in the data package
|
|
175
|
+
* - {@link Ext.data.reader.Reader Reader} - used by any subclass of {@link Ext.data.proxy.Server ServerProxy} to read a response
|
|
176
|
+
*
|
|
177
|
+
* @author Ed Spencer
|
|
178
|
+
*/
|
|
179
|
+
Ext.define('Ext.data.Store', {
|
|
180
|
+
extend: 'Ext.data.AbstractStore',
|
|
181
|
+
|
|
182
|
+
alias: 'store.store',
|
|
183
|
+
|
|
184
|
+
// Required classes must be loaded before the definition callback runs
|
|
185
|
+
// The class definition callback creates a dummy Store which requires that
|
|
186
|
+
// all the classes below have been loaded.
|
|
187
|
+
requires: [
|
|
188
|
+
'Ext.data.StoreManager',
|
|
189
|
+
'Ext.data.Model',
|
|
190
|
+
'Ext.data.proxy.Ajax',
|
|
191
|
+
'Ext.data.proxy.Memory',
|
|
192
|
+
'Ext.data.reader.Json',
|
|
193
|
+
'Ext.data.writer.Json',
|
|
194
|
+
'Ext.util.LruCache'
|
|
195
|
+
],
|
|
196
|
+
|
|
197
|
+
uses: [
|
|
198
|
+
'Ext.ModelManager',
|
|
199
|
+
'Ext.util.Grouper'
|
|
200
|
+
],
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
* @cfg {Boolean} remoteSort
|
|
204
|
+
* True to defer any sorting operation to the server. If false, sorting is done locally on the client.
|
|
205
|
+
*/
|
|
206
|
+
remoteSort: false,
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
* @cfg {Boolean} remoteFilter
|
|
210
|
+
* True to defer any filtering operation to the server. If false, filtering is done locally on the client.
|
|
211
|
+
*/
|
|
212
|
+
remoteFilter: false,
|
|
213
|
+
|
|
214
|
+
/**
|
|
215
|
+
* @cfg {Boolean} remoteGroup
|
|
216
|
+
* True if the grouping should apply on the server side, false if it is local only. If the
|
|
217
|
+
* grouping is local, it can be applied immediately to the data. If it is remote, then it will simply act as a
|
|
218
|
+
* helper, automatically sending the grouping information to the server.
|
|
219
|
+
*/
|
|
220
|
+
remoteGroup : false,
|
|
221
|
+
|
|
222
|
+
/**
|
|
223
|
+
* @cfg {String/Ext.data.proxy.Proxy/Object} proxy
|
|
224
|
+
* The Proxy to use for this Store. This can be either a string, a config object or a Proxy instance -
|
|
225
|
+
* see {@link #setProxy} for details.
|
|
226
|
+
*/
|
|
227
|
+
|
|
228
|
+
/**
|
|
229
|
+
* @cfg {Object[]/Ext.data.Model[]} data
|
|
230
|
+
* Array of Model instances or data objects to load locally. See "Inline data" above for details.
|
|
231
|
+
*/
|
|
232
|
+
|
|
233
|
+
/**
|
|
234
|
+
* @cfg {String} groupField
|
|
235
|
+
* The field by which to group data in the store. Internally, grouping is very similar to sorting - the
|
|
236
|
+
* groupField and {@link #groupDir} are injected as the first sorter (see {@link #sort}). Stores support a single
|
|
237
|
+
* level of grouping, and groups can be fetched via the {@link #getGroups} method.
|
|
238
|
+
*/
|
|
239
|
+
groupField: undefined,
|
|
240
|
+
|
|
241
|
+
/**
|
|
242
|
+
* @cfg {String} groupDir
|
|
243
|
+
* The direction in which sorting should be applied when grouping. Supported values are "ASC" and "DESC".
|
|
244
|
+
*/
|
|
245
|
+
groupDir: "ASC",
|
|
246
|
+
|
|
247
|
+
/**
|
|
248
|
+
* @cfg {Number} trailingBufferZone
|
|
249
|
+
* When {@link #buffered}, the number of extra records to keep cached on the trailing side of scrolling buffer
|
|
250
|
+
* as scrolling proceeds. A larger number means fewer replenishments from the server.
|
|
251
|
+
*/
|
|
252
|
+
trailingBufferZone: 25,
|
|
253
|
+
|
|
254
|
+
/**
|
|
255
|
+
* @cfg {Number} leadingBufferZone
|
|
256
|
+
* When {@link #buffered}, the number of extra rows to keep cached on the leading side of scrolling buffer
|
|
257
|
+
* as scrolling proceeds. A larger number means fewer replenishments from the server.
|
|
258
|
+
*/
|
|
259
|
+
leadingBufferZone: 200,
|
|
260
|
+
|
|
261
|
+
/**
|
|
262
|
+
* @cfg {Number} pageSize
|
|
263
|
+
* The number of records considered to form a 'page'. This is used to power the built-in
|
|
264
|
+
* paging using the nextPage and previousPage functions when the grid is paged using a
|
|
265
|
+
* {@link Ext.toolbar.Paging PagingScroller} Defaults to 25.
|
|
266
|
+
*
|
|
267
|
+
* If this Store is {@link #buffered}, pages are loaded into a page cache before the Store's
|
|
268
|
+
* data is updated from the cache. The pageSize is the number of rows loaded into the cache in one request.
|
|
269
|
+
* This will not affect the rendering of a buffered grid, but a larger page size will mean fewer loads.
|
|
270
|
+
*
|
|
271
|
+
* In a buffered grid, scrolling is monitored, and the page cache is kept primed with data ahead of the
|
|
272
|
+
* direction of scroll to provide rapid access to data when scrolling causes it to be required. Several pages
|
|
273
|
+
* in advance may be requested depending on various parameters.
|
|
274
|
+
*
|
|
275
|
+
* It is recommended to tune the {@link #pageSize}, {@link #trailingBufferZone} and
|
|
276
|
+
* {@link #leadingBufferZone} configurations based upon the conditions pertaining in your deployed application.
|
|
277
|
+
*
|
|
278
|
+
* The provided SDK example `examples/grid/infinite-scroll-grid-tuner.html` can be used to experiment with
|
|
279
|
+
* different settings including simulating Ajax latency.
|
|
280
|
+
*/
|
|
281
|
+
pageSize: undefined,
|
|
282
|
+
|
|
283
|
+
/**
|
|
284
|
+
* @property {Number} currentPage
|
|
285
|
+
* The page that the Store has most recently loaded (see {@link #loadPage})
|
|
286
|
+
*/
|
|
287
|
+
currentPage: 1,
|
|
288
|
+
|
|
289
|
+
/**
|
|
290
|
+
* @cfg {Boolean} clearOnPageLoad
|
|
291
|
+
* True to empty the store when loading another page via {@link #loadPage},
|
|
292
|
+
* {@link #nextPage} or {@link #previousPage}. Setting to false keeps existing records, allowing
|
|
293
|
+
* large data sets to be loaded one page at a time but rendered all together.
|
|
294
|
+
*/
|
|
295
|
+
clearOnPageLoad: true,
|
|
296
|
+
|
|
297
|
+
/**
|
|
298
|
+
* @property {Boolean} loading
|
|
299
|
+
* True if the Store is currently loading via its Proxy
|
|
300
|
+
* @private
|
|
301
|
+
*/
|
|
302
|
+
loading: false,
|
|
303
|
+
|
|
304
|
+
/**
|
|
305
|
+
* @cfg {Boolean} sortOnFilter
|
|
306
|
+
* For local filtering only, causes {@link #sort} to be called whenever {@link #filter} is called,
|
|
307
|
+
* causing the sorters to be reapplied after filtering. Defaults to true
|
|
308
|
+
*/
|
|
309
|
+
sortOnFilter: true,
|
|
310
|
+
|
|
311
|
+
/**
|
|
312
|
+
* @cfg {Boolean} buffered
|
|
313
|
+
* Allows the Store to prefetch and cache in a **page cache**, pages of Records, and to then satisfy
|
|
314
|
+
* loading requirements from this page cache.
|
|
315
|
+
*
|
|
316
|
+
* To use buffered Stores, initiate the process by loading the first page. The number of rows rendered are
|
|
317
|
+
* determined automatically, and the range of pages needed to keep the cache primed for scrolling is
|
|
318
|
+
* requested and cached.
|
|
319
|
+
* Example:
|
|
320
|
+
*
|
|
321
|
+
* // Load page 1
|
|
322
|
+
* myStore.loadPage(1);
|
|
323
|
+
*
|
|
324
|
+
* A {@link Ext.grid.PagingScroller PagingScroller} is instantiated which will monitor the scrolling in the grid, and
|
|
325
|
+
* refresh the view's rows from the page cache as needed. It will also pull new data into the page
|
|
326
|
+
* cache when scrolling of the view draws upon data near either end of the prefetched data.
|
|
327
|
+
*
|
|
328
|
+
* The margins which trigger view refreshing from the prefetched data are {@link Ext.grid.PagingScroller#numFromEdge},
|
|
329
|
+
* {@link Ext.grid.PagingScroller#leadingBufferZone} and {@link Ext.grid.PagingScroller#trailingBufferZone}.
|
|
330
|
+
*
|
|
331
|
+
* The margins which trigger loading more data into the page cache are, {@link #leadingBufferZone} and
|
|
332
|
+
* {@link #trailingBufferZone}.
|
|
333
|
+
*
|
|
334
|
+
* By defult, only 5 pages of data are cached in the page cache, with pages "scrolling" out of the buffer
|
|
335
|
+
* as the view moves down through the dataset. This can be increased by changing the {@link #purgePageSize}
|
|
336
|
+
* value. Setting this value to zero means that no pages are *ever* scrolled out of the page cache, and
|
|
337
|
+
* that eventually the whole dataset may become present in the page cache. This is sometimes desirable
|
|
338
|
+
* as long as datasets do not reach astronomical proportions.
|
|
339
|
+
*
|
|
340
|
+
* Selection state may be maintained across page boundaries by configuring the SelectionModel not to discard
|
|
341
|
+
* records from its collection when those Records cycle out of the Store's primary collection. This is done
|
|
342
|
+
* by configuring the SelectionModel like this:
|
|
343
|
+
*
|
|
344
|
+
* selModel: {
|
|
345
|
+
* pruneRemoved: false
|
|
346
|
+
* }
|
|
347
|
+
*
|
|
348
|
+
*/
|
|
349
|
+
buffered: false,
|
|
350
|
+
|
|
351
|
+
/**
|
|
352
|
+
* @cfg {Number} purgePageCount
|
|
353
|
+
* *Valid only when used with a {@link Ext.data.Store#buffered buffered} Store.*
|
|
354
|
+
*
|
|
355
|
+
* The number of pages *additional to the required buffered range* to keep in the prefetch cache before purging least recently used records.
|
|
356
|
+
*
|
|
357
|
+
* For example, if the height of the view area and the configured {@link trailingBufferZone} and {@link #leadingBufferZone} require that there
|
|
358
|
+
* are three pages in the cache, then a `purgePageCount` of 5 ensures that up to 8 pages can be in the page cache any any one time.
|
|
359
|
+
*
|
|
360
|
+
* A value of 0 indicates to never purge the prefetched data.
|
|
361
|
+
*/
|
|
362
|
+
purgePageCount: 5,
|
|
363
|
+
|
|
364
|
+
/**
|
|
365
|
+
* @cfg {Boolean} [clearRemovedOnLoad=true]
|
|
366
|
+
* True to clear anything in the {@link #removed} record collection when the store loads.
|
|
367
|
+
*/
|
|
368
|
+
clearRemovedOnLoad: true,
|
|
369
|
+
|
|
370
|
+
defaultPageSize: 25,
|
|
371
|
+
|
|
372
|
+
statics: {
|
|
373
|
+
recordIdFn: function(record) {
|
|
374
|
+
return record.internalId;
|
|
375
|
+
},
|
|
376
|
+
recordIndexFn: function(record) {
|
|
377
|
+
return record.index;
|
|
378
|
+
}
|
|
379
|
+
},
|
|
380
|
+
|
|
381
|
+
onClassExtended: function(cls, data, hooks) {
|
|
382
|
+
var model = data.model,
|
|
383
|
+
onBeforeClassCreated;
|
|
384
|
+
|
|
385
|
+
if (typeof model == 'string') {
|
|
386
|
+
onBeforeClassCreated = hooks.onBeforeCreated;
|
|
387
|
+
|
|
388
|
+
hooks.onBeforeCreated = function() {
|
|
389
|
+
var me = this,
|
|
390
|
+
args = arguments;
|
|
391
|
+
|
|
392
|
+
Ext.require(model, function() {
|
|
393
|
+
onBeforeClassCreated.apply(me, args);
|
|
394
|
+
});
|
|
395
|
+
};
|
|
396
|
+
}
|
|
397
|
+
},
|
|
398
|
+
|
|
399
|
+
/**
|
|
400
|
+
* Creates the store.
|
|
401
|
+
* @param {Object} [config] Config object
|
|
402
|
+
*/
|
|
403
|
+
constructor: function(config) {
|
|
404
|
+
// Clone the config so we don't modify the original config object
|
|
405
|
+
config = Ext.Object.merge({}, config);
|
|
406
|
+
|
|
407
|
+
var me = this,
|
|
408
|
+
groupers = config.groupers || me.groupers,
|
|
409
|
+
groupField = config.groupField || me.groupField,
|
|
410
|
+
proxy,
|
|
411
|
+
data;
|
|
412
|
+
|
|
413
|
+
/**
|
|
414
|
+
* @event beforeprefetch
|
|
415
|
+
* Fires before a prefetch occurs. Return false to cancel.
|
|
416
|
+
* @param {Ext.data.Store} this
|
|
417
|
+
* @param {Ext.data.Operation} operation The associated operation
|
|
418
|
+
*/
|
|
419
|
+
/**
|
|
420
|
+
* @event groupchange
|
|
421
|
+
* Fired whenever the grouping in the grid changes
|
|
422
|
+
* @param {Ext.data.Store} store The store
|
|
423
|
+
* @param {Ext.util.Grouper[]} groupers The array of grouper objects
|
|
424
|
+
*/
|
|
425
|
+
/**
|
|
426
|
+
* @event prefetch
|
|
427
|
+
* Fires whenever records have been prefetched
|
|
428
|
+
* @param {Ext.data.Store} this
|
|
429
|
+
* @param {Ext.data.Model[]} records An array of records.
|
|
430
|
+
* @param {Boolean} successful True if the operation was successful.
|
|
431
|
+
* @param {Ext.data.Operation} operation The associated operation
|
|
432
|
+
*/
|
|
433
|
+
data = config.data || me.data;
|
|
434
|
+
|
|
435
|
+
/**
|
|
436
|
+
* @property {Ext.util.MixedCollection} data
|
|
437
|
+
* The MixedCollection that holds this store's local cache of records.
|
|
438
|
+
*/
|
|
439
|
+
me.data = new Ext.util.MixedCollection(false, Ext.data.Store.recordIdFn);
|
|
440
|
+
|
|
441
|
+
if (data) {
|
|
442
|
+
me.inlineData = data;
|
|
443
|
+
delete config.data;
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
if (!groupers && groupField) {
|
|
447
|
+
groupers = [{
|
|
448
|
+
property : groupField,
|
|
449
|
+
direction: config.groupDir || me.groupDir
|
|
450
|
+
}];
|
|
451
|
+
}
|
|
452
|
+
delete config.groupers;
|
|
453
|
+
|
|
454
|
+
/**
|
|
455
|
+
* @property {Ext.util.MixedCollection} groupers
|
|
456
|
+
* The collection of {@link Ext.util.Grouper Groupers} currently applied to this Store.
|
|
457
|
+
*/
|
|
458
|
+
me.groupers = new Ext.util.MixedCollection();
|
|
459
|
+
me.groupers.addAll(me.decodeGroupers(groupers));
|
|
460
|
+
|
|
461
|
+
this.callParent([config]);
|
|
462
|
+
// don't use *config* anymore from here on... use *me* instead...
|
|
463
|
+
|
|
464
|
+
if (me.buffered) {
|
|
465
|
+
|
|
466
|
+
// Create our page map.
|
|
467
|
+
// Whenever it gets cleared, it means we re no longer interested in
|
|
468
|
+
// any outstanding page prefetches, so cancel tham all
|
|
469
|
+
me.pageMap = new me.PageMap({
|
|
470
|
+
pageSize: me.pageSize,
|
|
471
|
+
maxSize: me.purgePageCount,
|
|
472
|
+
listeners: {
|
|
473
|
+
clear: me.cancelAllPrefetches,
|
|
474
|
+
scope: me
|
|
475
|
+
}
|
|
476
|
+
});
|
|
477
|
+
me.pageRequests = {};
|
|
478
|
+
|
|
479
|
+
me.sortOnLoad = false;
|
|
480
|
+
me.filterOnLoad = false;
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
if (me.groupers.items.length) {
|
|
484
|
+
me.sort(me.groupers.items, 'prepend', false);
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
proxy = me.proxy;
|
|
488
|
+
data = me.inlineData;
|
|
489
|
+
|
|
490
|
+
// Page size for non-buffered Store defaults to 25
|
|
491
|
+
// For a buffered Store, the default page size is taken from the initial call to prefetch.
|
|
492
|
+
if (!me.buffered && !me.pageSize) {
|
|
493
|
+
me.pageSize = me.defaultPageSize;
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
if (data) {
|
|
497
|
+
if (proxy instanceof Ext.data.proxy.Memory) {
|
|
498
|
+
proxy.data = data;
|
|
499
|
+
me.read();
|
|
500
|
+
} else {
|
|
501
|
+
me.add.apply(me, [data]);
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
me.sort();
|
|
505
|
+
delete me.inlineData;
|
|
506
|
+
} else if (me.autoLoad) {
|
|
507
|
+
Ext.defer(me.load, 10, me, [ typeof me.autoLoad === 'object' ? me.autoLoad : undefined ]);
|
|
508
|
+
// Remove the defer call, we may need reinstate this at some point, but currently it's not obvious why it's here.
|
|
509
|
+
// this.load(typeof this.autoLoad == 'object' ? this.autoLoad : undefined);
|
|
510
|
+
}
|
|
511
|
+
},
|
|
512
|
+
|
|
513
|
+
destroy: function() {
|
|
514
|
+
// Release cached pages.
|
|
515
|
+
// Will also ccancel outstanding prefetch requests, and cause a generation change
|
|
516
|
+
// so that incoming prefetch data will be ignored.
|
|
517
|
+
if (this.pageMap) {
|
|
518
|
+
this.pageMap.clear();
|
|
519
|
+
}
|
|
520
|
+
this.callParent(arguments);
|
|
521
|
+
},
|
|
522
|
+
|
|
523
|
+
onBeforeSort: function() {
|
|
524
|
+
var groupers = this.groupers;
|
|
525
|
+
if (groupers.getCount() > 0) {
|
|
526
|
+
this.sort(groupers.items, 'prepend', false);
|
|
527
|
+
}
|
|
528
|
+
},
|
|
529
|
+
|
|
530
|
+
/**
|
|
531
|
+
* @private
|
|
532
|
+
* Normalizes an array of grouper objects, ensuring that they are all Ext.util.Grouper instances
|
|
533
|
+
* @param {Object[]} groupers The groupers array
|
|
534
|
+
* @return {Ext.util.Grouper[]} Array of Ext.util.Grouper objects
|
|
535
|
+
*/
|
|
536
|
+
decodeGroupers: function(groupers) {
|
|
537
|
+
if (!Ext.isArray(groupers)) {
|
|
538
|
+
if (groupers === undefined) {
|
|
539
|
+
groupers = [];
|
|
540
|
+
} else {
|
|
541
|
+
groupers = [groupers];
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
var length = groupers.length,
|
|
546
|
+
Grouper = Ext.util.Grouper,
|
|
547
|
+
config, i, result = [];
|
|
548
|
+
|
|
549
|
+
for (i = 0; i < length; i++) {
|
|
550
|
+
config = groupers[i];
|
|
551
|
+
|
|
552
|
+
if (!(config instanceof Grouper)) {
|
|
553
|
+
if (Ext.isString(config)) {
|
|
554
|
+
config = {
|
|
555
|
+
property: config
|
|
556
|
+
};
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
config = Ext.apply({
|
|
560
|
+
root : 'data',
|
|
561
|
+
direction: "ASC"
|
|
562
|
+
}, config);
|
|
563
|
+
|
|
564
|
+
//support for 3.x style sorters where a function can be defined as 'fn'
|
|
565
|
+
if (config.fn) {
|
|
566
|
+
config.sorterFn = config.fn;
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
//support a function to be passed as a sorter definition
|
|
570
|
+
if (typeof config == 'function') {
|
|
571
|
+
config = {
|
|
572
|
+
sorterFn: config
|
|
573
|
+
};
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
// return resulting Groupers in a separate array so as not to mutate passed in data objects.
|
|
577
|
+
result.push(new Grouper(config));
|
|
578
|
+
} else {
|
|
579
|
+
result.push(config);
|
|
580
|
+
}
|
|
581
|
+
}
|
|
582
|
+
return result;
|
|
583
|
+
},
|
|
584
|
+
|
|
585
|
+
/**
|
|
586
|
+
* Groups data inside the store.
|
|
587
|
+
* @param {String/Object[]} groupers Either a string name of one of the fields in this Store's
|
|
588
|
+
* configured {@link Ext.data.Model Model}, or an Array of grouper configurations.
|
|
589
|
+
* @param {String} [direction="ASC"] The overall direction to group the data by.
|
|
590
|
+
*/
|
|
591
|
+
group: function(groupers, direction) {
|
|
592
|
+
var me = this,
|
|
593
|
+
hasNew = false,
|
|
594
|
+
grouper,
|
|
595
|
+
newGroupers;
|
|
596
|
+
|
|
597
|
+
if (Ext.isArray(groupers)) {
|
|
598
|
+
newGroupers = groupers;
|
|
599
|
+
} else if (Ext.isObject(groupers)) {
|
|
600
|
+
newGroupers = [groupers];
|
|
601
|
+
} else if (Ext.isString(groupers)) {
|
|
602
|
+
grouper = me.groupers.get(groupers);
|
|
603
|
+
|
|
604
|
+
if (!grouper) {
|
|
605
|
+
grouper = {
|
|
606
|
+
property : groupers,
|
|
607
|
+
direction: direction
|
|
608
|
+
};
|
|
609
|
+
newGroupers = [grouper];
|
|
610
|
+
} else if (direction === undefined) {
|
|
611
|
+
grouper.toggle();
|
|
612
|
+
} else {
|
|
613
|
+
grouper.setDirection(direction);
|
|
614
|
+
}
|
|
615
|
+
}
|
|
616
|
+
|
|
617
|
+
if (newGroupers && newGroupers.length) {
|
|
618
|
+
hasNew = true;
|
|
619
|
+
newGroupers = me.decodeGroupers(newGroupers);
|
|
620
|
+
me.groupers.clear();
|
|
621
|
+
me.groupers.addAll(newGroupers);
|
|
622
|
+
}
|
|
623
|
+
|
|
624
|
+
if (me.remoteGroup) {
|
|
625
|
+
me.load({
|
|
626
|
+
scope: me,
|
|
627
|
+
callback: me.fireGroupChange
|
|
628
|
+
});
|
|
629
|
+
} else {
|
|
630
|
+
// need to explicitly force a sort if we have groupers
|
|
631
|
+
me.sort(null, null, null, hasNew);
|
|
632
|
+
me.fireGroupChange();
|
|
633
|
+
}
|
|
634
|
+
},
|
|
635
|
+
|
|
636
|
+
/**
|
|
637
|
+
* Clear any groupers in the store
|
|
638
|
+
*/
|
|
639
|
+
clearGrouping: function() {
|
|
640
|
+
var me = this,
|
|
641
|
+
groupers = me.groupers.items,
|
|
642
|
+
gLen = groupers.length,
|
|
643
|
+
grouper, g;
|
|
644
|
+
|
|
645
|
+
for (g = 0; g < gLen; g++) {
|
|
646
|
+
grouper = groupers[g];
|
|
647
|
+
|
|
648
|
+
me.sorters.remove(grouper);
|
|
649
|
+
}
|
|
650
|
+
|
|
651
|
+
me.groupers.clear();
|
|
652
|
+
if (me.remoteGroup) {
|
|
653
|
+
me.load({
|
|
654
|
+
scope: me,
|
|
655
|
+
callback: me.fireGroupChange
|
|
656
|
+
});
|
|
657
|
+
} else {
|
|
658
|
+
me.sort();
|
|
659
|
+
me.fireEvent('groupchange', me, me.groupers);
|
|
660
|
+
}
|
|
661
|
+
},
|
|
662
|
+
|
|
663
|
+
/**
|
|
664
|
+
* Checks if the store is currently grouped
|
|
665
|
+
* @return {Boolean} True if the store is grouped.
|
|
666
|
+
*/
|
|
667
|
+
isGrouped: function() {
|
|
668
|
+
return this.groupers.getCount() > 0;
|
|
669
|
+
},
|
|
670
|
+
|
|
671
|
+
/**
|
|
672
|
+
* Fires the groupchange event. Abstracted out so we can use it
|
|
673
|
+
* as a callback
|
|
674
|
+
* @private
|
|
675
|
+
*/
|
|
676
|
+
fireGroupChange: function() {
|
|
677
|
+
this.fireEvent('groupchange', this, this.groupers);
|
|
678
|
+
},
|
|
679
|
+
|
|
680
|
+
/**
|
|
681
|
+
* Returns an array containing the result of applying grouping to the records in this store.
|
|
682
|
+
* See {@link #groupField}, {@link #groupDir} and {@link #getGroupString}. Example for a store
|
|
683
|
+
* containing records with a color field:
|
|
684
|
+
*
|
|
685
|
+
* var myStore = Ext.create('Ext.data.Store', {
|
|
686
|
+
* groupField: 'color',
|
|
687
|
+
* groupDir : 'DESC'
|
|
688
|
+
* });
|
|
689
|
+
*
|
|
690
|
+
* myStore.getGroups(); // returns:
|
|
691
|
+
* [
|
|
692
|
+
* {
|
|
693
|
+
* name: 'yellow',
|
|
694
|
+
* children: [
|
|
695
|
+
* // all records where the color field is 'yellow'
|
|
696
|
+
* ]
|
|
697
|
+
* },
|
|
698
|
+
* {
|
|
699
|
+
* name: 'red',
|
|
700
|
+
* children: [
|
|
701
|
+
* // all records where the color field is 'red'
|
|
702
|
+
* ]
|
|
703
|
+
* }
|
|
704
|
+
* ]
|
|
705
|
+
*
|
|
706
|
+
* Group contents are effected by filtering.
|
|
707
|
+
*
|
|
708
|
+
* @param {String} [groupName] Pass in an optional groupName argument to access a specific
|
|
709
|
+
* group as defined by {@link #getGroupString}.
|
|
710
|
+
* @return {Object/Object[]} The grouped data
|
|
711
|
+
*/
|
|
712
|
+
getGroups: function(requestGroupString) {
|
|
713
|
+
var records = this.data.items,
|
|
714
|
+
length = records.length,
|
|
715
|
+
groups = [],
|
|
716
|
+
pointers = {},
|
|
717
|
+
record,
|
|
718
|
+
groupStr,
|
|
719
|
+
group,
|
|
720
|
+
i;
|
|
721
|
+
|
|
722
|
+
for (i = 0; i < length; i++) {
|
|
723
|
+
record = records[i];
|
|
724
|
+
groupStr = this.getGroupString(record);
|
|
725
|
+
group = pointers[groupStr];
|
|
726
|
+
|
|
727
|
+
if (group === undefined) {
|
|
728
|
+
group = {
|
|
729
|
+
name: groupStr,
|
|
730
|
+
children: []
|
|
731
|
+
};
|
|
732
|
+
|
|
733
|
+
groups.push(group);
|
|
734
|
+
pointers[groupStr] = group;
|
|
735
|
+
}
|
|
736
|
+
|
|
737
|
+
group.children.push(record);
|
|
738
|
+
}
|
|
739
|
+
|
|
740
|
+
return requestGroupString ? pointers[requestGroupString] : groups;
|
|
741
|
+
},
|
|
742
|
+
|
|
743
|
+
/**
|
|
744
|
+
* @private
|
|
745
|
+
* For a given set of records and a Grouper, returns an array of arrays - each of which is the set of records
|
|
746
|
+
* matching a certain group.
|
|
747
|
+
*/
|
|
748
|
+
getGroupsForGrouper: function(records, grouper) {
|
|
749
|
+
var length = records.length,
|
|
750
|
+
groups = [],
|
|
751
|
+
oldValue,
|
|
752
|
+
newValue,
|
|
753
|
+
record,
|
|
754
|
+
group,
|
|
755
|
+
i;
|
|
756
|
+
|
|
757
|
+
for (i = 0; i < length; i++) {
|
|
758
|
+
record = records[i];
|
|
759
|
+
newValue = grouper.getGroupString(record);
|
|
760
|
+
|
|
761
|
+
if (newValue !== oldValue) {
|
|
762
|
+
group = {
|
|
763
|
+
name: newValue,
|
|
764
|
+
grouper: grouper,
|
|
765
|
+
records: []
|
|
766
|
+
};
|
|
767
|
+
groups.push(group);
|
|
768
|
+
}
|
|
769
|
+
|
|
770
|
+
group.records.push(record);
|
|
771
|
+
|
|
772
|
+
oldValue = newValue;
|
|
773
|
+
}
|
|
774
|
+
|
|
775
|
+
return groups;
|
|
776
|
+
},
|
|
777
|
+
|
|
778
|
+
/**
|
|
779
|
+
* @private
|
|
780
|
+
* This is used recursively to gather the records into the configured Groupers. The data MUST have been sorted for
|
|
781
|
+
* this to work properly (see {@link #getGroupData} and {@link #getGroupsForGrouper}) Most of the work is done by
|
|
782
|
+
* {@link #getGroupsForGrouper} - this function largely just handles the recursion.
|
|
783
|
+
*
|
|
784
|
+
* @param {Ext.data.Model[]} records The set or subset of records to group
|
|
785
|
+
* @param {Number} grouperIndex The grouper index to retrieve
|
|
786
|
+
* @return {Object[]} The grouped records
|
|
787
|
+
*/
|
|
788
|
+
getGroupsForGrouperIndex: function(records, grouperIndex) {
|
|
789
|
+
var me = this,
|
|
790
|
+
groupers = me.groupers,
|
|
791
|
+
grouper = groupers.getAt(grouperIndex),
|
|
792
|
+
groups = me.getGroupsForGrouper(records, grouper),
|
|
793
|
+
length = groups.length,
|
|
794
|
+
i;
|
|
795
|
+
|
|
796
|
+
if (grouperIndex + 1 < groupers.length) {
|
|
797
|
+
for (i = 0; i < length; i++) {
|
|
798
|
+
groups[i].children = me.getGroupsForGrouperIndex(groups[i].records, grouperIndex + 1);
|
|
799
|
+
}
|
|
800
|
+
}
|
|
801
|
+
|
|
802
|
+
for (i = 0; i < length; i++) {
|
|
803
|
+
groups[i].depth = grouperIndex;
|
|
804
|
+
}
|
|
805
|
+
|
|
806
|
+
return groups;
|
|
807
|
+
},
|
|
808
|
+
|
|
809
|
+
/**
|
|
810
|
+
* @private
|
|
811
|
+
* Returns records grouped by the configured {@link #groupers grouper} configuration. Sample return value (in
|
|
812
|
+
* this case grouping by genre and then author in a fictional books dataset):
|
|
813
|
+
*
|
|
814
|
+
* [
|
|
815
|
+
* {
|
|
816
|
+
* name: 'Fantasy',
|
|
817
|
+
* depth: 0,
|
|
818
|
+
* records: [
|
|
819
|
+
* //book1, book2, book3, book4
|
|
820
|
+
* ],
|
|
821
|
+
* children: [
|
|
822
|
+
* {
|
|
823
|
+
* name: 'Rowling',
|
|
824
|
+
* depth: 1,
|
|
825
|
+
* records: [
|
|
826
|
+
* //book1, book2
|
|
827
|
+
* ]
|
|
828
|
+
* },
|
|
829
|
+
* {
|
|
830
|
+
* name: 'Tolkein',
|
|
831
|
+
* depth: 1,
|
|
832
|
+
* records: [
|
|
833
|
+
* //book3, book4
|
|
834
|
+
* ]
|
|
835
|
+
* }
|
|
836
|
+
* ]
|
|
837
|
+
* }
|
|
838
|
+
* ]
|
|
839
|
+
*
|
|
840
|
+
* @param {Boolean} [sort=true] True to call {@link #sort} before finding groups. Sorting is required to make grouping
|
|
841
|
+
* function correctly so this should only be set to false if the Store is known to already be sorted correctly.
|
|
842
|
+
* @return {Object[]} The group data
|
|
843
|
+
*/
|
|
844
|
+
getGroupData: function(sort) {
|
|
845
|
+
var me = this;
|
|
846
|
+
if (sort !== false) {
|
|
847
|
+
me.sort();
|
|
848
|
+
}
|
|
849
|
+
|
|
850
|
+
return me.getGroupsForGrouperIndex(me.data.items, 0);
|
|
851
|
+
},
|
|
852
|
+
|
|
853
|
+
/**
|
|
854
|
+
* Returns the string to group on for a given model instance. The default implementation of this method returns
|
|
855
|
+
* the model's {@link #groupField}, but this can be overridden to group by an arbitrary string. For example, to
|
|
856
|
+
* group by the first letter of a model's 'name' field, use the following code:
|
|
857
|
+
*
|
|
858
|
+
* Ext.create('Ext.data.Store', {
|
|
859
|
+
* groupDir: 'ASC',
|
|
860
|
+
* getGroupString: function(instance) {
|
|
861
|
+
* return instance.get('name')[0];
|
|
862
|
+
* }
|
|
863
|
+
* });
|
|
864
|
+
*
|
|
865
|
+
* @param {Ext.data.Model} instance The model instance
|
|
866
|
+
* @return {String} The string to compare when forming groups
|
|
867
|
+
*/
|
|
868
|
+
getGroupString: function(instance) {
|
|
869
|
+
var group = this.groupers.first();
|
|
870
|
+
if (group) {
|
|
871
|
+
return instance.get(group.property);
|
|
872
|
+
}
|
|
873
|
+
return '';
|
|
874
|
+
},
|
|
875
|
+
|
|
876
|
+
/**
|
|
877
|
+
* Inserts Model instances into the Store at the given index and fires the {@link #event-add} event.
|
|
878
|
+
* See also {@link #method-add}.
|
|
879
|
+
*
|
|
880
|
+
* @param {Number} index The start index at which to insert the passed Records.
|
|
881
|
+
* @param {Ext.data.Model[]} records An Array of Ext.data.Model objects to add to the store.
|
|
882
|
+
*/
|
|
883
|
+
insert: function(index, records) {
|
|
884
|
+
var me = this,
|
|
885
|
+
sync = false,
|
|
886
|
+
i,
|
|
887
|
+
record,
|
|
888
|
+
len;
|
|
889
|
+
|
|
890
|
+
records = [].concat(records);
|
|
891
|
+
for (i = 0,len = records.length; i < len; i++) {
|
|
892
|
+
record = me.createModel(records[i]);
|
|
893
|
+
record.set(me.modelDefaults);
|
|
894
|
+
// reassign the model in the array in case it wasn't created yet
|
|
895
|
+
records[i] = record;
|
|
896
|
+
|
|
897
|
+
me.data.insert(index + i, record);
|
|
898
|
+
record.join(me);
|
|
899
|
+
|
|
900
|
+
sync = sync || record.phantom === true;
|
|
901
|
+
}
|
|
902
|
+
|
|
903
|
+
if (me.snapshot) {
|
|
904
|
+
me.snapshot.addAll(records);
|
|
905
|
+
}
|
|
906
|
+
|
|
907
|
+
if (me.requireSort) {
|
|
908
|
+
// suspend events so the usual data changed events don't get fired.
|
|
909
|
+
me.suspendEvents();
|
|
910
|
+
me.sort();
|
|
911
|
+
me.resumeEvents();
|
|
912
|
+
}
|
|
913
|
+
|
|
914
|
+
me.fireEvent('add', me, records, index);
|
|
915
|
+
me.fireEvent('datachanged', me);
|
|
916
|
+
if (me.autoSync && sync && !me.autoSyncSuspended) {
|
|
917
|
+
me.sync();
|
|
918
|
+
}
|
|
919
|
+
},
|
|
920
|
+
|
|
921
|
+
/**
|
|
922
|
+
* Adds Model instance to the Store. This method accepts either:
|
|
923
|
+
*
|
|
924
|
+
* - An array of Model instances or Model configuration objects.
|
|
925
|
+
* - Any number of Model instance or Model configuration object arguments.
|
|
926
|
+
*
|
|
927
|
+
* The new Model instances will be added at the end of the existing collection.
|
|
928
|
+
*
|
|
929
|
+
* Sample usage:
|
|
930
|
+
*
|
|
931
|
+
* myStore.add({some: 'data'}, {some: 'other data'});
|
|
932
|
+
*
|
|
933
|
+
* Note that if this Store is sorted, the new Model instances will be inserted
|
|
934
|
+
* at the correct point in the Store to maintain the sort order.
|
|
935
|
+
*
|
|
936
|
+
* @param {Ext.data.Model[]/Ext.data.Model...} model An array of Model instances
|
|
937
|
+
* or Model configuration objects, or variable number of Model instance or config arguments.
|
|
938
|
+
* @return {Ext.data.Model[]} The model instances that were added
|
|
939
|
+
*/
|
|
940
|
+
add: function(records) {
|
|
941
|
+
//accept both a single-argument array of records, or any number of record arguments
|
|
942
|
+
if (!Ext.isArray(records)) {
|
|
943
|
+
records = Array.prototype.slice.apply(arguments);
|
|
944
|
+
} else {
|
|
945
|
+
// Create an array copy
|
|
946
|
+
records = records.slice(0);
|
|
947
|
+
}
|
|
948
|
+
|
|
949
|
+
var me = this,
|
|
950
|
+
i = 0,
|
|
951
|
+
length = records.length,
|
|
952
|
+
record,
|
|
953
|
+
isSorted = me.sorters && me.sorters.items.length;
|
|
954
|
+
|
|
955
|
+
// If this Store is sorted, and they only passed one Record (99% or use cases)
|
|
956
|
+
// then it's much more efficient to add it sorted than to append and then sort.
|
|
957
|
+
if (isSorted && length === 1) {
|
|
958
|
+
return [ me.addSorted(me.createModel(records[0])) ];
|
|
959
|
+
}
|
|
960
|
+
|
|
961
|
+
for (; i < length; i++) {
|
|
962
|
+
record = me.createModel(records[i]);
|
|
963
|
+
// reassign the model in the array in case it wasn't created yet
|
|
964
|
+
records[i] = record;
|
|
965
|
+
}
|
|
966
|
+
|
|
967
|
+
// If this sort is sorted, set the flag used by the insert method to sort
|
|
968
|
+
// before firing events.
|
|
969
|
+
if (isSorted) {
|
|
970
|
+
me.requireSort = true;
|
|
971
|
+
}
|
|
972
|
+
|
|
973
|
+
me.insert(me.data.length, records);
|
|
974
|
+
delete me.requireSort;
|
|
975
|
+
|
|
976
|
+
return records;
|
|
977
|
+
},
|
|
978
|
+
|
|
979
|
+
/**
|
|
980
|
+
* (Local sort only) Inserts the passed Record into the Store at the index where it
|
|
981
|
+
* should go based on the current sort information.
|
|
982
|
+
*
|
|
983
|
+
* @param {Ext.data.Record} record
|
|
984
|
+
*/
|
|
985
|
+
addSorted: function(record) {
|
|
986
|
+
var me = this,
|
|
987
|
+
index = me.data.findInsertionIndex(record, me.generateComparator());
|
|
988
|
+
|
|
989
|
+
me.insert(index, record);
|
|
990
|
+
return record;
|
|
991
|
+
},
|
|
992
|
+
|
|
993
|
+
/**
|
|
994
|
+
* Converts a literal to a model, if it's not a model already
|
|
995
|
+
* @private
|
|
996
|
+
* @param {Ext.data.Model/Object} record The record to create
|
|
997
|
+
* @return {Ext.data.Model}
|
|
998
|
+
*/
|
|
999
|
+
createModel: function(record) {
|
|
1000
|
+
if (!record.isModel) {
|
|
1001
|
+
record = Ext.ModelManager.create(record, this.model);
|
|
1002
|
+
}
|
|
1003
|
+
|
|
1004
|
+
return record;
|
|
1005
|
+
},
|
|
1006
|
+
|
|
1007
|
+
/**
|
|
1008
|
+
* Calls the specified function for each {@link Ext.data.Model record} in the store.
|
|
1009
|
+
*
|
|
1010
|
+
* When store is filtered, only loops over the filtered records.
|
|
1011
|
+
*
|
|
1012
|
+
* @param {Function} fn The function to call. The {@link Ext.data.Model Record} is passed as the first parameter.
|
|
1013
|
+
* Returning `false` aborts and exits the iteration.
|
|
1014
|
+
* @param {Object} [scope] The scope (this reference) in which the function is executed.
|
|
1015
|
+
* Defaults to the current {@link Ext.data.Model record} in the iteration.
|
|
1016
|
+
*/
|
|
1017
|
+
each: function(fn, scope) {
|
|
1018
|
+
var data = this.data.items,
|
|
1019
|
+
dLen = data.length,
|
|
1020
|
+
record, d;
|
|
1021
|
+
|
|
1022
|
+
for (d = 0; d < dLen; d++) {
|
|
1023
|
+
record = data[d];
|
|
1024
|
+
if (fn.call(scope || record, record, d, dLen) === false) {
|
|
1025
|
+
break;
|
|
1026
|
+
}
|
|
1027
|
+
}
|
|
1028
|
+
},
|
|
1029
|
+
|
|
1030
|
+
/**
|
|
1031
|
+
* Removes the given record from the Store, firing the 'remove' event for each instance that is removed,
|
|
1032
|
+
* plus a single 'datachanged' event after removal.
|
|
1033
|
+
*
|
|
1034
|
+
* @param {Ext.data.Model/Ext.data.Model[]} records Model instance or array of instances to remove.
|
|
1035
|
+
*/
|
|
1036
|
+
remove: function(records, /* private */ isMove) {
|
|
1037
|
+
if (!Ext.isArray(records)) {
|
|
1038
|
+
records = [records];
|
|
1039
|
+
}
|
|
1040
|
+
|
|
1041
|
+
/*
|
|
1042
|
+
* Pass the isMove parameter if we know we're going to be re-inserting this record
|
|
1043
|
+
*/
|
|
1044
|
+
isMove = isMove === true;
|
|
1045
|
+
var me = this,
|
|
1046
|
+
sync = false,
|
|
1047
|
+
i = 0,
|
|
1048
|
+
length = records.length,
|
|
1049
|
+
isPhantom,
|
|
1050
|
+
index,
|
|
1051
|
+
record;
|
|
1052
|
+
|
|
1053
|
+
for (; i < length; i++) {
|
|
1054
|
+
record = records[i];
|
|
1055
|
+
index = me.data.indexOf(record);
|
|
1056
|
+
|
|
1057
|
+
if (me.snapshot) {
|
|
1058
|
+
me.snapshot.remove(record);
|
|
1059
|
+
}
|
|
1060
|
+
|
|
1061
|
+
if (index > -1) {
|
|
1062
|
+
isPhantom = record.phantom === true;
|
|
1063
|
+
|
|
1064
|
+
if (!isMove && !isPhantom) {
|
|
1065
|
+
// don't push phantom records onto removed
|
|
1066
|
+
me.removed.push(record);
|
|
1067
|
+
}
|
|
1068
|
+
|
|
1069
|
+
record.unjoin(me);
|
|
1070
|
+
me.data.remove(record);
|
|
1071
|
+
sync = sync || !isPhantom;
|
|
1072
|
+
|
|
1073
|
+
me.fireEvent('remove', me, record, index);
|
|
1074
|
+
}
|
|
1075
|
+
}
|
|
1076
|
+
|
|
1077
|
+
me.fireEvent('datachanged', me);
|
|
1078
|
+
if (!isMove && me.autoSync && sync && !me.autoSyncSuspended) {
|
|
1079
|
+
me.sync();
|
|
1080
|
+
}
|
|
1081
|
+
},
|
|
1082
|
+
|
|
1083
|
+
/**
|
|
1084
|
+
* Removes the model instance at the given index
|
|
1085
|
+
* @param {Number} index The record index
|
|
1086
|
+
*/
|
|
1087
|
+
removeAt: function(index) {
|
|
1088
|
+
var record = this.getAt(index);
|
|
1089
|
+
|
|
1090
|
+
if (record) {
|
|
1091
|
+
this.remove(record);
|
|
1092
|
+
}
|
|
1093
|
+
},
|
|
1094
|
+
|
|
1095
|
+
/**
|
|
1096
|
+
* Loads data into the Store via the configured {@link #proxy}. This uses the Proxy to make an
|
|
1097
|
+
* asynchronous call to whatever storage backend the Proxy uses, automatically adding the retrieved
|
|
1098
|
+
* instances into the Store and calling an optional callback if required. Example usage:
|
|
1099
|
+
*
|
|
1100
|
+
* store.load({
|
|
1101
|
+
* scope: this,
|
|
1102
|
+
* callback: function(records, operation, success) {
|
|
1103
|
+
* // the {@link Ext.data.Operation operation} object
|
|
1104
|
+
* // contains all of the details of the load operation
|
|
1105
|
+
* console.log(records);
|
|
1106
|
+
* }
|
|
1107
|
+
* });
|
|
1108
|
+
*
|
|
1109
|
+
* If the callback scope does not need to be set, a function can simply be passed:
|
|
1110
|
+
*
|
|
1111
|
+
* store.load(function(records, operation, success) {
|
|
1112
|
+
* console.log('loaded records');
|
|
1113
|
+
* });
|
|
1114
|
+
*
|
|
1115
|
+
* @param {Object/Function} [options] config object, passed into the Ext.data.Operation object before loading.
|
|
1116
|
+
* Additionally `addRecords: true` can be specified to add these records to the existing records, default is
|
|
1117
|
+
* to remove the Store's existing records first.
|
|
1118
|
+
*/
|
|
1119
|
+
load: function(options) {
|
|
1120
|
+
var me = this;
|
|
1121
|
+
|
|
1122
|
+
options = options || {};
|
|
1123
|
+
|
|
1124
|
+
if (typeof options == 'function') {
|
|
1125
|
+
options = {
|
|
1126
|
+
callback: options
|
|
1127
|
+
};
|
|
1128
|
+
}
|
|
1129
|
+
|
|
1130
|
+
options.groupers = options.groupers || me.groupers.items;
|
|
1131
|
+
options.page = options.page || me.currentPage;
|
|
1132
|
+
options.start = (options.start !== undefined) ? options.start : (me.currentPage - 1) * me.pageSize;
|
|
1133
|
+
options.limit = options.limit || me.pageSize;
|
|
1134
|
+
options.addRecords = options.addRecords || false;
|
|
1135
|
+
|
|
1136
|
+
if (me.buffered) {
|
|
1137
|
+
return me.loadToPrefetch(options);
|
|
1138
|
+
}
|
|
1139
|
+
return me.callParent([options]);
|
|
1140
|
+
},
|
|
1141
|
+
|
|
1142
|
+
/**
|
|
1143
|
+
* @private
|
|
1144
|
+
* Called internally when a Proxy has completed a load request
|
|
1145
|
+
*/
|
|
1146
|
+
onProxyLoad: function(operation) {
|
|
1147
|
+
var me = this,
|
|
1148
|
+
resultSet = operation.getResultSet(),
|
|
1149
|
+
records = operation.getRecords(),
|
|
1150
|
+
successful = operation.wasSuccessful();
|
|
1151
|
+
|
|
1152
|
+
if (resultSet) {
|
|
1153
|
+
me.totalCount = resultSet.total;
|
|
1154
|
+
}
|
|
1155
|
+
|
|
1156
|
+
if (successful) {
|
|
1157
|
+
me.loadRecords(records, operation);
|
|
1158
|
+
}
|
|
1159
|
+
|
|
1160
|
+
me.loading = false;
|
|
1161
|
+
me.fireEvent('load', me, records, successful);
|
|
1162
|
+
|
|
1163
|
+
//TODO: deprecate this event, it should always have been 'load' instead. 'load' is now documented, 'read' is not.
|
|
1164
|
+
//People are definitely using this so can't deprecate safely until 2.x
|
|
1165
|
+
me.fireEvent('read', me, records, operation.wasSuccessful());
|
|
1166
|
+
|
|
1167
|
+
//this is a callback that would have been passed to the 'read' function and is optional
|
|
1168
|
+
Ext.callback(operation.callback, operation.scope || me, [records, operation, successful]);
|
|
1169
|
+
},
|
|
1170
|
+
|
|
1171
|
+
//inherit docs
|
|
1172
|
+
getNewRecords: function() {
|
|
1173
|
+
return this.data.filterBy(this.filterNew).items;
|
|
1174
|
+
},
|
|
1175
|
+
|
|
1176
|
+
//inherit docs
|
|
1177
|
+
getUpdatedRecords: function() {
|
|
1178
|
+
return this.data.filterBy(this.filterUpdated).items;
|
|
1179
|
+
},
|
|
1180
|
+
|
|
1181
|
+
/**
|
|
1182
|
+
* Filters the loaded set of records by a given set of filters.
|
|
1183
|
+
*
|
|
1184
|
+
* By default, the passed filter(s) are *added* to the collection of filters being used to filter this Store.
|
|
1185
|
+
*
|
|
1186
|
+
* To remove existing filters before applying a new set of filters use
|
|
1187
|
+
*
|
|
1188
|
+
* // Clear the filter collection without updating the UI
|
|
1189
|
+
* store.clearFilter(true);
|
|
1190
|
+
*
|
|
1191
|
+
* see (@link #clearFilter}.
|
|
1192
|
+
*
|
|
1193
|
+
* Alternatively, if filters are configured with an `id`, then existing filters store may be *replaced* by new
|
|
1194
|
+
* filters having the same `id`.
|
|
1195
|
+
*
|
|
1196
|
+
* Filtering by single field:
|
|
1197
|
+
*
|
|
1198
|
+
* store.filter("email", /\.com$/);
|
|
1199
|
+
*
|
|
1200
|
+
* Using multiple filters:
|
|
1201
|
+
*
|
|
1202
|
+
* store.filter([
|
|
1203
|
+
* {property: "email", value: /\.com$/},
|
|
1204
|
+
* {filterFn: function(item) { return item.get("age") > 10; }}
|
|
1205
|
+
* ]);
|
|
1206
|
+
*
|
|
1207
|
+
* Using Ext.util.Filter instances instead of config objects
|
|
1208
|
+
* (note that we need to specify the {@link Ext.util.Filter#root root} config option in this case):
|
|
1209
|
+
*
|
|
1210
|
+
* store.filter([
|
|
1211
|
+
* Ext.create('Ext.util.Filter', {property: "email", value: /\.com$/, root: 'data'}),
|
|
1212
|
+
* Ext.create('Ext.util.Filter', {filterFn: function(item) { return item.get("age") > 10; }, root: 'data'})
|
|
1213
|
+
* ]);
|
|
1214
|
+
*
|
|
1215
|
+
* When store is filtered, most of the methods for accessing store data will be working only
|
|
1216
|
+
* within the set of filtered records. Two notable exceptions are {@link #queryBy} and
|
|
1217
|
+
* {@link #getById}.
|
|
1218
|
+
*
|
|
1219
|
+
* @param {Object[]/Ext.util.Filter[]/String} filters The set of filters to apply to the data.
|
|
1220
|
+
* These are stored internally on the store, but the filtering itself is done on the Store's
|
|
1221
|
+
* {@link Ext.util.MixedCollection MixedCollection}. See MixedCollection's
|
|
1222
|
+
* {@link Ext.util.MixedCollection#filter filter} method for filter syntax.
|
|
1223
|
+
* Alternatively, pass in a property string
|
|
1224
|
+
* @param {String} [value] value to filter by (only if using a property string as the first argument)
|
|
1225
|
+
*/
|
|
1226
|
+
filter: function(filters, value) {
|
|
1227
|
+
if (Ext.isString(filters)) {
|
|
1228
|
+
filters = {
|
|
1229
|
+
property: filters,
|
|
1230
|
+
value: value
|
|
1231
|
+
};
|
|
1232
|
+
}
|
|
1233
|
+
|
|
1234
|
+
var me = this,
|
|
1235
|
+
decoded = me.decodeFilters(filters),
|
|
1236
|
+
i = 0,
|
|
1237
|
+
doLocalSort = me.sorters.length && me.sortOnFilter && !me.remoteSort,
|
|
1238
|
+
length = decoded.length;
|
|
1239
|
+
|
|
1240
|
+
for (; i < length; i++) {
|
|
1241
|
+
me.filters.replace(decoded[i]);
|
|
1242
|
+
}
|
|
1243
|
+
|
|
1244
|
+
if (me.remoteFilter) {
|
|
1245
|
+
// For a buffered Store, we have to clear the prefetch cache because the dataset will change upon filtering.
|
|
1246
|
+
// Then we must prefetch the new page 1, and when that arrives, reload the visible part of the Store
|
|
1247
|
+
// via the guaranteedrange event
|
|
1248
|
+
if (me.buffered) {
|
|
1249
|
+
me.pageMap.clear();
|
|
1250
|
+
me.loadPage(1);
|
|
1251
|
+
} else {
|
|
1252
|
+
// Reset to the first page, the filter is likely to produce a smaller data set
|
|
1253
|
+
me.currentPage = 1;
|
|
1254
|
+
//the load function will pick up the new filters and request the filtered data from the proxy
|
|
1255
|
+
me.load();
|
|
1256
|
+
}
|
|
1257
|
+
} else {
|
|
1258
|
+
/**
|
|
1259
|
+
* @property {Ext.util.MixedCollection} snapshot
|
|
1260
|
+
* A pristine (unfiltered) collection of the records in this store. This is used to reinstate
|
|
1261
|
+
* records when a filter is removed or changed
|
|
1262
|
+
*/
|
|
1263
|
+
if (me.filters.getCount()) {
|
|
1264
|
+
me.snapshot = me.snapshot || me.data.clone();
|
|
1265
|
+
me.data = me.data.filter(me.filters.items);
|
|
1266
|
+
|
|
1267
|
+
if (doLocalSort) {
|
|
1268
|
+
me.sort();
|
|
1269
|
+
} else {
|
|
1270
|
+
// fire datachanged event if it hasn't already been fired by doSort
|
|
1271
|
+
me.fireEvent('datachanged', me);
|
|
1272
|
+
me.fireEvent('refresh', me);
|
|
1273
|
+
}
|
|
1274
|
+
}
|
|
1275
|
+
}
|
|
1276
|
+
},
|
|
1277
|
+
|
|
1278
|
+
/**
|
|
1279
|
+
* Reverts to a view of the Record cache with no filtering applied.
|
|
1280
|
+
* @param {Boolean} suppressEvent If `true` the filter is cleared silently.
|
|
1281
|
+
*
|
|
1282
|
+
* For a locally filtered Store, this means that the filter collection is cleared without firing the
|
|
1283
|
+
* {@link #datachanged} event.
|
|
1284
|
+
*
|
|
1285
|
+
* For a remotely filtered Store, this means that the filter collection is cleared, but the store
|
|
1286
|
+
* is not reloaded from the server.
|
|
1287
|
+
*/
|
|
1288
|
+
clearFilter: function(suppressEvent) {
|
|
1289
|
+
var me = this;
|
|
1290
|
+
|
|
1291
|
+
me.filters.clear();
|
|
1292
|
+
|
|
1293
|
+
if (me.remoteFilter) {
|
|
1294
|
+
|
|
1295
|
+
// In a buffered Store, the meaing of suppressEvent is to simply clear the filters collection
|
|
1296
|
+
if (suppressEvent) {
|
|
1297
|
+
return;
|
|
1298
|
+
}
|
|
1299
|
+
|
|
1300
|
+
// For a buffered Store, we have to clear the prefetch cache because the dataset will change upon filtering.
|
|
1301
|
+
// Then we must prefetch the new page 1, and when that arrives, reload the visible part of the Store
|
|
1302
|
+
// via the guaranteedrange event
|
|
1303
|
+
if (me.buffered) {
|
|
1304
|
+
me.pageMap.clear();
|
|
1305
|
+
me.loadPage(1);
|
|
1306
|
+
} else {
|
|
1307
|
+
// Reset to the first page, clearing a filter will destroy the context of the current dataset
|
|
1308
|
+
me.currentPage = 1;
|
|
1309
|
+
me.load();
|
|
1310
|
+
}
|
|
1311
|
+
} else if (me.isFiltered()) {
|
|
1312
|
+
me.data = me.snapshot.clone();
|
|
1313
|
+
delete me.snapshot;
|
|
1314
|
+
|
|
1315
|
+
if (suppressEvent !== true) {
|
|
1316
|
+
me.fireEvent('datachanged', me);
|
|
1317
|
+
me.fireEvent('refresh', me);
|
|
1318
|
+
}
|
|
1319
|
+
}
|
|
1320
|
+
},
|
|
1321
|
+
|
|
1322
|
+
/**
|
|
1323
|
+
* Returns true if this store is currently filtered
|
|
1324
|
+
* @return {Boolean}
|
|
1325
|
+
*/
|
|
1326
|
+
isFiltered: function() {
|
|
1327
|
+
var snapshot = this.snapshot;
|
|
1328
|
+
return !! snapshot && snapshot !== this.data;
|
|
1329
|
+
},
|
|
1330
|
+
|
|
1331
|
+
/**
|
|
1332
|
+
* Filters by a function. The specified function will be called for each
|
|
1333
|
+
* Record in this Store. If the function returns `true` the Record is included,
|
|
1334
|
+
* otherwise it is filtered out.
|
|
1335
|
+
*
|
|
1336
|
+
* When store is filtered, most of the methods for accessing store data will be working only
|
|
1337
|
+
* within the set of filtered records. Two notable exceptions are {@link #queryBy} and
|
|
1338
|
+
* {@link #getById}.
|
|
1339
|
+
*
|
|
1340
|
+
* @param {Function} fn The function to be called. It will be passed the following parameters:
|
|
1341
|
+
* @param {Ext.data.Model} fn.record The record to test for filtering. Access field values
|
|
1342
|
+
* using {@link Ext.data.Model#get}.
|
|
1343
|
+
* @param {Object} fn.id The ID of the Record passed.
|
|
1344
|
+
* @param {Object} [scope] The scope (this reference) in which the function is executed.
|
|
1345
|
+
* Defaults to this Store.
|
|
1346
|
+
*/
|
|
1347
|
+
filterBy: function(fn, scope) {
|
|
1348
|
+
var me = this;
|
|
1349
|
+
|
|
1350
|
+
me.snapshot = me.snapshot || me.data.clone();
|
|
1351
|
+
me.data = me.queryBy(fn, scope || me);
|
|
1352
|
+
me.fireEvent('datachanged', me);
|
|
1353
|
+
me.fireEvent('refresh', me);
|
|
1354
|
+
},
|
|
1355
|
+
|
|
1356
|
+
/**
|
|
1357
|
+
* Query all the cached records in this Store using a filtering function. The specified function
|
|
1358
|
+
* will be called with each record in this Store. If the function returns `true` the record is
|
|
1359
|
+
* included in the results.
|
|
1360
|
+
*
|
|
1361
|
+
* This method is not effected by filtering, it will always look from all records inside the store
|
|
1362
|
+
* no matter if filter is applied or not.
|
|
1363
|
+
*
|
|
1364
|
+
* @param {Function} fn The function to be called. It will be passed the following parameters:
|
|
1365
|
+
* @param {Ext.data.Model} fn.record The record to test for filtering. Access field values
|
|
1366
|
+
* using {@link Ext.data.Model#get}.
|
|
1367
|
+
* @param {Object} fn.id The ID of the Record passed.
|
|
1368
|
+
* @param {Object} [scope] The scope (this reference) in which the function is executed
|
|
1369
|
+
* Defaults to this Store.
|
|
1370
|
+
* @return {Ext.util.MixedCollection} Returns an Ext.util.MixedCollection of the matched records
|
|
1371
|
+
*/
|
|
1372
|
+
queryBy: function(fn, scope) {
|
|
1373
|
+
var me = this,
|
|
1374
|
+
data = me.snapshot || me.data;
|
|
1375
|
+
return data.filterBy(fn, scope || me);
|
|
1376
|
+
},
|
|
1377
|
+
|
|
1378
|
+
/**
|
|
1379
|
+
* Loads an array of data straight into the Store.
|
|
1380
|
+
*
|
|
1381
|
+
* Using this method is great if the data is in the correct format already (e.g. it doesn't need to be
|
|
1382
|
+
* processed by a reader). If your data requires processing to decode the data structure, use a
|
|
1383
|
+
* {@link Ext.data.proxy.Memory MemoryProxy} instead.
|
|
1384
|
+
*
|
|
1385
|
+
* @param {Ext.data.Model[]/Object[]} data Array of data to load. Any non-model instances will be cast
|
|
1386
|
+
* into model instances first.
|
|
1387
|
+
* @param {Boolean} [append=false] True to add the records to the existing records in the store, false
|
|
1388
|
+
* to remove the old ones first.
|
|
1389
|
+
*/
|
|
1390
|
+
loadData: function(data, append) {
|
|
1391
|
+
var model = this.model,
|
|
1392
|
+
length = data.length,
|
|
1393
|
+
newData = [],
|
|
1394
|
+
i,
|
|
1395
|
+
record;
|
|
1396
|
+
|
|
1397
|
+
//make sure each data element is an Ext.data.Model instance
|
|
1398
|
+
for (i = 0; i < length; i++) {
|
|
1399
|
+
record = data[i];
|
|
1400
|
+
|
|
1401
|
+
if (!(record instanceof Ext.data.Model)) {
|
|
1402
|
+
record = Ext.ModelManager.create(record, model);
|
|
1403
|
+
}
|
|
1404
|
+
newData.push(record);
|
|
1405
|
+
}
|
|
1406
|
+
|
|
1407
|
+
this.loadRecords(newData, {addRecords: append});
|
|
1408
|
+
},
|
|
1409
|
+
|
|
1410
|
+
|
|
1411
|
+
/**
|
|
1412
|
+
* Loads data via the bound Proxy's reader
|
|
1413
|
+
*
|
|
1414
|
+
* Use this method if you are attempting to load data and want to utilize the configured data reader.
|
|
1415
|
+
*
|
|
1416
|
+
* @param {Object[]} data The full JSON object you'd like to load into the Data store.
|
|
1417
|
+
* @param {Boolean} [append=false] True to add the records to the existing records in the store, false
|
|
1418
|
+
* to remove the old ones first.
|
|
1419
|
+
*/
|
|
1420
|
+
loadRawData : function(data, append) {
|
|
1421
|
+
var me = this,
|
|
1422
|
+
result = me.proxy.reader.read(data),
|
|
1423
|
+
records = result.records;
|
|
1424
|
+
|
|
1425
|
+
if (result.success) {
|
|
1426
|
+
me.totalCount = result.total;
|
|
1427
|
+
me.loadRecords(records, { addRecords: append });
|
|
1428
|
+
me.fireEvent('load', me, records, true);
|
|
1429
|
+
}
|
|
1430
|
+
},
|
|
1431
|
+
|
|
1432
|
+
|
|
1433
|
+
/**
|
|
1434
|
+
* Loads an array of {@link Ext.data.Model model} instances into the store, fires the datachanged event. This should only usually
|
|
1435
|
+
* be called internally when loading from the {@link Ext.data.proxy.Proxy Proxy}, when adding records manually use {@link #method-add} instead
|
|
1436
|
+
* @param {Ext.data.Model[]} records The array of records to load
|
|
1437
|
+
* @param {Object} options {addRecords: true} to add these records to the existing records, false to remove the Store's existing records first
|
|
1438
|
+
*/
|
|
1439
|
+
loadRecords: function(records, options) {
|
|
1440
|
+
var me = this,
|
|
1441
|
+
i = 0,
|
|
1442
|
+
length = records.length,
|
|
1443
|
+
start = (options = options || {}).start,
|
|
1444
|
+
snapshot = me.snapshot;
|
|
1445
|
+
|
|
1446
|
+
if (!options.addRecords) {
|
|
1447
|
+
delete me.snapshot;
|
|
1448
|
+
me.clearData(true);
|
|
1449
|
+
} else if (snapshot) {
|
|
1450
|
+
snapshot.addAll(records);
|
|
1451
|
+
}
|
|
1452
|
+
|
|
1453
|
+
me.data.addAll(records);
|
|
1454
|
+
|
|
1455
|
+
if (typeof start != 'undefined') {
|
|
1456
|
+
for (; i < length; i++) {
|
|
1457
|
+
records[i].index = start + i;
|
|
1458
|
+
records[i].join(me);
|
|
1459
|
+
}
|
|
1460
|
+
} else {
|
|
1461
|
+
for (; i < length; i++) {
|
|
1462
|
+
records[i].join(me);
|
|
1463
|
+
}
|
|
1464
|
+
}
|
|
1465
|
+
|
|
1466
|
+
/*
|
|
1467
|
+
* this rather inelegant suspension and resumption of events is required because both the filter and sort functions
|
|
1468
|
+
* fire an additional datachanged event, which is not wanted. Ideally we would do this a different way. The first
|
|
1469
|
+
* datachanged event is fired by the call to this.add, above.
|
|
1470
|
+
*/
|
|
1471
|
+
me.suspendEvents();
|
|
1472
|
+
|
|
1473
|
+
if (me.filterOnLoad && !me.remoteFilter) {
|
|
1474
|
+
me.filter();
|
|
1475
|
+
}
|
|
1476
|
+
|
|
1477
|
+
if (me.sortOnLoad && !me.remoteSort) {
|
|
1478
|
+
me.sort();
|
|
1479
|
+
}
|
|
1480
|
+
|
|
1481
|
+
me.resumeEvents();
|
|
1482
|
+
me.fireEvent('datachanged', me);
|
|
1483
|
+
me.fireEvent('refresh', me);
|
|
1484
|
+
},
|
|
1485
|
+
|
|
1486
|
+
// PAGING METHODS
|
|
1487
|
+
/**
|
|
1488
|
+
* Loads a given 'page' of data by setting the start and limit values appropriately. Internally this just causes a normal
|
|
1489
|
+
* load operation, passing in calculated 'start' and 'limit' params
|
|
1490
|
+
* @param {Number} page The number of the page to load
|
|
1491
|
+
* @param {Object} options See options for {@link #method-load}
|
|
1492
|
+
*/
|
|
1493
|
+
loadPage: function(page, options) {
|
|
1494
|
+
var me = this;
|
|
1495
|
+
|
|
1496
|
+
me.currentPage = page;
|
|
1497
|
+
|
|
1498
|
+
// Copy options into a new object so as not to mutate passed in objects
|
|
1499
|
+
options = Ext.apply({
|
|
1500
|
+
page: page,
|
|
1501
|
+
start: (page - 1) * me.pageSize,
|
|
1502
|
+
limit: me.pageSize,
|
|
1503
|
+
addRecords: !me.clearOnPageLoad
|
|
1504
|
+
}, options);
|
|
1505
|
+
|
|
1506
|
+
if (me.buffered) {
|
|
1507
|
+
return me.loadToPrefetch(options);
|
|
1508
|
+
}
|
|
1509
|
+
me.read(options);
|
|
1510
|
+
},
|
|
1511
|
+
|
|
1512
|
+
/**
|
|
1513
|
+
* Loads the next 'page' in the current data set
|
|
1514
|
+
* @param {Object} options See options for {@link #method-load}
|
|
1515
|
+
*/
|
|
1516
|
+
nextPage: function(options) {
|
|
1517
|
+
this.loadPage(this.currentPage + 1, options);
|
|
1518
|
+
},
|
|
1519
|
+
|
|
1520
|
+
/**
|
|
1521
|
+
* Loads the previous 'page' in the current data set
|
|
1522
|
+
* @param {Object} options See options for {@link #method-load}
|
|
1523
|
+
*/
|
|
1524
|
+
previousPage: function(options) {
|
|
1525
|
+
this.loadPage(this.currentPage - 1, options);
|
|
1526
|
+
},
|
|
1527
|
+
|
|
1528
|
+
// private
|
|
1529
|
+
clearData: function(isLoad) {
|
|
1530
|
+
var me = this,
|
|
1531
|
+
records = me.data.items,
|
|
1532
|
+
i = records.length;
|
|
1533
|
+
|
|
1534
|
+
while (i--) {
|
|
1535
|
+
records[i].unjoin(me);
|
|
1536
|
+
}
|
|
1537
|
+
me.data.clear();
|
|
1538
|
+
if (isLoad !== true || me.clearRemovedOnLoad) {
|
|
1539
|
+
me.removed = [];
|
|
1540
|
+
}
|
|
1541
|
+
},
|
|
1542
|
+
|
|
1543
|
+
loadToPrefetch: function(options) {
|
|
1544
|
+
var me = this,
|
|
1545
|
+
waitForInitialRange = function() {
|
|
1546
|
+
if (me.rangeCached(options.start, options.limit - 1)) {
|
|
1547
|
+
me.pageMap.un('pageAdded', waitForInitialRange);
|
|
1548
|
+
me.guaranteeRange(options.start, (me.viewSize || me.pageSize) - 1);
|
|
1549
|
+
}
|
|
1550
|
+
};
|
|
1551
|
+
|
|
1552
|
+
// Wait for the requested range to become available in the page map
|
|
1553
|
+
me.pageMap.on('pageAdded', waitForInitialRange);
|
|
1554
|
+
return me.prefetch(options || {});
|
|
1555
|
+
},
|
|
1556
|
+
|
|
1557
|
+
// Buffering
|
|
1558
|
+
/**
|
|
1559
|
+
* Prefetches data into the store using its configured {@link #proxy}.
|
|
1560
|
+
* @param {Object} options (Optional) config object, passed into the Ext.data.Operation object before loading.
|
|
1561
|
+
* See {@link #method-load}
|
|
1562
|
+
*/
|
|
1563
|
+
prefetch: function(options) {
|
|
1564
|
+
var me = this,
|
|
1565
|
+
pageSize = me.pageSize,
|
|
1566
|
+
operation;
|
|
1567
|
+
|
|
1568
|
+
// Check pageSize has not been tampered with. That would break page caching
|
|
1569
|
+
if (pageSize) {
|
|
1570
|
+
if (me.lastPageSize && pageSize != me.lastPageSize) {
|
|
1571
|
+
Ext.error.raise("pageSize cannot be dynamically altered");
|
|
1572
|
+
}
|
|
1573
|
+
if (!me.pageMap.pageSize) {
|
|
1574
|
+
me.pageMap.pageSize = pageSize;
|
|
1575
|
+
}
|
|
1576
|
+
}
|
|
1577
|
+
|
|
1578
|
+
// Allow first prefetch call to imply the required page size.
|
|
1579
|
+
else {
|
|
1580
|
+
me.pageSize = me.pageMap.pageSize = pageSize = options.limit;
|
|
1581
|
+
}
|
|
1582
|
+
|
|
1583
|
+
// So that we can check for tampering next time through
|
|
1584
|
+
me.lastPageSize = pageSize;
|
|
1585
|
+
|
|
1586
|
+
// Always get whole pages.
|
|
1587
|
+
if (!options.page) {
|
|
1588
|
+
options.page = me.getPageFromRecordIndex(options.start);
|
|
1589
|
+
options.start = (options.page - 1) * pageSize;
|
|
1590
|
+
options.limit = Math.ceil(options.limit / pageSize) * pageSize;
|
|
1591
|
+
}
|
|
1592
|
+
|
|
1593
|
+
// Currently not requesting this page, then request it...
|
|
1594
|
+
if (!me.pageRequests[options.page]) {
|
|
1595
|
+
|
|
1596
|
+
// Copy options into a new object so as not to mutate passed in objects
|
|
1597
|
+
options = Ext.apply({
|
|
1598
|
+
action : 'read',
|
|
1599
|
+
filters: me.filters.items,
|
|
1600
|
+
sorters: me.sorters.items,
|
|
1601
|
+
|
|
1602
|
+
// Generation # of the page map to which the requested records belong.
|
|
1603
|
+
// If page map is cleared while this request is in flight, the generation will increment and the payload will be rejected
|
|
1604
|
+
generation: me.pageMap.generation
|
|
1605
|
+
}, options);
|
|
1606
|
+
|
|
1607
|
+
operation = new Ext.data.Operation(options);
|
|
1608
|
+
|
|
1609
|
+
if (me.fireEvent('beforeprefetch', me, operation) !== false) {
|
|
1610
|
+
me.loading = true;
|
|
1611
|
+
me.pageRequests[options.page] = me.proxy.read(operation, me.onProxyPrefetch, me);
|
|
1612
|
+
}
|
|
1613
|
+
}
|
|
1614
|
+
|
|
1615
|
+
return me;
|
|
1616
|
+
},
|
|
1617
|
+
|
|
1618
|
+
/**
|
|
1619
|
+
* @private
|
|
1620
|
+
* Cancels all pending prefetch requests.
|
|
1621
|
+
*
|
|
1622
|
+
* This is called when the page map is cleared.
|
|
1623
|
+
*
|
|
1624
|
+
* Any requests which still make it through will be for the previous page map generation
|
|
1625
|
+
* (generation is incremented upon clear), and so will be rejected upon arrival.
|
|
1626
|
+
*/
|
|
1627
|
+
cancelAllPrefetches: function() {
|
|
1628
|
+
var me = this,
|
|
1629
|
+
reqs = me.pageRequests,
|
|
1630
|
+
req,
|
|
1631
|
+
page;
|
|
1632
|
+
|
|
1633
|
+
// If any requests return, we no longer respond to them.
|
|
1634
|
+
if (me.pageMap.events.pageadded) {
|
|
1635
|
+
me.pageMap.events.pageadded.clearListeners();
|
|
1636
|
+
}
|
|
1637
|
+
|
|
1638
|
+
// Cancel all outstanding requests
|
|
1639
|
+
for (page in reqs) {
|
|
1640
|
+
if (reqs.hasOwnProperty(page)) {
|
|
1641
|
+
req = reqs[page];
|
|
1642
|
+
delete reqs[page];
|
|
1643
|
+
delete req.callback;
|
|
1644
|
+
}
|
|
1645
|
+
}
|
|
1646
|
+
},
|
|
1647
|
+
|
|
1648
|
+
/**
|
|
1649
|
+
* Prefetches a page of data.
|
|
1650
|
+
* @param {Number} page The page to prefetch
|
|
1651
|
+
* @param {Object} options (Optional) config object, passed into the Ext.data.Operation object before loading.
|
|
1652
|
+
* See {@link #method-load}
|
|
1653
|
+
*/
|
|
1654
|
+
prefetchPage: function(page, options) {
|
|
1655
|
+
var me = this,
|
|
1656
|
+
pageSize = me.pageSize || me.defaultPageSize,
|
|
1657
|
+
start = (page - 1) * me.pageSize,
|
|
1658
|
+
total = me.totalCount;
|
|
1659
|
+
|
|
1660
|
+
// No more data to prefetch.
|
|
1661
|
+
if (total !== undefined && me.getCount() === total) {
|
|
1662
|
+
return;
|
|
1663
|
+
}
|
|
1664
|
+
|
|
1665
|
+
// Copy options into a new object so as not to mutate passed in objects
|
|
1666
|
+
me.prefetch(Ext.apply({
|
|
1667
|
+
page : page,
|
|
1668
|
+
start : start,
|
|
1669
|
+
limit : pageSize
|
|
1670
|
+
}, options));
|
|
1671
|
+
},
|
|
1672
|
+
|
|
1673
|
+
/**
|
|
1674
|
+
* Called after the configured proxy completes a prefetch operation.
|
|
1675
|
+
* @private
|
|
1676
|
+
* @param {Ext.data.Operation} operation The operation that completed
|
|
1677
|
+
*/
|
|
1678
|
+
onProxyPrefetch: function(operation) {
|
|
1679
|
+
var me = this,
|
|
1680
|
+
resultSet = operation.getResultSet(),
|
|
1681
|
+
records = operation.getRecords(),
|
|
1682
|
+
successful = operation.wasSuccessful(),
|
|
1683
|
+
page = operation.page;
|
|
1684
|
+
|
|
1685
|
+
// Only cache the data if the operation was invoked for the current generation of the page map.
|
|
1686
|
+
// If the generation has changed since the request was fired off, it will have been cancelled.
|
|
1687
|
+
if (operation.generation === me.pageMap.generation) {
|
|
1688
|
+
|
|
1689
|
+
if (resultSet) {
|
|
1690
|
+
me.totalCount = resultSet.total;
|
|
1691
|
+
me.fireEvent('totalcountchange', me.totalCount);
|
|
1692
|
+
}
|
|
1693
|
+
|
|
1694
|
+
// Remove the loaded page from the outstanding pages hash
|
|
1695
|
+
if (page !== undefined) {
|
|
1696
|
+
delete me.pageRequests[page];
|
|
1697
|
+
}
|
|
1698
|
+
|
|
1699
|
+
// Add the page into the page map.
|
|
1700
|
+
// pageAdded event may trigger the onGuaranteedRange
|
|
1701
|
+
if (successful) {
|
|
1702
|
+
me.cachePage(records, operation.page);
|
|
1703
|
+
}
|
|
1704
|
+
|
|
1705
|
+
me.loading = false;
|
|
1706
|
+
me.fireEvent('prefetch', me, records, successful, operation);
|
|
1707
|
+
|
|
1708
|
+
//this is a callback that would have been passed to the 'read' function and is optional
|
|
1709
|
+
Ext.callback(operation.callback, operation.scope || me, [records, operation, successful]);
|
|
1710
|
+
}
|
|
1711
|
+
},
|
|
1712
|
+
|
|
1713
|
+
/**
|
|
1714
|
+
* Caches the records in the prefetch and stripes them with their server-side
|
|
1715
|
+
* index.
|
|
1716
|
+
* @private
|
|
1717
|
+
* @param {Ext.data.Model[]} records The records to cache
|
|
1718
|
+
* @param {Ext.data.Operation} The associated operation
|
|
1719
|
+
*/
|
|
1720
|
+
cachePage: function(records, page) {
|
|
1721
|
+
var me = this;
|
|
1722
|
+
|
|
1723
|
+
if (!Ext.isDefined(me.totalCount)) {
|
|
1724
|
+
me.totalCount = records.length;
|
|
1725
|
+
me.fireEvent('totalcountchange', me.totalCount);
|
|
1726
|
+
}
|
|
1727
|
+
|
|
1728
|
+
// Add the fetched page into the pageCache
|
|
1729
|
+
me.pageMap.addPage(page, records);
|
|
1730
|
+
},
|
|
1731
|
+
|
|
1732
|
+
/**
|
|
1733
|
+
* Determines if the passed range is available in the page cache.
|
|
1734
|
+
* @private
|
|
1735
|
+
* @param {Number} start The start index
|
|
1736
|
+
* @param {Number} end The end index in the range
|
|
1737
|
+
*/
|
|
1738
|
+
rangeCached: function(start, end) {
|
|
1739
|
+
return this.pageMap && this.pageMap.hasRange(start, end);
|
|
1740
|
+
},
|
|
1741
|
+
|
|
1742
|
+
/**
|
|
1743
|
+
* Determines if the passed page is available in the page cache.
|
|
1744
|
+
* @private
|
|
1745
|
+
* @param {Number} page The page to find in the page cache.
|
|
1746
|
+
*/
|
|
1747
|
+
pageCached: function(page) {
|
|
1748
|
+
return this.pageMap && this.pageMap.hasPage(page);
|
|
1749
|
+
},
|
|
1750
|
+
|
|
1751
|
+
/**
|
|
1752
|
+
* Determines if the passed range is available in the page cache.
|
|
1753
|
+
* @private
|
|
1754
|
+
* @deprecated 4.1.0 use {@link #rangeCached} instead
|
|
1755
|
+
* @param {Number} start The start index
|
|
1756
|
+
* @param {Number} end The end index in the range
|
|
1757
|
+
*/
|
|
1758
|
+
rangeSatisfied: function(start, end) {
|
|
1759
|
+
return this.rangeCached(start, end);
|
|
1760
|
+
},
|
|
1761
|
+
|
|
1762
|
+
/**
|
|
1763
|
+
* Determines the page from a record index
|
|
1764
|
+
* @param {Number} index The record index
|
|
1765
|
+
* @return {Number} The page the record belongs to
|
|
1766
|
+
*/
|
|
1767
|
+
getPageFromRecordIndex: function(index) {
|
|
1768
|
+
return Math.floor(index / this.pageSize) + 1;
|
|
1769
|
+
},
|
|
1770
|
+
|
|
1771
|
+
/**
|
|
1772
|
+
* Handles a guaranteed range being loaded
|
|
1773
|
+
* @private
|
|
1774
|
+
*/
|
|
1775
|
+
onGuaranteedRange: function(options) {
|
|
1776
|
+
var me = this,
|
|
1777
|
+
totalCount = me.getTotalCount(),
|
|
1778
|
+
start = options.prefetchStart,
|
|
1779
|
+
end = ((totalCount - 1) < options.prefetchEnd) ? totalCount - 1 : options.prefetchEnd,
|
|
1780
|
+
range;
|
|
1781
|
+
|
|
1782
|
+
end = Math.max(0, end);
|
|
1783
|
+
|
|
1784
|
+
//<debug>
|
|
1785
|
+
if (start > end) {
|
|
1786
|
+
Ext.log({
|
|
1787
|
+
level: 'warn',
|
|
1788
|
+
msg: 'Start (' + start + ') was greater than end (' + end +
|
|
1789
|
+
') for the range of records requested (' + start + '-' +
|
|
1790
|
+
options.prefetchEnd + ')' + (this.storeId ? ' from store "' + this.storeId + '"' : '')
|
|
1791
|
+
});
|
|
1792
|
+
}
|
|
1793
|
+
//</debug>
|
|
1794
|
+
|
|
1795
|
+
range = me.pageMap.getRange(start, end);
|
|
1796
|
+
me.fireEvent('guaranteedrange', range, start, end);
|
|
1797
|
+
if (options.cb) {
|
|
1798
|
+
options.cb.call(options.scope || me, range, start, end);
|
|
1799
|
+
}
|
|
1800
|
+
},
|
|
1801
|
+
|
|
1802
|
+
/**
|
|
1803
|
+
* Ensures that the specified range of rows is present in the cache.
|
|
1804
|
+
*
|
|
1805
|
+
* Converts the row range to a page range and then only load pages which are not already
|
|
1806
|
+
* present in the page cache.
|
|
1807
|
+
*/
|
|
1808
|
+
prefetchRange: function(start, end) {
|
|
1809
|
+
var me = this,
|
|
1810
|
+
startPage, endPage, page;
|
|
1811
|
+
if (!me.rangeCached(start, end)) {
|
|
1812
|
+
startPage = me.getPageFromRecordIndex(start);
|
|
1813
|
+
endPage = me.getPageFromRecordIndex(end);
|
|
1814
|
+
|
|
1815
|
+
// Ensure that the page cache's max size is correct.
|
|
1816
|
+
// Our purgePageCount is the number of additional pages *outside of the required range* which
|
|
1817
|
+
// may be kept in the cache. A purgePageCount of zero means unlimited.
|
|
1818
|
+
me.pageMap.maxSize = me.purgePageCount ? (endPage - startPage + 1) + me.purgePageCount : 0;
|
|
1819
|
+
|
|
1820
|
+
// We have the range, but ensure that we have a "buffer" of pages around it.
|
|
1821
|
+
for (page = startPage; page <= endPage; page++) {
|
|
1822
|
+
if (!me.pageCached(page)) {
|
|
1823
|
+
me.prefetchPage(page);
|
|
1824
|
+
}
|
|
1825
|
+
}
|
|
1826
|
+
}
|
|
1827
|
+
},
|
|
1828
|
+
|
|
1829
|
+
/**
|
|
1830
|
+
* Guarantee a specific range, this will load the store with a range (that
|
|
1831
|
+
* must be the pageSize or smaller) and take care of any loading that may
|
|
1832
|
+
* be necessary.
|
|
1833
|
+
*/
|
|
1834
|
+
guaranteeRange: function(start, end, cb, scope) {
|
|
1835
|
+
// Sanity check end point to be within dataset range
|
|
1836
|
+
end = (end > this.totalCount) ? this.totalCount - 1 : end;
|
|
1837
|
+
|
|
1838
|
+
var me = this,
|
|
1839
|
+
lastRequestStart = me.lastRequestStart,
|
|
1840
|
+
options = {
|
|
1841
|
+
prefetchStart: start,
|
|
1842
|
+
prefetchEnd: end,
|
|
1843
|
+
cb: cb,
|
|
1844
|
+
scope: scope
|
|
1845
|
+
},
|
|
1846
|
+
pageAddHandler;
|
|
1847
|
+
|
|
1848
|
+
me.lastRequestStart = start;
|
|
1849
|
+
|
|
1850
|
+
// If data request can be satisfied from the page cache
|
|
1851
|
+
if (me.rangeCached(start, end)) {
|
|
1852
|
+
|
|
1853
|
+
// Attempt to keep the page cache primed with pages which encompass the live data range
|
|
1854
|
+
if (start < lastRequestStart) {
|
|
1855
|
+
start = Math.max(start - me.leadingBufferZone, 0);
|
|
1856
|
+
end = Math.min(end + me.trailingBufferZone, me.totalCount - 1);
|
|
1857
|
+
} else {
|
|
1858
|
+
start = Math.max(Math.min(start - me.trailingBufferZone, me.totalCount - me.pageSize), 0);
|
|
1859
|
+
end = Math.min(end + me.leadingBufferZone, me.totalCount - 1);
|
|
1860
|
+
}
|
|
1861
|
+
|
|
1862
|
+
// If the prefetch window calculated round the requested range is not already satisfied in the page cache,
|
|
1863
|
+
// then arrange to prefetch it.
|
|
1864
|
+
if (!me.rangeCached(start, end)) {
|
|
1865
|
+
// We have the range, but ensure that we have a "buffer" of pages around it.
|
|
1866
|
+
me.prefetchRange(start, end);
|
|
1867
|
+
}
|
|
1868
|
+
me.onGuaranteedRange(options);
|
|
1869
|
+
}
|
|
1870
|
+
// At least some of the requested range needs loading from server
|
|
1871
|
+
else {
|
|
1872
|
+
// Private event used by the LoadMask class to perform masking when the range required for rendering is not found in the cache
|
|
1873
|
+
me.fireEvent('cachemiss', me, start, end);
|
|
1874
|
+
|
|
1875
|
+
// Calculate a prefetch range which is centered on the requested data
|
|
1876
|
+
start = Math.min(Math.max(Math.floor(start - ((me.leadingBufferZone + me.trailingBufferZone) / 2)), 0), me.totalCount - me.pageSize);
|
|
1877
|
+
end = Math.min(Math.max(Math.ceil (end + ((me.leadingBufferZone + me.trailingBufferZone) / 2)), 0), me.totalCount - 1);
|
|
1878
|
+
|
|
1879
|
+
// Add a pageAdded listener, and as soon as the requested range is loaded, fire the rangeguaranteed event
|
|
1880
|
+
pageAddHandler = function(page, records) {
|
|
1881
|
+
if (me.rangeCached(options.prefetchStart, options.prefetchEnd)) {
|
|
1882
|
+
// Private event used by the LoadMask class to unmask when the range required for rendering has been loaded into the cache
|
|
1883
|
+
me.fireEvent('cachefilled', me, start, end);
|
|
1884
|
+
me.pageMap.un('pageAdded', pageAddHandler);
|
|
1885
|
+
me.onGuaranteedRange(options);
|
|
1886
|
+
}
|
|
1887
|
+
};
|
|
1888
|
+
me.pageMap.on('pageAdded', pageAddHandler);
|
|
1889
|
+
|
|
1890
|
+
// Prioritize the request for the *exact range that the UI is asking for*.
|
|
1891
|
+
// When a page request is in flight, it will not be requested again by checking the me.pageRequests hash,
|
|
1892
|
+
// so the request after this will only request the *remaining* unrequested pages .
|
|
1893
|
+
me.prefetchRange(options.prefetchStart, options.prefetchEnd);
|
|
1894
|
+
|
|
1895
|
+
// Load the pages that need loading.
|
|
1896
|
+
me.prefetchRange(start, end);
|
|
1897
|
+
}
|
|
1898
|
+
},
|
|
1899
|
+
|
|
1900
|
+
// because prefetchData is stored by index
|
|
1901
|
+
// this invalidates all of the prefetchedData
|
|
1902
|
+
sort: function() {
|
|
1903
|
+
var me = this,
|
|
1904
|
+
prefetchData = me.pageMap;
|
|
1905
|
+
|
|
1906
|
+
if (me.buffered) {
|
|
1907
|
+
if (me.remoteSort) {
|
|
1908
|
+
prefetchData.clear();
|
|
1909
|
+
me.callParent(arguments);
|
|
1910
|
+
} else {
|
|
1911
|
+
me.callParent(arguments);
|
|
1912
|
+
}
|
|
1913
|
+
} else {
|
|
1914
|
+
me.callParent(arguments);
|
|
1915
|
+
}
|
|
1916
|
+
},
|
|
1917
|
+
|
|
1918
|
+
// overriden to provide striping of the indexes as sorting occurs.
|
|
1919
|
+
// this cannot be done inside of sort because datachanged has already
|
|
1920
|
+
// fired and will trigger a repaint of the bound view.
|
|
1921
|
+
doSort: function(sorterFn) {
|
|
1922
|
+
var me = this,
|
|
1923
|
+
range,
|
|
1924
|
+
ln,
|
|
1925
|
+
i;
|
|
1926
|
+
if (me.remoteSort) {
|
|
1927
|
+
|
|
1928
|
+
// For a buffered Store, we have to clear the prefetch cache since it is keyed by the index within the dataset.
|
|
1929
|
+
// Then we must prefetch the new page 1, and when that arrives, reload the visible part of the Store
|
|
1930
|
+
// via the guaranteedrange event
|
|
1931
|
+
if (me.buffered) {
|
|
1932
|
+
me.pageMap.clear();
|
|
1933
|
+
me.loadPage(1);
|
|
1934
|
+
} else {
|
|
1935
|
+
//the load function will pick up the new sorters and request the sorted data from the proxy
|
|
1936
|
+
me.load();
|
|
1937
|
+
}
|
|
1938
|
+
} else {
|
|
1939
|
+
me.data.sortBy(sorterFn);
|
|
1940
|
+
if (!me.buffered) {
|
|
1941
|
+
range = me.getRange();
|
|
1942
|
+
ln = range.length;
|
|
1943
|
+
i = 0;
|
|
1944
|
+
for (; i < ln; i++) {
|
|
1945
|
+
range[i].index = i;
|
|
1946
|
+
}
|
|
1947
|
+
}
|
|
1948
|
+
me.fireEvent('datachanged', me);
|
|
1949
|
+
me.fireEvent('refresh', me);
|
|
1950
|
+
}
|
|
1951
|
+
},
|
|
1952
|
+
|
|
1953
|
+
/**
|
|
1954
|
+
* Finds the index of the first matching Record in this store by a specific field value.
|
|
1955
|
+
*
|
|
1956
|
+
* When store is filtered, finds records only within filter.
|
|
1957
|
+
*
|
|
1958
|
+
* @param {String} fieldName The name of the Record field to test.
|
|
1959
|
+
* @param {String/RegExp} value Either a string that the field value
|
|
1960
|
+
* should begin with, or a RegExp to test against the field.
|
|
1961
|
+
* @param {Number} [startIndex=0] The index to start searching at
|
|
1962
|
+
* @param {Boolean} [anyMatch=false] True to match any part of the string, not just the beginning
|
|
1963
|
+
* @param {Boolean} [caseSensitive=false] True for case sensitive comparison
|
|
1964
|
+
* @param {Boolean} [exactMatch=false] True to force exact match (^ and $ characters added to the regex).
|
|
1965
|
+
* @return {Number} The matched index or -1
|
|
1966
|
+
*/
|
|
1967
|
+
find: function(property, value, start, anyMatch, caseSensitive, exactMatch) {
|
|
1968
|
+
var fn = this.createFilterFn(property, value, anyMatch, caseSensitive, exactMatch);
|
|
1969
|
+
return fn ? this.data.findIndexBy(fn, null, start) : -1;
|
|
1970
|
+
},
|
|
1971
|
+
|
|
1972
|
+
/**
|
|
1973
|
+
* Finds the first matching Record in this store by a specific field value.
|
|
1974
|
+
*
|
|
1975
|
+
* When store is filtered, finds records only within filter.
|
|
1976
|
+
*
|
|
1977
|
+
* @param {String} fieldName The name of the Record field to test.
|
|
1978
|
+
* @param {String/RegExp} value Either a string that the field value
|
|
1979
|
+
* should begin with, or a RegExp to test against the field.
|
|
1980
|
+
* @param {Number} [startIndex=0] The index to start searching at
|
|
1981
|
+
* @param {Boolean} [anyMatch=false] True to match any part of the string, not just the beginning
|
|
1982
|
+
* @param {Boolean} [caseSensitive=false] True for case sensitive comparison
|
|
1983
|
+
* @param {Boolean} [exactMatch=false] True to force exact match (^ and $ characters added to the regex).
|
|
1984
|
+
* @return {Ext.data.Model} The matched record or null
|
|
1985
|
+
*/
|
|
1986
|
+
findRecord: function() {
|
|
1987
|
+
var me = this,
|
|
1988
|
+
index = me.find.apply(me, arguments);
|
|
1989
|
+
return index !== -1 ? me.getAt(index) : null;
|
|
1990
|
+
},
|
|
1991
|
+
|
|
1992
|
+
/**
|
|
1993
|
+
* @private
|
|
1994
|
+
* Returns a filter function used to test a the given property's value. Defers most of the work to
|
|
1995
|
+
* Ext.util.MixedCollection's createValueMatcher function.
|
|
1996
|
+
*
|
|
1997
|
+
* @param {String} property The property to create the filter function for
|
|
1998
|
+
* @param {String/RegExp} value The string/regex to compare the property value to
|
|
1999
|
+
* @param {Boolean} [anyMatch=false] True if we don't care if the filter value is not the full value.
|
|
2000
|
+
* @param {Boolean} [caseSensitive=false] True to create a case-sensitive regex.
|
|
2001
|
+
* @param {Boolean} [exactMatch=false] True to force exact match (^ and $ characters added to the regex).
|
|
2002
|
+
* Ignored if anyMatch is true.
|
|
2003
|
+
*/
|
|
2004
|
+
createFilterFn: function(property, value, anyMatch, caseSensitive, exactMatch) {
|
|
2005
|
+
if (Ext.isEmpty(value)) {
|
|
2006
|
+
return false;
|
|
2007
|
+
}
|
|
2008
|
+
value = this.data.createValueMatcher(value, anyMatch, caseSensitive, exactMatch);
|
|
2009
|
+
return function(r) {
|
|
2010
|
+
return value.test(r.data[property]);
|
|
2011
|
+
};
|
|
2012
|
+
},
|
|
2013
|
+
|
|
2014
|
+
/**
|
|
2015
|
+
* Finds the index of the first matching Record in this store by a specific field value.
|
|
2016
|
+
*
|
|
2017
|
+
* When store is filtered, finds records only within filter.
|
|
2018
|
+
*
|
|
2019
|
+
* @param {String} fieldName The name of the Record field to test.
|
|
2020
|
+
* @param {Object} value The value to match the field against.
|
|
2021
|
+
* @param {Number} [startIndex=0] The index to start searching at
|
|
2022
|
+
* @return {Number} The matched index or -1
|
|
2023
|
+
*/
|
|
2024
|
+
findExact: function(property, value, start) {
|
|
2025
|
+
return this.data.findIndexBy(function(rec) {
|
|
2026
|
+
return rec.isEqual(rec.get(property), value);
|
|
2027
|
+
},
|
|
2028
|
+
this, start);
|
|
2029
|
+
},
|
|
2030
|
+
|
|
2031
|
+
/**
|
|
2032
|
+
* Find the index of the first matching Record in this Store by a function.
|
|
2033
|
+
* If the function returns `true` it is considered a match.
|
|
2034
|
+
*
|
|
2035
|
+
* When store is filtered, finds records only within filter.
|
|
2036
|
+
*
|
|
2037
|
+
* @param {Function} fn The function to be called. It will be passed the following parameters:
|
|
2038
|
+
* @param {Ext.data.Model} fn.record The record to test for filtering. Access field values
|
|
2039
|
+
* using {@link Ext.data.Model#get}.
|
|
2040
|
+
* @param {Object} fn.id The ID of the Record passed.
|
|
2041
|
+
* @param {Object} [scope] The scope (this reference) in which the function is executed.
|
|
2042
|
+
* Defaults to this Store.
|
|
2043
|
+
* @param {Number} [startIndex=0] The index to start searching at
|
|
2044
|
+
* @return {Number} The matched index or -1
|
|
2045
|
+
*/
|
|
2046
|
+
findBy: function(fn, scope, start) {
|
|
2047
|
+
return this.data.findIndexBy(fn, scope, start);
|
|
2048
|
+
},
|
|
2049
|
+
|
|
2050
|
+
/**
|
|
2051
|
+
* Collects unique values for a particular dataIndex from this store.
|
|
2052
|
+
*
|
|
2053
|
+
* @param {String} dataIndex The property to collect
|
|
2054
|
+
* @param {Boolean} [allowNull] Pass true to allow null, undefined or empty string values
|
|
2055
|
+
* @param {Boolean} [bypassFilter] Pass true to collect from all records, even ones which are filtered.
|
|
2056
|
+
* @return {Object[]} An array of the unique values
|
|
2057
|
+
*/
|
|
2058
|
+
collect: function(dataIndex, allowNull, bypassFilter) {
|
|
2059
|
+
var me = this,
|
|
2060
|
+
data = (bypassFilter === true && me.snapshot) ? me.snapshot : me.data;
|
|
2061
|
+
|
|
2062
|
+
return data.collect(dataIndex, 'data', allowNull);
|
|
2063
|
+
},
|
|
2064
|
+
|
|
2065
|
+
/**
|
|
2066
|
+
* Gets the number of records in store.
|
|
2067
|
+
*
|
|
2068
|
+
* If using paging, this may not be the total size of the dataset. If the data object
|
|
2069
|
+
* used by the Reader contains the dataset size, then the {@link #getTotalCount} function returns
|
|
2070
|
+
* the dataset size. **Note**: see the Important note in {@link #method-load}.
|
|
2071
|
+
*
|
|
2072
|
+
* When store is filtered, it's the number of records matching the filter.
|
|
2073
|
+
*
|
|
2074
|
+
* @return {Number} The number of Records in the Store.
|
|
2075
|
+
*/
|
|
2076
|
+
getCount: function() {
|
|
2077
|
+
return this.data.length || 0;
|
|
2078
|
+
},
|
|
2079
|
+
|
|
2080
|
+
/**
|
|
2081
|
+
* Returns the total number of {@link Ext.data.Model Model} instances that the {@link Ext.data.proxy.Proxy Proxy}
|
|
2082
|
+
* indicates exist. This will usually differ from {@link #getCount} when using paging - getCount returns the
|
|
2083
|
+
* number of records loaded into the Store at the moment, getTotalCount returns the number of records that
|
|
2084
|
+
* could be loaded into the Store if the Store contained all data
|
|
2085
|
+
* @return {Number} The total number of Model instances available via the Proxy. 0 returned if
|
|
2086
|
+
* no value has been set via the reader.
|
|
2087
|
+
*/
|
|
2088
|
+
getTotalCount: function() {
|
|
2089
|
+
return this.totalCount || 0;
|
|
2090
|
+
},
|
|
2091
|
+
|
|
2092
|
+
/**
|
|
2093
|
+
* Get the Record at the specified index.
|
|
2094
|
+
*
|
|
2095
|
+
* The index is effected by filtering.
|
|
2096
|
+
*
|
|
2097
|
+
* @param {Number} index The index of the Record to find.
|
|
2098
|
+
* @return {Ext.data.Model} The Record at the passed index. Returns undefined if not found.
|
|
2099
|
+
*/
|
|
2100
|
+
getAt: function(index) {
|
|
2101
|
+
return this.data.getAt(index);
|
|
2102
|
+
},
|
|
2103
|
+
|
|
2104
|
+
/**
|
|
2105
|
+
* Returns a range of Records between specified indices.
|
|
2106
|
+
*
|
|
2107
|
+
* This method is effected by filtering.
|
|
2108
|
+
*
|
|
2109
|
+
* @param {Number} [startIndex=0] The starting index
|
|
2110
|
+
* @param {Number} [endIndex] The ending index. Defaults to the last Record in the Store.
|
|
2111
|
+
* @return {Ext.data.Model[]} An array of Records
|
|
2112
|
+
*/
|
|
2113
|
+
getRange: function(start, end) {
|
|
2114
|
+
return this.data.getRange(start, end);
|
|
2115
|
+
},
|
|
2116
|
+
|
|
2117
|
+
/**
|
|
2118
|
+
* Get the Record with the specified id.
|
|
2119
|
+
*
|
|
2120
|
+
* This method is not effected by filtering, lookup will be performed from all records
|
|
2121
|
+
* inside the store, filtered or not.
|
|
2122
|
+
*
|
|
2123
|
+
* @param {Mixed} id The id of the Record to find.
|
|
2124
|
+
* @return {Ext.data.Model} The Record with the passed id. Returns null if not found.
|
|
2125
|
+
*/
|
|
2126
|
+
getById: function(id) {
|
|
2127
|
+
return (this.snapshot || this.data).findBy(function(record) {
|
|
2128
|
+
return record.getId() === id;
|
|
2129
|
+
});
|
|
2130
|
+
},
|
|
2131
|
+
|
|
2132
|
+
/**
|
|
2133
|
+
* Get the index of the record within the store.
|
|
2134
|
+
*
|
|
2135
|
+
* When store is filtered, records outside of filter will not be found.
|
|
2136
|
+
*
|
|
2137
|
+
* @param {Ext.data.Model} record The Ext.data.Model object to find.
|
|
2138
|
+
* @return {Number} The index of the passed Record. Returns -1 if not found.
|
|
2139
|
+
*/
|
|
2140
|
+
indexOf: function(record) {
|
|
2141
|
+
return this.data.indexOf(record);
|
|
2142
|
+
},
|
|
2143
|
+
|
|
2144
|
+
|
|
2145
|
+
/**
|
|
2146
|
+
* Get the index within the entire dataset. From 0 to the totalCount.
|
|
2147
|
+
*
|
|
2148
|
+
* Like #indexOf, this method is effected by filtering.
|
|
2149
|
+
*
|
|
2150
|
+
* @param {Ext.data.Model} record The Ext.data.Model object to find.
|
|
2151
|
+
* @return {Number} The index of the passed Record. Returns -1 if not found.
|
|
2152
|
+
*/
|
|
2153
|
+
indexOfTotal: function(record) {
|
|
2154
|
+
var index = record.index;
|
|
2155
|
+
if (index || index === 0) {
|
|
2156
|
+
return index;
|
|
2157
|
+
}
|
|
2158
|
+
return this.indexOf(record);
|
|
2159
|
+
},
|
|
2160
|
+
|
|
2161
|
+
/**
|
|
2162
|
+
* Get the index within the store of the Record with the passed id.
|
|
2163
|
+
*
|
|
2164
|
+
* Like #indexOf, this method is effected by filtering.
|
|
2165
|
+
*
|
|
2166
|
+
* @param {String} id The id of the Record to find.
|
|
2167
|
+
* @return {Number} The index of the Record. Returns -1 if not found.
|
|
2168
|
+
*/
|
|
2169
|
+
indexOfId: function(id) {
|
|
2170
|
+
return this.indexOf(this.getById(id));
|
|
2171
|
+
},
|
|
2172
|
+
|
|
2173
|
+
/**
|
|
2174
|
+
* Removes all items from the store.
|
|
2175
|
+
* @param {Boolean} silent Prevent the `clear` event from being fired.
|
|
2176
|
+
*/
|
|
2177
|
+
removeAll: function(silent) {
|
|
2178
|
+
var me = this;
|
|
2179
|
+
|
|
2180
|
+
me.clearData();
|
|
2181
|
+
if (me.snapshot) {
|
|
2182
|
+
me.snapshot.clear();
|
|
2183
|
+
}
|
|
2184
|
+
|
|
2185
|
+
// Special handling to synch the PageMap only for removeAll
|
|
2186
|
+
// TODO: handle other store/data modifications WRT buffered Stores.
|
|
2187
|
+
if (me.pageMap) {
|
|
2188
|
+
me.pageMap.clear();
|
|
2189
|
+
}
|
|
2190
|
+
if (silent !== true) {
|
|
2191
|
+
me.fireEvent('clear', me);
|
|
2192
|
+
}
|
|
2193
|
+
},
|
|
2194
|
+
|
|
2195
|
+
/*
|
|
2196
|
+
* Aggregation methods
|
|
2197
|
+
*/
|
|
2198
|
+
|
|
2199
|
+
/**
|
|
2200
|
+
* Convenience function for getting the first model instance in the store.
|
|
2201
|
+
*
|
|
2202
|
+
* When store is filtered, will return first item within the filter.
|
|
2203
|
+
*
|
|
2204
|
+
* @param {Boolean} [grouped] True to perform the operation for each group
|
|
2205
|
+
* in the store. The value returned will be an object literal with the key being the group
|
|
2206
|
+
* name and the first record being the value. The grouped parameter is only honored if
|
|
2207
|
+
* the store has a groupField.
|
|
2208
|
+
* @return {Ext.data.Model/undefined} The first model instance in the store, or undefined
|
|
2209
|
+
*/
|
|
2210
|
+
first: function(grouped) {
|
|
2211
|
+
var me = this;
|
|
2212
|
+
|
|
2213
|
+
if (grouped && me.isGrouped()) {
|
|
2214
|
+
return me.aggregate(function(records) {
|
|
2215
|
+
return records.length ? records[0] : undefined;
|
|
2216
|
+
}, me, true);
|
|
2217
|
+
} else {
|
|
2218
|
+
return me.data.first();
|
|
2219
|
+
}
|
|
2220
|
+
},
|
|
2221
|
+
|
|
2222
|
+
/**
|
|
2223
|
+
* Convenience function for getting the last model instance in the store.
|
|
2224
|
+
*
|
|
2225
|
+
* When store is filtered, will return last item within the filter.
|
|
2226
|
+
*
|
|
2227
|
+
* @param {Boolean} [grouped] True to perform the operation for each group
|
|
2228
|
+
* in the store. The value returned will be an object literal with the key being the group
|
|
2229
|
+
* name and the last record being the value. The grouped parameter is only honored if
|
|
2230
|
+
* the store has a groupField.
|
|
2231
|
+
* @return {Ext.data.Model/undefined} The last model instance in the store, or undefined
|
|
2232
|
+
*/
|
|
2233
|
+
last: function(grouped) {
|
|
2234
|
+
var me = this;
|
|
2235
|
+
|
|
2236
|
+
if (grouped && me.isGrouped()) {
|
|
2237
|
+
return me.aggregate(function(records) {
|
|
2238
|
+
var len = records.length;
|
|
2239
|
+
return len ? records[len - 1] : undefined;
|
|
2240
|
+
}, me, true);
|
|
2241
|
+
} else {
|
|
2242
|
+
return me.data.last();
|
|
2243
|
+
}
|
|
2244
|
+
},
|
|
2245
|
+
|
|
2246
|
+
/**
|
|
2247
|
+
* Sums the value of `property` for each {@link Ext.data.Model record} between `start`
|
|
2248
|
+
* and `end` and returns the result.
|
|
2249
|
+
*
|
|
2250
|
+
* When store is filtered, only sums items within the filter.
|
|
2251
|
+
*
|
|
2252
|
+
* @param {String} field A field in each record
|
|
2253
|
+
* @param {Boolean} [grouped] True to perform the operation for each group
|
|
2254
|
+
* in the store. The value returned will be an object literal with the key being the group
|
|
2255
|
+
* name and the sum for that group being the value. The grouped parameter is only honored if
|
|
2256
|
+
* the store has a groupField.
|
|
2257
|
+
* @return {Number} The sum
|
|
2258
|
+
*/
|
|
2259
|
+
sum: function(field, grouped) {
|
|
2260
|
+
var me = this;
|
|
2261
|
+
|
|
2262
|
+
if (grouped && me.isGrouped()) {
|
|
2263
|
+
return me.aggregate(me.getSum, me, true, [field]);
|
|
2264
|
+
} else {
|
|
2265
|
+
return me.getSum(me.data.items, field);
|
|
2266
|
+
}
|
|
2267
|
+
},
|
|
2268
|
+
|
|
2269
|
+
// @private, see sum
|
|
2270
|
+
getSum: function(records, field) {
|
|
2271
|
+
var total = 0,
|
|
2272
|
+
i = 0,
|
|
2273
|
+
len = records.length;
|
|
2274
|
+
|
|
2275
|
+
for (; i < len; ++i) {
|
|
2276
|
+
total += records[i].get(field);
|
|
2277
|
+
}
|
|
2278
|
+
|
|
2279
|
+
return total;
|
|
2280
|
+
},
|
|
2281
|
+
|
|
2282
|
+
/**
|
|
2283
|
+
* Gets the count of items in the store.
|
|
2284
|
+
*
|
|
2285
|
+
* When store is filtered, only items within the filter are counted.
|
|
2286
|
+
*
|
|
2287
|
+
* @param {Boolean} [grouped] True to perform the operation for each group
|
|
2288
|
+
* in the store. The value returned will be an object literal with the key being the group
|
|
2289
|
+
* name and the count for each group being the value. The grouped parameter is only honored if
|
|
2290
|
+
* the store has a groupField.
|
|
2291
|
+
* @return {Number} the count
|
|
2292
|
+
*/
|
|
2293
|
+
count: function(grouped) {
|
|
2294
|
+
var me = this;
|
|
2295
|
+
|
|
2296
|
+
if (grouped && me.isGrouped()) {
|
|
2297
|
+
return me.aggregate(function(records) {
|
|
2298
|
+
return records.length;
|
|
2299
|
+
}, me, true);
|
|
2300
|
+
} else {
|
|
2301
|
+
return me.getCount();
|
|
2302
|
+
}
|
|
2303
|
+
},
|
|
2304
|
+
|
|
2305
|
+
/**
|
|
2306
|
+
* Gets the minimum value in the store.
|
|
2307
|
+
*
|
|
2308
|
+
* When store is filtered, only items within the filter are aggregated.
|
|
2309
|
+
*
|
|
2310
|
+
* @param {String} field The field in each record
|
|
2311
|
+
* @param {Boolean} [grouped] True to perform the operation for each group
|
|
2312
|
+
* in the store. The value returned will be an object literal with the key being the group
|
|
2313
|
+
* name and the minimum in the group being the value. The grouped parameter is only honored if
|
|
2314
|
+
* the store has a groupField.
|
|
2315
|
+
* @return {Object} The minimum value, if no items exist, undefined.
|
|
2316
|
+
*/
|
|
2317
|
+
min: function(field, grouped) {
|
|
2318
|
+
var me = this;
|
|
2319
|
+
|
|
2320
|
+
if (grouped && me.isGrouped()) {
|
|
2321
|
+
return me.aggregate(me.getMin, me, true, [field]);
|
|
2322
|
+
} else {
|
|
2323
|
+
return me.getMin(me.data.items, field);
|
|
2324
|
+
}
|
|
2325
|
+
},
|
|
2326
|
+
|
|
2327
|
+
// @private, see min
|
|
2328
|
+
getMin: function(records, field) {
|
|
2329
|
+
var i = 1,
|
|
2330
|
+
len = records.length,
|
|
2331
|
+
value, min;
|
|
2332
|
+
|
|
2333
|
+
if (len > 0) {
|
|
2334
|
+
min = records[0].get(field);
|
|
2335
|
+
}
|
|
2336
|
+
|
|
2337
|
+
for (; i < len; ++i) {
|
|
2338
|
+
value = records[i].get(field);
|
|
2339
|
+
if (value < min) {
|
|
2340
|
+
min = value;
|
|
2341
|
+
}
|
|
2342
|
+
}
|
|
2343
|
+
return min;
|
|
2344
|
+
},
|
|
2345
|
+
|
|
2346
|
+
/**
|
|
2347
|
+
* Gets the maximum value in the store.
|
|
2348
|
+
*
|
|
2349
|
+
* When store is filtered, only items within the filter are aggregated.
|
|
2350
|
+
*
|
|
2351
|
+
* @param {String} field The field in each record
|
|
2352
|
+
* @param {Boolean} [grouped] True to perform the operation for each group
|
|
2353
|
+
* in the store. The value returned will be an object literal with the key being the group
|
|
2354
|
+
* name and the maximum in the group being the value. The grouped parameter is only honored if
|
|
2355
|
+
* the store has a groupField.
|
|
2356
|
+
* @return {Object} The maximum value, if no items exist, undefined.
|
|
2357
|
+
*/
|
|
2358
|
+
max: function(field, grouped) {
|
|
2359
|
+
var me = this;
|
|
2360
|
+
|
|
2361
|
+
if (grouped && me.isGrouped()) {
|
|
2362
|
+
return me.aggregate(me.getMax, me, true, [field]);
|
|
2363
|
+
} else {
|
|
2364
|
+
return me.getMax(me.data.items, field);
|
|
2365
|
+
}
|
|
2366
|
+
},
|
|
2367
|
+
|
|
2368
|
+
// @private, see max
|
|
2369
|
+
getMax: function(records, field) {
|
|
2370
|
+
var i = 1,
|
|
2371
|
+
len = records.length,
|
|
2372
|
+
value,
|
|
2373
|
+
max;
|
|
2374
|
+
|
|
2375
|
+
if (len > 0) {
|
|
2376
|
+
max = records[0].get(field);
|
|
2377
|
+
}
|
|
2378
|
+
|
|
2379
|
+
for (; i < len; ++i) {
|
|
2380
|
+
value = records[i].get(field);
|
|
2381
|
+
if (value > max) {
|
|
2382
|
+
max = value;
|
|
2383
|
+
}
|
|
2384
|
+
}
|
|
2385
|
+
return max;
|
|
2386
|
+
},
|
|
2387
|
+
|
|
2388
|
+
/**
|
|
2389
|
+
* Gets the average value in the store.
|
|
2390
|
+
*
|
|
2391
|
+
* When store is filtered, only items within the filter are aggregated.
|
|
2392
|
+
*
|
|
2393
|
+
* @param {String} field The field in each record
|
|
2394
|
+
* @param {Boolean} [grouped] True to perform the operation for each group
|
|
2395
|
+
* in the store. The value returned will be an object literal with the key being the group
|
|
2396
|
+
* name and the group average being the value. The grouped parameter is only honored if
|
|
2397
|
+
* the store has a groupField.
|
|
2398
|
+
* @return {Object} The average value, if no items exist, 0.
|
|
2399
|
+
*/
|
|
2400
|
+
average: function(field, grouped) {
|
|
2401
|
+
var me = this;
|
|
2402
|
+
if (grouped && me.isGrouped()) {
|
|
2403
|
+
return me.aggregate(me.getAverage, me, true, [field]);
|
|
2404
|
+
} else {
|
|
2405
|
+
return me.getAverage(me.data.items, field);
|
|
2406
|
+
}
|
|
2407
|
+
},
|
|
2408
|
+
|
|
2409
|
+
// @private, see average
|
|
2410
|
+
getAverage: function(records, field) {
|
|
2411
|
+
var i = 0,
|
|
2412
|
+
len = records.length,
|
|
2413
|
+
sum = 0;
|
|
2414
|
+
|
|
2415
|
+
if (records.length > 0) {
|
|
2416
|
+
for (; i < len; ++i) {
|
|
2417
|
+
sum += records[i].get(field);
|
|
2418
|
+
}
|
|
2419
|
+
return sum / len;
|
|
2420
|
+
}
|
|
2421
|
+
return 0;
|
|
2422
|
+
},
|
|
2423
|
+
|
|
2424
|
+
/**
|
|
2425
|
+
* Runs the aggregate function for all the records in the store.
|
|
2426
|
+
*
|
|
2427
|
+
* When store is filtered, only items within the filter are aggregated.
|
|
2428
|
+
*
|
|
2429
|
+
* @param {Function} fn The function to execute. The function is called with a single parameter,
|
|
2430
|
+
* an array of records for that group.
|
|
2431
|
+
* @param {Object} [scope] The scope to execute the function in. Defaults to the store.
|
|
2432
|
+
* @param {Boolean} [grouped] True to perform the operation for each group
|
|
2433
|
+
* in the store. The value returned will be an object literal with the key being the group
|
|
2434
|
+
* name and the group average being the value. The grouped parameter is only honored if
|
|
2435
|
+
* the store has a groupField.
|
|
2436
|
+
* @param {Array} [args] Any arguments to append to the function call
|
|
2437
|
+
* @return {Object} An object literal with the group names and their appropriate values.
|
|
2438
|
+
*/
|
|
2439
|
+
aggregate: function(fn, scope, grouped, args) {
|
|
2440
|
+
args = args || [];
|
|
2441
|
+
if (grouped && this.isGrouped()) {
|
|
2442
|
+
var groups = this.getGroups(),
|
|
2443
|
+
i = 0,
|
|
2444
|
+
len = groups.length,
|
|
2445
|
+
out = {},
|
|
2446
|
+
group;
|
|
2447
|
+
|
|
2448
|
+
for (; i < len; ++i) {
|
|
2449
|
+
group = groups[i];
|
|
2450
|
+
out[group.name] = fn.apply(scope || this, [group.children].concat(args));
|
|
2451
|
+
}
|
|
2452
|
+
return out;
|
|
2453
|
+
} else {
|
|
2454
|
+
return fn.apply(scope || this, [this.data.items].concat(args));
|
|
2455
|
+
}
|
|
2456
|
+
},
|
|
2457
|
+
|
|
2458
|
+
/**
|
|
2459
|
+
* Commits all Records with {@link #getModifiedRecords outstanding changes}. To handle updates for changes,
|
|
2460
|
+
* subscribe to the Store's {@link #update update event}, and perform updating when the third parameter is
|
|
2461
|
+
* Ext.data.Record.COMMIT.
|
|
2462
|
+
*/
|
|
2463
|
+
commitChanges : function(){
|
|
2464
|
+
var me = this,
|
|
2465
|
+
recs = me.getModifiedRecords(),
|
|
2466
|
+
len = recs.length,
|
|
2467
|
+
i = 0;
|
|
2468
|
+
|
|
2469
|
+
for (; i < len; i++){
|
|
2470
|
+
recs[i].commit();
|
|
2471
|
+
}
|
|
2472
|
+
|
|
2473
|
+
// Since removals are cached in a simple array we can simply reset it here.
|
|
2474
|
+
// Adds and updates are managed in the data MixedCollection and should already be current.
|
|
2475
|
+
me.removed.length = 0;
|
|
2476
|
+
},
|
|
2477
|
+
|
|
2478
|
+
filterNewOnly: function(item){
|
|
2479
|
+
return item.phantom === true;
|
|
2480
|
+
},
|
|
2481
|
+
|
|
2482
|
+
// Ideally in the future this will use getModifiedRecords, where there will be a param
|
|
2483
|
+
// to getNewRecords & getUpdatedRecords to indicate whether to get only the valid
|
|
2484
|
+
// records or grab all of them
|
|
2485
|
+
getRejectRecords: function(){
|
|
2486
|
+
var newRecs = this.data.filterBy(this.filterNewOnly).items;
|
|
2487
|
+
return newRecs.concat(this.getUpdatedRecords());
|
|
2488
|
+
},
|
|
2489
|
+
|
|
2490
|
+
/**
|
|
2491
|
+
* {@link Ext.data.Model#reject Rejects} outstanding changes on all {@link #getModifiedRecords modified records}
|
|
2492
|
+
* and re-insert any records that were removed locally. Any phantom records will be removed.
|
|
2493
|
+
*/
|
|
2494
|
+
rejectChanges : function() {
|
|
2495
|
+
var me = this,
|
|
2496
|
+
recs = me.getRejectRecords(),
|
|
2497
|
+
len = recs.length,
|
|
2498
|
+
i = 0,
|
|
2499
|
+
rec;
|
|
2500
|
+
|
|
2501
|
+
for (; i < len; i++) {
|
|
2502
|
+
rec = recs[i];
|
|
2503
|
+
rec.reject();
|
|
2504
|
+
if (rec.phantom) {
|
|
2505
|
+
me.remove(rec);
|
|
2506
|
+
}
|
|
2507
|
+
}
|
|
2508
|
+
|
|
2509
|
+
recs = me.removed;
|
|
2510
|
+
len = recs.length;
|
|
2511
|
+
|
|
2512
|
+
for (i = 0; i < len; i++) {
|
|
2513
|
+
rec = recs[i];
|
|
2514
|
+
me.insert(rec.index || 0, rec);
|
|
2515
|
+
rec.reject();
|
|
2516
|
+
}
|
|
2517
|
+
|
|
2518
|
+
// Since removals are cached in a simple array we can simply reset it here.
|
|
2519
|
+
// Adds and updates are managed in the data MixedCollection and should already be current.
|
|
2520
|
+
me.removed.length = 0;
|
|
2521
|
+
}
|
|
2522
|
+
}, function() {
|
|
2523
|
+
// A dummy empty store with a fieldless Model defined in it.
|
|
2524
|
+
// Just for binding to Views which are instantiated with no Store defined.
|
|
2525
|
+
// They will be able to run and render fine, and be bound to a generated Store later.
|
|
2526
|
+
Ext.regStore('ext-empty-store', {fields: [], proxy: 'memory'});
|
|
2527
|
+
|
|
2528
|
+
// Private class for use by only Store when configured buffered: true
|
|
2529
|
+
this.prototype.PageMap = new Ext.Class({
|
|
2530
|
+
extend: 'Ext.util.LruCache',
|
|
2531
|
+
|
|
2532
|
+
// Maintain a generation counter, so that the Store can reject incoming pages destined for the previous generation
|
|
2533
|
+
clear: function(initial) {
|
|
2534
|
+
this.generation = (this.generation ||0) + 1;
|
|
2535
|
+
this.callParent(arguments);
|
|
2536
|
+
},
|
|
2537
|
+
|
|
2538
|
+
getPageFromRecordIndex: this.prototype.getPageFromRecordIndex,
|
|
2539
|
+
|
|
2540
|
+
addPage: function(page, records) {
|
|
2541
|
+
this.add(page, records);
|
|
2542
|
+
this.fireEvent('pageAdded', page, records);
|
|
2543
|
+
},
|
|
2544
|
+
|
|
2545
|
+
getPage: function(page) {
|
|
2546
|
+
return this.get(page);
|
|
2547
|
+
},
|
|
2548
|
+
|
|
2549
|
+
hasRange: function(start, end) {
|
|
2550
|
+
var page = this.getPageFromRecordIndex(start),
|
|
2551
|
+
endPage = this.getPageFromRecordIndex(end);
|
|
2552
|
+
|
|
2553
|
+
for (; page <= endPage; page++) {
|
|
2554
|
+
if (!this.hasPage(page)) {
|
|
2555
|
+
return false;
|
|
2556
|
+
}
|
|
2557
|
+
}
|
|
2558
|
+
return true;
|
|
2559
|
+
},
|
|
2560
|
+
|
|
2561
|
+
hasPage: function(page) {
|
|
2562
|
+
return !!this.map[page];
|
|
2563
|
+
},
|
|
2564
|
+
|
|
2565
|
+
getRange: function(start, end) {
|
|
2566
|
+
if (!this.hasRange(start, end)) {
|
|
2567
|
+
Ext.Error.raise('PageMap asked for range which it does not have');
|
|
2568
|
+
}
|
|
2569
|
+
var me = this,
|
|
2570
|
+
startPage = me.getPageFromRecordIndex(start),
|
|
2571
|
+
endPage = me.getPageFromRecordIndex(end),
|
|
2572
|
+
dataStart = (startPage - 1) * me.pageSize,
|
|
2573
|
+
dataEnd = (endPage * me.pageSize) - 1,
|
|
2574
|
+
page = startPage,
|
|
2575
|
+
result = [],
|
|
2576
|
+
sliceBegin, sliceEnd, doSlice,
|
|
2577
|
+
i = 0, len;
|
|
2578
|
+
|
|
2579
|
+
for (; page <= endPage; page++) {
|
|
2580
|
+
|
|
2581
|
+
// First and last pages will need slicing to cut into the actual wanted records
|
|
2582
|
+
if (page == startPage) {
|
|
2583
|
+
sliceBegin = start - dataStart;
|
|
2584
|
+
doSlice = true;
|
|
2585
|
+
} else {
|
|
2586
|
+
sliceBegin = 0;
|
|
2587
|
+
doSlice = false;
|
|
2588
|
+
}
|
|
2589
|
+
if (page == endPage) {
|
|
2590
|
+
sliceEnd = me.pageSize - (dataEnd - end);
|
|
2591
|
+
doSlice = true;
|
|
2592
|
+
}
|
|
2593
|
+
|
|
2594
|
+
// First and last pages will need slicing
|
|
2595
|
+
if (doSlice) {
|
|
2596
|
+
Ext.Array.push(result, Ext.Array.slice(me.getPage(page), sliceBegin, sliceEnd));
|
|
2597
|
+
} else {
|
|
2598
|
+
Ext.Array.push(result, me.getPage(page));
|
|
2599
|
+
}
|
|
2600
|
+
}
|
|
2601
|
+
|
|
2602
|
+
// Inject the dataset ordinal position into the record as the index
|
|
2603
|
+
for (len = result.length; i < len; i++) {
|
|
2604
|
+
result[i].index = start++;
|
|
2605
|
+
}
|
|
2606
|
+
return result;
|
|
2607
|
+
}
|
|
2608
|
+
});
|
|
2609
|
+
});
|