observable-set
Version:
Configure observable set collections
136 lines (130 loc) • 4.97 kB
JavaScript
;
var aFrom = require('es5-ext/array/from')
, clear = require('es5-ext/array/#/clear')
, eIndexOf = require('es5-ext/array/#/e-index-of')
, isCopy = require('es5-ext/array/#/is-copy')
, remove = require('es5-ext/array/#/remove')
, invoke = require('es5-ext/function/invoke')
, callable = require('es5-ext/object/valid-callable')
, value = require('es5-ext/object/valid-value')
, toArray = require('es5-ext/array/to-array')
, d = require('d')
, memoize = require('memoizee/plain')
, memoizeMethods = require('memoizee/methods-plain')
, getNormalizer = require('memoizee/normalizers/get-1')
, ReadOnly = require('observable-array/create-read-only')(
require('observable-array')
)
, validObservableSet = require('./valid-observable-set')
, isArray = Array.isArray, push = Array.prototype.push
, sort = Array.prototype.sort, splice = Array.prototype.splice
, defineProperties = Object.defineProperties
, invokeDispose = invoke('_dispose');
require('memoizee/ext/ref-counter');
require('memoizee/ext/dispose');
module.exports = memoize(function (prototype) {
validObservableSet(prototype);
return defineProperties(prototype, memoizeMethods({
toArray: d(function (compareFn) {
var result, setData, disposed, listener, delListener, clearListener;
(value(this) && ((compareFn === undefined) || callable(compareFn)));
if (isArray(this.__setData__)) {
setData = this.__setData__;
result = ReadOnly.from(setData);
if (this._makeObservable_) this._makeObservable_();
this.on('_add', listener = function (index, value) {
if (compareFn) {
push.call(result, value);
sort.call(result, compareFn);
result.emit('change', {
type: 'splice',
arguments: [eIndexOf.call(result, value), 0, value],
removed: [],
target: result
});
} else if (result.length === index) {
push.call(result, value);
result.emit('change', { type: 'set', index: index, target: result });
} else {
result.emit('change', {
type: 'splice',
arguments: [index, 0, value],
removed: splice.call(result, index, 0, value),
target: this
});
}
});
this.on('_delete', delListener = function (index, value) {
if (compareFn) index = eIndexOf.call(result, value);
result.emit('change', { type: 'splice', arguments: [index, 1],
removed: splice.call(result, index, 1), target: result });
});
this.on('_clear', clearListener = function (value) {
clear.call(result);
result.emit('change', { type: 'clear', target: result });
});
} else {
result = ReadOnly.from(this);
this.on('change', listener = function (event) {
var index, type = event.type;
if (type === 'add') {
index = push.call(result, event.value);
if (compareFn) {
sort.call(result, compareFn);
result.emit('change', {
type: 'splice',
arguments: [eIndexOf.call(result, event.value), 0, event.value],
removed: [],
target: result
});
} else {
result.emit('change', { type: 'set', index: index - 1, target: result });
}
} else if (type === 'delete') {
index = eIndexOf.call(result, event.value);
result.emit('change', { type: 'splice', arguments: [index, 1],
removed: splice.call(result, index, 1), target: result });
} else if (type === 'clear') {
clear.call(result);
result.emit('change', { type: 'clear', target: result });
} else if (type === 'batch') {
if (event.deleted) remove.apply(result, toArray(event.deleted));
if (event.added) push.apply(result, toArray(event.added));
if (compareFn) sort.call(result, compareFn);
result.emit('change', {});
} else {
clear.call(result);
this.forEach(function (value) { push.call(result, value); });
if (compareFn) sort.call(result, compareFn);
result.emit('change', {});
}
});
}
if (compareFn) sort.call(result, compareFn);
defineProperties(result, {
refresh: d(function () {
var tmp;
if (!compareFn || (this.size <= 1)) return;
tmp = aFrom(result);
sort.call(result, compareFn);
if (!isCopy.call(result, tmp)) result.emit('change', {});
}.bind(this)),
unref: d(function () {
if (disposed) return;
this.toArray.deleteRef(compareFn);
}.bind(this)),
_dispose: d(function () {
if (setData) {
this.off('_add', listener);
this.off('_delete', delListener);
this.off('_clear', clearListener);
} else {
this.off('change', listener);
}
disposed = true;
}.bind(this))
});
return result;
}, { refCounter: true, dispose: invokeDispose, getNormalizer: getNormalizer })
}));
}, { normalizer: getNormalizer() });