1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
|
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
module.metadata = {
"stability": "experimental"
};
exports.Collection = Collection;
/**
* Adds a collection property to the given object. Setting the property to a
* scalar value empties the collection and adds the value. Setting it to an
* array empties the collection and adds all the items in the array.
*
* @param obj
* The property will be defined on this object.
* @param propName
* The name of the property.
* @param array
* If given, this will be used as the collection's backing array.
*/
exports.addCollectionProperty = function addCollProperty(obj, propName, array) {
array = array || [];
let publicIface = new Collection(array);
Object.defineProperty(obj, propName, {
configurable: true,
enumerable: true,
set: function set(itemOrItems) {
array.splice(0, array.length);
publicIface.add(itemOrItems);
},
get: function get() {
return publicIface;
}
});
};
/**
* A collection is ordered, like an array, but its items are unique, like a set.
*
* @param array
* The collection is backed by an array. If this is given, it will be
* used as the backing array. This way the caller can fully control the
* collection. Otherwise a new empty array will be used, and no one but
* the collection will have access to it.
*/
function Collection(array) {
array = array || [];
/**
* Provides iteration over the collection. Items are yielded in the order
* they were added.
*/
this.__iterator__ = function Collection___iterator__() {
let items = array.slice();
for (let i = 0; i < items.length; i++)
yield items[i];
};
/**
* The number of items in the collection.
*/
this.__defineGetter__("length", function Collection_get_length() {
return array.length;
});
/**
* Adds a single item or an array of items to the collection. Any items
* already contained in the collection are ignored.
*
* @param itemOrItems
* An item or array of items.
* @return The collection.
*/
this.add = function Collection_add(itemOrItems) {
let items = toArray(itemOrItems);
for (let i = 0; i < items.length; i++) {
let item = items[i];
if (array.indexOf(item) < 0)
array.push(item);
}
return this;
};
/**
* Removes a single item or an array of items from the collection. Any items
* not contained in the collection are ignored.
*
* @param itemOrItems
* An item or array of items.
* @return The collection.
*/
this.remove = function Collection_remove(itemOrItems) {
let items = toArray(itemOrItems);
for (let i = 0; i < items.length; i++) {
let idx = array.indexOf(items[i]);
if (idx >= 0)
array.splice(idx, 1);
}
return this;
};
};
function toArray(itemOrItems) {
let isArr = itemOrItems &&
itemOrItems.constructor &&
itemOrItems.constructor.name === "Array";
return isArr ? itemOrItems : [itemOrItems];
}
|