Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
seleniumhq
GitHub Repository: seleniumhq/selenium
Path: blob/trunk/third_party/closure/goog/datasource/datasource.js
2868 views
1
// Copyright 2006 The Closure Library Authors. All Rights Reserved.
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
/**
16
* @fileoverview Generic rich data access API.
17
*
18
* Abstraction for data sources that allows listening for changes at different
19
* levels of the data tree and updating the data via XHR requests
20
*
21
*/
22
23
24
goog.provide('goog.ds.BaseDataNode');
25
goog.provide('goog.ds.BasicNodeList');
26
goog.provide('goog.ds.DataNode');
27
goog.provide('goog.ds.DataNodeList');
28
goog.provide('goog.ds.EmptyNodeList');
29
goog.provide('goog.ds.LoadState');
30
goog.provide('goog.ds.SortedNodeList');
31
goog.provide('goog.ds.Util');
32
goog.provide('goog.ds.logger');
33
34
goog.require('goog.array');
35
goog.require('goog.log');
36
37
38
39
/**
40
* Interface for node in rich data tree.
41
*
42
* Names that are reserved for system use and shouldn't be used for data node
43
* names: eval, toSource, toString, unwatch, valueOf, watch. Behavior is
44
* undefined if these names are used.
45
*
46
* @constructor
47
*/
48
goog.ds.DataNode = function() {};
49
50
51
/**
52
* Get the value of the node
53
* @param {...?} var_args Do not check arity of arguments, because
54
* some subclasses require args.
55
* @return {*} The value of the node, or null if no value.
56
*/
57
goog.ds.DataNode.prototype.get = goog.abstractMethod;
58
59
60
/**
61
* Set the value of the node
62
* @param {*} value The new value of the node.
63
*/
64
goog.ds.DataNode.prototype.set = goog.abstractMethod;
65
66
67
/**
68
* Gets all of the child nodes of the current node.
69
* Should return an empty DataNode list if no child nodes.
70
* @param {string=} opt_selector String selector to choose child nodes.
71
* @return {!goog.ds.DataNodeList} The child nodes.
72
*/
73
goog.ds.DataNode.prototype.getChildNodes = goog.abstractMethod;
74
75
76
/**
77
* Gets a named child node of the current node
78
* @param {string} name The node name.
79
* @param {boolean=} opt_canCreate Whether to create a child node if it does not
80
* exist.
81
* @return {goog.ds.DataNode} The child node, or null
82
* if no node of this name exists.
83
*/
84
goog.ds.DataNode.prototype.getChildNode = goog.abstractMethod;
85
86
87
/**
88
* Gets the value of a child node
89
* @param {string} name The node name.
90
* @return {*} The value of the node, or null if no value or the child node
91
* doesn't exist.
92
*/
93
goog.ds.DataNode.prototype.getChildNodeValue = goog.abstractMethod;
94
95
96
/**
97
* Sets a named child node of the current node.
98
*
99
* @param {string} name The node name.
100
* @param {Object} value The value to set, can be DataNode, object, property,
101
* or null. If value is null, removes the child node.
102
* @return {Object} The child node, if the node was set.
103
*/
104
goog.ds.DataNode.prototype.setChildNode = goog.abstractMethod;
105
106
107
/**
108
* Get the name of the node relative to the parent node
109
* @return {string} The name of the node.
110
*/
111
goog.ds.DataNode.prototype.getDataName = goog.abstractMethod;
112
113
114
/**
115
* Set the name of the node relative to the parent node
116
* @param {string} name The name of the node.
117
*/
118
goog.ds.DataNode.prototype.setDataName = goog.abstractMethod;
119
120
121
/**
122
* Gets the a qualified data path to this node
123
* @return {string} The data path.
124
*/
125
goog.ds.DataNode.prototype.getDataPath = goog.abstractMethod;
126
127
128
/**
129
* Load or reload the backing data for this node
130
*/
131
goog.ds.DataNode.prototype.load = goog.abstractMethod;
132
133
134
/**
135
* Gets the state of the backing data for this node
136
* @return {goog.ds.LoadState} The state.
137
*/
138
goog.ds.DataNode.prototype.getLoadState = goog.abstractMethod;
139
140
141
/**
142
* Whether the value of this node is a homogeneous list of data
143
* @return {boolean} True if a list.
144
*/
145
goog.ds.DataNode.prototype.isList = goog.abstractMethod;
146
147
148
/**
149
* Enum for load state of a DataNode.
150
* @enum {string}
151
*/
152
goog.ds.LoadState = {
153
LOADED: 'LOADED',
154
LOADING: 'LOADING',
155
FAILED: 'FAILED',
156
NOT_LOADED: 'NOT_LOADED'
157
};
158
159
160
161
/**
162
* Base class for data node functionality, has default implementations for
163
* many of the functions.
164
*
165
* implements {goog.ds.DataNode}
166
* @constructor
167
*/
168
goog.ds.BaseDataNode = function() {};
169
170
171
/**
172
* Set the value of the node
173
* @param {Object} value The new value of the node.
174
*/
175
goog.ds.BaseDataNode.prototype.set = goog.abstractMethod;
176
177
178
/**
179
* Gets all of the child nodes of the current node.
180
* Should return an empty DataNode list if no child nodes.
181
* @param {string=} opt_selector String selector to choose child nodes.
182
* @return {!goog.ds.DataNodeList} The child nodes.
183
*/
184
goog.ds.BaseDataNode.prototype.getChildNodes = function(opt_selector) {
185
return new goog.ds.EmptyNodeList();
186
};
187
188
189
/**
190
* Gets a named child node of the current node
191
* @param {string} name The node name.
192
* @param {boolean=} opt_canCreate Whether you can create the child node if
193
* it doesn't exist already.
194
* @return {goog.ds.DataNode} The child node, or null if no node of
195
* this name exists and opt_create is false.
196
*/
197
goog.ds.BaseDataNode.prototype.getChildNode = function(name, opt_canCreate) {
198
return null;
199
};
200
201
202
/**
203
* Gets the value of a child node
204
* @param {string} name The node name.
205
* @return {Object} The value of the node, or null if no value or the
206
* child node doesn't exist.
207
*/
208
goog.ds.BaseDataNode.prototype.getChildNodeValue = function(name) {
209
return null;
210
};
211
212
213
/**
214
* Get the name of the node relative to the parent node
215
* @return {string} The name of the node.
216
*/
217
goog.ds.BaseDataNode.prototype.getDataName = goog.abstractMethod;
218
219
220
/**
221
* Gets the a qualified data path to this node
222
* @return {string} The data path.
223
*/
224
goog.ds.BaseDataNode.prototype.getDataPath = function() {
225
var parentPath = '';
226
var myName = this.getDataName();
227
if (this.getParent()) {
228
parentPath = this.getParent().getDataPath() +
229
(myName.indexOf(
230
/** @suppress {missingRequire} */ goog.ds.STR_ARRAY_START) != -1 ?
231
'' :
232
/** @suppress {missingRequire} */ goog.ds.STR_PATH_SEPARATOR);
233
}
234
235
return parentPath + myName;
236
};
237
238
239
/**
240
* Load or reload the backing data for this node
241
*/
242
goog.ds.BaseDataNode.prototype.load = goog.nullFunction;
243
244
245
/**
246
* Gets the state of the backing data for this node
247
* @return {goog.ds.LoadState} The state.
248
*/
249
goog.ds.BaseDataNode.prototype.getLoadState = function() {
250
return goog.ds.LoadState.LOADED;
251
};
252
253
254
/**
255
* Gets the parent node. Subclasses implement this function
256
* @return {?goog.ds.DataNode}
257
* @protected
258
*/
259
goog.ds.BaseDataNode.prototype.getParent = goog.abstractMethod;
260
261
262
/**
263
* Interface for node list in rich data tree.
264
*
265
* Has both map and list-style accessors
266
*
267
* @constructor
268
* @extends {goog.ds.DataNode}
269
*/
270
// TODO(arv): Use interfaces when available.
271
goog.ds.DataNodeList = function() {};
272
273
274
/**
275
* Add a node to the node list.
276
* If the node has a dataName, uses this for the key in the map.
277
*
278
* @param {goog.ds.DataNode} node The node to add.
279
*/
280
goog.ds.DataNodeList.prototype.add = goog.abstractMethod;
281
282
283
/**
284
* Get a node by string key.
285
* Returns null if node doesn't exist.
286
*
287
* @param {string} key String lookup key.
288
* @return {*} The node, or null if doesn't exist.
289
* @override
290
*/
291
goog.ds.DataNodeList.prototype.get = goog.abstractMethod;
292
293
294
/**
295
* Get a node by index
296
* Returns null if the index is out of range
297
*
298
* @param {number} index The index of the node.
299
* @return {goog.ds.DataNode} The node, or null if doesn't exist.
300
*/
301
goog.ds.DataNodeList.prototype.getByIndex = goog.abstractMethod;
302
303
304
/**
305
* Gets the size of the node list
306
*
307
* @return {number} The size of the list.
308
*/
309
goog.ds.DataNodeList.prototype.getCount = goog.abstractMethod;
310
311
312
/**
313
* Sets a node in the list of a given name
314
* @param {string} name Name of the node.
315
* @param {goog.ds.DataNode} node The node.
316
*/
317
goog.ds.DataNodeList.prototype.setNode = goog.abstractMethod;
318
319
320
/**
321
* Removes a node in the list of a given name
322
* @param {string} name Name of the node.
323
* @return {boolean} True if node existed and was deleted.
324
*/
325
goog.ds.DataNodeList.prototype.removeNode = goog.abstractMethod;
326
327
328
/**
329
* Simple node list implementation with underlying array and map
330
* implements goog.ds.DataNodeList.
331
*
332
* Names that are reserved for system use and shouldn't be used for data node
333
* names: eval, toSource, toString, unwatch, valueOf, watch. Behavior is
334
* undefined if these names are used.
335
*
336
* @param {Array<goog.ds.DataNode>=} opt_nodes optional nodes to add to list.
337
* @constructor
338
* @extends {goog.ds.DataNodeList}
339
*/
340
// TODO(arv): Use interfaces when available.
341
goog.ds.BasicNodeList = function(opt_nodes) {
342
this.map_ = {};
343
this.list_ = [];
344
this.indexMap_ = {};
345
if (opt_nodes) {
346
for (var i = 0, node; node = opt_nodes[i]; i++) {
347
this.add(node);
348
}
349
}
350
};
351
352
353
/**
354
* Add a node to the node list.
355
* If the node has a dataName, uses this for the key in the map.
356
* TODO(user) Remove function as well
357
*
358
* @param {goog.ds.DataNode} node The node to add.
359
* @override
360
*/
361
goog.ds.BasicNodeList.prototype.add = function(node) {
362
this.list_.push(node);
363
var dataName = node.getDataName();
364
if (dataName) {
365
this.map_[dataName] = node;
366
this.indexMap_[dataName] = this.list_.length - 1;
367
}
368
};
369
370
371
/**
372
* Get a node by string key.
373
* Returns null if node doesn't exist.
374
*
375
* @param {string} key String lookup key.
376
* @return {goog.ds.DataNode} The node, or null if doesn't exist.
377
* @override
378
*/
379
goog.ds.BasicNodeList.prototype.get = function(key) {
380
return this.map_[key] || null;
381
};
382
383
384
/**
385
* Get a node by index
386
* Returns null if the index is out of range
387
*
388
* @param {number} index The index of the node.
389
* @return {goog.ds.DataNode} The node, or null if doesn't exist.
390
* @override
391
*/
392
goog.ds.BasicNodeList.prototype.getByIndex = function(index) {
393
return this.list_[index] || null;
394
};
395
396
397
/**
398
* Gets the size of the node list
399
*
400
* @return {number} The size of the list.
401
* @override
402
*/
403
goog.ds.BasicNodeList.prototype.getCount = function() {
404
return this.list_.length;
405
};
406
407
408
/**
409
* Sets a node in the list of a given name
410
* @param {string} name Name of the node.
411
* @param {goog.ds.DataNode} node The node.
412
* @override
413
*/
414
goog.ds.BasicNodeList.prototype.setNode = function(name, node) {
415
if (node == null) {
416
this.removeNode(name);
417
} else {
418
var existingNode = this.indexMap_[name];
419
if (existingNode != null) {
420
this.map_[name] = node;
421
this.list_[existingNode] = node;
422
} else {
423
this.add(node);
424
}
425
}
426
};
427
428
429
/**
430
* Removes a node in the list of a given name
431
* @param {string} name Name of the node.
432
* @return {boolean} True if node existed and was deleted.
433
* @override
434
*/
435
goog.ds.BasicNodeList.prototype.removeNode = function(name) {
436
var existingNode = this.indexMap_[name];
437
if (existingNode != null) {
438
this.list_.splice(existingNode, 1);
439
delete this.map_[name];
440
delete this.indexMap_[name];
441
for (var index in this.indexMap_) {
442
if (this.indexMap_[index] > existingNode) {
443
this.indexMap_[index]--;
444
}
445
}
446
}
447
return existingNode != null;
448
};
449
450
451
/**
452
* Get the index of a named node
453
* @param {string} name The name of the node to get the index of.
454
* @return {number|undefined} The index.
455
*/
456
goog.ds.BasicNodeList.prototype.indexOf = function(name) {
457
return this.indexMap_[name];
458
};
459
460
461
/**
462
* Immulatable empty node list
463
* @extends {goog.ds.BasicNodeList}
464
* @constructor
465
* @final
466
*/
467
468
goog.ds.EmptyNodeList = function() {
469
goog.ds.BasicNodeList.call(this);
470
};
471
goog.inherits(goog.ds.EmptyNodeList, goog.ds.BasicNodeList);
472
473
474
/**
475
* Add a node to the node list.
476
* If the node has a dataName, uses this for the key in the map.
477
*
478
* @param {goog.ds.DataNode} node The node to add.
479
* @override
480
*/
481
goog.ds.EmptyNodeList.prototype.add = function(node) {
482
throw Error('Can\'t add to EmptyNodeList');
483
};
484
485
486
487
/**
488
* Node list implementation which maintains sort order during insertion and
489
* modification operations based on a comparison function.
490
*
491
* The SortedNodeList does not guarantee sort order will be maintained if
492
* the underlying data nodes are modified externally.
493
*
494
* Names that are reserved for system use and shouldn't be used for data node
495
* names: eval, toSource, toString, unwatch, valueOf, watch. Behavior is
496
* undefined if these names are used.
497
*
498
* @param {Function} compareFn Comparison function by which the
499
* node list is sorted. Should take 2 arguments to compare, and return a
500
* negative integer, zero, or a positive integer depending on whether the
501
* first argument is less than, equal to, or greater than the second.
502
* @param {Array<goog.ds.DataNode>=} opt_nodes optional nodes to add to list;
503
* these are assumed to be in sorted order.
504
* @extends {goog.ds.BasicNodeList}
505
* @constructor
506
*/
507
goog.ds.SortedNodeList = function(compareFn, opt_nodes) {
508
this.compareFn_ = compareFn;
509
goog.ds.BasicNodeList.call(this, opt_nodes);
510
};
511
goog.inherits(goog.ds.SortedNodeList, goog.ds.BasicNodeList);
512
513
514
/**
515
* Add a node to the node list, maintaining sort order.
516
* If the node has a dataName, uses this for the key in the map.
517
*
518
* @param {goog.ds.DataNode} node The node to add.
519
* @override
520
*/
521
goog.ds.SortedNodeList.prototype.add = function(node) {
522
if (!this.compareFn_) {
523
this.append(node);
524
return;
525
}
526
527
var searchLoc = goog.array.binarySearch(this.list_, node, this.compareFn_);
528
529
// if there is another node that is "equal" according to the comparison
530
// function, insert before that one; otherwise insert at the location
531
// goog.array.binarySearch indicated
532
if (searchLoc < 0) {
533
searchLoc = -(searchLoc + 1);
534
}
535
536
// update any indexes that are after the insertion point
537
for (var index in this.indexMap_) {
538
if (this.indexMap_[index] >= searchLoc) {
539
this.indexMap_[index]++;
540
}
541
}
542
543
goog.array.insertAt(this.list_, node, searchLoc);
544
var dataName = node.getDataName();
545
if (dataName) {
546
this.map_[dataName] = node;
547
this.indexMap_[dataName] = searchLoc;
548
}
549
};
550
551
552
/**
553
* Adds the given node to the end of the SortedNodeList. This should
554
* only be used when the caller can guarantee that the sort order will
555
* be maintained according to this SortedNodeList's compareFn (e.g.
556
* when initializing a new SortedNodeList from a list of nodes that has
557
* already been sorted).
558
* @param {goog.ds.DataNode} node The node to append.
559
*/
560
goog.ds.SortedNodeList.prototype.append = function(node) {
561
goog.ds.SortedNodeList.superClass_.add.call(this, node);
562
};
563
564
565
/**
566
* Sets a node in the list of a given name, maintaining sort order.
567
* @param {string} name Name of the node.
568
* @param {goog.ds.DataNode} node The node.
569
* @override
570
*/
571
goog.ds.SortedNodeList.prototype.setNode = function(name, node) {
572
if (node == null) {
573
this.removeNode(name);
574
} else {
575
var existingNode = this.indexMap_[name];
576
if (existingNode != null) {
577
if (this.compareFn_) {
578
var compareResult = this.compareFn_(this.list_[existingNode], node);
579
if (compareResult == 0) {
580
// the new node can just replace the old one
581
this.map_[name] = node;
582
this.list_[existingNode] = node;
583
} else {
584
// remove the old node, then add the new one
585
this.removeNode(name);
586
this.add(node);
587
}
588
}
589
} else {
590
this.add(node);
591
}
592
}
593
};
594
595
596
/**
597
* The character denoting an attribute.
598
* @type {string}
599
*/
600
goog.ds.STR_ATTRIBUTE_START = '@';
601
602
603
/**
604
* The character denoting all children.
605
* @type {string}
606
*/
607
goog.ds.STR_ALL_CHILDREN_SELECTOR = '*';
608
609
610
/**
611
* The wildcard character.
612
* @type {string}
613
*/
614
goog.ds.STR_WILDCARD = '*';
615
616
617
/**
618
* The character denoting path separation.
619
* @type {string}
620
*/
621
goog.ds.STR_PATH_SEPARATOR = '/';
622
623
624
/**
625
* The character denoting the start of an array.
626
* @type {string}
627
*/
628
goog.ds.STR_ARRAY_START = '[';
629
630
631
/**
632
* Shared logger instance for data package
633
* @type {goog.log.Logger}
634
*/
635
goog.ds.logger = goog.log.getLogger('goog.ds');
636
637
638
/**
639
* Create a data node that references another data node,
640
* useful for pointer-like functionality.
641
* All functions will return same values as the original node except for
642
* getDataName()
643
* @param {!goog.ds.DataNode} node The original node.
644
* @param {string} name The new name.
645
* @return {!goog.ds.DataNode} The new data node.
646
*/
647
goog.ds.Util.makeReferenceNode = function(node, name) {
648
/**
649
* @constructor
650
* @extends {goog.ds.DataNode}
651
* @final
652
*/
653
var nodeCreator = function() {};
654
nodeCreator.prototype = node;
655
var newNode = new nodeCreator();
656
newNode.getDataName = function() { return name; };
657
return newNode;
658
};
659
660