[Pkg-javascript-commits] [list.js] 02/06: Imported Upstream version 1.2.0~dfsg1

Alexandre Viau aviau at moszumanska.debian.org
Thu May 19 17:01:56 UTC 2016


This is an automated email from the git hooks/post-receive script.

aviau pushed a commit to branch master
in repository list.js.

commit 9847d255e57b97d46306afb98c7b0c093b23b351
Author: aviau <alexandre at alexandreviau.net>
Date:   Thu May 19 12:54:48 2016 -0400

    Imported Upstream version 1.2.0~dfsg1
---
 .jshintignore               |    1 +
 Gruntfile.js                |  133 ++-
 History.md                  |  124 ++-
 LICENSE                     |   21 +
 README.md                   |   28 +-
 bower.json                  |    3 +-
 component.json              |   44 -
 dist/list.js                | 2072 +++++++++++++++++++-----------------------
 index.js                    |  438 +++++----
 package.json                |   31 +-
 src/add-async.js            |   29 +-
 src/filter.js               |   46 +-
 src/item.js                 |  108 +--
 src/parse.js                |   78 +-
 src/search.js               |  210 +++--
 src/sort.js                 |  169 ++--
 src/templater.js            |  227 +++--
 src/utils/classes.js        |  185 ++++
 src/utils/events.js         |   38 +
 src/utils/extend.js         |   18 +
 src/utils/get-attribute.js  |   26 +
 src/utils/get-by-class.js   |   56 ++
 src/utils/index-of.js       |    9 +
 src/utils/natural-sort.js   |   48 +
 src/utils/to-array.js       |   33 +
 src/utils/to-string.js      |    6 +
 test/fixtures.js            |   98 +-
 test/index.html             |   84 +-
 test/test.add-get-remove.js |  188 ++--
 test/test.buttons.js        |  330 +++----
 test/test.create.js         |  230 +++--
 test/test.defaults.js       |  109 ++-
 test/test.filter.js         |  176 ++--
 test/test.item.js           |  252 +++---
 test/test.off.js            |   62 +-
 test/test.on.js             |  212 ++---
 test/test.parse.js          |  155 +++-
 test/test.re-index.js       |   34 +
 test/test.search-filter.js  |  114 +--
 test/test.search.js         |  228 +++--
 test/test.show.js           |  386 ++++----
 test/test.sort.js           |  608 ++++++-------
 test/test.trigger.js        |   28 +-
 test/usage/amd.html         |   34 +
 test/usage/boba.jpeg        |  Bin 0 -> 3271 bytes
 test/usage/classic.html     |   53 ++
 test/usage/darth.jpeg       |  Bin 0 -> 2109 bytes
 test/usage/leia.jpeg        |  Bin 0 -> 1707 bytes
 test/usage/luke.jpeg        |  Bin 0 -> 2009 bytes
 test/usage/main.js          |    6 +
 test/usage/require.js       | 2083 +++++++++++++++++++++++++++++++++++++++++++
 test/usage/rey.jpeg         |  Bin 0 -> 2281 bytes
 test/usage/style.css        |   87 ++
 53 files changed, 6312 insertions(+), 3426 deletions(-)

diff --git a/.jshintignore b/.jshintignore
new file mode 100644
index 0000000..2b7b69e
--- /dev/null
+++ b/.jshintignore
@@ -0,0 +1 @@
+src/utils/extend.js
diff --git a/Gruntfile.js b/Gruntfile.js
index 4871881..3a28545 100644
--- a/Gruntfile.js
+++ b/Gruntfile.js
@@ -2,87 +2,75 @@ module.exports = function(grunt) {
   "use strict";
 
   grunt.initConfig({
-    pkg: require("./package.json"),
-    watch: {
-      scripts: {
-        files: ['{,*/}*.js', '*.js', 'test/*.html', 'test/*.js'],
-        tasks: ['default'],
-        options: {
-          spawn: false,
-        },
+  pkg: require("./package.json"),
+  watch: {
+    scripts: {
+      files: ['src/*.js', 'src/utils/*.js', '*.js', 'test/*.html', 'test/*.js'],
+      tasks: ['test'],
+      options: {
+        spawn: false,
       },
     },
-    shell: {
-      install: {
-        command: 'component install --dev',
-        options: {
-          stderr: true
-        }
-      },
-      build: {
-        command: 'component build --dev',
-        options: {
-          stderr: true
-        }
-      },
-      standalone: {
-        command: 'component build --standalone List -n list.standalone'
-      },
-      mkdir: {
-        command: 'mkdir -p dist'
-      },
-      move: {
-        command: 'mv build/list.standalone.js dist/list.js'
-      },
-      remove: {
-        command: 'rm -fr build components dist'
+  },
+  shell: {
+    mkdir: {
+      command: 'mkdir -p dist'
+    },
+    build: {
+      command: 'browserify index.js > dist/list.js',
+      options: {
+        stderr: true
       }
     },
-    jshint: {
-      code: {
-        src: ['Gruntfile.js', '*.js', 'src/*.js'],
-        options: {
-          expr: true,
-          multistr: false,
-          globals: {
-            module: true
-          }
-        }
-      },
-      tests: {
-        src: ['test/(*|!mocha).js'],
-        options: {
-          expr: true,
-          multistr: true,
-          globals: {
-            jQuery: true,
-            module: true
-          }
+    remove: {
+      command: 'rm -fr node_modules dist'
+    }
+  },
+  jshint: {
+    code: {
+    src: ['Gruntfile.js', '*.js', 'src/*.js', 'src/utils/*.js'],
+    options: {
+      expr: true,
+      multistr: false,
+      globals: {
+        module: true
         }
       }
     },
-    uglify: {
-      target: {
-        files: {
-          'dist/list.min.js': ['dist/list.js']
+    tests: {
+    src: ['test/(*|!mocha).js'],
+    options: {
+      expr: true,
+      multistr: true,
+      globals: {
+        jQuery: true,
+        module: true
         }
       }
-    },
-    mocha: {
-      cool: {
-        src: [ 'test/index.html' ],
-        options: {
-          run: true,
-          timeout: 10000,
-          bail: false,
-          log: true,
-          reporter: 'Nyan',
-          mocha: {
-            ignoreLeaks: false
-          }
+    }
+  },
+  uglify: {
+    target: {
+      files: {
+        'dist/list.min.js': ['dist/list.js']
+      }
+    }
+  },
+  mocha: {
+    cool: {
+    src: [ 'test/index.html' ],
+    options: {
+      run: true,
+      timeout: 10000,
+      bail: false,
+      log: true,
+      reporter: 'Nyan',
+      mocha: {
+        ignoreLeaks: false
         }
       }
     }
+  }
   });
 
   grunt.loadNpmTasks("grunt-contrib-watch");
@@ -91,11 +79,10 @@ module.exports = function(grunt) {
   grunt.loadNpmTasks('grunt-contrib-jshint');
   grunt.loadNpmTasks('grunt-mocha');
 
-  grunt.registerTask('default', ['jshint:code', 'jshint:tests', 'shell:install', 'shell:build']);
-  grunt.registerTask('dist', ['default', 'shell:standalone', 'shell:mkdir', 'shell:move', 'uglify']);
+  grunt.registerTask('default', ['jshint:code', 'jshint:tests', 'shell:mkdir', 'shell:build']);
+  grunt.registerTask('dist', ['default', 'shell:mkdir', 'shell:build', 'uglify']);
   grunt.registerTask('clean', ['shell:remove']);
-
-  grunt.registerTask('test', ['mocha']);
+  grunt.registerTask('test', ['dist', 'mocha']);
 
   return grunt;
 };
diff --git a/History.md b/History.md
index 83c8652..46eb380 100644
--- a/History.md
+++ b/History.md
@@ -1,43 +1,103 @@
 # Changelog
 
+### TODO
+- Add tests for custom event handlers. 27e2d6fdeee7090eb1342a108013db898fc29b96
+- Regex in search https://github.com/javve/list.js/issues/371
+- Keep original order?
+- Automatically add item in the right place if sort is active
+- How to handle arrays?
+- Implement debouncing in search?
+- Better search https://github.com/javve/list.js/pull/312/files ?
+- Investigate sort button defaults:
+  - https://github.com/javve/list.js/issues/316
+  - https://github.com/javve/list.js/pull/301
+- Improve testability by decoupling things and make it possible to use require('') in tests
+
+### 2016-02-27: 1.2.0
+- **[Misc]** Move form Component to Browserify
+  [See commit →](https://github.com/javve/list.js/commit/58695c93849b78787d9cf78cbf9be20b01cdcc8a)
+- **[Misc]** Add tests to make sure List.js works with require.js
+  [See commit →](https://github.com/javve/list.js/commit/360098a04b87e18afd1b09e293a01a8dc113a01e)
+- **[Misc]** Update all dependencies to latest version
+  [See commit →](https://github.com/javve/list.js/commit/881991cd204a19af5ed3c62c1239c1206fa51e6c)
+- **[Breaking]** set sort order with List.js not sort function.
+  [See commit →](https://github.com/javve/list.js/commit/81d1148489c99b8503e725805c2a6ce2bde47b11)
+- **[Breaking]** set default page size to 10000 instead of 200 (because: page size is confusing for new users)
+  [See commit →](https://github.com/javve/list.js/commit/618565b203b61c34b868a9cb86eea899e75ea4b6)
+- **[Breaking]** Rename list.helpers to list.utils
+  [See commit →](https://github.com/javve/list.js/commit/58695c93849b78787d9cf78cbf9be20b01cdcc8a)
+- **[Feature]** Add support for data attributes and custom attributes ex. links and images. [See docs](http://listjs.com/).
+  [See commit →](https://github.com/javve/list.js/commit/a8e083dc0f642e90b7a3f3cc11b12f9bb353d3a0)
+- **[Feature]** Add toJSON method.
+  [See commit →](https://github.com/javve/list.js/commit/570fd10e65fcf2e0d3d959ca42137625d9fd3b7c)
+- **[Feature]** Add reIndex method that should be called if the html have been changed by something except List.js.
+  [See commit →](https://github.com/javve/list.js/commit/825b2b55d339de2bb78eb41145d56a8b27d3d888)
+- **[Feature]** Add option searchColumns to defined default columns to search in.
+  [See commit →](https://github.com/javve/list.js/commit/b8b74f21f78c17f1c1842480084ffdb58edc26cd)
+- **[Feature]** Support <tr> in options.item
+  [See commit →](https://github.com/javve/list.js/commit/9700858168811b6559983d2cb792014213b817a6)
+- **[Feature]** Make it possble to add event handlers on init `new List('listId', { searchComplete: function(list) {} })`.
+  [See commit →](https://github.com/javve/list.js/commit/b8b74f21f78c17f1c1842480084ffdb58edc26cd)
+- **[Bugfix]** Don't throw error if searching in a empty list.
+  [See commit →](https://github.com/javve/list.js/commit/d805494732922024bb99090fb6521021189861e9)
+- **[Bugfix]** Make it possible to use item.visible() on items not yet templated.
+  [See commit →](https://github.com/javve/list.js/commit/8e898b0e55a7d47a77ee27f109602bdb63183fda)
+- **[Bugfix]** Include reference to List when initializing plugins. Fix for require.js which don't have a global reference to List.
+  [See commit →](https://github.com/javve/list.js/commit/40d3c5e5f98cf3bcb9624a5717d4435a0b6f49f6)
+- **[Bugfix]** Fix index async. Fix #268
+  [See commit →](https://github.com/javve/list.js/commit/27e2d6fdeee7090eb1342a108013db898fc29b96)
+- **[Bugfix]** Fix add async
+  [See commit →](https://github.com/javve/list.js/commit/237f926d3ea0036ffb8b255dd0da42387b6a653a)
+- **[Bugfix]** Don't add empty item if empty list is initated with empty array.
+  [See commit →](https://github.com/javve/list.js/commit/607a176c12b2219fb5204a789cd44ef367a0025f)
+- **[Bugfix]** Make sort case insensitive by default for the automatic buttons
+  [See commit →](https://github.com/javve/list.js/commit/44260b862f74dccd248d08ca1f7df2b422c8f439)
+- **[Bugfix]** Clear all values from source item. Case: list.add({}) should not
+  get same values as first item in list
+  [See commit →](https://github.com/javve/list.js/commit/3a4733d52cff25ef99ee8a1326c0b54be81d64ca)
+
+
 ### 2014-02-03: 1.1.1
-- *[Bugfix]* Update `javve/events` version which fixes critical bugs in Safari for PC and PhantomJS (which makes the command line tests work again).
-- *[Bugfix]* Clear search when clicking in the HTML5 clear button.
-- *[Misc]* Add History.md file for changelog instead of having it at Listjs.com.
+- **[Bugfix]** Update `javve/events` version which fixes critical bugs in Safari
+  for PC and PhantomJS (which makes the command line tests work again).
+- **[Bugfix]** Clear search when clicking in the HTML5 clear button.
+- **[Misc]** Add History.md file for changelog instead of having it at Listjs.com.
 
 ### 2014-02-03: 1.1.0
-- *[Change]* The sorting API is update so it looks like this `listObj.sort('name', { order: "asc "})` and `listObj.sort('name', { order: "desc "})` instead or `listObj.sort('name', { desc: true/false })`.
-- *[Feature]* Added support for default sort function `new List('id', { sortFunction: function(itemA, itemB) { .. }})</
-- *[Feature]* Adding `data-order="asc/desc"` to a sort button makes that button only sort `asc` or `desc`, ie no to
-- *[Bugfix]* Fix `grunt watch` bug.
-- *[Bugfix]* Remove sorting when searching and filtering.
-- *[Bugfix]* Fix sorting and search when using pagiation plugin
+- **[Breaking]** The sorting API is update so it looks like this
+  `listObj.sort('name', { order: "asc "})` and `listObj.sort('name', { order: "desc "})`
+  instead or `listObj.sort('name', { desc: true/false })`.
+- **[Feature]** Added support for default sort function `new List('id', { sortFunction: function(itemA, itemB) { .. }})`
+- **[Feature]** Adding `data-order="asc/desc"` to a sort button makes that button only sort `asc` or `desc`, ie no to
+- **[Bugfix]** Fix `grunt watch` bug.
+- **[Bugfix]** Remove sorting when searching and filtering.
+- **[Bugfix]** Fix sorting and search when using pagiation plugin
 
 
 ### 2014-01-17: 1.0.2
-- *[Bugfix]* Fix error that broke the lib in IE8.
+- **[Bugfix]** Fix error that broke the lib in IE8.
 
 ### 2013-11-12: 1.0.0
-- *[Feature]* Add more events and enable to add them on initialization.
-- *[Feature]* Add support for Component.js, Bower, RequireJS and CommonJS
-- *[Feature]* Make it possible to remove event handlers by `.off('event', handler)`
-- *[Improvement]* Many new tests
-- *[Improvement]* Paging plugin default classes and structure now correspons to <a href="http://twitter.github.com/bootstrap/components.html#pagination">Twitter Bootstraps pagination</a>.
-- *[Improvement]* Make sorting case-insensitive (thanks @thomasklemm)
-- *[Improvement]* Add item._values for direct access to a items values. Simplifies debugging. Note: Always use item.values() when interacting with the values.
-- *[Bugfix]* `.add(items, callbak)` with `callback` set does no longer add an extra item.
-- *[Bugfix]* `templater.set()` no longer is called twice in a `templater.get()` call.
-- *[Bugfix]* Fix error when trying to sort `undefined,null,etc` values.
-- *[Bugfix]* Fix error when trying to search `undefined,null,etc` values.
-- *[Bugfix]* Fix issue #51, problems with filters/search + paging.
-- *[Misc]* Almost completely rewritten codebase and started using <a href="https://github.com/component/component">Component</a>
-- *[Misc]* Moved the website into another repo called <a href="https://github.com/javve/list-website">list-website</a>
-- *[Misc]* Add documentation for searching in specific columns.
-- *[Change]* `listObj.get('valueName', value)` does now always returns an array. Previously it return an object if only one item matched and null if no match was found.
-- *[Change]* The default sort order is now `asc` instead of `desc`.
-- *[Change]* Syntax for searching in specific columns are now `.search('val', [ 'columnName', 'columnName2' ])` instead of `.search('val', { columnName: true, columnName2: true })`.
-- *[Change]* Move plugins into seperated repos: <a href="https://github.com/javve/list.pagination.js">github.com/javve/list.pagination.js</a> and <a href="https://github.com/javve/list.fuzzysearch.js">github.com/javve/list.fuzzysearch.js</a>
-- *[Change]* Plugin initiation have changed. See <a href="/docs/plugins">getting started with plugins
+- **[Feature]** Add more events and enable to add them on initialization.
+- **[Feature]** Add support for Component.js, Bower, RequireJS and CommonJS
+- **[Feature]** Make it possible to remove event handlers by `.off('event', handler)`
+- **[Improvement]** Many new tests
+- **[Improvement]** Paging plugin default classes and structure now correspons to <a href="http://twitter.github.com/bootstrap/components.html#pagination">Twitter Bootstraps pagination</a>.
+- **[Improvement]** Make sorting case-insensitive (thanks @thomasklemm)
+- **[Improvement]** Add item.\_values for direct access to a items values. Simplifies debugging. Note: Always use item.values() when interacting with the values.
+- **[Bugfix]** `.add(items, callbak)` with `callback` set does no longer add an extra item.
+- **[Bugfix]** `templater.set()` no longer is called twice in a `templater.get()` call.
+- **[Bugfix]** Fix error when trying to sort `undefined,null,etc` values.
+- **[Bugfix]** Fix error when trying to search `undefined,null,etc` values.
+- **[Bugfix]** Fix issue #51, problems with filters/search + paging.
+- **[Misc]** Almost completely rewritten codebase and started using <a href="https://github.com/component/component">Component</a>
+- **[Misc]** Moved the website into another repo called <a href="https://github.com/javve/list-website">list-website</a>
+- **[Misc]** Add documentation for searching in specific columns.
+- **[Change]** `listObj.get('valueName', value)` does now always returns an array. Previously it return an object if only one item matched and null if no match was found.
+- **[Change]** The default sort order is now `asc` instead of `desc`.
+- **[Change]** Syntax for searching in specific columns are now `.search('val', [ 'columnName', 'columnName2' ])` instead of `.search('val', { columnName: true, columnName2: true })`.
+- **[Change]** Move plugins into seperated repos: <a href="https://github.com/javve/list.pagination.js">github.com/javve/list.pagination.js</a> and <a href="https://github.com/javve/list.fuzzysearch.js">github.com/javve/list.fuzzysearch.js</a>
+- **[Change]** Plugin initiation have changed. See <a href="/docs/plugins">getting started with plugins
 
 
 ### 2012-04-24: 0.2.1
@@ -58,8 +118,8 @@
 
 ### 2011-11-16: 0.1.2 release
 - Sorting is now indicated by class `asc` or `desc` at sorting buttons
-- Added three new small helper functions `hasClass(element, class)`, `addClass(element, class)</
-    and `removeClass(element, class)`</li>
+- Added three new small helper functions `hasClass(element, class)`, `addClass(element, class)``
+  and `removeClass(element, class)`</li>
 
 ### 2011-10-20: 0.1.1 release
 - Added possibility to reverse sort the list
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..20b618d
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2011-2014 Jonny Strömberg, jonnystromberg.com
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/README.md b/README.md
index 5122699..9dd0a88 100644
--- a/README.md
+++ b/README.md
@@ -22,6 +22,23 @@ Really simple and easy to use!
 - Plugins [Read more ›](http://listjs.com/docs/plugins)
 - Support for Chrome, Safari, Firefox, IE6+
 
+### Download / Install
+##### Via Bower
+```
+bower install list.js
+```
+##### Via Component
+```
+component install javve/list.js
+```
+##### Via CDNJS
+```
+<script src="//cdnjs.cloudflare.com/ajax/libs/list.js/1.1.1/list.min.js"></script>
+```
+##### Via Direct Download
+- [Compressed list.js](https://raw.githubusercontent.com/javve/list.js/v1.1.1/dist/list.min.js)
+- [Uncompressed list.js](https://raw.githubusercontent.com/javve/list.js/v1.1.1/dist/list.js)
+
 ### Demo / Examples
 - [Existing list](http://listjs.com/examples/existing-list)
 - [Existing list + add](http://listjs.com/examples/existing-list-add)
@@ -29,6 +46,10 @@ Really simple and easy to use!
 - [Add, get, remove](http://listjs.com/examples/add-get-remove)
 - [Fuzzy search](http://listjs.com/examples/fuzzy-search)
 - [Pagination](http://listjs.com/examples/pagination)
+- [Search in specific column](http://codepen.io/javve/pen/GpZpow)
+- [Filter in range](http://codepen.io/javve/pen/wKGKWL)
+- [Show message filter/search results in 0 items](http://codepen.io/javve/pen/VvavzG)
+- [Only show list after search/filter](http://codepen.io/javve/pen/YyqyRg)
 
 ## Documentation
 - [Getting started](http://listjs.com/docs)
@@ -45,8 +66,6 @@ Really simple and easy to use!
 
 ### Known issues
 - Sorting fails with some UTF8 characters. Example: `åä`, thinking that `ä` is before `å`.
-- Tables row items can't be created with the `{ item: '<html>' }`-method.
-
 
 ## Contributors
 * [javve](https://github.com/javve) / [Jonny Strömberg](http://jonnystromberg.com)
@@ -68,6 +87,7 @@ Really simple and easy to use!
 * [jkeyes](https://github.com/jkeyes) / [John Keyes](http://keyes.ie/)
 * [samosad](https://github.com/samosad) / Alexey Tabakman
 * [Page-](https://github.com/Page-)
+* [urkle](https://github.com/urkle) / Edward Rudd
 
 Built with [Component](https://github.com/component/component) which is created by [TJ Holowaychuk](https://github.com/visionmedia).
 
@@ -82,7 +102,5 @@ Built with [Component](https://github.com/component/component) which is created
 
 ## License (MIT)
 
-Copyright (c) 2012 Jonny Strömberg <[jonny.stromberg at gmail.com](jonny.stromberg at gmail.com)>
+Copyright (c) 2012 Jonny Strömberg <[jonny.stromberg at gmail.com](mailto:jonny.stromberg at gmail.com)>
 [http://jonnystromberg.com](http://jonnystromberg.com)
-
-[![Views in the last 24 hours](https://sourcegraph.com/api/repos/github.com/javve/list.js/counters/views-24h.png)](https://sourcegraph.com/github.com/javve/list.js)
diff --git a/bower.json b/bower.json
index 62b7cd7..8794778 100644
--- a/bower.json
+++ b/bower.json
@@ -1,12 +1,11 @@
 {
   "name": "list.js",
   "main": "dist/list.js",
-  "version": "1.1.1",
   "homepage": "http://listjs.com",
   "authors": [
     "Jonny Strömberg <jonny.stromberg at gmail.com>"
   ],
-  "description": "Add search, sort and flexibility to plain HTML lists or tables with cross-browser native JavaScript.",
+  "description": "The perfect library for adding search, sort, filters and flexibility to tables, lists and various HTML elements. Built to be invisible and work on existing HTML",
   "keywords": [
     "list",
     "search",
diff --git a/component.json b/component.json
deleted file mode 100644
index 8ad451f..0000000
--- a/component.json
+++ /dev/null
@@ -1,44 +0,0 @@
-{
-  "name": "list.js",
-  "repo": "javve/list.js",
-  "version": "1.1.1",
-  "description": "Add search, sort and flexibility to plain HTML lists or tables with cross-browser native JavaScript.",
-  "keywords": [
-    "list",
-    "search",
-    "sort",
-    "table",
-    "dom",
-    "html",
-    "ui"
-  ],
-  "scripts": [
-    "index.js",
-    "src/search.js",
-    "src/sort.js",
-    "src/item.js",
-    "src/templater.js",
-    "src/filter.js",
-    "src/add-async.js",
-    "src/parse.js"
-  ],
-  "license": "MIT",
-  "dependencies": {
-    "component/classes": "*",
-    "segmentio/extend": "*",
-    "component/indexof": "*",
-    "javve/events": "*",
-    "javve/get-by-class": "*",
-    "javve/get-attribute": "*",
-    "javve/natural-sort": "*",
-    "javve/to-string": "*",
-    "component/type": "*"
-  },
-  "development": {
-    "visionmedia/mocha": "*",
-    "techjacker/expect.js": "*",
-    "component/jquery": "1.9.1"
-  },
-  "twitter": "javve",
-  "remotes": []
-}
diff --git a/dist/list.js b/dist/list.js
index d8ea7ba..38ddeca 100644
--- a/dist/list.js
+++ b/dist/list.js
@@ -1,211 +1,825 @@
-;(function(){
+(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
+/*
+List.js 1.1.1
+By Jonny Strömberg (www.jonnystromberg.com, www.listjs.com)
+*/
+(function( window, undefined ) {
+"use strict";
 
-/**
- * Require the given path.
- *
- * @param {String} path
- * @return {Object} exports
- * @api public
- */
+var document = window.document,
+  getByClass = require('./src/utils/get-by-class'),
+  extend = require('./src/utils/extend'),
+  indexOf = require('./src/utils/index-of'),
+  events = require('./src/utils/events'),
+  toString = require('./src/utils/to-string'),
+  naturalSort = require('./src/utils/natural-sort'),
+  classes = require('./src/utils/classes'),
+  getAttribute = require('./src/utils/get-attribute'),
+  toArray = require('./src/utils/to-array');
 
-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 List = function(id, options, values) {
 
-  var module = require.modules[resolved];
-
-  // perform real require()
-  // by invoking the module's
-  // registered function
-  if (!module._resolving && !module.exports) {
-    var mod = {};
-    mod.exports = {};
-    mod.client = mod.component = true;
-    module._resolving = true;
-    module.call(this, mod.exports, require.relative(resolved), mod);
-    delete module._resolving;
-    module.exports = mod.exports;
-  }
+  var self = this,
+    init,
+    Item = require('./src/item')(self),
+    addAsync = require('./src/add-async')(self);
+
+  init = {
+    start: function() {
+      self.listClass      = "list";
+      self.searchClass    = "search";
+      self.sortClass      = "sort";
+      self.page           = 10000;
+      self.i              = 1;
+      self.items          = [];
+      self.visibleItems   = [];
+      self.matchingItems  = [];
+      self.searched       = false;
+      self.filtered       = false;
+      self.searchColumns  = undefined;
+      self.handlers       = { 'updated': [] };
+      self.plugins        = {};
+      self.valueNames     = [];
+      self.utils          = {
+        getByClass: getByClass,
+        extend: extend,
+        indexOf: indexOf,
+        events: events,
+        toString: toString,
+        naturalSort: naturalSort,
+        classes: classes,
+        getAttribute: getAttribute,
+        toArray: toArray
+      };
+
+      self.utils.extend(self, options);
+
+      self.listContainer = (typeof(id) === 'string') ? document.getElementById(id) : id;
+      if (!self.listContainer) { return; }
+      self.list       = getByClass(self.listContainer, self.listClass, true);
+
+      self.parse      = require('./src/parse')(self);
+      self.templater  = require('./src/templater')(self);
+      self.search     = require('./src/search')(self);
+      self.filter     = require('./src/filter')(self);
+      self.sort       = require('./src/sort')(self);
+
+      this.handlers();
+      this.items();
+      self.update();
+      this.plugins();
+    },
+    handlers: function() {
+      for (var handler in self.handlers) {
+        if (self[handler]) {
+          self.on(handler, self[handler]);
+        }
+      }
+    },
+    items: function() {
+      self.parse(self.list);
+      if (values !== undefined) {
+        self.add(values);
+      }
+    },
+    plugins: function() {
+      for (var i = 0; i < self.plugins.length; i++) {
+        var plugin = self.plugins[i];
+        self[plugin.name] = plugin;
+        plugin.init(self, List);
+      }
+    }
+  };
 
-  return module.exports;
-}
+  /*
+  * Re-parse the List, use if html have changed
+  */
+  this.reIndex = function() {
+    self.items          = [];
+    self.visibleItems   = [];
+    self.matchingItems  = [];
+    self.searched       = false;
+    self.filtered       = false;
+    self.parse(self.list);
+  };
 
-/**
- * Registered modules.
- */
+  this.toJSON = function() {
+    var json = [];
+    for (var i = 0, il = self.items.length; i < il; i++) {
+      json.push(self.items[i].values());
+    }
+    return json;
+  };
 
-require.modules = {};
 
-/**
- * Registered aliases.
- */
+  /*
+  * Add object to list
+  */
+  this.add = function(values, callback) {
+    if (values.length === 0) {
+      return;
+    }
+    if (callback) {
+      addAsync(values, callback);
+      return;
+    }
+    var added = [],
+      notCreate = false;
+    if (values[0] === undefined){
+      values = [values];
+    }
+    for (var i = 0, il = values.length; i < il; i++) {
+      var item = null;
+      notCreate = (self.items.length > self.page) ? true : false;
+      item = new Item(values[i], undefined, notCreate);
+      self.items.push(item);
+      added.push(item);
+    }
+    self.update();
+    return added;
+  };
 
-require.aliases = {};
+	this.show = function(i, page) {
+		this.i = i;
+		this.page = page;
+		self.update();
+    return self;
+	};
 
-/**
- * Resolve `path`.
- *
- * Lookup:
- *
- *   - PATH/index.js
- *   - PATH.js
- *   - PATH
- *
- * @param {String} path
- * @return {String} path or null
- * @api private
- */
+  /* Removes object from list.
+  * Loops through the list and removes objects where
+  * property "valuename" === value
+  */
+  this.remove = function(valueName, value, options) {
+    var found = 0;
+    for (var i = 0, il = self.items.length; i < il; i++) {
+      if (self.items[i].values()[valueName] == value) {
+        self.templater.remove(self.items[i], options);
+        self.items.splice(i,1);
+        il--;
+        i--;
+        found++;
+      }
+    }
+    self.update();
+    return found;
+  };
 
-require.resolve = function(path) {
-  if (path.charAt(0) === '/') path = path.slice(1);
-
-  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 (require.modules.hasOwnProperty(path)) return path;
-    if (require.aliases.hasOwnProperty(path)) return require.aliases[path];
-  }
+  /* Gets the objects in the list which
+  * property "valueName" === value
+  */
+  this.get = function(valueName, value) {
+    var matchedItems = [];
+    for (var i = 0, il = self.items.length; i < il; i++) {
+      var item = self.items[i];
+      if (item.values()[valueName] == value) {
+        matchedItems.push(item);
+      }
+    }
+    return matchedItems;
+  };
+
+  /*
+  * Get size of the list
+  */
+  this.size = function() {
+    return self.items.length;
+  };
+
+  /*
+  * Removes all items from the list
+  */
+  this.clear = function() {
+    self.templater.clear();
+    self.items = [];
+    return self;
+  };
+
+  this.on = function(event, callback) {
+    self.handlers[event].push(callback);
+    return self;
+  };
+
+  this.off = function(event, callback) {
+    var e = self.handlers[event];
+    var index = indexOf(e, callback);
+    if (index > -1) {
+      e.splice(index, 1);
+    }
+    return self;
+  };
+
+  this.trigger = function(event) {
+    var i = self.handlers[event].length;
+    while(i--) {
+      self.handlers[event][i](self);
+    }
+    return self;
+  };
+
+  this.reset = {
+    filter: function() {
+      var is = self.items,
+        il = is.length;
+      while (il--) {
+        is[il].filtered = false;
+      }
+      return self;
+    },
+    search: function() {
+      var is = self.items,
+        il = is.length;
+      while (il--) {
+        is[il].found = false;
+      }
+      return self;
+    }
+  };
+
+  this.update = function() {
+    var is = self.items,
+			il = is.length;
+
+    self.visibleItems = [];
+    self.matchingItems = [];
+    self.templater.clear();
+    for (var i = 0; i < il; i++) {
+      if (is[i].matching() && ((self.matchingItems.length+1) >= self.i && self.visibleItems.length < self.page)) {
+        is[i].show();
+        self.visibleItems.push(is[i]);
+        self.matchingItems.push(is[i]);
+      } else if (is[i].matching()) {
+        self.matchingItems.push(is[i]);
+        is[i].hide();
+      } else {
+        is[i].hide();
+      }
+    }
+    self.trigger('updated');
+    return self;
+  };
+
+  init.start();
 };
 
-/**
- * Normalize `path` relative to the current path.
- *
- * @param {String} curr
- * @param {String} path
- * @return {String}
- * @api private
- */
 
-require.normalize = function(curr, path) {
-  var segs = [];
+// AMD support
+if (typeof define === 'function' && define.amd) {
+  define(function () { return List; });
+}
+module.exports = List;
+window.List = List;
+
+})(window);
+
+},{"./src/add-async":2,"./src/filter":3,"./src/item":4,"./src/parse":5,"./src/search":6,"./src/sort":7,"./src/templater":8,"./src/utils/classes":9,"./src/utils/events":10,"./src/utils/extend":11,"./src/utils/get-attribute":12,"./src/utils/get-by-class":13,"./src/utils/index-of":14,"./src/utils/natural-sort":15,"./src/utils/to-array":16,"./src/utils/to-string":17}],2:[function(require,module,exports){
+module.exports = function(list) {
+  var addAsync = function(values, callback, items) {
+    var valuesToAdd = values.splice(0, 50);
+    items = items || [];
+    items = items.concat(list.add(valuesToAdd));
+    if (values.length > 0) {
+      setTimeout(function() {
+        addAsync(values, callback, items);
+      }, 1);
+    } else {
+      list.update();
+      callback(items);
+    }
+  };
+  return addAsync;
+};
 
-  if ('.' != path.charAt(0)) return path;
+},{}],3:[function(require,module,exports){
+module.exports = function(list) {
 
-  curr = curr.split('/');
-  path = path.split('/');
+  // Add handlers
+  list.handlers.filterStart = list.handlers.filterStart || [];
+  list.handlers.filterComplete = list.handlers.filterComplete || [];
 
-  for (var i = 0; i < path.length; ++i) {
-    if ('..' == path[i]) {
-      curr.pop();
-    } else if ('.' != path[i] && '' != path[i]) {
-      segs.push(path[i]);
+  return function(filterFunction) {
+    list.trigger('filterStart');
+    list.i = 1; // Reset paging
+    list.reset.filter();
+    if (filterFunction === undefined) {
+      list.filtered = false;
+    } else {
+      list.filtered = true;
+      var is = list.items;
+      for (var i = 0, il = is.length; i < il; i++) {
+        var item = is[i];
+        if (filterFunction(item)) {
+          item.filtered = true;
+        } else {
+          item.filtered = false;
+        }
+      }
     }
-  }
+    list.update();
+    list.trigger('filterComplete');
+    return list.visibleItems;
+  };
+};
+
+},{}],4:[function(require,module,exports){
+module.exports = function(list) {
+  return function(initValues, element, notCreate) {
+    var item = this;
+
+    this._values = {};
+
+    this.found = false; // Show if list.searched == true and this.found == true
+    this.filtered = false;// Show if list.filtered == true and this.filtered == true
+
+    var init = function(initValues, element, notCreate) {
+      if (element === undefined) {
+        if (notCreate) {
+          item.values(initValues, notCreate);
+        } else {
+          item.values(initValues);
+        }
+      } else {
+        item.elm = element;
+        var values = list.templater.get(item, initValues);
+        item.values(values);
+      }
+    };
+
+    this.values = function(newValues, notCreate) {
+      if (newValues !== undefined) {
+        for(var name in newValues) {
+          item._values[name] = newValues[name];
+        }
+        if (notCreate !== true) {
+          list.templater.set(item, item.values());
+        }
+      } else {
+        return item._values;
+      }
+    };
+
+    this.show = function() {
+      list.templater.show(item);
+    };
+
+    this.hide = function() {
+      list.templater.hide(item);
+    };
+
+    this.matching = function() {
+      return (
+        (list.filtered && list.searched && item.found && item.filtered) ||
+        (list.filtered && !list.searched && item.filtered) ||
+        (!list.filtered && list.searched && item.found) ||
+        (!list.filtered && !list.searched)
+      );
+    };
+
+    this.visible = function() {
+      return (item.elm && (item.elm.parentNode == list.list)) ? true : false;
+    };
 
-  return curr.concat(segs).join('/');
+    init(initValues, element, notCreate);
+  };
 };
 
-/**
- * Register module at `path` with callback `definition`.
- *
- * @param {String} path
- * @param {Function} definition
- * @api private
- */
+},{}],5:[function(require,module,exports){
+module.exports = function(list) {
+
+  var Item = require('./item')(list);
 
-require.register = function(path, definition) {
-  require.modules[path] = definition;
+  var getChildren = function(parent) {
+    var nodes = parent.childNodes,
+      items = [];
+    for (var i = 0, il = nodes.length; i < il; i++) {
+      // Only textnodes have a data attribute
+      if (nodes[i].data === undefined) {
+        items.push(nodes[i]);
+      }
+    }
+    return items;
+  };
+
+  var parse = function(itemElements, valueNames) {
+    for (var i = 0, il = itemElements.length; i < il; i++) {
+      list.items.push(new Item(valueNames, itemElements[i]));
+    }
+  };
+  var parseAsync = function(itemElements, valueNames) {
+    var itemsToIndex = itemElements.splice(0, 50); // TODO: If < 100 items, what happens in IE etc?
+    parse(itemsToIndex, valueNames);
+    if (itemElements.length > 0) {
+      setTimeout(function() {
+        parseAsync(itemElements, valueNames);
+      }, 1);
+    } else {
+      list.update();
+      list.trigger('parseComplete');
+    }
+  };
+
+  list.handlers.parseComplete = list.handlers.parseComplete || [];
+
+  return function() {
+    var itemsToIndex = getChildren(list.list),
+      valueNames = list.valueNames;
+
+    if (list.indexAsync) {
+      parseAsync(itemsToIndex, valueNames);
+    } else {
+      parse(itemsToIndex, valueNames);
+    }
+  };
 };
 
-/**
- * Alias a module definition.
- *
- * @param {String} from
- * @param {String} to
- * @api private
- */
+},{"./item":4}],6:[function(require,module,exports){
+module.exports = function(list) {
+  var item,
+    text,
+    columns,
+    searchString,
+    customSearch;
+
+  var prepare = {
+    resetList: function() {
+      list.i = 1;
+      list.templater.clear();
+      customSearch = undefined;
+    },
+    setOptions: function(args) {
+      if (args.length == 2 && args[1] instanceof Array) {
+        columns = args[1];
+      } else if (args.length == 2 && typeof(args[1]) == "function") {
+        customSearch = args[1];
+      } else if (args.length == 3) {
+        columns = args[1];
+        customSearch = args[2];
+      }
+    },
+    setColumns: function() {
+      if (list.items.length === 0) return;
+      if (columns === undefined) {
+        columns = (list.searchColumns === undefined) ? prepare.toArray(list.items[0].values()) : list.searchColumns;
+      }
+    },
+    setSearchString: function(s) {
+      s = list.utils.toString(s).toLowerCase();
+      s = s.replace(/[-[\]{}()*+?.,\\^$|#]/g, "\\$&"); // Escape regular expression characters
+      searchString = s;
+    },
+    toArray: function(values) {
+      var tmpColumn = [];
+      for (var name in values) {
+        tmpColumn.push(name);
+      }
+      return tmpColumn;
+    }
+  };
+  var search = {
+    list: function() {
+      for (var k = 0, kl = list.items.length; k < kl; k++) {
+        search.item(list.items[k]);
+      }
+    },
+    item: function(item) {
+      item.found = false;
+      for (var j = 0, jl = columns.length; j < jl; j++) {
+        if (search.values(item.values(), columns[j])) {
+          item.found = true;
+          return;
+        }
+      }
+    },
+    values: function(values, column) {
+      if (values.hasOwnProperty(column)) {
+        text = list.utils.toString(values[column]).toLowerCase();
+        if ((searchString !== "") && (text.search(searchString) > -1)) {
+          return true;
+        }
+      }
+      return false;
+    },
+    reset: function() {
+      list.reset.search();
+      list.searched = false;
+    }
+  };
 
-require.alias = function(from, to) {
-  if (!require.modules.hasOwnProperty(from)) {
-    throw new Error('Failed to alias "' + from + '", it does not exist');
-  }
-  require.aliases[to] = from;
+  var searchMethod = function(str) {
+    list.trigger('searchStart');
+
+    prepare.resetList();
+    prepare.setSearchString(str);
+    prepare.setOptions(arguments); // str, cols|searchFunction, searchFunction
+    prepare.setColumns();
+
+    if (searchString === "" ) {
+      search.reset();
+    } else {
+      list.searched = true;
+      if (customSearch) {
+        customSearch(searchString, columns);
+      } else {
+        search.list();
+      }
+    }
+
+    list.update();
+    list.trigger('searchComplete');
+    return list.visibleItems;
+  };
+
+  list.handlers.searchStart = list.handlers.searchStart || [];
+  list.handlers.searchComplete = list.handlers.searchComplete || [];
+
+  list.utils.events.bind(list.utils.getByClass(list.listContainer, list.searchClass), 'keyup', function(e) {
+    var target = e.target || e.srcElement, // IE have srcElement
+      alreadyCleared = (target.value === "" && !list.searched);
+    if (!alreadyCleared) { // If oninput already have resetted the list, do nothing
+      searchMethod(target.value);
+    }
+  });
+
+  // Used to detect click on HTML5 clear button
+  list.utils.events.bind(list.utils.getByClass(list.listContainer, list.searchClass), 'input', function(e) {
+    var target = e.target || e.srcElement;
+    if (target.value === "") {
+      searchMethod('');
+    }
+  });
+
+  return searchMethod;
 };
 
-/**
- * Return a require function relative to the `parent` path.
- *
- * @param {String} parent
- * @return {Function}
- * @api private
- */
+},{}],7:[function(require,module,exports){
+module.exports = function(list) {
+  list.sortFunction = list.sortFunction || function(itemA, itemB, options) {
+    options.desc = options.order == "desc" ? true : false; // Natural sort uses this format
+    return list.utils.naturalSort(itemA.values()[options.valueName], itemB.values()[options.valueName], options);
+  };
+
+  var buttons = {
+    els: undefined,
+    clear: function() {
+      for (var i = 0, il = buttons.els.length; i < il; i++) {
+        list.utils.classes(buttons.els[i]).remove('asc');
+        list.utils.classes(buttons.els[i]).remove('desc');
+      }
+    },
+    getOrder: function(btn) {
+      var predefinedOrder = list.utils.getAttribute(btn, 'data-order');
+      if (predefinedOrder == "asc" || predefinedOrder == "desc") {
+        return predefinedOrder;
+      } else if (list.utils.classes(btn).has('desc')) {
+        return "asc";
+      } else if (list.utils.classes(btn).has('asc')) {
+        return "desc";
+      } else {
+        return "asc";
+      }
+    },
+    getInSensitive: function(btn, options) {
+      var insensitive = list.utils.getAttribute(btn, 'data-insensitive');
+      if (insensitive === "false") {
+        options.insensitive = false;
+      } else {
+        options.insensitive = true;
+      }
+    },
+    setOrder: function(options) {
+      for (var i = 0, il = buttons.els.length; i < il; i++) {
+        var btn = buttons.els[i];
+        if (list.utils.getAttribute(btn, 'data-sort') !== options.valueName) {
+          continue;
+        }
+        var predefinedOrder = list.utils.getAttribute(btn, 'data-order');
+        if (predefinedOrder == "asc" || predefinedOrder == "desc") {
+          if (predefinedOrder == options.order) {
+            list.utils.classes(btn).add(options.order);
+          }
+        } else {
+          list.utils.classes(btn).add(options.order);
+        }
+      }
+    }
+  };
+  var sort = function() {
+    list.trigger('sortStart');
+    var options = {};
+
+    var target = arguments[0].currentTarget || arguments[0].srcElement || undefined;
+
+    if (target) {
+      options.valueName = list.utils.getAttribute(target, 'data-sort');
+      buttons.getInSensitive(target, options);
+      options.order = buttons.getOrder(target);
+    } else {
+      options = arguments[1] || options;
+      options.valueName = arguments[0];
+      options.order = options.order || "asc";
+      options.insensitive = (typeof options.insensitive == "undefined") ? true : options.insensitive;
+    }
+    buttons.clear();
+    buttons.setOrder(options);
+
+    options.sortFunction = options.sortFunction || list.sortFunction;
+    list.items.sort(function(a, b) {
+      var mult = (options.order === 'desc') ? -1 : 1;
+      return (options.sortFunction(a, b, options) * mult);
+    });
+    list.update();
+    list.trigger('sortComplete');
+  };
+
+  // Add handlers
+  list.handlers.sortStart = list.handlers.sortStart || [];
+  list.handlers.sortComplete = list.handlers.sortComplete || [];
+
+  buttons.els = list.utils.getByClass(list.listContainer, list.sortClass);
+  list.utils.events.bind(buttons.els, 'click', sort);
+  list.on('searchStart', buttons.clear);
+  list.on('filterStart', buttons.clear);
+
+  return sort;
+};
 
-require.relative = function(parent) {
-  var p = require.normalize(parent, '..');
+},{}],8:[function(require,module,exports){
+var Templater = function(list) {
+  var itemSource,
+    templater = this;
 
-  /**
-   * lastIndexOf helper.
-   */
+  var init = function() {
+    itemSource = templater.getItemSource(list.item);
+    itemSource = templater.clearSourceItem(itemSource, list.valueNames);
+  };
 
-  function lastIndexOf(arr, obj) {
-    var i = arr.length;
-    while (i--) {
-      if (arr[i] === obj) return i;
+  this.clearSourceItem = function(el, valueNames) {
+    for(var i = 0, il = valueNames.length; i < il; i++) {
+      var elm;
+      if (valueNames[i].data) {
+        for (var j = 0, jl = valueNames[i].data.length; j < jl; j++) {
+          el.setAttribute('data-'+valueNames[i].data[j], '');
+        }
+      } else if (valueNames[i].attr && valueNames[i].name) {
+        elm = list.utils.getByClass(el, valueNames[i].name, true);
+        if (elm) {
+          elm.setAttribute(valueNames[i].attr, "");
+        }
+      } else {
+        elm = list.utils.getByClass(el, valueNames[i], true);
+        if (elm) {
+          elm.innerHTML = "";
+        }
+      }
+      elm = undefined;
     }
-    return -1;
-  }
+    return el;
+  };
 
-  /**
-   * The relative require() itself.
-   */
+  this.getItemSource = function(item) {
+    if (item === undefined) {
+      var nodes = list.list.childNodes,
+        items = [];
 
-  function localRequire(path) {
-    var resolved = localRequire.resolve(path);
-    return require(resolved, parent, path);
-  }
+      for (var i = 0, il = nodes.length; i < il; i++) {
+        // Only textnodes have a data attribute
+        if (nodes[i].data === undefined) {
+          return nodes[i].cloneNode(true);
+        }
+      }
+    } else if (/^tr[\s>]/.exec(item)) {
+      var table = document.createElement('table');
+      table.innerHTML = item;
+      return table.firstChild;
+    } else if (item.indexOf("<") !== -1) {
+      var div = document.createElement('div');
+      div.innerHTML = item;
+      return div.firstChild;
+    } else {
+      var source = document.getElementById(list.item);
+      if (source) {
+        return source;
+      }
+    }
+    throw new Error("The list need to have at list one item on init otherwise you'll have to add a template.");
+  };
 
-  /**
-   * 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;
+  this.get = function(item, valueNames) {
+    templater.create(item);
+    var values = {};
+    for(var i = 0, il = valueNames.length; i < il; i++) {
+      var elm;
+      if (valueNames[i].data) {
+        for (var j = 0, jl = valueNames[i].data.length; j < jl; j++) {
+          values[valueNames[i].data[j]] = list.utils.getAttribute(item.elm, 'data-'+valueNames[i].data[j]);
+        }
+      } else if (valueNames[i].attr && valueNames[i].name) {
+        elm = list.utils.getByClass(item.elm, valueNames[i].name, true);
+        values[valueNames[i].name] = elm ? list.utils.getAttribute(elm, valueNames[i].attr) : "";
+      } else {
+        elm = list.utils.getByClass(item.elm, valueNames[i], true);
+        values[valueNames[i]] = elm ? elm.innerHTML : "";
+      }
+      elm = undefined;
+    }
+    return values;
   };
 
-  /**
-   * Check if module is defined at `path`.
-   */
+  this.set = function(item, values) {
+    var getValueName = function(name) {
+      for (var i = 0, il = list.valueNames.length; i < il; i++) {
+        if (list.valueNames[i].data) {
+          var data = list.valueNames[i].data;
+          for (var j = 0, jl = data.length; j < jl; j++) {
+            if (data[j] === name) {
+              return { data: name };
+            }
+          }
+        } else if (list.valueNames[i].attr && list.valueNames[i].name && list.valueNames[i].name == name) {
+          return list.valueNames[i];
+        } else if (list.valueNames[i] === name) {
+          return name;
+        }
+      }
+    };
+    var setValue = function(name, value) {
+      var elm;
+      var valueName = getValueName(name);
+      if (!valueName)
+        return;
+      if (valueName.data) {
+        item.elm.setAttribute('data-'+valueName.data, value);
+      } else if (valueName.attr && valueName.name) {
+        elm = list.utils.getByClass(item.elm, valueName.name, true);
+        if (elm) {
+          elm.setAttribute(valueName.attr, value);
+        }
+      } else {
+        elm = list.utils.getByClass(item.elm, valueName, true);
+        if (elm) {
+          elm.innerHTML = value;
+        }
+      }
+      elm = undefined;
+    };
+    if (!templater.create(item)) {
+      for(var v in values) {
+        if (values.hasOwnProperty(v)) {
+          setValue(v, values[v]);
+        }
+      }
+    }
+  };
 
-  localRequire.exists = function(path) {
-    return require.modules.hasOwnProperty(localRequire.resolve(path));
+  this.create = function(item) {
+    if (item.elm !== undefined) {
+      return false;
+    }
+    /* If item source does not exists, use the first item in list as
+    source for new items */
+    var newItem = itemSource.cloneNode(true);
+    newItem.removeAttribute('id');
+    item.elm = newItem;
+    templater.set(item, item.values());
+    return true;
+  };
+  this.remove = function(item) {
+    if (item.elm.parentNode === list.list) {
+      list.list.removeChild(item.elm);
+    }
+  };
+  this.show = function(item) {
+    templater.create(item);
+    list.list.appendChild(item.elm);
+  };
+  this.hide = function(item) {
+    if (item.elm !== undefined && item.elm.parentNode === list.list) {
+      list.list.removeChild(item.elm);
+    }
+  };
+  this.clear = function() {
+    /* .innerHTML = ''; fucks up IE */
+    if (list.list.hasChildNodes()) {
+      while (list.list.childNodes.length >= 1)
+      {
+        list.list.removeChild(list.list.firstChild);
+      }
+    }
   };
 
-  return localRequire;
+  init();
 };
-require.register("component-classes/index.js", function(exports, require, module){
+
+module.exports = function(list) {
+  return new Templater(list);
+};
+
+},{}],9:[function(require,module,exports){
 /**
  * Module dependencies.
  */
 
-var index = require('indexof');
+var index = require('./index-of');
 
 /**
  * Whitespace regexp.
@@ -239,7 +853,9 @@ module.exports = function(el){
  */
 
 function ClassList(el) {
-  if (!el) throw new Error('A DOM element reference is required');
+  if (!el || !el.nodeType) {
+    throw new Error('A DOM element reference is required');
+  }
   this.el = el;
   this.list = el.classList;
 }
@@ -365,7 +981,8 @@ ClassList.prototype.toggle = function(name, force){
  */
 
 ClassList.prototype.array = function(){
-  var str = this.el.className.replace(/^\s+|\s+$/g, '');
+  var className = this.el.getAttribute('class') || '';
+  var str = className.replace(/^\s+|\s+$/g, '');
   var arr = str.split(re);
   if ('' === arr[0]) arr.shift();
   return arr;
@@ -381,150 +998,102 @@ ClassList.prototype.array = function(){
 
 ClassList.prototype.has =
 ClassList.prototype.contains = function(name){
-  return this.list
-    ? this.list.contains(name)
-    : !! ~index(this.array(), name);
+  return this.list ? this.list.contains(name) : !! ~index(this.array(), name);
 };
 
-});
-require.register("segmentio-extend/index.js", function(exports, require, module){
-
-module.exports = function extend (object) {
-    // Takes an unlimited number of extenders.
-    var args = Array.prototype.slice.call(arguments, 1);
-
-    // For each extender, copy their properties on our object.
-    for (var i = 0, source; source = args[i]; i++) {
-        if (!source) continue;
-        for (var property in source) {
-            object[property] = source[property];
-        }
-    }
-
-    return object;
-};
-});
-require.register("component-indexof/index.js", function(exports, require, module){
-module.exports = function(arr, obj){
-  if (arr.indexOf) return arr.indexOf(obj);
-  for (var i = 0; i < arr.length; ++i) {
-    if (arr[i] === obj) return i;
-  }
-  return -1;
-};
-});
-require.register("component-event/index.js", function(exports, require, module){
-var bind = window.addEventListener ? 'addEventListener' : 'attachEvent',
-    unbind = window.removeEventListener ? 'removeEventListener' : 'detachEvent',
-    prefix = bind !== 'addEventListener' ? 'on' : '';
+},{"./index-of":14}],10:[function(require,module,exports){
+var bind = window.addEventListener ? 'addEventListener' : 'attachEvent',
+    unbind = window.removeEventListener ? 'removeEventListener' : 'detachEvent',
+    prefix = bind !== 'addEventListener' ? 'on' : '',
+    toArray = require('./to-array');
 
 /**
  * Bind `el` event `type` to `fn`.
  *
- * @param {Element} el
+ * @param {Element} el, NodeList, HTMLCollection or Array
  * @param {String} type
  * @param {Function} fn
  * @param {Boolean} capture
- * @return {Function}
  * @api public
  */
 
 exports.bind = function(el, type, fn, capture){
-  el[bind](prefix + type, fn, capture || false);
-  return fn;
+  el = toArray(el);
+  for ( var i = 0; i < el.length; i++ ) {
+    el[i][bind](prefix + type, fn, capture || false);
+  }
 };
 
 /**
  * Unbind `el` event `type`'s callback `fn`.
  *
- * @param {Element} el
+ * @param {Element} el, NodeList, HTMLCollection or Array
  * @param {String} type
  * @param {Function} fn
  * @param {Boolean} capture
- * @return {Function}
  * @api public
  */
 
 exports.unbind = function(el, type, fn, capture){
-  el[unbind](prefix + type, fn, capture || false);
-  return fn;
-};
-});
-require.register("timoxley-to-array/index.js", function(exports, require, module){
-/**
- * Convert an array-like object into an `Array`.
- * If `collection` is already an `Array`, then will return a clone of `collection`.
- *
- * @param {Array | Mixed} collection An `Array` or array-like object to convert e.g. `arguments` or `NodeList`
- * @return {Array} Naive conversion of `collection` to a new `Array`.
- * @api public
- */
-
-module.exports = function toArray(collection) {
-  if (typeof collection === 'undefined') return []
-  if (collection === null) return [null]
-  if (collection === window) return [window]
-  if (typeof collection === 'string') return [collection]
-  if (isArray(collection)) return collection
-  if (typeof collection.length != 'number') return [collection]
-  if (typeof collection === 'function' && collection instanceof Function) return [collection]
-
-  var arr = []
-  for (var i = 0; i < collection.length; i++) {
-    if (Object.prototype.hasOwnProperty.call(collection, i) || i in collection) {
-      arr.push(collection[i])
-    }
+  el = toArray(el);
+  for ( var i = 0; i < el.length; i++ ) {
+    el[i][unbind](prefix + type, fn, capture || false);
   }
-  if (!arr.length) return []
-  return arr
-}
+};
 
-function isArray(arr) {
-  return Object.prototype.toString.call(arr) === "[object Array]";
-}
+},{"./to-array":16}],11:[function(require,module,exports){
+/*
+ * Source: https://github.com/segmentio/extend
+ */
 
-});
-require.register("javve-events/index.js", function(exports, require, module){
-var events = require('event'),
-  toArray = require('to-array');
+module.exports = function extend (object) {
+    // Takes an unlimited number of extenders.
+    var args = Array.prototype.slice.call(arguments, 1);
 
-/**
- * Bind `el` event `type` to `fn`.
- *
- * @param {Element} el, NodeList, HTMLCollection or Array
- * @param {String} type
- * @param {Function} fn
- * @param {Boolean} capture
- * @api public
- */
+    // For each extender, copy their properties on our object.
+    for (var i = 0, source; source = args[i]; i++) {
+        if (!source) continue;
+        for (var property in source) {
+            object[property] = source[property];
+        }
+    }
 
-exports.bind = function(el, type, fn, capture){
-  el = toArray(el);
-  for ( var i = 0; i < el.length; i++ ) {
-    events.bind(el[i], type, fn, capture);
-  }
+    return object;
 };
 
+},{}],12:[function(require,module,exports){
 /**
- * Unbind `el` event `type`'s callback `fn`.
+ * A cross-browser implementation of getAttribute.
+ * Source found here: http://stackoverflow.com/a/3755343/361337 written by Vivin Paliath
  *
- * @param {Element} el, NodeList, HTMLCollection or Array
- * @param {String} type
- * @param {Function} fn
- * @param {Boolean} capture
+ * Return the value for `attr` at `element`.
+ *
+ * @param {Element} el
+ * @param {String} attr
  * @api public
  */
 
-exports.unbind = function(el, type, fn, capture){
-  el = toArray(el);
-  for ( var i = 0; i < el.length; i++ ) {
-    events.unbind(el[i], type, fn, capture);
+module.exports = function(el, attr) {
+  var result = (el.getAttribute && el.getAttribute(attr)) || null;
+  if( !result ) {
+    var attrs = el.attributes;
+    var length = attrs.length;
+    for(var i = 0; i < length; i++) {
+      if (attr[i] !== undefined) {
+        if(attr[i].nodeName === attr) {
+          result = attr[i].nodeValue;
+        }
+      }
+    }
   }
+  return result;
 };
 
-});
-require.register("javve-get-by-class/index.js", function(exports, require, module){
+},{}],13:[function(require,module,exports){
 /**
+ * A cross-browser implementation of getElementsByClass.
+ * Heavily based on Dustin Diaz's function: http://dustindiaz.com/getelementsbyclass.
+ *
  * Find all elements with class `className` inside `container`.
  * Use `single = true` to increase performance in older browsers
  * when only one element is needed.
@@ -557,7 +1126,7 @@ module.exports = (function() {
     return function(container, className, single) {
       var classElements = [],
         tag = '*';
-      if (container == null) {
+      if (container === null) {
         container = document;
       }
       var els = container.getElementsByTagName(tag);
@@ -578,897 +1147,108 @@ module.exports = (function() {
   }
 })();
 
-});
-require.register("javve-get-attribute/index.js", function(exports, require, module){
-/**
- * Return the value for `attr` at `element`.
- *
- * @param {Element} el
- * @param {String} attr
- * @api public
- */
+},{}],14:[function(require,module,exports){
+var indexOf = [].indexOf;
 
-module.exports = function(el, attr) {
-  var result = (el.getAttribute && el.getAttribute(attr)) || null;
-  if( !result ) {
-    var attrs = el.attributes;
-    var length = attrs.length;
-    for(var i = 0; i < length; i++) {
-      if (attr[i] !== undefined) {
-        if(attr[i].nodeName === attr) {
-          result = attr[i].nodeValue;
-        }
-      }
-    }
+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 result;
-}
-});
-require.register("javve-natural-sort/index.js", function(exports, require, module){
+  return -1;
+};
+
+},{}],15:[function(require,module,exports){
 /*
- * Natural Sort algorithm for Javascript - Version 0.7 - Released under MIT license
+ * Natural Sort algorithm for Javascript - Version 0.8 - Released under MIT license
  * Author: Jim Palmer (based on chunking idea from Dave Koelle)
  */
-
-module.exports = function(a, b, options) {
-  var re = /(^-?[0-9]+(\.?[0-9]*)[df]?e?[0-9]?$|^0x[0-9a-f]+$|[0-9]+)/gi,
-    sre = /(^[ ]*|[ ]*$)/g,
-    dre = /(^([\w ]+,?[\w ]+)?[\w ]+,?[\w ]+\d+:\d+(:\d+)?[\w ]?|^\d{1,4}[\/\-]\d{1,4}[\/\-]\d{1,4}|^\w+, \w+ \d+, \d{4})/,
-    hre = /^0x[0-9a-f]+$/i,
-    ore = /^0/,
-    options = options || {},
-    i = function(s) { return options.insensitive && (''+s).toLowerCase() || ''+s },
-    // convert all to strings strip whitespace
-    x = i(a).replace(sre, '') || '',
-    y = i(b).replace(sre, '') || '',
-    // chunk/tokenize
-    xN = x.replace(re, '\0$1\0').replace(/\0$/,'').replace(/^\0/,'').split('\0'),
-    yN = y.replace(re, '\0$1\0').replace(/\0$/,'').replace(/^\0/,'').split('\0'),
-    // numeric, hex or date detection
-    xD = parseInt(x.match(hre)) || (xN.length != 1 && x.match(dre) && Date.parse(x)),
-    yD = parseInt(y.match(hre)) || xD && y.match(dre) && Date.parse(y) || null,
-    oFxNcL, oFyNcL,
-    mult = options.desc ? -1 : 1;
-  // first try and sort Hex codes or Dates
-  if (yD)
-    if ( xD < yD ) return -1 * mult;
-    else if ( xD > yD ) return 1 * mult;
-  // natural sorting through split numeric strings and default strings
-  for(var cLoc=0, numS=Math.max(xN.length, yN.length); cLoc < numS; cLoc++) {
-    // find floats not starting with '0', string or 0 if not defined (Clint Priest)
-    oFxNcL = !(xN[cLoc] || '').match(ore) && parseFloat(xN[cLoc]) || xN[cLoc] || 0;
-    oFyNcL = !(yN[cLoc] || '').match(ore) && parseFloat(yN[cLoc]) || yN[cLoc] || 0;
-    // handle numeric vs string comparison - number < string - (Kyle Adams)
-    if (isNaN(oFxNcL) !== isNaN(oFyNcL)) { return (isNaN(oFxNcL)) ? 1 : -1; }
-    // rely on string comparison if different types - i.e. '02' < 2 != '02' < '2'
-    else if (typeof oFxNcL !== typeof oFyNcL) {
-      oFxNcL += '';
-      oFyNcL += '';
+module.exports = function(a, b, opts) {
+    var re = /(^([+\-]?(?:\d*)(?:\.\d*)?(?:[eE][+\-]?\d+)?)?$|^0x[\da-fA-F]+$|\d+)/g,
+        sre = /^\s+|\s+$/g,   // trim pre-post whitespace
+        snre = /\s+/g,        // normalize all whitespace to single ' ' character
+        dre = /(^([\w ]+,?[\w ]+)?[\w ]+,?[\w ]+\d+:\d+(:\d+)?[\w ]?|^\d{1,4}[\/\-]\d{1,4}[\/\-]\d{1,4}|^\w+, \w+ \d+, \d{4})/,
+        hre = /^0x[0-9a-f]+$/i,
+        ore = /^0/,
+        options = opts || {},
+        i = function(s) { return options.insensitive && (''+s).toLowerCase() || ''+s; },
+        // convert all to strings strip whitespace
+        x = i(a) || '',
+        y = i(b) || '',
+        // chunk/tokenize
+        xN = x.replace(re, '\0$1\0').replace(/\0$/,'').replace(/^\0/,'').split('\0'),
+        yN = y.replace(re, '\0$1\0').replace(/\0$/,'').replace(/^\0/,'').split('\0'),
+        // numeric, hex or date detection
+        xD = parseInt(x.match(hre), 16) || (xN.length !== 1 && Date.parse(x)),
+        yD = parseInt(y.match(hre), 16) || xD && y.match(dre) && Date.parse(y) || null,
+        normChunk = function(s, l) {
+            // normalize spaces; find floats not starting with '0', string or 0 if not defined (Clint Priest)
+            return (!s.match(ore) || l == 1) && parseFloat(s) || s.replace(snre, ' ').replace(sre, '') || 0;
+        },
+        oFxNcL, oFyNcL;
+    // first try and sort Hex codes or Dates
+    if (yD) {
+        if ( xD < yD ) { return -1; }
+        else if ( xD > yD ) { return 1; }
     }
-    if (oFxNcL < oFyNcL) return -1 * mult;
-    if (oFxNcL > oFyNcL) return 1 * mult;
-  }
-  return 0;
-};
-
-/*
-var defaultSort = getSortFunction();
-
-module.exports = function(a, b, options) {
-  if (arguments.length == 1) {
-    options = a;
-    return getSortFunction(options);
-  } else {
-    return defaultSort(a,b);
-  }
-}
-*/
-});
-require.register("javve-to-string/index.js", function(exports, require, module){
-module.exports = function(s) {
-    s = (s === undefined) ? "" : s;
-    s = (s === null) ? "" : s;
-    s = s.toString();
-    return s;
+    // natural sorting through split numeric strings and default strings
+    for(var cLoc=0, xNl = xN.length, yNl = yN.length, numS=Math.max(xNl, yNl); cLoc < numS; cLoc++) {
+        oFxNcL = normChunk(xN[cLoc], xNl);
+        oFyNcL = normChunk(yN[cLoc], yNl);
+        // handle numeric vs string comparison - number < string - (Kyle Adams)
+        if (isNaN(oFxNcL) !== isNaN(oFyNcL)) { return (isNaN(oFxNcL)) ? 1 : -1; }
+        // rely on string comparison if different types - i.e. '02' < 2 != '02' < '2'
+        else if (typeof oFxNcL !== typeof oFyNcL) {
+            oFxNcL += '';
+            oFyNcL += '';
+        }
+        if (oFxNcL < oFyNcL) { return -1; }
+        if (oFxNcL > oFyNcL) { return 1; }
+    }
+    return 0;
 };
 
-});
-require.register("component-type/index.js", function(exports, require, module){
-/**
- * toString ref.
- */
-
-var toString = Object.prototype.toString;
-
+},{}],16:[function(require,module,exports){
 /**
- * Return the type of `val`.
+ * Source: https://github.com/timoxley/to-array
+ *
+ * Convert an array-like object into an `Array`.
+ * If `collection` is already an `Array`, then will return a clone of `collection`.
  *
- * @param {Mixed} val
- * @return {String}
+ * @param {Array | Mixed} collection An `Array` or array-like object to convert e.g. `arguments` or `NodeList`
+ * @return {Array} Naive conversion of `collection` to a new `Array`.
  * @api public
  */
 
-module.exports = function(val){
-  switch (toString.call(val)) {
-    case '[object Date]': return 'date';
-    case '[object RegExp]': return 'regexp';
-    case '[object Arguments]': return 'arguments';
-    case '[object Array]': return 'array';
-    case '[object Error]': return 'error';
-  }
-
-  if (val === null) return 'null';
-  if (val === undefined) return 'undefined';
-  if (val !== val) return 'nan';
-  if (val && val.nodeType === 1) return 'element';
-
-  return typeof val.valueOf();
-};
-
-});
-require.register("list.js/index.js", function(exports, require, module){
-/*
-ListJS with beta 1.0.0
-By Jonny Strömberg (www.jonnystromberg.com, www.listjs.com)
-*/
-(function( window, undefined ) {
-"use strict";
-
-var document = window.document,
-    getByClass = require('get-by-class'),
-    extend = require('extend'),
-    indexOf = require('indexof');
-
-var List = function(id, options, values) {
-
-    var self = this,
-		init,
-        Item = require('./src/item')(self),
-        addAsync = require('./src/add-async')(self),
-        parse = require('./src/parse')(self);
-
-    init = {
-        start: function() {
-            self.listClass      = "list";
-            self.searchClass    = "search";
-            self.sortClass      = "sort";
-            self.page           = 200;
-            self.i              = 1;
-            self.items          = [];
-            self.visibleItems   = [];
-            self.matchingItems  = [];
-            self.searched       = false;
-            self.filtered       = false;
-            self.handlers       = { 'updated': [] };
-            self.plugins        = {};
-            self.helpers        = {
-                getByClass: getByClass,
-                extend: extend,
-                indexOf: indexOf
-            };
-
-            extend(self, options);
-
-            self.listContainer = (typeof(id) === 'string') ? document.getElementById(id) : id;
-            if (!self.listContainer) { return; }
-            self.list           = getByClass(self.listContainer, self.listClass, true);
-
-            self.templater      = require('./src/templater')(self);
-            self.search         = require('./src/search')(self);
-            self.filter         = require('./src/filter')(self);
-            self.sort           = require('./src/sort')(self);
-
-            this.items();
-            self.update();
-            this.plugins();
-        },
-        items: function() {
-            parse(self.list);
-            if (values !== undefined) {
-                self.add(values);
-            }
-        },
-        plugins: function() {
-            for (var i = 0; i < self.plugins.length; i++) {
-                var plugin = self.plugins[i];
-                self[plugin.name] = plugin;
-                plugin.init(self);
-            }
-        }
-    };
-
-
-    /*
-    * Add object to list
-    */
-    this.add = function(values, callback) {
-        if (callback) {
-            addAsync(values, callback);
-            return;
-        }
-        var added = [],
-            notCreate = false;
-        if (values[0] === undefined){
-            values = [values];
-        }
-        for (var i = 0, il = values.length; i < il; i++) {
-            var item = null;
-            if (values[i] instanceof Item) {
-                item = values[i];
-                item.reload();
-            } else {
-                notCreate = (self.items.length > self.page) ? true : false;
-                item = new Item(values[i], undefined, notCreate);
-            }
-            self.items.push(item);
-            added.push(item);
-        }
-        self.update();
-        return added;
-    };
-
-	this.show = function(i, page) {
-		this.i = i;
-		this.page = page;
-		self.update();
-        return self;
-	};
-
-    /* Removes object from list.
-    * Loops through the list and removes objects where
-    * property "valuename" === value
-    */
-    this.remove = function(valueName, value, options) {
-        var found = 0;
-        for (var i = 0, il = self.items.length; i < il; i++) {
-            if (self.items[i].values()[valueName] == value) {
-                self.templater.remove(self.items[i], options);
-                self.items.splice(i,1);
-                il--;
-                i--;
-                found++;
-            }
-        }
-        self.update();
-        return found;
-    };
-
-    /* Gets the objects in the list which
-    * property "valueName" === value
-    */
-    this.get = function(valueName, value) {
-        var matchedItems = [];
-        for (var i = 0, il = self.items.length; i < il; i++) {
-            var item = self.items[i];
-            if (item.values()[valueName] == value) {
-                matchedItems.push(item);
-            }
-        }
-        return matchedItems;
-    };
-
-    /*
-    * Get size of the list
-    */
-    this.size = function() {
-        return self.items.length;
-    };
-
-    /*
-    * Removes all items from the list
-    */
-    this.clear = function() {
-        self.templater.clear();
-        self.items = [];
-        return self;
-    };
-
-    this.on = function(event, callback) {
-        self.handlers[event].push(callback);
-        return self;
-    };
-
-    this.off = function(event, callback) {
-        var e = self.handlers[event];
-        var index = indexOf(e, callback);
-        if (index > -1) {
-            e.splice(index, 1);
-        }
-        return self;
-    };
-
-    this.trigger = function(event) {
-        var i = self.handlers[event].length;
-        while(i--) {
-            self.handlers[event][i](self);
-        }
-        return self;
-    };
-
-    this.reset = {
-        filter: function() {
-            var is = self.items,
-                il = is.length;
-            while (il--) {
-                is[il].filtered = false;
-            }
-            return self;
-        },
-        search: function() {
-            var is = self.items,
-                il = is.length;
-            while (il--) {
-                is[il].found = false;
-            }
-            return self;
-        }
-    };
-
-    this.update = function() {
-        var is = self.items,
-			il = is.length;
-
-        self.visibleItems = [];
-        self.matchingItems = [];
-        self.templater.clear();
-        for (var i = 0; i < il; i++) {
-            if (is[i].matching() && ((self.matchingItems.length+1) >= self.i && self.visibleItems.length < self.page)) {
-                is[i].show();
-                self.visibleItems.push(is[i]);
-                self.matchingItems.push(is[i]);
-			} else if (is[i].matching()) {
-                self.matchingItems.push(is[i]);
-                is[i].hide();
-			} else {
-                is[i].hide();
-			}
-        }
-        self.trigger('updated');
-        return self;
-    };
-
-    init.start();
-};
-
-module.exports = List;
-
-})(window);
-
-});
-require.register("list.js/src/search.js", function(exports, require, module){
-var events = require('events'),
-    getByClass = require('get-by-class'),
-    toString = require('to-string');
-
-module.exports = function(list) {
-    var item,
-        text,
-        columns,
-        searchString,
-        customSearch;
-
-    var prepare = {
-        resetList: function() {
-            list.i = 1;
-            list.templater.clear();
-            customSearch = undefined;
-        },
-        setOptions: function(args) {
-            if (args.length == 2 && args[1] instanceof Array) {
-                columns = args[1];
-            } else if (args.length == 2 && typeof(args[1]) == "function") {
-                customSearch = args[1];
-            } else if (args.length == 3) {
-                columns = args[1];
-                customSearch = args[2];
-            }
-        },
-        setColumns: function() {
-            columns = (columns === undefined) ? prepare.toArray(list.items[0].values()) : columns;
-        },
-        setSearchString: function(s) {
-            s = toString(s).toLowerCase();
-            s = s.replace(/[-[\]{}()*+?.,\\^$|#]/g, "\\$&"); // Escape regular expression characters
-            searchString = s;
-        },
-        toArray: function(values) {
-            var tmpColumn = [];
-            for (var name in values) {
-                tmpColumn.push(name);
-            }
-            return tmpColumn;
-        }
-    };
-    var search = {
-        list: function() {
-            for (var k = 0, kl = list.items.length; k < kl; k++) {
-                search.item(list.items[k]);
-            }
-        },
-        item: function(item) {
-            item.found = false;
-            for (var j = 0, jl = columns.length; j < jl; j++) {
-                if (search.values(item.values(), columns[j])) {
-                    item.found = true;
-                    return;
-                }
-            }
-        },
-        values: function(values, column) {
-            if (values.hasOwnProperty(column)) {
-                text = toString(values[column]).toLowerCase();
-                if ((searchString !== "") && (text.search(searchString) > -1)) {
-                    return true;
-                }
-            }
-            return false;
-        },
-        reset: function() {
-            list.reset.search();
-            list.searched = false;
-        }
-    };
-
-    var searchMethod = function(str) {
-        list.trigger('searchStart');
-
-        prepare.resetList();
-        prepare.setSearchString(str);
-        prepare.setOptions(arguments); // str, cols|searchFunction, searchFunction
-        prepare.setColumns();
-
-        if (searchString === "" ) {
-            search.reset();
-        } else {
-            list.searched = true;
-            if (customSearch) {
-                customSearch(searchString, columns);
-            } else {
-                search.list();
-            }
-        }
-
-        list.update();
-        list.trigger('searchComplete');
-        return list.visibleItems;
-    };
-
-    list.handlers.searchStart = list.handlers.searchStart || [];
-    list.handlers.searchComplete = list.handlers.searchComplete || [];
-
-    events.bind(getByClass(list.listContainer, list.searchClass), 'keyup', function(e) {
-        var target = e.target || e.srcElement, // IE have srcElement
-            alreadyCleared = (target.value === "" && !list.searched);
-        if (!alreadyCleared) { // If oninput already have resetted the list, do nothing
-            searchMethod(target.value);
-        }
-    });
-
-    // Used to detect click on HTML5 clear button
-    events.bind(getByClass(list.listContainer, list.searchClass), 'input', function(e) {
-        var target = e.target || e.srcElement;
-        if (target.value === "") {
-            searchMethod('');
-        }
-    });
-
-    list.helpers.toString = toString;
-    return searchMethod;
-};
-
-});
-require.register("list.js/src/sort.js", function(exports, require, module){
-var naturalSort = require('natural-sort'),
-    classes = require('classes'),
-    events = require('events'),
-    getByClass = require('get-by-class'),
-    getAttribute = require('get-attribute');
-
-module.exports = function(list) {
-    list.sortFunction = list.sortFunction || function(itemA, itemB, options) {
-        options.desc = options.order == "desc" ? true : false; // Natural sort uses this format
-        return naturalSort(itemA.values()[options.valueName], itemB.values()[options.valueName], options);
-    };
-
-    var buttons = {
-        els: undefined,
-        clear: function() {
-            for (var i = 0, il = buttons.els.length; i < il; i++) {
-                classes(buttons.els[i]).remove('asc');
-                classes(buttons.els[i]).remove('desc');
-            }
-        },
-        getOrder: function(btn) {
-            var predefinedOrder = getAttribute(btn, 'data-order');
-            if (predefinedOrder == "asc" || predefinedOrder == "desc") {
-                return predefinedOrder;
-            } else if (classes(btn).has('desc')) {
-                return "asc";
-            } else if (classes(btn).has('asc')) {
-                return "desc";
-            } else {
-                return "asc";
-            }
-        },
-        getInSensitive: function(btn, options) {
-            var insensitive = getAttribute(btn, 'data-insensitive');
-            if (insensitive === "true") {
-                options.insensitive = true;
-            } else {
-                options.insensitive = false;
-            }
-        },
-        setOrder: function(options) {
-            for (var i = 0, il = buttons.els.length; i < il; i++) {
-                var btn = buttons.els[i];
-                if (getAttribute(btn, 'data-sort') !== options.valueName) {
-                    continue;
-                }
-                var predefinedOrder = getAttribute(btn, 'data-order');
-                if (predefinedOrder == "asc" || predefinedOrder == "desc") {
-                    if (predefinedOrder == options.order) {
-                        classes(btn).add(options.order);
-                    }
-                } else {
-                    classes(btn).add(options.order);
-                }
-            }
-        }
-    };
-    var sort = function() {
-        list.trigger('sortStart');
-        options = {};
-
-        var target = arguments[0].currentTarget || arguments[0].srcElement || undefined;
-
-        if (target) {
-            options.valueName = getAttribute(target, 'data-sort');
-            buttons.getInSensitive(target, options);
-            options.order = buttons.getOrder(target);
-        } else {
-            options = arguments[1] || options;
-            options.valueName = arguments[0];
-            options.order = options.order || "asc";
-            options.insensitive = (typeof options.insensitive == "undefined") ? true : options.insensitive;
-        }
-        buttons.clear();
-        buttons.setOrder(options);
-
-        options.sortFunction = options.sortFunction || list.sortFunction;
-        list.items.sort(function(a, b) {
-            return options.sortFunction(a, b, options);
-        });
-        list.update();
-        list.trigger('sortComplete');
-    };
-
-    // Add handlers
-    list.handlers.sortStart = list.handlers.sortStart || [];
-    list.handlers.sortComplete = list.handlers.sortComplete || [];
-
-    buttons.els = getByClass(list.listContainer, list.sortClass);
-    events.bind(buttons.els, 'click', sort);
-    list.on('searchStart', buttons.clear);
-    list.on('filterStart', buttons.clear);
-
-    // Helpers
-    list.helpers.classes = classes;
-    list.helpers.naturalSort = naturalSort;
-    list.helpers.events = events;
-    list.helpers.getAttribute = getAttribute;
-
-    return sort;
-};
-
-});
-require.register("list.js/src/item.js", function(exports, require, module){
-module.exports = function(list) {
-    return function(initValues, element, notCreate) {
-        var item = this;
-
-        this._values = {};
-
-        this.found = false; // Show if list.searched == true and this.found == true
-        this.filtered = false;// Show if list.filtered == true and this.filtered == true
-
-        var init = function(initValues, element, notCreate) {
-            if (element === undefined) {
-                if (notCreate) {
-                    item.values(initValues, notCreate);
-                } else {
-                    item.values(initValues);
-                }
-            } else {
-                item.elm = element;
-                var values = list.templater.get(item, initValues);
-                item.values(values);
-            }
-        };
-        this.values = function(newValues, notCreate) {
-            if (newValues !== undefined) {
-                for(var name in newValues) {
-                    item._values[name] = newValues[name];
-                }
-                if (notCreate !== true) {
-                    list.templater.set(item, item.values());
-                }
-            } else {
-                return item._values;
-            }
-        };
-        this.show = function() {
-            list.templater.show(item);
-        };
-        this.hide = function() {
-            list.templater.hide(item);
-        };
-        this.matching = function() {
-            return (
-                (list.filtered && list.searched && item.found && item.filtered) ||
-                (list.filtered && !list.searched && item.filtered) ||
-                (!list.filtered && list.searched && item.found) ||
-                (!list.filtered && !list.searched)
-            );
-        };
-        this.visible = function() {
-            return (item.elm.parentNode == list.list) ? true : false;
-        };
-        init(initValues, element, notCreate);
-    };
-};
-
-});
-require.register("list.js/src/templater.js", function(exports, require, module){
-var getByClass = require('get-by-class');
-
-var Templater = function(list) {
-    var itemSource = getItemSource(list.item),
-        templater = this;
-
-    function getItemSource(item) {
-        if (item === undefined) {
-            var nodes = list.list.childNodes,
-                items = [];
-
-            for (var i = 0, il = nodes.length; i < il; i++) {
-                // Only textnodes have a data attribute
-                if (nodes[i].data === undefined) {
-                    return nodes[i];
-                }
-            }
-            return null;
-        } else if (item.indexOf("<") !== -1) { // Try create html element of list, do not work for tables!!
-            var div = document.createElement('div');
-            div.innerHTML = item;
-            return div.firstChild;
-        } else {
-            return document.getElementById(list.item);
-        }
+module.exports = function toArray(collection) {
+  if (typeof collection === 'undefined') return [];
+  if (collection === null) return [null];
+  if (collection === window) return [window];
+  if (typeof collection === 'string') return [collection];
+  if (isArray(collection)) return collection;
+  if (typeof collection.length != 'number') return [collection];
+  if (typeof collection === 'function' && collection instanceof Function) return [collection];
+
+  var arr = [];
+  for (var i = 0; i < collection.length; i++) {
+    if (Object.prototype.hasOwnProperty.call(collection, i) || i in collection) {
+      arr.push(collection[i]);
     }
-
-    /* Get values from element */
-    this.get = function(item, valueNames) {
-        templater.create(item);
-        var values = {};
-        for(var i = 0, il = valueNames.length; i < il; i++) {
-            var elm = getByClass(item.elm, valueNames[i], true);
-            values[valueNames[i]] = elm ? elm.innerHTML : "";
-        }
-        return values;
-    };
-
-    /* Sets values at element */
-    this.set = function(item, values) {
-        if (!templater.create(item)) {
-            for(var v in values) {
-                if (values.hasOwnProperty(v)) {
-                    // TODO speed up if possible
-                    var elm = getByClass(item.elm, v, true);
-                    if (elm) {
-                        /* src attribute for image tag & text for other tags */
-                        if (elm.tagName === "IMG" && values[v] !== "") {
-                            elm.src = values[v];
-                        } else {
-                            elm.innerHTML = values[v];
-                        }
-                    }
-                }
-            }
-        }
-    };
-
-    this.create = function(item) {
-        if (item.elm !== undefined) {
-            return false;
-        }
-        /* If item source does not exists, use the first item in list as
-        source for new items */
-        var newItem = itemSource.cloneNode(true);
-        newItem.removeAttribute('id');
-        item.elm = newItem;
-        templater.set(item, item.values());
-        return true;
-    };
-    this.remove = function(item) {
-        list.list.removeChild(item.elm);
-    };
-    this.show = function(item) {
-        templater.create(item);
-        list.list.appendChild(item.elm);
-    };
-    this.hide = function(item) {
-        if (item.elm !== undefined && item.elm.parentNode === list.list) {
-            list.list.removeChild(item.elm);
-        }
-    };
-    this.clear = function() {
-        /* .innerHTML = ''; fucks up IE */
-        if (list.list.hasChildNodes()) {
-            while (list.list.childNodes.length >= 1)
-            {
-                list.list.removeChild(list.list.firstChild);
-            }
-        }
-    };
-};
-
-module.exports = function(list) {
-    return new Templater(list);
-};
-
-});
-require.register("list.js/src/filter.js", function(exports, require, module){
-module.exports = function(list) {
-
-    // Add handlers
-    list.handlers.filterStart = list.handlers.filterStart || [];
-    list.handlers.filterComplete = list.handlers.filterComplete || [];
-
-    return function(filterFunction) {
-        list.trigger('filterStart');
-        list.i = 1; // Reset paging
-        list.reset.filter();
-        if (filterFunction === undefined) {
-            list.filtered = false;
-        } else {
-            list.filtered = true;
-            var is = list.items;
-            for (var i = 0, il = is.length; i < il; i++) {
-                var item = is[i];
-                if (filterFunction(item)) {
-                    item.filtered = true;
-                } else {
-                    item.filtered = false;
-                }
-            }
-        }
-        list.update();
-        list.trigger('filterComplete');
-        return list.visibleItems;
-    };
+  }
+  if (!arr.length) return [];
+  return arr;
 };
 
-});
-require.register("list.js/src/add-async.js", function(exports, require, module){
-module.exports = function(list) {
-    return function(values, callback, items) {
-        var valuesToAdd = values.splice(0, 100);
-        items = items || [];
-        items = items.concat(list.add(valuesToAdd));
-        if (values.length > 0) {
-            setTimeout(function() {
-                addAsync(values, callback, items);
-            }, 10);
-        } else {
-            list.update();
-            callback(items);
-        }
-    };
-};
-});
-require.register("list.js/src/parse.js", function(exports, require, module){
-module.exports = function(list) {
-
-    var Item = require('./item')(list);
-
-    var getChildren = function(parent) {
-        var nodes = parent.childNodes,
-            items = [];
-        for (var i = 0, il = nodes.length; i < il; i++) {
-            // Only textnodes have a data attribute
-            if (nodes[i].data === undefined) {
-                items.push(nodes[i]);
-            }
-        }
-        return items;
-    };
-
-    var parse = function(itemElements, valueNames) {
-        for (var i = 0, il = itemElements.length; i < il; i++) {
-            list.items.push(new Item(valueNames, itemElements[i]));
-        }
-    };
-    var parseAsync = function(itemElements, valueNames) {
-        var itemsToIndex = itemElements.splice(0, 100); // TODO: If < 100 items, what happens in IE etc?
-        parse(itemsToIndex, valueNames);
-        if (itemElements.length > 0) {
-            setTimeout(function() {
-                init.items.indexAsync(itemElements, valueNames);
-            }, 10);
-        } else {
-            list.update();
-            // TODO: Add indexed callback
-        }
-    };
-
-    return function() {
-        var itemsToIndex = getChildren(list.list),
-            valueNames = list.valueNames;
+function isArray(arr) {
+  return Object.prototype.toString.call(arr) === "[object Array]";
+}
 
-        if (list.indexAsync) {
-            parseAsync(itemsToIndex, valueNames);
-        } else {
-            parse(itemsToIndex, valueNames);
-        }
-    };
+},{}],17:[function(require,module,exports){
+module.exports = function(s) {
+  s = (s === undefined) ? "" : s;
+  s = (s === null) ? "" : s;
+  s = s.toString();
+  return s;
 };
 
-});
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-require.alias("component-classes/index.js", "list.js/deps/classes/index.js");
-require.alias("component-classes/index.js", "classes/index.js");
-require.alias("component-indexof/index.js", "component-classes/deps/indexof/index.js");
-
-require.alias("segmentio-extend/index.js", "list.js/deps/extend/index.js");
-require.alias("segmentio-extend/index.js", "extend/index.js");
-
-require.alias("component-indexof/index.js", "list.js/deps/indexof/index.js");
-require.alias("component-indexof/index.js", "indexof/index.js");
-
-require.alias("javve-events/index.js", "list.js/deps/events/index.js");
-require.alias("javve-events/index.js", "events/index.js");
-require.alias("component-event/index.js", "javve-events/deps/event/index.js");
-
-require.alias("timoxley-to-array/index.js", "javve-events/deps/to-array/index.js");
-
-require.alias("javve-get-by-class/index.js", "list.js/deps/get-by-class/index.js");
-require.alias("javve-get-by-class/index.js", "get-by-class/index.js");
-
-require.alias("javve-get-attribute/index.js", "list.js/deps/get-attribute/index.js");
-require.alias("javve-get-attribute/index.js", "get-attribute/index.js");
-
-require.alias("javve-natural-sort/index.js", "list.js/deps/natural-sort/index.js");
-require.alias("javve-natural-sort/index.js", "natural-sort/index.js");
-
-require.alias("javve-to-string/index.js", "list.js/deps/to-string/index.js");
-require.alias("javve-to-string/index.js", "list.js/deps/to-string/index.js");
-require.alias("javve-to-string/index.js", "to-string/index.js");
-require.alias("javve-to-string/index.js", "javve-to-string/index.js");
-require.alias("component-type/index.js", "list.js/deps/type/index.js");
-require.alias("component-type/index.js", "type/index.js");
-if (typeof exports == "object") {
-  module.exports = require("list.js");
-} else if (typeof define == "function" && define.amd) {
-  define(function(){ return require("list.js"); });
-} else {
-  this["List"] = require("list.js");
-}})();
\ No newline at end of file
+},{}]},{},[1]);
diff --git a/index.js b/index.js
index 05d3192..131e03c 100644
--- a/index.js
+++ b/index.js
@@ -1,226 +1,272 @@
 /*
-ListJS with beta 1.0.0
+List.js 1.1.1
 By Jonny Strömberg (www.jonnystromberg.com, www.listjs.com)
 */
 (function( window, undefined ) {
 "use strict";
 
 var document = window.document,
-    getByClass = require('get-by-class'),
-    extend = require('extend'),
-    indexOf = require('indexof');
+  getByClass = require('./src/utils/get-by-class'),
+  extend = require('./src/utils/extend'),
+  indexOf = require('./src/utils/index-of'),
+  events = require('./src/utils/events'),
+  toString = require('./src/utils/to-string'),
+  naturalSort = require('./src/utils/natural-sort'),
+  classes = require('./src/utils/classes'),
+  getAttribute = require('./src/utils/get-attribute'),
+  toArray = require('./src/utils/to-array');
 
 var List = function(id, options, values) {
 
-    var self = this,
-		init,
-        Item = require('./src/item')(self),
-        addAsync = require('./src/add-async')(self),
-        parse = require('./src/parse')(self);
-
-    init = {
-        start: function() {
-            self.listClass      = "list";
-            self.searchClass    = "search";
-            self.sortClass      = "sort";
-            self.page           = 200;
-            self.i              = 1;
-            self.items          = [];
-            self.visibleItems   = [];
-            self.matchingItems  = [];
-            self.searched       = false;
-            self.filtered       = false;
-            self.handlers       = { 'updated': [] };
-            self.plugins        = {};
-            self.helpers        = {
-                getByClass: getByClass,
-                extend: extend,
-                indexOf: indexOf
-            };
-
-            extend(self, options);
-
-            self.listContainer = (typeof(id) === 'string') ? document.getElementById(id) : id;
-            if (!self.listContainer) { return; }
-            self.list           = getByClass(self.listContainer, self.listClass, true);
-
-            self.templater      = require('./src/templater')(self);
-            self.search         = require('./src/search')(self);
-            self.filter         = require('./src/filter')(self);
-            self.sort           = require('./src/sort')(self);
-
-            this.items();
-            self.update();
-            this.plugins();
-        },
-        items: function() {
-            parse(self.list);
-            if (values !== undefined) {
-                self.add(values);
-            }
-        },
-        plugins: function() {
-            for (var i = 0; i < self.plugins.length; i++) {
-                var plugin = self.plugins[i];
-                self[plugin.name] = plugin;
-                plugin.init(self);
-            }
-        }
-    };
+  var self = this,
+    init,
+    Item = require('./src/item')(self),
+    addAsync = require('./src/add-async')(self);
 
+  init = {
+    start: function() {
+      self.listClass      = "list";
+      self.searchClass    = "search";
+      self.sortClass      = "sort";
+      self.page           = 10000;
+      self.i              = 1;
+      self.items          = [];
+      self.visibleItems   = [];
+      self.matchingItems  = [];
+      self.searched       = false;
+      self.filtered       = false;
+      self.searchColumns  = undefined;
+      self.handlers       = { 'updated': [] };
+      self.plugins        = {};
+      self.valueNames     = [];
+      self.utils          = {
+        getByClass: getByClass,
+        extend: extend,
+        indexOf: indexOf,
+        events: events,
+        toString: toString,
+        naturalSort: naturalSort,
+        classes: classes,
+        getAttribute: getAttribute,
+        toArray: toArray
+      };
 
-    /*
-    * Add object to list
-    */
-    this.add = function(values, callback) {
-        if (callback) {
-            addAsync(values, callback);
-            return;
-        }
-        var added = [],
-            notCreate = false;
-        if (values[0] === undefined){
-            values = [values];
-        }
-        for (var i = 0, il = values.length; i < il; i++) {
-            var item = null;
-            if (values[i] instanceof Item) {
-                item = values[i];
-                item.reload();
-            } else {
-                notCreate = (self.items.length > self.page) ? true : false;
-                item = new Item(values[i], undefined, notCreate);
-            }
-            self.items.push(item);
-            added.push(item);
+      self.utils.extend(self, options);
+
+      self.listContainer = (typeof(id) === 'string') ? document.getElementById(id) : id;
+      if (!self.listContainer) { return; }
+      self.list       = getByClass(self.listContainer, self.listClass, true);
+
+      self.parse      = require('./src/parse')(self);
+      self.templater  = require('./src/templater')(self);
+      self.search     = require('./src/search')(self);
+      self.filter     = require('./src/filter')(self);
+      self.sort       = require('./src/sort')(self);
+
+      this.handlers();
+      this.items();
+      self.update();
+      this.plugins();
+    },
+    handlers: function() {
+      for (var handler in self.handlers) {
+        if (self[handler]) {
+          self.on(handler, self[handler]);
         }
-        self.update();
-        return added;
-    };
+      }
+    },
+    items: function() {
+      self.parse(self.list);
+      if (values !== undefined) {
+        self.add(values);
+      }
+    },
+    plugins: function() {
+      for (var i = 0; i < self.plugins.length; i++) {
+        var plugin = self.plugins[i];
+        self[plugin.name] = plugin;
+        plugin.init(self, List);
+      }
+    }
+  };
+
+  /*
+  * Re-parse the List, use if html have changed
+  */
+  this.reIndex = function() {
+    self.items          = [];
+    self.visibleItems   = [];
+    self.matchingItems  = [];
+    self.searched       = false;
+    self.filtered       = false;
+    self.parse(self.list);
+  };
+
+  this.toJSON = function() {
+    var json = [];
+    for (var i = 0, il = self.items.length; i < il; i++) {
+      json.push(self.items[i].values());
+    }
+    return json;
+  };
+
+
+  /*
+  * Add object to list
+  */
+  this.add = function(values, callback) {
+    if (values.length === 0) {
+      return;
+    }
+    if (callback) {
+      addAsync(values, callback);
+      return;
+    }
+    var added = [],
+      notCreate = false;
+    if (values[0] === undefined){
+      values = [values];
+    }
+    for (var i = 0, il = values.length; i < il; i++) {
+      var item = null;
+      notCreate = (self.items.length > self.page) ? true : false;
+      item = new Item(values[i], undefined, notCreate);
+      self.items.push(item);
+      added.push(item);
+    }
+    self.update();
+    return added;
+  };
 
 	this.show = function(i, page) {
 		this.i = i;
 		this.page = page;
 		self.update();
-        return self;
+    return self;
 	};
 
-    /* Removes object from list.
-    * Loops through the list and removes objects where
-    * property "valuename" === value
-    */
-    this.remove = function(valueName, value, options) {
-        var found = 0;
-        for (var i = 0, il = self.items.length; i < il; i++) {
-            if (self.items[i].values()[valueName] == value) {
-                self.templater.remove(self.items[i], options);
-                self.items.splice(i,1);
-                il--;
-                i--;
-                found++;
-            }
-        }
-        self.update();
-        return found;
-    };
-
-    /* Gets the objects in the list which
-    * property "valueName" === value
-    */
-    this.get = function(valueName, value) {
-        var matchedItems = [];
-        for (var i = 0, il = self.items.length; i < il; i++) {
-            var item = self.items[i];
-            if (item.values()[valueName] == value) {
-                matchedItems.push(item);
-            }
-        }
-        return matchedItems;
-    };
-
-    /*
-    * Get size of the list
-    */
-    this.size = function() {
-        return self.items.length;
-    };
-
-    /*
-    * Removes all items from the list
-    */
-    this.clear = function() {
-        self.templater.clear();
-        self.items = [];
-        return self;
-    };
-
-    this.on = function(event, callback) {
-        self.handlers[event].push(callback);
-        return self;
-    };
-
-    this.off = function(event, callback) {
-        var e = self.handlers[event];
-        var index = indexOf(e, callback);
-        if (index > -1) {
-            e.splice(index, 1);
-        }
-        return self;
-    };
+  /* Removes object from list.
+  * Loops through the list and removes objects where
+  * property "valuename" === value
+  */
+  this.remove = function(valueName, value, options) {
+    var found = 0;
+    for (var i = 0, il = self.items.length; i < il; i++) {
+      if (self.items[i].values()[valueName] == value) {
+        self.templater.remove(self.items[i], options);
+        self.items.splice(i,1);
+        il--;
+        i--;
+        found++;
+      }
+    }
+    self.update();
+    return found;
+  };
 
-    this.trigger = function(event) {
-        var i = self.handlers[event].length;
-        while(i--) {
-            self.handlers[event][i](self);
-        }
-        return self;
-    };
-
-    this.reset = {
-        filter: function() {
-            var is = self.items,
-                il = is.length;
-            while (il--) {
-                is[il].filtered = false;
-            }
-            return self;
-        },
-        search: function() {
-            var is = self.items,
-                il = is.length;
-            while (il--) {
-                is[il].found = false;
-            }
-            return self;
-        }
-    };
+  /* Gets the objects in the list which
+  * property "valueName" === value
+  */
+  this.get = function(valueName, value) {
+    var matchedItems = [];
+    for (var i = 0, il = self.items.length; i < il; i++) {
+      var item = self.items[i];
+      if (item.values()[valueName] == value) {
+        matchedItems.push(item);
+      }
+    }
+    return matchedItems;
+  };
+
+  /*
+  * Get size of the list
+  */
+  this.size = function() {
+    return self.items.length;
+  };
+
+  /*
+  * Removes all items from the list
+  */
+  this.clear = function() {
+    self.templater.clear();
+    self.items = [];
+    return self;
+  };
+
+  this.on = function(event, callback) {
+    self.handlers[event].push(callback);
+    return self;
+  };
 
-    this.update = function() {
-        var is = self.items,
+  this.off = function(event, callback) {
+    var e = self.handlers[event];
+    var index = indexOf(e, callback);
+    if (index > -1) {
+      e.splice(index, 1);
+    }
+    return self;
+  };
+
+  this.trigger = function(event) {
+    var i = self.handlers[event].length;
+    while(i--) {
+      self.handlers[event][i](self);
+    }
+    return self;
+  };
+
+  this.reset = {
+    filter: function() {
+      var is = self.items,
+        il = is.length;
+      while (il--) {
+        is[il].filtered = false;
+      }
+      return self;
+    },
+    search: function() {
+      var is = self.items,
+        il = is.length;
+      while (il--) {
+        is[il].found = false;
+      }
+      return self;
+    }
+  };
+
+  this.update = function() {
+    var is = self.items,
 			il = is.length;
 
-        self.visibleItems = [];
-        self.matchingItems = [];
-        self.templater.clear();
-        for (var i = 0; i < il; i++) {
-            if (is[i].matching() && ((self.matchingItems.length+1) >= self.i && self.visibleItems.length < self.page)) {
-                is[i].show();
-                self.visibleItems.push(is[i]);
-                self.matchingItems.push(is[i]);
-			} else if (is[i].matching()) {
-                self.matchingItems.push(is[i]);
-                is[i].hide();
-			} else {
-                is[i].hide();
-			}
-        }
-        self.trigger('updated');
-        return self;
-    };
+    self.visibleItems = [];
+    self.matchingItems = [];
+    self.templater.clear();
+    for (var i = 0; i < il; i++) {
+      if (is[i].matching() && ((self.matchingItems.length+1) >= self.i && self.visibleItems.length < self.page)) {
+        is[i].show();
+        self.visibleItems.push(is[i]);
+        self.matchingItems.push(is[i]);
+      } else if (is[i].matching()) {
+        self.matchingItems.push(is[i]);
+        is[i].hide();
+      } else {
+        is[i].hide();
+      }
+    }
+    self.trigger('updated');
+    return self;
+  };
 
-    init.start();
+  init.start();
 };
 
+
+// AMD support
+if (typeof define === 'function' && define.amd) {
+  define(function () { return List; });
+}
 module.exports = List;
+window.List = List;
 
 })(window);
diff --git a/package.json b/package.json
index 81c4504..460cef2 100644
--- a/package.json
+++ b/package.json
@@ -1,7 +1,7 @@
 {
   "name": "list.js",
-  "version": "1.1.1",
-  "description": "Component package manager consuming git repositories",
+  "version": "1.2.0",
+  "description": "The perfect library for adding search, sort, filters and flexibility to tables, lists and various HTML elements. Built to be invisible and work on existing HTML",
   "keywords": [
     "list",
     "search",
@@ -15,15 +15,28 @@
   "repository": "git://github.com/javve/list.js.git",
   "dependencies": {},
   "devDependencies": {
-    "grunt": "~0.4.1",
-    "grunt-shell": "~0.5.0",
-    "grunt-contrib-watch": "~0.5.3",
-    "grunt-contrib-uglify": "~0.2.7",
-    "grunt-contrib-jshint": "~0.7.1",
-    "grunt-mocha": "~0.4.1"
+    "browserify": "^13.0.0",
+    "expect.js": "^0.3.1",
+    "grunt": "^0.4.5",
+    "grunt-cli": "^0.1.13",
+    "grunt-contrib-jshint": "^0.12.0",
+    "grunt-contrib-uglify": "^0.11.0",
+    "grunt-contrib-watch": "^0.6.1",
+    "grunt-mocha": "^0.4.15",
+    "grunt-shell": "^1.1.2",
+    "jquery": "^1.12.0"
   },
   "main": "index",
   "engines": {
     "node": ">= 0.10.21"
-  }
+  },
+  "npmName": "list.js",
+  "npmFileMap": [
+    {
+      "basePath": "/dist/",
+      "files": [
+        "*.js"
+      ]
+    }
+  ]
 }
diff --git a/src/add-async.js b/src/add-async.js
index 432333b..aa223f3 100644
--- a/src/add-async.js
+++ b/src/add-async.js
@@ -1,15 +1,16 @@
 module.exports = function(list) {
-    return function(values, callback, items) {
-        var valuesToAdd = values.splice(0, 100);
-        items = items || [];
-        items = items.concat(list.add(valuesToAdd));
-        if (values.length > 0) {
-            setTimeout(function() {
-                addAsync(values, callback, items);
-            }, 10);
-        } else {
-            list.update();
-            callback(items);
-        }
-    };
-};
\ No newline at end of file
+  var addAsync = function(values, callback, items) {
+    var valuesToAdd = values.splice(0, 50);
+    items = items || [];
+    items = items.concat(list.add(valuesToAdd));
+    if (values.length > 0) {
+      setTimeout(function() {
+        addAsync(values, callback, items);
+      }, 1);
+    } else {
+      list.update();
+      callback(items);
+    }
+  };
+  return addAsync;
+};
diff --git a/src/filter.js b/src/filter.js
index df6b2f0..4b14767 100644
--- a/src/filter.js
+++ b/src/filter.js
@@ -1,29 +1,29 @@
 module.exports = function(list) {
 
-    // Add handlers
-    list.handlers.filterStart = list.handlers.filterStart || [];
-    list.handlers.filterComplete = list.handlers.filterComplete || [];
+  // Add handlers
+  list.handlers.filterStart = list.handlers.filterStart || [];
+  list.handlers.filterComplete = list.handlers.filterComplete || [];
 
-    return function(filterFunction) {
-        list.trigger('filterStart');
-        list.i = 1; // Reset paging
-        list.reset.filter();
-        if (filterFunction === undefined) {
-            list.filtered = false;
+  return function(filterFunction) {
+    list.trigger('filterStart');
+    list.i = 1; // Reset paging
+    list.reset.filter();
+    if (filterFunction === undefined) {
+      list.filtered = false;
+    } else {
+      list.filtered = true;
+      var is = list.items;
+      for (var i = 0, il = is.length; i < il; i++) {
+        var item = is[i];
+        if (filterFunction(item)) {
+          item.filtered = true;
         } else {
-            list.filtered = true;
-            var is = list.items;
-            for (var i = 0, il = is.length; i < il; i++) {
-                var item = is[i];
-                if (filterFunction(item)) {
-                    item.filtered = true;
-                } else {
-                    item.filtered = false;
-                }
-            }
+          item.filtered = false;
         }
-        list.update();
-        list.trigger('filterComplete');
-        return list.visibleItems;
-    };
+      }
+    }
+    list.update();
+    list.trigger('filterComplete');
+    return list.visibleItems;
+  };
 };
diff --git a/src/item.js b/src/item.js
index 307a914..f5ab9a1 100644
--- a/src/item.js
+++ b/src/item.js
@@ -1,54 +1,60 @@
 module.exports = function(list) {
-    return function(initValues, element, notCreate) {
-        var item = this;
-
-        this._values = {};
-
-        this.found = false; // Show if list.searched == true and this.found == true
-        this.filtered = false;// Show if list.filtered == true and this.filtered == true
-
-        var init = function(initValues, element, notCreate) {
-            if (element === undefined) {
-                if (notCreate) {
-                    item.values(initValues, notCreate);
-                } else {
-                    item.values(initValues);
-                }
-            } else {
-                item.elm = element;
-                var values = list.templater.get(item, initValues);
-                item.values(values);
-            }
-        };
-        this.values = function(newValues, notCreate) {
-            if (newValues !== undefined) {
-                for(var name in newValues) {
-                    item._values[name] = newValues[name];
-                }
-                if (notCreate !== true) {
-                    list.templater.set(item, item.values());
-                }
-            } else {
-                return item._values;
-            }
-        };
-        this.show = function() {
-            list.templater.show(item);
-        };
-        this.hide = function() {
-            list.templater.hide(item);
-        };
-        this.matching = function() {
-            return (
-                (list.filtered && list.searched && item.found && item.filtered) ||
-                (list.filtered && !list.searched && item.filtered) ||
-                (!list.filtered && list.searched && item.found) ||
-                (!list.filtered && !list.searched)
-            );
-        };
-        this.visible = function() {
-            return (item.elm.parentNode == list.list) ? true : false;
-        };
-        init(initValues, element, notCreate);
+  return function(initValues, element, notCreate) {
+    var item = this;
+
+    this._values = {};
+
+    this.found = false; // Show if list.searched == true and this.found == true
+    this.filtered = false;// Show if list.filtered == true and this.filtered == true
+
+    var init = function(initValues, element, notCreate) {
+      if (element === undefined) {
+        if (notCreate) {
+          item.values(initValues, notCreate);
+        } else {
+          item.values(initValues);
+        }
+      } else {
+        item.elm = element;
+        var values = list.templater.get(item, initValues);
+        item.values(values);
+      }
+    };
+
+    this.values = function(newValues, notCreate) {
+      if (newValues !== undefined) {
+        for(var name in newValues) {
+          item._values[name] = newValues[name];
+        }
+        if (notCreate !== true) {
+          list.templater.set(item, item.values());
+        }
+      } else {
+        return item._values;
+      }
+    };
+
+    this.show = function() {
+      list.templater.show(item);
     };
+
+    this.hide = function() {
+      list.templater.hide(item);
+    };
+
+    this.matching = function() {
+      return (
+        (list.filtered && list.searched && item.found && item.filtered) ||
+        (list.filtered && !list.searched && item.filtered) ||
+        (!list.filtered && list.searched && item.found) ||
+        (!list.filtered && !list.searched)
+      );
+    };
+
+    this.visible = function() {
+      return (item.elm && (item.elm.parentNode == list.list)) ? true : false;
+    };
+
+    init(initValues, element, notCreate);
+  };
 };
diff --git a/src/parse.js b/src/parse.js
index cb39cf3..2294a47 100644
--- a/src/parse.js
+++ b/src/parse.js
@@ -1,45 +1,47 @@
 module.exports = function(list) {
 
-    var Item = require('./item')(list);
+  var Item = require('./item')(list);
 
-    var getChildren = function(parent) {
-        var nodes = parent.childNodes,
-            items = [];
-        for (var i = 0, il = nodes.length; i < il; i++) {
-            // Only textnodes have a data attribute
-            if (nodes[i].data === undefined) {
-                items.push(nodes[i]);
-            }
-        }
-        return items;
-    };
+  var getChildren = function(parent) {
+    var nodes = parent.childNodes,
+      items = [];
+    for (var i = 0, il = nodes.length; i < il; i++) {
+      // Only textnodes have a data attribute
+      if (nodes[i].data === undefined) {
+        items.push(nodes[i]);
+      }
+    }
+    return items;
+  };
 
-    var parse = function(itemElements, valueNames) {
-        for (var i = 0, il = itemElements.length; i < il; i++) {
-            list.items.push(new Item(valueNames, itemElements[i]));
-        }
-    };
-    var parseAsync = function(itemElements, valueNames) {
-        var itemsToIndex = itemElements.splice(0, 100); // TODO: If < 100 items, what happens in IE etc?
-        parse(itemsToIndex, valueNames);
-        if (itemElements.length > 0) {
-            setTimeout(function() {
-                init.items.indexAsync(itemElements, valueNames);
-            }, 10);
-        } else {
-            list.update();
-            // TODO: Add indexed callback
-        }
-    };
+  var parse = function(itemElements, valueNames) {
+    for (var i = 0, il = itemElements.length; i < il; i++) {
+      list.items.push(new Item(valueNames, itemElements[i]));
+    }
+  };
+  var parseAsync = function(itemElements, valueNames) {
+    var itemsToIndex = itemElements.splice(0, 50); // TODO: If < 100 items, what happens in IE etc?
+    parse(itemsToIndex, valueNames);
+    if (itemElements.length > 0) {
+      setTimeout(function() {
+        parseAsync(itemElements, valueNames);
+      }, 1);
+    } else {
+      list.update();
+      list.trigger('parseComplete');
+    }
+  };
 
-    return function() {
-        var itemsToIndex = getChildren(list.list),
-            valueNames = list.valueNames;
+  list.handlers.parseComplete = list.handlers.parseComplete || [];
 
-        if (list.indexAsync) {
-            parseAsync(itemsToIndex, valueNames);
-        } else {
-            parse(itemsToIndex, valueNames);
-        }
-    };
+  return function() {
+    var itemsToIndex = getChildren(list.list),
+      valueNames = list.valueNames;
+
+    if (list.indexAsync) {
+      parseAsync(itemsToIndex, valueNames);
+    } else {
+      parse(itemsToIndex, valueNames);
+    }
+  };
 };
diff --git a/src/search.js b/src/search.js
index f3434fa..2aeeb00 100644
--- a/src/search.js
+++ b/src/search.js
@@ -1,119 +1,117 @@
-var events = require('events'),
-    getByClass = require('get-by-class'),
-    toString = require('to-string');
-
 module.exports = function(list) {
-    var item,
-        text,
-        columns,
-        searchString,
-        customSearch;
+  var item,
+    text,
+    columns,
+    searchString,
+    customSearch;
 
-    var prepare = {
-        resetList: function() {
-            list.i = 1;
-            list.templater.clear();
-            customSearch = undefined;
-        },
-        setOptions: function(args) {
-            if (args.length == 2 && args[1] instanceof Array) {
-                columns = args[1];
-            } else if (args.length == 2 && typeof(args[1]) == "function") {
-                customSearch = args[1];
-            } else if (args.length == 3) {
-                columns = args[1];
-                customSearch = args[2];
-            }
-        },
-        setColumns: function() {
-            columns = (columns === undefined) ? prepare.toArray(list.items[0].values()) : columns;
-        },
-        setSearchString: function(s) {
-            s = toString(s).toLowerCase();
-            s = s.replace(/[-[\]{}()*+?.,\\^$|#]/g, "\\$&"); // Escape regular expression characters
-            searchString = s;
-        },
-        toArray: function(values) {
-            var tmpColumn = [];
-            for (var name in values) {
-                tmpColumn.push(name);
-            }
-            return tmpColumn;
+  var prepare = {
+    resetList: function() {
+      list.i = 1;
+      list.templater.clear();
+      customSearch = undefined;
+    },
+    setOptions: function(args) {
+      if (args.length == 2 && args[1] instanceof Array) {
+        columns = args[1];
+      } else if (args.length == 2 && typeof(args[1]) == "function") {
+        customSearch = args[1];
+      } else if (args.length == 3) {
+        columns = args[1];
+        customSearch = args[2];
+      }
+    },
+    setColumns: function() {
+      if (list.items.length === 0) return;
+      if (columns === undefined) {
+        columns = (list.searchColumns === undefined) ? prepare.toArray(list.items[0].values()) : list.searchColumns;
+      }
+    },
+    setSearchString: function(s) {
+      s = list.utils.toString(s).toLowerCase();
+      s = s.replace(/[-[\]{}()*+?.,\\^$|#]/g, "\\$&"); // Escape regular expression characters
+      searchString = s;
+    },
+    toArray: function(values) {
+      var tmpColumn = [];
+      for (var name in values) {
+        tmpColumn.push(name);
+      }
+      return tmpColumn;
+    }
+  };
+  var search = {
+    list: function() {
+      for (var k = 0, kl = list.items.length; k < kl; k++) {
+        search.item(list.items[k]);
+      }
+    },
+    item: function(item) {
+      item.found = false;
+      for (var j = 0, jl = columns.length; j < jl; j++) {
+        if (search.values(item.values(), columns[j])) {
+          item.found = true;
+          return;
         }
-    };
-    var search = {
-        list: function() {
-            for (var k = 0, kl = list.items.length; k < kl; k++) {
-                search.item(list.items[k]);
-            }
-        },
-        item: function(item) {
-            item.found = false;
-            for (var j = 0, jl = columns.length; j < jl; j++) {
-                if (search.values(item.values(), columns[j])) {
-                    item.found = true;
-                    return;
-                }
-            }
-        },
-        values: function(values, column) {
-            if (values.hasOwnProperty(column)) {
-                text = toString(values[column]).toLowerCase();
-                if ((searchString !== "") && (text.search(searchString) > -1)) {
-                    return true;
-                }
-            }
-            return false;
-        },
-        reset: function() {
-            list.reset.search();
-            list.searched = false;
+      }
+    },
+    values: function(values, column) {
+      if (values.hasOwnProperty(column)) {
+        text = list.utils.toString(values[column]).toLowerCase();
+        if ((searchString !== "") && (text.search(searchString) > -1)) {
+          return true;
         }
-    };
+      }
+      return false;
+    },
+    reset: function() {
+      list.reset.search();
+      list.searched = false;
+    }
+  };
 
-    var searchMethod = function(str) {
-        list.trigger('searchStart');
+  var searchMethod = function(str) {
+    list.trigger('searchStart');
 
-        prepare.resetList();
-        prepare.setSearchString(str);
-        prepare.setOptions(arguments); // str, cols|searchFunction, searchFunction
-        prepare.setColumns();
+    prepare.resetList();
+    prepare.setSearchString(str);
+    prepare.setOptions(arguments); // str, cols|searchFunction, searchFunction
+    prepare.setColumns();
 
-        if (searchString === "" ) {
-            search.reset();
-        } else {
-            list.searched = true;
-            if (customSearch) {
-                customSearch(searchString, columns);
-            } else {
-                search.list();
-            }
-        }
+    if (searchString === "" ) {
+      search.reset();
+    } else {
+      list.searched = true;
+      if (customSearch) {
+        customSearch(searchString, columns);
+      } else {
+        search.list();
+      }
+    }
 
-        list.update();
-        list.trigger('searchComplete');
-        return list.visibleItems;
-    };
+    list.update();
+    list.trigger('searchComplete');
+    return list.visibleItems;
+  };
 
-    list.handlers.searchStart = list.handlers.searchStart || [];
-    list.handlers.searchComplete = list.handlers.searchComplete || [];
+  list.handlers.searchStart = list.handlers.searchStart || [];
+  list.handlers.searchComplete = list.handlers.searchComplete || [];
 
-    events.bind(getByClass(list.listContainer, list.searchClass), 'keyup', function(e) {
-        var target = e.target || e.srcElement, // IE have srcElement
-            alreadyCleared = (target.value === "" && !list.searched);
-        if (!alreadyCleared) { // If oninput already have resetted the list, do nothing
-            searchMethod(target.value);
-        }
-    });
+  list.utils.events.bind(list.utils.getByClass(list.listContainer, list.searchClass), 'keyup', function(e) {
+    var target = e.target || e.srcElement, // IE have srcElement
+      alreadyCleared = (target.value === "" && !list.searched);
+    if (!alreadyCleared) { // If oninput already have resetted the list, do nothing
+      searchMethod(target.value);
+    }
+  });
 
-    // Used to detect click on HTML5 clear button
-    events.bind(getByClass(list.listContainer, list.searchClass), 'input', function(e) {
-        var target = e.target || e.srcElement;
-        if (target.value === "") {
-            searchMethod('');
-        }
-    });
+  // Used to detect click on HTML5 clear button
+  list.utils.events.bind(list.utils.getByClass(list.listContainer, list.searchClass), 'input', function(e) {
+    var target = e.target || e.srcElement;
+    if (target.value === "") {
+      searchMethod('');
+    }
+  });
 
-    list.helpers.toString = toString;
-    return searchMethod;
+  return searchMethod;
 };
diff --git a/src/sort.js b/src/sort.js
index 3373012..18030f6 100644
--- a/src/sort.js
+++ b/src/sort.js
@@ -1,101 +1,90 @@
-var naturalSort = require('natural-sort'),
-    classes = require('classes'),
-    events = require('events'),
-    getByClass = require('get-by-class'),
-    getAttribute = require('get-attribute');
-
 module.exports = function(list) {
-    list.sortFunction = list.sortFunction || function(itemA, itemB, options) {
-        options.desc = options.order == "desc" ? true : false; // Natural sort uses this format
-        return naturalSort(itemA.values()[options.valueName], itemB.values()[options.valueName], options);
-    };
+  list.sortFunction = list.sortFunction || function(itemA, itemB, options) {
+    options.desc = options.order == "desc" ? true : false; // Natural sort uses this format
+    return list.utils.naturalSort(itemA.values()[options.valueName], itemB.values()[options.valueName], options);
+  };
 
-    var buttons = {
-        els: undefined,
-        clear: function() {
-            for (var i = 0, il = buttons.els.length; i < il; i++) {
-                classes(buttons.els[i]).remove('asc');
-                classes(buttons.els[i]).remove('desc');
-            }
-        },
-        getOrder: function(btn) {
-            var predefinedOrder = getAttribute(btn, 'data-order');
-            if (predefinedOrder == "asc" || predefinedOrder == "desc") {
-                return predefinedOrder;
-            } else if (classes(btn).has('desc')) {
-                return "asc";
-            } else if (classes(btn).has('asc')) {
-                return "desc";
-            } else {
-                return "asc";
-            }
-        },
-        getInSensitive: function(btn, options) {
-            var insensitive = getAttribute(btn, 'data-insensitive');
-            if (insensitive === "true") {
-                options.insensitive = true;
-            } else {
-                options.insensitive = false;
-            }
-        },
-        setOrder: function(options) {
-            for (var i = 0, il = buttons.els.length; i < il; i++) {
-                var btn = buttons.els[i];
-                if (getAttribute(btn, 'data-sort') !== options.valueName) {
-                    continue;
-                }
-                var predefinedOrder = getAttribute(btn, 'data-order');
-                if (predefinedOrder == "asc" || predefinedOrder == "desc") {
-                    if (predefinedOrder == options.order) {
-                        classes(btn).add(options.order);
-                    }
-                } else {
-                    classes(btn).add(options.order);
-                }
-            }
+  var buttons = {
+    els: undefined,
+    clear: function() {
+      for (var i = 0, il = buttons.els.length; i < il; i++) {
+        list.utils.classes(buttons.els[i]).remove('asc');
+        list.utils.classes(buttons.els[i]).remove('desc');
+      }
+    },
+    getOrder: function(btn) {
+      var predefinedOrder = list.utils.getAttribute(btn, 'data-order');
+      if (predefinedOrder == "asc" || predefinedOrder == "desc") {
+        return predefinedOrder;
+      } else if (list.utils.classes(btn).has('desc')) {
+        return "asc";
+      } else if (list.utils.classes(btn).has('asc')) {
+        return "desc";
+      } else {
+        return "asc";
+      }
+    },
+    getInSensitive: function(btn, options) {
+      var insensitive = list.utils.getAttribute(btn, 'data-insensitive');
+      if (insensitive === "false") {
+        options.insensitive = false;
+      } else {
+        options.insensitive = true;
+      }
+    },
+    setOrder: function(options) {
+      for (var i = 0, il = buttons.els.length; i < il; i++) {
+        var btn = buttons.els[i];
+        if (list.utils.getAttribute(btn, 'data-sort') !== options.valueName) {
+          continue;
         }
-    };
-    var sort = function() {
-        list.trigger('sortStart');
-        options = {};
-
-        var target = arguments[0].currentTarget || arguments[0].srcElement || undefined;
-
-        if (target) {
-            options.valueName = getAttribute(target, 'data-sort');
-            buttons.getInSensitive(target, options);
-            options.order = buttons.getOrder(target);
+        var predefinedOrder = list.utils.getAttribute(btn, 'data-order');
+        if (predefinedOrder == "asc" || predefinedOrder == "desc") {
+          if (predefinedOrder == options.order) {
+            list.utils.classes(btn).add(options.order);
+          }
         } else {
-            options = arguments[1] || options;
-            options.valueName = arguments[0];
-            options.order = options.order || "asc";
-            options.insensitive = (typeof options.insensitive == "undefined") ? true : options.insensitive;
+          list.utils.classes(btn).add(options.order);
         }
-        buttons.clear();
-        buttons.setOrder(options);
+      }
+    }
+  };
+  var sort = function() {
+    list.trigger('sortStart');
+    var options = {};
+
+    var target = arguments[0].currentTarget || arguments[0].srcElement || undefined;
 
-        options.sortFunction = options.sortFunction || list.sortFunction;
-        list.items.sort(function(a, b) {
-            return options.sortFunction(a, b, options);
-        });
-        list.update();
-        list.trigger('sortComplete');
-    };
+    if (target) {
+      options.valueName = list.utils.getAttribute(target, 'data-sort');
+      buttons.getInSensitive(target, options);
+      options.order = buttons.getOrder(target);
+    } else {
+      options = arguments[1] || options;
+      options.valueName = arguments[0];
+      options.order = options.order || "asc";
+      options.insensitive = (typeof options.insensitive == "undefined") ? true : options.insensitive;
+    }
+    buttons.clear();
+    buttons.setOrder(options);
 
-    // Add handlers
-    list.handlers.sortStart = list.handlers.sortStart || [];
-    list.handlers.sortComplete = list.handlers.sortComplete || [];
+    options.sortFunction = options.sortFunction || list.sortFunction;
+    list.items.sort(function(a, b) {
+      var mult = (options.order === 'desc') ? -1 : 1;
+      return (options.sortFunction(a, b, options) * mult);
+    });
+    list.update();
+    list.trigger('sortComplete');
+  };
 
-    buttons.els = getByClass(list.listContainer, list.sortClass);
-    events.bind(buttons.els, 'click', sort);
-    list.on('searchStart', buttons.clear);
-    list.on('filterStart', buttons.clear);
+  // Add handlers
+  list.handlers.sortStart = list.handlers.sortStart || [];
+  list.handlers.sortComplete = list.handlers.sortComplete || [];
 
-    // Helpers
-    list.helpers.classes = classes;
-    list.helpers.naturalSort = naturalSort;
-    list.helpers.events = events;
-    list.helpers.getAttribute = getAttribute;
+  buttons.els = list.utils.getByClass(list.listContainer, list.sortClass);
+  list.utils.events.bind(buttons.els, 'click', sort);
+  list.on('searchStart', buttons.clear);
+  list.on('filterStart', buttons.clear);
 
-    return sort;
+  return sort;
 };
diff --git a/src/templater.js b/src/templater.js
index 29b8d02..782fd60 100644
--- a/src/templater.js
+++ b/src/templater.js
@@ -1,96 +1,169 @@
-var getByClass = require('get-by-class');
-
 var Templater = function(list) {
-    var itemSource = getItemSource(list.item),
-        templater = this;
+  var itemSource,
+    templater = this;
 
-    function getItemSource(item) {
-        if (item === undefined) {
-            var nodes = list.list.childNodes,
-                items = [];
+  var init = function() {
+    itemSource = templater.getItemSource(list.item);
+    itemSource = templater.clearSourceItem(itemSource, list.valueNames);
+  };
 
-            for (var i = 0, il = nodes.length; i < il; i++) {
-                // Only textnodes have a data attribute
-                if (nodes[i].data === undefined) {
-                    return nodes[i];
-                }
-            }
-            return null;
-        } else if (item.indexOf("<") !== -1) { // Try create html element of list, do not work for tables!!
-            var div = document.createElement('div');
-            div.innerHTML = item;
-            return div.firstChild;
-        } else {
-            return document.getElementById(list.item);
+  this.clearSourceItem = function(el, valueNames) {
+    for(var i = 0, il = valueNames.length; i < il; i++) {
+      var elm;
+      if (valueNames[i].data) {
+        for (var j = 0, jl = valueNames[i].data.length; j < jl; j++) {
+          el.setAttribute('data-'+valueNames[i].data[j], '');
+        }
+      } else if (valueNames[i].attr && valueNames[i].name) {
+        elm = list.utils.getByClass(el, valueNames[i].name, true);
+        if (elm) {
+          elm.setAttribute(valueNames[i].attr, "");
         }
+      } else {
+        elm = list.utils.getByClass(el, valueNames[i], true);
+        if (elm) {
+          elm.innerHTML = "";
+        }
+      }
+      elm = undefined;
     }
+    return el;
+  };
+
+  this.getItemSource = function(item) {
+    if (item === undefined) {
+      var nodes = list.list.childNodes,
+        items = [];
 
-    /* Get values from element */
-    this.get = function(item, valueNames) {
-        templater.create(item);
-        var values = {};
-        for(var i = 0, il = valueNames.length; i < il; i++) {
-            var elm = getByClass(item.elm, valueNames[i], true);
-            values[valueNames[i]] = elm ? elm.innerHTML : "";
+      for (var i = 0, il = nodes.length; i < il; i++) {
+        // Only textnodes have a data attribute
+        if (nodes[i].data === undefined) {
+          return nodes[i].cloneNode(true);
         }
-        return values;
-    };
+      }
+    } else if (/^tr[\s>]/.exec(item)) {
+      var table = document.createElement('table');
+      table.innerHTML = item;
+      return table.firstChild;
+    } else if (item.indexOf("<") !== -1) {
+      var div = document.createElement('div');
+      div.innerHTML = item;
+      return div.firstChild;
+    } else {
+      var source = document.getElementById(list.item);
+      if (source) {
+        return source;
+      }
+    }
+    throw new Error("The list need to have at list one item on init otherwise you'll have to add a template.");
+  };
 
-    /* Sets values at element */
-    this.set = function(item, values) {
-        if (!templater.create(item)) {
-            for(var v in values) {
-                if (values.hasOwnProperty(v)) {
-                    // TODO speed up if possible
-                    var elm = getByClass(item.elm, v, true);
-                    if (elm) {
-                        /* src attribute for image tag & text for other tags */
-                        if (elm.tagName === "IMG" && values[v] !== "") {
-                            elm.src = values[v];
-                        } else {
-                            elm.innerHTML = values[v];
-                        }
-                    }
-                }
-            }
+  this.get = function(item, valueNames) {
+    templater.create(item);
+    var values = {};
+    for(var i = 0, il = valueNames.length; i < il; i++) {
+      var elm;
+      if (valueNames[i].data) {
+        for (var j = 0, jl = valueNames[i].data.length; j < jl; j++) {
+          values[valueNames[i].data[j]] = list.utils.getAttribute(item.elm, 'data-'+valueNames[i].data[j]);
         }
-    };
+      } else if (valueNames[i].attr && valueNames[i].name) {
+        elm = list.utils.getByClass(item.elm, valueNames[i].name, true);
+        values[valueNames[i].name] = elm ? list.utils.getAttribute(elm, valueNames[i].attr) : "";
+      } else {
+        elm = list.utils.getByClass(item.elm, valueNames[i], true);
+        values[valueNames[i]] = elm ? elm.innerHTML : "";
+      }
+      elm = undefined;
+    }
+    return values;
+  };
 
-    this.create = function(item) {
-        if (item.elm !== undefined) {
-            return false;
+  this.set = function(item, values) {
+    var getValueName = function(name) {
+      for (var i = 0, il = list.valueNames.length; i < il; i++) {
+        if (list.valueNames[i].data) {
+          var data = list.valueNames[i].data;
+          for (var j = 0, jl = data.length; j < jl; j++) {
+            if (data[j] === name) {
+              return { data: name };
+            }
+          }
+        } else if (list.valueNames[i].attr && list.valueNames[i].name && list.valueNames[i].name == name) {
+          return list.valueNames[i];
+        } else if (list.valueNames[i] === name) {
+          return name;
         }
-        /* If item source does not exists, use the first item in list as
-        source for new items */
-        var newItem = itemSource.cloneNode(true);
-        newItem.removeAttribute('id');
-        item.elm = newItem;
-        templater.set(item, item.values());
-        return true;
-    };
-    this.remove = function(item) {
-        list.list.removeChild(item.elm);
+      }
     };
-    this.show = function(item) {
-        templater.create(item);
-        list.list.appendChild(item.elm);
-    };
-    this.hide = function(item) {
-        if (item.elm !== undefined && item.elm.parentNode === list.list) {
-            list.list.removeChild(item.elm);
+    var setValue = function(name, value) {
+      var elm;
+      var valueName = getValueName(name);
+      if (!valueName)
+        return;
+      if (valueName.data) {
+        item.elm.setAttribute('data-'+valueName.data, value);
+      } else if (valueName.attr && valueName.name) {
+        elm = list.utils.getByClass(item.elm, valueName.name, true);
+        if (elm) {
+          elm.setAttribute(valueName.attr, value);
         }
-    };
-    this.clear = function() {
-        /* .innerHTML = ''; fucks up IE */
-        if (list.list.hasChildNodes()) {
-            while (list.list.childNodes.length >= 1)
-            {
-                list.list.removeChild(list.list.firstChild);
-            }
+      } else {
+        elm = list.utils.getByClass(item.elm, valueName, true);
+        if (elm) {
+          elm.innerHTML = value;
         }
+      }
+      elm = undefined;
     };
+    if (!templater.create(item)) {
+      for(var v in values) {
+        if (values.hasOwnProperty(v)) {
+          setValue(v, values[v]);
+        }
+      }
+    }
+  };
+
+  this.create = function(item) {
+    if (item.elm !== undefined) {
+      return false;
+    }
+    /* If item source does not exists, use the first item in list as
+    source for new items */
+    var newItem = itemSource.cloneNode(true);
+    newItem.removeAttribute('id');
+    item.elm = newItem;
+    templater.set(item, item.values());
+    return true;
+  };
+  this.remove = function(item) {
+    if (item.elm.parentNode === list.list) {
+      list.list.removeChild(item.elm);
+    }
+  };
+  this.show = function(item) {
+    templater.create(item);
+    list.list.appendChild(item.elm);
+  };
+  this.hide = function(item) {
+    if (item.elm !== undefined && item.elm.parentNode === list.list) {
+      list.list.removeChild(item.elm);
+    }
+  };
+  this.clear = function() {
+    /* .innerHTML = ''; fucks up IE */
+    if (list.list.hasChildNodes()) {
+      while (list.list.childNodes.length >= 1)
+      {
+        list.list.removeChild(list.list.firstChild);
+      }
+    }
+  };
+
+  init();
 };
 
 module.exports = function(list) {
-    return new Templater(list);
+  return new Templater(list);
 };
diff --git a/src/utils/classes.js b/src/utils/classes.js
new file mode 100644
index 0000000..d7b5430
--- /dev/null
+++ b/src/utils/classes.js
@@ -0,0 +1,185 @@
+/**
+ * Module dependencies.
+ */
+
+var index = require('./index-of');
+
+/**
+ * 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) {
+  if (!el || !el.nodeType) {
+    throw new Error('A DOM element reference is required');
+  }
+  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`, can force state via `force`.
+ *
+ * For browsers that support classList, but do not support `force` yet,
+ * the mistake will be detected and corrected.
+ *
+ * @param {String} name
+ * @param {Boolean} force
+ * @return {ClassList}
+ * @api public
+ */
+
+ClassList.prototype.toggle = function(name, force){
+  // classList
+  if (this.list) {
+    if ("undefined" !== typeof force) {
+      if (force !== this.list.toggle(name, force)) {
+        this.list.toggle(name); // toggle again to correct
+      }
+    } else {
+      this.list.toggle(name);
+    }
+    return this;
+  }
+
+  // fallback
+  if ("undefined" !== typeof force) {
+    if (!force) {
+      this.remove(name);
+    } else {
+      this.add(name);
+    }
+  } else {
+    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 className = this.el.getAttribute('class') || '';
+  var str = className.replace(/^\s+|\s+$/g, '');
+  var arr = str.split(re);
+  if ('' === arr[0]) arr.shift();
+  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);
+};
diff --git a/src/utils/events.js b/src/utils/events.js
new file mode 100644
index 0000000..2169598
--- /dev/null
+++ b/src/utils/events.js
@@ -0,0 +1,38 @@
+var bind = window.addEventListener ? 'addEventListener' : 'attachEvent',
+    unbind = window.removeEventListener ? 'removeEventListener' : 'detachEvent',
+    prefix = bind !== 'addEventListener' ? 'on' : '',
+    toArray = require('./to-array');
+
+/**
+ * Bind `el` event `type` to `fn`.
+ *
+ * @param {Element} el, NodeList, HTMLCollection or Array
+ * @param {String} type
+ * @param {Function} fn
+ * @param {Boolean} capture
+ * @api public
+ */
+
+exports.bind = function(el, type, fn, capture){
+  el = toArray(el);
+  for ( var i = 0; i < el.length; i++ ) {
+    el[i][bind](prefix + type, fn, capture || false);
+  }
+};
+
+/**
+ * Unbind `el` event `type`'s callback `fn`.
+ *
+ * @param {Element} el, NodeList, HTMLCollection or Array
+ * @param {String} type
+ * @param {Function} fn
+ * @param {Boolean} capture
+ * @api public
+ */
+
+exports.unbind = function(el, type, fn, capture){
+  el = toArray(el);
+  for ( var i = 0; i < el.length; i++ ) {
+    el[i][unbind](prefix + type, fn, capture || false);
+  }
+};
diff --git a/src/utils/extend.js b/src/utils/extend.js
new file mode 100644
index 0000000..9fc6037
--- /dev/null
+++ b/src/utils/extend.js
@@ -0,0 +1,18 @@
+/*
+ * Source: https://github.com/segmentio/extend
+ */
+
+module.exports = function extend (object) {
+    // Takes an unlimited number of extenders.
+    var args = Array.prototype.slice.call(arguments, 1);
+
+    // For each extender, copy their properties on our object.
+    for (var i = 0, source; source = args[i]; i++) {
+        if (!source) continue;
+        for (var property in source) {
+            object[property] = source[property];
+        }
+    }
+
+    return object;
+};
diff --git a/src/utils/get-attribute.js b/src/utils/get-attribute.js
new file mode 100644
index 0000000..729e651
--- /dev/null
+++ b/src/utils/get-attribute.js
@@ -0,0 +1,26 @@
+/**
+ * A cross-browser implementation of getAttribute.
+ * Source found here: http://stackoverflow.com/a/3755343/361337 written by Vivin Paliath
+ *
+ * Return the value for `attr` at `element`.
+ *
+ * @param {Element} el
+ * @param {String} attr
+ * @api public
+ */
+
+module.exports = function(el, attr) {
+  var result = (el.getAttribute && el.getAttribute(attr)) || null;
+  if( !result ) {
+    var attrs = el.attributes;
+    var length = attrs.length;
+    for(var i = 0; i < length; i++) {
+      if (attr[i] !== undefined) {
+        if(attr[i].nodeName === attr) {
+          result = attr[i].nodeValue;
+        }
+      }
+    }
+  }
+  return result;
+};
diff --git a/src/utils/get-by-class.js b/src/utils/get-by-class.js
new file mode 100644
index 0000000..f475fd8
--- /dev/null
+++ b/src/utils/get-by-class.js
@@ -0,0 +1,56 @@
+/**
+ * A cross-browser implementation of getElementsByClass.
+ * Heavily based on Dustin Diaz's function: http://dustindiaz.com/getelementsbyclass.
+ *
+ * Find all elements with class `className` inside `container`.
+ * Use `single = true` to increase performance in older browsers
+ * when only one element is needed.
+ *
+ * @param {String} className
+ * @param {Element} container
+ * @param {Boolean} single
+ * @api public
+ */
+
+module.exports = (function() {
+  if (document.getElementsByClassName) {
+    return function(container, className, single) {
+      if (single) {
+        return container.getElementsByClassName(className)[0];
+      } else {
+        return container.getElementsByClassName(className);
+      }
+    };
+  } else if (document.querySelector) {
+    return function(container, className, single) {
+      className = '.' + className;
+      if (single) {
+        return container.querySelector(className);
+      } else {
+        return container.querySelectorAll(className);
+      }
+    };
+  } else {
+    return function(container, className, single) {
+      var classElements = [],
+        tag = '*';
+      if (container === null) {
+        container = document;
+      }
+      var els = container.getElementsByTagName(tag);
+      var elsLen = els.length;
+      var pattern = new RegExp("(^|\\s)"+className+"(\\s|$)");
+      for (var i = 0, j = 0; i < elsLen; i++) {
+        if ( pattern.test(els[i].className) ) {
+          if (single) {
+            return els[i];
+          } else {
+            classElements[j] = els[i];
+            j++;
+          }
+        }
+      }
+      return classElements;
+    };
+  }
+})();
diff --git a/src/utils/index-of.js b/src/utils/index-of.js
new file mode 100644
index 0000000..4c26161
--- /dev/null
+++ b/src/utils/index-of.js
@@ -0,0 +1,9 @@
+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;
+};
diff --git a/src/utils/natural-sort.js b/src/utils/natural-sort.js
new file mode 100644
index 0000000..76c1e70
--- /dev/null
+++ b/src/utils/natural-sort.js
@@ -0,0 +1,48 @@
+/*
+ * Natural Sort algorithm for Javascript - Version 0.8 - Released under MIT license
+ * Author: Jim Palmer (based on chunking idea from Dave Koelle)
+ */
+module.exports = function(a, b, opts) {
+    var re = /(^([+\-]?(?:\d*)(?:\.\d*)?(?:[eE][+\-]?\d+)?)?$|^0x[\da-fA-F]+$|\d+)/g,
+        sre = /^\s+|\s+$/g,   // trim pre-post whitespace
+        snre = /\s+/g,        // normalize all whitespace to single ' ' character
+        dre = /(^([\w ]+,?[\w ]+)?[\w ]+,?[\w ]+\d+:\d+(:\d+)?[\w ]?|^\d{1,4}[\/\-]\d{1,4}[\/\-]\d{1,4}|^\w+, \w+ \d+, \d{4})/,
+        hre = /^0x[0-9a-f]+$/i,
+        ore = /^0/,
+        options = opts || {},
+        i = function(s) { return options.insensitive && (''+s).toLowerCase() || ''+s; },
+        // convert all to strings strip whitespace
+        x = i(a) || '',
+        y = i(b) || '',
+        // chunk/tokenize
+        xN = x.replace(re, '\0$1\0').replace(/\0$/,'').replace(/^\0/,'').split('\0'),
+        yN = y.replace(re, '\0$1\0').replace(/\0$/,'').replace(/^\0/,'').split('\0'),
+        // numeric, hex or date detection
+        xD = parseInt(x.match(hre), 16) || (xN.length !== 1 && Date.parse(x)),
+        yD = parseInt(y.match(hre), 16) || xD && y.match(dre) && Date.parse(y) || null,
+        normChunk = function(s, l) {
+            // normalize spaces; find floats not starting with '0', string or 0 if not defined (Clint Priest)
+            return (!s.match(ore) || l == 1) && parseFloat(s) || s.replace(snre, ' ').replace(sre, '') || 0;
+        },
+        oFxNcL, oFyNcL;
+    // first try and sort Hex codes or Dates
+    if (yD) {
+        if ( xD < yD ) { return -1; }
+        else if ( xD > yD ) { return 1; }
+    }
+    // natural sorting through split numeric strings and default strings
+    for(var cLoc=0, xNl = xN.length, yNl = yN.length, numS=Math.max(xNl, yNl); cLoc < numS; cLoc++) {
+        oFxNcL = normChunk(xN[cLoc], xNl);
+        oFyNcL = normChunk(yN[cLoc], yNl);
+        // handle numeric vs string comparison - number < string - (Kyle Adams)
+        if (isNaN(oFxNcL) !== isNaN(oFyNcL)) { return (isNaN(oFxNcL)) ? 1 : -1; }
+        // rely on string comparison if different types - i.e. '02' < 2 != '02' < '2'
+        else if (typeof oFxNcL !== typeof oFyNcL) {
+            oFxNcL += '';
+            oFyNcL += '';
+        }
+        if (oFxNcL < oFyNcL) { return -1; }
+        if (oFxNcL > oFyNcL) { return 1; }
+    }
+    return 0;
+};
diff --git a/src/utils/to-array.js b/src/utils/to-array.js
new file mode 100644
index 0000000..9fac261
--- /dev/null
+++ b/src/utils/to-array.js
@@ -0,0 +1,33 @@
+/**
+ * Source: https://github.com/timoxley/to-array
+ *
+ * Convert an array-like object into an `Array`.
+ * If `collection` is already an `Array`, then will return a clone of `collection`.
+ *
+ * @param {Array | Mixed} collection An `Array` or array-like object to convert e.g. `arguments` or `NodeList`
+ * @return {Array} Naive conversion of `collection` to a new `Array`.
+ * @api public
+ */
+
+module.exports = function toArray(collection) {
+  if (typeof collection === 'undefined') return [];
+  if (collection === null) return [null];
+  if (collection === window) return [window];
+  if (typeof collection === 'string') return [collection];
+  if (isArray(collection)) return collection;
+  if (typeof collection.length != 'number') return [collection];
+  if (typeof collection === 'function' && collection instanceof Function) return [collection];
+
+  var arr = [];
+  for (var i = 0; i < collection.length; i++) {
+    if (Object.prototype.hasOwnProperty.call(collection, i) || i in collection) {
+      arr.push(collection[i]);
+    }
+  }
+  if (!arr.length) return [];
+  return arr;
+};
+
+function isArray(arr) {
+  return Object.prototype.toString.call(arr) === "[object Array]";
+}
diff --git a/src/utils/to-string.js b/src/utils/to-string.js
new file mode 100644
index 0000000..cdda3bc
--- /dev/null
+++ b/src/utils/to-string.js
@@ -0,0 +1,6 @@
+module.exports = function(s) {
+  s = (s === undefined) ? "" : s;
+  s = (s === null) ? "" : s;
+  s = s.toString();
+  return s;
+};
diff --git a/test/fixtures.js b/test/fixtures.js
index 79f5190..fadfc37 100644
--- a/test/fixtures.js
+++ b/test/fixtures.js
@@ -1,56 +1,56 @@
 var fixture = {
-    list: function(valueNames, items) {
-        var listHtml = $('<div id="list"><ul class="list"></ul></div>'),
-            item = "";
+  list: function(valueNames, items) {
+    var listHtml = $('<div id="list"><ul class="list"></ul></div>'),
+      item = "";
 
-        item = "<li>";
-        for (var i = 0; i < valueNames.length; i++) {
-            item += '<span class="'+valueNames[i]+'"</span>';
-        }
-        item += "</li>";
+    item = "<li>";
+    for (var i = 0; i < valueNames.length; i++) {
+      item += '<span class="'+valueNames[i]+'"</span>';
+    }
+    item += "</li>";
 
-        $(document.body).append(listHtml);
+    $(document.body).append(listHtml);
 
-        items = items || [];
+    items = items || [];
 
-        return new List('list', {
-            valueNames: valueNames,
-            item: item
-        }, items);
-    },
-    removeList: function() {
-        $('#list').remove();
-    },
-    jonny: {
-        name: "Jonny Strömberg",
-        born: '1986'
-    },
-    martina: {
-        name: "Martina Elm",
-        born: '1986'
-    },
-    angelica: {
-        name: "Angelica Abraham",
-        born: '1986'
-    },
-    sebastian: {
-        name: "Sebastian Höglund",
-        born: '1989'
-    },
-    imma: {
-        name: "Imma Grafström",
-        born: '1953'
-    },
-    hasse: {
-        name: "Hasse Strömberg",
-        born: '1955'
-    }
+    return new List('list', {
+      valueNames: valueNames,
+      item: item
+    }, items);
+  },
+  removeList: function() {
+    $('#list').remove();
+  },
+  jonny: {
+    name: "Jonny Strömberg",
+    born: '1986'
+  },
+  martina: {
+    name: "Martina Elm",
+    born: '1986'
+  },
+  angelica: {
+    name: "Angelica Abraham",
+    born: '1986'
+  },
+  sebastian: {
+    name: "Sebastian Höglund",
+    born: '1989'
+  },
+  imma: {
+    name: "Imma Grafström",
+    born: '1953'
+  },
+  hasse: {
+    name: "Hasse Strömberg",
+    born: '1955'
+  }
 };
 fixture.all = [
-    fixture.jonny,
-    fixture.martina,
-    fixture.angelica,
-    fixture.sebastian,
-    fixture.imma,
-    fixture.hasse
-];
\ No newline at end of file
+  fixture.jonny,
+  fixture.martina,
+  fixture.angelica,
+  fixture.sebastian,
+  fixture.imma,
+  fixture.hasse
+];
diff --git a/test/index.html b/test/index.html
index e5dfce5..89dcf54 100755
--- a/test/index.html
+++ b/test/index.html
@@ -1,56 +1,50 @@
 <html>
 <head>
-    <meta charset="utf-8">
-    <title>List.js Mocha Tests</title>
-    <link rel="stylesheet" href="../build/build.css" />
-    <style>
-        #list,
-        #parse-list,
-        .list {
-            margin-left:-1000px;
-        }
-    </style>
+  <meta charset="utf-8">
+  <title>List.js Mocha Tests</title>
+  <link rel="stylesheet" href="../node_modules/grunt-mocha/node_modules/mocha/mocha.css" />
+  <style>
+    #list,
+    #parse-list,
+    .list {
+      margin-left:-1000px;
+    }
+  </style>
 </head>
 <body>
 
-    <div id="mocha"></div>
-    <script src="../build/build.js"></script>
-    <script src="mocha.js"></script> <!-- this specific version is needed for grunt-mocha (wtf...) -->
+  <div id="mocha"></div>
+  <script src="../node_modules/jquery/dist/jquery.js"></script>
+  <script src="../dist/list.js"></script>
+  <script src="../node_modules/expect.js/index.js"></script>
+  <script src="../node_modules/grunt-mocha/node_modules/mocha/mocha.js"></script>
 
-    <script>
-        List = require('list.js');
-        $ = require('jquery');
+  <script>
+    mocha.setup('bdd');
+  </script>
 
-        if (navigator.userAgent.indexOf('PhantomJS') < 0) {
-            // This version is needed to not get "Out of stack space" error in IE
-            require('mocha');
-        }
+  <script src="fixtures.js"></script>
+  <script src="test.defaults.js"></script>
+  <script src="test.create.js"></script>
+  <script src="test.add-get-remove.js"></script>
+  <script src="test.item.js"></script>
+  <script src="test.filter.js"></script>
+  <script src="test.search.js"></script>
+  <script src="test.search-filter.js"></script>
+  <script src="test.show.js"></script>
+  <script src="test.on.js"></script>
+  <script src="test.off.js"></script>
+  <script src="test.trigger.js"></script>
+  <script src="test.re-index.js"></script>
 
-        mocha.setup('bdd');
-        expect = require('expect.js');
-    </script>
+  <script src="test.sort.js"></script>
+  <script src="test.buttons.js"></script>
+  <script src="test.parse.js"></script>
 
-    <script src="fixtures.js"></script>
-    <script src="test.defaults.js"></script>
-    <script src="test.create.js"></script>
-    <script src="test.add-get-remove.js"></script>
-    <script src="test.item.js"></script>
-    <script src="test.filter.js"></script>
-    <script src="test.search.js"></script>
-    <script src="test.search-filter.js"></script>
-    <script src="test.show.js"></script>
-    <script src="test.on.js"></script>
-    <script src="test.off.js"></script>
-    <script src="test.trigger.js"></script>
-
-    <script src="test.sort.js"></script>
-    <script src="test.buttons.js"></script>
-    <script src="test.parse.js"></script>
-
-    <script>
-        if (navigator.userAgent.indexOf('PhantomJS') < 0) {
-            mocha.run();
-        }
-    </script>
+  <script>
+    if (navigator.userAgent.indexOf('PhantomJS') < 0) {
+      mocha.run();
+    }
+  </script>
 </body>
 </html>
diff --git a/test/test.add-get-remove.js b/test/test.add-get-remove.js
index 4840298..9d806af 100644
--- a/test/test.add-get-remove.js
+++ b/test/test.add-get-remove.js
@@ -1,97 +1,119 @@
 describe('Add, get, remove', function() {
 
-    var list;
+  var list;
 
-    before(function() {
-        list = fixture.list(['name'], [ { name: "Jonny" } ]);
-    });
+  before(function() {
+    list = fixture.list(['name'], [ { name: "Jonny" } ]);
+  });
 
-    after(function() {
-        fixture.removeList();
-    });
+  after(function() {
+    fixture.removeList();
+  });
+
+  afterEach(function() {
+    list.clear();
+    list.add({ name: "Jonny" });
+  });
 
-    afterEach(function() {
-        list.clear();
-        list.add({ name: "Jonny" });
+  describe('Add', function() {
+    it('should add one item', function() {
+      list.add({ name: 'Jonas' });
+      expect(list.items.length).to.equal(2);
+    });
+    it('should add two items', function() {
+      list.add([
+        { name: 'Martina' },
+        { name: 'Angelica' }
+      ]);
+      expect(list.items.length).to.equal(3);
+    });
+    it('should add async items', function(done) {
+      list.add([
+{name:'Sven'},{name:'Sven'},{name:'Sven'},{name:'Sven'},{name:'Sven'},{name:'Sven'},
+{name:'Sven'},{name:'Sven'},{name:'Sven'},{name:'Sven'},{name:'Sven'},{name:'Sven'},
+{name:'Sven'},{name:'Sven'},{name:'Sven'},{name:'Sven'},{name:'Sven'},{name:'Sven'},
+{name:'Sven'},{name:'Sven'},{name:'Sven'},{name:'Sven'},{name:'Sven'},{name:'Sven'},
+{name:'Sven'},{name:'Sven'},{name:'Sven'},{name:'Sven'},{name:'Sven'},{name:'Sven'},
+{name:'Sven'},{name:'Sven'},{name:'Sven'},{name:'Sven'},{name:'Sven'},{name:'Sven'},
+{name:'Sven'},{name:'Sven'},{name:'Sven'},{name:'Sven'},{name:'Sven'},{name:'Sven'},
+{name:'Sven'},{name:'Sven'},{name:'Sven'},{name:'Sven'},{name:'Sven'},{name:'Sven'},
+{name:'Sven'},{name:'Sven'},{name:'Sven'},{name:'Sven'},{name:'Sven'},{name:'Sven'},
+{name:'Sven'},{name:'Sven'},{name:'Sven'},{name:'Sven'},{name:'Sven'},{name:'Sven'},
+{name:'Sven'},{name:'Sven'},{name:'Sven'},{name:'Sven'},{name:'Sven'},{name:'Sven'},
+{name:'Sven'},{name:'Sven'},{name:'Sven'},{name:'Sven'},{name:'Sven'},{name:'Sven'},
+{name:'Sven'},{name:'Sven'},{name:'Sven'},{name:'Sven'},{name:'Sven'},{name:'Sven'},
+{name:'Sven'},{name:'Sven'},{name:'Sven'},{name:'Sven'},{name:'Sven'},{name:'Sven'},
+{name:'Sven'},{name:'Sven'},{name:'Sven'},{name:'Sven'},{name:'Sven'},{name:'Sven'}
+      ], function() {
+        expect(list.items.length).to.equal(91);
+        done();
+      });
     });
+    it('should add async items to empty list', function(done) {
+      list.clear();
+      list.add([
+        { name: 'Sven' }
+      ], function() {
+        expect(list.items.length).to.equal(1);
+        done();
+      });
+    });
+  });
 
-    describe('Add', function() {
-        it('should add one item', function() {
-            list.add({ name: 'Jonas' });
-            expect(list.items.length).to.equal(2);
-        });
-        it('should add two items', function() {
-            list.add([
-                { name: 'Martina' },
-                { name: 'Angelica' }
-            ]);
-            expect(list.items.length).to.equal(3);
-        });
-        it('should add async items', function(done) {
-            list.add([
-                { name: 'Sven' }
-            ], function() {
-                expect(list.items.length).to.equal(2);
-                done();
-            });
-        });
-        it('should add async items to empty list', function(done) {
-            list.clear();
-            list.add([
-                { name: 'Sven' }
-            ], function() {
-                expect(list.items.length).to.equal(1);
-                done();
-            });
-        });
+  describe('Get', function() {
+    it('should return array with one item', function() {
+      var items = list.get('name', 'Jonny');
+      expect(items[0].values().name).to.equal('Jonny');
+    });
+    it('should return empty array', function() {
+      var items = list.get('name', 'jonny');
+      expect(items.length).to.be.zero;
+    });
+    it('should return two items', function() {
+      list.add({ name: 'Jonny' });
+      var items = list.get('name', 'Jonny');
+      expect(items.length).to.equal(2);
+      expect(items[0].values().name).to.equal('Jonny');
+      expect(items[1].values().name).to.equal('Jonny');
     });
+  });
 
-    describe('Get', function() {
-        it('should return array with one item', function() {
-            var items = list.get('name', 'Jonny');
-            expect(items[0].values().name).to.equal('Jonny');
-        });
-        it('should return empty array', function() {
-            var items = list.get('name', 'jonny');
-            expect(items.length).to.be.zero;
-        });
-        it('should return two items', function() {
-            list.add({ name: 'Jonny' });
-            var items = list.get('name', 'Jonny');
-            expect(items.length).to.equal(2);
-            expect(items[0].values().name).to.equal('Jonny');
-            expect(items[1].values().name).to.equal('Jonny');
-        });
+  describe('Remove', function() {
+    it('should remove one item', function() {
+      list.add({ name: "Jonas" });
+      expect(list.items.length).to.equal(2);
+      var count = list.remove('name', 'Jonas');
+      expect(count).to.equal(1);
+      expect(list.items.length).to.equal(1);
+    });
+    it('should not remove anything due to case sensitivity', function() {
+      var count = list.remove('name', 'jonny');
+      expect(count).to.be.equal(0);
+      expect(list.items.length).to.equal(1);
     });
 
-    describe('Remove', function() {
-        it('should remove one item', function() {
-            list.add({ name: "Jonas" });
-            expect(list.items.length).to.equal(2);
-            var count = list.remove('name', 'Jonas');
-            expect(count).to.equal(1);
-            expect(list.items.length).to.equal(1);
-        });
-        it('should not remove anything due to case sensitivity', function() {
-            var count = list.remove('name', 'jonny');
-            expect(count).to.be.equal(0);
-            expect(list.items.length).to.equal(1);
-        });
+    it('should avoid node not found error', function() {
+      var item = list.get('name', 'Jonny')[0];
+      list.list.removeChild(item.elm);
+      var count = list.remove('name', 'Jonny');
+      expect(count).to.be.equal(1);
+      expect(list.items.length).to.equal(0);
+    });
 
-        it('should remove eight items', function() {
-            list.add({ name: 'Jonny' });
-            list.add({ name: 'Jonny' });
-            list.add({ name: 'Sven' });
-            list.add({ name: 'Jonny' });
-            list.add({ name: 'Jonny' });
-            list.add({ name: 'Jonny' });
-            list.add({ name: 'Jonas' });
-            list.add({ name: 'Jonny' });
-            list.add({ name: 'Jonny' });
-            expect(list.items.length).to.equal(10);
-            var count = list.remove('name', 'Jonny');
-            expect(count).to.equal(8);
-            expect(list.items.length).to.equal(2);
-        });
+    it('should remove eight items', function() {
+      list.add({ name: 'Jonny' });
+      list.add({ name: 'Jonny' });
+      list.add({ name: 'Sven' });
+      list.add({ name: 'Jonny' });
+      list.add({ name: 'Jonny' });
+      list.add({ name: 'Jonny' });
+      list.add({ name: 'Jonas' });
+      list.add({ name: 'Jonny' });
+      list.add({ name: 'Jonny' });
+      expect(list.items.length).to.equal(10);
+      var count = list.remove('name', 'Jonny');
+      expect(count).to.equal(8);
+      expect(list.items.length).to.equal(2);
     });
+  });
 });
diff --git a/test/test.buttons.js b/test/test.buttons.js
index 012167e..1249b0b 100644
--- a/test/test.buttons.js
+++ b/test/test.buttons.js
@@ -1,191 +1,191 @@
 function fireKeyup(el) {
-    if (document.createEvent) {
-        var evObj;
-        if (window.KeyEvent) {
-            evObj = document.createEvent('KeyEvents');
-            evObj.initKeyEvent('keyup', true, true, window, false, false, false, false, 13, 0);
-        } else {
-            evObj = document.createEvent('UIEvents');
-            evObj.initUIEvent('keyup', true, true, window, 1);
-        }
-        el.dispatchEvent(evObj);
-    } else if( document.createEventObject ) {
-        el.fireEvent('onkeyup');
+  if (document.createEvent) {
+    var evObj;
+    if (window.KeyEvent) {
+      evObj = document.createEvent('KeyEvents');
+      evObj.initKeyEvent('keyup', true, true, window, false, false, false, false, 13, 0);
     } else {
-        // IE 5.0, seriously? :)
+      evObj = document.createEvent('UIEvents');
+      evObj.initUIEvent('keyup', true, true, window, 1);
     }
+    el.dispatchEvent(evObj);
+  } else if( document.createEventObject ) {
+    el.fireEvent('onkeyup');
+  } else {
+    // IE 5.0, seriously? :)
+  }
 }
 
 // http://stackoverflow.com/questions/5658849/whats-the-equivalent-of-jquerys-trigger-method-without-jquery
 function fireClick(el) {
-    var evt;
-    if (document.createEvent) {
-        evt = document.createEvent("MouseEvents");
-        evt.initMouseEvent("click", true, true, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
-    }
-    (evt) ? el.dispatchEvent(evt) : (el.click && el.click());
+  var evt;
+  if (document.createEvent) {
+    evt = document.createEvent("MouseEvents");
+    evt.initMouseEvent("click", true, true, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
+  }
+  (evt) ? el.dispatchEvent(evt) : (el.click && el.click());
 }
 
 describe('Button', function() {
 
-    var list;
+  var list;
 
-    beforeEach(function() {
-        $('body').append($('<div id="parse-list">\
-            <input class="search" />\
-            <span class="sort" id="sort-name" data-sort="name">Sort name</span>\
-            <span class="sort" id="sort-name-asc" data-sort="name" data-order="asc">Sort name asc</span>\
-            <span class="sort" id="sort-name-desc" data-sort="name" data-order="desc">Sort name desc</span>\
-            <div class="list">\
-                <div><span class="name">Jonny</span><span class="born">1986</span></div>\
-                <div><span class="name">Jocke</span><span class="born">1985</span></div>\
-            </div>\
-        </div>'));
+  beforeEach(function() {
+    $('body').append($('<div id="parse-list">\
+      <input class="search" />\
+      <span class="sort" id="sort-name" data-sort="name">Sort name</span>\
+      <span class="sort" id="sort-name-asc" data-sort="name" data-order="asc">Sort name asc</span>\
+      <span class="sort" id="sort-name-desc" data-sort="name" data-order="desc">Sort name desc</span>\
+      <div class="list">\
+        <div><span class="name">Jonny</span><span class="born">1986</span></div>\
+        <div><span class="name">Jocke</span><span class="born">1985</span></div>\
+      </div>\
+    </div>'));
 
-        list = new List('parse-list', {
-            valueNames: ['name', 'born']
-        });
+    list = new List('parse-list', {
+      valueNames: ['name', 'born']
     });
+  });
 
-    afterEach(function() {
-        $('#parse-list').remove();
+  afterEach(function() {
+    $('#parse-list').remove();
+  });
+
+  describe('Sort', function() {
+    it('should trigger sortStart', function(done) {
+      list.on('sortComplete', function() {
+        done();
+      });
+      fireClick($('#sort-name')[0]);
+    });
+    it('should trigger sortComplete', function(done) {
+      list.on('sortComplete', function() {
+        done();
+      });
+      fireClick($('#sort-name')[0]);
     });
 
-    describe('Sort', function() {
-        it('should trigger sortStart', function(done) {
-            list.on('sortComplete', function() {
-                done();
-            });
+    it('should switch sorting order when clicking multiple times', function(done) {
+      this.timeout(5000);
+      var sortRun = 0;
+      list.on('sortComplete', function() {
+        sortRun++;
+        if (sortRun == 1) {
+          expect($('#sort-name').hasClass('asc')).to.be(true);
+          expect($('#sort-name').hasClass('desc')).to.be(false);
+          setTimeout(function() {
             fireClick($('#sort-name')[0]);
-        });
-        it('should trigger sortComplete', function(done) {
-            list.on('sortComplete', function() {
-                done();
-            });
+          }, 50);
+        } else if (sortRun == 2) {
+          expect($('#sort-name').hasClass('asc')).to.be(false);
+          expect($('#sort-name').hasClass('desc')).to.be(true);
+          setTimeout(function() {
             fireClick($('#sort-name')[0]);
-        });
-
-        it('should switch sorting order when clicking multiple times', function(done) {
-            this.timeout(5000);
-            var sortRun = 0;
-            list.on('sortComplete', function() {
-                sortRun++;
-                if (sortRun == 1) {
-                    expect($('#sort-name').hasClass('asc')).to.be(true);
-                    expect($('#sort-name').hasClass('desc')).to.be(false);
-                    setTimeout(function() {
-                        fireClick($('#sort-name')[0]);
-                    }, 50);
-                } else if (sortRun == 2) {
-                    expect($('#sort-name').hasClass('asc')).to.be(false);
-                    expect($('#sort-name').hasClass('desc')).to.be(true);
-                    setTimeout(function() {
-                        fireClick($('#sort-name')[0]);
-                    }, 50);
-                } else if (sortRun == 3) {
-                    expect($('#sort-name').hasClass('asc')).to.be(true);
-                    expect($('#sort-name').hasClass('desc')).to.be(false);
-                    done();
-                }
-            });
-            expect($('#sort-name').hasClass('asc')).to.be(false);
-            expect($('#sort-name').hasClass('desc')).to.be(false);
-            fireClick($('#sort-name')[0]);
-        });
+          }, 50);
+        } else if (sortRun == 3) {
+          expect($('#sort-name').hasClass('asc')).to.be(true);
+          expect($('#sort-name').hasClass('desc')).to.be(false);
+          done();
+        }
+      });
+      expect($('#sort-name').hasClass('asc')).to.be(false);
+      expect($('#sort-name').hasClass('desc')).to.be(false);
+      fireClick($('#sort-name')[0]);
+    });
 
-        it('should sort with predefined order', function(done) {
-            this.timeout(10000);
-            var sortRun = 0;
-            list.on('sortComplete', function() {
-                sortRun++;
-                if (sortRun == 1) {
-                    expect($('#sort-name').hasClass('asc')).to.be(true);
-                    expect($('#sort-name').hasClass('desc')).to.be(false);
-                    expect($('#sort-name-asc').hasClass('asc')).to.be(true);
-                    expect($('#sort-name-asc').hasClass('desc')).to.be(false);
-                    expect($('#sort-name-desc').hasClass('asc')).to.be(false);
-                    expect($('#sort-name-desc').hasClass('desc')).to.be(false);
-                    setTimeout(function() {
-                        fireClick($('#sort-name-asc')[0]);
-                    }, 50);
-                } else if (sortRun == 2) {
-                    expect($('#sort-name').hasClass('asc')).to.be(true);
-                    expect($('#sort-name').hasClass('desc')).to.be(false);
-                    expect($('#sort-name-asc').hasClass('asc')).to.be(true);
-                    expect($('#sort-name-asc').hasClass('desc')).to.be(false);
-                    expect($('#sort-name-desc').hasClass('asc')).to.be(false);
-                    expect($('#sort-name-desc').hasClass('desc')).to.be(false);
-                    setTimeout(function() {
-                        fireClick($('#sort-name-asc')[0]);
-                    }, 50);
-                } else if (sortRun == 3) {
-                    expect($('#sort-name').hasClass('asc')).to.be(true);
-                    expect($('#sort-name').hasClass('desc')).to.be(false);
-                    expect($('#sort-name-asc').hasClass('asc')).to.be(true);
-                    expect($('#sort-name-asc').hasClass('desc')).to.be(false);
-                    expect($('#sort-name-desc').hasClass('asc')).to.be(false);
-                    expect($('#sort-name-desc').hasClass('desc')).to.be(false);
-                    setTimeout(function() {
-                        fireClick($('#sort-name-desc')[0]);
-                    }, 50);
-                } else if (sortRun == 4) {
-                    expect($('#sort-name').hasClass('asc')).to.be(false);
-                    expect($('#sort-name').hasClass('desc')).to.be(true);
-                    expect($('#sort-name-asc').hasClass('asc')).to.be(false);
-                    expect($('#sort-name-asc').hasClass('desc')).to.be(false);
-                    expect($('#sort-name-desc').hasClass('asc')).to.be(false);
-                    expect($('#sort-name-desc').hasClass('desc')).to.be(true);
-                    setTimeout(function() {
-                        fireClick($('#sort-name-desc')[0]);
-                    }, 50);
-                } else if (sortRun == 5) {
-                    expect($('#sort-name').hasClass('asc')).to.be(false);
-                    expect($('#sort-name').hasClass('desc')).to.be(true);
-                    expect($('#sort-name-asc').hasClass('asc')).to.be(false);
-                    expect($('#sort-name-asc').hasClass('desc')).to.be(false);
-                    expect($('#sort-name-desc').hasClass('asc')).to.be(false);
-                    expect($('#sort-name-desc').hasClass('desc')).to.be(true);
-                    done();
-                }
-            });
-            expect($('#sort-name').hasClass('asc')).to.be(false);
-            expect($('#sort-name').hasClass('desc')).to.be(false);
-            expect($('#sort-name-asc').hasClass('asc')).to.be(false);
-            expect($('#sort-name-asc').hasClass('desc')).to.be(false);
-            expect($('#sort-name-desc').hasClass('asc')).to.be(false);
-            expect($('#sort-name-desc').hasClass('desc')).to.be(false);
+    it('should sort with predefined order', function(done) {
+      this.timeout(10000);
+      var sortRun = 0;
+      list.on('sortComplete', function() {
+        sortRun++;
+        if (sortRun == 1) {
+          expect($('#sort-name').hasClass('asc')).to.be(true);
+          expect($('#sort-name').hasClass('desc')).to.be(false);
+          expect($('#sort-name-asc').hasClass('asc')).to.be(true);
+          expect($('#sort-name-asc').hasClass('desc')).to.be(false);
+          expect($('#sort-name-desc').hasClass('asc')).to.be(false);
+          expect($('#sort-name-desc').hasClass('desc')).to.be(false);
+          setTimeout(function() {
             fireClick($('#sort-name-asc')[0]);
-        });
-
-        it('buttons should change class when sorting programmatically', function(done) {
-            list.on('sortComplete', function() {
-                expect($('#sort-name').hasClass('asc')).to.be(true);
-                expect($('#sort-name').hasClass('desc')).to.be(false);
-                expect($('#sort-name-asc').hasClass('asc')).to.be(true);
-                expect($('#sort-name-asc').hasClass('desc')).to.be(false);
-                expect($('#sort-name-desc').hasClass('asc')).to.be(false);
-                expect($('#sort-name-desc').hasClass('desc')).to.be(false);
-                done();
-            });
-            list.sort('name', { order: "asc" });
-        })
+          }, 50);
+        } else if (sortRun == 2) {
+          expect($('#sort-name').hasClass('asc')).to.be(true);
+          expect($('#sort-name').hasClass('desc')).to.be(false);
+          expect($('#sort-name-asc').hasClass('asc')).to.be(true);
+          expect($('#sort-name-asc').hasClass('desc')).to.be(false);
+          expect($('#sort-name-desc').hasClass('asc')).to.be(false);
+          expect($('#sort-name-desc').hasClass('desc')).to.be(false);
+          setTimeout(function() {
+            fireClick($('#sort-name-asc')[0]);
+          }, 50);
+        } else if (sortRun == 3) {
+          expect($('#sort-name').hasClass('asc')).to.be(true);
+          expect($('#sort-name').hasClass('desc')).to.be(false);
+          expect($('#sort-name-asc').hasClass('asc')).to.be(true);
+          expect($('#sort-name-asc').hasClass('desc')).to.be(false);
+          expect($('#sort-name-desc').hasClass('asc')).to.be(false);
+          expect($('#sort-name-desc').hasClass('desc')).to.be(false);
+          setTimeout(function() {
+            fireClick($('#sort-name-desc')[0]);
+          }, 50);
+        } else if (sortRun == 4) {
+          expect($('#sort-name').hasClass('asc')).to.be(false);
+          expect($('#sort-name').hasClass('desc')).to.be(true);
+          expect($('#sort-name-asc').hasClass('asc')).to.be(false);
+          expect($('#sort-name-asc').hasClass('desc')).to.be(false);
+          expect($('#sort-name-desc').hasClass('asc')).to.be(false);
+          expect($('#sort-name-desc').hasClass('desc')).to.be(true);
+          setTimeout(function() {
+            fireClick($('#sort-name-desc')[0]);
+          }, 50);
+        } else if (sortRun == 5) {
+          expect($('#sort-name').hasClass('asc')).to.be(false);
+          expect($('#sort-name').hasClass('desc')).to.be(true);
+          expect($('#sort-name-asc').hasClass('asc')).to.be(false);
+          expect($('#sort-name-asc').hasClass('desc')).to.be(false);
+          expect($('#sort-name-desc').hasClass('asc')).to.be(false);
+          expect($('#sort-name-desc').hasClass('desc')).to.be(true);
+          done();
+        }
+      });
+      expect($('#sort-name').hasClass('asc')).to.be(false);
+      expect($('#sort-name').hasClass('desc')).to.be(false);
+      expect($('#sort-name-asc').hasClass('asc')).to.be(false);
+      expect($('#sort-name-asc').hasClass('desc')).to.be(false);
+      expect($('#sort-name-desc').hasClass('asc')).to.be(false);
+      expect($('#sort-name-desc').hasClass('desc')).to.be(false);
+      fireClick($('#sort-name-asc')[0]);
     });
 
+    it('buttons should change class when sorting programmatically', function(done) {
+      list.on('sortComplete', function() {
+        expect($('#sort-name').hasClass('asc')).to.be(true);
+        expect($('#sort-name').hasClass('desc')).to.be(false);
+        expect($('#sort-name-asc').hasClass('asc')).to.be(true);
+        expect($('#sort-name-asc').hasClass('desc')).to.be(false);
+        expect($('#sort-name-desc').hasClass('asc')).to.be(false);
+        expect($('#sort-name-desc').hasClass('desc')).to.be(false);
+        done();
+      });
+      list.sort('name', { order: "asc" });
+    })
+  });
+
 
-    describe('Search', function() {
-        it('should trigger searchStart', function(done) {
-            list.on('searchStart', function() {
-                done();
-            });
-            $('#parse-list .search').val('jon');
-            fireKeyup($('#parse-list .search')[0]);
-        });
-        it('should trigger searchComplete', function(done) {
-            list.on('searchComplete', function() {
-                done();
-            });
-            $('#parse-list .search').val('jon');
-            fireKeyup($('#parse-list .search')[0]);
-        });
+  describe('Search', function() {
+    it('should trigger searchStart', function(done) {
+      list.on('searchStart', function() {
+        done();
+      });
+      $('#parse-list .search').val('jon');
+      fireKeyup($('#parse-list .search')[0]);
+    });
+    it('should trigger searchComplete', function(done) {
+      list.on('searchComplete', function() {
+        done();
+      });
+      $('#parse-list .search').val('jon');
+      fireKeyup($('#parse-list .search')[0]);
     });
+  });
 });
diff --git a/test/test.create.js b/test/test.create.js
index 3d3cf37..96e2cc7 100644
--- a/test/test.create.js
+++ b/test/test.create.js
@@ -1,89 +1,189 @@
 describe('Create', function() {
 
-    describe('With HTML items', function() {
-        var listEl = $('<div id="list">\
-            <ul class="list">\
-                <li><span class="name">Jonny</span></li>\
-            </ul>\
-        </div>');
+  describe('With HTML items', function() {
+    var listEl = $('<div id="list">\
+      <ul class="list">\
+        <li><span class="name">Jonny</span></li>\
+      </ul>\
+    </div>');
 
-        $(document.body).append(listEl);
+    $(document.body).append(listEl);
 
-        var list = new List('list', { valueNames: ['name'] });
+    var list = new List('list', { valueNames: ['name'] });
 
-        it('should contain one item', function() {
-            expect(list.items.length).to.equal(1);
-            expect(listEl.find('li').size()).to.equal(1);
-        });
-
-        it('should contain two items', function() {
-            list.add({ name: 'Jonas' });
-            expect(list.items.length).to.equal(2);
-            expect(listEl.find('li').size()).to.equal(2);
-        });
+    it('should contain one item', function() {
+      expect(list.items.length).to.equal(1);
+      expect(listEl.find('li').size()).to.equal(1);
+    });
 
-        listEl.remove();
+    it('should contain two items', function() {
+      list.add({ name: 'Jonas' });
+      expect(list.items.length).to.equal(2);
+      expect(listEl.find('li').size()).to.equal(2);
     });
 
-    describe('Without items and with string template', function() {
-        var listEl = $('<div id="list">\
-            <ul class="list"></ul>\
-        </div>');
+    listEl.remove();
+  });
 
-        $(document.body).append(listEl);
+  describe('Without items and with string template', function() {
+    var listEl = $('<div id="list">\
+      <ul class="list"></ul>\
+    </div>');
 
-        var list = new List('list', {
-            valueNames: ['name'],
-            item: '<li><span class="name"></span></li>'
-        }, [
-            { name: 'Jonny' }
-        ]);
+    $(document.body).append(listEl);
 
-        it('should contain one item', function() {
-            expect(list.items.length).to.equal(1);
-            expect(listEl.find('li').size()).to.equal(1);
-        });
+    var list = new List('list', {
+      valueNames: ['name'],
+      item: '<li><span class="name"></span></li>'
+    }, [
+      { name: 'Jonny' }
+    ]);
 
-        it('should contain two items', function() {
-            list.add({ name: 'Jonas' });
-            expect(list.items.length).to.equal(2);
-            expect(listEl.find('li').size()).to.equal(2);
-        });
+    it('should contain one item', function() {
+      expect(list.items.length).to.equal(1);
+      expect(listEl.find('li').size()).to.equal(1);
+    });
 
-        listEl.remove();
+    it('should contain two items', function() {
+      list.add({ name: 'Jonas' });
+      expect(list.items.length).to.equal(2);
+      expect(listEl.find('li').size()).to.equal(2);
     });
 
-    describe('Without items and with HTML template', function() {
-        var listEl = $('<div id="list">\
-            <ul class="list"></ul>\
-        </div>');
+    listEl.remove();
+  });
 
-        var templateEl = $('<li id="template-item"><span class="name"></span></li>');
+  describe('Without items and with HTML template', function() {
+    var listEl = $('<div id="list">\
+      <ul class="list"></ul>\
+    </div>');
 
-        $(document.body).append(listEl);
-        $(document.body).append(templateEl);
+    var templateEl = $('<li id="template-item"><span class="name"></span></li>');
 
-        var list = new List('list', {
-            valueNames: ['name'],
-            item: 'template-item'
-        }, [
-            { name: 'Jonny' }
-        ]);
+    $(document.body).append(listEl);
+    $(document.body).append(templateEl);
 
-        it('should contain one item', function() {
-            expect(list.items.length).to.equal(1);
-            expect(listEl.find('li').size()).to.equal(1);
-        });
+    var list = new List('list', {
+      valueNames: ['name'],
+      item: 'template-item'
+    }, [
+      { name: 'Jonny' }
+    ]);
 
-        it('should contain two items', function() {
-            list.add({ name: 'Jonas' });
-            expect(list.items.length).to.equal(2);
-            expect(listEl.find('li').size()).to.equal(2);
-        });
+    it('should contain one item', function() {
+      expect(list.items.length).to.equal(1);
+      expect(listEl.find('li').size()).to.equal(1);
+    });
 
-        listEl.remove();
-        templateEl.remove();
+    it('should contain two items', function() {
+      list.add({ name: 'Jonas' });
+      expect(list.items.length).to.equal(2);
+      expect(listEl.find('li').size()).to.equal(2);
     });
 
+    listEl.remove();
+    templateEl.remove();
+  });
+
+  describe('Asyn index with existing list', function() {
+    var listEl = $('<div id="list">\
+      <ul class="list">\
+        <li><span class="name">Jonny</span></li><li><span class="name">Sven</span></li>\
+        <li><span class="name">Anna</span></li><li><span class="name">Lisa</span></li>\
+        <li><span class="name">Egon</span></li><li><span class="name">Frida</span></li>\
+        <li><span class="name">Maj-britt</span></li><li><span class="name">Fredrik</span></li>\
+        <li><span class="name">Torbjorn</span></li><li><span class="name">Lolzor</span></li>\
+        <li><span class="name">Sandra</span></li><li><span class="name">Gottfrid</span></li>\
+        <li><span class="name">Tobias</span></li><li><span class="name">Martina</span></li>\
+        <li><span class="name">Johannes</span></li><li><span class="name">Ted</span></li>\
+        <li><span class="name">Malin</span></li><li><span class="name">Filippa</span></li>\
+        <li><span class="name">Imma</span></li><li><span class="name">Hasse</span></li>\
+        <li><span class="name">Robert</span></li><li><span class="name">Mona</span></li>\
+        <li><span class="name">Anna</span></li><li><span class="name">Lisa</span></li>\
+        <li><span class="name">Egon</span></li><li><span class="name">Frida</span></li>\
+        <li><span class="name">Maj-britt</span></li><li><span class="name">Fredrik</span></li>\
+        <li><span class="name">Torbjorn</span></li><li><span class="name">Lolzor</span></li>\
+        <li><span class="name">Sandra</span></li><li><span class="name">Gottfrid</span></li>\
+        <li><span class="name">Tobias</span></li><li><span class="name">Martina</span></li>\
+        <li><span class="name">Johannes</span></li><li><span class="name">Ted</span></li>\
+        <li><span class="name">Malin</span></li><li><span class="name">Filippa</span></li>\
+        <li><span class="name">Imma</span></li><li><span class="name">Hasse</span></li>\
+        <li><span class="name">Robert</span></li><li><span class="name">Mona</span></li>\
+        <li><span class="name">Anna</span></li><li><span class="name">Lisa</span></li>\
+        <li><span class="name">Egon</span></li><li><span class="name">Frida</span></li>\
+        <li><span class="name">Maj-britt</span></li><li><span class="name">Fredrik</span></li>\
+        <li><span class="name">Torbjorn</span></li><li><span class="name">Lolzor</span></li>\
+        <li><span class="name">Sandra</span></li><li><span class="name">Gottfrid</span></li>\
+        <li><span class="name">Tobias</span></li><li><span class="name">Martina</span></li>\
+        <li><span class="name">Johannes</span></li><li><span class="name">Ted</span></li>\
+        <li><span class="name">Malin</span></li><li><span class="name">Filippa</span></li>\
+        <li><span class="name">Imma</span></li><li><span class="name">Hasse</span></li>\
+        <li><span class="name">Robert</span></li><li><span class="name">Mona</span></li>\
+        <li><span class="name">Anna</span></li><li><span class="name">Lisa</span></li>\
+        <li><span class="name">Egon</span></li><li><span class="name">Frida</span></li>\
+        <li><span class="name">Maj-britt</span></li><li><span class="name">Fredrik</span></li>\
+        <li><span class="name">Torbjorn</span></li><li><span class="name">Lolzor</span></li>\
+        <li><span class="name">Sandra</span></li><li><span class="name">Gottfrid</span></li>\
+        <li><span class="name">Tobias</span></li><li><span class="name">Martina</span></li>\
+        <li><span class="name">Johannes</span></li><li><span class="name">Ted</span></li>\
+        <li><span class="name">Malin</span></li><li><span class="name">Filippa</span></li>\
+        <li><span class="name">Imma</span></li><li><span class="name">Hasse</span></li>\
+        <li><span class="name">Robert</span></li><li><span class="name">Mona</span></li>\
+        <li><span class="name">Anna</span></li><li><span class="name">Lisa</span></li>\
+        <li><span class="name">Egon</span></li><li><span class="name">Frida</span></li>\
+        <li><span class="name">Maj-britt</span></li><li><span class="name">Fredrik</span></li>\
+        <li><span class="name">Torbjorn</span></li><li><span class="name">Lolzor</span></li>\
+        <li><span class="name">Sandra</span></li><li><span class="name">Gottfrid</span></li>\
+        <li><span class="name">Tobias</span></li><li><span class="name">Martina</span></li>\
+        <li><span class="name">Johannes</span></li><li><span class="name">Ted</span></li>\
+        <li><span class="name">Malin</span></li><li><span class="name">Filippa</span></li>\
+        <li><span class="name">Imma</span></li><li><span class="name">Hasse</span></li>\
+        <li><span class="name">Robert</span></li><li><span class="name">Mona</span></li>\
+        <li><span class="name">Anna</span></li><li><span class="name">Lisa</span></li>\
+        <li><span class="name">Egon</span></li><li><span class="name">Frida</span></li>\
+        <li><span class="name">Maj-britt</span></li><li><span class="name">Fredrik</span></li>\
+        <li><span class="name">Torbjorn</span></li><li><span class="name">Lolzor</span></li>\
+        <li><span class="name">Sandra</span></li><li><span class="name">Gottfrid</span></li>\
+        <li><span class="name">Tobias</span></li><li><span class="name">Martina</span></li>\
+        <li><span class="name">Johannes</span></li><li><span class="name">Ted</span></li>\
+        <li><span class="name">Malin</span></li><li><span class="name">Filippa</span></li>\
+        <li><span class="name">Imma</span></li><li><span class="name">Hasse</span></li>\
+        <li><span class="name">Robert</span></li><li><span class="name">Mona</span></li>\
+        <li><span class="name">Anna</span></li><li><span class="name">Lisa</span></li>\
+        <li><span class="name">Egon</span></li><li><span class="name">Frida</span></li>\
+        <li><span class="name">Maj-britt</span></li><li><span class="name">Fredrik</span></li>\
+        <li><span class="name">Torbjorn</span></li><li><span class="name">Lolzor</span></li>\
+        <li><span class="name">Sandra</span></li><li><span class="name">Gottfrid</span></li>\
+        <li><span class="name">Tobias</span></li><li><span class="name">Martina</span></li>\
+        <li><span class="name">Johannes</span></li><li><span class="name">Ted</span></li>\
+        <li><span class="name">Malin</span></li><li><span class="name">Filippa</span></li>\
+        <li><span class="name">Imma</span></li><li><span class="name">Hasse</span></li>\
+        <li><span class="name">Robert</span></li><li><span class="name">Mona</span></li>\
+        <li><span class="name">Anna</span></li><li><span class="name">Lisa</span></li>\
+        <li><span class="name">Egon</span></li><li><span class="name">Frida</span></li>\
+        <li><span class="name">Maj-britt</span></li><li><span class="name">Fredrik</span></li>\
+        <li><span class="name">Torbjorn</span></li><li><span class="name">Lolzor</span></li>\
+        <li><span class="name">Sandra</span></li><li><span class="name">Gottfrid</span></li>\
+        <li><span class="name">Tobias</span></li><li><span class="name">Martina</span></li>\
+        <li><span class="name">Johannes</span></li><li><span class="name">Ted</span></li>\
+        <li><span class="name">Malin</span></li><li><span class="name">Filippa</span></li>\
+        <li><span class="name">Imma</span></li><li><span class="name">Hasse</span></li>\
+        <li><span class="name">Robert</span></li><li><span class="name">Mona</span></li>\
+      </ul>\
+    </div>');
+
+    it('should contain one item', function(done) {
+      $(document.body).append(listEl);
+      var list = new List('list', {
+        valueNames: ['name'],
+        indexAsync: true,
+        parseComplete: function(list) {
+          expect(listEl.find('li').size()).to.equal(162);
+          listEl.remove();
+          done();
+        }
+      });
+    });
+  });
 
-});
\ No newline at end of file
+});
diff --git a/test/test.defaults.js b/test/test.defaults.js
index 7908551..0f3940c 100644
--- a/test/test.defaults.js
+++ b/test/test.defaults.js
@@ -1,65 +1,64 @@
 describe('Defaults', function() {
-    var list;
+  var list;
 
-    before(function() {
-        list = fixture.list(['name'], [ { name: 'Jonny' }]);
-    });
+  before(function() {
+    list = fixture.list(['name'], [ { name: 'Jonny' }]);
+  });
 
-    after(function() {
-        fixture.removeList();
-    });
+  after(function() {
+    fixture.removeList();
+  });
 
-    it('should have all default attributes', function() {
-        expect(list.items).to.be.an('array');
-        expect(list.visibleItems).to.be.an('array');
-        expect(list.matchingItems).to.be.an('array');
+  it('should have all default attributes', function() {
+    expect(list.items).to.be.an('array');
+    expect(list.visibleItems).to.be.an('array');
+    expect(list.matchingItems).to.be.an('array');
 
-        expect(list.handlers.updated).to.be.an('array');
-        expect(list.handlers.searchStart).to.be.an('array');
-        expect(list.handlers.searchComplete).to.be.an('array');
-        expect(list.handlers.sortStart).to.be.an('array');
-        expect(list.handlers.sortComplete).to.be.an('array');
-        expect(list.handlers.filterStart).to.be.an('array');
-        expect(list.handlers.filterComplete).to.be.an('array');
+    expect(list.handlers.updated).to.be.an('array');
+    expect(list.handlers.searchStart).to.be.an('array');
+    expect(list.handlers.searchComplete).to.be.an('array');
+    expect(list.handlers.sortStart).to.be.an('array');
+    expect(list.handlers.sortComplete).to.be.an('array');
+    expect(list.handlers.filterStart).to.be.an('array');
+    expect(list.handlers.filterComplete).to.be.an('array');
 
-        expect(list.searched).to.be(false);
-        expect(list.filtered).to.be(false);
-        expect(list.i).to.equal(1);
-        expect(list.page).to.equal(200);
-        expect(list.listClass).to.equal('list');
-        expect(list.sortClass).to.equal('sort');
-        expect(list.searchClass).to.equal('search');
-        expect(list.page).to.equal(200);
-    });
+    expect(list.searched).to.be(false);
+    expect(list.filtered).to.be(false);
+    expect(list.i).to.equal(1);
+    expect(list.page).to.equal(10000);
+    expect(list.listClass).to.equal('list');
+    expect(list.sortClass).to.equal('sort');
+    expect(list.searchClass).to.equal('search');
+  });
 
-    it('should have the right elements', function() {
-        expect(list.list).to.equal($('.list')[0]);
-        expect(list.listContainer).to.equal($('#list')[0]);
-    });
+  it('should have the right elements', function() {
+    expect(list.list).to.equal($('.list')[0]);
+    expect(list.listContainer).to.equal($('#list')[0]);
+  });
 
-    it('should have all default methods', function() {
-        expect(list.add).to.be.a('function');
-        expect(list.remove).to.be.a('function');
-        expect(list.get).to.be.a('function');
-        expect(list.sort).to.be.a('function');
-        expect(list.search).to.be.a('function');
-        expect(list.clear).to.be.a('function');
-        expect(list.filter).to.be.a('function');
-        expect(list.size).to.be.a('function');
-        expect(list.show).to.be.a('function');
-        expect(list.update).to.be.a('function');
-        expect(list.on).to.be.a('function');
-    });
+  it('should have all default methods', function() {
+    expect(list.add).to.be.a('function');
+    expect(list.remove).to.be.a('function');
+    expect(list.get).to.be.a('function');
+    expect(list.sort).to.be.a('function');
+    expect(list.search).to.be.a('function');
+    expect(list.clear).to.be.a('function');
+    expect(list.filter).to.be.a('function');
+    expect(list.size).to.be.a('function');
+    expect(list.show).to.be.a('function');
+    expect(list.update).to.be.a('function');
+    expect(list.on).to.be.a('function');
+  });
 
-    it('should have all helper methods', function() {
-        expect(list.helpers.classes).to.be.a('function');
-        expect(list.helpers.getAttribute).to.be.a('function');
-        expect(list.helpers.getByClass).to.be.a('function');
-        expect(list.helpers.naturalSort).to.be.a('function');
-        expect(list.helpers.events.bind).to.be.a('function');
-        expect(list.helpers.events.unbind).to.be.a('function');
-        expect(list.helpers.extend).to.be.a('function');
-        expect(list.helpers.indexOf).to.be.a('function');
-        expect(list.helpers.toString).to.be.a('function');
-    });
+  it('should have all helper methods', function() {
+    expect(list.utils.classes).to.be.a('function');
+    expect(list.utils.getAttribute).to.be.a('function');
+    expect(list.utils.getByClass).to.be.a('function');
+    expect(list.utils.naturalSort).to.be.a('function');
+    expect(list.utils.events.bind).to.be.a('function');
+    expect(list.utils.events.unbind).to.be.a('function');
+    expect(list.utils.extend).to.be.a('function');
+    expect(list.utils.indexOf).to.be.a('function');
+    expect(list.utils.toString).to.be.a('function');
+  });
 });
diff --git a/test/test.filter.js b/test/test.filter.js
index 21e693d..c6fe422 100644
--- a/test/test.filter.js
+++ b/test/test.filter.js
@@ -1,101 +1,101 @@
 describe('Filter', function() {
 
-    var list, jonny, martina, angelica, sebastian, imma, hasse;
+  var list, jonny, martina, angelica, sebastian, imma, hasse;
 
-    before(function() {
-        list = fixture.list(['name', 'born'], fixture.all);
-        jonny = list.get('name', 'Jonny Strömberg')[0];
-        martina = list.get('name', 'Martina Elm')[0];
-        angelica = list.get('name', 'Angelica Abraham')[0];
-        sebastian = list.get('name', 'Sebastian Höglund')[0];
-        imma = list.get('name', 'Imma Grafström')[0];
-        hasse = list.get('name', 'Hasse Strömberg')[0];
-    });
+  before(function() {
+    list = fixture.list(['name', 'born'], fixture.all);
+    jonny = list.get('name', 'Jonny Strömberg')[0];
+    martina = list.get('name', 'Martina Elm')[0];
+    angelica = list.get('name', 'Angelica Abraham')[0];
+    sebastian = list.get('name', 'Sebastian Höglund')[0];
+    imma = list.get('name', 'Imma Grafström')[0];
+    hasse = list.get('name', 'Hasse Strömberg')[0];
+  });
 
-    after(function() {
-        fixture.removeList();
-    });
+  after(function() {
+    fixture.removeList();
+  });
 
-    afterEach(function() {
-        list.filter();
-        list.show(1, 200);
-    });
+  afterEach(function() {
+    list.filter();
+    list.show(1, 200);
+  });
 
-    describe('Basics', function() {
-        it('should return everyone born after 1988', function() {
-            var result = list.filter(function(item) {
-                return (item.values().born > 1988);
-            });
-            expect(result.length).to.equal(1);
-            expect(result[0]).to.eql(sebastian);
-        });
-        it('should return everyone born 1986', function() {
-            var result = list.filter(function(item) {
-                return (item.values().born == 1986);
-            });
-            expect(result.length).to.equal(3);
-            for (var i = 0; i < result.length; i++) {
-                expect(result[i].values().born).to.equal('1986');
-            }
-        });
+  describe('Basics', function() {
+    it('should return everyone born after 1988', function() {
+      var result = list.filter(function(item) {
+        return (item.values().born > 1988);
+      });
+      expect(result.length).to.equal(1);
+      expect(result[0]).to.eql(sebastian);
     });
+    it('should return everyone born 1986', function() {
+      var result = list.filter(function(item) {
+        return (item.values().born == 1986);
+      });
+      expect(result.length).to.equal(3);
+      for (var i = 0; i < result.length; i++) {
+        expect(result[i].values().born).to.equal('1986');
+      }
+    });
+  });
 
-    describe('Show and pages', function() {
-        it('should return the visible items', function() {
-            list.show(1,2);
-            var result = list.filter(function(item) {
-                return (item.values().born > 1985);
-            });
-            expect(result).to.eql(list.visibleItems);
-        });
+  describe('Show and pages', function() {
+    it('should return the visible items', function() {
+      list.show(1,2);
+      var result = list.filter(function(item) {
+        return (item.values().born > 1985);
+      });
+      expect(result).to.eql(list.visibleItems);
+    });
 
-        it('should return be 2 visible items and 3 matching', function() {
-            list.show(1,2);
-            var result = list.filter(function(item) {
-                return (item.values().born > 1985);
-            });
-            expect(result.length).to.equal(2);
-            expect(list.visibleItems.length).to.equal(2);
-            expect(list.matchingItems.length).to.equal(4);
-        });
+    it('should return be 2 visible items and 3 matching', function() {
+      list.show(1,2);
+      var result = list.filter(function(item) {
+        return (item.values().born > 1985);
+      });
+      expect(result.length).to.equal(2);
+      expect(list.visibleItems.length).to.equal(2);
+      expect(list.matchingItems.length).to.equal(4);
+    });
 
-        describe('Specific items', function() {
-            beforeEach(function() {
-                list.show(1,2);
-                var result = list.filter(function(item) {
-                    return (item.values().born > 1985);
-                });
-            });
-            it('should match jonny', function() {
-                expect(jonny.matching()).to.be(true);
-                expect(jonny.filtered).to.be(true);
-                expect(jonny.visible()).to.be(true);
-            });
-            it('should match martina', function() {
-                expect(martina.matching()).to.be(true);
-                expect(martina.filtered).to.be(true);
-                expect(martina.visible()).to.be(true);
-            });
-            it('should match but not show angelica', function() {
-                expect(angelica.matching()).to.be(true);
-                expect(angelica.filtered).to.be(true);
-                expect(angelica.visible()).to.be(false);
-            });
-            it('should match but not show sebastian', function() {
-                expect(sebastian.matching()).to.be(true);
-                expect(sebastian.filtered).to.be(true);
-                expect(sebastian.visible()).to.be(false);
-            });
-            it('should not match imma', function() {
-                expect(imma.matching()).to.be(false);
-                expect(imma.filtered).to.be(false);
-                expect(imma.visible()).to.be(false);
-            });
-            it('should not match hasse', function() {
-                expect(hasse.matching()).to.be(false);
-                expect(hasse.filtered).to.be(false);
-                expect(hasse.visible()).to.be(false);
-            });
+    describe('Specific items', function() {
+      beforeEach(function() {
+        list.show(1,2);
+        var result = list.filter(function(item) {
+          return (item.values().born > 1985);
         });
+      });
+      it('should match jonny', function() {
+        expect(jonny.matching()).to.be(true);
+        expect(jonny.filtered).to.be(true);
+        expect(jonny.visible()).to.be(true);
+      });
+      it('should match martina', function() {
+        expect(martina.matching()).to.be(true);
+        expect(martina.filtered).to.be(true);
+        expect(martina.visible()).to.be(true);
+      });
+      it('should match but not show angelica', function() {
+        expect(angelica.matching()).to.be(true);
+        expect(angelica.filtered).to.be(true);
+        expect(angelica.visible()).to.be(false);
+      });
+      it('should match but not show sebastian', function() {
+        expect(sebastian.matching()).to.be(true);
+        expect(sebastian.filtered).to.be(true);
+        expect(sebastian.visible()).to.be(false);
+      });
+      it('should not match imma', function() {
+        expect(imma.matching()).to.be(false);
+        expect(imma.filtered).to.be(false);
+        expect(imma.visible()).to.be(false);
+      });
+      it('should not match hasse', function() {
+        expect(hasse.matching()).to.be(false);
+        expect(hasse.filtered).to.be(false);
+        expect(hasse.visible()).to.be(false);
+      });
     });
+  });
 });
diff --git a/test/test.item.js b/test/test.item.js
index b025ba0..0de3e98 100644
--- a/test/test.item.js
+++ b/test/test.item.js
@@ -1,146 +1,146 @@
 describe('Item', function() {
 
-    var list, item;
+  var list, item;
 
-    before(function() {
-        list = fixture.list(['name', 'born', 'doin'], [{
-            name: "Jonny",
-            born: "1986",
-            doin: "Living the dream"
-        }]);
-        item = list.get('name', 'Jonny')[0];
-    });
+  before(function() {
+    list = fixture.list(['name', 'born', 'doin'], [{
+      name: "Jonny",
+      born: "1986",
+      doin: "Living the dream"
+    }]);
+    item = list.get('name', 'Jonny')[0];
+  });
 
 
-    beforeEach(function() {
-        list.search();
-        list.filter();
-        list.show(1,200);
-    });
+  beforeEach(function() {
+    list.search();
+    list.filter();
+    list.show(1,200);
+  });
 
-    after(function() {
-        fixture.removeList();
-    });
+  after(function() {
+    fixture.removeList();
+  });
 
-    describe('Defaults', function() {
-        it('should have all default attributes', function() {
-            expect(item.found).to.be(false);
-            expect(item.filtered).to.be(false);
-        });
+  describe('Defaults', function() {
+    it('should have all default attributes', function() {
+      expect(item.found).to.be(false);
+      expect(item.filtered).to.be(false);
+    });
 
-        it('should have the right elements', function() {
-            expect(item.elm).to.equal($('#list li')[0]);
-        });
+    it('should have the right elements', function() {
+      expect(item.elm).to.equal($('#list li')[0]);
+    });
 
-        it('should have all default methods', function() {
-            expect(item.hide).to.be.a('function');
-            expect(item.show).to.be.a('function');
-            expect(item.values).to.be.a('function');
-            expect(item.matching).to.be.a('function');
-            expect(item.visible).to.be.a('function');
-        });
+    it('should have all default methods', function() {
+      expect(item.hide).to.be.a('function');
+      expect(item.show).to.be.a('function');
+      expect(item.values).to.be.a('function');
+      expect(item.matching).to.be.a('function');
+      expect(item.visible).to.be.a('function');
     });
+  });
 
-    describe('Values()', function() {
-        it('should have the right values', function() {
-            expect(item.values()).to.eql({
-                name: 'Jonny',
-                born: '1986',
-                doin: 'Living the dream'
-            });
-        });
-        it('should be able to change one value', function() {
-            expect(item.values().name).to.be.equal('Jonny');
-            item.values({ name: 'Egon' });
-            expect(item.values().name).to.be.equal('Egon');
-        });
-        it('should be able to change many value', function() {
-            expect(item.values()).to.eql({
-                name: 'Egon',
-                born: '1986',
-                doin: 'Living the dream'
-            });
-            item.values({
-                name: 'Sven',
-                born: '1801',
-                doin: 'Is dead'
-            });
-            expect(item.values()).to.eql({
-                name: 'Sven',
-                born: '1801',
-                doin: 'Is dead'
-            });
-        });
+  describe('Values()', function() {
+    it('should have the right values', function() {
+      expect(item.values()).to.eql({
+        name: 'Jonny',
+        born: '1986',
+        doin: 'Living the dream'
+      });
+    });
+    it('should be able to change one value', function() {
+      expect(item.values().name).to.be.equal('Jonny');
+      item.values({ name: 'Egon' });
+      expect(item.values().name).to.be.equal('Egon');
     });
+    it('should be able to change many value', function() {
+      expect(item.values()).to.eql({
+        name: 'Egon',
+        born: '1986',
+        doin: 'Living the dream'
+      });
+      item.values({
+        name: 'Sven',
+        born: '1801',
+        doin: 'Is dead'
+      });
+      expect(item.values()).to.eql({
+        name: 'Sven',
+        born: '1801',
+        doin: 'Is dead'
+      });
+    });
+  });
 
-    describe('Hide, show, visible', function() {
-        it('should be hidden', function() {
-            expect($('#list li').size()).to.equal(1);
-            item.hide();
-            expect(item.visible()).to.be(false);
-            expect($('#list li').size()).to.equal(0);
-        });
-        it('should be visible', function() {
-            item.hide();
-            expect($('#list li').size()).to.equal(0);
-            item.show();
-            expect(item.visible()).to.be(true);
-            expect($('#list li').size()).to.equal(1);
-        });
+  describe('Hide, show, visible', function() {
+    it('should be hidden', function() {
+      expect($('#list li').size()).to.equal(1);
+      item.hide();
+      expect(item.visible()).to.be(false);
+      expect($('#list li').size()).to.equal(0);
     });
+    it('should be visible', function() {
+      item.hide();
+      expect($('#list li').size()).to.equal(0);
+      item.show();
+      expect(item.visible()).to.be(true);
+      expect($('#list li').size()).to.equal(1);
+    });
+  });
 
-    describe('Matching, found, filtered', function() {
-        describe('Searching', function() {
-            it('should not be visible, match, found or filtered', function() {
-                list.search('Fredrik');
-                expect(item.matching()).to.be(false);
-                expect(item.found).to.be(false);
-                expect(item.filtered).to.be(false);
-                expect(item.visible()).to.be(false);
-            });
-            it('should be visble, match and found but not filterd', function() {
-                var result = list.search('Sven');
-                expect(item.matching()).to.be(true);
-                expect(item.found).to.be(true);
-                expect(item.filtered).to.be(false);
-                expect(item.visible()).to.be(true);
-            });
-            it('reset: should be visible and matching but not found or filtered', function() {
-                list.search();
-                expect(item.matching()).to.be(true);
-                expect(item.found).to.be(false);
-                expect(item.filtered).to.be(false);
-                expect(item.visible()).to.be(true);
-            });
+  describe('Matching, found, filtered', function() {
+    describe('Searching', function() {
+      it('should not be visible, match, found or filtered', function() {
+        list.search('Fredrik');
+        expect(item.matching()).to.be(false);
+        expect(item.found).to.be(false);
+        expect(item.filtered).to.be(false);
+        expect(item.visible()).to.be(false);
+      });
+      it('should be visble, match and found but not filterd', function() {
+        var result = list.search('Sven');
+        expect(item.matching()).to.be(true);
+        expect(item.found).to.be(true);
+        expect(item.filtered).to.be(false);
+        expect(item.visible()).to.be(true);
+      });
+      it('reset: should be visible and matching but not found or filtered', function() {
+        list.search();
+        expect(item.matching()).to.be(true);
+        expect(item.found).to.be(false);
+        expect(item.filtered).to.be(false);
+        expect(item.visible()).to.be(true);
+      });
+    });
+    describe('Filtering', function() {
+      it('should not be visble, match, found or filtered', function() {
+        list.filter(function(item) {
+          return (item.values().name == "Fredrik");
         });
-        describe('Filtering', function() {
-            it('should not be visble, match, found or filtered', function() {
-                list.filter(function(item) {
-                    return (item.values().name == "Fredrik");
-                });
-                expect(item.matching()).to.be(false);
-                expect(item.found).to.be(false);
-                expect(item.filtered).to.be(false);
-                expect(item.visible()).to.be(false);
-            });
-            it('should be visble, match and filtered but not found', function() {
-                list.filter(function(item) {
-                    return (item.values().name == "Sven");
-                });
-                expect(item.matching()).to.be(true);
-                expect(item.found).to.be(false);
-                expect(item.filtered).to.be(true);
-                expect(item.visible()).to.be(true);
-            });
-            it('reset: should be visble and match but not filtered or found', function() {
-                list.filter();
-                expect(item.matching()).to.be(true);
-                expect(item.found).to.be(false);
-                expect(item.filtered).to.be(false);
-                expect(item.visible()).to.be(true);
-            });
+        expect(item.matching()).to.be(false);
+        expect(item.found).to.be(false);
+        expect(item.filtered).to.be(false);
+        expect(item.visible()).to.be(false);
+      });
+      it('should be visble, match and filtered but not found', function() {
+        list.filter(function(item) {
+          return (item.values().name == "Sven");
         });
+        expect(item.matching()).to.be(true);
+        expect(item.found).to.be(false);
+        expect(item.filtered).to.be(true);
+        expect(item.visible()).to.be(true);
+      });
+      it('reset: should be visble and match but not filtered or found', function() {
+        list.filter();
+        expect(item.matching()).to.be(true);
+        expect(item.found).to.be(false);
+        expect(item.filtered).to.be(false);
+        expect(item.visible()).to.be(true);
+      });
     });
+  });
 
-    fixture.removeList();
+  fixture.removeList();
 });
diff --git a/test/test.off.js b/test/test.off.js
index b8bad4e..5d1449e 100644
--- a/test/test.off.js
+++ b/test/test.off.js
@@ -1,39 +1,39 @@
 describe('Off', function() {
 
-    var list;
+  var list;
 
-    before(function() {
-        list = fixture.list(['name', 'born'], fixture.all);
-    });
+  before(function() {
+    list = fixture.list(['name', 'born'], fixture.all);
+  });
 
-    after(function() {
-        fixture.removeList();
-    });
+  after(function() {
+    fixture.removeList();
+  });
 
-    describe('General', function() {
-        it('should be remove added handler', function(done) {
-            var updated = function(list) {
-                expect(list.handlers.updated.length).to.equal(1);
-                list.off('updated', updated);
-                expect(list.handlers.updated.length).to.equal(0);
-                done();
-            };
-            list.on('updated', updated);
-            list.search('jonny');
-        });
+  describe('General', function() {
+    it('should be remove added handler', function(done) {
+      var updated = function(list) {
+        expect(list.handlers.updated.length).to.equal(1);
+        list.off('updated', updated);
+        expect(list.handlers.updated.length).to.equal(0);
+        done();
+      };
+      list.on('updated', updated);
+      list.search('jonny');
+    });
 
-        it('should not remove unnamed handlers', function(done) {
-            var searchComplete = function(list) {
-                expect(list.handlers.searchComplete.length).to.equal(3);
-                list.off('searchComplete', function() {});
-                list.off('searchComplete', searchComplete);
-                expect(list.handlers.searchComplete.length).to.equal(2);
-                done();
-            };
-            list.on('searchComplete', function() {});
-            list.on('searchComplete', searchComplete);
-            list.on('searchComplete', function() {});
-            list.search('jonny');
-        });
+    it('should not remove unnamed handlers', function(done) {
+      var searchComplete = function(list) {
+        expect(list.handlers.searchComplete.length).to.equal(3);
+        list.off('searchComplete', function() {});
+        list.off('searchComplete', searchComplete);
+        expect(list.handlers.searchComplete.length).to.equal(2);
+        done();
+      };
+      list.on('searchComplete', function() {});
+      list.on('searchComplete', searchComplete);
+      list.on('searchComplete', function() {});
+      list.search('jonny');
     });
+  });
 });
diff --git a/test/test.on.js b/test/test.on.js
index b170254..faca353 100644
--- a/test/test.on.js
+++ b/test/test.on.js
@@ -1,123 +1,123 @@
 describe('On', function() {
 
-    var list;
+  var list;
 
-    beforeEach(function() {
-        list = fixture.list(['name', 'born'], fixture.all);
-    });
+  beforeEach(function() {
+    list = fixture.list(['name', 'born'], fixture.all);
+  });
 
-    afterEach(function() {
-        fixture.removeList();
-    });
+  afterEach(function() {
+    fixture.removeList();
+  });
 
-    describe('Updated', function() {
-        it('should be triggered after search', function(done) {
-            list.on('updated', function(list) {
-                done();
-            });
-            list.search('jonny');
-        });
-        it('should be triggered after sort', function(done) {
-            list.on('updated', function(list) {
-                done();
-            });
-            list.sort('name');
-        });
-        it('should be triggered after filter', function(done) {
-            list.on('updated', function(list) {
-                done();
-            });
-            list.filter(function() {
-                return true;
-            });
-        });
-        it('should be triggered after show', function(done) {
-            list.on('updated', function(list) {
-                done();
-            });
-            list.show(1,10);
-        });
+  describe('Updated', function() {
+    it('should be triggered after search', function(done) {
+      list.on('updated', function(list) {
+        done();
+      });
+      list.search('jonny');
+    });
+    it('should be triggered after sort', function(done) {
+      list.on('updated', function(list) {
+        done();
+      });
+      list.sort('name');
+    });
+    it('should be triggered after filter', function(done) {
+      list.on('updated', function(list) {
+        done();
+      });
+      list.filter(function() {
+        return true;
+      });
+    });
+    it('should be triggered after show', function(done) {
+      list.on('updated', function(list) {
+        done();
+      });
+      list.show(1,10);
+    });
 
-        it('should be triggered after add', function(done) {
-            list.on('updated', function(list) {
-                done();
-            });
-            list.add({ name: 'Hej' });
-        });
-        it('should be triggered after remove', function(done) {
-            list.on('updated', function(list) {
-                done();
-            });
-            list.remove('name', 'Jonny');
-        });
+    it('should be triggered after add', function(done) {
+      list.on('updated', function(list) {
+        done();
+      });
+      list.add({ name: 'Hej' });
+    });
+    it('should be triggered after remove', function(done) {
+      list.on('updated', function(list) {
+        done();
+      });
+      list.remove('name', 'Jonny');
     });
+  });
 
-    describe('Multiple handlers', function() {
-        it('should be trigger both handlers', function(done) {
-            var done1 = false,
-                done2 = false,
-                isDone = function() {
-                    if (done1 && done2) {
-                        done();
-                    }
-                };
+  describe('Multiple handlers', function() {
+    it('should be trigger both handlers', function(done) {
+      var done1 = false,
+        done2 = false,
+        isDone = function() {
+          if (done1 && done2) {
+            done();
+          }
+        };
 
-            list.on('updated', function(list) {
-                done1 = true;
-                isDone();
-            });
-            list.on('updated', function(list) {
-                done2 = true;
-                isDone();
-            });
-            list.search('jonny');
-        });
+      list.on('updated', function(list) {
+        done1 = true;
+        isDone();
+      });
+      list.on('updated', function(list) {
+        done2 = true;
+        isDone();
+      });
+      list.search('jonny');
     });
+  });
 
-    describe('Search', function() {
-        it('should be triggered before and after search', function(done) {
-            var done1 = false;
-            list.on('searchStart', function(list) {
-                done1 = true;
-            });
-            list.on('searchComplete', function(list) {
-                if (done1) {
-                    done();
-                }
-            });
-            list.search('jonny');
-        });
+  describe('Search', function() {
+    it('should be triggered before and after search', function(done) {
+      var done1 = false;
+      list.on('searchStart', function(list) {
+        done1 = true;
+      });
+      list.on('searchComplete', function(list) {
+        if (done1) {
+          done();
+        }
+      });
+      list.search('jonny');
     });
+  });
 
-    describe('Sort', function() {
-        it('should be triggered before and after sort', function(done) {
-            var done1 = false;
-            list.on('sortStart', function(list) {
-                done1 = true;
-            });
-            list.on('sortComplete', function(list) {
-                if (done1) {
-                    done();
-                }
-            });
-            list.sort('name');
-        });
+  describe('Sort', function() {
+    it('should be triggered before and after sort', function(done) {
+      var done1 = false;
+      list.on('sortStart', function(list) {
+        done1 = true;
+      });
+      list.on('sortComplete', function(list) {
+        if (done1) {
+          done();
+        }
+      });
+      list.sort('name');
     });
+  });
 
-    describe('Filter', function() {
-        it('should be triggered before and after filter', function(done) {
-            var done1 = false;
-            list.on('filterStart', function(list) {
-                done1 = true;
-            });
-            list.on('filterComplete', function(list) {
-                if (done1) {
-                    done();
-                }
-            });
-            list.filter(function() {
-                return true;
-            });
-        });
+  describe('Filter', function() {
+    it('should be triggered before and after filter', function(done) {
+      var done1 = false;
+      list.on('filterStart', function(list) {
+        done1 = true;
+      });
+      list.on('filterComplete', function(list) {
+        if (done1) {
+          done();
+        }
+      });
+      list.filter(function() {
+        return true;
+      });
     });
+  });
 });
diff --git a/test/test.parse.js b/test/test.parse.js
index 463099f..117107d 100644
--- a/test/test.parse.js
+++ b/test/test.parse.js
@@ -1,48 +1,119 @@
 describe('Parse', function() {
 
+  describe('Parse class', function() {
     var list;
+    beforeEach(function() {
+      $('body').append($('<div id="parse-list">\
+        <div class="list">\
+          <div><span class="name">Jonny</span><span class="born">1986</span></div>\
+          <div><span class="name">Jocke</span><span class="born">1985</span></div>\
+        </div>\
+      </div>'));
 
-    before(function() {
-        $('body').append($('<div id="parse-list">\
-            <div class="list">\
-                <div><span class="name">Jonny</span><span class="born">1986</span></div>\
-                <div><span class="name">Jocke</span><span class="born">1985</span></div>\
-            </div>\
-        </div>'));
-
-        list = new List('parse-list', {
-            valueNames: ['name', 'born']
-        });
-    });
-
-    after(function() {
-        $('#parse-list').remove();
-    });
-
-    describe('Parse', function() {
-        it('should have two items', function() {
-            expect(list.items.length).to.equal(2);
-            expect(list.items[0].values().name).to.equal("Jonny");
-            expect(list.items[1].values().name).to.equal("Jocke");
-        });
-        it('should add item to parsed list', function() {
-            list.add({ name: "Sven", born: 1950 });
-            expect(list.items.length).to.equal(3);
-            expect(list.items[0].values().name).to.equal("Jonny");
-            expect(list.items[1].values().name).to.equal("Jocke");
-            expect(list.items[2].values().name).to.equal("Sven");
-            expect(list.items[0].values().born).to.equal("1986");
-            expect(list.items[2].values().born).to.equal(1950);
-            var el = $($('#parse-list').find('.list div')[2]);
-            expect(el.find('span').size()).to.equal(2);
-            expect(el.find('span.name').text()).to.equal('Sven');
-            expect(el.find('span.born').text()).to.equal('1950');
-        });
-        it('should parsed value always be string while added could be number', function() {
-            expect(list.items[0].values().born).to.equal("1986");
-            expect(list.items[0].values().born).not.to.equal(1986);
-            expect(list.items[2].values().born).not.to.equal("1950");
-            expect(list.items[2].values().born).to.equal(1950);
-        });
+      list = new List('parse-list', {
+        valueNames: ['name', 'born']
+      });
     });
+
+    afterEach(function() {
+      $('#parse-list').remove();
+    });
+
+    it('should have two items', function() {
+      expect(list.items.length).to.equal(2);
+      expect(list.items[0].values().name).to.equal("Jonny");
+      expect(list.items[1].values().name).to.equal("Jocke");
+    });
+    it('should add item to parsed list', function() {
+      list.add({ name: "Sven", born: 1950 });
+      expect(list.items.length).to.equal(3);
+      expect(list.items[0].values().name).to.equal("Jonny");
+      expect(list.items[1].values().name).to.equal("Jocke");
+      expect(list.items[2].values().name).to.equal("Sven");
+      expect(list.items[0].values().born).to.equal("1986");
+      expect(list.items[2].values().born).to.equal(1950);
+      var el = $($('#parse-list').find('.list div')[2]);
+      expect(el.find('span').size()).to.equal(2);
+      expect(el.find('span.name').text()).to.equal('Sven');
+      expect(el.find('span.born').text()).to.equal('1950');
+    });
+    it('should parsed value always be string while added could be number', function() {
+      list.add({ name: "Sven", born: 1950 });
+      expect(list.items[0].values().born).to.equal("1986");
+      expect(list.items[0].values().born).not.to.equal(1986);
+      expect(list.items[2].values().born).not.to.equal("1950");
+      expect(list.items[2].values().born).to.equal(1950);
+    });
+  });
+
+  describe('Parse data', function() {
+
+    var list;
+
+    beforeEach(function() {
+      $('body').append($('<div id="parse-list">\
+        <div class="list">\
+          <div data-id="1">\
+            <a href="http://lol.com" class="link name">Jonny</a>\
+            <span class="born timestamp" data-timestamp="54321">1986</span>\
+            <img class="image" src="jonny.jpg">\
+            <input class="foo" value="Bar">\
+          </div>\
+          <div data-id="2">\
+            <a href="http://lol.com" class="link name">Jocke</a>\
+            <span class="born timestamp" data-timestamp="12345">1985</span>\
+            <img class="image" src="jocke.png">\
+            <input class="foo child" value="Car">\
+          </div>\
+        </div>\
+      </div>'));
+
+      list = new List('parse-list', {
+        valueNames: [
+          'name',
+          'born',
+          { data: [ 'id' ] },
+          { attr: 'src', name: 'image'},
+          { attr: 'href', name: 'link'},
+          { attr: 'value', name: 'foo'},
+          { attr: 'data-timestamp', name: 'timestamp' }
+        ]
+      });
+    });
+
+    afterEach(function() {
+      $('#parse-list').remove();
+    });
+
+    it('should get values from class, data, src, value and child els data-attribute', function() {
+      expect(list.items.length).to.equal(2);
+      var jonny = list.items[0].values()
+      expect(jonny.name).to.equal("Jonny");
+      expect(jonny.born).to.equal("1986");
+      expect(jonny.id).to.equal("1");
+      expect(jonny.image).to.equal("jonny.jpg");
+      expect(jonny.timestamp).to.equal("54321");
+      expect(jonny.foo).to.equal("Bar");
+    });
+    it('should add item to list with class, data and src', function() {
+      list.add({ name: "Sven", born: 1950, id: 4, image: 'sven.gif', link: 'localhost', timestamp: '1337', foo: 'hej' });
+      expect(list.items.length).to.equal(3);
+      var sven = list.items[2].values();
+      expect(sven.name).to.equal("Sven");
+      expect(sven.born).to.equal(1950);
+      expect(sven.id).to.equal(4);
+      expect(sven.image).to.equal("sven.gif");
+      expect(sven.link).to.equal("localhost");
+      expect(sven.timestamp).to.equal("1337");
+      expect(sven.foo).to.equal("hej");
+      var el = $($('#parse-list').find('.list div')[2]);
+      expect(el.data('id')).to.equal(4);
+      expect(el.find('.name').text()).to.equal('Sven');
+      expect(el.find('.born').text()).to.equal('1950');
+      expect(el.find('.image').attr('src')).to.equal('sven.gif');
+      expect(el.find('.link').attr('href')).to.equal('localhost');
+      expect(el.find('.timestamp').data('timestamp')).to.equal(1337);
+      expect(el.find('.foo').val()).to.equal('hej');
+    });
+  });
 });
diff --git a/test/test.re-index.js b/test/test.re-index.js
new file mode 100644
index 0000000..ad04f85
--- /dev/null
+++ b/test/test.re-index.js
@@ -0,0 +1,34 @@
+describe('ReIndex', function() {
+
+  var list, jonny, martina, angelica, sebastian, imma, hasse;
+
+  before(function() {
+    list = fixture.list(['name', 'born'], fixture.all);
+  });
+
+  after(function() {
+    fixture.removeList();
+  });
+
+  afterEach(function() {
+    list.show(1, 200);
+  });
+  it('should return everyone born after 1988', function() {
+    expect(list.toJSON()).to.eql([
+      { name: "Jonny Strömberg", born: '1986' },
+      { name: "Martina Elm", born: '1986' },
+      { name: "Angelica Abraham", born: '1986' },
+      { name: "Sebastian Höglund", born: '1989' },
+      { name: "Imma Grafström", born: '1953' },
+      { name: "Hasse Strömberg", born: '1955' }
+    ]);
+    var newHtml = '<li><span class="name">Sven</span><span class="born">2013</span>';
+    newHtml = newHtml + '<li><span class="name">Anna</span><span class="born">3043</span>'
+    $(list.list).html(newHtml);
+    list.reIndex();
+    expect(list.toJSON()).to.eql([
+      { name: "Sven", born: '2013' },
+      { name: "Anna", born: '3043' }
+    ]);
+  });
+});
diff --git a/test/test.search-filter.js b/test/test.search-filter.js
index c0643e3..3b9af3e 100644
--- a/test/test.search-filter.js
+++ b/test/test.search-filter.js
@@ -1,66 +1,66 @@
 describe('Search and filter', function() {
 
-    var list, jonny, martina, angelica, sebastian, imma, hasse;
+  var list, jonny, martina, angelica, sebastian, imma, hasse;
 
-    before(function() {
-        list = fixture.list(['name', 'born'], fixture.all);
+  before(function() {
+    list = fixture.list(['name', 'born'], fixture.all);
 
-        jonny = list.get('name', 'Jonny Strömberg')[0];
-        martina = list.get('name', 'Martina Elm')[0];
-        angelica = list.get('name', 'Angelica Abraham')[0];
-        sebastian = list.get('name', 'Sebastian Höglund')[0];
-        imma = list.get('name', 'Imma Grafström')[0];
-        hasse = list.get('name', 'Hasse Strömberg')[0];
-    });
+    jonny = list.get('name', 'Jonny Strömberg')[0];
+    martina = list.get('name', 'Martina Elm')[0];
+    angelica = list.get('name', 'Angelica Abraham')[0];
+    sebastian = list.get('name', 'Sebastian Höglund')[0];
+    imma = list.get('name', 'Imma Grafström')[0];
+    hasse = list.get('name', 'Hasse Strömberg')[0];
+  });
 
-    after(function() {
-        fixture.removeList();
-    });
+  after(function() {
+    fixture.removeList();
+  });
 
-    afterEach(function() {
-        list.search();
-        list.filter();
-    });
+  afterEach(function() {
+    list.search();
+    list.filter();
+  });
 
-    describe('Search with filter', function() {
-        it('should find everyone born 1986', function() {
-            list.filter(function(item) {
-                return (item.values().born == '1986');
-            });
-            expect(list.matchingItems.length).to.equal(3);
-            expect(jonny.matching()).to.be(true);
-            expect(martina.matching()).to.be(true);
-            expect(angelica.matching()).to.be(true);
-            expect(sebastian.matching()).to.be(false);
-            expect(imma.matching()).to.be(false);
-            expect(hasse.matching()).to.be(false);
-        });
-        it('should find everyone born 1986 and containes "ö"', function() {
-            list.filter(function(item) {
-                return (item.values().born == '1986');
-            });
-            list.search('ö');
-            expect(list.matchingItems.length).to.equal(1);
-            expect(jonny.matching()).to.be(true);
-            expect(martina.matching()).to.be(false);
-            expect(angelica.matching()).to.be(false);
-            expect(sebastian.matching()).to.be(false);
-            expect(imma.matching()).to.be(false);
-            expect(hasse.matching()).to.be(false);
-        });
-        it('should find everyone with a "ö"', function() {
-            list.filter(function(item) {
-                return (item.values().born == '1986');
-            });
-            list.search('ö');
-            list.filter();
-            expect(list.matchingItems.length).to.equal(4);
-            expect(jonny.matching()).to.be(true);
-            expect(martina.matching()).to.be(false);
-            expect(angelica.matching()).to.be(false);
-            expect(sebastian.matching()).to.be(true);
-            expect(imma.matching()).to.be(true);
-            expect(hasse.matching()).to.be(true);
-        });
+  describe('Search with filter', function() {
+    it('should find everyone born 1986', function() {
+      list.filter(function(item) {
+        return (item.values().born == '1986');
+      });
+      expect(list.matchingItems.length).to.equal(3);
+      expect(jonny.matching()).to.be(true);
+      expect(martina.matching()).to.be(true);
+      expect(angelica.matching()).to.be(true);
+      expect(sebastian.matching()).to.be(false);
+      expect(imma.matching()).to.be(false);
+      expect(hasse.matching()).to.be(false);
+    });
+    it('should find everyone born 1986 and containes "ö"', function() {
+      list.filter(function(item) {
+        return (item.values().born == '1986');
+      });
+      list.search('ö');
+      expect(list.matchingItems.length).to.equal(1);
+      expect(jonny.matching()).to.be(true);
+      expect(martina.matching()).to.be(false);
+      expect(angelica.matching()).to.be(false);
+      expect(sebastian.matching()).to.be(false);
+      expect(imma.matching()).to.be(false);
+      expect(hasse.matching()).to.be(false);
+    });
+    it('should find everyone with a "ö"', function() {
+      list.filter(function(item) {
+        return (item.values().born == '1986');
+      });
+      list.search('ö');
+      list.filter();
+      expect(list.matchingItems.length).to.equal(4);
+      expect(jonny.matching()).to.be(true);
+      expect(martina.matching()).to.be(false);
+      expect(angelica.matching()).to.be(false);
+      expect(sebastian.matching()).to.be(true);
+      expect(imma.matching()).to.be(true);
+      expect(hasse.matching()).to.be(true);
     });
+  });
 });
diff --git a/test/test.search.js b/test/test.search.js
index 69426e9..c98fc53 100644
--- a/test/test.search.js
+++ b/test/test.search.js
@@ -1,114 +1,148 @@
 describe('Search', function() {
 
-    var list, jonny, martina, angelica, sebastian, imma, hasse;
+  var list, jonny, martina, angelica, sebastian, imma, hasse;
 
-    beforeEach(function() {
-        list = fixture.list(['name', 'born'], fixture.all);
+  beforeEach(function() {
+    list = fixture.list(['name', 'born'], fixture.all);
 
-        jonny = list.get('name', 'Jonny Strömberg')[0];
-        martina = list.get('name', 'Martina Elm')[0];
-        angelica = list.get('name', 'Angelica Abraham')[0];
-        sebastian = list.get('name', 'Sebastian Höglund')[0];
-        imma = list.get('name', 'Imma Grafström')[0];
-        hasse = list.get('name', 'Hasse Strömberg')[0];
+    jonny = list.get('name', 'Jonny Strömberg')[0];
+    martina = list.get('name', 'Martina Elm')[0];
+    angelica = list.get('name', 'Angelica Abraham')[0];
+    sebastian = list.get('name', 'Sebastian Höglund')[0];
+    imma = list.get('name', 'Imma Grafström')[0];
+    hasse = list.get('name', 'Hasse Strömberg')[0];
+  });
+
+  afterEach(function() {
+    fixture.removeList();
+  });
+
+  describe('Case-sensitive', function() {
+    it('should not be case-sensitive', function() {
+      var result = list.search('jonny');
+      expect(result.length).to.equal(1);
+      expect(result[0]).to.eql(jonny);
     });
+  });
 
-    afterEach(function() {
-        fixture.removeList();
+  describe('Number of results', function() {
+    it('should find jonny, martina, angelice', function() {
+      var result = list.search('1986');
+      expect(result.length).to.equal(3); // 3!!
+      expect(jonny.matching()).to.be(true);
+      expect(martina.matching()).to.be(true);
+      expect(angelica.matching()).to.be(true);
+      expect(sebastian.matching()).to.be(false);
+      expect(imma.matching()).to.be(false);
+      expect(hasse.matching()).to.be(false);
+    });
+    it('should find all with utf-8 char ö', function() {
+      var result = list.search('ö');
+      expect(result.length).to.equal(4); // 4!!
+      expect(jonny.matching()).to.be(true);
+      expect(martina.matching()).to.be(false);
+      expect(angelica.matching()).to.be(false);
+      expect(sebastian.matching()).to.be(true);
+      expect(imma.matching()).to.be(true);
+      expect(hasse.matching()).to.be(true);
     });
+    it('should not break with weird searches', function() {
+      expect(list.search).withArgs(undefined).to.not.throwException();
+      expect(list.search).withArgs(null).to.not.throwException();
+      expect(list.search).withArgs(0).to.not.throwException();
+      expect(list.search).withArgs(function() {}).to.not.throwException();
+      expect(list.search).withArgs({ foo: "bar" }).to.not.throwException();
+    });
+    it('should not break with weird values', function() {
+      jonny.values({ name: undefined });
+      martina.values({ name: null });
+      angelica.values({ name: 0 });
+      sebastian.values({ name: function() {} });
+      imma.values({ name: { foo: "bar" } });
 
-    describe('Case-sensitive', function() {
-        it('should not be case-sensitive', function() {
-            var result = list.search('jonny');
-            expect(result.length).to.equal(1);
-            expect(result[0]).to.eql(jonny);
-        });
+      expect(list.search).withArgs("jonny").to.not.throwException();
+      expect(list.search).withArgs(undefined).to.not.throwException();
+      expect(list.search).withArgs(null).to.not.throwException();
+      expect(list.search).withArgs(0).to.not.throwException();
+      expect(list.search).withArgs(function() {}).to.not.throwException();
+      expect(list.search).withArgs({ foo: "bar" }).to.not.throwException();
     });
+  });
 
-    describe('Number of results', function() {
-        it('should find jonny, martina, angelice', function() {
-            var result = list.search('1986');
-            expect(result.length).to.equal(3); // 3!!
-            expect(jonny.matching()).to.be(true);
-            expect(martina.matching()).to.be(true);
-            expect(angelica.matching()).to.be(true);
-            expect(sebastian.matching()).to.be(false);
-            expect(imma.matching()).to.be(false);
-            expect(hasse.matching()).to.be(false);
-        });
-        it('should find all with utf-8 char ö', function() {
-            var result = list.search('ö');
-            expect(result.length).to.equal(4); // 4!!
-            expect(jonny.matching()).to.be(true);
-            expect(martina.matching()).to.be(false);
-            expect(angelica.matching()).to.be(false);
-            expect(sebastian.matching()).to.be(true);
-            expect(imma.matching()).to.be(true);
-            expect(hasse.matching()).to.be(true);
-        });
-        it('should not break with weird searches', function() {
-            expect(list.search).withArgs(undefined).to.not.throwException();
-            expect(list.search).withArgs(null).to.not.throwException();
-            expect(list.search).withArgs(0).to.not.throwException();
-            expect(list.search).withArgs(function() {}).to.not.throwException();
-            expect(list.search).withArgs({ foo: "bar" }).to.not.throwException();
-        });
-        it('should not break with weird values', function() {
-            jonny.values({ name: undefined });
-            martina.values({ name: null });
-            angelica.values({ name: 0 });
-            sebastian.values({ name: function() {} });
-            imma.values({ name: { foo: "bar" } });
 
-            expect(list.search).withArgs("jonny").to.not.throwException();
-            expect(list.search).withArgs(undefined).to.not.throwException();
-            expect(list.search).withArgs(null).to.not.throwException();
-            expect(list.search).withArgs(0).to.not.throwException();
-            expect(list.search).withArgs(function() {}).to.not.throwException();
-            expect(list.search).withArgs({ foo: "bar" }).to.not.throwException();
-        });
+  describe('Default search columns', function() {
+    it('should find in the default match column', function() {
+      list.searchColumns = ['name'];
+      var result = list.search('jonny');
+      expect(result.length).to.equal(1);
+      expect(result[0]).to.eql(jonny);
+    });
+    it('should not find in the default match column', function() {
+      list.searchColumns = ['born'];
+      var result = list.search('jonny');
+      expect(result.length).to.equal(0);
     });
+  });
+
 
-    describe('Specfic columns', function() {
-        it('should find match in column', function() {
-            var result = list.search('jonny', [ 'name' ]);
-            expect(result.length).to.equal(1);
-            expect(result[0]).to.eql(jonny);
-        });
-        it('should not find match in column', function() {
-            var result = list.search('jonny', [ 'born' ]);
-            expect(result.length).to.equal(0);
-        });
-        it('should find match in column', function() {
-            var result = list.search('jonny', [ 'name' ]);
-            expect(result.length).to.equal(1);
-            expect(result[0]).to.eql(jonny);
-        });
-        it('should not find match in column', function() {
-            var result = list.search('jonny', [ 'born' ]);
-            expect(result.length).to.equal(0);
-        });
-        it('should work with columns that does not exist', function() {
-            var result = list.search('jonny', [ 'pet' ]);
-            expect(result.length).to.equal(0);
-        });
+  describe('Specfic columns', function() {
+    it('should find match in column', function() {
+      var result = list.search('jonny', [ 'name' ]);
+      expect(result.length).to.equal(1);
+      expect(result[0]).to.eql(jonny);
     });
+    it('should not find match in column', function() {
+      var result = list.search('jonny', [ 'born' ]);
+      expect(result.length).to.equal(0);
+    });
+    it('should find match in column', function() {
+      var result = list.search('jonny', [ 'name' ]);
+      expect(result.length).to.equal(1);
+      expect(result[0]).to.eql(jonny);
+    });
+    it('should not find match in column', function() {
+      var result = list.search('jonny', [ 'born' ]);
+      expect(result.length).to.equal(0);
+    });
+    it('should work with columns that does not exist', function() {
+      var result = list.search('jonny', [ 'pet' ]);
+      expect(result.length).to.equal(0);
+    });
+  });
 
-    describe('Custom search function', function() {
-        var customSearchFunction = function(searchString, columns) {
-            for (var k = 0, kl = list.items.length; k < kl; k++) {
-                if (list.items[k].values().born > 1985) {
-                    list.items[k].found = true;
-                }
-            }
-        };
-        it('should use custom function in third argument', function() {
-            var result = list.search('jonny', [ 'name' ], customSearchFunction);
-            expect(result.length).to.equal(4);
-        });
-        it('should use custom function in second argument', function() {
-            var result = list.search('jonny', customSearchFunction);
-            expect(result.length).to.equal(4);
-        });
+  describe('Custom search function', function() {
+    var customSearchFunction = function(searchString, columns) {
+      for (var k = 0, kl = list.items.length; k < kl; k++) {
+        if (list.items[k].values().born > 1985) {
+          list.items[k].found = true;
+        }
+      }
+    };
+    it('should use custom function in third argument', function() {
+      var result = list.search('jonny', [ 'name' ], customSearchFunction);
+      expect(result.length).to.equal(4);
+    });
+    it('should use custom function in second argument', function() {
+      var result = list.search('jonny', customSearchFunction);
+      expect(result.length).to.equal(4);
     });
+  });
+  //
+  // describe('Special characters', function() {
+  //   it('should escape and handle special characters', function() {
+  //     list.add([
+  //       { name: 'Jonny&Jabba' },
+  //       { name: '<Leia' },
+  //       { name: '>Luke' },
+  //       { name: '"Chewie"' },
+  //       { name: "'Ewok'" }
+  //     ]);
+  //     var result = list.search('Leia');
+  //     console.log(result);
+  //     expect(result.length).to.equal(1);
+  //     var result = list.search('<');
+  //     console.log(result);
+  //     expect(result.length).to.equal(1);
+  //   });
+  // });
 });
diff --git a/test/test.show.js b/test/test.show.js
index 23261ca..eb42ddb 100644
--- a/test/test.show.js
+++ b/test/test.show.js
@@ -1,208 +1,208 @@
 describe('Show', function() {
 
-    var list, a, b, c, d, e, f;
+  var list, a, b, c, d, e, f;
 
-    before(function() {
-        list = fixture.list(['id'], [
-            { id: "1", id2: "a" },
-            { id: "2", id2: "a" },
-            { id: "3", id2: "b" },
-            { id: "4", id2: "b" },
-            { id: "5", id2: "bc" },
-            { id: "6", id2: "bc" }
-        ]);
-        a = list.get('id', '1')[0];
-        b = list.get('id', '2')[0];
-        c = list.get('id', '3')[0];
-        d = list.get('id', '4')[0];
-        e = list.get('id', '5')[0];
-        f = list.get('id', '6')[0];
-    });
+  before(function() {
+    list = fixture.list(['id', 'id2'], [
+      { id: "1", id2: "a" },
+      { id: "2", id2: "a" },
+      { id: "3", id2: "b" },
+      { id: "4", id2: "b" },
+      { id: "5", id2: "bc" },
+      { id: "6", id2: "bc" }
+    ]);
+    a = list.get('id', '1')[0];
+    b = list.get('id', '2')[0];
+    c = list.get('id', '3')[0];
+    d = list.get('id', '4')[0];
+    e = list.get('id', '5')[0];
+    f = list.get('id', '6')[0];
+  });
+
+  after(function() {
+    fixture.removeList();
+  });
+
+  afterEach(function() {
+    list.filter();
+    list.show(1, 200);
+  });
 
-    after(function() {
-        fixture.removeList();
+  describe('Basics', function() {
+    it('should be 1, 2', function() {
+      list.show(1,2);
+      expect(list.visibleItems.length).to.equal(2);
+      expect(a.visible()).to.be(true);
+      expect(b.visible()).to.be(true);
+      expect(c.visible()).to.be(false);
+      expect(d.visible()).to.be(false);
+      expect(e.visible()).to.be(false);
+      expect(f.visible()).to.be(false);
+    });
+    it('should show item 6', function() {
+      list.show(6,2);
+      expect(list.visibleItems.length).to.equal(1);
+      expect(a.visible()).to.be(false);
+      expect(b.visible()).to.be(false);
+      expect(c.visible()).to.be(false);
+      expect(d.visible()).to.be(false);
+      expect(e.visible()).to.be(false);
+      expect(f.visible()).to.be(true);
+    });
+    it('should show item 1, 2, 3, 4, 5, 6', function() {
+      list.show(1,200);
+      expect(list.visibleItems.length).to.equal(6);
+      expect(a.visible()).to.be(true);
+      expect(b.visible()).to.be(true);
+      expect(c.visible()).to.be(true);
+      expect(d.visible()).to.be(true);
+      expect(e.visible()).to.be(true);
+      expect(f.visible()).to.be(true);
     });
+    it('should show item 3, 4, 5', function() {
+      list.show(3,3);
+      expect(list.visibleItems.length).to.equal(3);
+      expect(a.visible()).to.be(false);
+      expect(b.visible()).to.be(false);
+      expect(c.visible()).to.be(true);
+      expect(d.visible()).to.be(true);
+      expect(e.visible()).to.be(true);
+      expect(f.visible()).to.be(false);
+    });
+    it('should show item 5, 6', function() {
+      list.show(5,3);
+      expect(list.visibleItems.length).to.equal(2);
+      expect(a.visible()).to.be(false);
+      expect(b.visible()).to.be(false);
+      expect(c.visible()).to.be(false);
+      expect(d.visible()).to.be(false);
+      expect(e.visible()).to.be(true);
+      expect(f.visible()).to.be(true);
+    });
+  });
 
+  describe('Search', function() {
     afterEach(function() {
-        list.filter();
-        list.show(1, 200);
+      list.search();
     });
-
-    describe('Basics', function() {
-        it('should be 1, 2', function() {
-            list.show(1,2);
-            expect(list.visibleItems.length).to.equal(2);
-            expect(a.visible()).to.be(true);
-            expect(b.visible()).to.be(true);
-            expect(c.visible()).to.be(false);
-            expect(d.visible()).to.be(false);
-            expect(e.visible()).to.be(false);
-            expect(f.visible()).to.be(false);
-        });
-        it('should show item 6', function() {
-            list.show(6,2);
-            expect(list.visibleItems.length).to.equal(1);
-            expect(a.visible()).to.be(false);
-            expect(b.visible()).to.be(false);
-            expect(c.visible()).to.be(false);
-            expect(d.visible()).to.be(false);
-            expect(e.visible()).to.be(false);
-            expect(f.visible()).to.be(true);
-        });
-        it('should show item 1, 2, 3, 4, 5, 6', function() {
-            list.show(1,200);
-            expect(list.visibleItems.length).to.equal(6);
-            expect(a.visible()).to.be(true);
-            expect(b.visible()).to.be(true);
-            expect(c.visible()).to.be(true);
-            expect(d.visible()).to.be(true);
-            expect(e.visible()).to.be(true);
-            expect(f.visible()).to.be(true);
-        });
-        it('should show item 3, 4, 5', function() {
-            list.show(3,3);
-            expect(list.visibleItems.length).to.equal(3);
-            expect(a.visible()).to.be(false);
-            expect(b.visible()).to.be(false);
-            expect(c.visible()).to.be(true);
-            expect(d.visible()).to.be(true);
-            expect(e.visible()).to.be(true);
-            expect(f.visible()).to.be(false);
-        });
-        it('should show item 5, 6', function() {
-            list.show(5,3);
-            expect(list.visibleItems.length).to.equal(2);
-            expect(a.visible()).to.be(false);
-            expect(b.visible()).to.be(false);
-            expect(c.visible()).to.be(false);
-            expect(d.visible()).to.be(false);
-            expect(e.visible()).to.be(true);
-            expect(f.visible()).to.be(true);
-        });
+    it('should show 3, 4', function() {
+      list.search('b');
+      list.show(1,2);
+      expect(list.visibleItems.length).to.equal(2);
+      expect(a.visible()).to.be(false);
+      expect(b.visible()).to.be(false);
+      expect(c.visible()).to.be(true);
+      expect(d.visible()).to.be(true);
+      expect(e.visible()).to.be(false);
+      expect(f.visible()).to.be(false);
     });
-
-    describe('Search', function() {
-        afterEach(function() {
-            list.search();
-        });
-        it('should show 3, 4', function() {
-            list.search('b');
-            list.show(1,2);
-            expect(list.visibleItems.length).to.equal(2);
-            expect(a.visible()).to.be(false);
-            expect(b.visible()).to.be(false);
-            expect(c.visible()).to.be(true);
-            expect(d.visible()).to.be(true);
-            expect(e.visible()).to.be(false);
-            expect(f.visible()).to.be(false);
-        });
-        it('should show item 3,4,5,6', function() {
-            list.search('b');
-            list.show(1,4);
-            expect(list.visibleItems.length).to.equal(4);
-            expect(a.visible()).to.be(false);
-            expect(b.visible()).to.be(false);
-            expect(c.visible()).to.be(true);
-            expect(d.visible()).to.be(true);
-            expect(e.visible()).to.be(true);
-            expect(f.visible()).to.be(true);
-        });
-        it('should not show any items but match two', function() {
-            list.search('a');
-            list.show(3,2);
-            expect(list.visibleItems.length).to.equal(0);
-            expect(list.matchingItems.length).to.equal(2);
-            expect(a.visible()).to.be(false);
-            expect(b.visible()).to.be(false);
-            expect(c.visible()).to.be(false);
-            expect(d.visible()).to.be(false);
-            expect(e.visible()).to.be(false);
-            expect(f.visible()).to.be(false);
-        });
+    it('should show item 3,4,5,6', function() {
+      list.search('b');
+      list.show(1,4);
+      expect(list.visibleItems.length).to.equal(4);
+      expect(a.visible()).to.be(false);
+      expect(b.visible()).to.be(false);
+      expect(c.visible()).to.be(true);
+      expect(d.visible()).to.be(true);
+      expect(e.visible()).to.be(true);
+      expect(f.visible()).to.be(true);
     });
+    it('should not show any items but match two', function() {
+      list.search('a');
+      list.show(3,2);
+      expect(list.visibleItems.length).to.equal(0);
+      expect(list.matchingItems.length).to.equal(2);
+      expect(a.visible()).to.be(false);
+      expect(b.visible()).to.be(false);
+      expect(c.visible()).to.be(false);
+      expect(d.visible()).to.be(false);
+      expect(e.visible()).to.be(false);
+      expect(f.visible()).to.be(false);
+    });
+  });
 
-    describe('Filter', function() {
-        afterEach(function() {
-            list.filter();
-        });
-        it('should show 3, 4', function() {
-            list.filter(function(item) {
-                return (item.values().id2 == 'b');
-            });
-            list.show(1,2);
-            expect(list.visibleItems.length).to.equal(2);
-            expect(list.matchingItems.length).to.equal(2);
-            expect(a.visible()).to.be(false);
-            expect(b.visible()).to.be(false);
-            expect(c.visible()).to.be(true);
-            expect(d.visible()).to.be(true);
-            expect(e.visible()).to.be(false);
-            expect(f.visible()).to.be(false);
-        });
-        it('should show item 3,4,5,6', function() {
-            list.filter(function(item) {
-                return (item.values().id2 == 'bc');
-            });
-            list.show(1,4);
-            expect(list.visibleItems.length).to.equal(2);
-            expect(list.matchingItems.length).to.equal(2);
-            expect(a.visible()).to.be(false);
-            expect(b.visible()).to.be(false);
-            expect(c.visible()).to.be(false);
-            expect(d.visible()).to.be(false);
-            expect(e.visible()).to.be(true);
-            expect(f.visible()).to.be(true);
-        });
-        it('should not show any items but match two', function() {
-            list.filter(function(item) {
-                return (item.values().id2 == 'b');
-            });
-            list.show(3,2);
-            expect(list.visibleItems.length).to.equal(0);
-            expect(list.matchingItems.length).to.equal(2);
-            expect(a.visible()).to.be(false);
-            expect(b.visible()).to.be(false);
-            expect(c.visible()).to.be(false);
-            expect(d.visible()).to.be(false);
-            expect(e.visible()).to.be(false);
-            expect(f.visible()).to.be(false);
-        });
+  describe('Filter', function() {
+    afterEach(function() {
+      list.filter();
+    });
+    it('should show 3, 4', function() {
+      list.filter(function(item) {
+        return (item.values().id2 == 'b');
+      });
+      list.show(1,2);
+      expect(list.visibleItems.length).to.equal(2);
+      expect(list.matchingItems.length).to.equal(2);
+      expect(a.visible()).to.be(false);
+      expect(b.visible()).to.be(false);
+      expect(c.visible()).to.be(true);
+      expect(d.visible()).to.be(true);
+      expect(e.visible()).to.be(false);
+      expect(f.visible()).to.be(false);
+    });
+    it('should show item 3,4,5,6', function() {
+      list.filter(function(item) {
+        return (item.values().id2 == 'bc');
+      });
+      list.show(1,4);
+      expect(list.visibleItems.length).to.equal(2);
+      expect(list.matchingItems.length).to.equal(2);
+      expect(a.visible()).to.be(false);
+      expect(b.visible()).to.be(false);
+      expect(c.visible()).to.be(false);
+      expect(d.visible()).to.be(false);
+      expect(e.visible()).to.be(true);
+      expect(f.visible()).to.be(true);
     });
+    it('should not show any items but match two', function() {
+      list.filter(function(item) {
+        return (item.values().id2 == 'b');
+      });
+      list.show(3,2);
+      expect(list.visibleItems.length).to.equal(0);
+      expect(list.matchingItems.length).to.equal(2);
+      expect(a.visible()).to.be(false);
+      expect(b.visible()).to.be(false);
+      expect(c.visible()).to.be(false);
+      expect(d.visible()).to.be(false);
+      expect(e.visible()).to.be(false);
+      expect(f.visible()).to.be(false);
+    });
+  });
 
-    describe('Filter and search', function() {
-        afterEach(function() {
-            list.filter();
-        });
-        it('should show 4, 5', function() {
-            list.show(1,2);
-            list.filter(function(item) {
-                return (item.values().id > '3');
-            });
-            list.search('b');
-            expect(list.visibleItems.length).to.equal(2);
-            expect(list.matchingItems.length).to.equal(3);
-            expect(a.visible()).to.be(false);
-            expect(b.visible()).to.be(false);
-            expect(c.visible()).to.be(false);
-            expect(d.visible()).to.be(true);
-            expect(e.visible()).to.be(true);
-            expect(f.visible()).to.be(false);
-        });
-        it('should show 5, 6', function() {
-            list.show(1,2);
-            list.filter(function(item) {
-                return (item.values().id > '3');
-            });
-            list.search('b');
-            list.show(2,2);
-            expect(list.visibleItems.length).to.equal(2);
-            expect(list.matchingItems.length).to.equal(3);
-            expect(a.visible()).to.be(false);
-            expect(b.visible()).to.be(false);
-            expect(c.visible()).to.be(false);
-            expect(d.visible()).to.be(false);
-            expect(e.visible()).to.be(true);
-            expect(f.visible()).to.be(true);
-        });
+  describe('Filter and search', function() {
+    afterEach(function() {
+      list.filter();
+    });
+    it('should show 4, 5', function() {
+      list.show(1,2);
+      list.filter(function(item) {
+        return (item.values().id > '3');
+      });
+      list.search('b');
+      expect(list.visibleItems.length).to.equal(2);
+      expect(list.matchingItems.length).to.equal(3);
+      expect(a.visible()).to.be(false);
+      expect(b.visible()).to.be(false);
+      expect(c.visible()).to.be(false);
+      expect(d.visible()).to.be(true);
+      expect(e.visible()).to.be(true);
+      expect(f.visible()).to.be(false);
+    });
+    it('should show 5, 6', function() {
+      list.show(1,2);
+      list.filter(function(item) {
+        return (item.values().id > '3');
+      });
+      list.search('b');
+      list.show(2,2);
+      expect(list.visibleItems.length).to.equal(2);
+      expect(list.matchingItems.length).to.equal(3);
+      expect(a.visible()).to.be(false);
+      expect(b.visible()).to.be(false);
+      expect(c.visible()).to.be(false);
+      expect(d.visible()).to.be(false);
+      expect(e.visible()).to.be(true);
+      expect(f.visible()).to.be(true);
     });
+  });
 });
diff --git a/test/test.sort.js b/test/test.sort.js
index 8450b7e..0e9ca9c 100644
--- a/test/test.sort.js
+++ b/test/test.sort.js
@@ -1,320 +1,320 @@
 describe('Sort', function() {
 
-    var list, i1, i2, i3, i4, i5, i6;
+  var list, i1, i2, i3, i4, i5, i6;
 
-    beforeEach(function() {
-        list = fixture.list(['id'], [
-            { id: "1", val: "" },
-            { id: "2", val: "" },
-            { id: "3", val: "" },
-            { id: "4", val: "" },
-            { id: "5", val: "" },
-            { id: "6", val: "" }
-        ]);
-        i1 = list.get('id', '1')[0];
-        i2 = list.get('id', '2')[0];
-        i3 = list.get('id', '3')[0];
-        i4 = list.get('id', '4')[0];
-        i5 = list.get('id', '5')[0];
-        i6 = list.get('id', '6')[0];
-    });
+  beforeEach(function() {
+    list = fixture.list(['id'], [
+      { id: "1", val: "" },
+      { id: "2", val: "" },
+      { id: "3", val: "" },
+      { id: "4", val: "" },
+      { id: "5", val: "" },
+      { id: "6", val: "" }
+    ]);
+    i1 = list.get('id', '1')[0];
+    i2 = list.get('id', '2')[0];
+    i3 = list.get('id', '3')[0];
+    i4 = list.get('id', '4')[0];
+    i5 = list.get('id', '5')[0];
+    i6 = list.get('id', '6')[0];
+  });
 
-    afterEach(function() {
-        fixture.removeList();
-    });
+  afterEach(function() {
+    fixture.removeList();
+  });
 
-    describe('Basics', function() {
-        it('should sort letters asc', function() {
-            i1.values({ val: "b" });
-            i2.values({ val: "a" });
-            i3.values({ val: "c" });
-            i4.values({ val: "z" });
-            i5.values({ val: "s" });
-            i6.values({ val: "y" });
-            list.sort('val');
-            expect(list.items[0].values().val).to.be.equal("a");
-            expect(list.items[1].values().val).to.be.equal("b");
-            expect(list.items[2].values().val).to.be.equal("c");
-            expect(list.items[3].values().val).to.be.equal("s");
-            expect(list.items[4].values().val).to.be.equal("y");
-            expect(list.items[5].values().val).to.be.equal("z");
-        });
-        it('should sort letters desc', function() {
-            i1.values({ val: "b" });
-            i2.values({ val: "a" });
-            i3.values({ val: "c" });
-            i4.values({ val: "z" });
-            i5.values({ val: "s" });
-            i6.values({ val: "y" });
-            list.sort('val', { order: "desc" });
-            expect(list.items[0].values().val).to.be.equal("z");
-            expect(list.items[1].values().val).to.be.equal("y");
-            expect(list.items[2].values().val).to.be.equal("s");
-            expect(list.items[3].values().val).to.be.equal("c");
-            expect(list.items[4].values().val).to.be.equal("b");
-            expect(list.items[5].values().val).to.be.equal("a");
-        });
-        it('should fail to sort åäö desc (becomes äåö)', function() {
-            i1.values({ val: "a" });
-            i2.values({ val: "å" });
-            i3.values({ val: "ä" });
-            i4.values({ val: "ö" });
-            i5.values({ val: "o" });
-            i6.values({ val: "s" });
-            list.sort('val');
-            expect(list.items[0].values().val).to.be.equal("a");
-            expect(list.items[1].values().val).to.be.equal("o");
-            expect(list.items[2].values().val).to.be.equal("s");
-            expect(list.items[3].values().val).to.be.equal("ä");
-            expect(list.items[4].values().val).to.be.equal("å");
-            expect(list.items[5].values().val).to.be.equal("ö");
-        });
-        it('should fail to sort åäö asc (becomes öåä)', function() {
-            i1.values({ val: "a" });
-            i2.values({ val: "å" });
-            i3.values({ val: "ä" });
-            i4.values({ val: "ö" });
-            i5.values({ val: "o" });
-            i6.values({ val: "s" });
-            list.sort('val', { order: "desc" });
-            expect(list.items[0].values().val).to.be.equal("ö");
-            expect(list.items[1].values().val).to.be.equal("å");
-            expect(list.items[2].values().val).to.be.equal("ä");
-            expect(list.items[3].values().val).to.be.equal("s");
-            expect(list.items[4].values().val).to.be.equal("o");
-            expect(list.items[5].values().val).to.be.equal("a");
-        });
-        it('should handle case-insensitive by default', function() {
-            i1.values({ val: "e" });
-            i2.values({ val: "b" });
-            i4.values({ val: "F" });
-            i3.values({ val: "D" });
-            i5.values({ val: "A" });
-            i6.values({ val: "C" });
-            list.sort('val');
-            expect(list.items[0].values().val).to.be.equal("A");
-            expect(list.items[1].values().val).to.be.equal("b");
-            expect(list.items[2].values().val).to.be.equal("C");
-            expect(list.items[3].values().val).to.be.equal("D");
-            expect(list.items[4].values().val).to.be.equal("e");
-            expect(list.items[5].values().val).to.be.equal("F");
-        });
-        it('should disable insensitive', function() {
-            i1.values({ val: "e" });
-            i2.values({ val: "b" });
-            i4.values({ val: "F" });
-            i3.values({ val: "D" });
-            i5.values({ val: "A" });
-            i6.values({ val: "C" });
-            list.sort('val', { insensitive: false });
-            expect(list.items[0].values().val).to.be.equal("A");
-            expect(list.items[1].values().val).to.be.equal("C");
-            expect(list.items[2].values().val).to.be.equal("D");
-            expect(list.items[3].values().val).to.be.equal("F");
-            expect(list.items[4].values().val).to.be.equal("b");
-            expect(list.items[5].values().val).to.be.equal("e");
-        });
-        it('should sort dates', function() {
-            i1.values({ val: "10/12/2008" });
-            i2.values({ val: "10/11/2008" });
-            i3.values({ val: "10/11/2007" });
-            i4.values({ val: "10/12/2009" });
-            i5.values({ val: "4/01/2007" });
-            i6.values({ val: "10/12/2006" });
-            list.sort('val', { order: "asc" });
-            expect(list.items[0].values().val).to.be.equal("10/12/2006");
-            expect(list.items[1].values().val).to.be.equal("4/01/2007");
-            expect(list.items[2].values().val).to.be.equal("10/11/2007");
-            expect(list.items[3].values().val).to.be.equal("10/11/2008");
-            expect(list.items[4].values().val).to.be.equal("10/12/2008");
-            expect(list.items[5].values().val).to.be.equal("10/12/2009");
-        });
-        it('should sort file names', function() {
-            i1.values({ val: "car.mov" });
-            i2.values({ val: "01alpha.sgi" });
-            i3.values({ val: "001alpha.sgi" });
-            i4.values({ val: "my.string_41299.tif" });
-            i5.values({ val: "0003.zip" });
-            i6.values({ val: "0002.asp" });
-            list.sort('val', { order: "asc" });
-            expect(list.items[0].values().val).to.be.equal("0002.asp");
-            expect(list.items[1].values().val).to.be.equal("0003.zip");
-            expect(list.items[2].values().val).to.be.equal("001alpha.sgi");
-            expect(list.items[3].values().val).to.be.equal("01alpha.sgi");
-            expect(list.items[4].values().val).to.be.equal("car.mov");
-            expect(list.items[5].values().val).to.be.equal("my.string_41299.tif");
-        });
-        it('should sort floates', function() {
-            i1.values({ val: "10.0401" });
-            i2.values({ val: "10.022" });
-            i3.values({ val: "10.021999" });
-            i4.values({ val: "11.231" });
-            i5.values({ val: "0003.123" });
-            i6.values({ val: "09.2123" });
-            list.sort('val', { order: "asc" });
-            expect(list.items[0].values().val).to.be.equal("0003.123");
-            expect(list.items[1].values().val).to.be.equal("09.2123");
-            expect(list.items[2].values().val).to.be.equal("10.021999");
-            expect(list.items[3].values().val).to.be.equal("10.022");
-            expect(list.items[4].values().val).to.be.equal("10.0401");
-            expect(list.items[5].values().val).to.be.equal("11.231");
-        });
-        it('should sort IP addresses', function() {
-            i1.values({ val: "192.168.1.1" });
-            i2.values({ val: "192.168.0.100" });
-            i3.values({ val: "192.168.0.1" });
-            i4.values({ val: "192.168.1.3" });
-            i5.values({ val: "127.0.0.1" });
-            i6.values({ val: "192.168.1.2" });
-            list.sort('val', { order: "asc" });
-            expect(list.items[0].values().val).to.be.equal("127.0.0.1");
-            expect(list.items[1].values().val).to.be.equal("192.168.0.1");
-            expect(list.items[2].values().val).to.be.equal("192.168.0.100");
-            expect(list.items[3].values().val).to.be.equal("192.168.1.1");
-            expect(list.items[4].values().val).to.be.equal("192.168.1.2");
-            expect(list.items[5].values().val).to.be.equal("192.168.1.3");
-        });
-        it('should not break with weird values', function() {
-            i1.values({ val: undefined });
-            i2.values({ val: null });
-            i3.values({ val: 0 });
-            i4.values({ val: function() {} });
-            i5.values({ val: { foo: "bar" } });
+  describe('Basics', function() {
+    it('should sort letters asc', function() {
+      i1.values({ val: "b" });
+      i2.values({ val: "a" });
+      i3.values({ val: "c" });
+      i4.values({ val: "z" });
+      i5.values({ val: "s" });
+      i6.values({ val: "y" });
+      list.sort('val');
+      expect(list.items[0].values().val).to.be.equal("a");
+      expect(list.items[1].values().val).to.be.equal("b");
+      expect(list.items[2].values().val).to.be.equal("c");
+      expect(list.items[3].values().val).to.be.equal("s");
+      expect(list.items[4].values().val).to.be.equal("y");
+      expect(list.items[5].values().val).to.be.equal("z");
+    });
+    it('should sort letters desc', function() {
+      i1.values({ val: "b" });
+      i2.values({ val: "a" });
+      i3.values({ val: "c" });
+      i4.values({ val: "z" });
+      i5.values({ val: "s" });
+      i6.values({ val: "y" });
+      list.sort('val', { order: "desc" });
+      expect(list.items[0].values().val).to.be.equal("z");
+      expect(list.items[1].values().val).to.be.equal("y");
+      expect(list.items[2].values().val).to.be.equal("s");
+      expect(list.items[3].values().val).to.be.equal("c");
+      expect(list.items[4].values().val).to.be.equal("b");
+      expect(list.items[5].values().val).to.be.equal("a");
+    });
+    it('should fail to sort åäö desc (becomes äåö)', function() {
+      i1.values({ val: "a" });
+      i2.values({ val: "å" });
+      i3.values({ val: "ä" });
+      i4.values({ val: "ö" });
+      i5.values({ val: "o" });
+      i6.values({ val: "s" });
+      list.sort('val');
+      expect(list.items[0].values().val).to.be.equal("a");
+      expect(list.items[1].values().val).to.be.equal("o");
+      expect(list.items[2].values().val).to.be.equal("s");
+      expect(list.items[3].values().val).to.be.equal("ä");
+      expect(list.items[4].values().val).to.be.equal("å");
+      expect(list.items[5].values().val).to.be.equal("ö");
+    });
+    it('should fail to sort åäö asc (becomes öåä)', function() {
+      i1.values({ val: "a" });
+      i2.values({ val: "å" });
+      i3.values({ val: "ä" });
+      i4.values({ val: "ö" });
+      i5.values({ val: "o" });
+      i6.values({ val: "s" });
+      list.sort('val', { order: "desc" });
+      expect(list.items[0].values().val).to.be.equal("ö");
+      expect(list.items[1].values().val).to.be.equal("å");
+      expect(list.items[2].values().val).to.be.equal("ä");
+      expect(list.items[3].values().val).to.be.equal("s");
+      expect(list.items[4].values().val).to.be.equal("o");
+      expect(list.items[5].values().val).to.be.equal("a");
+    });
+    it('should handle case-insensitive by default', function() {
+      i1.values({ val: "e" });
+      i2.values({ val: "b" });
+      i4.values({ val: "F" });
+      i3.values({ val: "D" });
+      i5.values({ val: "A" });
+      i6.values({ val: "C" });
+      list.sort('val');
+      expect(list.items[0].values().val).to.be.equal("A");
+      expect(list.items[1].values().val).to.be.equal("b");
+      expect(list.items[2].values().val).to.be.equal("C");
+      expect(list.items[3].values().val).to.be.equal("D");
+      expect(list.items[4].values().val).to.be.equal("e");
+      expect(list.items[5].values().val).to.be.equal("F");
+    });
+    it('should disable insensitive', function() {
+      i1.values({ val: "e" });
+      i2.values({ val: "b" });
+      i4.values({ val: "F" });
+      i3.values({ val: "D" });
+      i5.values({ val: "A" });
+      i6.values({ val: "C" });
+      list.sort('val', { insensitive: false });
+      expect(list.items[0].values().val).to.be.equal("A");
+      expect(list.items[1].values().val).to.be.equal("C");
+      expect(list.items[2].values().val).to.be.equal("D");
+      expect(list.items[3].values().val).to.be.equal("F");
+      expect(list.items[4].values().val).to.be.equal("b");
+      expect(list.items[5].values().val).to.be.equal("e");
+    });
+    it('should sort dates', function() {
+      i1.values({ val: "10/12/2008" });
+      i2.values({ val: "10/11/2008" });
+      i3.values({ val: "10/11/2007" });
+      i4.values({ val: "10/12/2009" });
+      i5.values({ val: "4/01/2007" });
+      i6.values({ val: "10/12/2006" });
+      list.sort('val', { order: "asc" });
+      expect(list.items[0].values().val).to.be.equal("10/12/2006");
+      expect(list.items[1].values().val).to.be.equal("4/01/2007");
+      expect(list.items[2].values().val).to.be.equal("10/11/2007");
+      expect(list.items[3].values().val).to.be.equal("10/11/2008");
+      expect(list.items[4].values().val).to.be.equal("10/12/2008");
+      expect(list.items[5].values().val).to.be.equal("10/12/2009");
+    });
+    it('should sort file names', function() {
+      i1.values({ val: "car.mov" });
+      i2.values({ val: "01alpha.sgi" });
+      i3.values({ val: "001alpha.sgi" });
+      i4.values({ val: "my.string_41299.tif" });
+      i5.values({ val: "0003.zip" });
+      i6.values({ val: "0002.asp" });
+      list.sort('val', { order: "asc" });
+      expect(list.items[0].values().val).to.be.equal("0002.asp");
+      expect(list.items[1].values().val).to.be.equal("0003.zip");
+      expect(list.items[2].values().val).to.be.equal("001alpha.sgi");
+      expect(list.items[3].values().val).to.be.equal("01alpha.sgi");
+      expect(list.items[4].values().val).to.be.equal("car.mov");
+      expect(list.items[5].values().val).to.be.equal("my.string_41299.tif");
+    });
+    it('should sort floates', function() {
+      i1.values({ val: "10.0401" });
+      i2.values({ val: "10.022" });
+      i3.values({ val: "10.021999" });
+      i4.values({ val: "11.231" });
+      i5.values({ val: "0003.123" });
+      i6.values({ val: "09.2123" });
+      list.sort('val', { order: "asc" });
+      expect(list.items[0].values().val).to.be.equal("0003.123");
+      expect(list.items[1].values().val).to.be.equal("09.2123");
+      expect(list.items[2].values().val).to.be.equal("10.021999");
+      expect(list.items[3].values().val).to.be.equal("10.022");
+      expect(list.items[4].values().val).to.be.equal("10.0401");
+      expect(list.items[5].values().val).to.be.equal("11.231");
+    });
+    it('should sort IP addresses', function() {
+      i1.values({ val: "192.168.1.1" });
+      i2.values({ val: "192.168.0.100" });
+      i3.values({ val: "192.168.0.1" });
+      i4.values({ val: "192.168.1.3" });
+      i5.values({ val: "127.0.0.1" });
+      i6.values({ val: "192.168.1.2" });
+      list.sort('val', { order: "asc" });
+      expect(list.items[0].values().val).to.be.equal("127.0.0.1");
+      expect(list.items[1].values().val).to.be.equal("192.168.0.1");
+      expect(list.items[2].values().val).to.be.equal("192.168.0.100");
+      expect(list.items[3].values().val).to.be.equal("192.168.1.1");
+      expect(list.items[4].values().val).to.be.equal("192.168.1.2");
+      expect(list.items[5].values().val).to.be.equal("192.168.1.3");
+    });
+    it('should not break with weird values', function() {
+      i1.values({ val: undefined });
+      i2.values({ val: null });
+      i3.values({ val: 0 });
+      i4.values({ val: function() {} });
+      i5.values({ val: { foo: "bar" } });
 
-            expect(list.sort).withArgs('val').to.not.throwException();
-            expect(list.sort).withArgs('val').to.not.throwException();
-            expect(list.sort).withArgs('val').to.not.throwException();
-            expect(list.sort).withArgs('val').to.not.throwException();
-            expect(list.sort).withArgs('val').to.not.throwException();
-            expect(list.sort).withArgs('val').to.not.throwException();
-        });
-        /*
-        it('should show how random values are sorted', function() {
-            list.add({ id: '7', val: "" });
-            list.add({ id: '8', val: "" });
-            list.add({ id: '9', val: "" });
-            list.add({ id: '10', val: "" });
-            list.add({ id: '11', val: "" });
-            list.add({ id: '12', val: "" });
+      expect(list.sort).withArgs('val').to.not.throwException();
+      expect(list.sort).withArgs('val').to.not.throwException();
+      expect(list.sort).withArgs('val').to.not.throwException();
+      expect(list.sort).withArgs('val').to.not.throwException();
+      expect(list.sort).withArgs('val').to.not.throwException();
+      expect(list.sort).withArgs('val').to.not.throwException();
+    });
+    /*
+    it('should show how random values are sorted', function() {
+      list.add({ id: '7', val: "" });
+      list.add({ id: '8', val: "" });
+      list.add({ id: '9', val: "" });
+      list.add({ id: '10', val: "" });
+      list.add({ id: '11', val: "" });
+      list.add({ id: '12', val: "" });
 
-            var i7 = list.get('id', '7')[0],
-                i8 = list.get('id', '8')[0],
-                i9 = list.get('id', '9')[0],
-                i10 = list.get('id', '10')[0],
-                i11 = list.get('id', '11')[0],
-                i12 = list.get('id', '12')[0];
+      var i7 = list.get('id', '7')[0],
+        i8 = list.get('id', '8')[0],
+        i9 = list.get('id', '9')[0],
+        i10 = list.get('id', '10')[0],
+        i11 = list.get('id', '11')[0],
+        i12 = list.get('id', '12')[0];
 
-            i1.values({ val: undefined });
-            i2.values({ val: "" });
-            i3.values({ val: null });
-            i4.values({ val: "a" });
-            i5.values({ val: "0" });
-            i6.values({ val: true });
-            i7.values({ val: 0 });
-            i8.values({ val: "z" });
-            i9.values({ val: "!" });
-            i10.values({ val: "?" });
-            i11.values({ val: 100 });
-            i12.values({ val: false });
+      i1.values({ val: undefined });
+      i2.values({ val: "" });
+      i3.values({ val: null });
+      i4.values({ val: "a" });
+      i5.values({ val: "0" });
+      i6.values({ val: true });
+      i7.values({ val: 0 });
+      i8.values({ val: "z" });
+      i9.values({ val: "!" });
+      i10.values({ val: "?" });
+      i11.values({ val: 100 });
+      i12.values({ val: false });
 
-            list.sort('val', { order: "asc" });
-            list.sort('val', { order: "desc" });
-            list.sort('val', { order: "asc" });
+      list.sort('val', { order: "asc" });
+      list.sort('val', { order: "desc" });
+      list.sort('val', { order: "asc" });
 
-            expect(list.items[0].values().val).to.be.equal("");
-            expect(list.items[1].values().val).to.be.equal("0");
-            expect(list.items[2].values().val).to.be.equal(0);
-            expect(list.items[3].values().val).to.be.equal(100);
-            expect(list.items[4].values().val).to.be.equal("!");
-            expect(list.items[5].values().val).to.be.equal("?");
-            expect(list.items[6].values().val).to.be.equal("a");
-            expect(list.items[7].values().val).to.be.equal(false);
-            expect(list.items[8].values().val).to.be.equal(null);
-            expect(list.items[9].values().val).to.be.equal(true);
-            expect(list.items[10].values().val).to.be.equal(undefined);
-            expect(list.items[11].values().val).to.be.equal("z");
-        });
+      expect(list.items[0].values().val).to.be.equal("");
+      expect(list.items[1].values().val).to.be.equal("0");
+      expect(list.items[2].values().val).to.be.equal(0);
+      expect(list.items[3].values().val).to.be.equal(100);
+      expect(list.items[4].values().val).to.be.equal("!");
+      expect(list.items[5].values().val).to.be.equal("?");
+      expect(list.items[6].values().val).to.be.equal("a");
+      expect(list.items[7].values().val).to.be.equal(false);
+      expect(list.items[8].values().val).to.be.equal(null);
+      expect(list.items[9].values().val).to.be.equal(true);
+      expect(list.items[10].values().val).to.be.equal(undefined);
+      expect(list.items[11].values().val).to.be.equal("z");
+    });
 
-        it('should handle space and zero the same for desc and asc (random)', function() {
-            list.clear();
-            list.add({ val: "" });
-            list.add({ val: "0" });
-            list.add({ val: 0 });
+    it('should handle space and zero the same for desc and asc (random)', function() {
+      list.clear();
+      list.add({ val: "" });
+      list.add({ val: "0" });
+      list.add({ val: 0 });
 
-            list.sort('val', { order: "asc" });
-            expect(list.items[0].values().val).to.be.equal("");
-            expect(list.items[1].values().val).to.be.equal("0");
-            expect(list.items[2].values().val).to.be.equal(0);
-            list.sort('val', { order: "desc" });
-            expect(list.items[0].values().val).to.be.equal("");
-            expect(list.items[1].values().val).to.be.equal("0");
-            expect(list.items[2].values().val).to.be.equal(0);
-            list.sort('val', { order: "asc" });
-            expect(list.items[0].values().val).to.be.equal("");
-            expect(list.items[1].values().val).to.be.equal("0");
-            expect(list.items[2].values().val).to.be.equal(0);
-        });
-        */
+      list.sort('val', { order: "asc" });
+      expect(list.items[0].values().val).to.be.equal("");
+      expect(list.items[1].values().val).to.be.equal("0");
+      expect(list.items[2].values().val).to.be.equal(0);
+      list.sort('val', { order: "desc" });
+      expect(list.items[0].values().val).to.be.equal("");
+      expect(list.items[1].values().val).to.be.equal("0");
+      expect(list.items[2].values().val).to.be.equal(0);
+      list.sort('val', { order: "asc" });
+      expect(list.items[0].values().val).to.be.equal("");
+      expect(list.items[1].values().val).to.be.equal("0");
+      expect(list.items[2].values().val).to.be.equal(0);
     });
+    */
+  });
 
-    describe('Custom sort function', function() {
-        it('should use custom sort option', function() {
-            i1.values({ val: "<input value='b' />" });
-            i2.values({ val: "<input value='a' />" });
-            i3.values({ val: "<input value='c' />" });
-            i4.values({ val: "<input value='z' />" });
-            i5.values({ val: "<input value='s' />" });
-            i6.values({ val: "<input value='y' />" });
-            list.sort('val', {
-                sortFunction: function(itemA, itemB, options) {
-                    options.desc = false;
-                    return list.helpers.naturalSort($(itemA.values()[options.valueName]).val(), $(itemB.values()[options.valueName]).val(), options);
-                }
-            });
-            expect(list.items[0].values().val).to.be.equal("<input value='a' />");
-            expect(list.items[1].values().val).to.be.equal("<input value='b' />");
-            expect(list.items[2].values().val).to.be.equal("<input value='c' />");
-            expect(list.items[3].values().val).to.be.equal("<input value='s' />");
-            expect(list.items[4].values().val).to.be.equal("<input value='y' />");
-            expect(list.items[5].values().val).to.be.equal("<input value='z' />");
-        });
-        it('should use default custom sort function', function() {
-            list.sortFunction = function(itemA, itemB, options) {
-                options.desc = false;
-                return list.helpers.naturalSort($(itemA.values()[options.valueName]).val(), $(itemB.values()[options.valueName]).val(), options);
-            };
-            i1.values({ val: "<input value='b' />" });
-            i2.values({ val: "<input value='a' />" });
-            i3.values({ val: "<input value='c' />" });
-            i4.values({ val: "<input value='z' />" });
-            i5.values({ val: "<input value='s' />" });
-            i6.values({ val: "<input value='y' />" });
-            list.sort('val');
-            expect(list.items[0].values().val).to.be.equal("<input value='a' />");
-            expect(list.items[1].values().val).to.be.equal("<input value='b' />");
-            expect(list.items[2].values().val).to.be.equal("<input value='c' />");
-            expect(list.items[3].values().val).to.be.equal("<input value='s' />");
-            expect(list.items[4].values().val).to.be.equal("<input value='y' />");
-            expect(list.items[5].values().val).to.be.equal("<input value='z' />");
-        });
-        it('should use default custom sort function with options', function() {
-            list.sortFunction = function(itemA, itemB, options) {
-                options.desc = true;
-                return list.helpers.naturalSort($(itemA.values()[options.valueName]).val(), $(itemB.values()[options.valueName]).val(), options);
-            };
-            i1.values({ val: "<input value='b' />" });
-            i2.values({ val: "<input value='a' />" });
-            i3.values({ val: "<input value='c' />" });
-            i4.values({ val: "<input value='z' />" });
-            i5.values({ val: "<input value='s' />" });
-            i6.values({ val: "<input value='y' />" });
-            list.sort('val', { order: "desc"});
-            expect(list.items[0].values().val).to.be.equal("<input value='z' />");
-            expect(list.items[1].values().val).to.be.equal("<input value='y' />");
-            expect(list.items[2].values().val).to.be.equal("<input value='s' />");
-            expect(list.items[3].values().val).to.be.equal("<input value='c' />");
-            expect(list.items[4].values().val).to.be.equal("<input value='b' />");
-            expect(list.items[5].values().val).to.be.equal("<input value='a' />");
-        });
+  describe('Custom sort function', function() {
+    it('should use custom sort option', function() {
+      i1.values({ val: "<input value='b' />" });
+      i2.values({ val: "<input value='a' />" });
+      i3.values({ val: "<input value='c' />" });
+      i4.values({ val: "<input value='z' />" });
+      i5.values({ val: "<input value='s' />" });
+      i6.values({ val: "<input value='y' />" });
+      list.sort('val', {
+        sortFunction: function(itemA, itemB, options) {
+          options.desc = false;
+          return list.utils.naturalSort($(itemA.values()[options.valueName]).val(), $(itemB.values()[options.valueName]).val(), options);
+        }
+      });
+      expect(list.items[0].values().val).to.be.equal("<input value='a' />");
+      expect(list.items[1].values().val).to.be.equal("<input value='b' />");
+      expect(list.items[2].values().val).to.be.equal("<input value='c' />");
+      expect(list.items[3].values().val).to.be.equal("<input value='s' />");
+      expect(list.items[4].values().val).to.be.equal("<input value='y' />");
+      expect(list.items[5].values().val).to.be.equal("<input value='z' />");
+    });
+    it('should use default custom sort function', function() {
+      list.sortFunction = function(itemA, itemB, options) {
+        options.desc = false;
+        return list.utils.naturalSort($(itemA.values()[options.valueName]).val(), $(itemB.values()[options.valueName]).val(), options);
+      };
+      i1.values({ val: "<input value='b' />" });
+      i2.values({ val: "<input value='a' />" });
+      i3.values({ val: "<input value='c' />" });
+      i4.values({ val: "<input value='z' />" });
+      i5.values({ val: "<input value='s' />" });
+      i6.values({ val: "<input value='y' />" });
+      list.sort('val');
+      expect(list.items[0].values().val).to.be.equal("<input value='a' />");
+      expect(list.items[1].values().val).to.be.equal("<input value='b' />");
+      expect(list.items[2].values().val).to.be.equal("<input value='c' />");
+      expect(list.items[3].values().val).to.be.equal("<input value='s' />");
+      expect(list.items[4].values().val).to.be.equal("<input value='y' />");
+      expect(list.items[5].values().val).to.be.equal("<input value='z' />");
+    });
+    it('should use default custom sort function with options', function() {
+      list.sortFunction = function(itemA, itemB, options) {
+        options.desc = true;
+        return list.utils.naturalSort($(itemA.values()[options.valueName]).val(), $(itemB.values()[options.valueName]).val(), options);
+      };
+      i1.values({ val: "<input value='b' />" });
+      i2.values({ val: "<input value='a' />" });
+      i3.values({ val: "<input value='c' />" });
+      i4.values({ val: "<input value='z' />" });
+      i5.values({ val: "<input value='s' />" });
+      i6.values({ val: "<input value='y' />" });
+      list.sort('val', { order: "desc"});
+      expect(list.items[0].values().val).to.be.equal("<input value='z' />");
+      expect(list.items[1].values().val).to.be.equal("<input value='y' />");
+      expect(list.items[2].values().val).to.be.equal("<input value='s' />");
+      expect(list.items[3].values().val).to.be.equal("<input value='c' />");
+      expect(list.items[4].values().val).to.be.equal("<input value='b' />");
+      expect(list.items[5].values().val).to.be.equal("<input value='a' />");
     });
+  });
 });
diff --git a/test/test.trigger.js b/test/test.trigger.js
index c51ecff..12ad889 100644
--- a/test/test.trigger.js
+++ b/test/test.trigger.js
@@ -1,21 +1,21 @@
 describe('Trigger', function() {
 
-    var list;
+  var list;
 
-    before(function() {
-        list = fixture.list(['name', 'born'], fixture.all);
-    });
+  before(function() {
+    list = fixture.list(['name', 'born'], fixture.all);
+  });
 
-    after(function() {
-        fixture.removeList();
-    });
+  after(function() {
+    fixture.removeList();
+  });
 
-    describe('General', function() {
-        it('should be triggered by searchComplete', function(done) {
-            list.on('searchComplete', function() {
-                done();
-            });
-            list.trigger('searchComplete');
-        });
+  describe('General', function() {
+    it('should be triggered by searchComplete', function(done) {
+      list.on('searchComplete', function() {
+        done();
+      });
+      list.trigger('searchComplete');
     });
+  });
 });
\ No newline at end of file
diff --git a/test/usage/amd.html b/test/usage/amd.html
new file mode 100644
index 0000000..32fccbb
--- /dev/null
+++ b/test/usage/amd.html
@@ -0,0 +1,34 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <script data-main="main" src="require.js"></script>
+  <link rel="stylesheet" href="style.css" />
+</head>
+<body>
+
+  <div id="users">
+    <input class="search" placeholder="Search" />
+    <button class="sort" data-sort="name">
+      Sort by name
+    </button>
+    <ul class="list">
+      <li>
+        <h3 class="name">Jonny Stromberg</h3>
+        <p class="born">1986</p>
+      </li>
+      <li>
+        <h3 class="name">Jonas Arnklint</h3>
+        <p class="born">1985</p>
+      </li>
+      <li>
+        <h3 class="name">Martina Elm</h3>
+        <p class="born">1986</p>
+      </li>
+      <li>
+        <h3 class="name">Gustaf Lindqvist</h3>
+        <p class="born">1983</p>
+      </li>
+    </ul>
+  </div>
+</body>
+</html>
diff --git a/test/usage/boba.jpeg b/test/usage/boba.jpeg
new file mode 100644
index 0000000..3003f7b
Binary files /dev/null and b/test/usage/boba.jpeg differ
diff --git a/test/usage/classic.html b/test/usage/classic.html
new file mode 100644
index 0000000..aa3fb0c
--- /dev/null
+++ b/test/usage/classic.html
@@ -0,0 +1,53 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <script src="../../dist/list.js"></script>
+  <link rel="stylesheet" href="style.css" />
+</head>
+<body>
+
+  <div id="users">
+    <input class="search" placeholder="Search" />
+    <button class="sort" data-sort="name">
+      Sort by name
+    </button>
+    <ul class="list">
+      <li data-id="1">
+        <a href="https://twitter.com/javve" class="link name">Jonny Stromberg</a>
+        <p class="born timestamp" data-timestamp="12345">1986</p>
+        <img class="image" src="luke.jpeg">
+      </li>
+      <li data-id="2">
+        <a href="https://twitter.com/arnklint" class="link name">Jonas Arnklint</a>
+        <p class="born timestamp" data-timestamp="23456">1985</p>
+        <img class="image" src="darth.jpeg">
+      </li>
+      <li data-id="3">
+        <a href="https://twitter.com/martinaelm" class="link name">Martina Elm</a>
+        <p class="born timestamp" data-timestamp="34567">1986</p>
+        <img class="image" src="rey.jpeg">
+      </li>
+      <li data-id="4">
+        <a href="https://twitter.com/GLindqvist" class="link name">Gustaf Lindqvist</a>
+        <p class="born timestamp" data-timestamp="45678">1983</p>
+        <img class="image" src="boba.jpeg">
+      </li>
+    </ul>
+  </div>
+
+  <script>
+    var options = {
+      valueNames: [
+        'name',
+        'born',
+        { data: ['id'] },
+        { attr: 'src', name: 'image' },
+        { attr: 'href', name: 'link' },
+        { attr: 'data-timestamp', name: 'timestamp' }
+      ]
+    };
+    var userList = new List('users', options);
+    userList.add({ name: 'Leia', born: '1954', image: 'leia.jpeg', id: 5, timestamp: '67893' });
+  </script>
+</body>
+</html>
diff --git a/test/usage/darth.jpeg b/test/usage/darth.jpeg
new file mode 100644
index 0000000..f4ff609
Binary files /dev/null and b/test/usage/darth.jpeg differ
diff --git a/test/usage/leia.jpeg b/test/usage/leia.jpeg
new file mode 100644
index 0000000..20d07cb
Binary files /dev/null and b/test/usage/leia.jpeg differ
diff --git a/test/usage/luke.jpeg b/test/usage/luke.jpeg
new file mode 100644
index 0000000..4eaaba6
Binary files /dev/null and b/test/usage/luke.jpeg differ
diff --git a/test/usage/main.js b/test/usage/main.js
new file mode 100644
index 0000000..63cc377
--- /dev/null
+++ b/test/usage/main.js
@@ -0,0 +1,6 @@
+require(['../../dist/list', '../../dist/list.min'], function(List, ListMin) {
+  var options = {
+    valueNames: [ 'name', 'born' ]
+  };
+  var userList = new List('users', options);
+});
diff --git a/test/usage/require.js b/test/usage/require.js
new file mode 100644
index 0000000..babfa9a
--- /dev/null
+++ b/test/usage/require.js
@@ -0,0 +1,2083 @@
+/** vim: et:ts=4:sw=4:sts=4
+ * @license RequireJS 2.1.17 Copyright (c) 2010-2015, The Dojo Foundation All Rights Reserved.
+ * Available via the MIT or new BSD license.
+ * see: http://github.com/jrburke/requirejs for details
+ */
+//Not using strict: uneven strict support in browsers, #392, and causes
+//problems with requirejs.exec()/transpiler plugins that may not be strict.
+/*jslint regexp: true, nomen: true, sloppy: true */
+/*global window, navigator, document, importScripts, setTimeout, opera */
+
+var requirejs, require, define;
+(function (global) {
+    var req, s, head, baseElement, dataMain, src,
+        interactiveScript, currentlyAddingScript, mainScript, subPath,
+        version = '2.1.17',
+        commentRegExp = /(\/\*([\s\S]*?)\*\/|([^:]|^)\/\/(.*)$)/mg,
+        cjsRequireRegExp = /[^.]\s*require\s*\(\s*["']([^'"\s]+)["']\s*\)/g,
+        jsSuffixRegExp = /\.js$/,
+        currDirRegExp = /^\.\//,
+        op = Object.prototype,
+        ostring = op.toString,
+        hasOwn = op.hasOwnProperty,
+        ap = Array.prototype,
+        apsp = ap.splice,
+        isBrowser = !!(typeof window !== 'undefined' && typeof navigator !== 'undefined' && window.document),
+        isWebWorker = !isBrowser && typeof importScripts !== 'undefined',
+        //PS3 indicates loaded and complete, but need to wait for complete
+        //specifically. Sequence is 'loading', 'loaded', execution,
+        // then 'complete'. The UA check is unfortunate, but not sure how
+        //to feature test w/o causing perf issues.
+        readyRegExp = isBrowser && navigator.platform === 'PLAYSTATION 3' ?
+                      /^complete$/ : /^(complete|loaded)$/,
+        defContextName = '_',
+        //Oh the tragedy, detecting opera. See the usage of isOpera for reason.
+        isOpera = typeof opera !== 'undefined' && opera.toString() === '[object Opera]',
+        contexts = {},
+        cfg = {},
+        globalDefQueue = [],
+        useInteractive = false;
+
+    function isFunction(it) {
+        return ostring.call(it) === '[object Function]';
+    }
+
+    function isArray(it) {
+        return ostring.call(it) === '[object Array]';
+    }
+
+    /**
+     * Helper function for iterating over an array. If the func returns
+     * a true value, it will break out of the loop.
+     */
+    function each(ary, func) {
+        if (ary) {
+            var i;
+            for (i = 0; i < ary.length; i += 1) {
+                if (ary[i] && func(ary[i], i, ary)) {
+                    break;
+                }
+            }
+        }
+    }
+
+    /**
+     * Helper function for iterating over an array backwards. If the func
+     * returns a true value, it will break out of the loop.
+     */
+    function eachReverse(ary, func) {
+        if (ary) {
+            var i;
+            for (i = ary.length - 1; i > -1; i -= 1) {
+                if (ary[i] && func(ary[i], i, ary)) {
+                    break;
+                }
+            }
+        }
+    }
+
+    function hasProp(obj, prop) {
+        return hasOwn.call(obj, prop);
+    }
+
+    function getOwn(obj, prop) {
+        return hasProp(obj, prop) && obj[prop];
+    }
+
+    /**
+     * Cycles over properties in an object and calls a function for each
+     * property value. If the function returns a truthy value, then the
+     * iteration is stopped.
+     */
+    function eachProp(obj, func) {
+        var prop;
+        for (prop in obj) {
+            if (hasProp(obj, prop)) {
+                if (func(obj[prop], prop)) {
+                    break;
+                }
+            }
+        }
+    }
+
+    /**
+     * Simple function to mix in properties from source into target,
+     * but only if target does not already have a property of the same name.
+     */
+    function mixin(target, source, force, deepStringMixin) {
+        if (source) {
+            eachProp(source, function (value, prop) {
+                if (force || !hasProp(target, prop)) {
+                    if (deepStringMixin && typeof value === 'object' && value &&
+                        !isArray(value) && !isFunction(value) &&
+                        !(value instanceof RegExp)) {
+
+                        if (!target[prop]) {
+                            target[prop] = {};
+                        }
+                        mixin(target[prop], value, force, deepStringMixin);
+                    } else {
+                        target[prop] = value;
+                    }
+                }
+            });
+        }
+        return target;
+    }
+
+    //Similar to Function.prototype.bind, but the 'this' object is specified
+    //first, since it is easier to read/figure out what 'this' will be.
+    function bind(obj, fn) {
+        return function () {
+            return fn.apply(obj, arguments);
+        };
+    }
+
+    function scripts() {
+        return document.getElementsByTagName('script');
+    }
+
+    function defaultOnError(err) {
+        throw err;
+    }
+
+    //Allow getting a global that is expressed in
+    //dot notation, like 'a.b.c'.
+    function getGlobal(value) {
+        if (!value) {
+            return value;
+        }
+        var g = global;
+        each(value.split('.'), function (part) {
+            g = g[part];
+        });
+        return g;
+    }
+
+    /**
+     * Constructs an error with a pointer to an URL with more information.
+     * @param {String} id the error ID that maps to an ID on a web page.
+     * @param {String} message human readable error.
+     * @param {Error} [err] the original error, if there is one.
+     *
+     * @returns {Error}
+     */
+    function makeError(id, msg, err, requireModules) {
+        var e = new Error(msg + '\nhttp://requirejs.org/docs/errors.html#' + id);
+        e.requireType = id;
+        e.requireModules = requireModules;
+        if (err) {
+            e.originalError = err;
+        }
+        return e;
+    }
+
+    if (typeof define !== 'undefined') {
+        //If a define is already in play via another AMD loader,
+        //do not overwrite.
+        return;
+    }
+
+    if (typeof requirejs !== 'undefined') {
+        if (isFunction(requirejs)) {
+            //Do not overwrite an existing requirejs instance.
+            return;
+        }
+        cfg = requirejs;
+        requirejs = undefined;
+    }
+
+    //Allow for a require config object
+    if (typeof require !== 'undefined' && !isFunction(require)) {
+        //assume it is a config object.
+        cfg = require;
+        require = undefined;
+    }
+
+    function newContext(contextName) {
+        var inCheckLoaded, Module, context, handlers,
+            checkLoadedTimeoutId,
+            config = {
+                //Defaults. Do not set a default for map
+                //config to speed up normalize(), which
+                //will run faster if there is no default.
+                waitSeconds: 7,
+                baseUrl: './',
+                paths: {},
+                bundles: {},
+                pkgs: {},
+                shim: {},
+                config: {}
+            },
+            registry = {},
+            //registry of just enabled modules, to speed
+            //cycle breaking code when lots of modules
+            //are registered, but not activated.
+            enabledRegistry = {},
+            undefEvents = {},
+            defQueue = [],
+            defined = {},
+            urlFetched = {},
+            bundlesMap = {},
+            requireCounter = 1,
+            unnormalizedCounter = 1;
+
+        /**
+         * Trims the . and .. from an array of path segments.
+         * It will keep a leading path segment if a .. will become
+         * the first path segment, to help with module name lookups,
+         * which act like paths, but can be remapped. But the end result,
+         * all paths that use this function should look normalized.
+         * NOTE: this method MODIFIES the input array.
+         * @param {Array} ary the array of path segments.
+         */
+        function trimDots(ary) {
+            var i, part;
+            for (i = 0; i < ary.length; i++) {
+                part = ary[i];
+                if (part === '.') {
+                    ary.splice(i, 1);
+                    i -= 1;
+                } else if (part === '..') {
+                    // If at the start, or previous value is still ..,
+                    // keep them so that when converted to a path it may
+                    // still work when converted to a path, even though
+                    // as an ID it is less than ideal. In larger point
+                    // releases, may be better to just kick out an error.
+                    if (i === 0 || (i === 1 && ary[2] === '..') || ary[i - 1] === '..') {
+                        continue;
+                    } else if (i > 0) {
+                        ary.splice(i - 1, 2);
+                        i -= 2;
+                    }
+                }
+            }
+        }
+
+        /**
+         * Given a relative module name, like ./something, normalize it to
+         * a real name that can be mapped to a path.
+         * @param {String} name the relative name
+         * @param {String} baseName a real name that the name arg is relative
+         * to.
+         * @param {Boolean} applyMap apply the map config to the value. Should
+         * only be done if this normalization is for a dependency ID.
+         * @returns {String} normalized name
+         */
+        function normalize(name, baseName, applyMap) {
+            var pkgMain, mapValue, nameParts, i, j, nameSegment, lastIndex,
+                foundMap, foundI, foundStarMap, starI, normalizedBaseParts,
+                baseParts = (baseName && baseName.split('/')),
+                map = config.map,
+                starMap = map && map['*'];
+
+            //Adjust any relative paths.
+            if (name) {
+                name = name.split('/');
+                lastIndex = name.length - 1;
+
+                // If wanting node ID compatibility, strip .js from end
+                // of IDs. Have to do this here, and not in nameToUrl
+                // because node allows either .js or non .js to map
+                // to same file.
+                if (config.nodeIdCompat && jsSuffixRegExp.test(name[lastIndex])) {
+                    name[lastIndex] = name[lastIndex].replace(jsSuffixRegExp, '');
+                }
+
+                // Starts with a '.' so need the baseName
+                if (name[0].charAt(0) === '.' && baseParts) {
+                    //Convert baseName to array, and lop off the last part,
+                    //so that . matches that 'directory' and not name of the baseName's
+                    //module. For instance, baseName of 'one/two/three', maps to
+                    //'one/two/three.js', but we want the directory, 'one/two' for
+                    //this normalization.
+                    normalizedBaseParts = baseParts.slice(0, baseParts.length - 1);
+                    name = normalizedBaseParts.concat(name);
+                }
+
+                trimDots(name);
+                name = name.join('/');
+            }
+
+            //Apply map config if available.
+            if (applyMap && map && (baseParts || starMap)) {
+                nameParts = name.split('/');
+
+                outerLoop: for (i = nameParts.length; i > 0; i -= 1) {
+                    nameSegment = nameParts.slice(0, i).join('/');
+
+                    if (baseParts) {
+                        //Find the longest baseName segment match in the config.
+                        //So, do joins on the biggest to smallest lengths of baseParts.
+                        for (j = baseParts.length; j > 0; j -= 1) {
+                            mapValue = getOwn(map, baseParts.slice(0, j).join('/'));
+
+                            //baseName segment has config, find if it has one for
+                            //this name.
+                            if (mapValue) {
+                                mapValue = getOwn(mapValue, nameSegment);
+                                if (mapValue) {
+                                    //Match, update name to the new value.
+                                    foundMap = mapValue;
+                                    foundI = i;
+                                    break outerLoop;
+                                }
+                            }
+                        }
+                    }
+
+                    //Check for a star map match, but just hold on to it,
+                    //if there is a shorter segment match later in a matching
+                    //config, then favor over this star map.
+                    if (!foundStarMap && starMap && getOwn(starMap, nameSegment)) {
+                        foundStarMap = getOwn(starMap, nameSegment);
+                        starI = i;
+                    }
+                }
+
+                if (!foundMap && foundStarMap) {
+                    foundMap = foundStarMap;
+                    foundI = starI;
+                }
+
+                if (foundMap) {
+                    nameParts.splice(0, foundI, foundMap);
+                    name = nameParts.join('/');
+                }
+            }
+
+            // If the name points to a package's name, use
+            // the package main instead.
+            pkgMain = getOwn(config.pkgs, name);
+
+            return pkgMain ? pkgMain : name;
+        }
+
+        function removeScript(name) {
+            if (isBrowser) {
+                each(scripts(), function (scriptNode) {
+                    if (scriptNode.getAttribute('data-requiremodule') === name &&
+                            scriptNode.getAttribute('data-requirecontext') === context.contextName) {
+                        scriptNode.parentNode.removeChild(scriptNode);
+                        return true;
+                    }
+                });
+            }
+        }
+
+        function hasPathFallback(id) {
+            var pathConfig = getOwn(config.paths, id);
+            if (pathConfig && isArray(pathConfig) && pathConfig.length > 1) {
+                //Pop off the first array value, since it failed, and
+                //retry
+                pathConfig.shift();
+                context.require.undef(id);
+
+                //Custom require that does not do map translation, since
+                //ID is "absolute", already mapped/resolved.
+                context.makeRequire(null, {
+                    skipMap: true
+                })([id]);
+
+                return true;
+            }
+        }
+
+        //Turns a plugin!resource to [plugin, resource]
+        //with the plugin being undefined if the name
+        //did not have a plugin prefix.
+        function splitPrefix(name) {
+            var prefix,
+                index = name ? name.indexOf('!') : -1;
+            if (index > -1) {
+                prefix = name.substring(0, index);
+                name = name.substring(index + 1, name.length);
+            }
+            return [prefix, name];
+        }
+
+        /**
+         * Creates a module mapping that includes plugin prefix, module
+         * name, and path. If parentModuleMap is provided it will
+         * also normalize the name via require.normalize()
+         *
+         * @param {String} name the module name
+         * @param {String} [parentModuleMap] parent module map
+         * for the module name, used to resolve relative names.
+         * @param {Boolean} isNormalized: is the ID already normalized.
+         * This is true if this call is done for a define() module ID.
+         * @param {Boolean} applyMap: apply the map config to the ID.
+         * Should only be true if this map is for a dependency.
+         *
+         * @returns {Object}
+         */
+        function makeModuleMap(name, parentModuleMap, isNormalized, applyMap) {
+            var url, pluginModule, suffix, nameParts,
+                prefix = null,
+                parentName = parentModuleMap ? parentModuleMap.name : null,
+                originalName = name,
+                isDefine = true,
+                normalizedName = '';
+
+            //If no name, then it means it is a require call, generate an
+            //internal name.
+            if (!name) {
+                isDefine = false;
+                name = '_ at r' + (requireCounter += 1);
+            }
+
+            nameParts = splitPrefix(name);
+            prefix = nameParts[0];
+            name = nameParts[1];
+
+            if (prefix) {
+                prefix = normalize(prefix, parentName, applyMap);
+                pluginModule = getOwn(defined, prefix);
+            }
+
+            //Account for relative paths if there is a base name.
+            if (name) {
+                if (prefix) {
+                    if (pluginModule && pluginModule.normalize) {
+                        //Plugin is loaded, use its normalize method.
+                        normalizedName = pluginModule.normalize(name, function (name) {
+                            return normalize(name, parentName, applyMap);
+                        });
+                    } else {
+                        // If nested plugin references, then do not try to
+                        // normalize, as it will not normalize correctly. This
+                        // places a restriction on resourceIds, and the longer
+                        // term solution is not to normalize until plugins are
+                        // loaded and all normalizations to allow for async
+                        // loading of a loader plugin. But for now, fixes the
+                        // common uses. Details in #1131
+                        normalizedName = name.indexOf('!') === -1 ?
+                                         normalize(name, parentName, applyMap) :
+                                         name;
+                    }
+                } else {
+                    //A regular module.
+                    normalizedName = normalize(name, parentName, applyMap);
+
+                    //Normalized name may be a plugin ID due to map config
+                    //application in normalize. The map config values must
+                    //already be normalized, so do not need to redo that part.
+                    nameParts = splitPrefix(normalizedName);
+                    prefix = nameParts[0];
+                    normalizedName = nameParts[1];
+                    isNormalized = true;
+
+                    url = context.nameToUrl(normalizedName);
+                }
+            }
+
+            //If the id is a plugin id that cannot be determined if it needs
+            //normalization, stamp it with a unique ID so two matching relative
+            //ids that may conflict can be separate.
+            suffix = prefix && !pluginModule && !isNormalized ?
+                     '_unnormalized' + (unnormalizedCounter += 1) :
+                     '';
+
+            return {
+                prefix: prefix,
+                name: normalizedName,
+                parentMap: parentModuleMap,
+                unnormalized: !!suffix,
+                url: url,
+                originalName: originalName,
+                isDefine: isDefine,
+                id: (prefix ?
+                        prefix + '!' + normalizedName :
+                        normalizedName) + suffix
+            };
+        }
+
+        function getModule(depMap) {
+            var id = depMap.id,
+                mod = getOwn(registry, id);
+
+            if (!mod) {
+                mod = registry[id] = new context.Module(depMap);
+            }
+
+            return mod;
+        }
+
+        function on(depMap, name, fn) {
+            var id = depMap.id,
+                mod = getOwn(registry, id);
+
+            if (hasProp(defined, id) &&
+                    (!mod || mod.defineEmitComplete)) {
+                if (name === 'defined') {
+                    fn(defined[id]);
+                }
+            } else {
+                mod = getModule(depMap);
+                if (mod.error && name === 'error') {
+                    fn(mod.error);
+                } else {
+                    mod.on(name, fn);
+                }
+            }
+        }
+
+        function onError(err, errback) {
+            var ids = err.requireModules,
+                notified = false;
+
+            if (errback) {
+                errback(err);
+            } else {
+                each(ids, function (id) {
+                    var mod = getOwn(registry, id);
+                    if (mod) {
+                        //Set error on module, so it skips timeout checks.
+                        mod.error = err;
+                        if (mod.events.error) {
+                            notified = true;
+                            mod.emit('error', err);
+                        }
+                    }
+                });
+
+                if (!notified) {
+                    req.onError(err);
+                }
+            }
+        }
+
+        /**
+         * Internal method to transfer globalQueue items to this context's
+         * defQueue.
+         */
+        function takeGlobalQueue() {
+            //Push all the globalDefQueue items into the context's defQueue
+            if (globalDefQueue.length) {
+                //Array splice in the values since the context code has a
+                //local var ref to defQueue, so cannot just reassign the one
+                //on context.
+                apsp.apply(defQueue,
+                           [defQueue.length, 0].concat(globalDefQueue));
+                globalDefQueue = [];
+            }
+        }
+
+        handlers = {
+            'require': function (mod) {
+                if (mod.require) {
+                    return mod.require;
+                } else {
+                    return (mod.require = context.makeRequire(mod.map));
+                }
+            },
+            'exports': function (mod) {
+                mod.usingExports = true;
+                if (mod.map.isDefine) {
+                    if (mod.exports) {
+                        return (defined[mod.map.id] = mod.exports);
+                    } else {
+                        return (mod.exports = defined[mod.map.id] = {});
+                    }
+                }
+            },
+            'module': function (mod) {
+                if (mod.module) {
+                    return mod.module;
+                } else {
+                    return (mod.module = {
+                        id: mod.map.id,
+                        uri: mod.map.url,
+                        config: function () {
+                            return  getOwn(config.config, mod.map.id) || {};
+                        },
+                        exports: mod.exports || (mod.exports = {})
+                    });
+                }
+            }
+        };
+
+        function cleanRegistry(id) {
+            //Clean up machinery used for waiting modules.
+            delete registry[id];
+            delete enabledRegistry[id];
+        }
+
+        function breakCycle(mod, traced, processed) {
+            var id = mod.map.id;
+
+            if (mod.error) {
+                mod.emit('error', mod.error);
+            } else {
+                traced[id] = true;
+                each(mod.depMaps, function (depMap, i) {
+                    var depId = depMap.id,
+                        dep = getOwn(registry, depId);
+
+                    //Only force things that have not completed
+                    //being defined, so still in the registry,
+                    //and only if it has not been matched up
+                    //in the module already.
+                    if (dep && !mod.depMatched[i] && !processed[depId]) {
+                        if (getOwn(traced, depId)) {
+                            mod.defineDep(i, defined[depId]);
+                            mod.check(); //pass false?
+                        } else {
+                            breakCycle(dep, traced, processed);
+                        }
+                    }
+                });
+                processed[id] = true;
+            }
+        }
+
+        function checkLoaded() {
+            var err, usingPathFallback,
+                waitInterval = config.waitSeconds * 1000,
+                //It is possible to disable the wait interval by using waitSeconds of 0.
+                expired = waitInterval && (context.startTime + waitInterval) < new Date().getTime(),
+                noLoads = [],
+                reqCalls = [],
+                stillLoading = false,
+                needCycleCheck = true;
+
+            //Do not bother if this call was a result of a cycle break.
+            if (inCheckLoaded) {
+                return;
+            }
+
+            inCheckLoaded = true;
+
+            //Figure out the state of all the modules.
+            eachProp(enabledRegistry, function (mod) {
+                var map = mod.map,
+                    modId = map.id;
+
+                //Skip things that are not enabled or in error state.
+                if (!mod.enabled) {
+                    return;
+                }
+
+                if (!map.isDefine) {
+                    reqCalls.push(mod);
+                }
+
+                if (!mod.error) {
+                    //If the module should be executed, and it has not
+                    //been inited and time is up, remember it.
+                    if (!mod.inited && expired) {
+                        if (hasPathFallback(modId)) {
+                            usingPathFallback = true;
+                            stillLoading = true;
+                        } else {
+                            noLoads.push(modId);
+                            removeScript(modId);
+                        }
+                    } else if (!mod.inited && mod.fetched && map.isDefine) {
+                        stillLoading = true;
+                        if (!map.prefix) {
+                            //No reason to keep looking for unfinished
+                            //loading. If the only stillLoading is a
+                            //plugin resource though, keep going,
+                            //because it may be that a plugin resource
+                            //is waiting on a non-plugin cycle.
+                            return (needCycleCheck = false);
+                        }
+                    }
+                }
+            });
+
+            if (expired && noLoads.length) {
+                //If wait time expired, throw error of unloaded modules.
+                err = makeError('timeout', 'Load timeout for modules: ' + noLoads, null, noLoads);
+                err.contextName = context.contextName;
+                return onError(err);
+            }
+
+            //Not expired, check for a cycle.
+            if (needCycleCheck) {
+                each(reqCalls, function (mod) {
+                    breakCycle(mod, {}, {});
+                });
+            }
+
+            //If still waiting on loads, and the waiting load is something
+            //other than a plugin resource, or there are still outstanding
+            //scripts, then just try back later.
+            if ((!expired || usingPathFallback) && stillLoading) {
+                //Something is still waiting to load. Wait for it, but only
+                //if a timeout is not already in effect.
+                if ((isBrowser || isWebWorker) && !checkLoadedTimeoutId) {
+                    checkLoadedTimeoutId = setTimeout(function () {
+                        checkLoadedTimeoutId = 0;
+                        checkLoaded();
+                    }, 50);
+                }
+            }
+
+            inCheckLoaded = false;
+        }
+
+        Module = function (map) {
+            this.events = getOwn(undefEvents, map.id) || {};
+            this.map = map;
+            this.shim = getOwn(config.shim, map.id);
+            this.depExports = [];
+            this.depMaps = [];
+            this.depMatched = [];
+            this.pluginMaps = {};
+            this.depCount = 0;
+
+            /* this.exports this.factory
+               this.depMaps = [],
+               this.enabled, this.fetched
+            */
+        };
+
+        Module.prototype = {
+            init: function (depMaps, factory, errback, options) {
+                options = options || {};
+
+                //Do not do more inits if already done. Can happen if there
+                //are multiple define calls for the same module. That is not
+                //a normal, common case, but it is also not unexpected.
+                if (this.inited) {
+                    return;
+                }
+
+                this.factory = factory;
+
+                if (errback) {
+                    //Register for errors on this module.
+                    this.on('error', errback);
+                } else if (this.events.error) {
+                    //If no errback already, but there are error listeners
+                    //on this module, set up an errback to pass to the deps.
+                    errback = bind(this, function (err) {
+                        this.emit('error', err);
+                    });
+                }
+
+                //Do a copy of the dependency array, so that
+                //source inputs are not modified. For example
+                //"shim" deps are passed in here directly, and
+                //doing a direct modification of the depMaps array
+                //would affect that config.
+                this.depMaps = depMaps && depMaps.slice(0);
+
+                this.errback = errback;
+
+                //Indicate this module has be initialized
+                this.inited = true;
+
+                this.ignore = options.ignore;
+
+                //Could have option to init this module in enabled mode,
+                //or could have been previously marked as enabled. However,
+                //the dependencies are not known until init is called. So
+                //if enabled previously, now trigger dependencies as enabled.
+                if (options.enabled || this.enabled) {
+                    //Enable this module and dependencies.
+                    //Will call this.check()
+                    this.enable();
+                } else {
+                    this.check();
+                }
+            },
+
+            defineDep: function (i, depExports) {
+                //Because of cycles, defined callback for a given
+                //export can be called more than once.
+                if (!this.depMatched[i]) {
+                    this.depMatched[i] = true;
+                    this.depCount -= 1;
+                    this.depExports[i] = depExports;
+                }
+            },
+
+            fetch: function () {
+                if (this.fetched) {
+                    return;
+                }
+                this.fetched = true;
+
+                context.startTime = (new Date()).getTime();
+
+                var map = this.map;
+
+                //If the manager is for a plugin managed resource,
+                //ask the plugin to load it now.
+                if (this.shim) {
+                    context.makeRequire(this.map, {
+                        enableBuildCallback: true
+                    })(this.shim.deps || [], bind(this, function () {
+                        return map.prefix ? this.callPlugin() : this.load();
+                    }));
+                } else {
+                    //Regular dependency.
+                    return map.prefix ? this.callPlugin() : this.load();
+                }
+            },
+
+            load: function () {
+                var url = this.map.url;
+
+                //Regular dependency.
+                if (!urlFetched[url]) {
+                    urlFetched[url] = true;
+                    context.load(this.map.id, url);
+                }
+            },
+
+            /**
+             * Checks if the module is ready to define itself, and if so,
+             * define it.
+             */
+            check: function () {
+                if (!this.enabled || this.enabling) {
+                    return;
+                }
+
+                var err, cjsModule,
+                    id = this.map.id,
+                    depExports = this.depExports,
+                    exports = this.exports,
+                    factory = this.factory;
+
+                if (!this.inited) {
+                    this.fetch();
+                } else if (this.error) {
+                    this.emit('error', this.error);
+                } else if (!this.defining) {
+                    //The factory could trigger another require call
+                    //that would result in checking this module to
+                    //define itself again. If already in the process
+                    //of doing that, skip this work.
+                    this.defining = true;
+
+                    if (this.depCount < 1 && !this.defined) {
+                        if (isFunction(factory)) {
+                            //If there is an error listener, favor passing
+                            //to that instead of throwing an error. However,
+                            //only do it for define()'d  modules. require
+                            //errbacks should not be called for failures in
+                            //their callbacks (#699). However if a global
+                            //onError is set, use that.
+                            if ((this.events.error && this.map.isDefine) ||
+                                req.onError !== defaultOnError) {
+                                try {
+                                    exports = context.execCb(id, factory, depExports, exports);
+                                } catch (e) {
+                                    err = e;
+                                }
+                            } else {
+                                exports = context.execCb(id, factory, depExports, exports);
+                            }
+
+                            // Favor return value over exports. If node/cjs in play,
+                            // then will not have a return value anyway. Favor
+                            // module.exports assignment over exports object.
+                            if (this.map.isDefine && exports === undefined) {
+                                cjsModule = this.module;
+                                if (cjsModule) {
+                                    exports = cjsModule.exports;
+                                } else if (this.usingExports) {
+                                    //exports already set the defined value.
+                                    exports = this.exports;
+                                }
+                            }
+
+                            if (err) {
+                                err.requireMap = this.map;
+                                err.requireModules = this.map.isDefine ? [this.map.id] : null;
+                                err.requireType = this.map.isDefine ? 'define' : 'require';
+                                return onError((this.error = err));
+                            }
+
+                        } else {
+                            //Just a literal value
+                            exports = factory;
+                        }
+
+                        this.exports = exports;
+
+                        if (this.map.isDefine && !this.ignore) {
+                            defined[id] = exports;
+
+                            if (req.onResourceLoad) {
+                                req.onResourceLoad(context, this.map, this.depMaps);
+                            }
+                        }
+
+                        //Clean up
+                        cleanRegistry(id);
+
+                        this.defined = true;
+                    }
+
+                    //Finished the define stage. Allow calling check again
+                    //to allow define notifications below in the case of a
+                    //cycle.
+                    this.defining = false;
+
+                    if (this.defined && !this.defineEmitted) {
+                        this.defineEmitted = true;
+                        this.emit('defined', this.exports);
+                        this.defineEmitComplete = true;
+                    }
+
+                }
+            },
+
+            callPlugin: function () {
+                var map = this.map,
+                    id = map.id,
+                    //Map already normalized the prefix.
+                    pluginMap = makeModuleMap(map.prefix);
+
+                //Mark this as a dependency for this plugin, so it
+                //can be traced for cycles.
+                this.depMaps.push(pluginMap);
+
+                on(pluginMap, 'defined', bind(this, function (plugin) {
+                    var load, normalizedMap, normalizedMod,
+                        bundleId = getOwn(bundlesMap, this.map.id),
+                        name = this.map.name,
+                        parentName = this.map.parentMap ? this.map.parentMap.name : null,
+                        localRequire = context.makeRequire(map.parentMap, {
+                            enableBuildCallback: true
+                        });
+
+                    //If current map is not normalized, wait for that
+                    //normalized name to load instead of continuing.
+                    if (this.map.unnormalized) {
+                        //Normalize the ID if the plugin allows it.
+                        if (plugin.normalize) {
+                            name = plugin.normalize(name, function (name) {
+                                return normalize(name, parentName, true);
+                            }) || '';
+                        }
+
+                        //prefix and name should already be normalized, no need
+                        //for applying map config again either.
+                        normalizedMap = makeModuleMap(map.prefix + '!' + name,
+                                                      this.map.parentMap);
+                        on(normalizedMap,
+                            'defined', bind(this, function (value) {
+                                this.init([], function () { return value; }, null, {
+                                    enabled: true,
+                                    ignore: true
+                                });
+                            }));
+
+                        normalizedMod = getOwn(registry, normalizedMap.id);
+                        if (normalizedMod) {
+                            //Mark this as a dependency for this plugin, so it
+                            //can be traced for cycles.
+                            this.depMaps.push(normalizedMap);
+
+                            if (this.events.error) {
+                                normalizedMod.on('error', bind(this, function (err) {
+                                    this.emit('error', err);
+                                }));
+                            }
+                            normalizedMod.enable();
+                        }
+
+                        return;
+                    }
+
+                    //If a paths config, then just load that file instead to
+                    //resolve the plugin, as it is built into that paths layer.
+                    if (bundleId) {
+                        this.map.url = context.nameToUrl(bundleId);
+                        this.load();
+                        return;
+                    }
+
+                    load = bind(this, function (value) {
+                        this.init([], function () { return value; }, null, {
+                            enabled: true
+                        });
+                    });
+
+                    load.error = bind(this, function (err) {
+                        this.inited = true;
+                        this.error = err;
+                        err.requireModules = [id];
+
+                        //Remove temp unnormalized modules for this module,
+                        //since they will never be resolved otherwise now.
+                        eachProp(registry, function (mod) {
+                            if (mod.map.id.indexOf(id + '_unnormalized') === 0) {
+                                cleanRegistry(mod.map.id);
+                            }
+                        });
+
+                        onError(err);
+                    });
+
+                    //Allow plugins to load other code without having to know the
+                    //context or how to 'complete' the load.
+                    load.fromText = bind(this, function (text, textAlt) {
+                        /*jslint evil: true */
+                        var moduleName = map.name,
+                            moduleMap = makeModuleMap(moduleName),
+                            hasInteractive = useInteractive;
+
+                        //As of 2.1.0, support just passing the text, to reinforce
+                        //fromText only being called once per resource. Still
+                        //support old style of passing moduleName but discard
+                        //that moduleName in favor of the internal ref.
+                        if (textAlt) {
+                            text = textAlt;
+                        }
+
+                        //Turn off interactive script matching for IE for any define
+                        //calls in the text, then turn it back on at the end.
+                        if (hasInteractive) {
+                            useInteractive = false;
+                        }
+
+                        //Prime the system by creating a module instance for
+                        //it.
+                        getModule(moduleMap);
+
+                        //Transfer any config to this other module.
+                        if (hasProp(config.config, id)) {
+                            config.config[moduleName] = config.config[id];
+                        }
+
+                        try {
+                            req.exec(text);
+                        } catch (e) {
+                            return onError(makeError('fromtexteval',
+                                             'fromText eval for ' + id +
+                                            ' failed: ' + e,
+                                             e,
+                                             [id]));
+                        }
+
+                        if (hasInteractive) {
+                            useInteractive = true;
+                        }
+
+                        //Mark this as a dependency for the plugin
+                        //resource
+                        this.depMaps.push(moduleMap);
+
+                        //Support anonymous modules.
+                        context.completeLoad(moduleName);
+
+                        //Bind the value of that module to the value for this
+                        //resource ID.
+                        localRequire([moduleName], load);
+                    });
+
+                    //Use parentName here since the plugin's name is not reliable,
+                    //could be some weird string with no path that actually wants to
+                    //reference the parentName's path.
+                    plugin.load(map.name, localRequire, load, config);
+                }));
+
+                context.enable(pluginMap, this);
+                this.pluginMaps[pluginMap.id] = pluginMap;
+            },
+
+            enable: function () {
+                enabledRegistry[this.map.id] = this;
+                this.enabled = true;
+
+                //Set flag mentioning that the module is enabling,
+                //so that immediate calls to the defined callbacks
+                //for dependencies do not trigger inadvertent load
+                //with the depCount still being zero.
+                this.enabling = true;
+
+                //Enable each dependency
+                each(this.depMaps, bind(this, function (depMap, i) {
+                    var id, mod, handler;
+
+                    if (typeof depMap === 'string') {
+                        //Dependency needs to be converted to a depMap
+                        //and wired up to this module.
+                        depMap = makeModuleMap(depMap,
+                                               (this.map.isDefine ? this.map : this.map.parentMap),
+                                               false,
+                                               !this.skipMap);
+                        this.depMaps[i] = depMap;
+
+                        handler = getOwn(handlers, depMap.id);
+
+                        if (handler) {
+                            this.depExports[i] = handler(this);
+                            return;
+                        }
+
+                        this.depCount += 1;
+
+                        on(depMap, 'defined', bind(this, function (depExports) {
+                            this.defineDep(i, depExports);
+                            this.check();
+                        }));
+
+                        if (this.errback) {
+                            on(depMap, 'error', bind(this, this.errback));
+                        } else if (this.events.error) {
+                            // No direct errback on this module, but something
+                            // else is listening for errors, so be sure to
+                            // propagate the error correctly.
+                            on(depMap, 'error', bind(this, function(err) {
+                                this.emit('error', err);
+                            }));
+                        }
+                    }
+
+                    id = depMap.id;
+                    mod = registry[id];
+
+                    //Skip special modules like 'require', 'exports', 'module'
+                    //Also, don't call enable if it is already enabled,
+                    //important in circular dependency cases.
+                    if (!hasProp(handlers, id) && mod && !mod.enabled) {
+                        context.enable(depMap, this);
+                    }
+                }));
+
+                //Enable each plugin that is used in
+                //a dependency
+                eachProp(this.pluginMaps, bind(this, function (pluginMap) {
+                    var mod = getOwn(registry, pluginMap.id);
+                    if (mod && !mod.enabled) {
+                        context.enable(pluginMap, this);
+                    }
+                }));
+
+                this.enabling = false;
+
+                this.check();
+            },
+
+            on: function (name, cb) {
+                var cbs = this.events[name];
+                if (!cbs) {
+                    cbs = this.events[name] = [];
+                }
+                cbs.push(cb);
+            },
+
+            emit: function (name, evt) {
+                each(this.events[name], function (cb) {
+                    cb(evt);
+                });
+                if (name === 'error') {
+                    //Now that the error handler was triggered, remove
+                    //the listeners, since this broken Module instance
+                    //can stay around for a while in the registry.
+                    delete this.events[name];
+                }
+            }
+        };
+
+        function callGetModule(args) {
+            //Skip modules already defined.
+            if (!hasProp(defined, args[0])) {
+                getModule(makeModuleMap(args[0], null, true)).init(args[1], args[2]);
+            }
+        }
+
+        function removeListener(node, func, name, ieName) {
+            //Favor detachEvent because of IE9
+            //issue, see attachEvent/addEventListener comment elsewhere
+            //in this file.
+            if (node.detachEvent && !isOpera) {
+                //Probably IE. If not it will throw an error, which will be
+                //useful to know.
+                if (ieName) {
+                    node.detachEvent(ieName, func);
+                }
+            } else {
+                node.removeEventListener(name, func, false);
+            }
+        }
+
+        /**
+         * Given an event from a script node, get the requirejs info from it,
+         * and then removes the event listeners on the node.
+         * @param {Event} evt
+         * @returns {Object}
+         */
+        function getScriptData(evt) {
+            //Using currentTarget instead of target for Firefox 2.0's sake. Not
+            //all old browsers will be supported, but this one was easy enough
+            //to support and still makes sense.
+            var node = evt.currentTarget || evt.srcElement;
+
+            //Remove the listeners once here.
+            removeListener(node, context.onScriptLoad, 'load', 'onreadystatechange');
+            removeListener(node, context.onScriptError, 'error');
+
+            return {
+                node: node,
+                id: node && node.getAttribute('data-requiremodule')
+            };
+        }
+
+        function intakeDefines() {
+            var args;
+
+            //Any defined modules in the global queue, intake them now.
+            takeGlobalQueue();
+
+            //Make sure any remaining defQueue items get properly processed.
+            while (defQueue.length) {
+                args = defQueue.shift();
+                if (args[0] === null) {
+                    return onError(makeError('mismatch', 'Mismatched anonymous define() module: ' + args[args.length - 1]));
+                } else {
+                    //args are id, deps, factory. Should be normalized by the
+                    //define() function.
+                    callGetModule(args);
+                }
+            }
+        }
+
+        context = {
+            config: config,
+            contextName: contextName,
+            registry: registry,
+            defined: defined,
+            urlFetched: urlFetched,
+            defQueue: defQueue,
+            Module: Module,
+            makeModuleMap: makeModuleMap,
+            nextTick: req.nextTick,
+            onError: onError,
+
+            /**
+             * Set a configuration for the context.
+             * @param {Object} cfg config object to integrate.
+             */
+            configure: function (cfg) {
+                //Make sure the baseUrl ends in a slash.
+                if (cfg.baseUrl) {
+                    if (cfg.baseUrl.charAt(cfg.baseUrl.length - 1) !== '/') {
+                        cfg.baseUrl += '/';
+                    }
+                }
+
+                //Save off the paths since they require special processing,
+                //they are additive.
+                var shim = config.shim,
+                    objs = {
+                        paths: true,
+                        bundles: true,
+                        config: true,
+                        map: true
+                    };
+
+                eachProp(cfg, function (value, prop) {
+                    if (objs[prop]) {
+                        if (!config[prop]) {
+                            config[prop] = {};
+                        }
+                        mixin(config[prop], value, true, true);
+                    } else {
+                        config[prop] = value;
+                    }
+                });
+
+                //Reverse map the bundles
+                if (cfg.bundles) {
+                    eachProp(cfg.bundles, function (value, prop) {
+                        each(value, function (v) {
+                            if (v !== prop) {
+                                bundlesMap[v] = prop;
+                            }
+                        });
+                    });
+                }
+
+                //Merge shim
+                if (cfg.shim) {
+                    eachProp(cfg.shim, function (value, id) {
+                        //Normalize the structure
+                        if (isArray(value)) {
+                            value = {
+                                deps: value
+                            };
+                        }
+                        if ((value.exports || value.init) && !value.exportsFn) {
+                            value.exportsFn = context.makeShimExports(value);
+                        }
+                        shim[id] = value;
+                    });
+                    config.shim = shim;
+                }
+
+                //Adjust packages if necessary.
+                if (cfg.packages) {
+                    each(cfg.packages, function (pkgObj) {
+                        var location, name;
+
+                        pkgObj = typeof pkgObj === 'string' ? { name: pkgObj } : pkgObj;
+
+                        name = pkgObj.name;
+                        location = pkgObj.location;
+                        if (location) {
+                            config.paths[name] = pkgObj.location;
+                        }
+
+                        //Save pointer to main module ID for pkg name.
+                        //Remove leading dot in main, so main paths are normalized,
+                        //and remove any trailing .js, since different package
+                        //envs have different conventions: some use a module name,
+                        //some use a file name.
+                        config.pkgs[name] = pkgObj.name + '/' + (pkgObj.main || 'main')
+                                     .replace(currDirRegExp, '')
+                                     .replace(jsSuffixRegExp, '');
+                    });
+                }
+
+                //If there are any "waiting to execute" modules in the registry,
+                //update the maps for them, since their info, like URLs to load,
+                //may have changed.
+                eachProp(registry, function (mod, id) {
+                    //If module already has init called, since it is too
+                    //late to modify them, and ignore unnormalized ones
+                    //since they are transient.
+                    if (!mod.inited && !mod.map.unnormalized) {
+                        mod.map = makeModuleMap(id);
+                    }
+                });
+
+                //If a deps array or a config callback is specified, then call
+                //require with those args. This is useful when require is defined as a
+                //config object before require.js is loaded.
+                if (cfg.deps || cfg.callback) {
+                    context.require(cfg.deps || [], cfg.callback);
+                }
+            },
+
+            makeShimExports: function (value) {
+                function fn() {
+                    var ret;
+                    if (value.init) {
+                        ret = value.init.apply(global, arguments);
+                    }
+                    return ret || (value.exports && getGlobal(value.exports));
+                }
+                return fn;
+            },
+
+            makeRequire: function (relMap, options) {
+                options = options || {};
+
+                function localRequire(deps, callback, errback) {
+                    var id, map, requireMod;
+
+                    if (options.enableBuildCallback && callback && isFunction(callback)) {
+                        callback.__requireJsBuild = true;
+                    }
+
+                    if (typeof deps === 'string') {
+                        if (isFunction(callback)) {
+                            //Invalid call
+                            return onError(makeError('requireargs', 'Invalid require call'), errback);
+                        }
+
+                        //If require|exports|module are requested, get the
+                        //value for them from the special handlers. Caveat:
+                        //this only works while module is being defined.
+                        if (relMap && hasProp(handlers, deps)) {
+                            return handlers[deps](registry[relMap.id]);
+                        }
+
+                        //Synchronous access to one module. If require.get is
+                        //available (as in the Node adapter), prefer that.
+                        if (req.get) {
+                            return req.get(context, deps, relMap, localRequire);
+                        }
+
+                        //Normalize module name, if it contains . or ..
+                        map = makeModuleMap(deps, relMap, false, true);
+                        id = map.id;
+
+                        if (!hasProp(defined, id)) {
+                            return onError(makeError('notloaded', 'Module name "' +
+                                        id +
+                                        '" has not been loaded yet for context: ' +
+                                        contextName +
+                                        (relMap ? '' : '. Use require([])')));
+                        }
+                        return defined[id];
+                    }
+
+                    //Grab defines waiting in the global queue.
+                    intakeDefines();
+
+                    //Mark all the dependencies as needing to be loaded.
+                    context.nextTick(function () {
+                        //Some defines could have been added since the
+                        //require call, collect them.
+                        intakeDefines();
+
+                        requireMod = getModule(makeModuleMap(null, relMap));
+
+                        //Store if map config should be applied to this require
+                        //call for dependencies.
+                        requireMod.skipMap = options.skipMap;
+
+                        requireMod.init(deps, callback, errback, {
+                            enabled: true
+                        });
+
+                        checkLoaded();
+                    });
+
+                    return localRequire;
+                }
+
+                mixin(localRequire, {
+                    isBrowser: isBrowser,
+
+                    /**
+                     * Converts a module name + .extension into an URL path.
+                     * *Requires* the use of a module name. It does not support using
+                     * plain URLs like nameToUrl.
+                     */
+                    toUrl: function (moduleNamePlusExt) {
+                        var ext,
+                            index = moduleNamePlusExt.lastIndexOf('.'),
+                            segment = moduleNamePlusExt.split('/')[0],
+                            isRelative = segment === '.' || segment === '..';
+
+                        //Have a file extension alias, and it is not the
+                        //dots from a relative path.
+                        if (index !== -1 && (!isRelative || index > 1)) {
+                            ext = moduleNamePlusExt.substring(index, moduleNamePlusExt.length);
+                            moduleNamePlusExt = moduleNamePlusExt.substring(0, index);
+                        }
+
+                        return context.nameToUrl(normalize(moduleNamePlusExt,
+                                                relMap && relMap.id, true), ext,  true);
+                    },
+
+                    defined: function (id) {
+                        return hasProp(defined, makeModuleMap(id, relMap, false, true).id);
+                    },
+
+                    specified: function (id) {
+                        id = makeModuleMap(id, relMap, false, true).id;
+                        return hasProp(defined, id) || hasProp(registry, id);
+                    }
+                });
+
+                //Only allow undef on top level require calls
+                if (!relMap) {
+                    localRequire.undef = function (id) {
+                        //Bind any waiting define() calls to this context,
+                        //fix for #408
+                        takeGlobalQueue();
+
+                        var map = makeModuleMap(id, relMap, true),
+                            mod = getOwn(registry, id);
+
+                        removeScript(id);
+
+                        delete defined[id];
+                        delete urlFetched[map.url];
+                        delete undefEvents[id];
+
+                        //Clean queued defines too. Go backwards
+                        //in array so that the splices do not
+                        //mess up the iteration.
+                        eachReverse(defQueue, function(args, i) {
+                            if(args[0] === id) {
+                                defQueue.splice(i, 1);
+                            }
+                        });
+
+                        if (mod) {
+                            //Hold on to listeners in case the
+                            //module will be attempted to be reloaded
+                            //using a different config.
+                            if (mod.events.defined) {
+                                undefEvents[id] = mod.events;
+                            }
+
+                            cleanRegistry(id);
+                        }
+                    };
+                }
+
+                return localRequire;
+            },
+
+            /**
+             * Called to enable a module if it is still in the registry
+             * awaiting enablement. A second arg, parent, the parent module,
+             * is passed in for context, when this method is overridden by
+             * the optimizer. Not shown here to keep code compact.
+             */
+            enable: function (depMap) {
+                var mod = getOwn(registry, depMap.id);
+                if (mod) {
+                    getModule(depMap).enable();
+                }
+            },
+
+            /**
+             * Internal method used by environment adapters to complete a load event.
+             * A load event could be a script load or just a load pass from a synchronous
+             * load call.
+             * @param {String} moduleName the name of the module to potentially complete.
+             */
+            completeLoad: function (moduleName) {
+                var found, args, mod,
+                    shim = getOwn(config.shim, moduleName) || {},
+                    shExports = shim.exports;
+
+                takeGlobalQueue();
+
+                while (defQueue.length) {
+                    args = defQueue.shift();
+                    if (args[0] === null) {
+                        args[0] = moduleName;
+                        //If already found an anonymous module and bound it
+                        //to this name, then this is some other anon module
+                        //waiting for its completeLoad to fire.
+                        if (found) {
+                            break;
+                        }
+                        found = true;
+                    } else if (args[0] === moduleName) {
+                        //Found matching define call for this script!
+                        found = true;
+                    }
+
+                    callGetModule(args);
+                }
+
+                //Do this after the cycle of callGetModule in case the result
+                //of those calls/init calls changes the registry.
+                mod = getOwn(registry, moduleName);
+
+                if (!found && !hasProp(defined, moduleName) && mod && !mod.inited) {
+                    if (config.enforceDefine && (!shExports || !getGlobal(shExports))) {
+                        if (hasPathFallback(moduleName)) {
+                            return;
+                        } else {
+                            return onError(makeError('nodefine',
+                                             'No define call for ' + moduleName,
+                                             null,
+                                             [moduleName]));
+                        }
+                    } else {
+                        //A script that does not call define(), so just simulate
+                        //the call for it.
+                        callGetModule([moduleName, (shim.deps || []), shim.exportsFn]);
+                    }
+                }
+
+                checkLoaded();
+            },
+
+            /**
+             * Converts a module name to a file path. Supports cases where
+             * moduleName may actually be just an URL.
+             * Note that it **does not** call normalize on the moduleName,
+             * it is assumed to have already been normalized. This is an
+             * internal API, not a public one. Use toUrl for the public API.
+             */
+            nameToUrl: function (moduleName, ext, skipExt) {
+                var paths, syms, i, parentModule, url,
+                    parentPath, bundleId,
+                    pkgMain = getOwn(config.pkgs, moduleName);
+
+                if (pkgMain) {
+                    moduleName = pkgMain;
+                }
+
+                bundleId = getOwn(bundlesMap, moduleName);
+
+                if (bundleId) {
+                    return context.nameToUrl(bundleId, ext, skipExt);
+                }
+
+                //If a colon is in the URL, it indicates a protocol is used and it is just
+                //an URL to a file, or if it starts with a slash, contains a query arg (i.e. ?)
+                //or ends with .js, then assume the user meant to use an url and not a module id.
+                //The slash is important for protocol-less URLs as well as full paths.
+                if (req.jsExtRegExp.test(moduleName)) {
+                    //Just a plain path, not module name lookup, so just return it.
+                    //Add extension if it is included. This is a bit wonky, only non-.js things pass
+                    //an extension, this method probably needs to be reworked.
+                    url = moduleName + (ext || '');
+                } else {
+                    //A module that needs to be converted to a path.
+                    paths = config.paths;
+
+                    syms = moduleName.split('/');
+                    //For each module name segment, see if there is a path
+                    //registered for it. Start with most specific name
+                    //and work up from it.
+                    for (i = syms.length; i > 0; i -= 1) {
+                        parentModule = syms.slice(0, i).join('/');
+
+                        parentPath = getOwn(paths, parentModule);
+                        if (parentPath) {
+                            //If an array, it means there are a few choices,
+                            //Choose the one that is desired
+                            if (isArray(parentPath)) {
+                                parentPath = parentPath[0];
+                            }
+                            syms.splice(0, i, parentPath);
+                            break;
+                        }
+                    }
+
+                    //Join the path parts together, then figure out if baseUrl is needed.
+                    url = syms.join('/');
+                    url += (ext || (/^data\:|\?/.test(url) || skipExt ? '' : '.js'));
+                    url = (url.charAt(0) === '/' || url.match(/^[\w\+\.\-]+:/) ? '' : config.baseUrl) + url;
+                }
+
+                return config.urlArgs ? url +
+                                        ((url.indexOf('?') === -1 ? '?' : '&') +
+                                         config.urlArgs) : url;
+            },
+
+            //Delegates to req.load. Broken out as a separate function to
+            //allow overriding in the optimizer.
+            load: function (id, url) {
+                req.load(context, id, url);
+            },
+
+            /**
+             * Executes a module callback function. Broken out as a separate function
+             * solely to allow the build system to sequence the files in the built
+             * layer in the right sequence.
+             *
+             * @private
+             */
+            execCb: function (name, callback, args, exports) {
+                return callback.apply(exports, args);
+            },
+
+            /**
+             * callback for script loads, used to check status of loading.
+             *
+             * @param {Event} evt the event from the browser for the script
+             * that was loaded.
+             */
+            onScriptLoad: function (evt) {
+                //Using currentTarget instead of target for Firefox 2.0's sake. Not
+                //all old browsers will be supported, but this one was easy enough
+                //to support and still makes sense.
+                if (evt.type === 'load' ||
+                        (readyRegExp.test((evt.currentTarget || evt.srcElement).readyState))) {
+                    //Reset interactive script so a script node is not held onto for
+                    //to long.
+                    interactiveScript = null;
+
+                    //Pull out the name of the module and the context.
+                    var data = getScriptData(evt);
+                    context.completeLoad(data.id);
+                }
+            },
+
+            /**
+             * Callback for script errors.
+             */
+            onScriptError: function (evt) {
+                var data = getScriptData(evt);
+                if (!hasPathFallback(data.id)) {
+                    return onError(makeError('scripterror', 'Script error for: ' + data.id, evt, [data.id]));
+                }
+            }
+        };
+
+        context.require = context.makeRequire();
+        return context;
+    }
+
+    /**
+     * Main entry point.
+     *
+     * If the only argument to require is a string, then the module that
+     * is represented by that string is fetched for the appropriate context.
+     *
+     * If the first argument is an array, then it will be treated as an array
+     * of dependency string names to fetch. An optional function callback can
+     * be specified to execute when all of those dependencies are available.
+     *
+     * Make a local req variable to help Caja compliance (it assumes things
+     * on a require that are not standardized), and to give a short
+     * name for minification/local scope use.
+     */
+    req = requirejs = function (deps, callback, errback, optional) {
+
+        //Find the right context, use default
+        var context, config,
+            contextName = defContextName;
+
+        // Determine if have config object in the call.
+        if (!isArray(deps) && typeof deps !== 'string') {
+            // deps is a config object
+            config = deps;
+            if (isArray(callback)) {
+                // Adjust args if there are dependencies
+                deps = callback;
+                callback = errback;
+                errback = optional;
+            } else {
+                deps = [];
+            }
+        }
+
+        if (config && config.context) {
+            contextName = config.context;
+        }
+
+        context = getOwn(contexts, contextName);
+        if (!context) {
+            context = contexts[contextName] = req.s.newContext(contextName);
+        }
+
+        if (config) {
+            context.configure(config);
+        }
+
+        return context.require(deps, callback, errback);
+    };
+
+    /**
+     * Support require.config() to make it easier to cooperate with other
+     * AMD loaders on globally agreed names.
+     */
+    req.config = function (config) {
+        return req(config);
+    };
+
+    /**
+     * Execute something after the current tick
+     * of the event loop. Override for other envs
+     * that have a better solution than setTimeout.
+     * @param  {Function} fn function to execute later.
+     */
+    req.nextTick = typeof setTimeout !== 'undefined' ? function (fn) {
+        setTimeout(fn, 4);
+    } : function (fn) { fn(); };
+
+    /**
+     * Export require as a global, but only if it does not already exist.
+     */
+    if (!require) {
+        require = req;
+    }
+
+    req.version = version;
+
+    //Used to filter out dependencies that are already paths.
+    req.jsExtRegExp = /^\/|:|\?|\.js$/;
+    req.isBrowser = isBrowser;
+    s = req.s = {
+        contexts: contexts,
+        newContext: newContext
+    };
+
+    //Create default context.
+    req({});
+
+    //Exports some context-sensitive methods on global require.
+    each([
+        'toUrl',
+        'undef',
+        'defined',
+        'specified'
+    ], function (prop) {
+        //Reference from contexts instead of early binding to default context,
+        //so that during builds, the latest instance of the default context
+        //with its config gets used.
+        req[prop] = function () {
+            var ctx = contexts[defContextName];
+            return ctx.require[prop].apply(ctx, arguments);
+        };
+    });
+
+    if (isBrowser) {
+        head = s.head = document.getElementsByTagName('head')[0];
+        //If BASE tag is in play, using appendChild is a problem for IE6.
+        //When that browser dies, this can be removed. Details in this jQuery bug:
+        //http://dev.jquery.com/ticket/2709
+        baseElement = document.getElementsByTagName('base')[0];
+        if (baseElement) {
+            head = s.head = baseElement.parentNode;
+        }
+    }
+
+    /**
+     * Any errors that require explicitly generates will be passed to this
+     * function. Intercept/override it if you want custom error handling.
+     * @param {Error} err the error object.
+     */
+    req.onError = defaultOnError;
+
+    /**
+     * Creates the node for the load command. Only used in browser envs.
+     */
+    req.createNode = function (config, moduleName, url) {
+        var node = config.xhtml ?
+                document.createElementNS('http://www.w3.org/1999/xhtml', 'html:script') :
+                document.createElement('script');
+        node.type = config.scriptType || 'text/javascript';
+        node.charset = 'utf-8';
+        node.async = true;
+        return node;
+    };
+
+    /**
+     * Does the request to load a module for the browser case.
+     * Make this a separate function to allow other environments
+     * to override it.
+     *
+     * @param {Object} context the require context to find state.
+     * @param {String} moduleName the name of the module.
+     * @param {Object} url the URL to the module.
+     */
+    req.load = function (context, moduleName, url) {
+        var config = (context && context.config) || {},
+            node;
+        if (isBrowser) {
+            //In the browser so use a script tag
+            node = req.createNode(config, moduleName, url);
+
+            node.setAttribute('data-requirecontext', context.contextName);
+            node.setAttribute('data-requiremodule', moduleName);
+
+            //Set up load listener. Test attachEvent first because IE9 has
+            //a subtle issue in its addEventListener and script onload firings
+            //that do not match the behavior of all other browsers with
+            //addEventListener support, which fire the onload event for a
+            //script right after the script execution. See:
+            //https://connect.microsoft.com/IE/feedback/details/648057/script-onload-event-is-not-fired-immediately-after-script-execution
+            //UNFORTUNATELY Opera implements attachEvent but does not follow the script
+            //script execution mode.
+            if (node.attachEvent &&
+                    //Check if node.attachEvent is artificially added by custom script or
+                    //natively supported by browser
+                    //read https://github.com/jrburke/requirejs/issues/187
+                    //if we can NOT find [native code] then it must NOT natively supported.
+                    //in IE8, node.attachEvent does not have toString()
+                    //Note the test for "[native code" with no closing brace, see:
+                    //https://github.com/jrburke/requirejs/issues/273
+                    !(node.attachEvent.toString && node.attachEvent.toString().indexOf('[native code') < 0) &&
+                    !isOpera) {
+                //Probably IE. IE (at least 6-8) do not fire
+                //script onload right after executing the script, so
+                //we cannot tie the anonymous define call to a name.
+                //However, IE reports the script as being in 'interactive'
+                //readyState at the time of the define call.
+                useInteractive = true;
+
+                node.attachEvent('onreadystatechange', context.onScriptLoad);
+                //It would be great to add an error handler here to catch
+                //404s in IE9+. However, onreadystatechange will fire before
+                //the error handler, so that does not help. If addEventListener
+                //is used, then IE will fire error before load, but we cannot
+                //use that pathway given the connect.microsoft.com issue
+                //mentioned above about not doing the 'script execute,
+                //then fire the script load event listener before execute
+                //next script' that other browsers do.
+                //Best hope: IE10 fixes the issues,
+                //and then destroys all installs of IE 6-9.
+                //node.attachEvent('onerror', context.onScriptError);
+            } else {
+                node.addEventListener('load', context.onScriptLoad, false);
+                node.addEventListener('error', context.onScriptError, false);
+            }
+            node.src = url;
+
+            //For some cache cases in IE 6-8, the script executes before the end
+            //of the appendChild execution, so to tie an anonymous define
+            //call to the module name (which is stored on the node), hold on
+            //to a reference to this node, but clear after the DOM insertion.
+            currentlyAddingScript = node;
+            if (baseElement) {
+                head.insertBefore(node, baseElement);
+            } else {
+                head.appendChild(node);
+            }
+            currentlyAddingScript = null;
+
+            return node;
+        } else if (isWebWorker) {
+            try {
+                //In a web worker, use importScripts. This is not a very
+                //efficient use of importScripts, importScripts will block until
+                //its script is downloaded and evaluated. However, if web workers
+                //are in play, the expectation that a build has been done so that
+                //only one script needs to be loaded anyway. This may need to be
+                //reevaluated if other use cases become common.
+                importScripts(url);
+
+                //Account for anonymous modules
+                context.completeLoad(moduleName);
+            } catch (e) {
+                context.onError(makeError('importscripts',
+                                'importScripts failed for ' +
+                                    moduleName + ' at ' + url,
+                                e,
+                                [moduleName]));
+            }
+        }
+    };
+
+    function getInteractiveScript() {
+        if (interactiveScript && interactiveScript.readyState === 'interactive') {
+            return interactiveScript;
+        }
+
+        eachReverse(scripts(), function (script) {
+            if (script.readyState === 'interactive') {
+                return (interactiveScript = script);
+            }
+        });
+        return interactiveScript;
+    }
+
+    //Look for a data-main script attribute, which could also adjust the baseUrl.
+    if (isBrowser && !cfg.skipDataMain) {
+        //Figure out baseUrl. Get it from the script tag with require.js in it.
+        eachReverse(scripts(), function (script) {
+            //Set the 'head' where we can append children by
+            //using the script's parent.
+            if (!head) {
+                head = script.parentNode;
+            }
+
+            //Look for a data-main attribute to set main script for the page
+            //to load. If it is there, the path to data main becomes the
+            //baseUrl, if it is not already set.
+            dataMain = script.getAttribute('data-main');
+            if (dataMain) {
+                //Preserve dataMain in case it is a path (i.e. contains '?')
+                mainScript = dataMain;
+
+                //Set final baseUrl if there is not already an explicit one.
+                if (!cfg.baseUrl) {
+                    //Pull off the directory of data-main for use as the
+                    //baseUrl.
+                    src = mainScript.split('/');
+                    mainScript = src.pop();
+                    subPath = src.length ? src.join('/')  + '/' : './';
+
+                    cfg.baseUrl = subPath;
+                }
+
+                //Strip off any trailing .js since mainScript is now
+                //like a module name.
+                mainScript = mainScript.replace(jsSuffixRegExp, '');
+
+                 //If mainScript is still a path, fall back to dataMain
+                if (req.jsExtRegExp.test(mainScript)) {
+                    mainScript = dataMain;
+                }
+
+                //Put the data-main script in the files to load.
+                cfg.deps = cfg.deps ? cfg.deps.concat(mainScript) : [mainScript];
+
+                return true;
+            }
+        });
+    }
+
+    /**
+     * The function that handles definitions of modules. Differs from
+     * require() in that a string for the module should be the first argument,
+     * and the function to execute after dependencies are loaded should
+     * return a value to define the module corresponding to the first argument's
+     * name.
+     */
+    define = function (name, deps, callback) {
+        var node, context;
+
+        //Allow for anonymous modules
+        if (typeof name !== 'string') {
+            //Adjust args appropriately
+            callback = deps;
+            deps = name;
+            name = null;
+        }
+
+        //This module may not have dependencies
+        if (!isArray(deps)) {
+            callback = deps;
+            deps = null;
+        }
+
+        //If no name, and callback is a function, then figure out if it a
+        //CommonJS thing with dependencies.
+        if (!deps && isFunction(callback)) {
+            deps = [];
+            //Remove comments from the callback string,
+            //look for require calls, and pull them into the dependencies,
+            //but only if there are function args.
+            if (callback.length) {
+                callback
+                    .toString()
+                    .replace(commentRegExp, '')
+                    .replace(cjsRequireRegExp, function (match, dep) {
+                        deps.push(dep);
+                    });
+
+                //May be a CommonJS thing even without require calls, but still
+                //could use exports, and module. Avoid doing exports and module
+                //work though if it just needs require.
+                //REQUIRES the function to expect the CommonJS variables in the
+                //order listed below.
+                deps = (callback.length === 1 ? ['require'] : ['require', 'exports', 'module']).concat(deps);
+            }
+        }
+
+        //If in IE 6-8 and hit an anonymous define() call, do the interactive
+        //work.
+        if (useInteractive) {
+            node = currentlyAddingScript || getInteractiveScript();
+            if (node) {
+                if (!name) {
+                    name = node.getAttribute('data-requiremodule');
+                }
+                context = contexts[node.getAttribute('data-requirecontext')];
+            }
+        }
+
+        //Always save off evaluating the def call until the script onload handler.
+        //This allows multiple modules to be in a file without prematurely
+        //tracing dependencies, and allows for anonymous module support,
+        //where the module name is not known until the script onload event
+        //occurs. If no context, use the global queue, and get it processed
+        //in the onscript load callback.
+        (context ? context.defQueue : globalDefQueue).push([name, deps, callback]);
+    };
+
+    define.amd = {
+        jQuery: true
+    };
+
+
+    /**
+     * Executes the text. Normally just uses eval, but can be modified
+     * to use a better, environment-specific call. Only used for transpiling
+     * loader plugins, not for plain JS modules.
+     * @param {String} text the text to execute/evaluate.
+     */
+    req.exec = function (text) {
+        /*jslint evil: true */
+        return eval(text);
+    };
+
+    //Set up with config info.
+    req(cfg);
+}(this));
diff --git a/test/usage/rey.jpeg b/test/usage/rey.jpeg
new file mode 100644
index 0000000..a399b78
Binary files /dev/null and b/test/usage/rey.jpeg differ
diff --git a/test/usage/style.css b/test/usage/style.css
new file mode 100644
index 0000000..4c744c5
--- /dev/null
+++ b/test/usage/style.css
@@ -0,0 +1,87 @@
+    .list {
+      font-family:sans-serif;
+      margin:0;
+      padding:20px 0 0;
+    }
+    .list > li {
+      display:block;
+      background-color: #eee;
+      padding:10px;
+      box-shadow: inset 0 1px 0 #fff;
+    }
+    .avatar {
+      max-width: 150px;
+    }
+    img {
+      max-width: 100%;
+    }
+    h3 {
+      font-size: 16px;
+      margin:0 0 0.3rem;
+      font-weight: normal;
+      font-weight:bold;
+    }
+    p {
+      margin:0;
+    }
+
+    input {
+      border:solid 1px #ccc;
+      border-radius: 5px;
+      padding:7px 14px;
+      margin-bottom:10px
+    }
+    input:focus {
+      outline:none;
+      border-color:#aaa;
+    }
+    .sort {
+      padding:8px 30px;
+      border-radius: 6px;
+      border:none;
+      display:inline-block;
+      color:#fff;
+      text-decoration: none;
+      background-color: #28a8e0;
+      height:30px;
+    }
+    .sort:hover {
+      text-decoration: none;
+      background-color:#1b8aba;
+    }
+    .sort:focus {
+      outline:none;
+    }
+    .sort:after {
+      width: 0;
+      height: 0;
+      border-left: 5px solid transparent;
+      border-right: 5px solid transparent;
+      border-bottom: 5px solid transparent;
+      content:"";
+      position: relative;
+      top:-10px;
+      right:-5px;
+    }
+    .sort.asc:after {
+      width: 0;
+      height: 0;
+      border-left: 5px solid transparent;
+      border-right: 5px solid transparent;
+      border-top: 5px solid #fff;
+      content:"";
+      position: relative;
+      top:13px;
+      right:-5px;
+    }
+    .sort.desc:after {
+      width: 0;
+      height: 0;
+      border-left: 5px solid transparent;
+      border-right: 5px solid transparent;
+      border-bottom: 5px solid #fff;
+      content:"";
+      position: relative;
+      top:-10px;
+      right:-5px;
+    }

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-javascript/list.js.git



More information about the Pkg-javascript-commits mailing list