marko
Version:
UI Components + streaming, async, high performance, HTML templating for Node.js and the browser.
102 lines (87 loc) • 2.47 kB
JavaScript
var extend = require("raptor-util/extend");
function ensure(state, propertyName) {
var proto = state.constructor.prototype;
if (!(propertyName in proto)) {
Object.defineProperty(proto, propertyName, {
get: function () {
return this.___raw[propertyName];
},
set: function (value) {
this.___set(propertyName, value, false /* ensure:false */);
},
});
}
}
function State(component) {
this.___component = component;
this.___raw = {};
this.___dirty = false;
this.___old = null;
this.___changes = null;
this.___forced = null; // An object that we use to keep tracking of state properties that were forced to be dirty
Object.seal(this);
}
State.prototype = {
___reset: function () {
this.___dirty = false;
this.___old = null;
this.___changes = null;
this.___forced = null;
},
___replace: function (newState) {
var key;
var rawState = this.___raw;
for (key in rawState) {
if (!(key in newState)) {
this.___set(
key,
undefined,
false /* ensure:false */,
false /* forceDirty:false */,
);
}
}
for (key in newState) {
this.___set(
key,
newState[key],
true /* ensure:true */,
false /* forceDirty:false */,
);
}
},
___set: function (name, value, shouldEnsure, forceDirty) {
var rawState = this.___raw;
if (shouldEnsure) {
ensure(this, name);
}
if (forceDirty) {
var forcedDirtyState = this.___forced || (this.___forced = {});
forcedDirtyState[name] = true;
} else if (rawState[name] === value) {
return;
}
if (!this.___dirty) {
// This is the first time we are modifying the component state
// so introduce some properties to do some tracking of
// changes to the state
this.___dirty = true; // Mark the component state as dirty (i.e. modified)
this.___old = rawState;
this.___raw = rawState = extend({}, rawState);
this.___changes = {};
this.___component.___queueUpdate();
}
this.___changes[name] = value;
if (value === undefined) {
// Don't store state properties with an undefined or null value
delete rawState[name];
} else {
// Otherwise, store the new value in the component state
rawState[name] = value;
}
},
toJSON: function () {
return this.___raw;
},
};
module.exports = State;