Skip to content

Instantly share code, notes, and snippets.

@juandopazo
Last active January 2, 2016 09:59
Show Gist options
  • Save juandopazo/8287117 to your computer and use it in GitHub Desktop.
Save juandopazo/8287117 to your computer and use it in GitHub Desktop.
ES5-based Y.Model
function assign(dest, source) {
for (var prop in source) {
if (source.hasOwnProperty(prop)) {
dest[prop] = source[prop];
}
}
return dest;
}
function createStateClass(superclass, props) {
var prop, record;
function StateClass() {
}
StateClass.COMPUTABLE = {};
if (superclass) {
StateClass.prototype = Object.create(superclass.prototype, {
constructor: {
value: StateClass
}
});
assign(StateClass.COMPUTABLE, superclass.COMPUTABLE);
}
if (props) {
for (prop in props) {
if (props.hasOwnProperty(prop)) {
record = props[prop];
if (!record.hasOwnProperty('writable')) {
record.writable = true;
}
if (!record.hasOwnProperty('configurable')) {
record.configurable = true;
}
if (!record.hasOwnProperty('enumerable')) {
record.configurable = true;
}
if (record.hasOwnProperty('set') ||
record.hasOwnProperty('get')) {
StateClass.COMPUTABLE[prop] = true;
}
Object.defineProperty(StateClass.prototype, prop, record);
}
}
Object.defineProperties(StateClass.prototype, props);
}
return StateClass;
}
function Model(config) {
var prop,
state = new this.constructor.__STATE__();
this._state = state;
this._changes = null;
this._callbacks = [];
if (config) {
for (prop in config) {
if (prop in state) {
state[prop] = config[prop];
}
}
}
this._observe();
}
assign(Model.prototype, {
_observe: function () {
var self = this;
Object.observe(this._state, function (changes) {
self._notify(changes);
});
},
_notify: function (changes) {
var callbacks = this._callbacks;
this._callbacks = [];
for (var i = 0, length = callbacks.length; i < length; i++) {
callbacks[i](changes);
}
},
set: function (propName, value) {
if (propName in this._state) {
this._state[propName] = value;
}
return this;
},
get: function (propName) {
if (propName in this._state) {
return this._state[propName];
}
},
onChanged: function (callback) {
this._callbacks.push(callback);
return this;
},
toJSON: function () {
var result = {},
prop;
for (prop in this._state) {
result[prop] = this._state[prop];
}
return result;
}
});
Model.extend = function extend(proto, attrs) {
var superclass = this,
prop,
subclass = (proto && proto.hasOwnProperty('constructor')) ?
proto.constructor : function BuiltModel(config) {
superclass.call(this, config);
};
subclass.prototype = Object.create(superclass.prototype, {
constructor: {
value: subclass
}
});
subclass.extend = extend;
if (proto) {
assign(subclass.prototype, proto);
}
if (attrs) {
assign(subclass, attrs);
}
subclass.__STATE__ = createStateClass(superclass.__STATE__, attrs && attrs.PROPS);
return subclass;
};
Model.__STATE__ = createStateClass();
var Model = Y.Model,
asap = Y.asap;
Model.prototype._observe = function () {
this._changes = [];
this._observing = false;
};
Model.prototype._scheduleChange = function () {
var self = this;
self._observing = true;
asap(function () {
var changes = self._changes;
self._observing = false;
self._changes = [];
self._notify(changes);
});
};
Model.prototype.set = function (propName, value) {
var state = this._state,
oldValue,
added = false,
record = {};
if (!(propName in state)) {
added = true;
}
oldValue = state[propName];
state[propName] = value;
if (!(oldValue === value || this.constructor.__STATE__.COMPUTABLE[propName])) {
record = {
name: propName,
object: this
};
if (added) {
record.type = 'add';
} else {
record.oldValue = oldValue;
record.type = 'update';
}
this._changes.push(record);
if (!this._observing) {
this._scheduleChange();
}
}
return this;
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment