ende 0.5.20 → 0.5.21

Sign up to get free protection for your applications and to get access to all the features.
Files changed (203) hide show
  1. checksums.yaml +4 -4
  2. data/component.json +1 -1
  3. data/components/indefinido/indemma/master/.gitignore +17 -0
  4. data/components/indefinido/indemma/master/.ruby-gemset +1 -0
  5. data/components/indefinido/indemma/master/.ruby-version +1 -0
  6. data/components/indefinido/indemma/master/Gemfile +12 -0
  7. data/components/indefinido/indemma/master/Guardfile +39 -0
  8. data/components/indefinido/indemma/master/History.md +0 -0
  9. data/components/indefinido/indemma/master/Readme.md +445 -0
  10. data/components/indefinido/indemma/master/build/development.js +26123 -0
  11. data/components/indefinido/indemma/master/build/release.js +16741 -0
  12. data/components/indefinido/indemma/master/build/test.js +26123 -0
  13. data/components/indefinido/indemma/master/component.json +1 -1
  14. data/components/indefinido/indemma/master/components/chaijs/assertion-error/1.0.0/component.json +18 -0
  15. data/components/indefinido/indemma/master/components/chaijs/assertion-error/1.0.0/index.js +110 -0
  16. data/components/indefinido/indemma/master/components/chaijs/chai/1.9.1/.gitignore +22 -0
  17. data/components/indefinido/indemma/master/components/chaijs/chai/1.9.1/.mailmap +1 -0
  18. data/components/indefinido/indemma/master/components/chaijs/chai/1.9.1/.npmignore +14 -0
  19. data/components/indefinido/indemma/master/components/chaijs/chai/1.9.1/.travis.yml +14 -0
  20. data/components/indefinido/indemma/master/components/chaijs/chai/1.9.1/CONTRIBUTING.md +173 -0
  21. data/components/indefinido/indemma/master/components/chaijs/chai/1.9.1/History.md +895 -0
  22. data/components/indefinido/indemma/master/components/chaijs/chai/1.9.1/Makefile +93 -0
  23. data/components/indefinido/indemma/master/components/chaijs/chai/1.9.1/README.md +99 -0
  24. data/components/indefinido/indemma/master/components/chaijs/chai/1.9.1/ReleaseNotes.md +482 -0
  25. data/components/indefinido/indemma/master/components/chaijs/chai/1.9.1/bower.json +27 -0
  26. data/components/indefinido/indemma/master/components/chaijs/chai/1.9.1/chai.js +4782 -0
  27. data/components/indefinido/indemma/master/components/chaijs/chai/1.9.1/component.json +50 -0
  28. data/components/indefinido/indemma/master/components/chaijs/chai/1.9.1/index.js +1 -0
  29. data/components/indefinido/indemma/master/components/chaijs/chai/1.9.1/karma.conf.js +28 -0
  30. data/components/indefinido/indemma/master/components/chaijs/chai/1.9.1/karma.sauce.js +41 -0
  31. data/components/indefinido/indemma/master/components/chaijs/chai/1.9.1/lib/chai/assertion.js +130 -0
  32. data/components/indefinido/indemma/master/components/chaijs/chai/1.9.1/lib/chai/config.js +50 -0
  33. data/components/indefinido/indemma/master/components/chaijs/chai/1.9.1/lib/chai/core/assertions.js +1314 -0
  34. data/components/indefinido/indemma/master/components/chaijs/chai/1.9.1/lib/chai/interface/assert.js +1056 -0
  35. data/components/indefinido/indemma/master/components/chaijs/chai/1.9.1/lib/chai/interface/expect.js +12 -0
  36. data/components/indefinido/indemma/master/components/chaijs/chai/1.9.1/lib/chai/interface/should.js +78 -0
  37. data/components/indefinido/indemma/master/components/chaijs/chai/1.9.1/lib/chai/utils/addChainableMethod.js +111 -0
  38. data/components/indefinido/indemma/master/components/chaijs/chai/1.9.1/lib/chai/utils/addMethod.js +43 -0
  39. data/components/indefinido/indemma/master/components/chaijs/chai/1.9.1/lib/chai/utils/addProperty.js +40 -0
  40. data/components/indefinido/indemma/master/components/chaijs/chai/1.9.1/lib/chai/utils/flag.js +32 -0
  41. data/components/indefinido/indemma/master/components/chaijs/chai/1.9.1/lib/chai/utils/getActual.js +18 -0
  42. data/components/indefinido/indemma/master/components/chaijs/chai/1.9.1/lib/chai/utils/getEnumerableProperties.js +25 -0
  43. data/components/indefinido/indemma/master/components/chaijs/chai/1.9.1/lib/chai/utils/getMessage.js +49 -0
  44. data/components/indefinido/indemma/master/components/chaijs/chai/1.9.1/lib/chai/utils/getName.js +20 -0
  45. data/components/indefinido/indemma/master/components/chaijs/chai/1.9.1/lib/chai/utils/getPathValue.js +102 -0
  46. data/components/indefinido/indemma/master/components/chaijs/chai/1.9.1/lib/chai/utils/getProperties.js +35 -0
  47. data/components/indefinido/indemma/master/components/chaijs/chai/1.9.1/lib/chai/utils/index.js +114 -0
  48. data/components/indefinido/indemma/master/components/chaijs/chai/1.9.1/lib/chai/utils/inspect.js +320 -0
  49. data/components/indefinido/indemma/master/components/chaijs/chai/1.9.1/lib/chai/utils/objDisplay.js +49 -0
  50. data/components/indefinido/indemma/master/components/chaijs/chai/1.9.1/lib/chai/utils/overwriteChainableMethod.js +53 -0
  51. data/components/indefinido/indemma/master/components/chaijs/chai/1.9.1/lib/chai/utils/overwriteMethod.js +51 -0
  52. data/components/indefinido/indemma/master/components/chaijs/chai/1.9.1/lib/chai/utils/overwriteProperty.js +54 -0
  53. data/components/indefinido/indemma/master/components/chaijs/chai/1.9.1/lib/chai/utils/test.js +26 -0
  54. data/components/indefinido/indemma/master/components/chaijs/chai/1.9.1/lib/chai/utils/transferFlags.js +44 -0
  55. data/components/indefinido/indemma/master/components/chaijs/chai/1.9.1/lib/chai/utils/type.js +45 -0
  56. data/components/indefinido/indemma/master/components/chaijs/chai/1.9.1/lib/chai.js +87 -0
  57. data/components/indefinido/indemma/master/components/chaijs/chai/1.9.1/package.json +42 -0
  58. data/components/indefinido/indemma/master/components/chaijs/chai/1.9.1/sauce.browsers.js +128 -0
  59. data/components/indefinido/indemma/master/components/chaijs/chai/1.9.1/support/sauce/sauce_connect_block.sh +7 -0
  60. data/components/indefinido/indemma/master/components/chaijs/chai/1.9.1/support/sauce/sauce_connect_setup.sh +53 -0
  61. data/components/indefinido/indemma/master/components/chaijs/chai/1.9.1/test/assert.js +638 -0
  62. data/components/indefinido/indemma/master/components/chaijs/chai/1.9.1/test/auth/.gitkeep +0 -0
  63. data/components/indefinido/indemma/master/components/chaijs/chai/1.9.1/test/bootstrap/index.js +22 -0
  64. data/components/indefinido/indemma/master/components/chaijs/chai/1.9.1/test/bootstrap/karma.js +22 -0
  65. data/components/indefinido/indemma/master/components/chaijs/chai/1.9.1/test/configuration.js +133 -0
  66. data/components/indefinido/indemma/master/components/chaijs/chai/1.9.1/test/display/errors.js +14 -0
  67. data/components/indefinido/indemma/master/components/chaijs/chai/1.9.1/test/display/message.js +47 -0
  68. data/components/indefinido/indemma/master/components/chaijs/chai/1.9.1/test/expect.js +814 -0
  69. data/components/indefinido/indemma/master/components/chaijs/chai/1.9.1/test/globalShould.js +15 -0
  70. data/components/indefinido/indemma/master/components/chaijs/chai/1.9.1/test/plugins.js +24 -0
  71. data/components/indefinido/indemma/master/components/chaijs/chai/1.9.1/test/should.js +744 -0
  72. data/components/indefinido/indemma/master/components/chaijs/chai/1.9.1/test/utilities.js +309 -0
  73. data/components/indefinido/indemma/master/components/chaijs/deep-eql/0.1.3/component.json +20 -0
  74. data/components/indefinido/indemma/master/components/chaijs/deep-eql/0.1.3/lib/eql.js +257 -0
  75. data/components/indefinido/indemma/master/components/chaijs/type-detect/0.1.1/component.json +18 -0
  76. data/components/indefinido/indemma/master/components/chaijs/type-detect/0.1.1/lib/type.js +142 -0
  77. data/components/indefinido/indemma/master/components/component/bind/1.0.0/component.json +14 -0
  78. data/components/indefinido/indemma/master/components/component/bind/1.0.0/index.js +23 -0
  79. data/components/indefinido/indemma/master/components/component/jquery/1.0.0/component.json +10 -0
  80. data/components/indefinido/indemma/master/components/component/jquery/1.0.0/index.js +10308 -0
  81. data/components/indefinido/indemma/master/components/component/type/1.0.0/component.json +20 -0
  82. data/components/indefinido/indemma/master/components/component/type/1.0.0/index.js +32 -0
  83. data/components/indefinido/indemma/master/components/indefinido/advisable/master/component.json +21 -0
  84. data/components/indefinido/indemma/master/components/indefinido/advisable/master/index.js +1 -0
  85. data/components/indefinido/indemma/master/components/indefinido/advisable/master/lib/advisable.js +60 -0
  86. data/components/indefinido/indemma/master/components/indefinido/observable/es6-modules/component.json +39 -0
  87. data/components/indefinido/indemma/master/components/indefinido/observable/es6-modules/index.js +1 -0
  88. data/components/indefinido/indemma/master/components/indefinido/observable/es6-modules/lib/adapters/rivets.js +40 -0
  89. data/components/indefinido/indemma/master/components/indefinido/observable/es6-modules/lib/legacy/notifierable.js +145 -0
  90. data/components/indefinido/indemma/master/components/indefinido/observable/es6-modules/lib/legacy/schedulerable.js +147 -0
  91. data/components/indefinido/indemma/master/components/indefinido/observable/es6-modules/lib/lookup.js +38 -0
  92. data/components/indefinido/indemma/master/components/indefinido/observable/es6-modules/lib/observable/keypath_observer.js +38 -0
  93. data/components/indefinido/indemma/master/components/indefinido/observable/es6-modules/lib/observable/observation.js +45 -0
  94. data/components/indefinido/indemma/master/components/indefinido/observable/es6-modules/lib/observable/selection.js +57 -0
  95. data/components/indefinido/indemma/master/components/indefinido/observable/es6-modules/lib/observable/self_observer.js +38 -0
  96. data/components/indefinido/indemma/master/components/indefinido/observable/es6-modules/lib/observable.js +97 -0
  97. data/components/indefinido/indemma/master/components/indefinido/observable/es6-modules/lib/platform.js +12 -0
  98. data/components/indefinido/indemma/master/components/indefinido/observable/es6-modules/vendor/observe-js/observe.js +1631 -0
  99. data/components/indefinido/indemma/master/components/indefinido/observable/es6-modules/vendor/shims/accessors-legacy.js +92 -0
  100. data/components/indefinido/indemma/master/components/indefinido/observable/es6-modules/vendor/shims/accessors.js +248 -0
  101. data/components/indefinido/indemma/master/components/indefinido/observable/es6-modules/vendor/shims/array.indexOf.js +8 -0
  102. data/components/indefinido/indemma/master/components/indefinido/observable/es6-modules/vendor/shims/object.create.js +77 -0
  103. data/components/indefinido/indemma/master/components/pluma/assimilate/0.4.0/component.json +25 -0
  104. data/components/indefinido/indemma/master/components/pluma/assimilate/0.4.0/dist/assimilate.js +127 -0
  105. data/components/indefinido/indemma/master/karma.conf.js +75 -0
  106. data/components/indefinido/indemma/master/lib/record/associable.js +4 -2
  107. data/components/indefinido/indemma/master/lib/record/dirtyable.js +1 -1
  108. data/components/indefinido/indemma/master/package.json +9 -0
  109. data/components/indefinido/indemma/master/spec/record/associable_spec.js +211 -0
  110. data/components/indefinido/indemma/master/spec/record/dirtyable_spec.js +57 -0
  111. data/components/indefinido/indemma/master/spec/record/maid_spec.js +40 -0
  112. data/components/indefinido/indemma/master/spec/record/persistable_spec.js +46 -0
  113. data/components/indefinido/indemma/master/spec/record/queryable_spec.js +39 -0
  114. data/components/indefinido/indemma/master/spec/record/resource_spec.js +93 -0
  115. data/components/indefinido/indemma/master/spec/record/rest_spec.js +32 -0
  116. data/components/indefinido/indemma/master/spec/record/restfulable_spec.js +346 -0
  117. data/components/indefinido/indemma/master/spec/record/scopable_spec.js +242 -0
  118. data/components/indefinido/indemma/master/spec/record/storable_spec.js +44 -0
  119. data/components/indefinido/indemma/master/spec/record/translationable.js +28 -0
  120. data/components/indefinido/indemma/master/spec/record/validatable_spec.js +142 -0
  121. data/components/indefinido/indemma/master/spec/record/validations/associated_spec.js +43 -0
  122. data/components/indefinido/indemma/master/spec/record/validations/confirmation_spec.js +36 -0
  123. data/components/indefinido/indemma/master/spec/record/validations/cpf_spec.js +34 -0
  124. data/components/indefinido/indemma/master/spec/record/validations/presence_spec.js +28 -0
  125. data/components/indefinido/indemma/master/spec/record/validations/remote_spec.js +87 -0
  126. data/components/indefinido/indemma/master/spec/record/validations/type_spec.js +48 -0
  127. data/components/indefinido/indemma/master/spec/record_spec.js +49 -0
  128. data/components/indefinido/indemma/master/spec/spec_helper.js +15 -0
  129. data/components/indefinido/indemma/master/spec/support/value_objects/phone.js +45 -0
  130. data/components/indefinido/indemma/master/src/lib/extensions/rivets.coffee +17 -0
  131. data/components/indefinido/indemma/master/src/lib/record/associable.coffee +419 -0
  132. data/components/indefinido/indemma/master/src/lib/record/dirtyable.coffee +47 -0
  133. data/components/indefinido/indemma/master/src/lib/record/errors.coffee +20 -0
  134. data/components/indefinido/indemma/master/src/lib/record/maid.coffee +16 -0
  135. data/components/indefinido/indemma/master/src/lib/record/persistable.coffee +34 -0
  136. data/components/indefinido/indemma/master/src/lib/record/queryable.coffee +29 -0
  137. data/components/indefinido/indemma/master/src/lib/record/resource.coffee +107 -0
  138. data/components/indefinido/indemma/master/src/lib/record/rest.coffee +34 -0
  139. data/components/indefinido/indemma/master/src/lib/record/restfulable.coffee +487 -0
  140. data/components/indefinido/indemma/master/src/lib/record/scopable.coffee +279 -0
  141. data/components/indefinido/indemma/master/src/lib/record/storable.coffee +49 -0
  142. data/components/indefinido/indemma/master/src/lib/record/translationable.coffee +18 -0
  143. data/components/indefinido/indemma/master/src/lib/record/validatable.coffee +241 -0
  144. data/components/indefinido/indemma/master/src/lib/record/validations/associated.coffee +34 -0
  145. data/components/indefinido/indemma/master/src/lib/record/validations/confirmation.coffee +17 -0
  146. data/components/indefinido/indemma/master/src/lib/record/validations/cpf.coffee +57 -0
  147. data/components/indefinido/indemma/master/src/lib/record/validations/presence.coffee +16 -0
  148. data/components/indefinido/indemma/master/src/lib/record/validations/remote.coffee +61 -0
  149. data/components/indefinido/indemma/master/src/lib/record/validations/type.coffee +31 -0
  150. data/components/indefinido/indemma/master/src/lib/record/validations/validatorable.coffee +5 -0
  151. data/components/indefinido/indemma/master/src/lib/record.coffee +143 -0
  152. data/components/indefinido/indemma/master/src/spec/record/associable_spec.coffee +205 -0
  153. data/components/indefinido/indemma/master/src/spec/record/dirtyable_spec.coffee +47 -0
  154. data/components/indefinido/indemma/master/src/spec/record/maid_spec.coffee +34 -0
  155. data/components/indefinido/indemma/master/src/spec/record/persistable_spec.coffee +39 -0
  156. data/components/indefinido/indemma/master/src/spec/record/queryable_spec.coffee +33 -0
  157. data/components/indefinido/indemma/master/src/spec/record/resource_spec.coffee +69 -0
  158. data/components/indefinido/indemma/master/src/spec/record/rest_spec.coffee +22 -0
  159. data/components/indefinido/indemma/master/src/spec/record/restfulable_spec.coffee +257 -0
  160. data/components/indefinido/indemma/master/src/spec/record/scopable_spec.coffee +227 -0
  161. data/components/indefinido/indemma/master/src/spec/record/storable_spec.coffee +39 -0
  162. data/components/indefinido/indemma/master/src/spec/record/translationable.coffee +19 -0
  163. data/components/indefinido/indemma/master/src/spec/record/validatable_spec.coffee +127 -0
  164. data/components/indefinido/indemma/master/src/spec/record/validations/associated_spec.coffee +35 -0
  165. data/components/indefinido/indemma/master/src/spec/record/validations/confirmation_spec.coffee +25 -0
  166. data/components/indefinido/indemma/master/src/spec/record/validations/cpf_spec.coffee +27 -0
  167. data/components/indefinido/indemma/master/src/spec/record/validations/presence_spec.coffee +24 -0
  168. data/components/indefinido/indemma/master/src/spec/record/validations/remote_spec.coffee +74 -0
  169. data/components/indefinido/indemma/master/src/spec/record/validations/type_spec.coffee +33 -0
  170. data/components/indefinido/indemma/master/src/spec/record_spec.coffee +29 -0
  171. data/components/indefinido/indemma/master/src/spec/spec_helper.coffee +11 -0
  172. data/components/indefinido/indemma/master/src/spec/support/value_objects/phone.coffee +30 -0
  173. data/components/indefinido/indemma/master/vendor/object/mixin.js +196 -0
  174. data/components/indefinido/indemma/master/vendor/spec/sinon/assert.js +199 -0
  175. data/components/indefinido/indemma/master/vendor/spec/sinon/behavior.js +334 -0
  176. data/components/indefinido/indemma/master/vendor/spec/sinon/call.js +205 -0
  177. data/components/indefinido/indemma/master/vendor/spec/sinon/collection.js +155 -0
  178. data/components/indefinido/indemma/master/vendor/spec/sinon/match.js +245 -0
  179. data/components/indefinido/indemma/master/vendor/spec/sinon/mock.js +451 -0
  180. data/components/indefinido/indemma/master/vendor/spec/sinon/sandbox.js +144 -0
  181. data/components/indefinido/indemma/master/vendor/spec/sinon/spy.js +413 -0
  182. data/components/indefinido/indemma/master/vendor/spec/sinon/stub.js +161 -0
  183. data/components/indefinido/indemma/master/vendor/spec/sinon/test.js +77 -0
  184. data/components/indefinido/indemma/master/vendor/spec/sinon/test_case.js +99 -0
  185. data/components/indefinido/indemma/master/vendor/spec/sinon/util/event.js +94 -0
  186. data/components/indefinido/indemma/master/vendor/spec/sinon/util/fake_server.js +212 -0
  187. data/components/indefinido/indemma/master/vendor/spec/sinon/util/fake_server_with_clock.js +83 -0
  188. data/components/indefinido/indemma/master/vendor/spec/sinon/util/fake_timers.js +405 -0
  189. data/components/indefinido/indemma/master/vendor/spec/sinon/util/fake_xdomain_request.js +206 -0
  190. data/components/indefinido/indemma/master/vendor/spec/sinon/util/fake_xml_http_request.js +575 -0
  191. data/components/indefinido/indemma/master/vendor/spec/sinon/util/timers_ie.js +31 -0
  192. data/components/indefinido/indemma/master/vendor/spec/sinon/util/xdr_ie.js +14 -0
  193. data/components/indefinido/indemma/master/vendor/spec/sinon/util/xhr_ie.js +19 -0
  194. data/components/indefinido/indemma/master/vendor/spec/sinon.js +383 -0
  195. data/lib/assets/javascripts/value_objects/phone.js.coffee +3 -1
  196. data/lib/assets/javascripts/widgets/viewer/plugins/scopable.js.coffee +5 -5
  197. data/lib/ende/version.rb +1 -1
  198. data/vendor/assets/components/ende_build.css +4 -4
  199. data/vendor/assets/components/ende_build.js +7974 -7889
  200. metadata +191 -5
  201. data/vendor/assets/component/build.css +0 -112
  202. data/vendor/assets/components/build.css +0 -112
  203. data/vendor/assets/components/indemma_with_none.js +0 -30553
