mirror of
https://github.com/marko-js/marko.git
synced 2025-12-08 19:26:05 +00:00
116 lines
3.4 KiB
JavaScript
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; |