Skip to content
Browse files

Initial implementation of getPlainValue interface and others.

  • Loading branch information...
1 parent 261f912 commit 4b8b5ffc9e60b7398586d6fbb31427b03b0c2597 @asudoh committed Feb 2, 2012
Showing with 240 additions and 147 deletions.
  1. +3 −5 Repeat.js
  2. +62 −22 StatefulArray.js
  3. +118 −40 StatefulModel.js
  4. +4 −5 _base.js
  5. +44 −0 getPlainValue.js
  6. +9 −23 getStateful.js
  7. +0 −52 getStatefulModelOptions.js
View
8 Repeat.js
@@ -162,11 +162,9 @@ define([
this._addRemoveWatch.unwatch();
}
var pThis = this;
- this._addRemoveWatch = this.get("binding").watch(function(name,old,current){
- if(/^[0-9]+$/.test(name.toString())){
- if(!old || !current){
- pThis._buildContained();
- } // else not an insert or delete, will get updated in above
+ this._addRemoveWatch = this.get("binding").watchElements(function(idx, removals, adds){
+ if(!removals || !adds || removals.length || adds.length){
+ pThis._buildContained();
}
});
}
View
84 StatefulArray.js 100755 → 100644
@@ -2,15 +2,29 @@ define([
"dojo/_base/lang",
"dojo/Stateful"
], function(lang, Stateful){
+ /*=====
+ dojox.mvc.StatefulArray.watchElements.handle = {
+ // summary:
+ // A handle of setting watch callback for array elements.
+
+ unwatch: function(){
+ // summary:
+ // Stops watching for array elements.
+ }
+ };
+ =====*/
+
function update(/*dojox.mvc.StatefulArray*/ a){
// summary:
// Set all array elements as stateful so that watch function runs.
// a: dojox.mvc.StatefulArray
// The array.
- for(var i = 0; i < a.get("length"); i++){
- a.set(i, a[i]);
+ // Notify change of elements.
+ if(a._watchElementCallbacks){
+ a._watchElementCallbacks();
}
+
return a; // dojox.mvc.StatefulArray
}
@@ -32,34 +46,27 @@ define([
var l = a.get("length"),
p = Math.min(idx, l),
removals = a.slice(idx, idx + n),
- adds = lang._toArray(arguments).slice(3),
- slid = a.notifySlides && a.slice(idx, idx + l - p - n);
+ adds = lang._toArray(arguments).slice(3);
- // If we don't need to notify slid elements, do the modification in a native manner except for setting additions
- if(!a.notifySlides){
- [].splice.apply(this, [idx, n].concat(new Array(adds.length)));
- }
+ // Do the modification in a native manner except for setting additions
+ [].splice.apply(this, [idx, n].concat(new Array(adds.length)));
// Set additions in a stateful manner
for(var i = 0; i < adds.length; i++){
a.set(p + i, adds[i]);
}
- // Set slid elements in a stateful manner to notify of them
- if(a.notifySlides && (n > 0 || adds.length > 0)){
- for(i = 0; i < slid.length; i++){
- a.set(p + adds.length + i, slid[i]);
- }
+ // Notify change of elements.
+ if(this._watchElementCallbacks){
+ this._watchElementCallbacks(idx, removals, adds);
}
- // Set elements of reduced index, in a stateful manner
- for(var i = l - n + adds.length; i < l; i++){
- a.set(i, void 0);
+ // Notify change of length.
+ // Not calling the setter for "length" though, given removal/addition of array automatically changes the length.
+ if(this._watchCallbacks){
+ this._watchCallbacks("length", l, l - removals.length + adds.length);
}
- // Update the length
- a.set("length", l - n + adds.length);
-
return removals; // dojox.mvc.StatefulArray
}
@@ -105,9 +112,7 @@ define([
// value: Anything
// The new value.
- if(arguments.callee.caller.caller == splice){
- return Stateful.prototype.set.call(this, name, value);
- }else if(name == "length"){
+ if(name == "length"){
var old = a.get("length");
if(old < value){
a.splice.apply(a, [old, 0].concat(new Array(value - old)))
@@ -121,6 +126,38 @@ define([
}
}
+ function watchElements(/*dojox.mvc.StatefulArray*/ a, /*Function*/ callback){
+ // summary:
+ // Watch for change in array elements.
+ // a: dojox.mvc.StatefulArray
+ // The array.
+ // callback: Function
+ // The callback function, which should take: The array index, the removed elements, and the added elements.
+
+ var callbacks = a._watchElementCallbacks;
+ if(!callbacks){
+ callbacks = a._watchElementCallbacks = function(idx, removals, adds){
+ for(var list = [].concat(callbacks.list), i = 0; i < list.length; i++){
+ list[i].call(a, idx, removals, adds);
+ }
+ };
+ callbacks.list = [];
+ }
+
+ callbacks.list.push(callback);
+
+ return {
+ unwatch: function(){
+ for(var list = callbacks.list, i = 0; i < list.length; i++){
+ if(list[i] == callback){
+ list.splice(i, 1);
+ break;
+ }
+ }
+ }
+ }; // dojox.mvc.StatefulArray.watchElements.handle
+ }
+
var StatefulArray = /*===== dojox.mvc.StatefulArray = =====*/ function(/*Anything[]*/ a){
// summary:
// An inheritance of native JavaScript array, that adds dojo.Stateful capability.
@@ -176,6 +213,9 @@ define([
},
slice: function(/*Number*/ start, /*Number*/ end){
return slice.apply(this, [this].concat(lang._toArray(arguments)));
+ },
+ watchElements: function(/*Function*/ callback){
+ return watchElements(this, callback);
}
}, Stateful.prototype, {
set: function(/*Number|String*/ name, /*Anything*/ value){
View
158 StatefulModel.js
@@ -1,10 +1,13 @@
define([
+ "dojo/_base/kernel",
"dojo/_base/lang",
"dojo/_base/array",
"dojo/_base/declare",
"dojo/Stateful",
+ "./getStateful",
+ "./getPlainValue",
"./StatefulArray"
-], function(lang, array, declare, Stateful, StatefulArray){
+], function(kernel, lang, array, declare, Stateful, getStateful, getPlainValue, StatefulArray){
/*=====
declare = dojo.declare;
Stateful = dojo.Stateful;
@@ -224,25 +227,8 @@ define([
// Object
// The plain JavaScript object representation of the data in this
// model.
- var ret = {};
- var nested = false;
- for(var p in this){
- if(this[p] && lang.isFunction(this[p].toPlainObject)){
- if(!nested && typeof this.get("length") === "number"){
- ret = [];
- }
- nested = true;
- ret[p] = this[p].toPlainObject();
- }
- }
- if(!nested){
- if(this.get("length") === 0){
- ret = [];
- }else{
- ret = this.value;
- }
- }
- return ret;
+
+ return getPlainValue(this, StatefulModel.getPlainValueOptions);
},
splice: function(/*Number*/ idx, /*Number*/ n){
@@ -352,31 +338,29 @@ define([
// tags:
// private
var data = (args && "data" in args) ? args.data : this.data;
- this._createModel(data);
- },
-
- //////////////////////// PRIVATE METHODS ////////////////////////
- _createModel: function(/*Object*/ obj){
- // summary:
- // Create this data model from provided input data.
- // obj:
- // The input for the model, as a plain JavaScript object.
- // tags:
- // private
- if(lang.isObject(obj) && !(obj instanceof Date) && !(obj instanceof RegExp) && obj !== null){
- for(var x in obj){
- var newProp = new StatefulModel({ data : obj[x] });
- this.set(x, newProp);
- }
- if(lang.isArray(obj)){
- this.set("length", obj.length);
+ if(data != null){
+ kernel.deprecated("To create dojox.mvc.StatefulModel from data, dojox.mvc.getStateful() should be used.");
+ data = getStateful(data, StatefulModel.getStatefulOptions);
+ if(lang.isArray(data)){
+ // Some consumers of dojox.mvc.StatefulModel inherits it via dojo.declare(), where we cannot use array inheritance technique
+ // (dojo.declare() does not support return value in constructor)
+ this.length = 0;
+ [].splice.apply(this, data);
+ }else if(lang.isObject(data)){
+ for(var s in data){
+ if(data.hasOwnProperty(s)){
+ this[s] = data[s];
+ }
+ }
+ }else{
+ this.set("value", data);
}
- }else{
- this.set("value", obj);
}
},
+ //////////////////////// PRIVATE METHODS ////////////////////////
+
_commit: function(){
// summary:
// Commits this data model, saves the current state into data to become the saved state,
@@ -417,5 +401,99 @@ define([
}
});
+ lang.mixin(StatefulModel, {
+ getStatefulOptions: {
+ // summary:
+ // An object that defines how model object should be created from plain object hierarchy.
+
+ getType: function(/*Anything*/ v){
+ // summary:
+ // Returns the type of the given value.
+ // v: Anything
+ // The value.
+
+ return lang.isArray(v) ? "array" : {}.toString.call(v) == "[object Object]" ? "object" : "value"; // String
+ },
+
+ getStatefulArray: function(/*Anything[]*/ a){
+ // summary:
+ // Create a stateful array from a plain array.
+ // a: Anything[]
+ // The plain array.
+
+ var _self = this, statefularray = lang.mixin(new StatefulArray(array.map(a, function(item){ return getStateful(item, _self); })));
+ for(var s in StatefulModel.prototype){
+ if(s != "set"){ statefularray[s] = StatefulModel.prototype[s]; }
+ }
+ statefularray.data = a;
+ return statefularray;
+ },
+
+ getStatefulObject: function(/*Object*/ o){
+ // summary:
+ // Create a stateful object from a plain object.
+ // o: Object
+ // The plain object.
+
+ var object = new StatefulModel();
+ object.data = o;
+ for(var s in o){
+ object.set(s, getStateful(o[s], this));
+ }
+ return object; // dojox.mvc.StatefulModel
+ },
+
+ getStatefulValue: function(/*Anything*/ v){
+ // summary:
+ // Create a stateful value from a plain value.
+ // v: Anything
+ // The plain value.
+
+ var value = new StatefulModel();
+ value.data = v;
+ value.set("value", v);
+ return value;
+ }
+ },
+
+ getPlainValueOptions: {
+ // summary:
+ // An object that defines how plain value should be created from model object.
+
+ getType: function(/*Anything*/ v){
+ // summary:
+ // Returns the type of the given value.
+ // v: Anything
+ // The value.
+
+ if(lang.isArray(v)){ return "array"; }
+ if(lang.isObject(v)){ // Primitive values may have their own properties
+ for(var s in v){
+ if(v.hasOwnProperty(s) && s != "value" && (v[s] || {}).get && (v[s] || {}).watch){
+ return "object";
+ }
+ }
+ }
+ return "value";
+ },
+
+ getPlainArray: function(/*dojox.mvc.StatefulArray*/ a){
+ return array.map(this, function(item){ return getPlainValue(item, this); });
+ },
+
+ getPlainObject: function(/*dojox.mvc.StatefulModel*/ o){
+ var plain = {};
+ for(var s in o){
+ plain[s] = getPlainValue(o[s], this);
+ }
+ return plain;
+ },
+
+ getPlainValue: function(/*Anything*/ v){
+ return (v || {}).set && (v || {}).watch ? v.value : v;
+ }
+ }
+ });
+
return StatefulModel;
});
View
9 _base.js 100755 → 100644
@@ -2,12 +2,11 @@ define([
"dojo/_base/kernel",
"dojo/_base/lang",
"./getStateful",
- "./getStatefulModelOptions",
"./StatefulModel",
"./Bind",
"./_DataBindingMixin",
"./_patches"
-], function(kernel, lang, getStateful, getStatefulModelOptions, StatefulModel){
+], function(kernel, lang, getStateful, StatefulModel){
// module:
// dojox/mvc/_base
// summary:
@@ -45,18 +44,18 @@ define([
// Promise
if(args.data){
- return getStateful(args.data, getStatefulModelOptions);
+ return getStateful(args.data, StatefulModel.getStatefulOptions);
}else if(args.store && lang.isFunction(args.store.query)){
var model;
var result = args.store.query(args.query);
if(result.then){
return (result.then(function(data){
- model = getStateful(data, getStatefulModelOptions);
+ model = getStateful(data, StatefulModel.getStatefulOptions);
model.store = args.store;
return model;
}));
}else{
- model = getStateful(result, getStatefulModelOptions);
+ model = getStateful(result, StatefulModel.getStatefulOptions);
model.store = args.store;
return model;
}
View
44 getPlainValue.js
@@ -0,0 +1,44 @@
+define(["dojo/_base/lang"], function(lang){
+ /*=====
+ dojox.mvc.getPlainValueOptions = {
+ // summary:
+ // An object that defines how model object should be created from plain object hierarchy.
+
+ getType: function(v){
+ // summary:
+ // Returns the type of the given value.
+ // v: Anything
+ // The value.
+
+ return "value"; // String
+ },
+
+ getPlainType: function(v){
+ // summary:
+ // Creates a plain value from a stateful value.
+ // The "Type" in this function name is actually what getType() returns, with first character uppercased, such as: getPlainArray, getPlainObject, getPlainValue.
+ // v: Anything
+ // The stateful value.
+
+ return v; // Anything
+ }
+ };
+ =====*/
+
+ var getPlainValue = /*===== dojox.mvc.getPlainValue = =====*/ function(/*Anything*/ value, /*dojox.mvc.getPlainValueOptions*/ options){
+ // summary:
+ // Create a raw value from a dojo.Stateful object.
+ // description:
+ // Recursively iterates the stateful value given, and convert them to raw ones.
+ // value: Anything
+ // The stateful value.
+ // options: Object
+ // The object that defines how plain value should be created from stateful value.
+ // returns: Anything
+ // The converted value.
+
+ return options["getPlain" + options.getType(value).replace(/^[a-z]/, function(c){ return c.toUpperCase(); })](value); // Anything
+ };
+
+ return lang.setObject("dojox.mvc.getPlainValue", getPlainValue);
+});
View
32 getStateful.js 100755 → 100644
@@ -4,27 +4,19 @@ define(["dojo/_base/lang"], function(lang){
// summary:
// An object that defines how model object should be created from plain object hierarchy.
- getStatefulArray: function(a){
+ getType: function(v){
// summary:
- // Create a stateful array from a plain array.
- // a: Anything[]
- // The plain array.
-
- return a; // dojox.mvc.StatefulArray
- },
-
- getStatefulObject: function(o){
- // summary:
- // Create a stateful object from a plain object.
- // o: Object
- // The plain object.
+ // Returns the type of the given value.
+ // v: Anything
+ // The value.
- return o; // dojo.Stateful
+ return "value"; // String
},
- getStatefulValue: function(v){
+ getStatefulType: function(v){
// summary:
- // Create a stateful value from a plain value.
+ // Creates a stateful value from a plain value.
+ // The "Type" in this function name is actually what getType() returns, with first character uppercased, such as: getStatefulArray, getStatefulObject, getStatefulValue.
// v: Anything
// The plain value.
@@ -45,13 +37,7 @@ define(["dojo/_base/lang"], function(lang){
// returns: Anything
// The converted value.
- if(lang.isArray(value)){
- return options.getStatefulArray(value);
- }else if({}.toString.call(value) == "[object Object]"){
- return options.getStatefulObject(value);
- }else{
- return options.getStatefulValue(value);
- }
+ return options["getStateful" + options.getType(value).replace(/^[a-z]/, function(c){ return c.toUpperCase(); })](value); // Anything
};
return lang.setObject("dojox.mvc.getStateful", getStateful);
View
52 getStatefulModelOptions.js
@@ -1,52 +0,0 @@
-define([
- "dojo/_base/array",
- "dojo/_base/lang",
- "./getStateful",
- "./StatefulArray",
- "./StatefulModel"
-], function(darray, lang, getStateful, StatefulArray, StatefulModel){
- return /*===== dojox.mvc.getStatefulModelOptions = =====*/ {
- // summary:
- // An object that defines how model object should be created from plain object hierarchy.
-
- getStatefulArray: function(/*Anything[]*/ a){
- // summary:
- // Create a stateful array from a plain array.
- // a: Anything[]
- // The plain array.
-
- var _self = this, array = lang.mixin(new StatefulArray(darray.map(a, function(item){ return getStateful(item, _self); })));
- for(var s in StatefulModel.prototype){
- if(s != "set"){ array[s] = StatefulModel.prototype[s]; }
- }
- array.data = a;
- return array;
- },
-
- getStatefulObject: function(/*Object*/ o){
- // summary:
- // Create a stateful object from a plain object.
- // o: Object
- // The plain object.
-
- var object = new StatefulModel({data: {}});
- object.data = o;
- for(var s in o){
- object.set(s, getStateful(o[s], this));
- }
- return object; // dojox.mvc.StatefulModel
- },
-
- getStatefulValue: function(/*Anything*/ v){
- // summary:
- // Create a stateful value from a plain value.
- // v: Anything
- // The plain value.
-
- var value = new StatefulModel({data: {}});
- value.data = v;
- value.set("value", v);
- return value;
- }
- };
-});

0 comments on commit 4b8b5ff

Please sign in to comment.
Something went wrong with that request. Please try again.