Skip to content

Commit

Permalink
removed 'readonly' from the API and added property support to the att…
Browse files Browse the repository at this point in the history
…ributes configuration
  • Loading branch information
delambo committed Oct 13, 2012
1 parent e62d2f8 commit e7d3b18
Show file tree
Hide file tree
Showing 2 changed files with 43 additions and 43 deletions.
48 changes: 21 additions & 27 deletions backbone.stickit.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@
stickit: function(optionalModel, optionalBindingsConfig) {
var self = this, observeModelEvent,
model = optionalModel || this.model,
bindings = optionalBindingsConfig || this.bindings || {};
bindings = optionalBindingsConfig || this.bindings || {},
props = ['autofocus', 'autoplay', 'async', 'checked', 'controls', 'defer', 'disabled', 'hidden', 'loop', 'multiple', 'open', 'readonly', 'required', 'scoped', 'selected'];

this._modelBindings || (this._modelBindings = []);

Expand Down Expand Up @@ -61,20 +62,29 @@
return format ? applyViewFn(self, format, val, modelAttr) : val;
};

// Setup the attributes configuration.
// Setup the attributes configuration - a list that maps an attribute or
// property `name`, to an `observe`d model attribute, using an optional
// `format`ter.
//
// [{
// name: 'attributeOrPropertyName',
// observe: 'modelAttrName'
// format: function(modelAttrVal, modelAttrName) { ... }
// }, ...]
//
_.each(attributes, function(attrConfig) {
var lastClass = '',
observed = attrConfig.observe || modelAttr,
updateAttr = function() {
var val;
var val, updateType = _.indexOf(props, attrConfig.name) > -1 ? 'prop' : 'attr';
if (attrConfig.format) val = applyViewFn(self, attrConfig.format, model.get(observed), observed);
else val = model.get(observed);
// If it is a class then we need to remove the last value and add the new.
if (attrConfig.name == 'class') {
$el.removeClass(lastClass).addClass(val);
lastClass = val;
}
else $el.attr(attrConfig.name, val);
else $el[updateType](attrConfig.name, val);
};
observeModelEvent('bind:' + observed, updateAttr);
updateAttr();
Expand All @@ -84,16 +94,15 @@
// If the bind element is a form element, then configure `this.events` bindings
// so that the model stays in sync with user input/changes.
eventCallback = function(e) {
var options = _.extend({bindKey:bindKey}, config.setOptions || {});
model.set(modelAttr, getFormElVal($el), options);
};
var options = _.extend({bindKey:bindKey}, config.setOptions || {});
model.set(modelAttr, getFormElVal($el), options);
};
if ($el.is('input[type=radio]') || $el.is('input[type=checkbox]') || $el.is('select'))
self.events['change '+selector] = eventCallback;
else if ($el.is('input') || $el.is('textarea')) {
self.events['keyup '+selector] = eventCallback;
self.events['change '+selector] = eventCallback;
}


// Setup a `bind:modelAttr` observer for the model to keep the view element in sync.
observeModelEvent('bind:'+modelAttr, function(val, options) {
Expand Down Expand Up @@ -177,36 +186,22 @@

// Update the value of `$el` in `view` using the given configuration.
updateViewBindEl = function(view, $el, config, val, model, isInitializing) {
var markReadonly, originalVal, tempSelection,
var originalVal, radioEl,
modelAttr = config.modelAttr,
readonly = config.readonly,
afterUpdate = config.afterUpdate,
selectConfig = config.selectOptions,
updateMethod = config.updateMethod || 'text';

// Sets the readonly property of the bind element based on the truthiness of the `readonly`
// configuration, or the result of its execution in the case that it is a function.
markReadonly = function() {
if (readonly) {
if (_.isBoolean(readonly)) $el.prop('readonly', readonly);
else $el.prop('readonly', view[readonly].call(view, modelAttr));
} else
$el.prop('readonly', false);
};

if ($el.is('input[type=radio]')) {
tempSelection = $el.filter('[value='+val+']');
originalVal = tempSelection.prop('checked');
tempSelection.prop('checked', true);
markReadonly();
radioEl = $el.filter('[value='+val+']');
originalVal = radioEl.prop('checked');
radioEl.prop('checked', true);
} else if ($el.is('input[type=checkbox]')) {
originalVal = $el.prop('checked');
$el.prop('checked', val === true);
markReadonly();
} else if ($el.is('input') || $el.is('textarea')) {
originalVal = $el.val();
if (originalVal !== val) $el.val(val);
markReadonly();
} else if ($el.is('select')) {
var optList, list = selectConfig.collection, fieldVal = model.get(modelAttr);

Expand Down Expand Up @@ -243,7 +238,6 @@

$el.append(option);
});
markReadonly();
} else {
originalVal = $el[updateMethod]();
$el[updateMethod](val);
Expand Down
38 changes: 22 additions & 16 deletions test/bindData.js
Original file line number Diff line number Diff line change
Expand Up @@ -252,22 +252,6 @@ $(document).ready(function() {
equal(view.$('#test5').text(), '_fountain_water');
});

test('bindings:readonly', function() {

model.set({'water':'fountain'});
view.model = model;
view.templateId = 'jst1';
view.bindings = {
'#test1': {
modelAttr: 'water',
readonly: true
}
};
$('#qunit-fixture').html(view.render().el);

ok(view.$('#test1').prop('readonly'));
});

test('bindings:afterUpdate', function() {

model.set({'water':'fountain'});
Expand Down Expand Up @@ -467,6 +451,28 @@ $(document).ready(function() {
equal(view.$('#test5').attr('data-name'), 'evian-snickers');
});

test('bindings:attributes (properties)', function() {

model.set({'water':true});
view.model = model;
view.templateId = 'jst1';
view.bindings = {
'#test1': {
attributes: [{
name: 'readonly',
observe: 'water'
}]
}
};

$('#qunit-fixture').html(view.render().el);

equal(view.$('#test1').prop('readonly'), true);

model.set({'water':false});
equal(view.$('#test1').prop('readonly'), false);
});

test('input:number', function() {

model.set({'code':1});
Expand Down

0 comments on commit e7d3b18

Please sign in to comment.