@@ -0,0 +1,1631 @@
1
+ // Copyright 2012 Google Inc.
2
+ //
3
+ // Licensed under the Apache License, Version 2.0 (the "License");
4
+ // you may not use this file except in compliance with the License.
5
+ // You may obtain a copy of the License at
6
+ //
7
+ // http://www.apache.org/licenses/LICENSE-2.0
8
+ //
9
+ // Unless required by applicable law or agreed to in writing, software
10
+ // distributed under the License is distributed on an "AS IS" BASIS,
11
+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ // See the License for the specific language governing permissions and
13
+ // limitations under the License.
14
+
15
+ (function(global) {
16
+ 'use strict';
17
+
18
+ // Detect and do basic sanity checking on Object/Array.observe.
19
+ function detectObjectObserve() {
20
+ if (typeof Object.observe !== 'function' ||
21
+ typeof Array.observe !== 'function') {
22
+ return false;
23
+ }
24
+
25
+ var records = [];
26
+
27
+ function callback(recs) {
28
+ records = recs;
29
+ }
30
+
31
+ var test = {};
32
+ var arr = [];
33
+ Object.observe(test, callback);
34
+ Array.observe(arr, callback);
35
+ test.id = 1;
36
+ test.id = 2;
37
+ delete test.id;
38
+ arr.push(1, 2);
39
+ arr.length = 0;
40
+
41
+ Object.deliverChangeRecords(callback);
42
+ if (records.length !== 5)
43
+ return false;
44
+
45
+ if (records[0].type != 'add' ||
46
+ records[1].type != 'update' ||
47
+ records[2].type != 'delete' ||
48
+ records[3].type != 'splice' ||
49
+ records[4].type != 'splice') {
50
+ return false;
51
+ }
52
+
53
+ Object.unobserve(test, callback);
54
+ Array.unobserve(arr, callback);
55
+
56
+ return true;
57
+ }
58
+
59
+ var hasObserve = detectObjectObserve();
60
+
61
+ function detectEval() {
62
+ // Don't test for eval if we're running in a Chrome App environment.
63
+ // We check for APIs set that only exist in a Chrome App context.
64
+ if (typeof chrome !== 'undefined' && chrome.app && chrome.app.runtime) {
65
+ return false;
66
+ }
67
+
68
+ try {
69
+ var f = new Function('', 'return true;');
70
+ return f();
71
+ } catch (ex) {
72
+ return false;
73
+ }
74
+ }
75
+
76
+ var hasEval = detectEval();
77
+
78
+ function isIndex(s) {
79
+ return +s === s >>> 0;
80
+ }
81
+
82
+ function toNumber(s) {
83
+ return +s;
84
+ }
85
+
86
+ function isObject(obj) {
87
+ return obj === Object(obj);
88
+ }
89
+
90
+ var numberIsNaN = Number.isNaN || function isNaN(value) {
91
+ return typeof value === 'number' && global.isNaN(value);
92
+ }
93
+
94
+ function areSameValue(left, right) {
95
+ if (left === right)
96
+ return left !== 0 || 1 / left === 1 / right;
97
+ if (numberIsNaN(left) && numberIsNaN(right))
98
+ return true;
99
+
100
+ return left !== left && right !== right;
101
+ }
102
+
103
+ var createObject = ('__proto__' in {}) ?
104
+ function(obj) { return obj; } :
105
+ function(obj) {
106
+ var proto = obj.__proto__;
107
+ if (!proto)
108
+ return obj;
109
+ var newObject = Object.create(proto);
110
+ Object.getOwnPropertyNames(obj).forEach(function(name) {
111
+ Object.defineProperty(newObject, name,
112
+ Object.getOwnPropertyDescriptor(obj, name));
113
+ });
114
+ return newObject;
115
+ };
116
+
117
+ var identStart = '[\$_a-zA-Z]';
118
+ var identPart = '[\$_a-zA-Z0-9]';
119
+ var ident = identStart + '+' + identPart + '*';
120
+ var elementIndex = '(?:[0-9]|[1-9]+[0-9]+)';
121
+ var identOrElementIndex = '(?:' + ident + '|' + elementIndex + ')';
122
+ var path = '(?:' + identOrElementIndex + ')(?:\\s*\\.\\s*' + identOrElementIndex + ')*';
123
+ var pathRegExp = new RegExp('^' + path + '$');
124
+
125
+ function isPathValid(s) {
126
+ if (typeof s != 'string')
127
+ return false;
128
+ s = s.trim();
129
+
130
+ if (s == '')
131
+ return true;
132
+
133
+ if (s[0] == '.')
134
+ return false;
135
+
136
+ return pathRegExp.test(s);
137
+ }
138
+
139
+ var constructorIsPrivate = {};
140
+
141
+ function Path(s, privateToken) {
142
+ if (privateToken !== constructorIsPrivate)
143
+ throw Error('Use Path.get to retrieve path objects');
144
+
145
+ if (s.trim() == '')
146
+ return this;
147
+
148
+ if (isIndex(s)) {
149
+ this.push(s);
150
+ return this;
151
+ }
152
+
153
+ s.split(/\s*\.\s*/).filter(function(part) {
154
+ return part;
155
+ }).forEach(function(part) {
156
+ this.push(part);
157
+ }, this);
158
+
159
+ if (hasEval && this.length) {
160
+ this.getValueFrom = this.compiledGetValueFromFn();
161
+ }
162
+ }
163
+
164
+ // TODO(rafaelw): Make simple LRU cache
165
+ var pathCache = {};
166
+
167
+ function getPath(pathString) {
168
+ if (pathString instanceof Path)
169
+ return pathString;
170
+
171
+ if (pathString == null)
172
+ pathString = '';
173
+
174
+ if (typeof pathString !== 'string')
175
+ pathString = String(pathString);
176
+
177
+ var path = pathCache[pathString];
178
+ if (path)
179
+ return path;
180
+ if (!isPathValid(pathString))
181
+ return invalidPath;
182
+ var path = new Path(pathString, constructorIsPrivate);
183
+ pathCache[pathString] = path;
184
+ return path;
185
+ }
186
+
187
+ Path.get = getPath;
188
+
189
+ Path.prototype = createObject({
190
+ __proto__: [],
191
+ valid: true,
192
+
193
+ toString: function() {
194
+ return this.join('.');
195
+ },
196
+
197
+ getValueFrom: function(obj, directObserver) {
198
+ for (var i = 0; i < this.length; i++) {
199
+ if (obj == null)
200
+ return;
201
+ obj = obj[this[i]];
202
+ }
203
+ return obj;
204
+ },
205
+
206
+ iterateObjects: function(obj, observe) {
207
+ for (var i = 0; i < this.length; i++) {
208
+ if (i)
209
+ obj = obj[this[i - 1]];
210
+ if (!isObject(obj))
211
+ return;
212
+ observe(obj, this[0]);
213
+ }
214
+ },
215
+
216
+ compiledGetValueFromFn: function() {
217
+ var accessors = this.map(function(ident) {
218
+ return isIndex(ident) ? '["' + ident + '"]' : '.' + ident;
219
+ });
220
+
221
+ var str = '';
222
+ var pathString = 'obj';
223
+ str += 'if (obj != null';
224
+ var i = 0;
225
+ for (; i < (this.length - 1); i++) {
226
+ var ident = this[i];
227
+ pathString += accessors[i];
228
+ str += ' &&\n ' + pathString + ' != null';
229
+ }
230
+ str += ')\n';
231
+
232
+ pathString += accessors[i];
233
+
234
+ str += ' return ' + pathString + ';\nelse\n return undefined;';
235
+ return new Function('obj', str);
236
+ },
237
+
238
+ setValueFrom: function(obj, value) {
239
+ if (!this.length)
240
+ return false;
241
+
242
+ for (var i = 0; i < this.length - 1; i++) {
243
+ if (!isObject(obj))
244
+ return false;
245
+ obj = obj[this[i]];
246
+ }
247
+
248
+ if (!isObject(obj))
249
+ return false;
250
+
251
+ obj[this[i]] = value;
252
+ return true;
253
+ }
254
+ });
255
+
256
+ var invalidPath = new Path('', constructorIsPrivate);
257
+ invalidPath.valid = false;
258
+ invalidPath.getValueFrom = invalidPath.setValueFrom = function() {};
259
+
260
+ var MAX_DIRTY_CHECK_CYCLES = 1000;
261
+
262
+ function dirtyCheck(observer) {
263
+ var cycles = 0;
264
+ while (cycles < MAX_DIRTY_CHECK_CYCLES && observer.check_()) {
265
+ cycles++;
266
+ }
267
+ if (global.testingExposeCycleCount)
268
+ global.dirtyCheckCycleCount = cycles;
269
+
270
+ return cycles > 0;
271
+ }
272
+
273
+ function objectIsEmpty(object) {
274
+ for (var prop in object)
275
+ return false;
276
+ return true;
277
+ }
278
+
279
+ function diffIsEmpty(diff) {
280
+ return objectIsEmpty(diff.added) &&
281
+ objectIsEmpty(diff.removed) &&
282
+ objectIsEmpty(diff.changed);
283
+ }
284
+
285
+ function diffObjectFromOldObject(object, oldObject) {
286
+ var added = {};
287
+ var removed = {};
288
+ var changed = {};
289
+
290
+ for (var prop in oldObject) {
291
+ var newValue = object[prop];
292
+
293
+ if (newValue !== undefined && newValue === oldObject[prop])
294
+ continue;
295
+
296
+ if (!(prop in object)) {
297
+ removed[prop] = undefined;
298
+ continue;
299
+ }
300
+
301
+ if (newValue !== oldObject[prop])
302
+ changed[prop] = newValue;
303
+ }
304
+
305
+ for (var prop in object) {
306
+ if (prop in oldObject)
307
+ continue;
308
+
309
+ added[prop] = object[prop];
310
+ }
311
+
312
+ if (Array.isArray(object) && object.length !== oldObject.length)
313
+ changed.length = object.length;
314
+
315
+ return {
316
+ added: added,
317
+ removed: removed,
318
+ changed: changed
319
+ };
320
+ }
321
+
322
+ var eomTasks = [];
323
+ function runEOMTasks() {
324
+ if (!eomTasks.length)
325
+ return false;
326
+
327
+ for (var i = 0; i < eomTasks.length; i++) {
328
+ eomTasks[i]();
329
+ }
330
+ eomTasks.length = 0;
331
+ return true;
332
+ }
333
+
334
+ var runEOM = hasObserve ? (function(){
335
+ var eomObj = { pingPong: true };
336
+ var eomRunScheduled = false;
337
+
338
+ Object.observe(eomObj, function() {
339
+ runEOMTasks();
340
+ eomRunScheduled = false;
341
+ });
342
+
343
+ return function(fn) {
344
+ eomTasks.push(fn);
345
+ if (!eomRunScheduled) {
346
+ eomRunScheduled = true;
347
+ eomObj.pingPong = !eomObj.pingPong;
348
+ }
349
+ };
350
+ })() :
351
+ (function() {
352
+ return function(fn) {
353
+ eomTasks.push(fn);
354
+ };
355
+ })();
356
+
357
+ var observedObjectCache = [];
358
+
359
+ function newObservedObject() {
360
+ var observer;
361
+ var object;
362
+ var discardRecords = false;
363
+ var first = true;
364
+
365
+ function callback(records) {
366
+ if (observer && observer.state_ === OPENED && !discardRecords)
367
+ observer.check_(records);
368
+ }
369
+
370
+ return {
371
+ open: function(obs) {
372
+ if (observer)
373
+ throw Error('ObservedObject in use');
374
+
375
+ if (!first)
376
+ Object.deliverChangeRecords(callback);
377
+
378
+ observer = obs;
379
+ first = false;
380
+ },
381
+ observe: function(obj, arrayObserve) {
382
+ object = obj;
383
+ if (arrayObserve)
384
+ Array.observe(object, callback);
385
+ else
386
+ Object.observe(object, callback);
387
+ },
388
+ deliver: function(discard) {
389
+ discardRecords = discard;
390
+ Object.deliverChangeRecords(callback);
391
+ discardRecords = false;
392
+ },
393
+ close: function() {
394
+ observer = undefined;
395
+ Object.unobserve(object, callback);
396
+ observedObjectCache.push(this);
397
+ }
398
+ };
399
+ }
400
+
401
+ /*
402
+ * The observedSet abstraction is a perf optimization which reduces the total
403
+ * number of Object.observe observations of a set of objects. The idea is that
404
+ * groups of Observers will have some object dependencies in common and this
405
+ * observed set ensures that each object in the transitive closure of
406
+ * dependencies is only observed once. The observedSet acts as a write barrier
407
+ * such that whenever any change comes through, all Observers are checked for
408
+ * changed values.
409
+ *
410
+ * Note that this optimization is explicitly moving work from setup-time to
411
+ * change-time.
412
+ *
413
+ * TODO(rafaelw): Implement "garbage collection". In order to move work off
414
+ * the critical path, when Observers are closed, their observed objects are
415
+ * not Object.unobserve(d). As a result, it's possible that if the observedSet
416
+ * is kept open, but some Observers have been closed, it could cause "leaks"
417
+ * (prevent otherwise collectable objects from being collected). At some
418
+ * point, we should implement incremental "gc" which keeps a list of
419
+ * observedSets which may need clean-up and does small amounts of cleanup on a
420
+ * timeout until all is clean.
421
+ */
422
+
423
+ function getObservedObject(observer, object, arrayObserve) {
424
+ var dir = observedObjectCache.pop() || newObservedObject();
425
+ dir.open(observer);
426
+ dir.observe(object, arrayObserve);
427
+ return dir;
428
+ }
429
+
430
+ var observedSetCache = [];
431
+
432
+ function newObservedSet() {
433
+ var observerCount = 0;
434
+ var observers = [];
435
+ var objects = [];
436
+ var rootObj;
437
+ var rootObjProps;
438
+
439
+ function observe(obj, prop) {
440
+ if (!obj)
441
+ return;
442
+
443
+ if (obj === rootObj)
444
+ rootObjProps[prop] = true;
445
+
446
+ if (objects.indexOf(obj) < 0) {
447
+ objects.push(obj);
448
+ Object.observe(obj, callback);
449
+ }
450
+
451
+ observe(Object.getPrototypeOf(obj), prop);
452
+ }
453
+
454
+ function allRootObjNonObservedProps(recs) {
455
+ for (var i = 0; i < recs.length; i++) {
456
+ var rec = recs[i];
457
+ if (rec.object !== rootObj ||
458
+ rootObjProps[rec.name] ||
459
+ rec.type === 'setPrototype') {
460
+ return false;
461
+ }
462
+ }
463
+ return true;
464
+ }
465
+
466
+ function callback(recs) {
467
+ if (allRootObjNonObservedProps(recs))
468
+ return;
469
+
470
+ var observer;
471
+ for (var i = 0; i < observers.length; i++) {
472
+ observer = observers[i];
473
+ if (observer.state_ == OPENED) {
474
+ observer.iterateObjects_(observe);
475
+ }
476
+ }
477
+
478
+ for (var i = 0; i < observers.length; i++) {
479
+ observer = observers[i];
480
+ if (observer.state_ == OPENED) {
481
+ observer.check_();
482
+ }
483
+ }
484
+ }
485
+
486
+ var record = {
487
+ object: undefined,
488
+ objects: objects,
489
+ open: function(obs, object) {
490
+ if (!rootObj) {
491
+ rootObj = object;
492
+ rootObjProps = {};
493
+ }
494
+
495
+ observers.push(obs);
496
+ observerCount++;
497
+ obs.iterateObjects_(observe);
498
+ },
499
+ close: function(obs) {
500
+ observerCount--;
501
+ if (observerCount > 0) {
502
+ return;
503
+ }
504
+
505
+ for (var i = 0; i < objects.length; i++) {
506
+ Object.unobserve(objects[i], callback);
507
+ Observer.unobservedCount++;
508
+ }
509
+
510
+ observers.length = 0;
511
+ objects.length = 0;
512
+ rootObj = undefined;
513
+ rootObjProps = undefined;
514
+ observedSetCache.push(this);
515
+ }
516
+ };
517
+
518
+ return record;
519
+ }
520
+
521
+ var lastObservedSet;
522
+
523
+ function getObservedSet(observer, obj) {
524
+ if (!lastObservedSet || lastObservedSet.object !== obj) {
525
+ lastObservedSet = observedSetCache.pop() || newObservedSet();
526
+ lastObservedSet.object = obj;
527
+ }
528
+ lastObservedSet.open(observer, obj);
529
+ return lastObservedSet;
530
+ }
531
+
532
+ var UNOPENED = 0;
533
+ var OPENED = 1;
534
+ var CLOSED = 2;
535
+ var RESETTING = 3;
536
+
537
+ var nextObserverId = 1;
538
+
539
+ function Observer() {
540
+ this.state_ = UNOPENED;
541
+ this.callback_ = undefined;
542
+ this.target_ = undefined; // TODO(rafaelw): Should be WeakRef
543
+ this.directObserver_ = undefined;
544
+ this.value_ = undefined;
545
+ this.id_ = nextObserverId++;
546
+ }
547
+
548
+ Observer.prototype = {
549
+ open: function(callback, target) {
550
+ if (this.state_ != UNOPENED)
551
+ throw Error('Observer has already been opened.');
552
+
553
+ addToAll(this);
554
+ this.callback_ = callback;
555
+ this.target_ = target;
556
+ this.connect_();
557
+ this.state_ = OPENED;
558
+ return this.value_;
559
+ },
560
+
561
+ close: function() {
562
+ if (this.state_ != OPENED)
563
+ return;
564
+
565
+ removeFromAll(this);
566
+ this.disconnect_();
567
+ this.value_ = undefined;
568
+ this.callback_ = undefined;
569
+ this.target_ = undefined;
570
+ this.state_ = CLOSED;
571
+ },
572
+
573
+ deliver: function() {
574
+ if (this.state_ != OPENED)
575
+ return;
576
+
577
+ dirtyCheck(this);
578
+ },
579
+
580
+ report_: function(changes) {
581
+ try {
582
+ this.callback_.apply(this.target_, changes);
583
+ } catch (ex) {
584
+ Observer._errorThrownDuringCallback = true;
585
+ console.error('Exception caught during observer callback: ' +
586
+ (ex.stack || ex));
587
+ }
588
+ },
589
+
590
+ discardChanges: function() {
591
+ this.check_(undefined, true);
592
+ return this.value_;
593
+ }
594
+ }
595
+
596
+ var collectObservers = !hasObserve;
597
+ var allObservers;
598
+ Observer._allObserversCount = 0;
599
+
600
+ if (collectObservers) {
601
+ allObservers = [];
602
+ }
603
+
604
+ function addToAll(observer) {
605
+ Observer._allObserversCount++;
606
+ if (!collectObservers)
607
+ return;
608
+
609
+ allObservers.push(observer);
610
+ }
611
+
612
+ function removeFromAll(observer) {
613
+ Observer._allObserversCount--;
614
+ }
615
+
616
+ var runningMicrotaskCheckpoint = false;
617
+
618
+ var hasDebugForceFullDelivery = hasObserve && (function() {
619
+ try {
620
+ eval('%RunMicrotasks()');
621
+ return true;
622
+ } catch (ex) {
623
+ return false;
624
+ }
625
+ })();
626
+
627
+ global.Platform = global.Platform || {};
628
+
629
+ global.Platform.performMicrotaskCheckpoint = function() {
630
+ if (runningMicrotaskCheckpoint)
631
+ return;
632
+
633
+ if (hasDebugForceFullDelivery) {
634
+ eval('%RunMicrotasks()');
635
+ return;
636
+ }
637
+
638
+ if (!collectObservers)
639
+ return;
640
+
641
+ runningMicrotaskCheckpoint = true;
642
+
643
+ var cycles = 0;
644
+ var anyChanged, toCheck;
645
+
646
+ do {
647
+ cycles++;
648
+ toCheck = allObservers;
649
+ allObservers = [];
650
+ anyChanged = false;
651
+
652
+ for (var i = 0; i < toCheck.length; i++) {
653
+ var observer = toCheck[i];
654
+ if (observer.state_ != OPENED)
655
+ continue;
656
+
657
+ if (observer.check_())
658
+ anyChanged = true;
659
+
660
+ allObservers.push(observer);
661
+ }
662
+ if (runEOMTasks())
663
+ anyChanged = true;
664
+ } while (cycles < MAX_DIRTY_CHECK_CYCLES && anyChanged);
665
+
666
+ if (global.testingExposeCycleCount)
667
+ global.dirtyCheckCycleCount = cycles;
668
+
669
+ runningMicrotaskCheckpoint = false;
670
+ };
671
+
672
+ if (collectObservers) {
673
+ global.Platform.clearObservers = function() {
674
+ allObservers = [];
675
+ };
676
+ }
677
+
678
+ function ObjectObserver(object) {
679
+ Observer.call(this);
680
+ this.value_ = object;
681
+ this.oldObject_ = undefined;
682
+ }
683
+
684
+ ObjectObserver.prototype = createObject({
685
+ __proto__: Observer.prototype,
686
+
687
+ arrayObserve: false,
688
+
689
+ connect_: function(callback, target) {
690
+ if (hasObserve) {
691
+ this.directObserver_ = getObservedObject(this, this.value_,
692
+ this.arrayObserve);
693
+ } else {
694
+ this.oldObject_ = this.copyObject(this.value_);
695
+ }
696
+
697
+ },
698
+
699
+ copyObject: function(object) {
700
+ var copy = Array.isArray(object) ? [] : {};
701
+ for (var prop in object) {
702
+ copy[prop] = object[prop];
703
+ };
704
+ if (Array.isArray(object))
705
+ copy.length = object.length;
706
+ return copy;
707
+ },
708
+
709
+ check_: function(changeRecords, skipChanges) {
710
+ var diff;
711
+ var oldValues;
712
+ if (hasObserve) {
713
+ if (!changeRecords)
714
+ return false;
715
+
716
+ oldValues = {};
717
+ diff = diffObjectFromChangeRecords(this.value_, changeRecords,
718
+ oldValues);
719
+ } else {
720
+ oldValues = this.oldObject_;
721
+ diff = diffObjectFromOldObject(this.value_, this.oldObject_);
722
+ }
723
+
724
+ if (diffIsEmpty(diff))
725
+ return false;
726
+
727
+ if (!hasObserve)
728
+ this.oldObject_ = this.copyObject(this.value_);
729
+
730
+ this.report_([
731
+ diff.added || {},
732
+ diff.removed || {},
733
+ diff.changed || {},
734
+ function(property) {
735
+ return oldValues[property];
736
+ }
737
+ ]);
738
+
739
+ return true;
740
+ },
741
+
742
+ disconnect_: function() {
743
+ if (hasObserve) {
744
+ this.directObserver_.close();
745
+ this.directObserver_ = undefined;
746
+ } else {
747
+ this.oldObject_ = undefined;
748
+ }
749
+ },
750
+
751
+ deliver: function() {
752
+ if (this.state_ != OPENED)
753
+ return;
754
+
755
+ if (hasObserve)
756
+ this.directObserver_.deliver(false);
757
+ else
758
+ dirtyCheck(this);
759
+ },
760
+
761
+ discardChanges: function() {
762
+ if (this.directObserver_)
763
+ this.directObserver_.deliver(true);
764
+ else
765
+ this.oldObject_ = this.copyObject(this.value_);
766
+
767
+ return this.value_;
768
+ }
769
+ });
770
+
771
+ function ArrayObserver(array) {
772
+ if (!Array.isArray(array))
773
+ throw Error('Provided object is not an Array');
774
+ ObjectObserver.call(this, array);
775
+ }
776
+
777
+ ArrayObserver.prototype = createObject({
778
+
779
+ __proto__: ObjectObserver.prototype,
780
+
781
+ arrayObserve: true,
782
+
783
+ copyObject: function(arr) {
784
+ return arr.slice();
785
+ },
786
+
787
+ check_: function(changeRecords) {
788
+ var splices;
789
+ if (hasObserve) {
790
+ if (!changeRecords)
791
+ return false;
792
+ splices = projectArraySplices(this.value_, changeRecords);
793
+ } else {
794
+ splices = calcSplices(this.value_, 0, this.value_.length,
795
+ this.oldObject_, 0, this.oldObject_.length);
796
+ }
797
+
798
+ if (!splices || !splices.length)
799
+ return false;
800
+
801
+ if (!hasObserve)
802
+ this.oldObject_ = this.copyObject(this.value_);
803
+
804
+ this.report_([splices]);
805
+ return true;
806
+ }
807
+ });
808
+
809
+ ArrayObserver.applySplices = function(previous, current, splices) {
810
+ splices.forEach(function(splice) {
811
+ var spliceArgs = [splice.index, splice.removed.length];
812
+ var addIndex = splice.index;
813
+ while (addIndex < splice.index + splice.addedCount) {
814
+ spliceArgs.push(current[addIndex]);
815
+ addIndex++;
816
+ }
817
+
818
+ Array.prototype.splice.apply(previous, spliceArgs);
819
+ });
820
+ };
821
+
822
+ function PathObserver(object, path) {
823
+ Observer.call(this);
824
+
825
+ this.object_ = object;
826
+ this.path_ = getPath(path);
827
+ this.directObserver_ = undefined;
828
+ }
829
+
830
+ PathObserver.prototype = createObject({
831
+ __proto__: Observer.prototype,
832
+
833
+ connect_: function() {
834
+ if (hasObserve)
835
+ this.directObserver_ = getObservedSet(this, this.object_);
836
+
837
+ this.check_(undefined, true);
838
+ },
839
+
840
+ disconnect_: function() {
841
+ this.value_ = undefined;
842
+
843
+ if (this.directObserver_) {
844
+ this.directObserver_.close(this);
845
+ this.directObserver_ = undefined;
846
+ }
847
+ },
848
+
849
+ iterateObjects_: function(observe) {
850
+ this.path_.iterateObjects(this.object_, observe);
851
+ },
852
+
853
+ check_: function(changeRecords, skipChanges) {
854
+ var oldValue = this.value_;
855
+ this.value_ = this.path_.getValueFrom(this.object_);
856
+ if (skipChanges || areSameValue(this.value_, oldValue))
857
+ return false;
858
+
859
+ this.report_([this.value_, oldValue]);
860
+ return true;
861
+ },
862
+
863
+ setValue: function(newValue) {
864
+ if (this.path_)
865
+ this.path_.setValueFrom(this.object_, newValue);
866
+ }
867
+ });
868
+
869
+ function CompoundObserver(reportChangesOnOpen) {
870
+ Observer.call(this);
871
+
872
+ this.reportChangesOnOpen_ = reportChangesOnOpen;
873
+ this.value_ = [];
874
+ this.directObserver_ = undefined;
875
+ this.observed_ = [];
876
+ }
877
+
878
+ var observerSentinel = {};
879
+
880
+ CompoundObserver.prototype = createObject({
881
+ __proto__: Observer.prototype,
882
+
883
+ connect_: function() {
884
+ if (hasObserve) {
885
+ var object;
886
+ var needsDirectObserver = false;
887
+ for (var i = 0; i < this.observed_.length; i += 2) {
888
+ object = this.observed_[i]
889
+ if (object !== observerSentinel) {
890
+ needsDirectObserver = true;
891
+ break;
892
+ }
893
+ }
894
+
895
+ if (needsDirectObserver)
896
+ this.directObserver_ = getObservedSet(this, object);
897
+ }
898
+
899
+ this.check_(undefined, !this.reportChangesOnOpen_);
900
+ },
901
+
902
+ disconnect_: function() {
903
+ for (var i = 0; i < this.observed_.length; i += 2) {
904
+ if (this.observed_[i] === observerSentinel)
905
+ this.observed_[i + 1].close();
906
+ }
907
+ this.observed_.length = 0;
908
+ this.value_.length = 0;
909
+
910
+ if (this.directObserver_) {
911
+ this.directObserver_.close(this);
912
+ this.directObserver_ = undefined;
913
+ }
914
+ },
915
+
916
+ addPath: function(object, path) {
917
+ if (this.state_ != UNOPENED && this.state_ != RESETTING)
918
+ throw Error('Cannot add paths once started.');
919
+
920
+ var path = getPath(path);
921
+ this.observed_.push(object, path);
922
+ if (!this.reportChangesOnOpen_)
923
+ return;
924
+ var index = this.observed_.length / 2 - 1;
925
+ this.value_[index] = path.getValueFrom(object);
926
+ },
927
+
928
+ addObserver: function(observer) {
929
+ if (this.state_ != UNOPENED && this.state_ != RESETTING)
930
+ throw Error('Cannot add observers once started.');
931
+
932
+ this.observed_.push(observerSentinel, observer);
933
+ if (!this.reportChangesOnOpen_)
934
+ return;
935
+ var index = this.observed_.length / 2 - 1;
936
+ this.value_[index] = observer.open(this.deliver, this);
937
+ },
938
+
939
+ startReset: function() {
940
+ if (this.state_ != OPENED)
941
+ throw Error('Can only reset while open');
942
+
943
+ this.state_ = RESETTING;
944
+ this.disconnect_();
945
+ },
946
+
947
+ finishReset: function() {
948
+ if (this.state_ != RESETTING)
949
+ throw Error('Can only finishReset after startReset');
950
+ this.state_ = OPENED;
951
+ this.connect_();
952
+
953
+ return this.value_;
954
+ },
955
+
956
+ iterateObjects_: function(observe) {
957
+ var object;
958
+ for (var i = 0; i < this.observed_.length; i += 2) {
959
+ object = this.observed_[i]
960
+ if (object !== observerSentinel)
961
+ this.observed_[i + 1].iterateObjects(object, observe)
962
+ }
963
+ },
964
+
965
+ check_: function(changeRecords, skipChanges) {
966
+ var oldValues;
967
+ for (var i = 0; i < this.observed_.length; i += 2) {
968
+ var object = this.observed_[i];
969
+ var path = this.observed_[i+1];
970
+ var value;
971
+ if (object === observerSentinel) {
972
+ var observable = path;
973
+ value = this.state_ === UNOPENED ?
974
+ observable.open(this.deliver, this) :
975
+ observable.discardChanges();
976
+ } else {
977
+ value = path.getValueFrom(object);
978
+ }
979
+
980
+ if (skipChanges) {
981
+ this.value_[i / 2] = value;
982
+ continue;
983
+ }
984
+
985
+ if (areSameValue(value, this.value_[i / 2]))
986
+ continue;
987
+
988
+ oldValues = oldValues || [];
989
+ oldValues[i / 2] = this.value_[i / 2];
990
+ this.value_[i / 2] = value;
991
+ }
992
+
993
+ if (!oldValues)
994
+ return false;
995
+
996
+ // TODO(rafaelw): Having observed_ as the third callback arg here is
997
+ // pretty lame API. Fix.
998
+ this.report_([this.value_, oldValues, this.observed_]);
999
+ return true;
1000
+ }
1001
+ });
1002
+
1003
+ function identFn(value) { return value; }
1004
+
1005
+ function ObserverTransform(observable, getValueFn, setValueFn,
1006
+ dontPassThroughSet) {
1007
+ this.callback_ = undefined;
1008
+ this.target_ = undefined;
1009
+ this.value_ = undefined;
1010
+ this.observable_ = observable;
1011
+ this.getValueFn_ = getValueFn || identFn;
1012
+ this.setValueFn_ = setValueFn || identFn;
1013
+ // TODO(rafaelw): This is a temporary hack. PolymerExpressions needs this
1014
+ // at the moment because of a bug in it's dependency tracking.
1015
+ this.dontPassThroughSet_ = dontPassThroughSet;
1016
+ }
1017
+
1018
+ ObserverTransform.prototype = {
1019
+ open: function(callback, target) {
1020
+ this.callback_ = callback;
1021
+ this.target_ = target;
1022
+ this.value_ =
1023
+ this.getValueFn_(this.observable_.open(this.observedCallback_, this));
1024
+ return this.value_;
1025
+ },
1026
+
1027
+ observedCallback_: function(value) {
1028
+ value = this.getValueFn_(value);
1029
+ if (areSameValue(value, this.value_))
1030
+ return;
1031
+ var oldValue = this.value_;
1032
+ this.value_ = value;
1033
+ this.callback_.call(this.target_, this.value_, oldValue);
1034
+ },
1035
+
1036
+ discardChanges: function() {
1037
+ this.value_ = this.getValueFn_(this.observable_.discardChanges());
1038
+ return this.value_;
1039
+ },
1040
+
1041
+ deliver: function() {
1042
+ return this.observable_.deliver();
1043
+ },
1044
+
1045
+ setValue: function(value) {
1046
+ value = this.setValueFn_(value);
1047
+ if (!this.dontPassThroughSet_ && this.observable_.setValue)
1048
+ return this.observable_.setValue(value);
1049
+ },
1050
+
1051
+ close: function() {
1052
+ if (this.observable_)
1053
+ this.observable_.close();
1054
+ this.callback_ = undefined;
1055
+ this.target_ = undefined;
1056
+ this.observable_ = undefined;
1057
+ this.value_ = undefined;
1058
+ this.getValueFn_ = undefined;
1059
+ this.setValueFn_ = undefined;
1060
+ }
1061
+ }
1062
+
1063
+ var expectedRecordTypes = {
1064
+ add: true,
1065
+ update: true,
1066
+ delete: true
1067
+ };
1068
+
1069
+ var updateRecord = {
1070
+ object: undefined,
1071
+ type: 'update',
1072
+ name: undefined,
1073
+ oldValue: undefined
1074
+ };
1075
+
1076
+ function notify(object, name, value, oldValue) {
1077
+ if (areSameValue(value, oldValue))
1078
+ return;
1079
+
1080
+ // TODO(rafaelw): Hack hack hack. This entire code really needs to move
1081
+ // out of observe-js into polymer.
1082
+ if (typeof object.propertyChanged_ == 'function')
1083
+ object.propertyChanged_(name, value, oldValue);
1084
+
1085
+ if (!hasObserve)
1086
+ return;
1087
+
1088
+ var notifier = object.notifier_;
1089
+ if (!notifier)
1090
+ notifier = object.notifier_ = Object.getNotifier(object);
1091
+
1092
+ updateRecord.object = object;
1093
+ updateRecord.name = name;
1094
+ updateRecord.oldValue = oldValue;
1095
+
1096
+ notifier.notify(updateRecord);
1097
+ }
1098
+
1099
+ Observer.createBindablePrototypeAccessor = function(proto, name) {
1100
+ var privateName = name + '_';
1101
+ var privateObservable = name + 'Observable_';
1102
+
1103
+ proto[privateName] = proto[name];
1104
+
1105
+ Object.defineProperty(proto, name, {
1106
+ get: function() {
1107
+ var observable = this[privateObservable];
1108
+ if (observable)
1109
+ observable.deliver();
1110
+
1111
+ return this[privateName];
1112
+ },
1113
+ set: function(value) {
1114
+ var observable = this[privateObservable];
1115
+ if (observable) {
1116
+ observable.setValue(value);
1117
+ return;
1118
+ }
1119
+
1120
+ var oldValue = this[privateName];
1121
+ this[privateName] = value;
1122
+ notify(this, name, value, oldValue);
1123
+
1124
+ return value;
1125
+ },
1126
+ configurable: true
1127
+ });
1128
+ }
1129
+
1130
+ Observer.bindToInstance = function(instance, name, observable, resolveFn) {
1131
+ var privateName = name + '_';
1132
+ var privateObservable = name + 'Observable_';
1133
+
1134
+ instance[privateObservable] = observable;
1135
+ var oldValue = instance[privateName];
1136
+ var value = observable.open(function(value, oldValue) {
1137
+ instance[privateName] = value;
1138
+ notify(instance, name, value, oldValue);
1139
+ });
1140
+
1141
+ if (resolveFn && !areSameValue(oldValue, value)) {
1142
+ var resolvedValue = resolveFn(oldValue, value);
1143
+ if (!areSameValue(value, resolvedValue)) {
1144
+ value = resolvedValue;
1145
+ if (observable.setValue)
1146
+ observable.setValue(value);
1147
+ }
1148
+ }
1149
+
1150
+ instance[privateName] = value;
1151
+ notify(instance, name, value, oldValue);
1152
+
1153
+ return {
1154
+ close: function() {
1155
+ observable.close();
1156
+ instance[privateObservable] = undefined;
1157
+ }
1158
+ };
1159
+ }
1160
+
1161
+ function diffObjectFromChangeRecords(object, changeRecords, oldValues) {
1162
+ var added = {};
1163
+ var removed = {};
1164
+
1165
+ for (var i = 0; i < changeRecords.length; i++) {
1166
+ var record = changeRecords[i];
1167
+ if (!expectedRecordTypes[record.type]) {
1168
+ console.error('Unknown changeRecord type: ' + record.type);
1169
+ console.error(record);
1170
+ continue;
1171
+ }
1172
+
1173
+ if (!(record.name in oldValues))
1174
+ oldValues[record.name] = record.oldValue;
1175
+
1176
+ if (record.type == 'update')
1177
+ continue;
1178
+
1179
+ if (record.type == 'add') {
1180
+ if (record.name in removed)
1181
+ delete removed[record.name];
1182
+ else
1183
+ added[record.name] = true;
1184
+
1185
+ continue;
1186
+ }
1187
+
1188
+ // type = 'delete'
1189
+ if (record.name in added) {
1190
+ delete added[record.name];
1191
+ delete oldValues[record.name];
1192
+ } else {
1193
+ removed[record.name] = true;
1194
+ }
1195
+ }
1196
+
1197
+ for (var prop in added)
1198
+ added[prop] = object[prop];
1199
+
1200
+ for (var prop in removed)
1201
+ removed[prop] = undefined;
1202
+
1203
+ var changed = {};
1204
+ for (var prop in oldValues) {
1205
+ if (prop in added || prop in removed)
1206
+ continue;
1207
+
1208
+ var newValue = object[prop];
1209
+ if (oldValues[prop] !== newValue)
1210
+ changed[prop] = newValue;
1211
+ }
1212
+
1213
+ return {
1214
+ added: added,
1215
+ removed: removed,
1216
+ changed: changed
1217
+ };
1218
+ }
1219
+
1220
+ function newSplice(index, removed, addedCount) {
1221
+ return {
1222
+ index: index,
1223
+ removed: removed,
1224
+ addedCount: addedCount
1225
+ };
1226
+ }
1227
+
1228
+ var EDIT_LEAVE = 0;
1229
+ var EDIT_UPDATE = 1;
1230
+ var EDIT_ADD = 2;
1231
+ var EDIT_DELETE = 3;
1232
+
1233
+ function ArraySplice() {}
1234
+
1235
+ ArraySplice.prototype = {
1236
+
1237
+ // Note: This function is *based* on the computation of the Levenshtein
1238
+ // "edit" distance. The one change is that "updates" are treated as two
1239
+ // edits - not one. With Array splices, an update is really a delete
1240
+ // followed by an add. By retaining this, we optimize for "keeping" the
1241
+ // maximum array items in the original array. For example:
1242
+ //
1243
+ // 'xxxx123' -> '123yyyy'
1244
+ //
1245
+ // With 1-edit updates, the shortest path would be just to update all seven
1246
+ // characters. With 2-edit updates, we delete 4, leave 3, and add 4. This
1247
+ // leaves the substring '123' intact.
1248
+ calcEditDistances: function(current, currentStart, currentEnd,
1249
+ old, oldStart, oldEnd) {
1250
+ // "Deletion" columns
1251
+ var rowCount = oldEnd - oldStart + 1;
1252
+ var columnCount = currentEnd - currentStart + 1;
1253
+ var distances = new Array(rowCount);
1254
+
1255
+ // "Addition" rows. Initialize null column.
1256
+ for (var i = 0; i < rowCount; i++) {
1257
+ distances[i] = new Array(columnCount);
1258
+ distances[i][0] = i;
1259
+ }
1260
+
1261
+ // Initialize null row
1262
+ for (var j = 0; j < columnCount; j++)
1263
+ distances[0][j] = j;
1264
+
1265
+ for (var i = 1; i < rowCount; i++) {
1266
+ for (var j = 1; j < columnCount; j++) {
1267
+ if (this.equals(current[currentStart + j - 1], old[oldStart + i - 1]))
1268
+ distances[i][j] = distances[i - 1][j - 1];
1269
+ else {
1270
+ var north = distances[i - 1][j] + 1;
1271
+ var west = distances[i][j - 1] + 1;
1272
+ distances[i][j] = north < west ? north : west;
1273
+ }
1274
+ }
1275
+ }
1276
+
1277
+ return distances;
1278
+ },
1279
+
1280
+ // This starts at the final weight, and walks "backward" by finding
1281
+ // the minimum previous weight recursively until the origin of the weight
1282
+ // matrix.
1283
+ spliceOperationsFromEditDistances: function(distances) {
1284
+ var i = distances.length - 1;
1285
+ var j = distances[0].length - 1;
1286
+ var current = distances[i][j];
1287
+ var edits = [];
1288
+ while (i > 0 || j > 0) {
1289
+ if (i == 0) {
1290
+ edits.push(EDIT_ADD);
1291
+ j--;
1292
+ continue;
1293
+ }
1294
+ if (j == 0) {
1295
+ edits.push(EDIT_DELETE);
1296
+ i--;
1297
+ continue;
1298
+ }
1299
+ var northWest = distances[i - 1][j - 1];
1300
+ var west = distances[i - 1][j];
1301
+ var north = distances[i][j - 1];
1302
+
1303
+ var min;
1304
+ if (west < north)
1305
+ min = west < northWest ? west : northWest;
1306
+ else
1307
+ min = north < northWest ? north : northWest;
1308
+
1309
+ if (min == northWest) {
1310
+ if (northWest == current) {
1311
+ edits.push(EDIT_LEAVE);
1312
+ } else {
1313
+ edits.push(EDIT_UPDATE);
1314
+ current = northWest;
1315
+ }
1316
+ i--;
1317
+ j--;
1318
+ } else if (min == west) {
1319
+ edits.push(EDIT_DELETE);
1320
+ i--;
1321
+ current = west;
1322
+ } else {
1323
+ edits.push(EDIT_ADD);
1324
+ j--;
1325
+ current = north;
1326
+ }
1327
+ }
1328
+
1329
+ edits.reverse();
1330
+ return edits;
1331
+ },
1332
+
1333
+ /**
1334
+ * Splice Projection functions:
1335
+ *
1336
+ * A splice map is a representation of how a previous array of items
1337
+ * was transformed into a new array of items. Conceptually it is a list of
1338
+ * tuples of
1339
+ *
1340
+ * <index, removed, addedCount>
1341
+ *
1342
+ * which are kept in ascending index order of. The tuple represents that at
1343
+ * the |index|, |removed| sequence of items were removed, and counting forward
1344
+ * from |index|, |addedCount| items were added.
1345
+ */
1346
+
1347
+ /**
1348
+ * Lacking individual splice mutation information, the minimal set of
1349
+ * splices can be synthesized given the previous state and final state of an
1350
+ * array. The basic approach is to calculate the edit distance matrix and
1351
+ * choose the shortest path through it.
1352
+ *
1353
+ * Complexity: O(l * p)
1354
+ * l: The length of the current array
1355
+ * p: The length of the old array
1356
+ */
1357
+ calcSplices: function(current, currentStart, currentEnd,
1358
+ old, oldStart, oldEnd) {
1359
+ var prefixCount = 0;
1360
+ var suffixCount = 0;
1361
+
1362
+ var minLength = Math.min(currentEnd - currentStart, oldEnd - oldStart);
1363
+ if (currentStart == 0 && oldStart == 0)
1364
+ prefixCount = this.sharedPrefix(current, old, minLength);
1365
+
1366
+ if (currentEnd == current.length && oldEnd == old.length)
1367
+ suffixCount = this.sharedSuffix(current, old, minLength - prefixCount);
1368
+
1369
+ currentStart += prefixCount;
1370
+ oldStart += prefixCount;
1371
+ currentEnd -= suffixCount;
1372
+ oldEnd -= suffixCount;
1373
+
1374
+ if (currentEnd - currentStart == 0 && oldEnd - oldStart == 0)
1375
+ return [];
1376
+
1377
+ if (currentStart == currentEnd) {
1378
+ var splice = newSplice(currentStart, [], 0);
1379
+ while (oldStart < oldEnd)
1380
+ splice.removed.push(old[oldStart++]);
1381
+
1382
+ return [ splice ];
1383
+ } else if (oldStart == oldEnd)
1384
+ return [ newSplice(currentStart, [], currentEnd - currentStart) ];
1385
+
1386
+ var ops = this.spliceOperationsFromEditDistances(
1387
+ this.calcEditDistances(current, currentStart, currentEnd,
1388
+ old, oldStart, oldEnd));
1389
+
1390
+ var splice = undefined;
1391
+ var splices = [];
1392
+ var index = currentStart;
1393
+ var oldIndex = oldStart;
1394
+ for (var i = 0; i < ops.length; i++) {
1395
+ switch(ops[i]) {
1396
+ case EDIT_LEAVE:
1397
+ if (splice) {
1398
+ splices.push(splice);
1399
+ splice = undefined;
1400
+ }
1401
+
1402
+ index++;
1403
+ oldIndex++;
1404
+ break;
1405
+ case EDIT_UPDATE:
1406
+ if (!splice)
1407
+ splice = newSplice(index, [], 0);
1408
+
1409
+ splice.addedCount++;
1410
+ index++;
1411
+
1412
+ splice.removed.push(old[oldIndex]);
1413
+ oldIndex++;
1414
+ break;
1415
+ case EDIT_ADD:
1416
+ if (!splice)
1417
+ splice = newSplice(index, [], 0);
1418
+
1419
+ splice.addedCount++;
1420
+ index++;
1421
+ break;
1422
+ case EDIT_DELETE:
1423
+ if (!splice)
1424
+ splice = newSplice(index, [], 0);
1425
+
1426
+ splice.removed.push(old[oldIndex]);
1427
+ oldIndex++;
1428
+ break;
1429
+ }
1430
+ }
1431
+
1432
+ if (splice) {
1433
+ splices.push(splice);
1434
+ }
1435
+ return splices;
1436
+ },
1437
+
1438
+ sharedPrefix: function(current, old, searchLength) {
1439
+ for (var i = 0; i < searchLength; i++)
1440
+ if (!this.equals(current[i], old[i]))
1441
+ return i;
1442
+ return searchLength;
1443
+ },
1444
+
1445
+ sharedSuffix: function(current, old, searchLength) {
1446
+ var index1 = current.length;
1447
+ var index2 = old.length;
1448
+ var count = 0;
1449
+ while (count < searchLength && this.equals(current[--index1], old[--index2]))
1450
+ count++;
1451
+
1452
+ return count;
1453
+ },
1454
+
1455
+ calculateSplices: function(current, previous) {
1456
+ return this.calcSplices(current, 0, current.length, previous, 0,
1457
+ previous.length);
1458
+ },
1459
+
1460
+ equals: function(currentValue, previousValue) {
1461
+ return currentValue === previousValue;
1462
+ }
1463
+ };
1464
+
1465
+ var arraySplice = new ArraySplice();
1466
+
1467
+ function calcSplices(current, currentStart, currentEnd,
1468
+ old, oldStart, oldEnd) {
1469
+ return arraySplice.calcSplices(current, currentStart, currentEnd,
1470
+ old, oldStart, oldEnd);
1471
+ }
1472
+
1473
+ function intersect(start1, end1, start2, end2) {
1474
+ // Disjoint
1475
+ if (end1 < start2 || end2 < start1)
1476
+ return -1;
1477
+
1478
+ // Adjacent
1479
+ if (end1 == start2 || end2 == start1)
1480
+ return 0;
1481
+
1482
+ // Non-zero intersect, span1 first
1483
+ if (start1 < start2) {
1484
+ if (end1 < end2)
1485
+ return end1 - start2; // Overlap
1486
+ else
1487
+ return end2 - start2; // Contained
1488
+ } else {
1489
+ // Non-zero intersect, span2 first
1490
+ if (end2 < end1)
1491
+ return end2 - start1; // Overlap
1492
+ else
1493
+ return end1 - start1; // Contained
1494
+ }
1495
+ }
1496
+
1497
+ function mergeSplice(splices, index, removed, addedCount) {
1498
+
1499
+ var splice = newSplice(index, removed, addedCount);
1500
+
1501
+ var inserted = false;
1502
+ var insertionOffset = 0;
1503
+
1504
+ for (var i = 0; i < splices.length; i++) {
1505
+ var current = splices[i];
1506
+ current.index += insertionOffset;
1507
+
1508
+ if (inserted)
1509
+ continue;
1510
+
1511
+ var intersectCount = intersect(splice.index,
1512
+ splice.index + splice.removed.length,
1513
+ current.index,
1514
+ current.index + current.addedCount);
1515
+
1516
+ if (intersectCount >= 0) {
1517
+ // Merge the two splices
1518
+
1519
+ splices.splice(i, 1);
1520
+ i--;
1521
+
1522
+ insertionOffset -= current.addedCount - current.removed.length;
1523
+
1524
+ splice.addedCount += current.addedCount - intersectCount;
1525
+ var deleteCount = splice.removed.length +
1526
+ current.removed.length - intersectCount;
1527
+
1528
+ if (!splice.addedCount && !deleteCount) {
1529
+ // merged splice is a noop. discard.
1530
+ inserted = true;
1531
+ } else {
1532
+ var removed = current.removed;
1533
+
1534
+ if (splice.index < current.index) {
1535
+ // some prefix of splice.removed is prepended to current.removed.
1536
+ var prepend = splice.removed.slice(0, current.index - splice.index);
1537
+ Array.prototype.push.apply(prepend, removed);
1538
+ removed = prepend;
1539
+ }
1540
+
1541
+ if (splice.index + splice.removed.length > current.index + current.addedCount) {
1542
+ // some suffix of splice.removed is appended to current.removed.
1543
+ var append = splice.removed.slice(current.index + current.addedCount - splice.index);
1544
+ Array.prototype.push.apply(removed, append);
1545
+ }
1546
+
1547
+ splice.removed = removed;
1548
+ if (current.index < splice.index) {
1549
+ splice.index = current.index;
1550
+ }
1551
+ }
1552
+ } else if (splice.index < current.index) {
1553
+ // Insert splice here.
1554
+
1555
+ inserted = true;
1556
+
1557
+ splices.splice(i, 0, splice);
1558
+ i++;
1559
+
1560
+ var offset = splice.addedCount - splice.removed.length
1561
+ current.index += offset;
1562
+ insertionOffset += offset;
1563
+ }
1564
+ }
1565
+
1566
+ if (!inserted)
1567
+ splices.push(splice);
1568
+ }
1569
+
1570
+ function createInitialSplices(array, changeRecords) {
1571
+ var splices = [];
1572
+
1573
+ for (var i = 0; i < changeRecords.length; i++) {
1574
+ var record = changeRecords[i];
1575
+ switch(record.type) {
1576
+ case 'splice':
1577
+ mergeSplice(splices, record.index, record.removed.slice(), record.addedCount);
1578
+ break;
1579
+ case 'add':
1580
+ case 'update':
1581
+ case 'delete':
1582
+ if (!isIndex(record.name))
1583
+ continue;
1584
+ var index = toNumber(record.name);
1585
+ if (index < 0)
1586
+ continue;
1587
+ mergeSplice(splices, index, [record.oldValue], 1);
1588
+ break;
1589
+ default:
1590
+ console.error('Unexpected record type: ' + JSON.stringify(record));
1591
+ break;
1592
+ }
1593
+ }
1594
+
1595
+ return splices;
1596
+ }
1597
+
1598
+ function projectArraySplices(array, changeRecords) {
1599
+ var splices = [];
1600
+
1601
+ createInitialSplices(array, changeRecords).forEach(function(splice) {
1602
+ if (splice.addedCount == 1 && splice.removed.length == 1) {
1603
+ if (splice.removed[0] !== array[splice.index])
1604
+ splices.push(splice);
1605
+
1606
+ return
1607
+ };
1608
+
1609
+ splices = splices.concat(calcSplices(array, splice.index, splice.index + splice.addedCount,
1610
+ splice.removed, 0, splice.removed.length));
1611
+ });
1612
+
1613
+ return splices;
1614
+ }
1615
+
1616
+ global.Observer = Observer;
1617
+ global.Observer.runEOM_ = runEOM;
1618
+ global.Observer.observerSentinel_ = observerSentinel; // for testing.
1619
+ global.Observer.hasObjectObserve = hasObserve;
1620
+ global.ArrayObserver = ArrayObserver;
1621
+ global.ArrayObserver.calculateSplices = function(current, previous) {
1622
+ return arraySplice.calculateSplices(current, previous);
1623
+ };
1624
+
1625
+ global.ArraySplice = ArraySplice;
1626
+ global.ObjectObserver = ObjectObserver;
1627
+ global.PathObserver = PathObserver;
1628
+ global.CompoundObserver = CompoundObserver;
1629
+ global.Path = Path;
1630
+ global.ObserverTransform = ObserverTransform;
1631
+ })(typeof global !== 'undefined' && global && typeof module !== 'undefined' && module ? exports || global : exports || this || window);