spiritjs
Version:
The animation toolkit for the web
191 lines (183 loc) • 6.37 kB
JavaScript
;
exports.__esModule = true;
exports.emitChange = emitChange;
var _events = require("./events");
var _list = _interopRequireDefault(require("../list/list"));
var _is = require("./is");
function _interopRequireDefault(e) { return e && e.__esModule ? e : { "default": e }; }
function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; }
function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; }
function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); } /**
* -------------------------------------------
* Decorator for emitting changes
* -------------------------------------------
*
* @example on setter:
*
* class Item {
*
* _label = null
* _list = new List()
*
* get label() {
* return this._label
* }
*
* @emitChange()
* set label(val) {
* this._label = val
* }
*
* }
*
* @example on class:
*
* @emitChange('album')
* @emitChange('label', 'untitled', [
* {
* validator: v => /\d+/.test(v),
* message: 'Not a number'
* },
* {
* validator = v => typeof v === 'string',
* message: 'Must be a string'
* }
* ])
*
* class Song {
*
* }
*/
/**
* Setter deco
*
* @param {Emitter} target
* @param {string} key
* @param {object} descriptor
* @returns {object}
*/
var setter = function setter(target, key, descriptor) {
var fn = descriptor.set;
if (!_events.Emitter.prototype.isPrototypeOf(target) && !_events.Emitter.prototype.isPrototypeOf(target.prototype)) {
throw new Error('@emitter.emitChange can only be applied to event emitters');
}
return _objectSpread(_objectSpread({}, descriptor), {}, {
configurable: true,
set: function set(val) {
var _this = this;
var toObj = function toObj(v) {
var _ref;
return (0, _is.isFunction)(_this.toObject) ? _this.toObject() : (_ref = {}, _ref[key] = v !== undefined ? v : val, _ref);
};
// get previous value
var prev = this['_' + key];
if (prev && typeof prev.toArray === 'function') {
prev = prev.toArray();
} else if (prev && typeof prev.toObject === 'function') {
prev = prev.toObject();
}
var previous;
if (prev !== val) {
previous = toObj(prev);
}
// call class setter method
fn.call(this, val);
// is a duplicate on list?
if (this._list instanceof _list["default"] && this._list._duplicates !== true) {
try {
this._list.checkOnDuplicates();
} catch (err) {
fn.call(this, prev);
throw err;
}
}
// only emit changes
if (prev === val) {
return;
}
var from = prev && (0, _is.isFunction)(prev.toObject) ? prev.toObject() : prev;
var to = val && (0, _is.isFunction)(val.toObject) ? val.toObject() : val;
var changed = {
type: key,
from: from,
to: to
};
var current;
try {
current = toObj();
} catch (err) {
var _current;
current = (_current = {}, _current[key] = val, _current);
}
var evtParams = {
previous: previous,
current: current,
changed: changed
};
var evtChange = ['change', evtParams];
var evtChangeProp = ["change:" + key, evtParams, val];
this.emit.apply(this, evtChange);
this.emit.apply(this, evtChangeProp);
if (this._list && this._list instanceof _events.Emitter) {
var _this$_list, _this$_list2;
(_this$_list = this._list).emit.apply(_this$_list, evtChange);
(_this$_list2 = this._list).emit.apply(_this$_list2, evtChangeProp);
}
}
});
};
/**
* Decorator
*
* @param {string} prop (apply on classes)
* @param {*} defaultValue (optional, default=null)
* @param {Array} validators (optional)
*/
function emitChange(prop, defaultValue, validators) {
if (prop === void 0) {
prop = null;
}
if (defaultValue === void 0) {
defaultValue = null;
}
if (validators === void 0) {
validators = [];
}
if (prop) {
// bind as class
return function (target) {
var _Object$definePropert;
// setup class prototype
Object.defineProperties(target.prototype, (_Object$definePropert = {}, _Object$definePropert["_" + prop] = {
value: defaultValue,
writable: true,
enumerable: false,
configurable: true
}, _Object$definePropert[prop] = {
configurable: true,
get: function get() {
return this["_" + prop];
},
set: function set(val) {
var errors = validators.reduce(function (res, v) {
if (!v.validator(val)) {
res.push(v.message);
}
return res;
}, []);
if (errors.length > 0) {
throw new Error("" + errors[0]);
}
this["_" + prop] = val;
}
}, _Object$definePropert));
// apply setter on it
var descriptor = Object.getOwnPropertyDescriptor(target.prototype, prop);
Object.defineProperty(target.prototype, prop, setter(target, prop, descriptor));
};
}
// bind as setter
return setter;
}