MooVeeStar is a client-side MV* Framework built ontop of MooTools. It has been built to feel familiar while harnessing the power and practices of the MooTools library.
Introduction
The advancement of JavaScript the past decade has been nothing short of breathtaking. No longer is it a simple tool to popup an image slideshow or validate a contact form. It is a powerful tool that can be used to drive massive single-page websites. And if you've ever created a large-scale application you know all to well how you can quickly loose control of your client-side codebase in a jumbled mess of JavaScript.
There are plenty of great JavaScript libraries out there, and no shortage of frameworks to help you structure your code better. Unfortunately, most were built for specific libraries that don't lend themselves well to structured code in the first place, or were built to be completey fairly library agnostic. These simply add unnecessary bloat recreating what MooTools already has while simultaneously leaving out powerful features of it. So you've been writing structured code with MooTools already, now MooVeeStar is here to further optimize your development and put your app in the spotlight.
Documentation
- MooVeeStar
-
MooVeeStar is the object/namespace that holds the MooVeeStar modules. However, the MooVeeStar object itself is an instantiated MooTools Events object, and can therefore be used as a global mediator between components:
MooVeeStar.addEvent('someEvent', function(eventObject){ alert(eventObject.say); }); MooVeeStar.fireEvent('someEvent', { say:'hi'});
- MooVeeStar.Model
-
The MooVeeStar.Model is a MooTools class that implements the Events class already.
- idProperty
model.idProperty
- A configurable key that will be used to uniquely identify the model. It will default to id.
- properties
model.properties
-
A configurable object with a properties hash where you can: Set an initial value; Override the default
get
and/orset
methods; Definevalidate
and/orsanitize
methods for each property.var Employee = new Class({ Extends: MooVeeStar.Model, idProperty: 'ssn', properties: { employed: { initial: true }, fullname: { set: function(value){ var names = (value || '').split(' '); this.set('firstname', names[0] || null); this.set('lastname', names[1] || null); }, get: function(){ return this.get('firstname')+' '+this.get('lastname'); } }, ssn: { validate: function(value){ return /^\d{3}-\d{2}-\d{4}$/.test(value) || 'The SSN was not formatted correctly'; } } } }); var employee = new Employee({'ssn':'123-45-6789', 'firstname':'John','lastname':'Smith'}); employee.addEvent('change:ssn', function(event){ alert(employee.get('fullname') + "'s SSN has changed."); }); employee.addEvent('error:ssn', function(event){ alert(event.error); }); // If the ssn doesn't validate, then error:ssn above will fire // If the value has changed, then change:ssn above will fire var ssn = prompt("Enter " + employee.get('fullname') + "'s SSN (XXX-XX-XXXX)", employee.get('ssn')); if(ssn != null) // Not Cancel employee.set('ssn', ssn);
- initialize/constructor
new MooVeeStar.Model([object])
- set
model.set((key, value)|(object), [silent])
-
Overloaded set method to set a property or properties on the model. Can be called with a single key/value, or an object with many keys/values. Options can have a silent key that, when true, supresses events.
model.set('name', 'Edward', { silent:true }); // or... model.set({ name:'Edward' }, { silent:true });
- get
model.get(keyOrArray, [raw])
-
Overloaded get method to get a single value or a map if an array is passed. Passing
raw
as true will get the raw value directly as it’s stored, without checking if there’s a custom getter within the Model’s properties - getId
model.getId()
- Returns an id for the model. If the idProperty exists, it will return it, otherwise it will return a unique string. If there is no cid set yet, it will permenently assign it at this time. MooVeeStar.Collection uses this to identify models within itself.
- unset
model.unset(keys, [silent])
-
Accepts a list of keys and passes them to
Model#set
with a null value. - destroy
model.destroy()
- Destroys a model by setting it’s property to an empty map and firing a destroy event
- toJSON
model.toJSON()
- Returns a recursively cloned value map of the model’s raw properties.
-
cid
model.cid
- An internal unique identifier. Lazily set in getId(), it will be assigned a unique string if the model has no idProperty value
-
changed
model.changed
- An array of all the changed properties of the last set call
-
errors
model.errors
- An array of all the properties that had an error of the last set call
- idProperty
- MooVeeStar.Collection
-
-
errors
collection.modelClass
-
The class of models will auto-instantiate to when added if not an instance of
MooVeeStar.Model
already -
constructor/initialize
new MooVeeStar.Collection([models], [options])
-
add
collection.add(items, [options])
- Adds an item to the collection. Will not allow duplicates unless the collection's
allowDuplicates
istrue
. Will instantiate the collection'smodelClass
if the item added is not aMooVeeStar.Model
. It is possible to add mixed Model instances. FiresCollection#change
andCollection#add
andCollection#error
events. -
remove
collection.remove(indexOrModels, [options])
- Removes a model by index or all instance of a model or array of models from the collection. If
indexOrModels
is a number, then remove at that index; if it is a string id, then get the model and remove all instances of it; if it is a model or array of models, then remove all instances of each. FiresCollection#change
andCollection#remove
events. -
empty
collection.empty([options])
- Empties the Collection by callng
remove
on all items -
move
collection.move(indexOrModel, to, [options])
- Moves a model from one index to another. If
indexOrModel
is a number, then move the model at that index. If it is a model then only whose first instance of the model in the collection will be moved. -
getId
collection.getId()
-
getLength
collection.getLength()
- Returns the number of items in the collection
-
at
collection.at(index)
- Returns the model at a specific index, if it exists.
-
get
collection.get([key])
- Returns the first model found from the key. If
key
isnull
, return all items; or callCollection:findFirst
withkey
; or ifkey
is numeric call Collection:at -
getAll
collection.getAll()
- Returns the list of models
-
find
collection.find(values, [keyToFind])
- Accept a value or list of values and returns any models who’s idProperty is within the values list. Pass
keyToFind
to compare that key’s value instread ofidProperty
-
findFirst
collection.findFirst(value, [keyToFind])
- Returns the first model whos
idProperty
(orkeyToFind
value) matches the passed value -
toJSON
collection.toJSON()
- Returns a _new array_ of all of the
Models.toJSON
values -
destroy
collection.destroy([options])
- Silently empties the list and fires a destroy message
-
applyToModels
collection.applyToModels(operation, opArgs, modelsOrFindValues, findKeyToFind)
- Calls a method on all models, or all models found
// Set all models to complete collection.applyToModels('set', ['complete', true]); // Set all models whos 'complete' key is === false collection.applyToModels('set', [{ complete:true }], false, 'complete'); // Unset 'complete' and 'due' on models whos 'complete' key is === false collection.applyToModels('unset', [['complete','due']], collection.find(false, 'complete'));
Array Methods
forEach
each
every
invoke
filter
map
some
indexOf
contains
getRandom
getLast
-
errors
- MooVeeStar.View
-
MooVeeStar views help you take control of how your interface interacts with user input and data changes. It was built to take full power of the MooVeeStar.Templating system, but can be used with any templating library.
Extending
You will be creating your own, extended views by overriding some of the properties and methods. If you're using the MooVeeStar templating system then all you really need is to define a template name. Here's a simple view that renders a template, with a couple events:
var EmployeeIdView = new Class({ Extends: MooVeeStar.View, events: { 'model:change':'render', 'click:relay(button.delete)':'destroy' }, template:'employee-id-card' }); $(document.body).grab(new EmployeeIdView(existingEmployeeModel));
-
constructor/initialize
new MooVeeStar.View([model], [options])
-
The MooVeeStar.View constructor sets a few things for us upfront. As you will likely be overriding the constructor when defining your own view, the placement of your parent call could be important.
- Sets and merges the passed
options
object to the default options - Sets the
model
property to the passed model, if it is not previously defined - Inflates the template from the Views template and sets it to the
element
property as well aselements.container
- Attaches the events, unless
options.autoattach
is false - Calls render, unless
options.autorender
is false
- Sets and merges the passed
-
options
view.options
-
MooVeeStar.View implements the MooTools Options methods by default, and comes with a few options to run itself upfront, usually overriden when defining your own, extended view.
{ autorender: true, // Automatically call the render function on initialization autoattach: true // Automatically attach events on initialization inflater: MooVeeStar.Templates.inflate, // The template inflate method. Called as: "inflater(this.template, null)" // by default when intializing the element binder: MooVeeStar.Templates.bind // The template binder method. Called as: "binder(this.element, model.toJSON())" // by default in "this.render" }
autorender -
events
model.events
-
Events are what automate your view's interface with user input, data changes, interface changes... really anything. If it can fire an event your view can listen to it. You can bind events to any property that is defined in your constructor before calling
this.parent()
. The event object is a set of string event-keys, with string function names.How's it work?
The events are somewhat magical. There is a lot you can throw at it, and it will only fail when it can't find what you're trying to attach to, or the string method name doesn't exist on your view. The event string syntax can be generalized as
'attachmentObject:eventToListen'
. TheattachmentObject
should be: an existing property of the view,this
,window
,document
,MooVeeStar
, an existing element html-id, or an object onwindow
. If you do not supply anattachmentObject
, then it will attempt to use thethis.element
only if theeventToListen
is anElement.NativeEvents
, otherwise it will listen to the view's own events. Here's some examples:var MyView = new Class({ Extends: MooVeeStar.View, events: { 'model:change': 'render', // Listen for 'change' events on 'this.model' 'this.model:change': 'render', // (Same as above) 'model:change:name': 'render', // Listen for the specific 'change:name' events on 'this.model' 'click': 'onClick', // Listen for 'click' events on 'this.element' 'element:click': 'onClick', // (Same as above) 'this.element:click': 'onClick', // (Same as above) 'this:click': 'onFiredClick', // Not a mouse-click! Force listening to an internal view event // named "click" fired through 'this.fireEvent("click")' 'click:relay(button)': 'onButtonClick', // Listen for 'click' events on button children of 'this.element' 'elements.button:click': 'onButtonClick', // Assuming 'this.elements.button' was set before attaching events // this will listen for clicks on this element 'someProperty:some-event': 'someFn', // Assuming 'this.someProperty' exists and has an 'addEvent' method 'this.someProperty:some-event': 'someFn', // (Same as above) 'window:scroll': 'onWindowScroll', // Window Scroll event 'document:click': 'onWindowScroll', // Click events on the 'document' 'MooVeeStar:some-event': 'someFn', // Listen for 'some-event' fired through the MooVeeStar mediator 'someGlobalObject:some-event': 'someFn', // Assuming 'window.someGlobalObject' exists and has an 'addEvent' method 'someHtmlId:keydown':'onSomeKeydown' // Assuming an element with 'id="someHtmlId"', listen for it's keydowns }, initialize: function(model, options){ // Need to define these per the above before calling this.parent this.elements.button = $('aButtonsId'); this.someProperty = new ClassWithEvents(); this.parent(model, options); // Auto attaching events }, /* the defined event callback methods from above */ });
A view error will be thrown if: You attempt to attach events to something that does not exist or does not have a
addEvent
method; or the listeners callback method name does not exist on your view. -
template
view.template
-
The string key of the template to use. Can also be an element. The template will get inflated and set as
this.element
-
model
view.model
-
The view model. A view can have as many models as you would like and all can be used in any facility. A
view.model
will be setup by default in the view constructor. -
element
view.element
-
The element inflated from
view.template
-
elements
view.elements
-
A map for elements to be cached to for use in either the events map, or in other view methods. The
view.element
is added automatically asview.elements.container
as well. -
render
view.render([data])
- Likely overridden and called through parent(), this determines the data to bind to the element. Pass a MooVeeStar.Event instance which contains a changed key, it will only rebind those changed values. Otherwise, it will use the passed argument or, more likely, call model.toJSON
-
toElement
view.toElement()
- Returns the
this.element
. Automatically called by MooTools when the view is used as an element, like:$(myView)
ordocument.body.grab(myView)
-
destroy
view.destroy([element])
-
Destroy the element, detaching all events and any child elements with view controller's events.
You should ensure to destroy your views by calling
view.destroy()
and avoid removing the element directly, either throughthis.element.destroy()
, orsomeParentElement.empty()
, etc. Doing so will not detach all event listeners. -
empty
view.empty([element])
- Empties the passed element, or the view’s element. Calls view.destroy() for all attached views within the element’s DOM. Fires the View#empty event
-
dispose
view.dispose([element])
- Disposes of an element, or the view’s element. This does not affect and attached sub views (like destroy and empty). Fires the View#dispose event
-
attach
view.attach([element], [excludeSelf])
- Attaches all the events in the
this.events
map, as well as attaching all child elements with a view controller -
detach
view.detach([element], [excludeSelf])
- Detaches all the events in the
this.events
map, as well as attaching all child elements with a view controller
-
constructor/initialize