1 2function ParseChangePath(path) { 3 var strs = path.split(/\.|\[|\]/); 4 5 var assign_str = ""; 6 var elems = []; 7 for(var i = 0; i < strs.length; i++) { 8 if(strs[i] != "") { 9 assign_str += "[\"" + strs[i] + "\"]"; 10 elems.push(strs[i]); 11 } 12 } 13 14 return { "assign": assign_str, "elems": elems, "path": path }; 15} 16 17function ParseChangeNotification(str) { 18 var first_space = str.indexOf(' '); 19 if(first_space == -1) { 20 return null; 21 } 22 23 var operation = str.substr(0, first_space); 24 if(operation == "kClear" || operation == "kCompress") { 25 var temp_path = ParseChangePath(str.substr(first_space + 1)); 26 return { "op": operation, "path": temp_path }; 27 } 28 29 first_space++; 30 var next_space = str.indexOf(' ', first_space); 31 if(next_space == -1) { 32 return null; 33 } 34 35 var path = ParseChangePath(str.substr(first_space, next_space - first_space)); 36 37 next_space++; 38 39 if(operation == "kSet") { 40 var data = str.substr(next_space); 41 return { "op": operation, "path": path, "data": data }; 42 } 43 44 if(operation == "kRemove") { 45 var index = str.substr(next_space); 46 return { "op": operation, "path": path, "index": index }; 47 } 48 49 if(operation == "kInsert") { 50 var final_space = str.indexOf(' ', next_space); 51 var insert_index = str.substr(next_space, final_space - next_space); 52 var insert_data = str.substr(final_space + 1); 53 return { "op": operation, "path": path, "index": insert_index, "data": insert_data }; 54 } 55 56 return null; 57} 58 59function GetValueAtPath(path, obj) { 60 return eval("obj" + path["assign"]); 61} 62 63function ApplyChangeNotification(change, obj) { 64 if(change == null) { 65 return obj; 66 } 67 68 if(change["op"] == "kSet") { 69 var set_eval_data = "obj" + change["path"]["assign"] + " = " + change["data"]; 70 eval(set_eval_data); 71 } 72 73 if(change["op"] == "kClear") { 74 var clear_eval_data = "obj" + change["path"]["assign"] + " = {}"; 75 eval(clear_eval_data); 76 } 77 78 if(change["op"] == "kInsert") { 79 var insert_eval_data = "obj" + change["path"]["assign"] + "[\"" + change["index"] + "\"] = " + change["data"]; 80 eval(insert_eval_data); 81 } 82 83 if(change["op"] == "kRemove") { 84 var remove_eval_data = "delete obj" + change["path"]["assign"] + "[\"" + change["index"] + "\"]"; 85 eval(remove_eval_data); 86 } 87 88 return obj; 89} 90 91function CreateChangeCallback(callback_list, obj, change_path, onset_cb) { 92 var path = ParseChangePath(change_path); 93 callback_list.push({ 94 "path": path, 95 "defunct": false, 96 "onset": onset_cb 97 }); 98 99 if(PathExistsInObject(path, obj)) { 100 onset_cb(GetValueAtPath(path, obj)); 101 } 102} 103 104function CreateListChangeCallback(callback_list, obj, change_path, oninsert_cb, onmodify_cb, onremove_cb, onclear_cb) { 105 var path = ParseChangePath(change_path); 106 callback_list.push({ 107 "path": path, 108 "defunct": false, 109 "oninsert": oninsert_cb, 110 "onmodify": onmodify_cb, 111 "onremove": onremove_cb, 112 "onclear": onclear_cb 113 }); 114 115 onclear_cb(); 116 if(PathExistsInObject(path, obj)) { 117 var val = GetValueAtPath(path, obj); 118 if(IsList(val)) { 119 for(var e in val) { 120 oninsert_cb(e, val[e], true); 121 } 122 } 123 } 124} 125 126function RemoveChangeCallback(callback_list, change_path) { 127 var num_elems = callback_list.length; 128 for(var i = 0; i < num_elems; i++) { 129 if(callback_list[i].path["path"] == change_path && callback_list[i].defunct == false) { 130 callback_list[i].defunct = true; 131 return; 132 } 133 } 134} 135 136function CleanupCallbackList(callback_list) { 137 var num_elems = callback_list.length; 138 for(var i = num_elems - 1; i >= 0; i--) { 139 if(callback_list[i].defunct) { 140 callback_list.splice(i, 1); 141 } 142 } 143} 144 145function PathExistsInObject(path, obj) 146{ 147 var obj_ptr = obj; 148 var num_elems = path["elems"].length; 149 for(var i = 0; i < num_elems; i++) { 150 if(path["elems"][i] in obj_ptr) { 151 obj_ptr = obj_ptr[path["elems"][i]]; 152 } 153 else { 154 return false; 155 } 156 } 157 158 return true; 159} 160 161function IsList(v) { 162 if(typeof v !== 'object') { 163 return false; 164 } 165 166 if(v === null) { 167 return false;
168 } 169 170 if(v instanceof Array) { 171 return false; 172 } 173 174 if(v instanceof Date) { 175 return false; 176 } 177 178 return true; 179} 180 181 182function CallChangeCallbacks(change, callback_list, obj) { 183 184 if(change["op"] == "kSet") { 185 HandleSetChange(change, callback_list, obj); 186 } 187 188 if(change["op"] == "kClear") { 189 HandleClearChange(change, callback_list, obj); 190 } 191 192 if(change["op"] == "kInsert") { 193 HandleInsertChange(change, callback_list, obj); 194 } 195 196 if(change["op"] == "kRemove") { 197 HandleRemoveChange(change, callback_list, obj); 198 } 199 200 CleanupCallbackList(callback_list); 201} 202 203function HandleSetChange(change, callback_list, obj) { 204 var change_path = change["path"]; 205 var num_callbacks = callback_list.length; 206 for(var i = 0; i < num_callbacks; i++) { 207 var callback = callback_list[i]; 208 var callback_path = callback["path"]; 209 210 if(callback["defunct"]) { 211 continue; 212 } 213 214 if(change_path["path"].length <= callback_path["path"].length) { 215 if(callback_path["path"].substr(0, change_path["path"].length) == change_path["path"]) { 216 // Root level change 217 if(PathExistsInObject(callback_path, obj)) { 218 var val = GetValueAtPath(callback_path, obj); 219 220 if("onset" in callback) { 221 callback.onset(val); 222 } 223 224 if("onclear" in callback) { 225 callback.onclear(); 226 } 227 228 if("oninsert" in callback && IsList(val)) { 229 for(var e in val) { 230 callback.oninsert(e, val[e]); 231 } 232 } 233 } 234 else { 235 if("ondelete" in callback) { 236 callback.ondelete(); 237 } 238 } 239 } 240 } 241 else { 242 if(change_path["path"].substr(0, callback_path["path"].length) == callback_path["path"]) { 243 // Child level change 244 var parent_val = GetValueAtPath(callback_path, obj); 245 246 if("onset" in callback) { 247 callback.onset(parent_val); 248 } 249 250 if("onmodify" in callback) { 251 var sub_index = change_path["elems"][callback_path["elems"].length]; 252 callback.onmodify(sub_index, parent_val[sub_index]); 253 } 254 } 255 } 256 } 257} 258 259function HandleClearChange(change, callback_list, obj) { 260 var change_path = change["path"]; 261 var num_callbacks = callback_list.length; 262 for(var i = 0; i < num_callbacks; i++) { 263 var callback = callback_list[i]; 264 var callback_path = callback["path"]; 265 266 if(callback["defunct"]) { 267 continue; 268 } 269 270 if(change_path["path"].length < callback_path["path"].length) { 271 if(callback_path["path"].substr(0, change_path["path"].length) == change_path["path"]) { 272 // Root level change 273 if("ondelete" in callback) { 274 callback.ondelete(); 275 } 276 277 if("onclear" in callback) { 278 callback.onclear(); 279 } 280 } 281 } 282 else if(change_path["path"] == callback_path["path"]) { 283 if("onclear" in callback) { 284 callback.onclear(); 285 } 286 } 287 else if(change_path["path"].substr(0, callback_path["path"].length) == callback_path["path"]) { 288 // Child level change 289 if("onmodify" in callback) { 290 var parent_val = GetValueAtPath(callback_path, obj); 291 var sub_index = change_path["elems"][callback_path["elems"].length]; 292 callback.onmodify(sub_index, parent_val[sub_index]); 293 } 294 } 295 } 296} 297 298function HandleInsertChange(change, callback_list, obj) { 299 var change_path = change["path"]; 300 var elem_path = change_path["path"] + '[' + change["index"] + ']'; 301 var num_callbacks = callback_list.length; 302 for(var i = 0; i < num_callbacks; i++) { 303 var callback = callback_list[i]; 304 var callback_path = callback["path"]; 305 306 if(callback["defunct"]) { 307 continue; 308 } 309 310 if(elem_path.length < callback_path["path"].length) { 311 if(callback_path["path"].substr(0, elem_path.length) == elem_path) { 312 // Root level change 313 if(PathExistsInObject(callback_path, obj)) { 314 var val = GetValueAtPath(callback_path, obj); 315 316 if("onset" in callback) { 317 callback.onset(val); 318 } 319 320 if("onclear" in callback) { 321 callback.onclear(); 322 } 323 324 if("oninsert" in callback && IsList(val)) { 325 for(var e in val) { 326 callback.oninsert(e, val[e]); 327 } 328 } 329 } 330 } 331 }
332 else if(change_path["path"] == callback_path["path"]) { 333 if("oninsert" in callback) { 334 var matching_val = GetValueAtPath(callback_path, obj); 335 callback.oninsert(change["index"], matching_val[change["index"]]); 336 } 337 } 338 else if(change_path["path"].substr(0, callback_path["path"].length) == callback_path["path"]) { 339 if("onmodify" in callback) { 340 var parent_val = GetValueAtPath(callback_path, obj); 341 var sub_index = change_path["elems"][callback_path["elems"].length]; 342 callback.onmodify(sub_index, parent_val[sub_index]); 343 } 344 } 345 } 346} 347 348function HandleRemoveChange(change, callback_list, obj) { 349 var change_path = change["path"]; 350 var elem_path = change_path["path"] + '[' + change["index"] + ']'; 351 352 var num_callbacks = callback_list.length; 353 for(var i = 0; i < num_callbacks; i++) { 354 var callback = callback_list[i]; 355 var callback_path = callback["path"]; 356 357 if(callback["defunct"]) { 358 continue; 359 } 360 361 if(elem_path.length < callback_path["path"].length) { 362 if(callback_path["path"].substr(0, elem_path.length) == elem_path) { 363 // Root level change 364 if("ondelete" in callback) { 365 callback.ondelete(); 366 } 367 368 if("onclear" in callback) { 369 callback.onclear(); 370 } 371 } 372 } 373 else if(change_path["path"] == callback_path["path"]) { 374 if("onremove" in callback) { 375 callback.onremove(change["index"]); 376 } 377 } 378 else if(change_path["path"].substr(0, callback_path["path"].length) == callback_path["path"]) { 379 if("onmodify" in callback) { 380 var parent_val = GetValueAtPath(callback_path, obj); 381 var sub_index = change_path["elems"][callback_path["elems"].length]; 382 callback.onmodify(sub_index, parent_val[sub_index]); 383 } 384 } 385 } 386} 387 388function ClearChangeCallbacks(callback_list) { 389 390 var num_callbacks = callback_list.length; 391 for(var i = 0; i < num_callbacks; i++) { 392 var callback = callback_list[i]; 393 394 if("ondelete" in callback) { 395 callback.ondelete(); 396 } 397 398 if("onclear" in callback) { 399 callback.onclear(); 400 } 401 } 402} 403 404// cases 405/// thing comes into existence <- same as set, for lists nothing happens 406/// thing gets modified <- call onset, for lists nothing happens? 407/// thing gets destroyed <- not handled explicity, must be dealt with up stream? 408/// child gets added <- call oninsert 409/// child gets removed <- call onremove 410/// child gets modified <- call onmodify 411 412
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.