120 lines
2.7 KiB
JavaScript
120 lines
2.7 KiB
JavaScript
|
|
'use strict';
|
||
|
|
|
||
|
|
/**
|
||
|
|
* An empty collection stub. Use {@link RefsCollection.extend} to extend a
|
||
|
|
* collection with ref semantics.
|
||
|
|
*
|
||
|
|
* @class RefsCollection
|
||
|
|
*/
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Extends a collection with {@link Refs} aware methods
|
||
|
|
*
|
||
|
|
* @memberof RefsCollection
|
||
|
|
* @static
|
||
|
|
*
|
||
|
|
* @param {Array<Object>} collection
|
||
|
|
* @param {Refs} refs instance
|
||
|
|
* @param {Object} property represented by the collection
|
||
|
|
* @param {Object} target object the collection is attached to
|
||
|
|
*
|
||
|
|
* @return {RefsCollection<Object>} the extended array
|
||
|
|
*/
|
||
|
|
function extend(collection, refs, property, target) {
|
||
|
|
|
||
|
|
var inverseProperty = property.inverse;
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Removes the given element from the array and returns it.
|
||
|
|
*
|
||
|
|
* @method RefsCollection#remove
|
||
|
|
*
|
||
|
|
* @param {Object} element the element to remove
|
||
|
|
*/
|
||
|
|
Object.defineProperty(collection, 'remove', {
|
||
|
|
value: function(element) {
|
||
|
|
var idx = this.indexOf(element);
|
||
|
|
if (idx !== -1) {
|
||
|
|
this.splice(idx, 1);
|
||
|
|
|
||
|
|
// unset inverse
|
||
|
|
refs.unset(element, inverseProperty, target);
|
||
|
|
}
|
||
|
|
|
||
|
|
return element;
|
||
|
|
}
|
||
|
|
});
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Returns true if the collection contains the given element
|
||
|
|
*
|
||
|
|
* @method RefsCollection#contains
|
||
|
|
*
|
||
|
|
* @param {Object} element the element to check for
|
||
|
|
*/
|
||
|
|
Object.defineProperty(collection, 'contains', {
|
||
|
|
value: function(element) {
|
||
|
|
return this.indexOf(element) !== -1;
|
||
|
|
}
|
||
|
|
});
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Adds an element to the array, unless it exists already (set semantics).
|
||
|
|
*
|
||
|
|
* @method RefsCollection#add
|
||
|
|
*
|
||
|
|
* @param {Object} element the element to add
|
||
|
|
* @param {Number} optional index to add element to
|
||
|
|
* (possibly moving other elements around)
|
||
|
|
*/
|
||
|
|
Object.defineProperty(collection, 'add', {
|
||
|
|
value: function(element, idx) {
|
||
|
|
|
||
|
|
var currentIdx = this.indexOf(element);
|
||
|
|
|
||
|
|
if (typeof idx === 'undefined') {
|
||
|
|
|
||
|
|
if (currentIdx !== -1) {
|
||
|
|
// element already in collection (!)
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
// add to end of array, as no idx is specified
|
||
|
|
idx = this.length;
|
||
|
|
}
|
||
|
|
|
||
|
|
// handle already in collection
|
||
|
|
if (currentIdx !== -1) {
|
||
|
|
|
||
|
|
// remove element from currentIdx
|
||
|
|
this.splice(currentIdx, 1);
|
||
|
|
}
|
||
|
|
|
||
|
|
// add element at idx
|
||
|
|
this.splice(idx, 0, element);
|
||
|
|
|
||
|
|
if (currentIdx === -1) {
|
||
|
|
// set inverse, unless element was
|
||
|
|
// in collection already
|
||
|
|
refs.set(element, inverseProperty, target);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
});
|
||
|
|
|
||
|
|
// a simple marker, identifying this element
|
||
|
|
// as being a refs collection
|
||
|
|
Object.defineProperty(collection, '__refs_collection', {
|
||
|
|
value: true
|
||
|
|
});
|
||
|
|
|
||
|
|
return collection;
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
function isExtended(collection) {
|
||
|
|
return collection.__refs_collection === true;
|
||
|
|
}
|
||
|
|
|
||
|
|
module.exports.extend = extend;
|
||
|
|
|
||
|
|
module.exports.isExtended = isExtended;
|