| OLD | NEW |
| 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 part of dart.mdv_observe_impl; | 5 part of observe; |
| 6 | 6 |
| 7 // This code is inspired by ChangeSummary: | 7 // This code is inspired by ChangeSummary: |
| 8 // https://github.com/rafaelw/ChangeSummary/blob/master/change_summary.js | 8 // https://github.com/rafaelw/ChangeSummary/blob/master/change_summary.js |
| 9 // ...which underlies MDV. Since we don't need the functionality of | 9 // ...which underlies MDV. Since we don't need the functionality of |
| 10 // ChangeSummary, we just implement what we need for data bindings. | 10 // ChangeSummary, we just implement what we need for data bindings. |
| 11 // This allows our implementation to be much simpler. | 11 // This allows our implementation to be much simpler. |
| 12 | 12 |
| 13 // TODO(jmesserly): should we make these types stronger, and require | 13 // TODO(jmesserly): should we make these types stronger, and require |
| 14 // Observable objects? Currently, it is fine to say something like: | 14 // Observable objects? Currently, it is fine to say something like: |
| 15 // var path = new PathObserver(123, ''); | 15 // var path = new PathObserver(123, ''); |
| (...skipping 148 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 164 var last = _lastObserver; | 164 var last = _lastObserver; |
| 165 if (_setObjectProperty(last._object, last._property, value)) { | 165 if (_setObjectProperty(last._object, last._property, value)) { |
| 166 // Technically, this would get updated asynchronously via a change record. | 166 // Technically, this would get updated asynchronously via a change record. |
| 167 // However, it is nice if calling the getter will yield the same value | 167 // However, it is nice if calling the getter will yield the same value |
| 168 // that was just set. So we use this opportunity to update our cache. | 168 // that was just set. So we use this opportunity to update our cache. |
| 169 last.value = value; | 169 last.value = value; |
| 170 } | 170 } |
| 171 } | 171 } |
| 172 } | 172 } |
| 173 | 173 |
| 174 // TODO(jmesserly): these should go away in favor of mirrors! | |
| 175 _getObjectProperty(object, property) { | 174 _getObjectProperty(object, property) { |
| 176 if (object is List && property is int) { | 175 if (object is List && property is int) { |
| 177 if (property >= 0 && property < object.length) { | 176 if (property >= 0 && property < object.length) { |
| 178 return object[property]; | 177 return object[property]; |
| 179 } else { | 178 } else { |
| 180 return null; | 179 return null; |
| 181 } | 180 } |
| 182 } | 181 } |
| 183 | 182 |
| 184 // TODO(jmesserly): what about length? | 183 if (property is Symbol) { |
| 185 if (object is Map) return object[property]; | 184 var mirror = reflect(object); |
| 185 try { |
| 186 return mirror.getField(property).reflectee; |
| 187 } catch (e) {} |
| 188 } |
| 186 | 189 |
| 187 if (object is Observable) return object.getValueWorkaround(property); | 190 if (object is Map) { |
| 191 return object[property]; |
| 192 } |
| 188 | 193 |
| 189 return null; | 194 return null; |
| 190 } | 195 } |
| 191 | 196 |
| 192 bool _setObjectProperty(object, property, value) { | 197 bool _setObjectProperty(object, property, value) { |
| 193 if (object is List && property is int) { | 198 if (object is List && property is int) { |
| 199 if (property >= 0 && property < object.length) { |
| 200 object[property] = value; |
| 201 return true; |
| 202 } else { |
| 203 return false; |
| 204 } |
| 205 } |
| 206 |
| 207 if (property is Symbol) { |
| 208 var mirror = reflect(object); |
| 209 try { |
| 210 mirror.setField(property, value); |
| 211 return true; |
| 212 } catch (e) {} |
| 213 } |
| 214 |
| 215 if (object is Map) { |
| 194 object[property] = value; | 216 object[property] = value; |
| 195 } else if (object is Map) { | 217 return true; |
| 196 object[property] = value; | |
| 197 } else if (object is Observable) { | |
| 198 (object as Observable).setValueWorkaround(property, value); | |
| 199 } else { | |
| 200 return false; | |
| 201 } | 218 } |
| 202 return true; | 219 |
| 220 return false; |
| 203 } | 221 } |
| 204 | 222 |
| 205 | |
| 206 class _PropertyObserver { | 223 class _PropertyObserver { |
| 207 final PathObserver _path; | 224 final PathObserver _path; |
| 208 final _property; | 225 final _property; |
| 209 final _PropertyObserver _next; | 226 final _PropertyObserver _next; |
| 210 | 227 |
| 211 // TODO(jmesserly): would be nice not to store both of these. | 228 // TODO(jmesserly): would be nice not to store both of these. |
| 212 Object _object; | 229 Object _object; |
| 213 Object _value; | 230 Object _value; |
| 214 StreamSubscription _sub; | 231 StreamSubscription _sub; |
| 215 | 232 |
| (...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 278 | 295 |
| 279 final _spacesRegExp = new RegExp(r'\s'); | 296 final _spacesRegExp = new RegExp(r'\s'); |
| 280 | 297 |
| 281 bool _isPathValid(String s) { | 298 bool _isPathValid(String s) { |
| 282 s = s.replaceAll(_spacesRegExp, ''); | 299 s = s.replaceAll(_spacesRegExp, ''); |
| 283 | 300 |
| 284 if (s == '') return true; | 301 if (s == '') return true; |
| 285 if (s[0] == '.') return false; | 302 if (s[0] == '.') return false; |
| 286 return _pathRegExp.hasMatch(s); | 303 return _pathRegExp.hasMatch(s); |
| 287 } | 304 } |
| OLD | NEW |