aboutsummaryrefslogtreecommitdiff
path: root/node_modules/montage/ui/repetition.reel/repetition.js
diff options
context:
space:
mode:
Diffstat (limited to 'node_modules/montage/ui/repetition.reel/repetition.js')
-rwxr-xr-xnode_modules/montage/ui/repetition.reel/repetition.js711
1 files changed, 512 insertions, 199 deletions
diff --git a/node_modules/montage/ui/repetition.reel/repetition.js b/node_modules/montage/ui/repetition.reel/repetition.js
index 95790bc3..c278e84d 100755
--- a/node_modules/montage/ui/repetition.reel/repetition.js
+++ b/node_modules/montage/ui/repetition.reel/repetition.js
@@ -16,7 +16,106 @@ var Montage = require("montage").Montage,
16 Template = require("ui/template").Template, 16 Template = require("ui/template").Template,
17 logger = require("core/logger").logger("repetition"), 17 logger = require("core/logger").logger("repetition"),
18 Gate = require("core/gate").Gate, 18 Gate = require("core/gate").Gate,
19 ChangeTypeModification = require("core/event/mutable-event").ChangeTypes.MODIFICATION; 19 ChangeNotification = require("core/change-notification").ChangeNotification,
20 PropertyChangeNotification = require("core/change-notification").PropertyChangeNotification;
21
22var FakeObjects = Montage.create(Object.prototype, {
23 _repetition: {value: null},
24 _fakeIndex: {value: null},
25 _unusedIndexes: {value: null},
26
27 initWithRepetition: {
28 value: function(repetition) {
29 this._repetition = repetition;
30 this._fakeIndex = [];
31 this._unusedIndexes = [];
32 return this;
33 }
34 },
35
36 automaticallyDispatchPropertyChangeListener: {
37 value: function() {
38 return false;
39 }
40 },
41
42 undefinedGet: {
43 value: function(propertyName) {
44 if (this._repetition.objects) {
45 return this._repetition.objects[this._fakeIndex.indexOf(propertyName)];
46 }
47 }
48 },
49
50 // This is to catch a two-way binding on
51 "0": {
52 // This is to catch two way bindings
53 set: function() {
54 throw("You cannot use a two-way binding on the \"objectAtCurrentIteration\" or \"current\" property.");
55 },
56 get: function() {
57 if (this._repetition.objects) {
58 return this._repetition.objects[this._fakeIndex.indexOf("0")];
59 }
60 }
61 },
62
63 addFakeObjectAtPosition: {
64 value: function(position) {
65 var index;
66
67 if (this._unusedIndexes.length > 0) {
68 index = this._unusedIndexes.pop();
69 } else {
70 index = String(this._fakeIndex.length);
71 }
72
73 this._fakeIndex.splice(position, 0, index);
74 return index;
75 }
76 },
77 resetFakeObjects: {
78 value: function() {
79 var objects = this._repetition.objects;
80
81 this._fakeIndex.length = 0;
82 if (objects) {
83 for (var i = 0, l = objects.length; i < l; i++) {
84 this._fakeIndex[i] = String(i);
85 }
86 }
87 }
88 },
89 removeFakeObjectAtPosition: {
90 value: function(position) {
91 var index;
92
93 this._unusedIndexes.unshift(this._fakeIndex.splice(position, 1)[0]);
94
95 return this._unusedIndexes[0];
96 }
97 },
98 _dispatchFakePropertyChange: {
99 value: function(propertyName, minus) {
100 var descriptor,
101 notification;
102
103 descriptor = ChangeNotification.getPropertyChangeDescriptor(this, propertyName);
104 if (descriptor) {
105 notification = Object.create(PropertyChangeNotification);
106
107 notification.target = this;
108 notification.propertyPath = propertyName;
109 notification.minus = minus;
110 notification.plus = this.undefinedGet(propertyName);
111 if (minus !== notification.plus) {
112 descriptor.handleChange(notification);
113 }
114 }
115 }
116 }
117});
118
20/** 119/**
21 @class module:"montage/ui/repetition.reel".Repetition 120 @class module:"montage/ui/repetition.reel".Repetition
22 @extends module:montage/ui/component.Component 121 @extends module:montage/ui/component.Component
@@ -29,24 +128,72 @@ var Repetition = exports.Repetition = Montage.create(Component, /** @lends modul
29 128
30 didCreate: { 129 didCreate: {
31 value: function() { 130 value: function() {
32 this.addEventListener("change@objects", this._onObjectsChange, false); 131 var self = this;
132
133 this.addPropertyChangeListener("objects", this);
134 this._fakeObjects = Object.create(FakeObjects).initWithRepetition(this);
33 } 135 }
34 }, 136 },
35 137
36 _onObjectsChange: { 138 _emptyFunction: {value: function(){}},
37 enumerable: false, 139
38 value: function(event) { 140 _updateItems: {
39 if(event._event.propertyChange !== ChangeTypeModification) { 141 value: function(minus, plus, index) {
40 this.selectedIndexes = null; 142 var fakeObjects = this._fakeObjects,
41 this._mappedObjects = null; 143 fakeIndex,
144 minusCount = minus ? minus.length : 0,
145 plusCount = plus ? plus.length : 0,
146 max, min, delta;
147
148 max = Math.max(minusCount, plusCount);
149 min = Math.min(minusCount, plusCount);
150 delta = plusCount - minusCount;
151
152//console.log("Going to change " + min + " iterations", fakeObjects._fakeIndex);
42 153
43 if (this._isComponentExpanded) { 154 // send updates for the elements that were just replaced by new ones
44 this._refreshItems(); 155 for (var i = 0; i < min; i++) {
156//console.log("Going to change " + (index+i), minus[index+i]);
157 fakeObjects._dispatchFakePropertyChange(fakeObjects._fakeIndex[index+i], minus[index+i]);
158 }
159
160 // add new objects, no need to send updates on this one, they're new!
161 if (delta > 0) {
162//console.log("Going to add " + (max-i) + " iterations");
163 this._expectedChildComponentsCount += (this._iterationChildComponentsCount||1) * delta;
164 this.canDrawGate.setField("iterationLoaded", false);
165 for (; i < max; i++) {
166//console.log("New item " + (index+i) + " " + plus[index+i].uuid);
167 fakeObjects.addFakeObjectAtPosition(index + i);
168 this._addItem({index: index + i, insertionIndex: index + i});
45 } 169 }
170 } else if (delta < 0) { // remove elements and send updates
171//console.log("Going to remove " + (max-i) + " iterations");
172 // this index is fixed because we're changing the array at each iteration of the for loop
173 removeIndex = index + min;
174 for (; i < max; i++) {
175//console.log("Going to remove " + (index+i), minus[i], min);
176 fakeIndex = fakeObjects.removeFakeObjectAtPosition(removeIndex);
177 fakeObjects._dispatchFakePropertyChange(fakeIndex, minus[i]);
178 this._deleteItem(removeIndex);
179 }
180 }
181 }
182 },
183
184 handleChange: {
185 enumerable: false,
186 value: function(notification) {
187 if (this._isComponentExpanded) {
188 this._updateItems(notification.minus, notification.plus, notification.index || 0);
46 } 189 }
47 } 190 }
48 }, 191 },
49 192
193 _fakeObjects: {
194 value: null
195 },
196
50/** 197/**
51 @private 198 @private
52*/ 199*/
@@ -182,15 +329,15 @@ var Repetition = exports.Repetition = Montage.create(Component, /** @lends modul
182 @default null 329 @default null
183 */ 330 */
184 objects: { 331 objects: {
185 dependencies: ["indexMap"], 332 dependencies: ["indexMap", "indexMapEnabled"],
186 enumerable: false, 333 enumerable: false,
187 get: function() { 334 get: function() {
188 if (!this.indexMap) { 335 if (!this.indexMap || !this.indexMapEnabled) {
189 return this._objects; 336 return this._objects;
190 } else { 337 } else {
191 if (this._objects && !this._mappedObjects) { 338 if (this._objects && !this._mappedObjects) {
192 this._mappedObjects = this.indexMap.map(function(value) { 339 this._mappedObjects = this.indexMap.map(function(value) {
193 return this._objects.getProperty(value);