1
+ function HandsontableObserveChanges ( ) {
2
+ // begin shim code
3
+ // fragments from https://github.com/Starcounter-Jack/JSON-Patch/blob/master/src/json-patch-duplex.js
4
+ //
5
+ // json-patch.js 0.3
6
+ // (c) 2013 Joachim Wester
7
+ // MIT license
8
+ var observeOps = {
9
+ 'new' : function ( patches , path ) {
10
+ var patch = {
11
+ op : "add" ,
12
+ path : path + "/" + this . name ,
13
+ value : this . object [ this . name ]
14
+ } ;
15
+ patches . push ( patch ) ;
16
+ } ,
17
+ deleted : function ( patches , path ) {
18
+ var patch = {
19
+ op : "remove" ,
20
+ path : path + "/" + this . name
21
+ } ;
22
+ patches . push ( patch ) ;
23
+ } ,
24
+ updated : function ( patches , path ) {
25
+ var patch = {
26
+ op : "replace" ,
27
+ path : path + "/" + this . name ,
28
+ value : this . object [ this . name ]
29
+ } ;
30
+ patches . push ( patch ) ;
31
+ }
32
+ } ;
33
+ // ES6 symbols are not here yet. Used to calculate the json pointer to each object
34
+ function markPaths ( observer , node ) {
35
+ for ( var key in node ) {
36
+ var kid = node [ key ] ;
37
+ if ( kid instanceof Object ) {
38
+ Object . unobserve ( kid , observer ) ;
39
+ kid . ____Path = node . ____Path + "/" + key ;
40
+ markPaths ( observer , kid ) ;
41
+ }
42
+ }
43
+ }
44
+
45
+ // Detach poor mans ES6 symbols
46
+ function clearPaths ( observer , node ) {
47
+ delete node . ____Path ;
48
+ Object . observe ( node , observer ) ;
49
+ for ( var key in node ) {
50
+ var kid = node [ key ] ;
51
+ if ( kid instanceof Object ) {
52
+ clearPaths ( observer , kid ) ;
53
+ }
54
+ }
55
+ }
56
+
57
+ var beforeDict = [ ] ;
58
+ var callbacks = [ ] ;
59
+
60
+ function observe ( obj , callback ) {
61
+ var patches = [ ] ;
62
+ var root = obj ;
63
+ if ( Object . observe ) {
64
+ var observer = function ( arr ) {
65
+ if ( ! root . ___Path ) {
66
+ Object . unobserve ( root , observer ) ;
67
+ root . ____Path = "" ;
68
+ markPaths ( observer , root ) ;
69
+ arr . forEach ( function ( elem ) {
70
+ if ( elem . name != "____Path" ) {
71
+ observeOps [ elem . type ] . call ( elem , patches , elem . object . ____Path ) ;
72
+ }
73
+ } ) ;
74
+ clearPaths ( observer , root ) ;
75
+ }
76
+ if ( callback ) {
77
+ callback . call ( patches ) ;
78
+ }
79
+ } ;
80
+ } else {
81
+ observer = {
82
+ } ;
83
+
84
+ var found ;
85
+ for ( var i = 0 , ilen = beforeDict . length ; i < ilen ; i ++ ) {
86
+ if ( beforeDict [ i ] . obj === obj ) {
87
+ found = beforeDict [ i ] ;
88
+ break ;
89
+ }
90
+ }
91
+
92
+ if ( ! found ) {
93
+ found = { obj : obj } ;
94
+ beforeDict . push ( found ) ;
95
+ }
96
+
97
+ found . value = JSON . parse ( JSON . stringify ( obj ) ) // Faster than ES5 clone
98
+
99
+ if ( callback ) {
100
+ callbacks . push ( callback ) ;
101
+ var next ;
102
+ var intervals = [
103
+ 100
104
+ ] ;
105
+ var currentInterval = 0 ;
106
+ var dirtyCheck = function ( ) {
107
+ var temp = generate ( observer ) ;
108
+ if ( temp . length > 0 ) {
109
+ observer . patches = [ ] ;
110
+ callback . call ( null , temp ) ;
111
+ }
112
+ } ;
113
+ var fastCheck = function ( e ) {
114
+ clearTimeout ( next ) ;
115
+ next = setTimeout ( function ( ) {
116
+ dirtyCheck ( ) ;
117
+ currentInterval = 0 ;
118
+ next = setTimeout ( slowCheck , intervals [ currentInterval ++ ] ) ;
119
+ } , 0 ) ;
120
+ } ;
121
+ var slowCheck = function ( ) {
122
+ dirtyCheck ( ) ;
123
+ if ( currentInterval == intervals . length ) {
124
+ currentInterval = intervals . length - 1 ;
125
+ }
126
+ next = setTimeout ( slowCheck , intervals [ currentInterval ++ ] ) ;
127
+ } ;
128
+ [
129
+ "mousedown" ,
130
+ "mouseup" ,
131
+ "keydown"
132
+ ] . forEach ( function ( str ) {
133
+ window . addEventListener ( str , fastCheck ) ;
134
+ } ) ;
135
+ next = setTimeout ( slowCheck , intervals [ currentInterval ++ ] ) ;
136
+ }
137
+ }
138
+ observer . patches = patches ;
139
+ observer . object = obj ;
140
+ return _observe ( observer , obj , patches ) ;
141
+ }
142
+
143
+ /// Listen to changes on an object tree, accumulate patches
144
+ function _observe ( observer , obj , patches ) {
145
+ if ( Object . observe ) {
146
+ Object . observe ( obj , observer ) ;
147
+ }
148
+ for ( var key in obj ) {
149
+ if ( obj . hasOwnProperty ( key ) ) {
150
+ var v = obj [ key ] ;
151
+ if ( v && typeof ( v ) === "object" ) {
152
+ _observe ( observer , v , patches ) //path+key);
153
+ ;
154
+ }
155
+ }
156
+ }
157
+ return observer ;
158
+ }
159
+
160
+ function generate ( observer ) {
161
+ if ( Object . observe ) {
162
+ Object . deliverChangeRecords ( observer ) ;
163
+ } else {
164
+ var mirror ;
165
+ for ( var i = 0 , ilen = beforeDict . length ; i < ilen ; i ++ ) {
166
+ if ( beforeDict [ i ] . obj === observer . object ) {
167
+ mirror = beforeDict [ i ] ;
168
+ break ;
169
+ }
170
+ }
171
+ _generate ( mirror , observer . object , observer . patches , "" ) ;
172
+ }
173
+ return observer . patches ;
174
+ }
175
+
176
+ function _generate ( mirror , obj , patches , path ) {
177
+ var newKeys = Object . keys ( obj ) ;
178
+ var oldKeys = Object . keys ( mirror ) ;
179
+ var changed = false ;
180
+ var deleted = false ;
181
+ var added = false ;
182
+ for ( var t = 0 ; t < oldKeys . length ; t ++ ) {
183
+ var key = oldKeys [ t ] ;
184
+ var oldVal = mirror [ key ] ;
185
+ if ( obj . hasOwnProperty ( key ) ) {
186
+ var newVal = obj [ key ] ;
187
+ if ( oldVal instanceof Object ) {
188
+ _generate ( oldVal , newVal , patches , path + "/" + key ) ;
189
+ } else {
190
+ if ( oldVal != newVal ) {
191
+ changed = true ;
192
+ patches . push ( {
193
+ op : "replace" ,
194
+ path : path + "/" + key ,
195
+ value : newVal
196
+ } ) ;
197
+ mirror [ key ] = newVal ;
198
+ }
199
+ }
200
+ } else {
201
+ patches . push ( {
202
+ op : "remove" ,
203
+ path : path + "/" + key
204
+ } ) ;
205
+ deleted = true // property has been deleted
206
+ ;
207
+ }
208
+ }
209
+ if ( ! deleted && newKeys . length == oldKeys . length ) {
210
+ return ;
211
+ }
212
+ for ( var t = 0 ; t < newKeys . length ; t ++ ) {
213
+ var key = newKeys [ t ] ;
214
+ if ( ! mirror . hasOwnProperty ( key ) ) {
215
+ patches . push ( {
216
+ op : "add" ,
217
+ path : path + "/" + key ,
218
+ value : obj [ key ]
219
+ } ) ;
220
+ }
221
+ }
222
+ }
223
+ //end shim code
224
+
225
+
226
+ this . afterLoadData = function ( ) {
227
+ if ( ! this . observer && this . getSettings ( ) . observeChanges ) {
228
+ var that = this ;
229
+ this . observer = observe ( this . getData ( ) , function ( ) {
230
+ that . render ( ) ;
231
+ } ) ;
232
+ }
233
+ } ;
234
+ }
235
+ var htObserveChanges = new HandsontableObserveChanges ( ) ;
236
+
237
+ Handsontable . PluginHooks . add ( 'afterLoadData' , htObserveChanges . afterLoadData ) ;
0 commit comments