{"id":28092411,"url":"https://github.com/epitome-mvc/epitome","last_synced_at":"2025-05-13T13:12:54.195Z","repository":{"id":3527910,"uuid":"4587132","full_name":"epitome-mvc/Epitome","owner":"epitome-mvc","description":"Epitome is a MVC* (MVP) framework for MooTools.","archived":false,"fork":false,"pushed_at":"2015-02-12T18:48:06.000Z","size":2404,"stargazers_count":48,"open_issues_count":1,"forks_count":11,"subscribers_count":12,"default_branch":"master","last_synced_at":"2025-05-12T00:24:58.444Z","etag":null,"topics":["javascript","mootools","mvc"],"latest_commit_sha":null,"homepage":"http://epitome-mvc.github.io/Epitome/","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/epitome-mvc.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2012-06-07T15:48:47.000Z","updated_at":"2024-05-05T11:39:16.000Z","dependencies_parsed_at":"2022-09-11T16:50:10.347Z","dependency_job_id":null,"html_url":"https://github.com/epitome-mvc/Epitome","commit_stats":null,"previous_names":["dimitarchristoff/epitome"],"tags_count":15,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/epitome-mvc%2FEpitome","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/epitome-mvc%2FEpitome/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/epitome-mvc%2FEpitome/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/epitome-mvc%2FEpitome/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/epitome-mvc","download_url":"https://codeload.github.com/epitome-mvc/Epitome/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":253948447,"owners_count":21988959,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["javascript","mootools","mvc"],"created_at":"2025-05-13T13:12:53.345Z","updated_at":"2025-05-13T13:12:54.179Z","avatar_url":"https://github.com/epitome-mvc.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"![Epitome](https://github.com/DimitarChristoff/Epitome/raw/master/example/epitome-logo.png)\n\n\u003e _Epitome: a typical example of a characteristic or class; embodiment; personification; model_\n\nEpitome is a small extensible and modular open-source MVC* framework, built out of MooTools Classes and Events. See [credits and licensing](#credits-and-licensing)\n\n[![Build Status](https://secure.travis-ci.org/DimitarChristoff/Epitome.png?branch=master)](http://travis-ci.org/DimitarChristoff/Epitome)\n\nIf you feel strongly about semantics of the patterns used, you should look at [Digesting JavaScript MVC – Pattern Abuse Or Evolution?](http://addyosmani.com/blog/digesting-javascript-mvc-pattern-abuse-or-evolution/) by Addy Osmani, a talk he gave at London Ajax recently. Epitome can be used as MVP or even classic MVC since you can create pure controllers out of MooTools Classes.\n\nCurrent version: **0.6.1**\n\n\u003ca class=\"btn btn-large btn-primary\" href=\"#download-building\"\u003eEpitome Builder\u003c/a\u003e\n\u003ca class=\"btn btn-large\" href=\"https://epitomemvp.uservoice.com/\" target=\"_blank\"\u003eIssue / Discussion on UserVoice\u003c/a\u003e\n\nA quick-and-dirty way to add the whole minified library, courtesy of cdnjs.com (probably out of date):\n```HTML\n\u003cscript src=\"//cdnjs.cloudflare.com/ajax/libs/epitome/0.3.0/Epitome-min.js\"\u003e\u003c/script\u003e\n```\n\n\u003e As of January 2014, going forward notice: due to MooTools' decline, Epitome will be supported only with bug fixes. You should look at [epik](https://github.com/DimitarChristoff/epik) instead, which is Epitome 2 without MooTools - built on top of [primish](https://github.com/DimitarChristoff/primish) and lodash.\n\n\n## Changelog\n- 0.6.2\n - BUGFIX: fixed change event fires in error when value is falsy and is not actually different\n- 0.6.1\n - Breaking: custom setters need to return a value only, not re-implement `_set` (see #14)\n- 0.6.0\n - Breaking: enabled `Slick.parser` under `node.js` via [slicker](http://npmjs/slicker/). Collection.find methods now work\n just like they do in the browser.\n- 0.5.0\n - BUGFIX: Collection needs `.length === 0` when instantiated w/o any models\n - `Collection.reset` removes models first\n- 0.4.1\n - Updated `bower.json` and added a `.npmignore` to stop distributing docs and tests as component install\n- 0.4.0\n - Added CommonJS suport to Model, Collection, Template, Events and isEqual, reliant on `mootools npm`\n- 0.3.1\n - Added `.jshintrc` and changed all files to pass linting settings\n- 0.3.0\n - Breaking API change, all events are now via `.on` / `.off` / `.trigger`\n - Added `.listenTo(obj, event, cb)` and `.stopListening(obj, event, cb)` methods for easy pubsub and event bubbling\n- 0.2.2\n - fixed a validators error firing errors without there being any.\n- 0.2.1\n - the default Epitome Object now returns an instance of Events so you can mediate like `Epitome.trigger('awesome')`\n between components. \n- 0.2.0\n - big shift in he way Sync works with servers. Previously, Model and Collection were only accepting `application/json` as\n content type to be returned. Failing to receive that caused the browser not to fire any readystatechange events, which in\n turn caused all change/save/sync/error events not to bubble. As of this version, Epitome will also accept `text/plain` and\n `text/html` as fallbacks. There is still an expectation to convert the responseText to an Object, so failure to do so will\n fire `error` events instead.\n - Model.Sync now accept an optional argument `request`, which accepts a Class constructor for the MooTools Request with\n your own definition of what success/failure is and conversion to JSON.\n- 0.1.10\n - fixed bug where fetch/save/create/update events were firing before model.isNew was being changed\n- 0.1.9\n - added `headers` to Model.Sync options that gets passed to the Request\n- 0.1.8\n - added `queryParams` support to Collection.Sync::fetch, allows for pagination etc.\n- 0.1.7\n - updated templating engine to a later version based on the one in _.js\n - added support for `\u003c%-var%\u003e` syntax to allow escaping of entities\n - Internally, extending the MooTools String proto and adding `escape` for dealing with entities in strings.\n - Updated tests\n- 0.1.6\n - build.js server changes\n - moved to uglify2 for minification\n - updated Epitome-min.js to reflect\n - prevented stacking up for function deocration for Model instances' `.fireEvent`\n - merged example tweak PR\n- 0.1.5\n - small tweaks to AMD/browser wrappers, no breaking changes\n- 0.1.4\n - breaking API change. deprecated: `model.sync.parse`, replaced with `preProcessor` and `postProcessor`\n\nAll individual components of Epitome work as normal javscript files to be used in a browser as well as through `require.js` modules. See [Downloading + Building](#download-building)\n\n\n## Epitome.Events\n\nA lightweight replacement for the default MooTools Events class that adds shorthand for ease of use.\n\n### on\n---\n\u003cdiv class=\"alert\"\u003e\n\u003cp\u003e\n_Expects arguments mixed: `(String) name, (Function) callback` or `(Object) name:callback` pairs_\n\u003c/p\u003e\n\u003cp\u003e\n_Returns: `this`_\n\u003c/p\u003e\n\u003c/div\u003e\n\nAttaches an event or an event object on any Epitome instance (Model, Collection, View). You can also add multiple events\nthat will trigger the same callback function. Examples:\n```javascript\n// single\nthis.on('change', this.modelChange.bind(this));\n\n// multiple\nthis.model.on('fetch change', this.render.bind(this));\n```\n\n### off\n---\n\u003cdiv class=\"alert\"\u003e\n\u003cp\u003e\n_Expects arguments mixed: `(String) name`, optional `(Function) callback` or `(Object) name:callback` pairs_\n\u003c/p\u003e\n\u003cp\u003e\n_Returns: `this`_\n\u003c/p\u003e\n\u003c/div\u003e\n\nRemoves a specific event callback (if supplied) or all events sharing the same name (wildcard) when not.\n\n### trigger\n---\n\u003cdiv class=\"alert\"\u003e\n\u003cp\u003e\n_Expects arguments mixed: `(String) name`, optional `(Array) arguments`_\n\u003c/p\u003e\n\u003cp\u003e\n_Returns: `this`_\n\u003c/p\u003e\n\u003c/div\u003e\n\nFires an event on the current instance, passing any arguments passed (as Array or mixed).\n\n### listenTo\n---\n\u003cdiv class=\"alert\"\u003e\n\u003cp\u003e\n_Expects arguments mixed: `(Object) instance`, optional `(String) name`, optional `(Function) callback`_\n\u003c/p\u003e\n\u003cp\u003e\n_Returns: `this`_\n\u003c/p\u003e\n\u003c/div\u003e\n\nSubscribes to another instance's events. Can be broad or specific in how it attaches a listener. If no event name is\nsupplied, it will subscribe to ANY event fired by the other object instance. If no function callback is supplied, it will\nbubble the event onto the host object instance but shift the callback arguments by 1, placing the other object instance\nas the first argument. Use with caution as it can cause `event storms` if not much specificity has been set.\n\n### stopListening\n---\n\u003cdiv class=\"alert\"\u003e\n\u003cp\u003e\n_Expects arguments mixed: `(Object) instance`, optional `(String) name`, optional `(Function) callback`_\n\u003c/p\u003e\n\u003cp\u003e\n_Returns: `this`_\n\u003c/p\u003e\n\u003c/div\u003e\n\nUn-subscribes your instance from another instance's Events. If no arguments supplied other than the other instance, it\nwill remove all subscriptions. You can optionally narrow it down by adding an event name or a name and a function in\nparticular you'd like to un-subscribe from.\n\n## Epitome.Model\n\nThe Epitome.Model implementation at its core is a MooTools class with custom data accessors that fires events. As a MooTools Class, you can extend models or implement objects or other classes into your definitions. By default, the it comes with Epitome.Events and Options setters already (similar to the MooTools Class.Extras ones).\n\nThe Model can fire the following events:\n\n* `ready` - when instantiated\n* `change` - when any properties have changed\n* `change:key` - when a particular property `key` has changed\n* `empty` - when a model has been emptied of all properties\n* `destroy` - when a model has been `destroyed` and all data removed.\n\nThe following methods are official API on all Model Classes:\n\n### constructor (initialize)\n---\n\u003cdiv class=\"alert\"\u003e\n\u003cp\u003e\n_Expects arguments: `(Object) model`, `(Object) options`_\n\u003c/p\u003e\n\u003cp\u003e\n_Returns: `this`_\n\u003c/p\u003e\n\u003cp\u003e\n_Events: `ready`_\n\u003c/p\u003e\n\u003c/div\u003e\n\nThe `model` - if passed, sets the internal data hash to a new derefrenced object. Special accessor properties, as defined in the `Epitome.Model.prototype.properties`, will run first and be applicable. See [properties](#epitomemodel/model-properties) for more info.\n\nThe `options` object is a standard MooTools class options override and is being merged with the `Epitome.Model.prototype.options` when a new model is created. It typically contains various event handlers in the form of:\n\n```ace\nvar model = new Epitome.Model({}, {\n   defaults: {\n       userTitle: 'admin'\n   }\n});\n\nmodel.set('name', 'Bob');\nconsole.log(model.toJSON());\n```\n\nSupported: `(Object) options.defaults` - allows initial values of the model to be set if they are not being passed to the model constructor.\n\nOf note, the Constructor fires an event called `ready` when done and setting the initial model does not fire a `change` event.\n\n### set\n---\n\u003cdiv class=\"alert\" markdown=\"1\"\u003e\n\u003cp\u003e\n_Expects arguments: mixed: `(String) key`, `(Mixed) value` - pair - or: `(Object) obj`_\n\u003c/p\u003e\n\u003cp\u003e\n_Returns: `this`_\n\u003c/p\u003e\n\u003cp\u003e\n_Events:_\n\n\u003cul\u003e\n \u003cli\u003e `change: function(changedProperties) {}`\u003c/li\u003e\n \u003cli\u003e `change:key: function(valueForKey) {}`\u003c/li\u003e\n \u003cli\u003e `error: function(objectFailedValidation) {}`\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/p\u003e\n\u003c/div\u003e\n\nAllows changing of any individual model key or a set of key/value pairs, encapsulated in an object. Will fire a single `change` event with all the changed properties as well as a specific `change:key` event that passes just the value of the key as argument.\n\nFor typing of value, you can store anything at all (Primitives, Objects, Functions). Keep in mind that, when it comes to serialising the Model and sending it to the server, only Primitive types or ones with a sensible `toString()` implementation will make sense.\n\n### get\n---\n\u003cdiv class=\"alert\"\u003e\n\u003cp\u003e\n_Expects arguments mixed: `(String) key` or `(Array) keys`_\n\u003c/p\u003e\n\u003cp\u003e\n_Returns: `this`_\n\u003c/p\u003e\n\u003c/div\u003e\n\nReturns known values within the model for either a single key or an array of keys. For an array of keys, it will return an object with `key` : `value` mapping.\n\n### toJSON\n------\n\u003cdiv class=\"alert\"\u003e\n\u003cp\u003e\n_Expects arguments: none_\n\u003c/p\u003e\n\u003c/div\u003e\n\nReturns a de-referenced Object, containing all the known model keys and values.\n\n### unset\n-----\n\u003cdiv class=\"alert\"\u003e\n\u003cp\u003e\n_Expects arguments: mixed: `(String) key` or `(Array) keys`_\n\u003c/p\u003e\n\u003cp\u003e\n_Returns: `this`_\n\u003c/p\u003e\n\u003c/div\u003e\n\nRemoves keys from model, either a single one or an array of multiple keys. Does not fire a change event.\n\n### empty\n-----\n\u003cdiv class=\"alert\"\u003e\n\u003cp\u003e\n_Expects arguments: none_\n\u003c/p\u003e\n\u003cp\u003e\n_Returns: `this`_\n\u003c/p\u003e\n\u003cp\u003e\n_Events: `empty`_\n\u003c/p\u003e\n\u003c/div\u003e\n\nEmpties the model of all data and fires a single change event with all keys as well as individual `change:key` events.\n\n### destroy\n-------\n\u003cdiv class=\"alert\"\u003e\n\u003cp\u003e\n_Expects arguments: none_\n\u003c/p\u003e\n\u003cp\u003e\n_Returns: `this`_\n\u003c/p\u003e\n\u003cp\u003e\n_Events: `destroy`_\n\u003c/p\u003e\n\u003c/div\u003e\n\nEmpties the model. No change event. Event is observed by Collections the model is a member of, where it triggers a `removeModel()`\n\n\n### Model properties*\n\nThere are several additional properties each model instance will have.\n\n#### _attributes: {}\n---------------\nThe attributes object is __public__ (exposed to manipulation on the instance) and it holds the hash data for the model, based upon keys. It is de-referenced from the constructor object used when creating a model but should not be read directly (normally). Exported by `model.toJSON()`. Avoid changing this directly as it won't fire any change events at all.\n\n#### collections: []\n---------------\nAn array that contains references to all instances of Epitome.Collection that the model is currently a member of. Useful for iteration as well as utilised by collections that want to know if Event observers are required.\n\n#### options: {}\n-----------\nA MooTools default options set, which can be on the prototype of the Model constructor.\n\n#### options.defaults: {}\n--------------------\nAn object with default Model Attributes to use when instantiating. Merged with Model object when creating.\n\n#### changedProperties: []\n--------------\nAn array of all property keys that reflect the last `change` event. Available on all instances.\n\n#### properties: {}\n--------------\nA collection of custom accessors that override default `model.get` and `model.set` methods. For example:\n\n```javascript\nproperties: {\n    foo: {\n        get: function() {\n            // scope is model\n            return this.foo();\n        },\n        set: function(value) {\n            // don't send this to the attributes, store in the instance directly.\n            // won't fire a traditional onChange, you need to manually fire the events\n            this.foo = value;\n        }\n    }\n}\n```\nIn the example above, any calls to `model.set('foo', value)` and `model.get('foo')` are handled by custom functions. This is a pattern that allows you to use getters and setters for properties that are handled differently than normal ones. It can also be used as pre-processors for data. Make sure that you either set them on the instance directly or that you import the default ones for id in a custom prototype version as they are not merged like options.\n\nIf you want, you can also use custom setters as transformers. For instance, decorating a property `price` with a currency sign:\n```javascript\nproperties: {\n    price: {\n        set: function(value) {\n            // failing to return a value here won't set anything.\n            return '$' + value; // will fire all the change events for you.\n        }\n    }\n}\n```\n\n### Model validators*\n\nYou can also include basic validators into your model. Validators are an object on the Model prototype that maps any expected key to a function that will return `true` if the validation passes or a `string` error message or `false` on failure.\n\nHere is an example:\n```ace\nvar validUser = new Class({\n    Extends: Epitome.Model,\n    validators: {\n        email: function(value) {\n            return (/(.+)@(.+){2,}\\.(.+){2,}/).test(value) ? true : 'This looks like an invalid email address';\n        }\n    }\n});\n\nvar userInstance = new validUser({}, {\n    onError: function(allErrors) {\n        console.log('The following fields were rejected', allErrors);\n    },\n    'onError:email': function(errorObj) {\n        // can have a custom message, action or whatever.\n        console.log('Email rejected', errorObj.error);\n    }\n});\n\nuserInstance.set('email', 'this will fail!');\n```\nThe `error` event is observed by collections and views and fires on all view and collection instances.\n\n## Epitome.Model.Sync\n\nThis is an example implementation of RESTful module that extends the base Epitome.Model class and adds the ability to read, update and delete models with remote server. In terms of implementation, there are subtle differences. The API and methods are as the normal [Model](#epitomemodel), unless outlined below:\n\n### constructor (initialize)\n---\n\u003cdiv class=\"alert\"\u003e\n\u003cp\u003e\n_Expects arguments: `(Object) model`, `(Object) options`_\n\u003c/p\u003e\n\u003c/div\u003e\n\nA model `id` with your model as well as setup a `urlRoot` either as a property of the model or as an options property is required for your model to be synced. The constructor function first calls the Epitome.Model constructor and then sets up the XHR instance and methods.\n\n\u003cdiv class=\"alert\"\u003e\n`options.useJSON` (boolean) is an all-important way to control how your Model talks to your server backend. If your server is a native REST implementation, when this value is `true`, Epitome Sync will set the content-type to application/json and send a strigified JSON of your model on every POST or PUT operation.\n \u003c/div\u003e\n\nAn additional option has been added `options.emulateREST: true || false`, which is being passed to the Request instance. If your server has no CRUD mapping, emulation can be enabled so everything will go through POST/GET requests with `_method` containing the original intent.\n\n`options.headers` (object) is an extra argument that gets passed to the Request instance, allowing you to set whatever you want for CSRF or CORS on your Model.Sync calls.\n\n`options.request` (Class) is a constructor to instantiate into `this.request` on the model instance. It needs to support all the APIs and functionality of MooTools' Request.JSON.\n\n### sync\n---\n\u003cdiv class=\"alert\"\u003e\n\u003cp\u003e\nExpects optional arguments: `(String) method`, `(Object) model`_\n\u003c/p\u003e\n\u003cp\u003e\n_Events: `sync: function(responseObj, method, options) {}`_\n\u003c/p\u003e\n\u003c/div\u003e\n\nSync acts as a proxy/interface to the XHR instance in the model `this.request` A method can be one of the following:\n\u003e get, post, create, read, delete, update\n\nIf no method is supplied, a `read` is performed.\n\nThe second argument `model` is optional and should be a simple object. If it is not supplied, the default `model.toJSON()` is used instead.\n\nAs a whole, you should NOT use the sync directly but elect to use the API methods for each specific request task.\n\n__WARNING:__ Epitome is a REST framework. Please make sure you are returning a valid JSON string or 204 (no content) after all requests -\notherwise, the save events may not fire. Additionally, try to ensure `application/json` content type of your response, although\n`text/html` and `text/plain` will also be accepted, as long as the responseText can be parsed into an Object.\n\n### postProcessor\n---\n\u003cdiv class=\"alert\"\u003e\n\u003cp\u003e\n_Expects arguments: `(Object) response`_\n\u003c/p\u003e\n\u003cp\u003e\n_Expected return: `(Object) response`_\n\u003c/p\u003e\n\u003c/div\u003e\n\nA method that you can extend in your definition of Models for doing any post-processing of data `returned` by sync from the server. For example:\n\n```javascript\npostProcessor: function(response) {\n    // data comes back with decoration. split them first.\n    this.meta = response.meta;\n    return response.data;\n}\n```\n\n### save\n---\n\u003cdiv class=\"alert\"\u003e\n\u003cp\u003e\n_Expects optional arguments: `(String) key`, `(String) value`_\n\u003c/p\u003e\n\u003cp\u003e\n_Returns: `this`_\n\u003c/p\u003e\n\u003cp\u003e\n_Events: `save`, `sync`, possibly `create`, `update`_\n\u003c/p\u003e\n\u003c/div\u003e\n\nThe save should send the contents of the model to the server for storage. If it is a model that has not been saved before or fetched from the server, it will do so via `create()`, else, it will use `update()` instead.\n\nIf the optional `key` =\u003e `value` pair is passed, it will set them on the model and then save the updated model.\n\n### preProcessor\n---\n\u003cdiv class=\"alert\"\u003e\n\u003cp\u003e\n_Expects arguments: `(Object) response`_\n\u003c/p\u003e\n\u003cp\u003e\n_Expected return: `(Object) response`_\n\u003c/p\u003e\n\u003c/div\u003e\n\nA method that you can add to your definition of Models for doing any pre-processing of data before using `CREATE` or `UPDATE` (so, `save`) via sync to the server. For example:\n\n```javascript\npreProcessor: function(data) {\n    // remove local property 'meta' which the server does not like.\n    delete data.meta;\n    return data;\n}\n```\n\n### fetch\n---\n\u003cdiv class=\"alert\"\u003e\n\u003cp\u003e\n_Expects arguments: none_\n\u003c/p\u003e\n\u003cp\u003e\n_Returns: `this`_\n\u003c/p\u003e\n\u003cp\u003e\n_Events: `fetch`, `sync`, `read`_\n\u003c/p\u003e\n\u003c/div\u003e\n\nIt will request the server to return the model object for the current id via a `.read()`. It will also change the status of the model (`model.isNewModel`) to false, meaning `.save()` will never use `.create()`. The fetch event will fire once the response object has been returned. The response object is then merged with the current model via a `.set`, it won't empty your data. To do so, you need to issue a `.empty()` first.\n\n## Epitome.Collection\n\nEpitome collections are in essence, an Array-like Class that can contain multiple Models. It has a basic model prototype and adding and removing of models works either based upon passing a simple data has or an actual Model instance. When a model is in a collection, it observes all of the model events and fires them on the collection instance. It also allows for filtering, mapping, sorting and many other more convenience methods.\n\n### constructor (initialize)\n---\n\u003cdiv class=\"alert\"\u003e\n\u003cp\u003e\n_Expects arguments: `(Array) models / objects` (or a single model /object), `(Object) options`_\n\u003c/p\u003e\n\u003cp\u003e\n_Returns: `this`_\n\u003c/p\u003e\n\u003cp\u003e\n_Events: `ready`_\n\u003c/p\u003e\n\u003c/div\u003e\n\nThe constructor method will accept a large variety of arguments. You can pass on either an Array of Models or an Array of Objects or a single Model or a single Object. You can also pass an empty Array and populate it later. Typical Collection prototype definition looks something like this:\n```ace\nvar userModel = new Class({Extends: Epitome.Model}),\n\tusersCollection = new Class({\n\t\tExtends: Epitome.Collection,\n        model: userModel // or Epitome.Model by default\n\t});\n\nvar users = new usersCollection([{\n    id: 'bob'\n}], {\n    onChange: function(model, props) {\n        console.log('model change', model, props);\n    },\n    onReady: function() {\n        console.log('the collection is ready');\n    }\n});\n```\nFor reference purposes, each Model that enters a collection needs to have a `cid` - collection id. If the Model has an `id`, that is preferred. Otherwise, a `cid` will be generated. If the Model gets an `id` later on, the `cid` will not be changed.\n\n\u003cdiv class=\"alert alert-info\"\u003e\n\u003cp\u003e\n_Please note that Collections **observe** and bubble **all** model events. For instance, if a Model fires `change`, the Collection instance will fire `onChange`, passing the model as `arguments[0]` and then keeping the rest of the arguments in their original order. For the purposes of implementing this, a decorated local copy of each Model's `.fireEvent` method is created instead of the one from Class.Event prototype. Once a Model stops being a member of collections, the original `fireEvent` is restored by deleting the local method on the Model instance._\n\u003c/p\u003e\n\u003c/div\u003e\n\n### reset\n---\n\u003cdiv class=\"alert\"\u003e\n\u003cp\u003e\n_Expects arguments: `(Mixed) model(s)` , `(Boolean) quiet`_\n\u003c/p\u003e\n\u003cp\u003e\n_Returns: `this`_\n\u003c/p\u003e\n\u003cp\u003e\n_Events: `reset: function() {}`_\n\u003c/p\u003e\n\u003c/div\u003e\n\nInitial collection population and adding of models at a later stage. Accepts either a single model or an array. Fires a `reset` event.\n\n### addModel\n---\n\u003cdiv class=\"alert\"\u003e\n\u003cp\u003e\n_Expects arguments: `(Mixed) model` , `(Boolean) replace`_\n\u003c/p\u003e\n\u003cp\u003e\n_Returns: `this`_\n\u003c/p\u003e\n\u003cp\u003e\n_Events: `add: function(model, cid) {}`_\n\u003c/p\u003e\n\u003c/div\u003e\n\nAdding a Model to a Collection must always happen through this method. It either appends the Model instance to the internal `_models` Array or it creates a new Model and then appends it. It also starts observing the Model's events and emitting them to the Collection instance with an additional argument passed `Model`. So, if you add a Model stored in `bob` and then do `bob.trigger('hai', 'there')`, the collection will also fire an event like this: `this.trigger('hai', [bob, 'there']); Adding a Model also increases the `Collection.length` property.\n\nThe monitoring of the events (Observer) is done through creating a local function override / decoration of the Model's `fireEvent` method, normally inherited from the MooTools Events Class. If a model stops being a part of a collection, the override is destroyed and the default `fireEvent`.\n\n### removeModel\n---\n\u003cdiv class=\"alert\"\u003e\n\u003cp\u003e\n_Expects arguments: `(Mixed) model(s)`_\n\u003c/p\u003e\n\u003cp\u003e\n_Returns: `this`_\n\u003c/p\u003e\n\u003cp\u003e\n_Events: `remove: function(model, cid) {}`, `reset`_\n\u003c/p\u003e\n\u003c/div\u003e\n\nThis method allows you to remove a single model or an array of models from the collection in the same call. For each removed model, a `remove` Event will fire. When removing of all Models is done, the collection will also fire a `reset` event, allowing you to re-render your views if you like.\n\nIn addition to removing the Model from the Collection, it removes the reference to the Collection in the Model's `collections` Array. If that model stops being a member of any collection, the observed `fireEvent` method is removed from the Model instance, resulting in the method from the Events Class prototype taking over.\n\nDecreases the `Collection.length` property.\n\n### getModel\n---\n\u003cdiv class=\"alert\"\u003e\n\u003cp\u003e\n_Expects arguments: `(Number) id`_\n\u003c/p\u003e\n\u003cp\u003e\n_Returns: `modelInstance` or `null`_\n\u003c/p\u003e\n\u003c/div\u003e\n\nReturns a model based upon the Array index in the Collection.\n\n### getModelByCID\n---\n\u003cdiv class=\"alert\"\u003e\n\u003cp\u003e\n_Expects arguments: `(String) cid`_\n\u003c/p\u003e\n\u003cp\u003e\n_Returns: `modelInstance` or `null`_\n\u003c/p\u003e\n\u003c/div\u003e\n\nPerforms a search in the collection by `cid` (Collection id). Returns found Model instance or `null` if no match is found.\n\n### getModelById\n---\n\u003cdiv class=\"alert\"\u003e\n\u003cp\u003e\n_Expects arguments: `(String) id`_\n\u003c/p\u003e\n\u003cp\u003e\n_Returns: `modelInstance` or `null`_\n\u003c/p\u003e\n\u003c/div\u003e\n\nPerforms a search in the collection by the Model's `id` via the standard `getter`. Returns found Model instance or `null` if no match is found.\n\n### toJSON\n---\n\u003cdiv class=\"alert\"\u003e\n\u003cp\u003e\n_Expects arguments: none_\n\u003c/p\u003e\n\u003cp\u003e\n_Returns: `modelsData`_\n\u003c/p\u003e\n\u003c/div\u003e\n\nReturns an array of the applied `toJSON` method on all Models in the collection.\n\n### empty\n---\n\u003cdiv class=\"alert\"\u003e\n\u003cp\u003e\n_Expects arguments: none_\n\u003c/p\u003e\n\u003cp\u003e\n_Returns: `this`_\n\u003c/p\u003e\n\u003cp\u003e\n_Events: `remove`, `reset`, `empty`_\n\u003c/p\u003e\n\u003c/div\u003e\n\nApplies `this.removeModel` to all Models of the collection. Fires `empty` when done - though before that, a `remove` and `reset` will fire, see [removeModel](#epitomecollection/removemodel)\n\n### sort\n---\n\u003cdiv class=\"alert\"\u003e\n\u003cp\u003e\n_Expects arguments: (Mixed) how_\n\u003c/p\u003e\n\u003cp\u003e\n_Returns: `this`_\n\u003c/p\u003e\n\u003cp\u003e\n_Events: `sort`_\n\u003c/p\u003e\n\u003c/div\u003e\n\nSorting is quite flexible. It works a lot like `Array.prototype.sort`. By default, you can sort based upon strings that represent keys in the Models. You can also stack up secondary, trinary etc sort keys in case the first one is equal. For example:\n```javascript\nusers.sort('name');\n// descending order pseduo\nusers.sort('name:desc');\n// by type and then birthdate in reverse order (oldest first)\nusers.sort('type,birthdate:desc');\n```\nSorting also allows you to pass a function you define yourself as per the [Array.prototype.sort](https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/sort) interface. When done, it will fire a `sort` event.\n\n### reverse\n---\n\u003cdiv class=\"alert\"\u003e\n\u003cp\u003e\n_Expects arguments: none_\n\u003c/p\u003e\n\u003cp\u003e\n_Returns: `this`_\n\u003c/p\u003e\n\u003cp\u003e\n_Events: `sort`_\n\u003c/p\u003e\n\u003c/div\u003e\n\nReverses sort the order of Models in the collection. Fires a `sort` event, not `reverse`\n\n### find\n---\n\u003cdiv class=\"alert\"\u003e\n\u003cp\u003e\n_Expects arguments: (String) expression_\n\u003c/p\u003e\n\u003cp\u003e\n_Returns: `(Array) MatchingModelObjects`_\n\u003c/p\u003e\n\u003c/div\u003e\n\nThis is an experimental API and is subject to change without notice. `Collection.find` is currently powered by the MooTools `Slick.parse` engine. This means you can\n search through your Collection for Models by attributes and `#ids` like you would search in a CSS selector.\n\nFor example:\n```ace\nvar collection = new Epitome.Collection([{\n    name: 'Bob',\n    id: 2\n}, {\n    name: 'Angry Bob',\n    id: 3\n}]);\n\ncollection.find('[name]'); // where name is defined.\ncollection.find('[name=Bob]'); // where name is exactly Bob.\ncollection.find('[name*=Bob]'); // where name contains Bob.\ncollection.find('[name$=Bob]'); // where name ends on Bob.\ncollection.find('[name^=Bob]'); // where name starts with Bob.\ncollection.find('[name=Bob],[name^=Angry]'); // name Bob OR starting with Angry.\ncollection.find('[name=Bob][id]'); // name Bob AND to have an id\ncollection.find('#2[name=Bob],#3'); // (name Bob AND id==2) OR id==3\ncollection.find('[name=Bob][id=2]'); // name Bob AND id==2\n```\n\nSupported operators are `=` (equals), `!=` (not equal), `*=` (contains), `$=` (ends on), `^=` (starts with). Currently, you cannot reverse a condition by adding `!` or `not:` - in fact, pseudos are not supported yet. Find is just sugar and for more complicated stuff, you can either extend it or use `filter` instead.\n\nA new 'feature' has been added that allows you to quickly select deeper object properties by treating any parent keys as tags. For instance:\n\n```javascript\nvar collection = new Epitome.Collection([{\n    name: 'Bob',\n    permissions: {\n        edit: true\n    }\n}, {\n    name: 'Angry Bob',\n    permissions: {\n        edit: false\n    }\n}]);\n\n\ncollection.find('permissions[edit]'); // all where there is an edit property\ncollection.find('permissions[edit=true]'); // all where there edit is true\n\n```\n\nHowever, this is more of a syntactic sugar than convention. It won't allow you to do complex CSS-like selections as you cannot combine 'tag' with properties. This means you cannot do `permissions[edit][name=Bob]` as the context changes to the permissions property. This kind of structure is possibly an anti-pattern anyway, try to keep your models flat.\n\n\n### findOne\n---\n\u003cdiv class=\"alert\"\u003e\n\u003cp\u003e\n_Expects arguments: (String) expression_\n\u003c/p\u003e\n\u003cp\u003e\n_Returns: `(Model) First matching Model instance or null`_\n\u003c/p\u003e\n\u003c/div\u003e\n\nUseful for getting a single Model via the `.find`, this method will return the first matched Model or null if none found.\n\n\n```javascript\nvar bob = collection.findOne('[name=bob]');\n// if found, set\nbob \u0026\u0026 bob.set('name','Robert');\n```\n\n### Array helpers\n\nThe following Array methods are also available directly on the Collection instances:\n\n* forEach\n* each\n* invoke\n* filter\n* map\n* some\n* indexOf\n* contains\n* getRandom\n* getLast\n\nFor more information, see [Mootools Array Type](http://mootools.net/docs/core/Types/Array)\n\n### Collection properties*\n\n#### _models\n---\nEach Collection instance has an Array property called `_models` that contains all referenced Model instances. Even though it is not a real private property, it is recommended you do not alter it from outside of the API.\n\n#### length\n---\nTries to always reference the length of `_models`.\n\n#### model\n---\nEach Collection prototype has that property that references a Model prototype constructor. When data is being received in raw format (so, simple Objects), Models are being created by instantiating the stored constructor object in `this.model`.\n\n## Epitome.Collection.Sync\n\nThe Sync Class is just a layer on top of the normal [Epitome.Collection](#epitomecollection). It extends the default Collection prototype and adds a Request instance that can retrieve an Array of Model data from a server and add / update the Collection after.\n\n### constructor (initialize)\n---\n\u003cdiv class=\"alert\"\u003e\n\u003cp\u003e\n_Expects arguments: `(Array) models / objects` (or a single model /object), `(Object) options`_\n\u003c/p\u003e\n\u003cp\u003e\n_Returns: `this`_\n\u003c/p\u003e\n\u003cp\u003e\n_Events: `ready`_\n\u003c/p\u003e\n\u003c/div\u003e\n\nIn terms of differences with the original prototype, the `options`, needs just one extra key: `urlRoot`, which should contain the absolute or relative URL to the end-point that can return the Model data.\n\n### fetch\n---\n\u003cdiv class=\"alert\"\u003e\n\u003cp\u003e\n_Expects optional arguments: `(Boolean) refresh`, `(Object) queryParams`_\n\u003c/p\u003e\n\u003cp\u003e\n_Returns: `this`_\n\u003c/p\u003e\n\u003cp\u003e\n_Events: `fetch`_\n\u003c/p\u003e\n\u003c/div\u003e\n\nWhen called, it will asynchronously try to go and fetch Model data. When data arrives, Models are reconciled with the Models in the collection already by `id`. If they exist already, a `set()` is called that will merge new data into the Model instance and fire `change` events as appropriate. If the optional `refresh` argument is set to true, the current collection will be emptied first via [empty](#epitomecollection/empty).\n\nReturns the instance 'now' but because it is async, applying anything to the collection before the `fetch` event has fired may have unexpected results.\n\nThe `queryParams` object, which is also optional, allows you to pass on any `GET` arguments to the `baseUrl`. If your default endpoint looks like this:\n\n`/comments/2/` and you call `collection.fetch(false, {page: 2})`, it will actually get `/comments/2/?page=2`.\n\n### postProcessor\n---\n\u003cdiv class=\"alert\"\u003e\n\u003cp\u003e\n_Expects arguments: `(Mixed) response`_\n\u003c/p\u003e\n\u003cp\u003e\n_Expected return: `(Array) response`_\n\u003c/p\u003e\n\u003c/div\u003e\n\nA method that you can extend in your definition of Epitome.Collection.Sync for doing any pre-processing of data returned by sync from the server. For example:\n\n```javascript\npostProcessor: function(response) {\n    // data comes back with decoration. split them first.\n    // { meta: { something: 'here' }, models: [] }\n    this.meta = response.meta;\n    return response.models;\n}\n```\n\n## Epitome.View\n\nThe view is a pretty loose binding around a HTMLElement, it does not try to do much by default. It essentially binds the element to either a Model or a Collection, listening and propagating events that they fire in order to be able to react to them. The expectation is that a `render` method will be defined that uses the data to output it in the browser. The render can be called based upon change or reset events as needed.\n\n### constructor (initialize)\n---\n\u003cdiv class=\"alert\"\u003e\n\u003cp\u003e\n_Expects arguments: `(Object) options`_\n\u003c/p\u003e\n\u003cp\u003e\n_Returns: `this`_\n\u003c/p\u003e\n\u003cp\u003e\n_Events: `ready`_\n\u003c/p\u003e\n\u003c/div\u003e\n\nA single argument in the shape of an `options` Object is passed to the constructor of the View. It is expected to have special 'mutator'-like properties and key properties that it stores for future use.\n\nA simple example would look like this:\n```ace\n// define the View prototype\nvar testView = new Class({\n\n    Extends: Epitome.View,\n\n    render: function() {\n        // have a render.\n        this.empty();\n        this.element.set('html', this.template(this.model.toJSON()));\n        this.parent();\n        return this;\n    },\n\n    doEmpty: function() {\n        this.model.empty();\n        this.render();\n    }\n});\n\n\nvar testInstance = new testView({\n\n    model: new Epitome.Model({name: 'View fun'}),\n\n    element: 'main',\n\n    template: 'I am a template and I am called \u003ca href=\"#\" class=\"task-remove\"\u003e\u003c%=name%\u003e\u003c/a\u003e\u003cbr/\u003e\u003cbutton class=\"change-one\"\u003eempty it\u003c/button\u003e',\n\n    // event binding\n    events: {\n        'click:relay(a.task-remove)': 'emptyModel', // emit this event to instance\n        'click:relay(button.change-one)': 'changeModel'\n    },\n\n    onReady: function() {\n        this.render();\n    },\n\n    'onChange:model': function(){\n        this.model.set('name', new Date().getTime());\n        this.render();\n    },\n\n    onEmptyModel: function(event, element) {\n        event \u0026\u0026 event.stop \u0026\u0026 event.stop();\n        console.log(element); // a.task-remove\n        this.doEmpty();\n    }\n});\n```\n\nThe key `options` are:\n\n* `element` - a String id or an element to bind events to and reference\n* `model` - optional Model instance structure to bind to. Exchangeable with `collection`\n* `collection` - optional Collection instance to bind to. Exchangeable with `model`\n* `template` - a String of raw HTML that defines the raw template to use in output.\n* `events` - an Object with MooTools style event bindings to apply to the `element`, delegated or not. values are implied event handlers on the instance\n* `onEventHandlers` - code that reacts to various events that the instance fires.\n\n### render\n---\n\u003cdiv class=\"alert\"\u003e\n\u003cp\u003e\n_Expects arguments: unknown_\n\u003c/p\u003e\n\u003cp\u003e\n_Returns: `this`_\n\u003c/p\u003e\n\u003cp\u003e\n_Events: `render`_\n\u003c/p\u003e\n\u003c/div\u003e\n\nIt is essential that this method is defined in your View prototype Object definition. It does not assume to do anything by default, you need to define how the output takes place and how your data is being used. For convenience, it has access to either `this.model` or `this.collection` as the source of data that can be be passed to the [template](#epitomeview/template) method. It is expected that at the bottom of your definition, `this.parent()` is called in order for the `render` event to fire.\n\n### setElement\n---\n\u003cdiv class=\"alert\"\u003e\n\u003cp\u003e\n_Expects arguments: `(Mixed) element`, optional `(Object) events`_\n\u003c/p\u003e\n\u003cp\u003e\n_Returns: `this`_\n\u003c/p\u003e\n\u003c/div\u003e\n\nA public method that allows you to change or set an element that powers a view. If called the first time, it will get the Element (through `document.id()`) and save the reference in `this.element`. If an events object is passed, it will bind the events. If called a second time, it will unbind all events on the old element, change the element reference and rebind new events, if supplied.\n\n### template\n---\n\u003cdiv class=\"alert\"\u003e\n\u003cp\u003e\n_Expects arguments: `(Object) data`, optional `(String) template`_\n\u003c/p\u003e\n\u003cp\u003e\n_Returns: compiled template or function._\n\u003c/p\u003e\n\u003c/div\u003e\n\nA simple sandbox function where you can either use the Epitome.Template templating engine or call an external engine like Mustache, Handlebars, Hogan etc. The second argument is optional and if not supplied, it will revert to `this.options.template` instead.\n\nAn example override to make it work with Mustache would be:\n```javascript\nvar myView = new Class({\n    Extends: Epitome.View,\n    template: function(data, template) {\n        template = template || this.options.template;\n        return Mustache.render(template, data);\n    },\n    render: function() {\n        this.element.set('html', this.template({name:'there'}, 'Hello {{name}}'));\n    }\n});\n```\n\nYou can change the View prototype to always have Mustache in your views. For example, via AMD/RequireJS, you could do a\nsmall module that deals with the prototyping of the default View constructor. Say, `epitome-view-mustache.js`\n```javascript\n\ndefine(['epitome/epitome-view'], function(View){\n\t// prototype it for everyone to use mustache in every view.\n\n\tView.implement({\n\t\ttemplate: function(data, template) {\n\t\t\t// refactor this to work with any other template engine in your constructor\n\t\t\ttemplate = template || this.options.template;\n\n\t\t\treturn Mustache.render(template, data);\n\t\t}\n\t});\n\n});\n```\n\nIn your Require config (loose example):\n```\nrequire.config({\n\tpaths: {\n\t\tepitome: '/js/vendor/epitome'\n\t},\n\tdeps: [\n\t    // always load\n\t\t'epitome/epitome-view-mustache'\n\t]\n});\n\nrequire(['epitome/epitome-view'], function(View){\n    // View is now with the mustache template.\n});\n```\n\n### empty\n---\n\u003cdiv class=\"alert\"\u003e\n\u003cp\u003e\n_Expects arguments: `(Boolean) soft`_\n\u003c/p\u003e\n\u003cp\u003e\n_Returns: this._\n\u003c/p\u003e\n\u003cp\u003e\n_Events: `empty`_\n\u003c/p\u003e\n\u003c/div\u003e\n\nBy default, it will empty the element through making innerHTML an empty string, calling GC on all child nodes. If the `soft` argument is true, will apply `this.element.empty()`, which is a MooTools Element method that removes all child nodes without destroying them.\n\n### dispose\n---\n\u003cdiv class=\"alert\"\u003e\n\u003cp\u003e\n_Expects arguments: none_\n\u003c/p\u003e\n\u003cp\u003e\n_Returns: this._\n\u003c/p\u003e\n\u003cp\u003e\n_Events: `dispose`_\n\u003c/p\u003e\n\u003c/div\u003e\n\nWill detach `this.element` from the DOM. It can be injected again later on.\n\n### destroy\n---\n\u003cdiv class=\"alert\"\u003e\n\u003cp\u003e\n_Expects arguments: none_\n\u003c/p\u003e\n\u003cp\u003e\n_Returns: this._\n\u003c/p\u003e\n\u003cp\u003e\n_Events: `dispose`_\n\u003c/p\u003e\n\u003c/div\u003e\n\nRemoves and destroys `this.element` from the DOM and from memory. You need to use [setElement](#epitomeview/setelement) to add a new one if you want to re-render.\n\n## Epitome.Storage\n\nThe storage Class is meant to be used as a mix-in. It works with any instances of Epitome.Model (including Epitome.Model.Sync) as well as Epitome.Collection.\n\nTo add storage functionality to your model, you declare use in the prototype via the `Implements` mutator:\n```javascript\nvar user = new Class({\n    Extends: Epitome.Model,\n    Implements: Epitome.Storage.localStorage('model')\n});\n```\nThe code above will call the storage factory and enable `localStorage` within your model with a storage namespace key `model`. In the actual storage massive, data will appear under an `epitome-model` key.\n\nThe following methods are added to your Class (identical to Element.Storage from MooTools):\n\n### store\n---\n\u003cdiv class=\"alert\"\u003e\n\u003cp\u003e\n_Expects optional arguments: `(Object) model`_\n\u003c/p\u003e\n\u003cp\u003e\n_Returns: `this`_\n\u003c/p\u003e\n\u003cp\u003e\n_Events: `store: function(model) {}`_\n\u003c/p\u003e\n\u003c/div\u003e\n\nWhen called without any arguments, store will just save the current model or collection into storage. The models and collections are stored under a sub-key of the value returned `.get('id')`, so it is important to have an id in both if you want to achieve persistence.\n\n**If no id is provided, an id is generated for models and collections, which means a page reload will cause a different id to be generated and no data will be retrieved**\n\nYou can also pass a custom object as argument to write instead of the current model or collection.\n\n### retrieve\n---\n\u003cdiv class=\"alert\"\u003e\n\u003cp\u003e\n_Expects arguments: none_\n\u003c/p\u003e\n\u003cp\u003e\n_Returns: `(Object) model` or `(Array) collection`_\n\u003c/p\u003e\n\u003cp\u003e\n_Events: `retrieve: function(model) {}`_\n\u003c/p\u003e\n\u003c/div\u003e\n\nWhen you retrieve a model or a collection, it will simply return what the browser has as data (based upon the model or colleciton id as key). It will **NOT** apply a `model.set(data)` for you, you need to do this yourself.\n```javascript\nvar bob = new user({\n    id: 'bob'\n});\n\n// populate model from storage, if available.\nbob.set(bob.retrieve());\n```\n\nAutomatically populate:\n```javascript\nvar bob = new user({\n    id: 'bob'\n}, {\n    onRetrieve: function(data) {\n        this.set(data);\n    }\n}).retrieve();\n```\n\n### eliminate\n---\n\u003cdiv class=\"alert\"\u003e\n\u003cp\u003e\n_Expects arguments: none_\n\u003c/p\u003e\n\u003cp\u003e\n_Returns: `this`_\n\u003c/p\u003e\n\u003cp\u003e\n_Events: `eliminate`_\n\u003c/p\u003e\n\u003c/div\u003e\n\nCalling eliminate on a model or a collection will destroy the stored data the browser has for that model or collection.\n\n## Epitome.Template\n\nThe Template module is a dumbed down implementation of the `underscore.js` _.template(), which in turn was based on work by John Resig. The main differences are the following:\n\n* referencing object keys in the template that have no matching data causes no javascript exception\n* blocks can be used like so: `\u003c% if (foo) { %\u003eis foo\u003c% } else { %\u003eis not foo\u003c% } %\u003e`\n* conditional output can also work through `print` like this: \n\n```javascript\n\u003c%-address_1%\u003e \u003c% if(address_2){ print(', ', address_2) } %\u003e\n```\n\nYou can modify the syntax for the tags by altering the regex in the constructor:\n```javascript\noptions: {\n\t// evaluated logic syntax: \u003c% if (data.prop) { %\u003e\n\tevaluate: /\u003c%([\\s\\S]+?)%\u003e/g,\n\t// literal output: \u003c%=property%\u003e\n\tnormal: /\u003c%=([\\s\\S]+?)%\u003e/g,\n\t// DOM safe scripts and tags: \u003c%-property%\u003e\n\tescape: /\u003c%-([\\s\\S]+?)%\u003e/g\n}\n```\nFor more info, read the underscore.js documentation. We still recommend using Mustache or Handlebars instead.\n\n## Eptiome.Router\n\nThe Router Class is a hashbang controller, useful for single page applications. A direct import of [https://github.com/DimitarChristoff/Router](https://github.com/DimitarChristoff/Router).\n\n### constructor (initialize)\n---\n\u003cdiv class=\"alert\"\u003e\n\u003cp\u003e\n_Expects arguments: `(Object) options`_\n\u003c/p\u003e\n\u003cp\u003e\n_Returns: `this`_\n\u003c/p\u003e\n\u003cp\u003e\n_Events: `ready`, `before`, `after`, mixed, `undefined`, `error`, `route:add`, `route:remove`_\n\u003c/p\u003e\n\u003c/div\u003e\n\nAs this is quite involved and can act as a Controller for your app, here's a practical example that defines a few routes and event handlers within the Epitome.Router Class instantiation:\n```javascript\nApp.router = new Epitome.Router({\n    // routes definition will proxy the events\n    routes: {\n        ''\t\t\t\t\t\t: 'index',\n        '#!help'\t\t\t\t: 'help',\n        '#!test1/:query/:id?'\t: 'test1',\n        '#!test2/:query/*'\t\t: 'test2',\n        '#!error'               : 'dummyerror'\n    },\n\n    // router init\n    onReady: function(){\n        console.log('init');\n    },\n\n    // before route method, fires before the event handler once a match has been found\n    onBefore: function(routeId){\n        console.log('before', routeId)\n    },\n\n    // specific pseudos for :before\n    'onIndex:before': function() {\n        console.log('we are about to go to the index route');\n    },\n\n    // specific pseudos for after\n    'onIndex:after': function() {\n        console.log('navigated already to index route, update breadcrumb?');\n    },\n\n    // after route method has fired, post-route event.\n    onAfter: function(route){\n        console.info('after', route)\n    },\n\n    // routes events callbacks are functions that call parts of your app\n\n    // index\n    onIndex: function() {\n        console.log('index')\n    },\n\n    onHelp: function() {\n        console.log('help');\n        console.log(this.route, this.req, this.param, this.query)\n    },\n\n    onTest1: function(query, id) {\n        console.info('test1', query, id);\n        console.log(this.route, this.req, this.param, this.query)\n    },\n\n    onTest2: function(query) {\n        console.info('test2', query);\n        console.log(this.route, this.req, this.param, this.query)\n    },\n\n    // no route event was found, though route was defined\n    onError: function(error){\n        console.error(error);\n        // recover by going default route\n        this.navigate('');\n    },\n\n    onUndefined: function() {\n        console.log('this is an undefined route');\n    },\n\n    'onRoute:remove': function(route) {\n        alert(route + ' was removed by popular demand');\n    },\n\n    'onRoute:add': function(constructorObject) {\n        console.log(constructorObject.id + ' was added as a new route');\n    }\n});\n```\n### addRoute\n---\n\u003cdiv class=\"alert\"\u003e\n\u003cp\u003e\n_Expects arguments: `(Object) route`_\n\u003c/p\u003e\n\u003cp\u003e\n_Returns: `this`_\n\u003c/p\u003e\n\u003cp\u003e\n_Events: `route:add`_\n\u003cp\u003e\n\u003c/div\u003e\n\nExample adding of route to your instance after instantiation:\n\n```javascript\nApp.router.addRoute({\n    route: '#!dynamicRoute',\n    id: 'dynamic',\n    events: {\n        onDynamic: function() {\n            alert('you found the blowfish');\n            if (confirm('remove this route?'))\n                this.removeRoute('#!dynamicRoute');\n        }\n    }\n});\n```\n\n### removeRoute\n---\n\u003cdiv class=\"alert\"\u003e\n\u003cp\u003e\n_Expects arguments: `(String) route`_\n\u003c/p\u003e\n\u003cp\u003e\n_Returns: `this`_\n\u003c/p\u003e\n\u003cp\u003e\n_Events: `route:remove`_\n\u003c/p\u003e\n\u003c/div\u003e\n\nRemoves a route by the route identifier string.\n\nFor more examples of Router, have a look inside the [todomvc](https://github.com/DimitarChristoff/Epitome-todo/blob/master/epitome/js/app.js#L42-70) demo.\n\n\n\n## Examples\n\nEpitome is modular via AMD but all the files will also work in a browser in plain script tags. When using Require.JS, you can pull in only sub-modules that you need and Epitome will resolve any dependencies automatically:\n```\nrequire.config({\n    baseUrl: 'src'\n});\n\nrequire(['epitome-model-sync'], function(ModelSync) {\n    // pulls in isEqual and Model automatically.\n    var tweet = new Class({\n        Extends: ModelSync\n    });\n});\n```\nIf you'd like the whole project (all modules), you can require `main.js` (also exported via NPM):\n```\nrequire(['main'], function(Epitome) {\n    // Epitome is an object with all the submodules.\n    var tweet = new Class({\n        Extends: Epitome.Model.Sync,\n        Implements: Epitome.Storage.sessionStorage()\n    });\n});\n```\n\nan example skeleton of an Epitome-powered AMD app for RequireJS is available [here](https://github.com/DimitarChristoff/epitome-skeleton-amd)\n\nWhen using it in a browser or after the Epitome Object contains all your modules, quick model creation with prototyping and `localStorage` can look something like this:\n```javascript\n// create a new user class prototype, basing it on Epitome.Model.Sync and implement storage\nvar User = new Class({\n    Extends: Epitome.Model.Sync,\n    Implements: Epitome.Storage.sessionStorage(),\n    options: {\n        defaults: {\n            urlRoot: '/user'\n        }\n    }\n});\n\n// make a new model with id '1' and a property 'name'\nvar userModel = new User({\n    id: '1',\n    name: 'Bobby'\n}, {\n    // default model values to instance only.\n    defaults: {\n        surname: 'Robertson'\n    },\n    // add some events\n    onChange: function(key, value) {\n        console.log('you changed ' + key + ' to ' + value);\n    },\n    onSave: function() {\n        // also save to localStorage\n        this.store();\n    },\n    \"onChange:name\": function(value) {\n        console.log('you changed your name to ' + value);\n    }\n}); // attr: name: 'Bobby', id: 1, surname: 'Robertson', userModel.urlRoot = '/user/'\n\n// change some values.\nuserModel.set({\n    surname: 'Roberts',\n    name: 'Bob'\n});\n\n\n// get from storage if available, else - from server\nvar data = userModel.retrieve();\nif (data) {\n    userModel.set(data);\n}\nelse {\n    userModel.read();\n}\n\n// go wild!\nuserModel.save();\n```\n\n### Sync and Storage\n\nHere's an example pattern that allows you to use Storage and Sync on a model to reconcile data on the client and on the server. In a scenario where a model is being updated on the client with an implicit Save button that does the Sync but a `onChange` event that saves any changes in `localStorage` in the meanwhile, this is how you'd reconcile the differences:\n\n```javascript\nvar Model = new Class({\n   // extends always before implements\n\tExtends: Epitome.Model.Sync,\n\t// use storage\n\tImplements: Epitome.Storage.localStorage('model')\n});\n\n// typically, this will be bound in a view\nvar model = new Model({\n\tid: 3\n}, {\n\tonChange: function(){\n\t\tthis.store();\n\t},\n\tonFetch: function(){\n\t\tvar data = this.retrieve();\n\n\t\tif (!Epitome.isEqual(data, this.toJSON)){\n\t\t\tif (confirm('Local copy differs from server, use it?')) {\n\t\t\t\tthis.set(data);\n\t\t\t}\n\t\t}\n    }\n});\n\n// get latest\nmodel.fetch();\n\n```\n\nThis pattern can be applied from views as well. Essentially, you are saying: when a model is fetched (and you already know the id), compare server-side version to what storage knows of this model. If a difference is found, you can either prompt the user to accept the client version and load it or you can automatically merge the changes into the model. Since a change always saves into storage, the client-side version will always have an upto date version of data. This is useful when a model is bound to a view and a user modifies it and then reloads the page or navigates away before saving.\n\n### Prototyping Views\n\nIt is sometimes useful to prototype the view, including the events that will be bound - as opposed to doing it in the instantiation.\n\n```javascript\nvar myView = new Class({\n\tExtends: Epitome.View,\n\toptions: {\n\t\tevents: {\n\t\t\t// these relate to this.element. if an element is not passed, they won't matter\n\t\t\t'click:relay(button.save)': 'saveData'\n\t\t},\n\t\tonSaveData: function(){\n\t\t\tvar data = {};\n\t\t\tthis.element.getElements('input').each(function(el){\n\t\t\t\tdata[el.get('name')] = el.get('value').stripScripts().clean()\n\t\t\t});\n\t\t\t// notice there is no onChange:model saving via sync, we save on demand\n\t\t\tthis.model.set(data);\n\t\t\tthis.model.save();\n\t\t},\n\t\t'onChange:model': function(){\n\t\t\tthis.model.store(); // changes in-between go to storage\n\t\t}\n\t}\n});\n\n```\n\n\nFor more examples, have a look inside of `example/js/`\n\n### TodoMVC reference\n---\nA standard [TodoMVC](http://todomvc.com/) reference implementation has been provided here in both AMD and normal namespaced modules: [Epitome-todo](https://github.com/DimitarChristoff/Epitome-todo).\n\nYou can view it in action here:\n[http://fragged.org/Epitome/example/todo/epitome/#!/](http://fragged.org/Epitome/example/todo/epitome/#!/)\n\nThe todo app is also a submodule of Epitome so you can add it by doing this at the root of the repo:\n```sh\ngit submodule init\ngit submodule update\n```\n\nAnd you can keep it updated by going to `~/example/todo/` and doing a pull\n\nA RequireJS version of the todo app is available here as a branch of the main todo app:\n[Epitome-todo AMD](http://fragged.org/Epitome/example/todo/epitome-amd/#!/)\n\n## Download + Building\n\nYou can check it out of the [github repo](https://github.com/DimitarChristoff/Epitome/) or you can [grab the zip](https://github.com/DimitarChristoff/Epitome/zipball/master) or simply download the minified [Epitome-min.js](https://raw.github.com/DimitarChristoff/Epitome/master/Epitome-min.js).\n\nAll files are wrapped into `define` blocks, which means you can simply use `require.js` to ask for a component and all of its dependencies will be resolved automatically for you.\n\nYou can create your own minified concatenated version of Epitome with the components you want. Have a look inside of the simple `app.build.js` you can use for `r.js` (require.js optimiser).\n\nTypically, you'd create a new production build by running:\n\n```sh\n\u003e r.js -o app.build.js\n\nTracing dependencies for: epitome\nUglifying file: /projects/Epitome/Epitome-min.js\n\n/projects/Epitome/Epitome-min.js\n----------------\n/projects/Epitome/src/epitome-events.js\n/projects/Epitome/src/epitome.js\n/projects/Epitome/src/epitome-isequal.js\n/projects/Epitome/src/epitome-model.js\n/projects/Epitome/src/epitome-model-sync.js\n/projects/Epitome/src/epitome-storage.js\n/projects/Epitome/src/epitome-collection.js\n/projects/Epitome/src/epitome-collection-sync.js\n/projects/Epitome/src/epitome-template.js\n/projects/Epitome/src/epitome-view.js\n/projects/Epitome/src/epitome-router.js\n```\nInstall requirejs via npm, if you haven't:\n\n```sh\nnpm install -g requirejs\n```\n\nAlternatively, grab r.js and put it inside the project, then do `node r.js -o app.build.js`\n\n### AMD Builder\n---\n\u003cdiv id='customDownload'\u003eYou can use \u003ca href='http://fragged.org:39170/' rel='nofollow'\u003ehttp://fragged.org:39170/?build=module1,module2\u003c/a\u003e to create a custom build automatically. See the documentation page for more\u003c/div\u003e\n\n### CommonJS\n---\nYou can now use Epitome under nodejs. The following modules are exported: `Model`, `Collection`, `Events`, `Template`, `isEqual`. You can either reference the files directly by requirting them (you also need to require `mootools` first) or you can require `epitome` directly.\n\n```sh\n$ npm install epitome\n...\nnpm http GET https://registry.npmjs.org/mootools\nnpm http 304 https://registry.npmjs.org/mootools\nepitome@0.4.0 node_modules/epitome\n└── mootools@1.4.5-2\n```\n\nand then in your nodejs app:\n```javascript\n// MooTools gloabls get loaded.\nvar epitome = require('epitome');\n\nvar model = new Class({\n\tExtends: epitome.Model\n});\n\nvar bob = new model({\n\tname: 'Bob'\n});\n\nconsole.log(bob.toJSON());\n```\n\n## Testing\n\nTests are currently separated in 2 groups: node tests and browser tests. The distinction is that under node only,\nit uses `mootools-server` and lacks `Request` or `Element`, so only unit tests will run.\n\nTesting is run via [Buster.js](http://busterjs.org) can be found in `/tests/` - check the README.md there for more info.\n\n\u003cdiv class=\"alert alert-error\"\u003e\n\u003cp\u003e\n_Please note that as of buster 0.6.0, having browser and node test groups at the same time fails to terminate the buster-test process. node tests are temporary disabled_\n\u003c/p\u003e\n\u003c/div\u003e\n\n## Development and contribution\n\nFeel free to fork, play and contribute back to the project if you can, pull requests are more than welcome. Just make sure you\ncreate the request in a branch and write tests / fix existing tests before you send it. Oh, and make sure it does not break the build!\n\nThe creation and logic employed in the writing of Epitome has been documented in several blog posts on the QMetric tech blog:\n\n* [Creating the Model](http://tech.qmetric.co.uk/creating-your-own-mvc-like-data-model-class-in-mootools_59.html)\n* [Creating the Model.Sync](http://tech.qmetric.co.uk/building-a-mootools-micro-mvc-part-2-adding-sync-to-your-model_132.html)\n* [Adding the template](http://tech.qmetric.co.uk/epitome-template-a-lightweight-templating-engine-for-mootools-that-works_190.html)\n* [Testing it in CI via Travis CI](http://tech.qmetric.co.uk/automating-javascript-ci-with-buster-js-and-travisci_205.html)\n\n## Credits and licensing\n\nConcept and development by [Dimitar Christoff](http://twitter.com/D_mitar) with help from [Garrick Cheung](http://twitter.com/garrickcheung), [Chase Wilson](http://twitter.com/jiggliemon) \u0026 [Simon Smith](http://twitter.com/blinkdesign)\n\nDeveloped for use by QMetric Group Limited, kindly released with their permission.\n\nReleased under the MIT license [http://mootools.net/license.txt](http://mootools.net/license.txt)\n\nDocumentation generated via [DocumentUp](http://documentup.com), with a local theme in the style of js garden and our [mootstrap scrollspy plugin](https://github.com/DimitarChristoff/mootstrap-scrollspy)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fepitome-mvc%2Fepitome","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fepitome-mvc%2Fepitome","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fepitome-mvc%2Fepitome/lists"}