ampersand-dom-bindings
Advanced tools
Comparing version 2.3.2 to 2.4.0
@@ -40,6 +40,11 @@ var Store = require('key-tree-store'); | ||
if (selector === '') return [el]; | ||
if (matchesSelector(el, selector)) return [el]; | ||
return slice.call(el.querySelectorAll(selector)); | ||
var matches = []; | ||
if (matchesSelector(el, selector)) matches.push(el); | ||
return matches.concat(slice.call(el.querySelectorAll(selector))); | ||
} | ||
function makeArray(val) { | ||
return Array.isArray(val) ? val : [val]; | ||
} | ||
function getBindingFunc(binding) { | ||
@@ -77,4 +82,7 @@ var type = binding.type || 'text'; | ||
return function (el, value) { | ||
var names = makeArray(binding.name); | ||
getMatches(el, selector).forEach(function (match) { | ||
dom.setAttribute(match, binding.name, value); | ||
names.forEach(function (name) { | ||
dom.setAttribute(match, name, value); | ||
}); | ||
}); | ||
@@ -95,8 +103,13 @@ previousValue = value; | ||
return function (el, value, keyName) { | ||
var yes = binding.name || binding.yes || keyName; | ||
var no = binding.no; | ||
var yes = makeArray(binding.name || binding.yes || keyName); | ||
var no = makeArray(binding.no); | ||
var prevClass = value ? no : yes; | ||
var newClass = value ? yes : no; | ||
getMatches(el, selector).forEach(function (match) { | ||
var prevClass = value ? no : yes; | ||
var newClass = value ? yes : no; | ||
dom.switchClass(match, prevClass, newClass); | ||
prevClass.forEach(function (pc) { | ||
dom.removeClass(match, pc); | ||
}); | ||
newClass.forEach(function (nc) { | ||
dom.addClass(match, nc); | ||
}); | ||
}); | ||
@@ -106,5 +119,7 @@ }; | ||
return function (el, value, keyName) { | ||
var name = binding.name || keyName; | ||
var name = makeArray(binding.name || keyName); | ||
getMatches(el, selector).forEach(function (match) { | ||
dom[value ? 'addClass' : 'removeClass'](match, name); | ||
name.forEach(function (className) { | ||
dom[value ? 'addClass' : 'removeClass'](match, className); | ||
}); | ||
}); | ||
@@ -115,5 +130,7 @@ }; | ||
return function (el, value, keyName) { | ||
var name = binding.name || keyName; | ||
var name = makeArray(binding.name || keyName); | ||
getMatches(el, selector).forEach(function (match) { | ||
dom[value ? 'addAttribute' : 'removeAttribute'](match, name); | ||
name.forEach(function (attr) { | ||
dom[value ? 'addAttribute' : 'removeAttribute'](match, attr); | ||
}); | ||
}); | ||
@@ -120,0 +137,0 @@ }; |
{ | ||
"name": "ampersand-dom-bindings", | ||
"description": "Takes binding declarations and returns key-tree-store of functions that can be used to apply those bindings.", | ||
"version": "2.3.2", | ||
"version": "2.4.0", | ||
"author": "'Henrik Joreteg' <henrik@andyet.net>", | ||
@@ -6,0 +6,0 @@ "bugs": { |
@@ -46,3 +46,3 @@ # ampersand-dom-bindings | ||
### attribute | ||
sets the whole attribute to match value of property. treats `undefined`, `null`, and `NaN` as `''` (empty string). | ||
sets the whole attribute to match value of property. treats `undefined`, `null`, and `NaN` as `''` (empty string). `name` can also be an array to set multiple attributes to the same value. | ||
@@ -70,3 +70,3 @@ ```js | ||
add/removes class based on boolean interpretation of property name. | ||
add/removes class based on boolean interpretation of property name. `name`, `yes`, or `no` can also be an array of class names where all the values will be toggled. | ||
@@ -88,3 +88,3 @@ ```js | ||
toggles whole attribute on the element (think `checked`) based on boolean interpretation of property name. | ||
toggles whole attribute on the element (think `checked`) based on boolean interpretation of property name. `name` can also be an array of attribute names where all the values will be toggled. | ||
@@ -163,2 +163,15 @@ ```js | ||
The `attribute`, `booleanAttribute` and `booleanClass` types also accept an array for the `name` property (and `yes`/`no` for `booleanClass`). All the values in the array will be set the same as if each were bound separately. | ||
```js | ||
'model.key': { | ||
// Also works with booleanAttribute and booleanClass | ||
type: 'attribute', | ||
selector: '#avatar', | ||
// Both height and width will be bound to model.key | ||
name: ['height', 'width'] | ||
} | ||
``` | ||
## binding using `role` attribute | ||
@@ -165,0 +178,0 @@ |
@@ -79,2 +79,26 @@ var test = require('tape'); | ||
test('attribute array bindings', function (t) { | ||
var el = getEl('<span class="thing" role="some-role"></span>'); | ||
var bindings = domBindings({ | ||
'model': { | ||
type: 'attribute', | ||
selector: '.thing', | ||
name: ['height', 'width'] | ||
} | ||
}); | ||
t.equal(el.firstChild.getAttribute('height'), null); | ||
t.equal(el.firstChild.getAttribute('width'), null); | ||
bindings.run('model', null, el, '100'); | ||
t.equal(el.firstChild.getAttribute('height'), '100'); | ||
t.equal(el.firstChild.getAttribute('width'), '100'); | ||
bindings.run('model', null, el, '200'); | ||
t.equal(el.firstChild.getAttribute('height'), '200'); | ||
t.equal(el.firstChild.getAttribute('width'), '200'); | ||
t.end(); | ||
}); | ||
test('value bindings', function (t) { | ||
@@ -179,2 +203,60 @@ var input = getEl('<input class="thing" type="text">'); | ||
test('booleanClass array bindings', function (t) { | ||
var el = getEl('<input type="checkbox" class="thing" role="some-role">'); | ||
var bindings = domBindings({ | ||
'model': { | ||
type: 'booleanClass', | ||
selector: '.thing', | ||
name: ['class1', 'class2'] | ||
} | ||
}); | ||
t.notOk(dom.hasClass(el.firstChild, 'class1')); | ||
t.notOk(dom.hasClass(el.firstChild, 'class2')); | ||
bindings.run('', null, el, true); | ||
t.ok(dom.hasClass(el.firstChild, 'class1')); | ||
t.ok(dom.hasClass(el.firstChild, 'class2')); | ||
bindings.run('', null, el, false); | ||
t.notOk(dom.hasClass(el.firstChild, 'class1')); | ||
t.notOk(dom.hasClass(el.firstChild, 'class2')); | ||
t.end(); | ||
}); | ||
test('booleanClass yes/no array bindings', function (t) { | ||
var el = getEl('<input type="checkbox" class="thing" role="some-role">'); | ||
var bindings = domBindings({ | ||
'model': { | ||
type: 'booleanClass', | ||
selector: '.thing', | ||
yes: ['awesome', 'very-awesome', 'super-awesome'], | ||
no: ['not-awesome', 'very-not-awesome'] | ||
} | ||
}); | ||
t.notOk(dom.hasClass(el.firstChild, 'awesome'), 'should not start with yes class'); | ||
t.notOk(dom.hasClass(el.firstChild, 'very-awesome'), 'should not start with no class'); | ||
t.notOk(dom.hasClass(el.firstChild, 'super-awesome'), 'should not start with no class'); | ||
t.notOk(dom.hasClass(el.firstChild, 'not-awesome'), 'should not start with yes class'); | ||
t.notOk(dom.hasClass(el.firstChild, 'very-not-awesome'), 'should not start with no class'); | ||
bindings.run('', null, el, true); | ||
t.ok(dom.hasClass(el.firstChild, 'awesome'), 'should have yes class'); | ||
t.ok(dom.hasClass(el.firstChild, 'very-awesome'), 'should have yes class'); | ||
t.ok(dom.hasClass(el.firstChild, 'super-awesome'), 'should have yes class'); | ||
t.notOk(dom.hasClass(el.firstChild, 'not-awesome'), 'should not have no class'); | ||
t.notOk(dom.hasClass(el.firstChild, 'very-not-awesome'), 'should not have no class'); | ||
bindings.run('', null, el, false); | ||
t.notOk(dom.hasClass(el.firstChild, 'awesome'), 'should not have yes class'); | ||
t.notOk(dom.hasClass(el.firstChild, 'very-awesome'), 'should not have yes class'); | ||
t.notOk(dom.hasClass(el.firstChild, 'super-awesome'), 'should not have yes class'); | ||
t.ok(dom.hasClass(el.firstChild, 'not-awesome'), 'should have no class'); | ||
t.ok(dom.hasClass(el.firstChild, 'very-not-awesome'), 'should have no class'); | ||
t.end(); | ||
}); | ||
test('booleanAttribute bindings', function (t) { | ||
@@ -201,2 +283,26 @@ var el = getEl('<input type="checkbox" class="thing" role="some-role">'); | ||
test('booleanAttribute array bindings', function (t) { | ||
var el = getEl('<input type="checkbox" class="thing" role="some-role">'); | ||
var bindings = domBindings({ | ||
'model': { | ||
type: 'booleanAttribute', | ||
selector: '.thing', | ||
name: ['disabled', 'readOnly'] | ||
} | ||
}); | ||
t.notOk(el.firstChild.disabled, 'should not be disabled to start'); | ||
t.notOk(el.firstChild.readOnly, 'should not be readOnly to start'); | ||
bindings.run('', null, el, true, 'disabled, readOnly'); | ||
t.ok(el.firstChild.disabled, 'should disabled'); | ||
t.ok(el.firstChild.readOnly, 'should readOnly'); | ||
bindings.run('', null, el, false, 'disabled, readOnly'); | ||
t.notOk(el.firstChild.disabled, 'should not be disabled'); | ||
t.notOk(el.firstChild.readOnly, 'should not be readOnly'); | ||
t.end(); | ||
}); | ||
test('innerHTML bindings', function (t) { | ||
@@ -240,5 +346,50 @@ var el = getEl(); | ||
t.end(); | ||
}); | ||
test('ensure commas work in selectors', function (t) { | ||
var el = getEl('<span class="thing"></span><span class="another-thing"></span>'); | ||
var bindings = domBindings({ | ||
'model': { | ||
type: 'class', | ||
selector: '.thing, .another-thing' | ||
} | ||
}); | ||
t.notOk(dom.hasClass(el.firstChild, 'hello')); | ||
t.notOk(dom.hasClass(el.lastChild, 'hello')); | ||
bindings.run('model', null, el, 'hello'); | ||
t.ok(dom.hasClass(el.firstChild, 'hello')); | ||
t.ok(dom.hasClass(el.lastChild, 'hello')); | ||
bindings.run('model', null, el, 'string'); | ||
t.ok(dom.hasClass(el.firstChild, 'string')); | ||
t.ok(dom.hasClass(el.lastChild, 'string')); | ||
t.notOk(dom.hasClass(el.firstChild, 'hello')); | ||
t.notOk(dom.hasClass(el.lastChild, 'hello')); | ||
t.end(); | ||
}); | ||
test('selector will find root *and* children', function (t) { | ||
var el = getEl('<div></div><div></div>'); | ||
var bindings = domBindings({ | ||
'model': { | ||
type: 'class', | ||
selector: 'div' // Root and children are all divs | ||
} | ||
}); | ||
t.notOk(dom.hasClass(el, 'hello')); | ||
t.notOk(dom.hasClass(el.firstChild, 'hello')); | ||
t.notOk(dom.hasClass(el.lastChild, 'hello')); | ||
bindings.run('model', null, el, 'hello'); | ||
t.ok(dom.hasClass(el, 'hello')); | ||
t.ok(dom.hasClass(el.firstChild, 'hello')); | ||
t.ok(dom.hasClass(el.lastChild, 'hello')); | ||
t.end(); | ||
}); | ||
// TODO: tests for toggle | ||
@@ -249,4 +400,1 @@ | ||
// TODO: tests for multiple bindings in one declaration | ||
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
26051
468
259