aboutsummaryrefslogtreecommitdiff
path: root/node_modules/montage/core/event/binding.js
diff options
context:
space:
mode:
Diffstat (limited to 'node_modules/montage/core/event/binding.js')
-rwxr-xr-xnode_modules/montage/core/event/binding.js202
1 files changed, 58 insertions, 144 deletions
diff --git a/node_modules/montage/core/event/binding.js b/node_modules/montage/core/event/binding.js
index c10c52e4..4206e1c2 100755
--- a/node_modules/montage/core/event/binding.js
+++ b/node_modules/montage/core/event/binding.js
@@ -82,91 +82,57 @@ var PropertyChangeBindingListener = exports.PropertyChangeBindingListener = Obje
82 this.deferredValueTarget = ""; 82 this.deferredValueTarget = "";
83 } 83 }
84 }, 84 },
85 handleChange: {value: function(event) { 85 handleChange:{
86 var targetPropertyPath = this.targetPropertyPath, 86 value:function (notification) {
87 target = this.target, 87
88 localNewValue = event.plus, 88 var bindingOriginTriggeredChange,
89 localPrevValue = event.minus, 89 // Left
90 localTarget = event.target, 90 bindingOrigin = this.bindingOrigin,
91 boundObjectValue, 91 bindingOriginPropertyPath = this.bindingPropertyPath,
92 sourceObjectValue, 92 bindingOriginValue = bindingOrigin.getProperty(bindingOriginPropertyPath),
93 dotIndex, 93 // Right
94 nextPathComponent, 94 boundObject = this.target,
95 atSignIndex, 95 boundObjectPropertyPath = this.targetPropertyPath,
96 baseType, 96 boundObjectValue;
97 bindingDescriptor, 97
98 bindingOrigin = this.bindingOrigin, 98 // Determine if binding triggered by change on bindingOrigin
99 leftOriginated, 99 if (boundObject !== bindingOrigin) {
100 changeOriginPropertyPath = null, 100 // the origin and bound object are different objects; easy enough
101 exploredPath, 101 bindingOriginTriggeredChange = notification.currentTarget === bindingOrigin;
102 valueChanged; 102 } else {
103 103 // otherwise, if the objects are the same the propertyPaths must differ
104 if (target !== bindingOrigin) { 104 bindingOriginTriggeredChange = notification.currentPropertyPath === bindingOriginPropertyPath;
105 //the left and the right are different objects; easy enough 105 }
106 leftOriginated = event.target === bindingOrigin;
107 } else {
108 //otherwise, they're the same object; time to try and figure out which "side" the event came from
109 // TODO this is a very weak check that relies on the bindingOrigin using a property and not a full propertyPath
110 leftOriginated = event.propertyName === this.bindingPropertyPath;
111 }
112
113 if (leftOriginated) {
114 // This change event targeted the left side of the binding; try to push to the right side
115 106
116 if (!bindingOrigin.setProperty.changeEvent) { 107 if (bindingOriginTriggeredChange) {
108 // This change notification targeted the left side of the binding; try to push to the right side
117 109
118 sourceObjectValue = localNewValue; 110 // If this notification was triggered by the right-to-left value push; don't bother setting
111 // the value on the left side, that's where all this value changing started
112 // (The original right-to-left push installs this changeEvent key on the setProperty function)
113 if (bindingOrigin.setProperty.changeEvent) {
114 return;
115 }
119 116
117 // TODO should not assume revert is available
120 if (this.bindingDescriptor.converter) { 118 if (this.bindingDescriptor.converter) {
121 sourceObjectValue = this.bindingDescriptor.converter.revert(sourceObjectValue); 119 bindingOriginValue = this.bindingDescriptor.converter.revert(bindingOriginValue);
122 } 120 }
123 121
124 // If this event was triggered by the right-to-left- value push; don't bother setting
125 // the value on the left side, that's where all this value changing started
126 // (The original right-to-left push installs this changeEvent key on the setProperty function)
127 if (this.bindingOriginValueDeferred === true || bindingOrigin._bindingsDisabled) { 122 if (this.bindingOriginValueDeferred === true || bindingOrigin._bindingsDisabled) {
128 this.deferredValue = sourceObjectValue; 123 this.deferredValue = bindingOriginValue;
129 this.deferredValueTarget = "target"; 124 this.deferredValueTarget = "target";
130 } else { 125 } else {
131 this.bindingOriginChangeTriggered = true; 126 this.bindingOriginChangeTriggered = true;
132 // Set the value on the RIGHT side now 127 // Set the value on the RIGHT side now
133 this.target.setProperty(this.targetPropertyPath, sourceObjectValue); 128 boundObject.setProperty(boundObjectPropertyPath, bindingOriginValue);
134 this.bindingOriginChangeTriggered = false; 129 this.bindingOriginChangeTriggered = false;
135 } 130 }
136 }
137
138 } else if (!this.bindingOriginChangeTriggered) {
139
140 // If we're handling the event at this point we know the right side triggered it, from somewhere inside the observed propertyPath
141 // the event target, which just changed, could be any of the objects along the path, but from here on we want to
142 // treat the event as "change@fullTargetPropertyPath" so adjust the event we have to reflect that
143 if (this.target && targetPropertyPath) {
144 event.target = target;
145 event.propertyPath = targetPropertyPath;
146
147 event.plus = target.getProperty(targetPropertyPath);
148
149 // If the newValue and the storedPreviousValue are the same, this was a mutation on that object
150 // we want to show the prevValue that came along from the event lest we point
151 // somebody a reference to the same array as the prevValue and newValue
152 if (!Array.isArray(this.previousTargetPropertyPathValue) && event.plus !== this.previousTargetPropertyPathValue) {
153 event.minus = this.previousTargetPropertyPathValue;
154 }
155
156 } else {
157 // TODO I'm not sure when this would happen..
158 event.target = this;
159 }
160
161 // The binding listener detected some change along the property path it cared about
162 // make sure the event we "dispatch" has the full change@propertyPath eventType
163 event.type = this.targetPropertyPath;
164 131
165 //For bindings, start the right-to-left value push 132 } else if (!this.bindingOriginChangeTriggered) {
166 if (event.target === this.target && this.bindingPropertyPath && bindingOrigin) {
167 //console.log("@ % @ % @ % @ % @ % Binding Worked!!");
168 133
169 boundObjectValue = event.plus; 134 // Start the right-to-left value push
135 boundObjectValue = boundObject.getProperty(boundObjectPropertyPath);
170 136
171 if (this.bindingDescriptor.boundValueMutator) { 137 if (this.bindingDescriptor.boundValueMutator) {
172 boundObjectValue = this.bindingDescriptor.boundValueMutator(boundObjectValue); 138 boundObjectValue = this.bindingDescriptor.boundValueMutator(boundObjectValue);
@@ -174,75 +140,23 @@ var PropertyChangeBindingListener = exports.PropertyChangeBindingListener = Obje
174 boundObjectValue = this.bindingDescriptor.converter.convert(boundObjectValue); 140 boundObjectValue = this.bindingDescriptor.converter.convert(boundObjectValue);
175 } 141 }
176 142
177 // If the the value about to be pushed over to the bindingOrigin is already there don't call the setter 143 if (boundObjectValue !== bindingOriginValue) {
178 valueChanged = boundObjectValue !== event.plus ?
179 (this.bindingOrigin.getProperty(this.bindingPropertyPath) !== boundObjectValue) : true;
180
181 if (valueChanged) {
182 if (this.bindingOriginValueDeferred === true || bindingOrigin._bindingsDisabled) { 144 if (this.bindingOriginValueDeferred === true || bindingOrigin._bindingsDisabled) {
183 this.deferredValue = boundObjectValue; 145 this.deferredValue = boundObjectValue;
184 this.deferredValueTarget = "bound"; 146 this.deferredValueTarget = "bound";
185 } else { 147 } else {
186 // Make the original event available to the setter 148 // Make the original notification available to the setter
187 this.bindingOrigin.setProperty.changeEvent = event; 149 bindingOrigin.setProperty.changeEvent = notification;
188 // Set the value on the LEFT side now 150 // Set the value on the LEFT side now
189 this.bindingOrigin.setProperty(this.bindingPropertyPath, boundObjectValue); 151 bindingOrigin.setProperty(bindingOriginPropertyPath, boundObjectValue);
190 this.bindingOrigin.setProperty.changeEvent = null; 152 bindingOrigin.setProperty.changeEvent = null;
191 } 153 }
192 } 154 }
193 }
194 // Otherwise, there was probably a listener for a change at this path that was not a part of some binding
195 // so distribute the event to the original listener
196 // TODO this is not as full featured as the EventManager event distribution so it may differ, which is bad
197 else if (this.originalListener) {
198 if (this.originalListenerIsFunction) {
199 this.originalListener.call(this.target, event);
200 } else {
201 this.originalListener.handleEvent(event);
202 }
203 }
204
205 // Update the stored value of the propertyPath
206 this.previousTargetPropertyPathValue = event.plus;
207
208 // TODO I'm not exactly sure why this happens here, or really why it does in general
209 event.minus = localPrevValue;
210 event.plus = localNewValue;
211 event.target = localTarget;
212 155
213 if (localPrevValue) { 156 // Update the stored value of the propertyPath
214 157 this.previousTargetPropertyPathValue = boundObjectValue;
215 // Determine where along the property path the change originated from so we know how to build the path
216 // to stop observing on things that were removed
217 //TODO extract this into a "obj.getPathOfObjectAlongPropertyPath" method or something with proper tests
218 exploredPath = "";
219 this.target.getProperty(this.targetPropertyPath, null, null, function(value, currentPathComponent, result) {
220
221 if (changeOriginPropertyPath) {
222 return;
223 }
224
225 exploredPath += "." + currentPathComponent;
226
227 if (result === event.target) {
228 changeOriginPropertyPath = exploredPath.replace(/^\./, "");
229 }
230 });
231 } 158 }
232 } 159 }
233
234 targetPropertyPath = null;
235 target = null;
236 localNewValue = null;
237 localPrevValue = null;
238 localTarget = null;
239 dotIndex = null;
240 nextPathComponent = null;
241 atSignIndex = null;
242 baseType = null;
243 bindingDescriptor = null;