Permalink
Browse files

merge with upstream

  • Loading branch information...
2 parents cc6a490 + 84134cd commit 104b38e12d188fe913c77635232185955807398d @vendethiel vendethiel committed Mar 1, 2013
Showing with 1,887 additions and 202 deletions.
  1. +15 −0 History.md
  2. +3 −0 Makefile
  3. +227 −167 Readme.md
  4. +4 −2 component.json
  5. +1,338 −0 dom.js
  6. +24 −0 examples/delegation.html
  7. +24 −0 examples/manipulation.html
  8. +22 −0 examples/standalone.html
  9. +115 −27 index.js
  10. +113 −6 test/dom.js
  11. +2 −0 test/index.html
View
15 History.md
@@ -1,4 +1,19 @@
+0.2.0 / 2013-02-23
+==================
+
+ * add event delegation example
+ * add manipulation example
+ * add initial .remove() implementation
+ * add .text(str) tmp implementation
+ * add `.prop()` method
+ * add `.get()` == `.get(0)`
+ * add `.appendTo()`
+ * add `.removeClass(regexp)` support
+ * add `.css(object)` support
+ * change .append() and .prepend() to return new list
+ * change `.attr()` to set attribute for each element
+
0.1.0 / 2013-01-04
==================
View
3 Makefile
@@ -11,4 +11,7 @@ clean:
test:
@mocha-phantomjs -R dot test/index.html
+dom.js:
+ @component build --standalone dom --out . --name dom
+
.PHONY: clean test
View
394 Readme.md
@@ -10,13 +10,22 @@
- [delegate](http://github.com/component/delegate) for event delegation
- [event](http://github.com/component/event) for event binding
- [type](http://github.com/component/type) for type checking
+ - [css](http://github.com/component/css) for style properties
## Installation
+ With [component](https://github.com/component/component):
+
```
$ component install component/dom
```
+## Stand-alone
+
+ This library may be used stand-alone without the component
+ tool, simply add ./dom.js to your application and reference
+ the `dom` global. With all its dependencies dom is ~5kb gzipped.
+
## Example
```js
@@ -29,276 +38,327 @@ dom('li').select(function(el){
## API
- ... not even remotely done, feel free to fork and help ...
+ All occurrances of `list` refer to:
-## API
+ - an element passed
+ - a string of html
+ - a selector string
+ - a node list
+ - an array of nodes
+ - a dom `List` itself
- - [dom(id)](#domid)
- - [dom(html)](#domhtml)
- - [.length()](#length)
- - [.get(i)](#geti)
- - [.at(i)](#ati)
- - [.first()](#first)
- - [.last()](#last)
- - [.addClass(name)](#addclassname)
- - [.removeClass(name)](#removeclassname)
- - [.toggleClass(name)](#toggleclassname)
- - [.hasClass(name)](#hasclassname)
- - [.find(selector)](#findselector)
- - [.empty()](#empty)
- - [.each(fn)](#eachfn)
- - [.forEach(fn)](#foreachfn)
- - [.map(fn)](#mapfn)
- - [.select(fn)](#selectfn)
- - [.filter(fn)](#filterfn)
- - [.css(prop, value)](#cssprop-value)
- - [.css(prop)](#cssprop)
-
-<a name="domid"></a>
-### dom(id)
-should return an element by id.
+### dom(list)
+
+ Return a `List` with the given element(s)
+ via selector, html, arrays, nodelists, etc.
```js
-var list = dom('<ul><li id="one">foo</li><li id="two">bar</li></ul>');
-list = dom('#two', list);
-assert(1 == list.length(), 'expected length of 1');
-assert('bar' == list.get(0).textContent);
+dom('ul li');
+dom(dom('a'));
+dom('<p>Hello</p>');
```
-<a name="domhtml"></a>
-### dom(html)
-should return a dom List of elements.
+### .append(list)
+
+ Append and return `list`:
```js
-var list = dom('<em>Hello</em>');
-assert('Hello' == list.get(0).textContent);
+dom('ul')
+ .append('<li>Tobi</li>')
+ .addClass('user');
```
-<a name="length"></a>
-### .length()
-should return the number of elements.
+### .prepend(list)
+
+ Prepend and return `list`:
```js
-var list = dom('<em>Hello</em>');
-assert(1 == list.length());
+dom('ul')
+ .prepend('<li>Tobi</li>')
+ .addClass('user');
```
-<a name="geti"></a>
-### .get(i)
-should return the element at i.
+### .on(event, fn, [capture])
+
+ Bind `event` handler function:
```js
-var list = dom('<em>Hello</em>');
-assert('Hello' == list.get(0).textContent);
+dom('a.remove').on('click', function(e){
+
+});
```
-<a name="ati"></a>
-### .at(i)
-should return the element at i as a List.
+### .on(event, selector, fn, [capture])
+
+ Bind delegate `event` handler function for `selector`:
```js
-var list = dom('<em>Hello</em>');
-assert('Hello' == list.at(0).get(0).textContent);
+dom('ul li').on('click', 'a.remove', function(e){
+
+});
```
-<a name="first"></a>
-### .first()
-should return the first element in the List.
+### .off(event, fn, [capture])
+
+ Unbind `event` callback `fn`.
```js
-var list = dom('<ul><li>foo</li><li>bar</li></ul>').find('li');
-assert('foo' == list.first().text());
+dom('a.remove').off('click', onremove);
```
-<a name="last"></a>
-### .last()
-should return the last element in the List.
+### .off(event, selector, fn, [capture])
+
+ Unbind delegate `event` callback `fn` with `selector`.
```js
-var list = dom('<ul><li>foo</li><li>bar</li></ul>').find('li');
-assert('bar' == list.last().text());
+dom('ul li').off('click', 'a.remove', onremove);
```
-<a name="addclassname"></a>
-### .addClass(name)
-should add the given class name.
+### .appendTo(list)
+
+ Append elements in the list to `list`
+ and return itself for chaining.
```js
-var list = dom('<em>Hello</em>');
-list.addClass('foo').addClass('bar');
-assert('foo bar' == list.get(0).className);
+dom('<li>Tobi</li>')
+ .appendTo('ul')
+ .addClass('user');
```
-<a name="removeclassname"></a>
-### .removeClass(name)
-should remove the given class name.
+### .attr(name)
+
+ Return value for attribute `name`:
```js
-var list = dom('<em>Hello</em>');
-list.addClass('foo').addClass('bar').removeClass('foo');
-assert('bar' == list.get(0).className);
+var url = dom('img').attr('src');
```
-<a name="toggleclassname"></a>
-### .toggleClass(name)
-should toggle the given class name.
+### .attr(name, val)
+
+ Set attribute `name` to `val`.
```js
-var list = dom('<em>Hello</em>');
+dom('img').attr('src', 'image/of/maru.jpg');
+```
-list.toggleClass('show');
-assert('show' == list.get(0).className);
+### .ATTR()
-list.toggleClass('show');
-assert('' == list.get(0).className);
+ Attribute getters. These are functionally equivalent
+ to `.attr(ATTR)`:
+
+```js
+el.id()
+el.src()
+el.rel()
+el.cols()
+el.rows()
+el.name()
+el.href()
+el.title()
+el.style()
+el.tabindex()
+el.placeholder()
```
-<a name="hasclassname"></a>
-### .hasClass(name)
-should return true when the classname is present.
+### .ATTR(val)
+
+ Attribute setters. These are functionally equivalent
+ to `.attr(ATTR, val)`:
```js
-var list = dom('<em>Hello</em>').addClass('show');
-assert(true === list.hasClass('show'));
+el.id('item-1')
+el.src('some/image.png')
+el.rel('stylesheet')
+el.cols(2)
+el.rows(3)
+el.name('username')
+el.href('http://google.com')
+el.title('Maru the cat')
+el.style('color: white')
+el.tabindex(2)
+el.placeholder('Username')
```
-should return false when the classname is not present.
+### .css(prop)
+
+ Get css property value:
```js
-var list = dom('<em>Hello</em>').addClass('show');
-assert(false === list.hasClass('hide'));
+dom(el).css('width');
```
-<a name="findselector"></a>
-### .find(selector)
-should return descendants matching the selector.
+### .css(prop, val)
+
+ Set css property value:
```js
-var list = dom('<ul><li>foo</li><li>bar</li></ul>');
-list = list.find('li');
-assert(2 == list.length());
+dom(el).css('width', '300px');
```
-<a name="empty"></a>
-### .empty()
-should empty the elements.
+### .css(object)
+
+ Set css property values:
```js
-var list = dom('<div></div>');
-assert('' == list.empty().html());
+dom(el).css({
+ top: 5,
+ left: 10
+});
```
-<a name="eachfn"></a>
-### .each(fn)
-should iterate passing (list, i).
+### .addClass(name)
+
+ Add a class `name` to all elements in the list.
```js
-var list = dom('<ul><li>foo</li><li>bar</li></ul>').find('li');
+dom('img').addClass('loading');
+```
-var indexes = [];
-var values = [];
-var ret = list.each(function(el, i){
- indexes.push(i);
- values.push(el);
-});
+### .removeClass(name)
+
+ Remove class `name` to all elements in the list.
-assert(ret == list, 'should return self for chaining');
-assert(0 == indexes[0]);
-assert(1 == indexes[1]);
-assert(values[0] instanceof dom.List, 'values should be dom lists');
-assert(list.get(0) == values[0].get(0));
-assert(list.get(1) == values[1].get(0));
+```js
+dom('img.loading').removeClass('loading');
```
-<a name="foreachfn"></a>
-### .forEach(fn)
-should iterate passing (el, i).
+### .toggleClass(name, [bool])
+
+ Toggle class `name`, with optional `bool`.
```js
-var list = dom('<ul><li>foo</li><li>bar</li></ul>').find('li');
+dom('img').toggleClass('loading');
+dom('img').toggleClass('loading', image.pending);
+```
-var indexes = [];
-var values = [];
-var ret = list.forEach(function(el, i){
- indexes.push(i);
- values.push(el);
-});
+### .hasClass(name)
+
+ Check if any element in the list has the given class `name`.
-assert(ret == list, 'should return self for chaining');
-assert(0 == indexes[0]);
-assert(1 == indexes[1]);
-assert(!(values[0] instanceof dom.List), 'values should be elements');
-assert(list.get(0) == values[0]);
-assert(list.get(1) == values[1]);
+```js
+dom('img').hasClass('loading');
```
-<a name="mapfn"></a>
-### .map(fn)
-should map passing (list, i).
+### .find(selector)
+
+ Return a list of descendants matching `selector`.
```js
-var list = dom('<ul><li>foo</li><li>bar</li></ul>').find('li');
+dom('.uploads').find('.complete').remove();
+```
+
+### .each(fn)
-var ret = list.map(function(el, i){
- return el.text();
-}).join('|');
+ Iterate elements passing each one as a list, and its index:
-assert('foo|bar' == ret);
+```js
+dom('ul li').each(function(li, i){
+ if (li.hasClass('complete')) {
+ li.remove();
+ }
+});
```
-<a name="selectfn"></a>
-### .select(fn)
-should filter passing (list, i).
+### .empty()
+
+ Empties the elements.
```js
-var list = dom('<ul><li>foo</li><li>bar</li></ul>').find('li');
+var list = dom('<div><a href="/meow.html">cute kitty</a></div>');
+assert('' == list.empty().html());
+```
+
+### .forEach(fn)
+
+ Iterate elements passing each one, and its index:
-var selected = list.select(function(el){
- return el.text() == 'bar';
+```js
+dom('ul li').forEach(function(li, i){
+ if (li.className == 'complete') {
+ li.parentNode.removeChild(li);
+ }
});
+```
-assert(1 == selected.length(), 'invalid length');
-assert(selected.get(0) == list.get(1));
+### .map(fn)
+
+ Return an array with map `fn`, passing each element as a list:
+
+```js
+var hrefs = dom('a').forEach(function(a){
+ return a.attr('href');
+});
```
-<a name="filterfn"></a>
-### .filter(fn)
-should alias .select.
+### .select(fn)
+
+ Filter elements with the given function, passing each element
+ as a list. This method is aliased as `.filter(fn)`.
```js
-assert(dom.List.prototype.filter == dom.List.prototype.select);
+var pending = dom('ul li').select(function(li){
+ return li.hasClass('pending');
+});
```
-<a name="cssprop-value"></a>
-### .css(prop, value)
-should set a style value.
+### .first()
+
+ Return a `List` containing the first element:
```js
-var list = dom('<em>Hello</em>');
-list.css('display', 'none');
-assert('none' == list.get(0).style.display);
+dom('ul li').first().remove();
```
-<a name="cssprop"></a>
-### .css(prop)
-should get a style value.
+### .last()
+
+ Return a `List` containing the last element:
```js
-var list = dom('<em>Hello</em>');
-list.css('display', 'none');
-assert('none' == list.css('display'));
+dom('ul li').last().remove();
```
+### .length()
+
+ Return the number of elements in the list.
+
+### .html()
+
+ Return the inner html.
+
+### .html(str)
+
+ Set the inner html to `str`.
+
+### .text()
+
+ Return the text content.
+
+### .text(str)
+
+ Set text content to `str`.
+
+### .clone()
+
+ Return a cloned list of cloned nodes.
+
+### .get(i)
+
+ Return the `i`th element.
+
+### .at(i)
+
+ Return a `List` containing the `i`th element.
+
## Notes
It is recommended that you do _not_ depend on this library directly
when creating public components, unless you require most or all of
the functionality provided. Otherwise it is preferred that you use
the smaller more specific components.
- This lib will not include _any_ XHR support, that is out of scope,
- this library is for DOM manipulation, traversal, and events only.
+ This lib will not include _any_ XHR support, js animations, promises, or anything
+ else out of scope. This library is for DOM manipulation, traversal, and events only.
-## License
+## License
- MIT
+ MIT
View
6 component.json
@@ -1,6 +1,6 @@
{
"name": "dom",
- "version": "0.1.0",
+ "version": "0.2.0",
"description": "DOM traversal, manipulation and events aggregate library",
"keywords": ["html", "dom", "ui", "jquery"],
"scripts": ["index.js"],
@@ -10,7 +10,9 @@
"component/delegate": "*",
"component/indexof": "*",
"component/domify": "*",
- "component/classes": "*"
+ "component/classes": "*",
+ "component/css": "*",
+ "component/sort": "*"
},
"development": {
"component/assert": "*"
View
1,338 dom.js
@@ -0,0 +1,1338 @@
+;(function(){
+
+
+/**
+ * hasOwnProperty.
+ */
+
+var has = Object.prototype.hasOwnProperty;
+
+/**
+ * Require the given path.
+ *
+ * @param {String} path
+ * @return {Object} exports
+ * @api public
+ */
+
+function require(path, parent, orig) {
+ var resolved = require.resolve(path);
+
+ // lookup failed
+ if (null == resolved) {
+ orig = orig || path;
+ parent = parent || 'root';
+ var err = new Error('Failed to require "' + orig + '" from "' + parent + '"');
+ err.path = orig;
+ err.parent = parent;
+ err.require = true;
+ throw err;
+ }
+
+ var module = require.modules[resolved];
+
+ // perform real require()
+ // by invoking the module's
+ // registered function
+ if (!module.exports) {
+ module.exports = {};
+ module.client = module.component = true;
+ module.call(this, module.exports, require.relative(resolved), module);
+ }
+
+ return module.exports;
+}
+
+/**
+ * Registered modules.
+ */
+
+require.modules = {};
+
+/**
+ * Registered aliases.
+ */
+
+require.aliases = {};
+
+/**
+ * Resolve `path`.
+ *
+ * Lookup:
+ *
+ * - PATH/index.js
+ * - PATH.js
+ * - PATH
+ *
+ * @param {String} path
+ * @return {String} path or null
+ * @api private
+ */
+
+require.resolve = function(path) {
+ if (path.charAt(0) === '/') path = path.slice(1);
+ var index = path + '/index.js';
+
+ var paths = [
+ path,
+ path + '.js',
+ path + '.json',
+ path + '/index.js',
+ path + '/index.json'
+ ];
+
+ for (var i = 0; i < paths.length; i++) {
+ var path = paths[i];
+ if (has.call(require.modules, path)) return path;
+ }
+
+ if (has.call(require.aliases, index)) {
+ return require.aliases[index];
+ }
+};
+
+/**
+ * Normalize `path` relative to the current path.
+ *
+ * @param {String} curr
+ * @param {String} path
+ * @return {String}
+ * @api private
+ */
+
+require.normalize = function(curr, path) {
+ var segs = [];
+
+ if ('.' != path.charAt(0)) return path;
+
+ curr = curr.split('/');
+ path = path.split('/');
+
+ for (var i = 0; i < path.length; ++i) {
+ if ('..' == path[i]) {
+ curr.pop();
+ } else if ('.' != path[i] && '' != path[i]) {
+ segs.push(path[i]);
+ }
+ }
+
+ return curr.concat(segs).join('/');
+};
+
+/**
+ * Register module at `path` with callback `definition`.
+ *
+ * @param {String} path
+ * @param {Function} definition
+ * @api private
+ */
+
+require.register = function(path, definition) {
+ require.modules[path] = definition;
+};
+
+/**
+ * Alias a module definition.
+ *
+ * @param {String} from
+ * @param {String} to
+ * @api private
+ */
+
+require.alias = function(from, to) {
+ if (!has.call(require.modules, from)) {
+ throw new Error('Failed to alias "' + from + '", it does not exist');
+ }
+ require.aliases[to] = from;
+};
+
+/**
+ * Return a require function relative to the `parent` path.
+ *
+ * @param {String} parent
+ * @return {Function}
+ * @api private
+ */
+
+require.relative = function(parent) {
+ var p = require.normalize(parent, '..');
+
+ /**
+ * lastIndexOf helper.
+ */
+
+ function lastIndexOf(arr, obj) {
+ var i = arr.length;
+ while (i--) {
+ if (arr[i] === obj) return i;
+ }
+ return -1;
+ }
+
+ /**
+ * The relative require() itself.
+ */
+
+ function localRequire(path) {
+ var resolved = localRequire.resolve(path);
+ return require(resolved, parent, path);
+ }
+
+ /**
+ * Resolve relative to the parent.
+ */
+
+ localRequire.resolve = function(path) {
+ var c = path.charAt(0);
+ if ('/' == c) return path.slice(1);
+ if ('.' == c) return require.normalize(p, path);
+
+ // resolve deps by returning
+ // the dep in the nearest "deps"
+ // directory
+ var segs = parent.split('/');
+ var i = lastIndexOf(segs, 'deps') + 1;
+ if (!i) i = 0;
+ path = segs.slice(0, i + 1).join('/') + '/deps/' + path;
+ return path;
+ };
+
+ /**
+ * Check if module is defined at `path`.
+ */
+
+ localRequire.exists = function(path) {
+ return has.call(require.modules, localRequire.resolve(path));
+ };
+
+ return localRequire;
+};
+require.register("component-type/index.js", function(exports, require, module){
+
+/**
+ * toString ref.
+ */
+
+var toString = Object.prototype.toString;
+
+/**
+ * Return the type of `val`.
+ *
+ * @param {Mixed} val
+ * @return {String}
+ * @api public
+ */
+
+module.exports = function(val){
+ switch (toString.call(val)) {
+ case '[object Function]': return 'function';
+ case '[object Date]': return 'date';
+ case '[object RegExp]': return 'regexp';
+ case '[object Arguments]': return 'arguments';
+ case '[object Array]': return 'array';
+ case '[object String]': return 'string';
+ }
+
+ if (val === null) return 'null';
+ if (val === undefined) return 'undefined';
+ if (val === Object(val)) return 'object';
+
+ return typeof val;
+};
+
+});
+require.register("component-event/index.js", function(exports, require, module){
+
+/**
+ * Bind `el` event `type` to `fn`.
+ *
+ * @param {Element} el
+ * @param {String} type
+ * @param {Function} fn
+ * @param {Boolean} capture
+ * @return {Function}
+ * @api public
+ */
+
+exports.bind = function(el, type, fn, capture){
+ if (el.addEventListener) {
+ el.addEventListener(type, fn, capture);
+ } else {
+ el.attachEvent('on' + type, fn);
+ }
+ return fn;
+};
+
+/**
+ * Unbind `el` event `type`'s callback `fn`.
+ *
+ * @param {Element} el
+ * @param {String} type
+ * @param {Function} fn
+ * @param {Boolean} capture
+ * @return {Function}
+ * @api public
+ */
+
+exports.unbind = function(el, type, fn, capture){
+ if (el.removeEventListener) {
+ el.removeEventListener(type, fn, capture);
+ } else {
+ el.detachEvent('on' + type, fn);
+ }
+ return fn;
+};
+
+});
+require.register("component-matches-selector/index.js", function(exports, require, module){
+
+/**
+ * Element prototype.
+ */
+
+var proto = Element.prototype;
+
+/**
+ * Vendor function.
+ */
+
+var vendor = proto.matchesSelector
+ || proto.webkitMatchesSelector
+ || proto.mozMatchesSelector
+ || proto.msMatchesSelector
+ || proto.oMatchesSelector;
+
+/**
+ * Expose `match()`.
+ */
+
+module.exports = match;
+
+/**
+ * Match `el` to `selector`.
+ *
+ * @param {Element} el
+ * @param {String} selector
+ * @return {Boolean}
+ * @api public
+ */
+
+function match(el, selector) {
+ if (vendor) return vendor.call(el, selector);
+ var nodes = el.parentNode.querySelectorAll(selector);
+ for (var i = 0; i < nodes.length; ++i) {
+ if (nodes[i] == el) return true;
+ }
+ return false;
+}
+});
+require.register("component-delegate/index.js", function(exports, require, module){
+
+/**
+ * Module dependencies.
+ */
+
+var matches = require('matches-selector')
+ , event = require('event');
+
+/**
+ * Delegate event `type` to `selector`
+ * and invoke `fn(e)`. A callback function
+ * is returned which may be passed to `.unbind()`.
+ *
+ * @param {Element} el
+ * @param {String} selector
+ * @param {String} type
+ * @param {Function} fn
+ * @param {Boolean} capture
+ * @return {Function}
+ * @api public
+ */
+
+exports.bind = function(el, selector, type, fn, capture){
+ return event.bind(el, type, function(e){
+ if (matches(e.target, selector)) fn.call(el, e);
+ }, capture);
+};
+
+/**
+ * Unbind event `type`'s callback `fn`.
+ *
+ * @param {Element} el
+ * @param {String} type
+ * @param {Function} fn
+ * @param {Boolean} capture
+ * @api public
+ */
+
+exports.unbind = function(el, type, fn, capture){
+ event.unbind(el, type, fn, capture);
+};
+
+});
+require.register("component-indexof/index.js", function(exports, require, module){
+
+var indexOf = [].indexOf;
+
+module.exports = function(arr, obj){
+ if (indexOf) return arr.indexOf(obj);
+ for (var i = 0; i < arr.length; ++i) {
+ if (arr[i] === obj) return i;
+ }
+ return -1;
+};
+});
+require.register("component-domify/index.js", function(exports, require, module){
+
+/**
+ * Expose `parse`.
+ */
+
+module.exports = parse;
+
+/**
+ * Wrap map from jquery.
+ */
+
+var map = {
+ option: [1, '<select multiple="multiple">', '</select>'],
+ optgroup: [1, '<select multiple="multiple">', '</select>'],
+ legend: [1, '<fieldset>', '</fieldset>'],
+ thead: [1, '<table>', '</table>'],
+ tbody: [1, '<table>', '</table>'],
+ tfoot: [1, '<table>', '</table>'],
+ colgroup: [1, '<table>', '</table>'],
+ caption: [1, '<table>', '</table>'],
+ tr: [2, '<table><tbody>', '</tbody></table>'],
+ td: [3, '<table><tbody><tr>', '</tr></tbody></table>'],
+ th: [3, '<table><tbody><tr>', '</tr></tbody></table>'],
+ col: [2, '<table><tbody></tbody><colgroup>', '</colgroup></table>'],
+ _default: [0, '', '']
+};
+
+/**
+ * Parse `html` and return the children.
+ *
+ * @param {String} html
+ * @return {Array}
+ * @api private
+ */
+
+function parse(html) {
+ if ('string' != typeof html) throw new TypeError('String expected');
+
+ // tag name
+ var m = /<([\w:]+)/.exec(html);
+ if (!m) throw new Error('No elements were generated.');
+ var tag = m[1];
+
+ // body support
+ if (tag == 'body') {
+ var el = document.createElement('html');
+ el.innerHTML = html;
+ return [el.removeChild(el.lastChild)];
+ }
+
+ // wrap map
+ var wrap = map[tag] || map._default;
+ var depth = wrap[0];
+ var prefix = wrap[1];
+ var suffix = wrap[2];
+ var el = document.createElement('div');
+ el.innerHTML = prefix + html + suffix;
+ while (depth--) el = el.lastChild;
+
+ return orphan(el.children);
+}
+
+/**
+ * Orphan `els` and return an array.
+ *
+ * @param {NodeList} els
+ * @return {Array}
+ * @api private
+ */
+
+function orphan(els) {
+ var ret = [];
+
+ while (els.length) {
+ ret.push(els[0].parentNode.removeChild(els[0]));
+ }
+
+ return ret;
+}
+
+});
+require.register("component-classes/index.js", function(exports, require, module){
+
+/**
+ * Module dependencies.
+ */
+
+var index = require('indexof');
+
+/**
+ * Whitespace regexp.
+ */
+
+var re = /\s+/;
+
+/**
+ * toString reference.
+ */
+
+var toString = Object.prototype.toString;
+
+/**
+ * Wrap `el` in a `ClassList`.
+ *
+ * @param {Element} el
+ * @return {ClassList}
+ * @api public
+ */
+
+module.exports = function(el){
+ return new ClassList(el);
+};
+
+/**
+ * Initialize a new ClassList for `el`.
+ *
+ * @param {Element} el
+ * @api private
+ */
+
+function ClassList(el) {
+ this.el = el;
+ this.list = el.classList;
+}
+
+/**
+ * Add class `name` if not already present.
+ *
+ * @param {String} name
+ * @return {ClassList}
+ * @api public
+ */
+
+ClassList.prototype.add = function(name){
+ // classList
+ if (this.list) {
+ this.list.add(name);
+ return this;
+ }
+
+ // fallback
+ var arr = this.array();
+ var i = index(arr, name);
+ if (!~i) arr.push(name);
+ this.el.className = arr.join(' ');
+ return this;
+};
+
+/**
+ * Remove class `name` when present, or
+ * pass a regular expression to remove
+ * any which match.
+ *
+ * @param {String|RegExp} name
+ * @return {ClassList}
+ * @api public
+ */
+
+ClassList.prototype.remove = function(name){
+ if ('[object RegExp]' == toString.call(name)) {
+ return this.removeMatching(name);
+ }
+
+ // classList
+ if (this.list) {
+ this.list.remove(name);
+ return this;
+ }
+
+ // fallback
+ var arr = this.array();
+ var i = index(arr, name);
+ if (~i) arr.splice(i, 1);
+ this.el.className = arr.join(' ');
+ return this;
+};
+
+/**
+ * Remove all classes matching `re`.
+ *
+ * @param {RegExp} re
+ * @return {ClassList}
+ * @api private
+ */
+
+ClassList.prototype.removeMatching = function(re){
+ var arr = this.array();
+ for (var i = 0; i < arr.length; i++) {
+ if (re.test(arr[i])) {
+ this.remove(arr[i]);
+ }
+ }
+ return this;
+};
+
+/**
+ * Toggle class `name`.
+ *
+ * @param {String} name
+ * @return {ClassList}
+ * @api public
+ */
+
+ClassList.prototype.toggle = function(name){
+ // classList
+ if (this.list) {
+ this.list.toggle(name);
+ return this;
+ }
+
+ // fallback
+ if (this.has(name)) {
+ this.remove(name);
+ } else {
+ this.add(name);
+ }
+ return this;
+};
+
+/**
+ * Return an array of classes.
+ *
+ * @return {Array}
+ * @api public
+ */
+
+ClassList.prototype.array = function(){
+ var arr = this.el.className.split(re);
+ if ('' === arr[0]) arr.pop();
+ return arr;
+};
+
+/**
+ * Check if class `name` is present.
+ *
+ * @param {String} name
+ * @return {ClassList}
+ * @api public
+ */
+
+ClassList.prototype.has =
+ClassList.prototype.contains = function(name){
+ return this.list
+ ? this.list.contains(name)
+ : !! ~index(this.array(), name);
+};
+
+});
+require.register("component-sort/index.js", function(exports, require, module){
+
+/**
+ * Expose `sort`.
+ */
+
+exports = module.exports = sort;
+
+/**
+ * Sort `el`'s children with the given `fn(a, b)`.
+ *
+ * @param {Element} el
+ * @param {Function} fn
+ * @api public
+ */
+
+function sort(el, fn) {
+ var arr = [].slice.call(el.children).sort(fn);
+ el.innerHTML = '';
+ for (var i = 0; i < arr.length; i++) {
+ el.appendChild(arr[i]);
+ }
+};
+
+/**
+ * Sort descending.
+ *
+ * @param {Element} el
+ * @param {Function} fn
+ * @api public
+ */
+
+exports.desc = function(el, fn){
+ sort(el, function(a, b){
+ return ~fn(a, b) + 1;
+ });
+};
+
+});
+require.register("dom/index.js", function(exports, require, module){
+/**
+ * Module dependencies.
+ */
+
+var domify = require('domify')
+ , classes = require('classes')
+ , indexof = require('indexof')
+ , delegate = require('delegate')
+ , events = require('event')
+ , type = require('type')
+
+/**
+ * Attributes supported.
+ */
+
+var attrs = [
+ 'id',
+ 'src',
+ 'rel',
+ 'cols',
+ 'rows',
+ 'name',
+ 'href',
+ 'title',
+ 'style',
+ 'width',
+ 'height',
+ 'tabindex',
+ 'placeholder'
+];
+
+/**
+ * Expose `dom()`.
+ */
+
+exports = module.exports = dom;
+
+/**
+ * Expose supported attrs.
+ */
+
+exports.attrs = attrs;
+
+/**
+ * Return a dom `List` for the given
+ * `html`, selector, or element.
+ *
+ * @param {String|Element|List}
+ * @return {List}
+ * @api public
+ */
+
+function dom(selector, context) {
+ // array
+ if (Array.isArray(selector)) {
+ return new List(selector);
+ }
+
+ // List
+ if (selector instanceof List) {
+ return selector;
+ }
+
+ // node
+ if (selector.nodeName) {
+ return new List([selector]);
+ }
+
+ if ('string' != typeof selector) {
+ throw new TypeError('invalid selector');
+ }
+
+ // html
+ if ('<' == selector.charAt(0)) {
+ return new List([domify(selector)[0]], selector);
+ }
+
+ // selector
+ var ctx = context
+ ? (context.els ? context.els[0] : context)
+ : document;
+
+ return new List(ctx.querySelectorAll(selector), selector);
+}
+
+/**
+ * Expose `List` constructor.
+ */
+
+exports.List = List;
+
+/**
+ * Initialize a new `List` with the
+ * given array-ish of `els` and `selector`
+ * string.
+ *
+ * @param {Mixed} els
+ * @param {String} selector
+ * @api private
+ */
+
+function List(els, selector) {
+ this.els = els || [];
+ this.selector = selector;
+}
+
+/**
+ * Remove elements from the DOM.
+ *
+ * @api public
+ */
+
+List.prototype.remove = function(){
+ for (var i = 0; i < this.els.length; i++) {
+ var el = this.els[i];
+ var parent = el.parentNode;
+ if (parent) parent.removeChild(el);
+ }
+};
+
+/**
+ * Set attribute `name` to `val`, or get attr `name`.
+ *
+ * @param {String} name
+ * @param {String} [val]
+ * @return {String|List} self
+ * @api public
+ */
+
+List.prototype.attr = function(name, val){
+ if (1 == arguments.length) {
+ return this.els[0] && this.els[0].getAttribute(name);
+ }
+
+ return this.forEach(function(el){
+ el.setAttribute(name, val);
+ });
+};
+
+/**
+ * Set property `name` to `val`, or get property `name`.
+ *
+ * @param {String} name
+ * @param {String} [val]
+ * @return {Object|List} self
+ * @api public
+ */
+
+List.prototype.prop = function(name, val){
+ if (1 == arguments.length) {
+ return this.els[0] && this.els[0][name];
+ }
+
+ return this.forEach(function(el){
+ el[name] = val;
+ });
+};
+
+/**
+ * Return a cloned `List` with all elements cloned.
+ *
+ * @return {List}
+ * @api public
+ */
+
+List.prototype.clone = function(){
+ var arr = [];
+ for (var i = 0, len = this.els.length; i < len; ++i) {
+ arr.push(this.els[i].cloneNode(true));
+ }
+ return new List(arr);
+};
+
+/**
+ * Prepend `val`.
+ *
+ * @param {String|Element|List} val
+ * @return {List} new list
+ * @api public
+ */
+
+List.prototype.prepend = function(val){
+ var el = this.els[0];
+ if (!el) return this;
+ val = dom(val);
+ for (var i = 0; i < val.els.length; ++i) {
+ if (el.children.length) {
+ el.insertBefore(val.els[i], el.firstChild);
+ } else {
+ el.appendChild(val.els[i]);
+ }
+ }
+ return val;
+};
+
+/**
+ * Append `val`.
+ *
+ * @param {String|Element|List} val
+ * @return {List} new list
+ * @api public
+ */
+
+List.prototype.append = function(val){
+ var el = this.els[0];
+ if (!el) return this;
+ val = dom(val);
+ for (var i = 0; i < val.els.length; ++i) {
+ el.appendChild(val.els[i]);
+ }
+ return val;
+};
+
+/**
+ * Append self's `el` to `val`
+ *
+ * @param {String|Element|List} val
+ * @return {List} self
+ * @api public
+ */
+
+List.prototype.appendTo = function(val){
+ dom(val).append(this);
+ return this;
+};
+
+/**
+ * Return a `List` containing the element at `i`.
+ *
+ * @param {Number} i
+ * @return {List}
+ * @api public
+ */
+
+List.prototype.at = function(i){
+ return new List([this.els[i]], this.selector);
+};
+
+/**
+ * Return a `List` containing the first element.
+ *
+ * @param {Number} i
+ * @return {List}
+ * @api public
+ */
+
+List.prototype.first = function(){
+ return new List([this.els[0]], this.selector);
+};
+
+/**
+ * Return a `List` containing the last element.
+ *
+ * @param {Number} i
+ * @return {List}
+ * @api public
+ */
+
+List.prototype.last = function(){
+ return new List([this.els[this.els.length - 1]], this.selector);
+};
+
+/**
+ * Return an `Element` at `i`.
+ *
+ * @param {Number} i
+ * @return {Element}
+ * @api public
+ */
+
+List.prototype.get = function(i){
+ return this.els[i || 0];
+};
+
+/**
+ * Return list length.
+ *
+ * @return {Number}
+ * @api public
+ */
+
+List.prototype.length = function(){
+ return this.els.length;
+};
+
+/**
+ * Return element text.
+ *
+ * @param {String} str
+ * @return {String|List}
+ * @api public
+ */
+
+List.prototype.text = function(str){
+ // TODO: real impl
+ if (1 == arguments.length) {
+ this.forEach(function(el){
+ el.textContent = str;
+ });
+ return this;
+ }
+
+ var str = '';
+ for (var i = 0; i < this.els.length; ++i) {
+ str += this.els[i].textContent;
+ }
+ return str;
+};
+
+/**
+ * Return element html.
+ *
+ * @return {String} html
+ * @api public
+ */
+
+List.prototype.html = function(html){
+ if (1 == arguments.length) {
+ this.forEach(function(el){
+ el.innerHTML = html;
+ });
+ }
+ // TODO: real impl
+ return this.els[0] && this.els[0].innerHTML;
+};
+
+/**
+ * Bind to `event` and invoke `fn(e)`. When
+ * a `selector` is given then events are delegated.
+ *
+ * @param {String} event
+ * @param {String} [selector]
+ * @param {Function} fn
+ * @param {Boolean} capture
+ * @return {List}
+ * @api public
+ */
+
+List.prototype.on = function(event, selector, fn, capture){
+ if ('string' == typeof selector) {
+ for (var i = 0; i < this.els.length; ++i) {
+ fn._delegate = delegate.bind(this.els[i], selector, event, fn, capture);
+ }
+ return this;
+ }
+
+ capture = fn;
+ fn = selector;
+
+ for (var i = 0; i < this.els.length; ++i) {
+ events.bind(this.els[i], event, fn, capture);
+ }
+
+ return this;
+};
+
+/**
+ * Unbind to `event` and invoke `fn(e)`. When
+ * a `selector` is given then delegated event
+ * handlers are unbound.
+ *
+ * @param {String} event
+ * @param {String} [selector]
+ * @param {Function} fn
+ * @param {Boolean} capture
+ * @return {List}
+ * @api public
+ */
+
+List.prototype.off = function(event, selector, fn, capture){
+ if ('string' == typeof selector) {
+ for (var i = 0; i < this.els.length; ++i) {
+ // TODO: add selector support back
+ delegate.unbind(this.els[i], event, fn._delegate, capture);
+ }
+ return this;
+ }
+
+ capture = fn;
+ fn = selector;
+
+ for (var i = 0; i < this.els.length; ++i) {
+ events.unbind(this.els[i], event, fn, capture);
+ }
+ return this;
+};
+
+/**
+ * Iterate elements and invoke `fn(list, i)`.
+ *
+ * @param {Function} fn
+ * @return {List} self
+ * @api public
+ */
+
+List.prototype.each = function(fn){
+ for (var i = 0; i < this.els.length; ++i) {
+ fn(new List([this.els[i]], this.selector), i);
+ }
+ return this;
+};
+
+/**
+ * Iterate elements and invoke `fn(el, i)`.
+ *
+ * @param {Function} fn
+ * @return {List} self
+ * @api public
+ */
+
+List.prototype.forEach = function(fn){
+ for (var i = 0; i < this.els.length; ++i) {
+ fn(this.els[i], i);
+ }
+ return this;
+};
+
+/**
+ * Map elements invoking `fn(list, i)`.
+ *
+ * @param {Function} fn
+ * @return {Array}
+ * @api public
+ */
+
+List.prototype.map = function(fn){
+ var arr = [];
+ for (var i = 0; i < this.els.length; ++i) {
+ arr.push(fn(new List([this.els[i]], this.selector), i));
+ }
+ return arr;
+};
+
+/**
+ * Filter elements invoking `fn(list, i)`, returning
+ * a new `List` of elements when a truthy value is returned.
+ *
+ * @param {Function} fn
+ * @return {List}
+ * @api public
+ */
+
+List.prototype.select =
+List.prototype.filter = function(fn){
+ var el;
+ var list = new List([], this.selector);
+ for (var i = 0; i < this.els.length; ++i) {
+ el = this.els[i];
+ if (fn(new List([el], this.selector), i)) list.els.push(el);
+ }
+ return list;
+};
+
+/**
+ * Add the given class `name`.
+ *
+ * @param {String} name
+ * @return {List} self
+ * @api public
+ */
+
+List.prototype.addClass = function(name){
+ var el;
+ for (var i = 0; i < this.els.length; ++i) {
+ el = this.els[i];
+ el._classes = el._classes || classes(el);
+ el._classes.add(name);
+ }
+ return this;
+};
+
+/**
+ * Remove the given class `name`.
+ *
+ * @param {String|RegExp} name
+ * @return {List} self
+ * @api public
+ */
+
+List.prototype.removeClass = function(name){
+ var el;
+
+ if ('regexp' == type(name)) {
+ for (var i = 0; i < this.els.length; ++i) {
+ el = this.els[i];
+ el._classes = el._classes || classes(el);
+ var arr = el._classes.array();
+ for (var j = 0; j < arr.length; j++) {
+ if (name.test(arr[j])) {
+ el._classes.remove(arr[j]);
+ }
+ }
+ }
+ return this;
+ }
+
+ for (var i = 0; i < this.els.length; ++i) {
+ el = this.els[i];
+ el._classes = el._classes || classes(el);
+ el._classes.remove(name);
+ }
+
+ return this;
+};
+
+/**
+ * Toggle the given class `name`,
+ * optionally a `bool` may be given
+ * to indicate that the class should
+ * be added when truthy.
+ *
+ * @param {String} name
+ * @param {Boolean} bool
+ * @return {List} self
+ * @api public
+ */
+
+List.prototype.toggleClass = function(name, bool){
+ var el;
+ var fn = 'toggle';
+
+ // toggle with boolean
+ if (2 == arguments.length) {
+ fn = bool ? 'add' : 'remove';
+ }
+
+ for (var i = 0; i < this.els.length; ++i) {
+ el = this.els[i];
+ el._classes = el._classes || classes(el);
+ el._classes[fn](name);
+ }
+
+ return this;
+};
+
+/**
+ * Check if the given class `name` is present.
+ *
+ * @param {String} name
+ * @return {Boolean}
+ * @api public
+ */
+
+List.prototype.hasClass = function(name){
+ var el;
+ for (var i = 0; i < this.els.length; ++i) {
+ el = this.els[i];
+ el._classes = el._classes || classes(el);
+ if (el._classes.has(name)) return true;
+ }
+ return false;
+};
+
+/**
+ * Set CSS `prop` to `val` or get `prop` value.
+ * Also accepts an object (`prop`: `val`)
+ *
+ * @param {String} prop
+ * @param {Mixed} val
+ * @return {List|String}
+ * @api public
+ */
+
+List.prototype.css = function(prop, val){
+ if (2 == arguments.length) return this.setStyle(prop, val);
+
+ if ('object' == type(prop)) {
+ for (var key in prop) {
+ this.setStyle(key, prop[key]);
+ }
+ return this;
+ }
+
+ return this.getStyle(prop);
+};
+
+/**
+ * Set CSS `prop` to `val`.
+ *
+ * @param {String} prop
+ * @param {Mixed} val
+ * @return {List} self
+ * @api private
+ */
+
+List.prototype.setStyle = function(prop, val){
+ for (var i = 0; i < this.els.length; ++i) {
+ this.els[i].style[prop] = val;
+ }
+ return this;
+};
+
+/**
+ * Get CSS `prop` value.
+ *
+ * @param {String} prop
+ * @return {String}
+ * @api private
+ */
+
+List.prototype.getStyle = function(prop){
+ var el = this.els[0];
+ if (el) return el.style[prop];
+};
+
+/**
+ * Find children matching the given `selector`.
+ *
+ * @param {String} selector
+ * @return {List}
+ * @api public
+ */
+
+List.prototype.find = function(selector){
+ // TODO: real implementation
+ var list = new List([], this.selector);
+ var el, els;
+ for (var i = 0; i < this.els.length; ++i) {
+ el = this.els[i];
+ els = el.querySelectorAll(selector);
+ for (var j = 0; j < els.length; ++j) {
+ list.els.push(els[j]);
+ }
+ }
+ return list;
+};
+
+/**
+ * Attribute accessors.
+ */
+
+attrs.forEach(function(name){
+ List.prototype[name] = function(val){
+ if (0 == arguments.length) return this.attr(name);
+ return this.attr(name, val);
+ };
+});
+
+
+});
+require.alias("component-type/index.js", "dom/deps/type/index.js");
+
+require.alias("component-event/index.js", "dom/deps/event/index.js");
+
+require.alias("component-delegate/index.js", "dom/deps/delegate/index.js");
+require.alias("component-matches-selector/index.js", "component-delegate/deps/matches-selector/index.js");
+
+require.alias("component-event/index.js", "component-delegate/deps/event/index.js");
+
+require.alias("component-indexof/index.js", "dom/deps/indexof/index.js");
+
+require.alias("component-domify/index.js", "dom/deps/domify/index.js");
+
+require.alias("component-classes/index.js", "dom/deps/classes/index.js");
+require.alias("component-indexof/index.js", "component-classes/deps/indexof/index.js");
+
+require.alias("component-sort/index.js", "dom/deps/sort/index.js");
+
+if (typeof exports == "object") {
+ module.exports = require("dom");
+} else if (typeof define == "function" && define.amd) {
+ define(function(){ return require("dom"); });
+} else {
+ window["dom"] = require("dom");
+}})();
View
24 examples/delegation.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <title>dom - event delegation</title>
+</head>
+<body>
+ <ul></ul>
+ <script type="text/javascript" src="../build/build.js"></script>
+ <script>
+ var dom = require('dom');
+
+ var n = 0;
+ setInterval(function(){
+ dom('ul')
+ .append('<li></li>')
+ .html('item ' + ++n + ' <a href="#">x</a>');
+ }, 1500);
+
+ dom('ul').on('click', 'a', function(e){
+ dom(e.target.parentNode).remove();
+ });
+ </script>
+</body>
+</html>
View
24 examples/manipulation.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <title>dom - manipulation</title>
+</head>
+<body>
+ <ul></ul>
+ <button class="add">add item</button>
+ <button class="remove">remove items</button>
+ <script type="text/javascript" src="../build/build.js"></script>
+ <script>
+ var dom = require('dom');
+
+ dom('.add').on('click', function(){
+ var val = prompt('Item:');
+ dom('ul').append('<li></li>').text(val);
+ });
+
+ dom('.remove').on('click', function(){
+ dom('ul li').remove();
+ });
+ </script>
+</body>
+</html>
View
22 examples/standalone.html
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <title>dom - standalone</title>
+</head>
+<body>
+ <ul></ul>
+ <script type="text/javascript" src="../dom.js"></script>
+ <script>
+ var n = 0;
+ setInterval(function(){
+ dom('ul')
+ .append('<li></li>')
+ .html('item ' + ++n + ' <a href="#">x</a>');
+ }, 1500);
+
+ dom('ul').on('click', 'a', function(e){
+ dom(e.target.parentNode).remove();
+ });
+ </script>
+</body>
+</html>
View
142 index.js
@@ -8,6 +8,7 @@ var domify = require('domify')
, delegate = require('delegate')
, events = require('event')
, type = require('type')
+ , css = require('css')
/**
* Attributes supported.
@@ -51,10 +52,6 @@ exports.attrs = attrs;
*/
function dom(selector, context) {
- var ctx = context
- ? (context.els ? context.els[0] : context)
- : document.firstChild;
-
// array
if (Array.isArray(selector)) {
return new List(selector);
@@ -70,15 +67,21 @@ function dom(selector, context) {
return new List([selector]);
}
+ if ('string' != typeof selector) {
+ throw new TypeError('invalid selector');
+ }
+
// html
if ('<' == selector.charAt(0)) {
return new List([domify(selector)[0]], selector);
}
// selector
- if ('string' == typeof selector) {
- return new List(ctx.querySelectorAll(selector), selector);
- }
+ var ctx = context
+ ? (context.els ? context.els[0] : context)
+ : document;
+
+ return new List(ctx.querySelectorAll(selector), selector);
}
/**
@@ -103,6 +106,20 @@ function List(els, selector) {
}
/**
+ * Remove elements from the DOM.
+ *
+ * @api public
+ */
+
+List.prototype.remove = function(){
+ for (var i = 0; i < this.els.length; i++) {
+ var el = this.els[i];
+ var parent = el.parentNode;
+ if (parent) parent.removeChild(el);
+ }
+};
+
+/**
* Set attribute `name` to `val`, or get attr `name`.
*
* @param {String} name
@@ -112,12 +129,32 @@ function List(els, selector) {
*/
List.prototype.attr = function(name, val){
- if (2 == arguments.length) {
- this.els[0].setAttribute(name, val);
- return this;
- } else {
- return this.els[0].getAttribute(name);
+ if (1 == arguments.length) {
+ return this.els[0] && this.els[0].getAttribute(name);
+ }
+
+ return this.forEach(function(el){
+ el.setAttribute(name, val);
+ });
+};
+
+/**
+ * Set property `name` to `val`, or get property `name`.
+ *
+ * @param {String} name
+ * @param {String} [val]
+ * @return {Object|List} self
+ * @api public
+ */
+
+List.prototype.prop = function(name, val){
+ if (1 == arguments.length) {
+ return this.els[0] && this.els[0][name];
}
+
+ return this.forEach(function(el){
+ el[name] = val;
+ });
};
/**
@@ -139,7 +176,7 @@ List.prototype.clone = function(){
* Prepend `val`.
*
* @param {String|Element|List} val
- * @return {List} self
+ * @return {List} new list
* @api public
*/
@@ -154,14 +191,14 @@ List.prototype.prepend = function(val){
el.appendChild(val.els[i]);
}
}
- return this;
+ return val;
};
/**
* Append `val`.
*
* @param {String|Element|List} val
- * @return {List} self
+ * @return {List} new list
* @api public
*/
@@ -172,6 +209,19 @@ List.prototype.append = function(val){
for (var i = 0; i < val.els.length; ++i) {
el.appendChild(val.els[i]);
}
+ return val;
+};
+
+/**
+ * Append self's `el` to `val`
+ *
+ * @param {String|Element|List} val
+ * @return {List} self
+ * @api public
+ */
+
+List.prototype.appendTo = function(val){
+ dom(val).append(this);
return this;
};
@@ -220,7 +270,7 @@ List.prototype.last = function(){
*/
List.prototype.get = function(i){
- return this.els[i];
+ return this.els[i || 0];
};
/**
@@ -237,12 +287,20 @@ List.prototype.length = function(){
/**
* Return element text.
*
- * @return {String}
+ * @param {String} str
+ * @return {String|List}
* @api public
*/
-List.prototype.text = function(){
+List.prototype.text = function(str){
// TODO: real impl
+ if (1 == arguments.length) {
+ this.forEach(function(el){
+ el.textContent = str;
+ });
+ return this;
+ }
+
var str = '';
for (var i = 0; i < this.els.length; ++i) {
str += this.els[i].textContent;
@@ -253,11 +311,16 @@ List.prototype.text = function(){
/**
* Return element html.
*
- * @return {String}
+ * @return {String} html
* @api public
*/
-List.prototype.html = function(){
+List.prototype.html = function(html){
+ if (1 == arguments.length) {
+ this.forEach(function(el){
+ el.innerHTML = html;
+ });
+ }
// TODO: real impl
return this.els[0] && this.els[0].innerHTML;
};
@@ -410,18 +473,34 @@ List.prototype.addClass = function(name){
/**
* Remove the given class `name`.
*
- * @param {String} name
+ * @param {String|RegExp} name
* @return {List} self
* @api public
*/
List.prototype.removeClass = function(name){
var el;
+
+ if ('regexp' == type(name)) {
+ for (var i = 0; i < this.els.length; ++i) {
+ el = this.els[i];
+ el._classes = el._classes || classes(el);
+ var arr = el._classes.array();
+ for (var j = 0; j < arr.length; j++) {
+ if (name.test(arr[j])) {
+ el._classes.remove(arr[j]);
+ }
+ }
+ }
+ return this;
+ }
+
for (var i = 0; i < this.els.length; ++i) {
el = this.els[i];
el._classes = el._classes || classes(el);
el._classes.remove(name);
}
+
return this;
};
@@ -475,6 +554,7 @@ List.prototype.hasClass = function(name){
/**
* Set CSS `prop` to `val` or get `prop` value.
+ * Also accepts an object (`prop`: `val`)
*
* @param {String} prop
* @param {Mixed} val
@@ -483,22 +563,30 @@ List.prototype.hasClass = function(name){
*/
List.prototype.css = function(prop, val){
- if (2 == arguments.length) return this.setStyle(prop, val);
+ if (2 == arguments.length) {
+ var obj = {};
+ obj[prop] = val;
+ return this.setStyle(obj);
+ }
+
+ if ('object' == type(prop)) {
+ return this.setStyle(prop);
+ }
+
return this.getStyle(prop);
};
/**
- * Set CSS `prop` to `val`.
+ * Set CSS `props`.
*
- * @param {String} prop
- * @param {Mixed} val
+ * @param {Object} props
* @return {List} self
* @api private
*/
-List.prototype.setStyle = function(prop, val){
+List.prototype.setStyle = function(props){
for (var i = 0; i < this.els.length; ++i) {
- this.els[i].style[prop] = val;
+ css(this.els[i], props);
}
return this;
};
View
119 test/dom.js
@@ -9,6 +9,7 @@ describe('dom()', function(){
list = dom('#two', list);
assert(1 == list.length(), 'expected length of 1');
assert('bar' == list.get(0).textContent);
+ assert('Hello' == dom('.foo').text())
})
})
@@ -36,9 +37,9 @@ describe('dom()', function(){
})
describe('.prepend()', function(){
- it('should return itself for chaining', function(){
+ it('should return the new list', function(){
var list = dom('<div></div>');
- assert(list == list.prepend('<p></p>'));
+ assert(list != list.prepend('<p></p>'));
})
it('should prepend the element(s)', function(){
@@ -55,9 +56,9 @@ describe('.prepend()', function(){
})
describe('.append()', function(){
- it('should return itself for chaining', function(){
+ it('should return the new list', function(){
var list = dom('<div></div>');
- assert(list == list.append('<p></p>'));
+ assert(list != list.append('<p></p>'));
})
it('should append the element(s)', function(){