marko/widgets/State.js
2017-01-02 15:53:38 -07:00

116 lines
3.4 KiB
JavaScript

var updateManager = require('./update-manager');
var extend = require('raptor-util/extend');
function ensure(state, propertyName) {
var proto = state.constructor.prototype;
if (!proto.hasOwnProperty(propertyName)) {
Object.defineProperty(proto, propertyName, {
get: function() {
return this.$__raw[propertyName];
},
set: function(value) {
this.$__set(propertyName, value, false /* ensure:false */);
}
});
}
}
function State(widget, initialState) {
this.$__widget = widget;
this.$__raw = initialState || {};
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
if (initialState) {
for(var key in initialState) {
if (initialState.hasOwnProperty(key)) {
ensure(this, key);
}
}
}
}
State.prototype = {
$__reset: function() {
var self = this;
self.$__dirty = false;
self.$__old = null;
self.$__changes = null;
self.$__forced = null;
},
$__replace: function(newState, noQueue) {
var state = this;
var key;
var rawState = this.$__raw;
for (key in rawState) {
if (rawState.hasOwnProperty(key) && !newState.hasOwnProperty(key)) {
state.$__set(key, undefined, false /* ensure:false */, false /* forceDirty:false */, noQueue);
}
}
for (key in newState) {
if (newState.hasOwnProperty(key)) {
state.$__set(key, newState[key], true /* ensure:true */, false /* forceDirty:false */, noQueue);
}
}
},
$__set: function(name, value, shouldEnsure, forceDirty, noQueue) {
var rawState = this.$__raw;
if (shouldEnsure) {
ensure(this, name);
}
if (value === null) {
// Treat null as undefined to simplify our comparison logic
value = undefined;
}
if (forceDirty) {
var forcedDirtyState = this.$__forced || (this.$__forced = {});
forcedDirtyState[name] = true;
} else if (rawState[name] === value) {
return;
}
var clean = !this.$__dirty;
if (clean) {
// This is the first time we are modifying the widget state
// so introduce some properties to do some tracking of
// changes to the state
this.$__dirty = true; // Mark the widget state as dirty (i.e. modified)
this.$__old = rawState;
this.$__raw = rawState = extend({}, rawState);
this.$__changes = {};
}
this.$__changes[name] = value;
if (value == null) {
// Don't store state properties with an undefined or null value
delete rawState[name];
} else {
// Otherwise, store the new value in the widget state
rawState[name] = value;
}
if (clean && noQueue !== true) {
// If we were clean before then we are now dirty so queue
// up the widget for update
updateManager.$__queueWidgetUpdate(this.$__widget);
}
},
toJSON: function() {
return this.$__raw;
}
};
module.exports = State;