Skip to content

Commit

Permalink
docs
Browse files Browse the repository at this point in the history
  • Loading branch information
justinbmeyer committed Apr 5, 2014
1 parent a3c287e commit f1ec168
Show file tree
Hide file tree
Showing 17 changed files with 706 additions and 75 deletions.
14 changes: 12 additions & 2 deletions list/list.js
Original file line number Diff line number Diff line change
Expand Up @@ -257,7 +257,7 @@ steal("can/util", "can/map", "can/map/bubble.js",function (can, Map, bubble) {
i;

for (i = 2; i < args.length; i++) {
args[i] = bubble.set(this, i, args[i]);
args[i] = bubble.set(this, i, this.__type(args[i], i) );

}
if (howMany === undefined) {
Expand Down Expand Up @@ -685,7 +685,7 @@ steal("can/util", "can/map", "can/map/bubble.js",function (can, Map, bubble) {
// Go through and convert anything to an `map` that needs to be converted.
while (i--) {
val = arguments[i];
args[i] = bubble.set(this, i, val);
args[i] = bubble.set(this, i, this.__type(val, i) );
}

// Call the original method.
Expand Down Expand Up @@ -1033,6 +1033,16 @@ steal("can/util", "can/map", "can/map/bubble.js",function (can, Map, bubble) {
}

return this;
},
filter: function(filter){
var items = [],
self = this;
this.each(function(item){
if(filter.call(self, item)) {
items.push(item)
}
});
return new this.constructor(items);
}
});
can.List = Map.List = list;
Expand Down
2 changes: 1 addition & 1 deletion map/attributes/attributes.js
Original file line number Diff line number Diff line change
Expand Up @@ -286,7 +286,7 @@ steal('can/util', 'can/map', 'can/list', function (can, Map) {
can.Map.prototype.__convert = function (prop, value) {
// check if there is a
var Class = this.constructor,
oldVal = this.attr(prop),
oldVal = this.__get(prop),
type, converter;
if (Class.attributes) {
// the type of the attribute
Expand Down
14 changes: 7 additions & 7 deletions map/bubble.js
Original file line number Diff line number Diff line change
Expand Up @@ -111,17 +111,17 @@ steal('can/util', function(can){
}
}
},
set: function(parent, prop, value){
set: function(parent, prop, value, current){

var res = parent.__type(value, prop);
if(can.Map.helpers.isObservable(res)) {
bubble.add(parent, res, prop);
//var res = parent.__type(value, prop);
if( can.Map.helpers.isObservable(value) ) {
bubble.add(parent, value, prop);
}
// bubble.add will remove, so only remove if we are replacing another object
if(can.Map.helpers.isObservable(value) && value !== res) {
bubble.remove(parent, value);
if( can.Map.helpers.isObservable(current) ) {
bubble.remove(parent, current);
}
return res;
return value;
}
};

Expand Down
88 changes: 66 additions & 22 deletions map/define/define.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,39 @@
steal('can/util', 'can/compute','can/map/attributes', 'can/util/string/classize.js',function (can) {
steal('can/util','can/observe', function (can) {


can.Map.helpers.define = function(Map){
var define = Map.prototype.define;
Map.defaultGenerators = {};
for(prop in define) {
if( "value" in define[prop] ) {
if(typeof define[prop].value === "function") {
Map.defaultGenerators[prop] = define[prop].value;
} else {
Map.defaults[prop] = define[prop].value;
}
}
if( typeof define[prop].Value === "function" ) {
(function(Constructor){
Map.defaultGenerators[prop] = function(){
return new Constructor;
}
})(define[prop].Value);
}
}
};


var oldSetupDefaults = can.Map.prototype._setupDefaults;
can.Map.prototype._setupDefaults = function(){
var defaults = oldSetupDefaults.call(this),
Map = this.constructor;
for(var prop in Map.defaultGenerators) {
defaults[prop] = Map.defaultGenerators[prop].call(this);
}
return defaults;
};


var proto = can.Map.prototype,
oldSet = proto.__set;
proto.__set = function (prop, value, current, success, error) {
Expand All @@ -24,37 +59,50 @@ steal('can/util', 'can/compute','can/map/attributes', 'can/util/string/classize.
}
return false;
},
self = this;
self = this,
define = this.define && this.define[prop],
setter = define && define.set,
getter = define && define.get;



// if we have a setter
if (this.define && this.define[prop] && this.define[prop].set ) {
if ( setter ) {
// call the setter, if returned value is undefined,
// this means the setter is async so we
// do not call update property and return right away
can.batch.start();
var setterCalled = false;
value = this.define[prop].set.call(this, value, function (value) {
oldSet.call(self, prop, value, current, success, errorCallback);
setterCalled = true;
//!steal-remove-start
clearTimeout(asyncTimer);
//!steal-remove-end
}, errorCallback);

var setterCalled = false,

if(value === undefined && !setterCalled) {
setValue = setter.call(this, value, function (value) {
oldSet.call(self, prop, value, current, success, errorCallback);
setterCalled = true;
//!steal-remove-start
clearTimeout(asyncTimer);
//!steal-remove-end
}, errorCallback);
if(getter) {
// if there's a getter we do nothing
can.batch.stop();
return;
}
// if it took a setter and returned nothing, don't set the value
else if(setValue === undefined && !setterCalled && setter.length >= 2) {
//!steal-remove-start
asyncTimer = setTimeout(function(){
can.dev.warn('can/map/setter.js: Setter ' + prop+' did not return a value or call the setter callback.');
can.dev.warn('can/map/setter.js: Setter "' + prop+'" did not return a value or call the setter callback.');
},can.dev.warnTimeout);
can.batch.stop();
//!steal-remove-end
can.batch.stop();
return;
} else {
if(!setterCalled) {
oldSet.call(self, prop, value, current, success, errorCallback);
oldSet.call(self, prop,
// if no arguments, we are side-effects only
setter.length === 0 && setValue === undefined ? value : setValue,
current,
success,
errorCallback);
}
can.batch.stop();
return this;
Expand Down Expand Up @@ -114,15 +162,11 @@ steal('can/util', 'can/compute','can/map/attributes', 'can/util/string/classize.
newValue = type.call(this, newValue, prop);
}
// If there's a Type create a new instance of it
if(Type) {
if(Type && !(newValue instanceof Type) ) {
newValue = new Type(newValue);
}
// If the newValue is a Map, we need to hook it up
if(newValue instanceof can.Map) {
return can.Map.helpers.hookupBubble(newValue, prop, this);
} else {
return newValue;
}
return newValue;

}
return oldType.call(this,newValue, prop);
Expand Down
152 changes: 152 additions & 0 deletions map/define/define_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,33 @@ steal("can/map/define", "can/test", function () {

});

test("basic Type", function(){
var Foo = function(name) {
this.name = name
};
Foo.prototype.getName = function(){
return this.name;
};

var Typer = can.Map.extend({
define : {
foo : {
Type: Foo
}
}
});

var t = new Typer({foo: "Justin"});
equal( t.attr("foo").getName(), "Justin", "correctly created an instance");

var brian = new Foo("brian");

t.attr("foo",brian);

equal(t.attr("foo"), brian, "same instances");

});

test("type converters", function(){

var Typer = can.Map.extend({
Expand Down Expand Up @@ -218,4 +245,129 @@ steal("can/map/define", "can/test", function () {
equal( t.attr("leaveAlone"), obj, "left as object");

});


test("basics value", function(){
var Typer = can.Map.extend({
define : {
prop : { value: 'foo' }
}
});

equal( new Typer().attr('prop'), "foo", "value is used as default value");


Typer2 = can.Map.extend({
define : {
prop : {
value: function(){
return [];
},
type: "*"
}
}
});

var t1 = new Typer2,
t2 = new Typer2;
ok(t1.attr("prop") !== t2.attr("prop"), "different array instances");
ok( can.isArray(t1.attr("prop")), "its an array" )


});

test("basics Value", function(){

var Typer = can.Map.extend({
define : {
prop : {
Value: Array,
type: "*"
}
}
});

var t1 = new Typer,
t2 = new Typer;
ok(t1.attr("prop") !== t2.attr("prop"), "different array instances");
ok( can.isArray(t1.attr("prop")), "its an array" );


});


test("setter with no arguments and returns undefined does the default behavior, the setter is for side effects only", function(){

var Typer = can.Map.extend({
define: {
prop: {
set: function(){
this.attr("foo","bar")
}
}
}
});

var t = new Typer();

t.attr("prop", false);

deepEqual(t.attr(), {foo: "bar", prop: false})


});

test("type happens before the set", function(){
var MyMap = can.Map.extend({
define: {
prop: {
type: "number",
set: function(newValue){
equal(typeof newValue, "number", "got a number");
return newValue+1;
}
}
}
});

var map = new MyMap();
map.attr("prop", "5");

equal(map.attr("prop"), 6, "number");
});

test("getter and setter work", function(){
expect(5);
var Paginate = can.Map.extend({
define: {
page: {
set: function(newVal){
this.attr('offset', (parseInt(newVal) - 1) * this.attr('limit'));
},
get: function () {
return Math.floor(this.attr('offset') / this.attr('limit')) + 1;
}
}
}
});

var p = new Paginate({limit: 10, offset: 20});

equal( p.attr("page"), 3, "page get right" );

p.bind("page", function(ev, newValue, oldValue){
equal(newValue, 2, "got new value event");
equal(oldValue, 3, "got old value event");
});


p.attr("page",2);

equal( p.attr("page"), 2, "page set right" );

equal( p.attr("offset"), 10, "page offset set");


});

});
Loading

0 comments on commit f1ec168

Please sign in to comment.