Commit 4453ce21 authored by Stephen Sawchuk's avatar Stephen Sawchuk

puremvc updated with bower.

parent 52fa9a06
{
"name": "todomvc-puremvc",
"version": "0.0.0",
"dependencies": {
"puremvc": "latest",
"director": "~1.2.0",
"todomvc-common": "~0.1.2"
}
}
//
// Generated on Sun Dec 16 2012 22:47:05 GMT-0500 (EST) by Nodejitsu, Inc (Using Codesurgeon).
// Version 1.1.9
//
(function (exports) {
/*
* browser.js: Browser specific functionality for director.
*
* (C) 2011, Nodejitsu Inc.
* MIT LICENSE
*
*/
if (!Array.prototype.filter) {
Array.prototype.filter = function(filter, that) {
var other = [], v;
for (var i = 0, n = this.length; i < n; i++) {
if (i in this && filter.call(that, v = this[i], i, this)) {
other.push(v);
}
}
return other;
};
}
if (!Array.isArray){
Array.isArray = function(obj) {
return Object.prototype.toString.call(obj) === '[object Array]';
};
}
var dloc = document.location;
function dlocHashEmpty() {
// Non-IE browsers return '' when the address bar shows '#'; Director's logic
// assumes both mean empty.
return dloc.hash === '' || dloc.hash === '#';
}
var listener = {
mode: 'modern',
hash: dloc.hash,
history: false,
check: function () {
var h = dloc.hash;
if (h != this.hash) {
this.hash = h;
this.onHashChanged();
}
},
fire: function () {
if (this.mode === 'modern') {
this.history === true ? window.onpopstate() : window.onhashchange();
}
else {
this.onHashChanged();
}
},
init: function (fn, history) {
var self = this;
this.history = history;
if (!Router.listeners) {
Router.listeners = [];
}
function onchange(onChangeEvent) {
for (var i = 0, l = Router.listeners.length; i < l; i++) {
Router.listeners[i](onChangeEvent);
}
}
//note IE8 is being counted as 'modern' because it has the hashchange event
if ('onhashchange' in window && (document.documentMode === undefined
|| document.documentMode > 7)) {
// At least for now HTML5 history is available for 'modern' browsers only
if (this.history === true) {
// There is an old bug in Chrome that causes onpopstate to fire even
// upon initial page load. Since the handler is run manually in init(),
// this would cause Chrome to run it twise. Currently the only
// workaround seems to be to set the handler after the initial page load
// http://code.google.com/p/chromium/issues/detail?id=63040
setTimeout(function() {
window.onpopstate = onchange;
}, 500);
}
else {
window.onhashchange = onchange;
}
this.mode = 'modern';
}
else {
//
// IE support, based on a concept by Erik Arvidson ...
//
var frame = document.createElement('iframe');
frame.id = 'state-frame';
frame.style.display = 'none';
document.body.appendChild(frame);
this.writeFrame('');
if ('onpropertychange' in document && 'attachEvent' in document) {
document.attachEvent('onpropertychange', function () {
if (event.propertyName === 'location') {
self.check();
}
});
}
window.setInterval(function () { self.check(); }, 50);
this.onHashChanged = onchange;
this.mode = 'legacy';
}
Router.listeners.push(fn);
return this.mode;
},
destroy: function (fn) {
if (!Router || !Router.listeners) {
return;
}
var listeners = Router.listeners;
for (var i = listeners.length - 1; i >= 0; i--) {
if (listeners[i] === fn) {
listeners.splice(i, 1);
}
}
},
setHash: function (s) {
// Mozilla always adds an entry to the history
if (this.mode === 'legacy') {
this.writeFrame(s);
}
if (this.history === true) {
window.history.pushState({}, document.title, s);
// Fire an onpopstate event manually since pushing does not obviously
// trigger the pop event.
this.fire();
} else {
dloc.hash = (s[0] === '/') ? s : '/' + s;
}
return this;
},
writeFrame: function (s) {
// IE support...
var f = document.getElementById('state-frame');
var d = f.contentDocument || f.contentWindow.document;
d.open();
d.write("<script>_hash = '" + s + "'; onload = parent.listener.syncHash;<script>");
d.close();
},
syncHash: function () {
// IE support...
var s = this._hash;
if (s != dloc.hash) {
dloc.hash = s;
}
return this;
},
onHashChanged: function () {}
};
var Router = exports.Router = function (routes) {
if (!(this instanceof Router)) return new Router(routes);
this.params = {};
this.routes = {};
this.methods = ['on', 'once', 'after', 'before'];
this.scope = [];
this._methods = {};
this._insert = this.insert;
this.insert = this.insertEx;
this.historySupport = (window.history != null ? window.history.pushState : null) != null
this.configure();
this.mount(routes || {});
};
Router.prototype.init = function (r) {
var self = this;
this.handler = function(onChangeEvent) {
var newURL = onChangeEvent && onChangeEvent.newURL || window.location.hash;
var url = self.history === true ? self.getPath() : newURL.replace(/.*#/, '');
self.dispatch('on', url);
};
listener.init(this.handler, this.history);
if (this.history === false) {
if (dlocHashEmpty() && r) {
dloc.hash = r;
} else if (!dlocHashEmpty()) {
self.dispatch('on', dloc.hash.replace(/^#/, ''));
}
}
else {
var routeTo = dlocHashEmpty() && r ? r : !dlocHashEmpty() ? dloc.hash.replace(/^#/, '') : null;
if (routeTo) {
window.history.replaceState({}, document.title, routeTo);
}
// Router has been initialized, but due to the chrome bug it will not
// yet actually route HTML5 history state changes. Thus, decide if should route.
if (routeTo || this.run_in_init === true) {
this.handler();
}
}
return this;
};
Router.prototype.explode = function () {
var v = this.history === true ? this.getPath() : dloc.hash;
if (v.charAt(1) === '/') { v=v.slice(1) }
return v.slice(1, v.length).split("/");
};
Router.prototype.setRoute = function (i, v, val) {
var url = this.explode();
if (typeof i === 'number' && typeof v === 'string') {
url[i] = v;
}
else if (typeof val === 'string') {
url.splice(i, v, s);
}
else {
url = [i];
}
listener.setHash(url.join('/'));
return url;
};
//
// ### function insertEx(method, path, route, parent)
// #### @method {string} Method to insert the specific `route`.
// #### @path {Array} Parsed path to insert the `route` at.
// #### @route {Array|function} Route handlers to insert.
// #### @parent {Object} **Optional** Parent "routes" to insert into.
// insert a callback that will only occur once per the matched route.
//
Router.prototype.insertEx = function(method, path, route, parent) {
if (method === "once") {
method = "on";
route = function(route) {
var once = false;
return function() {
if (once) return;
once = true;
return route.apply(this, arguments);
};
}(route);
}
return this._insert(method, path, route, parent);
};
Router.prototype.getRoute = function (v) {
var ret = v;
if (typeof v === "number") {
ret = this.explode()[v];
}
else if (typeof v === "string"){
var h = this.explode();
ret = h.indexOf(v);
}
else {
ret = this.explode();
}
return ret;
};
Router.prototype.destroy = function () {
listener.destroy(this.handler);
return this;
};
Router.prototype.getPath = function () {
var path = window.location.pathname;
if (path.substr(0, 1) !== '/') {
path = '/' + path;
}
return path;
};
function _every(arr, iterator) {
for (var i = 0; i < arr.length; i += 1) {
if (iterator(arr[i], i, arr) === false) {
return;
}
}
}
function _flatten(arr) {
var flat = [];
for (var i = 0, n = arr.length; i < n; i++) {
flat = flat.concat(arr[i]);
}
return flat;
}
function _asyncEverySeries(arr, iterator, callback) {
if (!arr.length) {
return callback();
}
var completed = 0;
(function iterate() {
iterator(arr[completed], function(err) {
if (err || err === false) {
callback(err);
callback = function() {};
} else {
completed += 1;
if (completed === arr.length) {
callback();
} else {
iterate();
}
}
});
})();
}
function paramifyString(str, params, mod) {
mod = str;
for (var param in params) {
if (params.hasOwnProperty(param)) {
mod = params[param](str);
if (mod !== str) {
break;
}
}
}
return mod === str ? "([._a-zA-Z0-9-]+)" : mod;
}
function regifyString(str, params) {
var matches, last = 0, out = "";
while (matches = str.substr(last).match(/[^\w\d\- %@&]*\*[^\w\d\- %@&]*/)) {
last = matches.index + matches[0].length;
matches[0] = matches[0].replace(/^\*/, "([_.()!\\ %@&a-zA-Z0-9-]+)");
out += str.substr(0, matches.index) + matches[0];
}
str = out += str.substr(last);
var captures = str.match(/:([^\/]+)/ig), length;
if (captures) {
length = captures.length;
for (var i = 0; i < length; i++) {
str = str.replace(captures[i], paramifyString(captures[i], params));
}
}
return str;
}
function terminator(routes, delimiter, start, stop) {
var last = 0, left = 0, right = 0, start = (start || "(").toString(), stop = (stop || ")").toString(), i;
for (i = 0; i < routes.length; i++) {
var chunk = routes[i];
if (chunk.indexOf(start, last) > chunk.indexOf(stop, last) || ~chunk.indexOf(start, last) && !~chunk.indexOf(stop, last) || !~chunk.indexOf(start, last) && ~chunk.indexOf(stop, last)) {
left = chunk.indexOf(start, last);
right = chunk.indexOf(stop, last);
if (~left && !~right || !~left && ~right) {
var tmp = routes.slice(0, (i || 1) + 1).join(delimiter);
routes = [ tmp ].concat(routes.slice((i || 1) + 1));
}
last = (right > left ? right : left) + 1;
i = 0;
} else {
last = 0;
}
}
return routes;
}
Router.prototype.configure = function(options) {
options = options || {};
for (var i = 0; i < this.methods.length; i++) {
this._methods[this.methods[i]] = true;
}
this.recurse = options.recurse || this.recurse || false;
this.async = options.async || false;
this.delimiter = options.delimiter || "/";
this.strict = typeof options.strict === "undefined" ? true : options.strict;
this.notfound = options.notfound;
this.resource = options.resource;
this.history = options.html5history && this.historySupport || false;
this.run_in_init = this.history === true && options.run_handler_in_init !== false;
this.every = {
after: options.after || null,
before: options.before || null,
on: options.on || null
};
return this;
};
Router.prototype.param = function(token, matcher) {
if (token[0] !== ":") {
token = ":" + token;
}
var compiled = new RegExp(token, "g");
this.params[token] = function(str) {
return str.replace(compiled, matcher.source || matcher);
};
};
Router.prototype.on = Router.prototype.route = function(method, path, route) {
var self = this;
if (!route && typeof path == "function") {
route = path;
path = method;
method = "on";
}
if (Array.isArray(path)) {
return path.forEach(function(p) {
self.on(method, p, route);
});
}
if (path.source) {
path = path.source.replace(/\\\//ig, "/");
}
if (Array.isArray(method)) {
return method.forEach(function(m) {
self.on(m.toLowerCase(), path, route);
});
}
path = path.split(new RegExp(this.delimiter));
path = terminator(path, this.delimiter);
this.insert(method, this.scope.concat(path), route);
};
Router.prototype.dispatch = function(method, path, callback) {
var self = this, fns = this.traverse(method, path, this.routes, ""), invoked = this._invoked, after;
this._invoked = true;
if (!fns || fns.length === 0) {
this.last = [];
if (typeof this.notfound === "function") {
this.invoke([ this.notfound ], {
method: method,
path: path
}, callback);
}
return false;
}
if (this.recurse === "forward") {
fns = fns.reverse();
}
function updateAndInvoke() {
self.last = fns.after;
self.invoke(self.runlist(fns), self, callback);
}
after = this.every && this.every.after ? [ this.every.after ].concat(this.last) : [ this.last ];
if (after && after.length > 0 && invoked) {
if (this.async) {
this.invoke(after, this, updateAndInvoke);
} else {
this.invoke(after, this);
updateAndInvoke();
}
return true;
}
updateAndInvoke();
return true;
};
Router.prototype.invoke = function(fns, thisArg, callback) {
var self = this;
if (this.async) {
_asyncEverySeries(fns, function apply(fn, next) {
if (Array.isArray(fn)) {
return _asyncEverySeries(fn, apply, next);
} else if (typeof fn == "function") {
fn.apply(thisArg, fns.captures.concat(next));
}
}, function() {
if (callback) {
callback.apply(thisArg, arguments);
}
});
} else {
_every(fns, function apply(fn) {
if (Array.isArray(fn)) {
return _every(fn, apply);
} else if (typeof fn === "function") {
return fn.apply(thisArg, fns.captures || []);
} else if (typeof fn === "string" && self.resource) {
self.resource[fn].apply(thisArg, fns.captures || []);
}
});
}
};
Router.prototype.traverse = function(method, path, routes, regexp, filter) {
var fns = [], current, exact, match, next, that;
function filterRoutes(routes) {
if (!filter) {
return routes;
}
function deepCopy(source) {
var result = [];
for (var i = 0; i < source.length; i++) {
result[i] = Array.isArray(source[i]) ? deepCopy(source[i]) : source[i];
}
return result;
}
function applyFilter(fns) {
for (var i = fns.length - 1; i >= 0; i--) {
if (Array.isArray(fns[i])) {
applyFilter(fns[i]);
if (fns[i].length === 0) {
fns.splice(i, 1);
}
} else {
if (!filter(fns[i])) {
fns.splice(i, 1);
}
}
}
}
var newRoutes = deepCopy(routes);
newRoutes.matched = routes.matched;
newRoutes.captures = routes.captures;
newRoutes.after = routes.after.filter(filter);
applyFilter(newRoutes);
return newRoutes;
}
if (path === this.delimiter && routes[method]) {
next = [ [ routes.before, routes[method] ].filter(Boolean) ];
next.after = [ routes.after ].filter(Boolean);
next.matched = true;
next.captures = [];
return filterRoutes(next);
}
for (var r in routes) {
if (routes.hasOwnProperty(r) && (!this._methods[r] || this._methods[r] && typeof routes[r] === "object" && !Array.isArray(routes[r]))) {
current = exact = regexp + this.delimiter + r;
if (!this.strict) {
exact += "[" + this.delimiter + "]?";
}
match = path.match(new RegExp("^" + exact));
if (!match) {
continue;
}
if (match[0] && match[0] == path && routes[r][method]) {
next = [ [ routes[r].before, routes[r][method] ].filter(Boolean) ];
next.after = [ routes[r].after ].filter(Boolean);
next.matched = true;
next.captures = match.slice(1);
if (this.recurse && routes === this.routes) {
next.push([ routes.before, routes.on ].filter(Boolean));
next.after = next.after.concat([ routes.after ].filter(Boolean));
}
return filterRoutes(next);
}
next = this.traverse(method, path, routes[r], current);
if (next.matched) {
if (next.length > 0) {
fns = fns.concat(next);
}
if (this.recurse) {
fns.push([ routes[r].before, routes[r].on ].filter(Boolean));
next.after = next.after.concat([ routes[r].after ].filter(Boolean));
if (routes === this.routes) {
fns.push([ routes["before"], routes["on"] ].filter(Boolean));
next.after = next.after.concat([ routes["after"] ].filter(Boolean));
}
}
fns.matched = true;
fns.captures = next.captures;
fns.after = next.after;
return filterRoutes(fns);
}
}
}
return false;
};
Router.prototype.insert = function(method, path, route, parent) {
var methodType, parentType, isArray, nested, part;
path = path.filter(function(p) {
return p && p.length > 0;
});
parent = parent || this.routes;
part = path.shift();
if (/\:|\*/.test(part) && !/\\d|\\w/.test(part)) {
part = regifyString(part, this.params);
}
if (path.length > 0) {
parent[part] = parent[part] || {};
return this.insert(method, path, route, parent[part]);
}
if (!part && !path.length && parent === this.routes) {
methodType = typeof parent[method];
switch (methodType) {
case "function":
parent[method] = [ parent[method], route ];
return;
case "object":
parent[method].push(route);
return;
case "undefined":
parent[method] = route;
return;
}
return;
}
parentType = typeof parent[part];
isArray = Array.isArray(parent[part]);
if (parent[part] && !isArray && parentType == "object") {
methodType = typeof parent[part][method];
switch (methodType) {
case "function":
parent[part][method] = [ parent[part][method], route ];
return;
case "object":
parent[part][method].push(route);
return;
case "undefined":
parent[part][method] = route;
return;
}
} else if (parentType == "undefined") {
nested = {};
nested[method] = route;
parent[part] = nested;
return;
}
throw new Error("Invalid route context: " + parentType);
};
Router.prototype.extend = function(methods) {
var self = this, len = methods.length, i;
function extend(method) {
self._methods[method] = true;
self[method] = function() {
var extra = arguments.length === 1 ? [ method, "" ] : [ method ];
self.on.apply(self, extra.concat(Array.prototype.slice.call(arguments)));
};
}
for (i = 0; i < len; i++) {
extend(methods[i]);
}
};
Router.prototype.runlist = function(fns) {
var runlist = this.every && this.every.before ? [ this.every.before ].concat(_flatten(fns)) : _flatten(fns);
if (this.every && this.every.on) {
runlist.push(this.every.on);
}
runlist.captures = fns.captures;
runlist.source = fns.source;
return runlist;
};
Router.prototype.mount = function(routes, path) {
if (!routes || typeof routes !== "object" || Array.isArray(routes)) {
return;
}
var self = this;
path = path || [];
if (!Array.isArray(path)) {
path = path.split(self.delimiter);
}
function insertOrMount(route, local) {
var rename = route, parts = route.split(self.delimiter), routeType = typeof routes[route], isRoute = parts[0] === "" || !self._methods[parts[0]], event = isRoute ? "on" : rename;
if (isRoute) {
rename = rename.slice((rename.match(new RegExp(self.delimiter)) || [ "" ])[0].length);
parts.shift();
}
if (isRoute && routeType === "object" && !Array.isArray(routes[route])) {
local = local.concat(parts);
self.mount(routes[route], local);
return;
}
if (isRoute) {
local = local.concat(rename.split(self.delimiter));
local = terminator(local, self.delimiter);
}
self.insert(event, local, routes[route]);
}
for (var route in routes) {
if (routes.hasOwnProperty(route)) {
insertOrMount(route, path.slice(0));
}
}
};
}(typeof exports === "object" ? exports : window));
\ No newline at end of file
/**
* @fileOverview
* PureMVC JS Native Port by David Foley, Frédéric Saunier, & Alain Duchesneau
* Copyright(c) 2006-2012 Futurescale, Inc., Some rights reserved.
* Reuse governed by Creative Commons Attribution 3.0
* http://creativecommons.org/licenses/by/3.0/us/
* @author david.foley@puremvc.org
*/
(function (scope){
if (null == scope)
scope= window;
// if the global puremvc namespace already exists, turn back now
if (scope.puremvc)
{
return;
}
/* implementation begin */
/**
* @author PureMVC JS Native Port by David Foley, Frédéric Saunier, & Alain Duchesneau
* @author Copyright(c) 2006-2012 Futurescale, Inc., Some rights reserved.
*
* @class puremvc.Observer
*
* A base Observer implementation.
*
* An Observer is an object that encapsulates information
* about an interested object with a method that should
* be called when a particular Notification is broadcast.
*
* In PureMVC, the Observer class assumes these responsibilities:
*
* - Encapsulate the notification (callback) method of the interested object.
* - Encapsulate the notification context (this) of the interested object.
* - Provide methods for setting the notification method and context.
* - Provide a method for notifying the interested object.
*
*
* The notification method on the interested object should take
* one parameter of type Notification.
*
*
* @param {Function} notifyMethod
* the notification method of the interested object
* @param {Object} notifyContext
* the notification context of the interested object
* @constructor
*/
function Observer (notifyMethod, notifyContext)
{
this.setNotifyMethod(notifyMethod);
this.setNotifyContext(notifyContext);
};
/**
* Set the Observers notification method.
*
* The notification method should take one parameter of type Notification
* @param {Function} notifyMethod
* the notification (callback) method of the interested object.
* @return {void}
*/
Observer.prototype.setNotifyMethod= function (notifyMethod)
{
this.notify= notifyMethod;
};
/**
* Set the Observers notification context.
*
* @param {Object} notifyContext
* the notification context (this) of the interested object.
*
* @return {void}
*/
Observer.prototype.setNotifyContext= function (notifyContext)
{
this.context= notifyContext;
};
/**
* Get the Function that this Observer will invoke when it is notified.
*
* @private
* @return {Function}
*/
Observer.prototype.getNotifyMethod= function ()
{
return this.notify;
};
/**
* Get the Object that will serve as the Observers callback execution context
*
* @private
* @return {Object}
*/
Observer.prototype.getNotifyContext= function ()
{
return this.context;
};
/**
* Notify the interested object.
*
* @param {puremvc.Notification} notification
* The Notification to pass to the interested objects notification method
* @return {void}
*/
Observer.prototype.notifyObserver= function (notification)
{
this.getNotifyMethod().call(this.getNotifyContext(), notification);
};
/**
* Compare an object to this Observers notification context.
*
* @param {Object} object
*
* @return {boolean}
*/
Observer.prototype.compareNotifyContext= function (object)
{
return object === this.context;
};
/**
* The Observers callback Function
*
* @private
* @type {Function}
*/
Observer.prototype.notify= null;
/**
* The Observers callback Object
* @private
* @type {Object}
*/
Observer.prototype.context= null;
/**
* @author PureMVC JS Native Port by David Foley, Frédéric Saunier, & Alain Duchesneau
* @author Copyright(c) 2006-2012 Futurescale, Inc., Some rights reserved.
*
* @class puremvc.Notification
*
* A base Notification implementation.
*
* PureMVC does not rely upon underlying event models such as the one provided
* with the DOM or other browser centric W3C event models.
*
* The Observer Pattern as implemented within PureMVC exists to support
* event-driven communication between the application and the actors of the MVC
* triad.
*
* Notifications are not meant to be a replacement for events in the browser.
* Generally, Mediator implementors place event listeners on their view
* components, which they then handle in the usual way. This may lead to the
* broadcast of Notifications to trigger commands or to communicate with other
* Mediators. {@link puremvc.Proxy Proxy},
* {@link puremvc.SimpleCommand SimpleCommand}
* and {@link puremvc.MacroCommand MacroCommand}
* instances communicate with each other and
* {@link puremvc.Mediator Mediator}s
* by broadcasting Notifications.
*
* A key difference between browser events and PureMVC Notifications is that
* events follow the 'Chain of Responsibility' pattern, 'bubbling' up the
* display hierarchy until some parent component handles the event, while
* PureMVC Notification follow a 'Publish/Subscribe' pattern. PureMVC classes
* need not be related to each other in a parent/child relationship in order to
* communicate with one another using Notifications.
*
* @constructor
* @param {string} name
* The Notification name
* @param {Object} [body]
* The Notification body
* @param {Object} [type]
* The Notification type
*/
function Notification(name, body, type)
{
this.name= name;
this.body= body;
this.type= type;
};
/**
* Get the name of the Notification instance
*
* @return {string}
* The name of the Notification instance
*/
Notification.prototype.getName= function()
{
return this.name;
};
/**
* Set this Notifications body.
* @param {Object} body
* @return {void}
*/
Notification.prototype.setBody= function(body)
{
this.body= body;
};
/**
* Get the Notification body.
*
* @return {Object}
*/
Notification.prototype.getBody= function()
{
return this.body
};
/**
* Set the type of the Notification instance.
*
* @param {Object} type
* @return {void}
*/
Notification.prototype.setType= function(type)
{
this.type= type;
};
/**
* Get the type of the Notification instance.
*
* @return {Object}
*/
Notification.prototype.getType= function()
{
return this.type;
};
/**
* Get a string representation of the Notification instance
*
* @return {string}
*/
Notification.prototype.toString= function()
{
var msg= "Notification Name: " + this.getName();
msg+= "\nBody:" + ((this.body == null ) ? "null" : this.body.toString());
msg+= "\nType:" + ((this.type == null ) ? "null" : this.type);
return msg;
};
/**
* The Notifications name.
*
* @type {string}
* @private
*/
Notification.prototype.name= null;
/**
* The Notifications type.
*
* @type {string}
* @private
*/
Notification.prototype.type= null;
/**
* The Notifications body.
*
* @type {Object}
* @private
*/
Notification.prototype.body= null;
/**
* @author PureMVC JS Native Port by David Foley, Frédéric Saunier, & Alain Duchesneau
* @author Copyright(c) 2006-2012 Futurescale, Inc., Some rights reserved.
*
* @class puremvc.Notifier
*
* A Base Notifier implementation.
*
* {@link puremvc.MacroCommand MacroCommand},
* {@link puremvc.SimpleCommand SimpleCommand},
* {@link puremvc.Mediator Mediator} and
* {@link puremvc.Proxy Proxy}
* all have a need to send Notifications
*
* The Notifier interface provides a common method called #sendNotification that
* relieves implementation code of the necessity to actually construct
* Notifications.
*
* The Notifier class, which all of the above mentioned classes
* extend, provides an initialized reference to the
* {@link puremvc.Facade Facade}
* Multiton, which is required for the convienience method
* for sending Notifications but also eases implementation as these
* classes have frequent
* {@link puremvc.Facade Facade} interactions
* and usually require access to the facade anyway.
*
* NOTE: In the MultiCore version of the framework, there is one caveat to
* notifiers, they cannot send notifications or reach the facade until they
* have a valid multitonKey.
*
* The multitonKey is set:
* - on a Command when it is executed by the Controller
* - on a Mediator is registered with the View
* - on a Proxy is registered with the Model.
*
* @constructor
*/
function Notifier()
{
};
/**
* Create and send a Notification.
*
* Keeps us from having to construct new Notification instances in our
* implementation code.
*
* @param {string} notificationName
* A notification name
* @param {Object} [body]
* The body of the notification
* @param {string} [type]
* The notification type
* @return {void}
*/
Notifier.prototype.sendNotification = function(notificationName, body, type)
{
var facade = this.getFacade();
if(facade)
{
facade.sendNotification(notificationName, body, type);
}
};
/**
* @protected
* A reference to this Notifier's Facade. This reference will not be available
* until #initializeNotifier has been called.
*
* @type {puremvc.Facade}
*/
Notifier.prototype.facade;
/**
* Initialize this Notifier instance.
*
* This is how a Notifier gets its multitonKey.
* Calls to #sendNotification or to access the
* facade will fail until after this method
* has been called.
*
* Mediators, Commands or Proxies may override
* this method in order to send notifications
* or access the Multiton Facade instance as
* soon as possible. They CANNOT access the facade
* in their constructors, since this method will not
* yet have been called.
*
*
* @param {string} key
* The Notifiers multiton key;
* @return {void}
*/
Notifier.prototype.initializeNotifier = function(key)
{
this.multitonKey = String(key);
this.facade= this.getFacade();
};
/**
* Retrieve the Multiton Facade instance
*
*
* @protected
* @return {puremvc.Facade}
*/
Notifier.prototype.getFacade = function()
{
if(this.multitonKey == null)
{
throw new Error(Notifier.MULTITON_MSG);
};
return Facade.getInstance(this.multitonKey);
};
/**
* @ignore
* The Notifiers internal multiton key.
*
* @protected
* @type string
*/
Notifier.prototype.multitonKey = null;
/**
* @ignore
* The error message used if the Notifier is not initialized correctly and
* attempts to retrieve its own multiton key
*
* @static
* @protected
* @const
* @type string
*/
Notifier.MULTITON_MSG = "multitonKey for this Notifier not yet initialized!";
/**
* @author PureMVC JS Native Port by David Foley, Frédéric Saunier, & Alain Duchesneau
* @author Copyright(c) 2006-2012 Futurescale, Inc., Some rights reserved.
*
* @class puremvc.SimpleCommand
* @extends puremvc.Notifier
*
* SimpleCommands encapsulate the business logic of your application. Your
* subclass should override the #execute method where your business logic will
* handle the
* {@link puremvc.Notification Notification}
*
* Take a look at
* {@link puremvc.Facade#registerCommand Facade's registerCommand}
* or {@link puremvc.Controller#registerCommand Controllers registerCommand}
* methods to see how to add commands to your application.
*
* @constructor
*/
function SimpleCommand () { };
SimpleCommand.prototype= new Notifier;
SimpleCommand.prototype.constructor= SimpleCommand;
/**
* Fulfill the use-case initiated by the given Notification
*
* In the Command Pattern, an application use-case typically begins with some
* user action, which results in a Notification is handled by the business logic
* in the #execute method of a command.
*
* @param {puremvc.Notification} notification
* The notification to handle.
* @return {void}
*/
SimpleCommand.prototype.execute= function (notification) { };
/**
* @author PureMVC JS Native Port by David Foley, Frédéric Saunier, & Alain Duchesneau
* @author Copyright(c) 2006-2012 Futurescale, Inc., Some rights reserved.
*
* @class puremvc.MacroCommand
* @extends puremvc.Notifier
*
* A base command implementation that executes other commands, such as
* {@link puremvc.SimpleCommand SimpleCommand}
* or {@link puremvc.MacroCommand MacroCommand}
* subclasses.
*
* A MacroCommand maintains an list of
* command constructor references called *SubCommands*.
*
* When #execute is called, the MacroCommand
* instantiates and calls #execute on each of its *SubCommands* in turn.
* Each *SubCommand* will be passed a reference to the original
* {@link puremvc.Notification Notification}
* that was passed to the MacroCommands #execute method
*
* Unlike {@link puremvc.SimpleCommand SimpleCommand},
* your subclass should not override #execute but instead, should
* override the #initializeMacroCommand method, calling #addSubCommand once for
* each *SubCommand* to be executed.
*
* If your subclass does define a constructor, be sure to call "super" like so
*
* function MyMacroCommand ()
* {
* MacroCommand.call(this);
* };
* @constructor
*/
function MacroCommand()
{
this.subCommands= [];
this.initializeMacroCommand();
};
/* subclass Notifier */
MacroCommand.prototype= new Notifier;
MacroCommand.prototype.constructor= MacroCommand;
/**
* @private
* @type {Array.<puremvc.SimpleCommand|puremvc.MacroCommand>}
*/
MacroCommand.prototype.subCommands= null;
/**
* @protected
* Initialize the MacroCommand.
*
* In your subclass, override this method to
* initialize the MacroCommand's *SubCommand*
* list with command class references like
* this:
*
* // Initialize MyMacroCommand
* MyMacroCommand.prototype.initializeMacroCommand= function ()
* {
* this.addSubCommand( com.me.myapp.controller.FirstCommand );
* this.addSubCommand( com.me.myapp.controller.SecondCommand );
* this.addSubCommand( com.me.myapp.controller.ThirdCommand );
* };
*
* Note that *SubCommand*s may be any command implementor,
* MacroCommands or SimpleCommands are both acceptable.
* @return {void}
*/
MacroCommand.prototype.initializeMacroCommand= function() {}
/**
* @protected
* Add a *SubCommand*
*
* The *SubCommand*s will be called in First In / First Out (FIFO) order
* @param {Function} commandClassRef
* A reference to a subclassed SimpleCommand or MacroCommand constructor
*/
MacroCommand.prototype.addSubCommand= function(commandClassRef)
{
this.subCommands.push(commandClassRef);
};
/**
* Execute this MacroCommands *SubCommands*
*
* The *SubCommand*s will be called in First In / First Out (FIFO) order
* @param {puremvc.Notification} note
* The Notification object to be passed to each *SubCommand*
*/
MacroCommand.prototype.execute= function(note)
{
// SIC- TODO optimize
while(this.subCommands.length > 0)
{
var ref= this.subCommands.shift();
var cmd= new ref;
cmd.initializeNotifier(this.multitonKey);
cmd.execute(note);
}
};
/**
* @author PureMVC JS Native Port by David Foley, Frédéric Saunier, & Alain Duchesneau
* @author Copyright(c) 2006-2012 Futurescale, Inc., Some rights reserved.
*
* @class puremvc.Mediator
* @extends puremvc.Notifier
*
* A base Mediator implementation.
*
* In PureMVC, Mediator classes are used to mediate communication between a view
* component and the rest of the application.
*
* A Mediator should listen to its view components for events, and handle them
* by sending notifications (to be handled by other Mediators,
* {@link puremvc.SimpleCommand SimpleCommands}
* or
* {@link puremvc.MacroCommand MacroCommands})
* or passing data from the view component directly to a
* {@link puremvc.Proxy Proxy}, such as submitting
* the contents of a form to a service.
*
* Mediators should not perform business logic, maintain state or other
* information for its view component, or break the encapsulation of the view
* component by manipulating the view component's children. It should only call
* methods or set properties on the view component.
*
* The view component should encapsulate its own behavior and implementation by
* exposing methods and properties that the Mediator can call without having to
* know about the view component's children.
*
* @constructor
* @param {string} [mediatorName]
* The Mediators name. The Mediators static #NAME value is used by default
* @param {Object} [viewComponent]
* The Mediators {@link #setViewComponent viewComponent}.
*/
function Mediator (mediatorName, viewComponent)
{
this.mediatorName= mediatorName || this.constructor.NAME;
this.viewComponent=viewComponent;
};
/**
* @static
* The name of the Mediator.
*
* Typically, a Mediator will be written to serve one specific control or group
* of controls and so, will not have a need to be dynamically named.
*
* @type {string}
*/
Mediator.NAME= "Mediator";
/* subclass */
Mediator.prototype= new Notifier;
Mediator.prototype.constructor= Mediator;
/**
* Get the name of the Mediator
*
* @return {string}
* The Mediator name
*/
Mediator.prototype.getMediatorName= function ()
{
return this.mediatorName;
};
/**
* Set the Mediators view component. This could
* be a HTMLElement, a bespoke UiComponent wrapper
* class, a MooTools Element, a jQuery result or a
* css selector, depending on which DOM abstraction
* library you are using.
*
*
* @param {Object} the view component
* @return {void}
*/
Mediator.prototype.setViewComponent= function (viewComponent)
{
this.viewComponent= viewComponent;
};
/**
* Get the Mediators view component.
*
* Additionally, an optional explicit getter can be
* be defined in the subclass that defines the
* view components, providing a more semantic interface
* to the Mediator.
*
* This is different from the AS3 implementation in
* the sense that no casting is required from the
* object supplied as the view component.
*
* MyMediator.prototype.getComboBox= function ()
* {
* return this.viewComponent;
* }
*
* @return {Object}
* The view component
*/
Mediator.prototype.getViewComponent= function ()
{
return this.viewComponent;
};
/**
* List the Notification names this Mediator is interested
* in being notified of.
*
* @return {Array}
* The list of Notification names.
*/
Mediator.prototype.listNotificationInterests= function ()
{
return [];
};
/**
* Handle Notifications.
*
* Typically this will be handled in a switch statement
* with one 'case' entry per Notification the Mediator
* is interested in
*
* @param {puremvc.Notification} notification
* @return {void}
*/
Mediator.prototype.handleNotification= function (notification)
{
return;
};
/**
* Called by the View when the Mediator is registered
* @return {void}
*/
Mediator.prototype.onRegister= function ()
{
return;
};
/**
* Called by the View when the Mediator is removed
*/
Mediator.prototype.onRemove= function ()
{
return;
};
/**
* @ignore
* The Mediators name. Should only be accessed by Mediator subclasses.
*
* @protected
* @type string
*/
Mediator.prototype.mediatorName= null;
/**
* @ignore
* The Mediators viewComponent. Should only be accessed by Mediator subclasses.
*
* @protected
* @type Object
*/
Mediator.prototype.viewComponent=null;
/**
* @author PureMVC JS Native Port by David Foley, Frédéric Saunier, & Alain Duchesneau
* @author Copyright(c) 2006-2012 Futurescale, Inc., Some rights reserved.
*
* @class puremvc.Proxy
* @extends puremvc.Notifier
*
* A base Proxy implementation.
*
* In PureMVC, Proxy classes are used to manage parts of the application's data
* model.
*
* A Proxy might simply manage a reference to a local data object, in which case
* interacting with it might involve setting and getting of its data in
* synchronous fashion.
*
* Proxy classes are also used to encapsulate the application's interaction with
* remote services to save or retrieve data, in which case, we adopt an
* asyncronous idiom; setting data (or calling a method) on the Proxy and
* listening for a
* {@link puremvc.Notification Notification}
* to be sent when the Proxy has retrieved the data from the service.
*
*
* @param {string} [proxyName]
* The Proxy's name. If none is provided, the Proxy will use its constructors
* NAME property.
* @param {Object} [data]
* The Proxy's data object
* @constructor
*/
function Proxy(proxyName, data)
{
this.proxyName= proxyName || this.constructor.NAME;
if(data != null)
{
this.setData(data);
}
};
Proxy.NAME= "Proxy";
Proxy.prototype= new Notifier;
Proxy.prototype.constructor= Proxy;
/**
* Get the Proxy's name.
*
* @return {string}
*/
Proxy.prototype.getProxyName= function()
{
return this.proxyName;
};
/**
* Set the Proxy's data object
*
* @param {Object} data
* @return {void}
*/
Proxy.prototype.setData= function(data)
{
this.data= data;
};
/**
* Get the Proxy's data object
*
* @return {Object}
*/
Proxy.prototype.getData= function()
{
return this.data;
};
/**
* Called by the {@link puremvc.Model Model} when
* the Proxy is registered.
*
* @return {void}
*/
Proxy.prototype.onRegister= function()
{
return;
};
/**
* Called by the {@link puremvc.Model Model} when
* the Proxy is removed.
*
* @return {void}
*/
Proxy.prototype.onRemove= function()
{
return;
};
/**
* @ignore
* The Proxys name.
*
* @protected
* @type String
*/
Proxy.prototype.proxyName= null;
/**
* @ignore
* The Proxy's data object.
*
* @protected
* @type Object
*/
Proxy.prototype.data= null;
/**
* @author PureMVC JS Native Port by David Foley, Frédéric Saunier, & Alain Duchesneau
* @author Copyright(c) 2006-2012 Futurescale, Inc., Some rights reserved.
*
* @class puremvc.Facade
* Facade exposes the functionality of the Controller, Model and View
* actors to client facing code.
*
* This Facade implementation is a Multiton, so you should not call the
* constructor directly, but instead call the static Factory method,
* passing the unique key for this instance to #getInstance
*
* @constructor
* @param {string} key
* The multiton key to use to retrieve the Facade instance.
* @throws {Error}
* If an attempt is made to instantiate Facade directly
*/
function Facade(key)
{
if(Facade.instanceMap[key] != null)
{
throw new Error(Facade.MULTITON_MSG);
}
this.initializeNotifier(key);
Facade.instanceMap[key] = this;
this.initializeFacade();
};
/**
* Initialize the Multiton Facade instance.
*
* Called automatically by the constructor. Override in your subclass to any
* subclass specific initializations. Be sure to call the 'super'
* initializeFacade method, though
*
* MyFacade.prototype.initializeFacade= function ()
* {
* Facade.call(this);
* };
* @protected
* @return {void}
*/
Facade.prototype.initializeFacade = function()
{
this.initializeModel();
this.initializeController();
this.initializeView();
};
/**
* Facade Multiton Factory method.
* Note that this method will return null if supplied a
* null or undefined multiton key.
*
* @param {string} key
* The multiton key use to retrieve a particular Facade instance
* @return {puremvc.Facade}
*/
Facade.getInstance = function(key)
{
if (null == key)
return null;
if(Facade.instanceMap[key] == null)
{
Facade.instanceMap[key] = new Facade(key);
}
return Facade.instanceMap[key];
};
/**
* Initialize the {@link puremvc.Controller Controller}.
*
* Called by the #initializeFacade method.
*
* Override this method in your subclass of Facade
* if one or both of the following are true:
* - You wish to initialize a different Controller
* - You have
* {@link puremvc.SimpleCommand SimpleCommand}s
* or {@link puremvc.MacroCommand MacroCommand}s
* to register with the Controllerat startup.
*
* If you don't want to initialize a different Controller,
* call the 'super' initializeControlle method at the beginning of your
* method, then register commands.
*
* MyFacade.prototype.initializeController= function ()
* {
* Facade.prototype.initializeController.call(this);
* this.registerCommand(AppConstants.A_NOTE_NAME, ABespokeCommand)
* }
*
* @protected
* @return {void}
*/
Facade.prototype.initializeController = function()
{
if(this.controller != null)
return;
this.controller = Controller.getInstance(this.multitonKey);
};
/**
* @protected
* Initialize the {@link puremvc.Model Model};
*
* Called by the #initializeFacade method.
* Override this method in your subclass of Facade if one of the following are
* true:
*
* - You wish to initialize a different Model.
*
* - You have {@link puremvc.Proxy Proxy}s to
* register with the Model that do not retrieve a reference to the Facade at
* construction time.
*
* If you don't want to initialize a different Model
* call 'super' #initializeModel at the beginning of your method, then register
* Proxys.
*
* Note: This method is *rarely* overridden; in practice you are more
* likely to use a command to create and registerProxys with the Model>,
* since Proxys with mutable data will likely
* need to send Notifications and thus will likely want to fetch a reference to
* the Facade during their construction.
*
* @return {void}
*/
Facade.prototype.initializeModel = function()
{
if(this.model != null)
return;
this.model = Model.getInstance(this.multitonKey);
};
/**
* @protected
*
* Initialize the {@link puremvc.View View}.
*
* Called by the #initializeFacade method.
*
* Override this method in your subclass of Facade if one or both of the
* following are true:
*
* - You wish to initialize a different View.
* - You have Observers to register with the View
*
* If you don't want to initialize a different View
* call 'super' #initializeView at the beginning of your
* method, then register Mediator instances.
*
* MyFacade.prototype.initializeView= function ()
* {
* Facade.prototype.initializeView.call(this);
* this.registerMediator(new MyMediator());
* };
*
* Note: This method is *rarely* overridden; in practice you are more
* likely to use a command to create and register Mediators
* with the View, since Mediator instances will need to send
* Notifications and thus will likely want to fetch a reference
* to the Facade during their construction.
* @return {void}
*/
Facade.prototype.initializeView = function()
{
if(this.view != null)
return;
this.view = View.getInstance(this.multitonKey);
};
/**
* Register a command with the Controller by Notification name
* @param {string} notificationName
* The name of the Notification to associate the command with
* @param {Function} commandClassRef
* A reference ot the commands constructor.
* @return {void}
*/
Facade.prototype.registerCommand = function(notificationName, commandClassRef)
{
this.controller.registerCommand(notificationName, commandClassRef);
};
/**
* Remove a previously registered command to Notification mapping from the
* {@link puremvc.Controller#removeCommand Controller}
* @param {string} notificationName
* The name of the the Notification to remove from the command mapping for.
* @return {void}
*/
Facade.prototype.removeCommand = function(notificationName)
{
this.controller.removeCommand(notificationName);
};
/**
* Check if a command is registered for a given notification.
*
* @param {string} notificationName
* A Notification name
* @return {boolean}
* Whether a comman is currently registered for the given notificationName
*/
Facade.prototype.hasCommand = function(notificationName)
{
return this.controller.hasCommand(notificationName);
};
/**
* Register a Proxy with the {@link puremvc.Model#registerProxy Model}
* by name.
*
* @param {puremvc.Proxy} proxy
* The Proxy instance to be registered with the Model.
* @return {void}
*/
Facade.prototype.registerProxy = function(proxy)
{
this.model.registerProxy(proxy);
};
/**
* Retrieve a Proxy from the Model
*
* @param {string} proxyName
* @return {puremvc.Proxy}
*/
Facade.prototype.retrieveProxy = function(proxyName)
{
return this.model.retrieveProxy(proxyName);
};
/**
* Remove a Proxy from the Model by name
* @param {string} proxyName
* The name of the Proxy
* @return {puremvc.Proxy}
* The Proxy that was removed from the Model
*/
Facade.prototype.removeProxy = function(proxyName)
{
var proxy = null;
if(this.model != null)
{
proxy = this.model.removeProxy(proxyName);
}
return proxy;
};
/**
* Check it a Proxy is registered.
* @param {string} proxyName
* A Proxy name
* @return {boolean}
* Whether a Proxy is currently registered with the given proxyName
*/
Facade.prototype.hasProxy = function(proxyName)
{
return this.model.hasProxy(proxyName);
};
/**
* Register a Mediator with with the View.
*
* @param {puremvc.Mediator} mediator
* A reference to the Mediator to register
* @return {void}
*/
Facade.prototype.registerMediator = function(mediator)
{
if(this.view != null)
{
this.view.registerMediator(mediator);
}
};
/**
* Retrieve a Mediator from the View by name
*
* @param {string} mediatorName
* The Mediators name
* @return {puremvc.Mediator}
* The retrieved Mediator
*/
Facade.prototype.retrieveMediator = function(mediatorName)
{
return this.view.retrieveMediator(mediatorName);
};
/**
* Remove a Mediator from the View.
*
* @param {string} mediatorName
* The name of the Mediator to remove.
* @return {puremvc.Mediator}
* The removed Mediator
*/
Facade.prototype.removeMediator = function(mediatorName)
{
var mediator = null;
if(this.view != null)
{
mediator = this.view.removeMediator(mediatorName);
}
return mediator;
};
/**
* Check if a Mediator is registered or not.
*
* @param {string} mediatorName
* A Mediator name
* @return {boolean}
* Whether a Mediator is registered with the given mediatorName
*/
Facade.prototype.hasMediator = function(mediatorName)
{
return this.view.hasMediator(mediatorName);
};
/**
* Create and send a
* {@link puremvc.Notification Notification}
*
* Keeps us from having to construct new Notification instances in our
* implementation
*
* @param {string} notificationName
* The name of the Notification to send
* @param {Object} [body]
* The body of the notification
* @param {string} [type]
* The type of the notification
* @return {void}
*/
Facade.prototype.sendNotification = function(notificationName, body, type)
{
this.notifyObservers(new Notification(notificationName, body, type));
};
/**
* Notify {@link puremvc.Observer Observer}s
*
* This method is left public mostly for backward compatibility, and to allow
* you to send custom notification classes using the facade.
*
* Usually you should just call sendNotification and pass the parameters, never
* having to construct the notification yourself.
*
* @param {puremvc.Notification} notification
* The Notification to send
* @return {void}
*/
Facade.prototype.notifyObservers = function(notification)
{
if(this.view != null)
{
this.view.notifyObservers(notification);
}
};
/**
* Initialize the Facades Notifier capabilities by setting the Multiton key for
* this facade instance.
*
* Not called directly, but instead from the constructor when #getInstance is
* invoked. It is necessary to be public in order to implement Notifier
*
* @param {string} key
* @return {void}
*/
Facade.prototype.initializeNotifier = function(key)
{
this.multitonKey = key;
};
/**
* Check if a *Core* is registered or not
*
* @static
* @param {string} key
* The multiton key for the *Core* in question
* @return {boolean}
* Whether a *Core* is registered with the given key
*/
Facade.hasCore = function(key)
{
return Facade.instanceMap[key] != null;
};
/**
* Remove a *Core*
*
* Remove the Model, View, Controller and Facade for a given key.
*
* @static
* @param {string} key
* @return {void}
*/
Facade.removeCore = function(key)
{
if(Facade.instanceMap[key] == null)
return;
Model.removeModel(key);
View.removeView(key);
Controller.removeController(key);
delete Facade.instanceMap[key];
};
/**
* @ignore
* The Facades corresponding Controller
*
* @protected
* @type puremvc.Controller
*/
Facade.prototype.controller = null;
/**
* @ignore
* The Facades corresponding Model instance
*
* @protected
* @type puremvc.Model
*/
Facade.prototype.model = null;
/**
* @ignore
* The Facades correspnding View instance.
*
* @protected
* @type puremvc.View
*/
Facade.prototype.view = null;
/**
* @ignore
* The Facades multiton key.
*
* @protected
* @type string
*/
Facade.prototype.multitonKey = null;
/**
* @ignore
* The Multiton Facade instance map.
* @static
* @protected
* @type Array
*/
Facade.instanceMap = [];
/**
* @ignore
* Message Constants
* @protected
* @type {string}
* @const
* @static
*/
Facade.MULTITON_MSG = "Facade instance for this Multiton key already constructed!";
/**
* @author PureMVC JS Native Port by David Foley, Frédéric Saunier, & Alain Duchesneau
* @author Copyright(c) 2006-2012 Futurescale, Inc., Some rights reserved.
*
* @class puremvc.View
*
* A Multiton View implementation.
*
* In PureMVC, the View class assumes these responsibilities
*
* - Maintain a cache of {@link puremvc.Mediator Mediator}
* instances.
*
* - Provide methods for registering, retrieving, and removing
* {@link puremvc.Mediator Mediator}.
*
* - Notifiying {@link puremvc.Mediator Mediator} when they are registered or
* removed.
*
* - Managing the observer lists for each {@link puremvc.Notification Notification}
* in the application.
*
* - Providing a method for attaching {@link puremvc.Observer Observer} to an
* {@link puremvc.Notification Notification}'s observer list.
*
* - Providing a method for broadcasting a {@link puremvc.Notification Notification}.
*
* - Notifying the {@link puremvc.Observer Observer}s of a given
* {@link puremvc.Notification Notification} when it broadcast.
*
* This View implementation is a Multiton, so you should not call the
* constructor directly, but instead call the static Multiton
* Factory #getInstance method.
*
* @param {string} key
* @constructor
* @throws {Error}
* if instance for this Multiton key has already been constructed
*/
function View(key)
{
if(View.instanceMap[key] != null)
{
throw new Error(View.MULTITON_MSG);
};
this.multitonKey = key;
View.instanceMap[this.multitonKey] = this;
this.mediatorMap = [];
this.observerMap = [];
this.initializeView();
};
/**
* @protected
* Initialize the Singleton View instance
*
* Called automatically by the constructor, this is your opportunity to
* initialize the Singleton instance in your subclass without overriding the
* constructor
*
* @return {void}
*/
View.prototype.initializeView = function()
{
return;
};
/**
* View Singleton Factory method.
* Note that this method will return null if supplied a null
* or undefined multiton key.
*
* @return {puremvc.View}
* The Singleton instance of View
*/
View.getInstance = function(key)
{
if (null == key)
return null;
if(View.instanceMap[key] == null)
{
View.instanceMap[key] = new View(key);
};
return View.instanceMap[key];
};
/**
* Register an Observer to be notified of Notifications with a given name
*
* @param {string} notificationName
* The name of the Notifications to notify this Observer of
* @param {puremvc.Observer} observer
* The Observer to register.
* @return {void}
*/
View.prototype.registerObserver = function(notificationName, observer)
{
if(this.observerMap[notificationName] != null)
{
this.observerMap[notificationName].push(observer);
}
else
{
this.observerMap[notificationName] = [observer];
}
};
/**
* Notify the Observersfor a particular Notification.
*
* All previously attached Observers for this Notification's
* list are notified and are passed a reference to the INotification in
* the order in which they were registered.
*
* @param {puremvc.Notification} notification
* The Notification to notify Observers of
* @return {void}
*/
View.prototype.notifyObservers = function(notification)
{
// SIC
if(this.observerMap[notification.getName()] != null)
{
var observers_ref = this.observerMap[notification.getName()], observers = [], observer
for(var i = 0; i < observers_ref.length; i++)
{
observer = observers_ref[i];
observers.push(observer);
}
for(var i = 0; i < observers.length; i++)
{
observer = observers[i];
observer.notifyObserver(notification);
}
}
};
/**
* Remove the Observer for a given notifyContext from an observer list for
* a given Notification name
*
* @param {string} notificationName
* Which observer list to remove from
* @param {Object} notifyContext
* Remove the Observer with this object as its notifyContext
* @return {void}
*/
View.prototype.removeObserver = function(notificationName, notifyContext)
{
// SIC
var observers = this.observerMap[notificationName];
for(var i = 0; i < observers.length; i++)
{
if(observers[i].compareNotifyContext(notifyContext) == true)
{
observers.splice(i, 1);
break;
}
}
if(observers.length == 0)
{
delete this.observerMap[notificationName];
}
};
/**
* Register a Mediator instance with the View.
*
* Registers the Mediator so that it can be retrieved by name,
* and further interrogates the Mediator for its
* {@link puremvc.Mediator#listNotificationInterests interests}.
*
* If the Mediator returns any Notification
* names to be notified about, an Observer is created encapsulating
* the Mediator instance's
* {@link puremvc.Mediator#handleNotification handleNotification}
* method and registering it as an Observer for all Notifications the
* Mediator is interested in.
*
* @param {puremvc.Mediator}
* a reference to the Mediator instance
*/
View.prototype.registerMediator = function(mediator)
{
if(this.mediatorMap[mediator.getMediatorName()] != null)
{
return;
}
mediator.initializeNotifier(this.multitonKey);
// register the mediator for retrieval by name
this.mediatorMap[mediator.getMediatorName()] = mediator;
// get notification interests if any
var interests = mediator.listNotificationInterests();
// register mediator as an observer for each notification
if(interests.length > 0)
{
// create observer referencing this mediators handleNotification method
var observer = new Observer(mediator.handleNotification, mediator);
for(var i = 0; i < interests.length; i++)
{
this.registerObserver(interests[i], observer);
}
}
mediator.onRegister();
}
/**
* Retrieve a Mediator from the View
*
* @param {string} mediatorName
* The name of the Mediator instance to retrieve
* @return {puremvc.Mediator}
* The Mediator instance previously registered with the given mediatorName
*/
View.prototype.retrieveMediator = function(mediatorName)
{
return this.mediatorMap[mediatorName];
};
/**
* Remove a Mediator from the View.
*
* @param {string} mediatorName
* Name of the Mediator instance to be removed
* @return {puremvc.Mediator}
* The Mediator that was removed from the View
*/
View.prototype.removeMediator = function(mediatorName)
{
var mediator = this.mediatorMap[mediatorName];
if(mediator)
{
// for every notification the mediator is interested in...
var interests = mediator.listNotificationInterests();
for(var i = 0; i < interests.length; i++)
{
// remove the observer linking the mediator to the notification
// interest
this.removeObserver(interests[i], mediator);
}
// remove the mediator from the map
delete this.mediatorMap[mediatorName];
// alert the mediator that it has been removed
mediator.onRemove();
}
return mediator;
};
/**
* Check if a Mediator is registered or not.
*
* @param {string} mediatorName
* @return {boolean}
* Whether a Mediator is registered with the given mediatorname
*/
View.prototype.hasMediator = function(mediatorName)
{
return this.mediatorMap[mediatorName] != null;
};
/**
* Remove a View instance
*
* @return {void}
*/
View.removeView = function(key)
{
delete View.instanceMap[key];
};
/**
* @ignore
* The Views internal mapping of mediator names to mediator instances
*
* @type Array
* @protected
*/
View.prototype.mediatorMap = null;
/**
* @ignore
* The Views internal mapping of Notification names to Observer lists
*
* @type Array
* @protected
*/
View.prototype.observerMap = null;
/**
* @ignore
* The internal map used to store multiton View instances
*
* @type Array
* @protected
*/
View.instanceMap = [];
/**
* @ignore
* The Views internal multiton key.
*
* @type string
* @protected
*/
View.prototype.multitonKey = null;
/**
* @ignore
* The error message used if an attempt is made to instantiate View directly
*
* @type string
* @protected
* @const
* @static
*/
View.MULTITON_MSG = "View instance for this Multiton key already constructed!";
/**
* @author PureMVC JS Native Port by David Foley, Frédéric Saunier, & Alain Duchesneau
* @author Copyright(c) 2006-2012 Futurescale, Inc., Some rights reserved.
*
* @class puremvc.Model
*
* A Multiton Model implementation.
*
* In PureMVC, the Model class provides
* access to model objects (Proxies) by named lookup.
*
* The Model assumes these responsibilities:
*
* - Maintain a cache of {@link puremvc.Proxy Proxy}
* instances.
* - Provide methods for registering, retrieving, and removing
* {@link puremvc.Proxy Proxy} instances.
*
* Your application must register
* {@link puremvc.Proxy Proxy} instances with the Model.
* Typically, you use a
* {@link puremvc.SimpleCommand SimpleCommand}
* or
* {@link puremvc.MacroCommand MacroCommand}
* to create and register Proxy instances once the Facade has initialized the
* *Core* actors.
*
* This Model implementation is a Multiton, so you should not call the
* constructor directly, but instead call the
* {@link #getInstance static Multiton Factory method}
* @constructor
* @param {string} key
* The Models multiton key
* @throws {Error}
* An error is thrown if this multitons key is already in use by another instance
*/
function Model(key)
{
if(Model.instanceMap[key])
{
throw new Error(Model.MULTITON_MSG);
}
this.multitonKey= key;
Model.instanceMap[key]= this;
this.proxyMap= [];
this.initializeModel();
};
/**
* Initialize the Model instance.
*
* Called automatically by the constructor, this
* is your opportunity to initialize the Singleton
* instance in your subclass without overriding the
* constructor.
*
* @return void
*/
Model.prototype.initializeModel= function(){};
/**
* Model Multiton Factory method.
* Note that this method will return null if supplied a null
* or undefined multiton key.
*
* @param {string} key
* The multiton key for the Model to retrieve
* @return {puremvc.Model}
* the instance for this Multiton key
*/
Model.getInstance= function(key)
{
if (null == key)
return null;
if(Model.instanceMap[key] == null)
{
Model.instanceMap[key]= new Model(key);
}
return Model.instanceMap[key];
};
/**
* Register a Proxy with the Model
* @param {puremvc.Proxy}
*/
Model.prototype.registerProxy= function(proxy)
{
proxy.initializeNotifier(this.multitonKey);
this.proxyMap[proxy.getProxyName()]= proxy;
proxy.onRegister();
};
/**
* Retrieve a Proxy from the Model
*
* @param {string} proxyName
* @return {puremvc.Proxy}
* The Proxy instance previously registered with the provided proxyName
*/
Model.prototype.retrieveProxy= function(proxyName)
{
return this.proxyMap[proxyName];
};
/**
* Check if a Proxy is registered
* @param {string} proxyName
* @return {boolean}
* whether a Proxy is currently registered with the given proxyName.
*/
Model.prototype.hasProxy= function(proxyName)
{
return this.proxyMap[proxyName] != null;
};
/**
* Remove a Proxy from the Model.
*
* @param {string} proxyName
* The name of the Proxy instance to remove
* @return {puremvc.Proxy}
* The Proxy that was removed from the Model
*/
Model.prototype.removeProxy= function(proxyName)
{
var proxy= this.proxyMap[proxyName];
if(proxy)
{
this.proxyMap[proxyName]= null;
proxy.onRemove();
}
return proxy;
};
/**
* @static
* Remove a Model instance.
*
* @param {string} key
* @return {void}
*/
Model.removeModel= function(key)
{
delete Model.instanceMap[key];
};
/**
* @ignore
* The map used by the Model to store Proxy instances.
*
* @protected
* @type Array
*/
Model.prototype.proxyMap= null;
/**
* @ignore
* The map used by the Model to store multiton instances
*
* @protected
* @static
* @type Array
*/
Model.instanceMap= [];
/**
* @ignore
* The Models multiton key.
*
* @protected
* @type string
*/
Model.prototype.multitonKey;
/**
* @ignore
* Message Constants
*
* @static
* @type {string}
*/
Model.MULTITON_MSG= "Model instance for this Multiton key already constructed!";
/**
* @author PureMVC JS Native Port by David Foley, Frédéric Saunier, & Alain Duchesneau
* @author Copyright(c) 2006-2012 Futurescale, Inc., Some rights reserved.
*
* @class puremvc.Controller
*
* In PureMVC, the Controller class follows the 'Command and Controller'
* strategy, and assumes these responsibilities:
*
* - Remembering which
* {@link puremvc.SimpleCommand SimpleCommand}s
* or
* {@link puremvc.MacroCommand MacroCommand}s
* are intended to handle which
* {@link puremvc.Notification Notification}s
* - Registering itself as an
* {@link puremvc.Observer Observer} with
* the {@link puremvc.View View} for each
* {@link puremvc.Notification Notification}
* that it has an
* {@link puremvc.SimpleCommand SimpleCommand}
* or {@link puremvc.MacroCommand MacroCommand}
* mapping for.
* - Creating a new instance of the proper
* {@link puremvc.SimpleCommand SimpleCommand}s
* or
* {@link puremvc.MacroCommand MacroCommand}s
* to handle a given
* {@link puremvc.Notification Notification}
* when notified by the
* {@link puremvc.View View}.
* - Calling the command's execute method, passing in the
* {@link puremvc.Notification Notification}.
*
* Your application must register
* {@link puremvc.SimpleCommand SimpleCommand}s
* or {@link puremvc.MacroCommand MacroCommand}s
* with the Controller.
*
* The simplest way is to subclass
* {@link puremvc.Facade Facade},
* and use its
* {@link puremvc.Facade#initializeController initializeController}
* method to add your registrations.
*
* @constructor
* This Controller implementation is a Multiton, so you should not call the
* constructor directly, but instead call the static #getInstance factory method,
* passing the unique key for this instance to it.
* @param {string} key
* @throws {Error}
* If instance for this Multiton key has already been constructed
*/
function Controller(key)
{
if(Controller.instanceMap[key] != null)
{
throw new Error(Controller.MULTITON_MSG);
}
this.multitonKey= key;
Controller.instanceMap[this.multitonKey]= this;
this.commandMap= new Array();
this.initializeController();
}
/**
* @protected
*
* Initialize the multiton Controller instance.
*
* Called automatically by the constructor.
*
* Note that if you are using a subclass of View
* in your application, you should *also* subclass Controller
* and override the initializeController method in the
* following way.
*
* MyController.prototype.initializeController= function ()
* {
* this.view= MyView.getInstance(this.multitonKey);
* };
*
* @return {void}
*/
Controller.prototype.initializeController= function()
{
this.view= View.getInstance(this.multitonKey);
};
/**
* The Controllers multiton factory method.
* Note that this method will return null if supplied a null
* or undefined multiton key.
*
* @param {string} key
* A Controller's multiton key
* @return {puremvc.Controller}
* the Multiton instance of Controller
*/
Controller.getInstance= function(key)
{
if (null == key)
return null;
if(null == this.instanceMap[key])
{
this.instanceMap[key]= new this(key);
}
return this.instanceMap[key];
};
/**
* If a SimpleCommand or MacroCommand has previously been registered to handle
* the given Notification then it is executed.
*
* @param {puremvc.Notification} note
* @return {void}
*/
Controller.prototype.executeCommand= function(note)
{
var commandClassRef= this.commandMap[note.getName()];
if(commandClassRef == null)
return;
var commandInstance= new commandClassRef();
commandInstance.initializeNotifier(this.multitonKey);
commandInstance.execute(note);
};
/**
* Register a particular SimpleCommand or MacroCommand class as the handler for
* a particular Notification.
*
* If an command already been registered to handle Notifications with this name,
* it is no longer used, the new command is used instead.
*
* The Observer for the new command is only created if this the irst time a
* command has been regisered for this Notification name.
*
* @param {string} notificationName
* the name of the Notification
* @param {Function} commandClassRef
* a command constructor
* @return {void}
*/
Controller.prototype.registerCommand= function(notificationName, commandClassRef)
{
if(this.commandMap[notificationName] == null)
{
this.view.registerObserver(notificationName, new Observer(this.executeCommand, this));
}
this.commandMap[notificationName]= commandClassRef;
};
/**
* Check if a command is registered for a given Notification
*
* @param {string} notificationName
* @return {boolean}
* whether a Command is currently registered for the given notificationName.
*/
Controller.prototype.hasCommand= function(notificationName)
{
return this.commandMap[notificationName] != null;
};
/**
* Remove a previously registered command to
* {@link puremvc.Notification Notification}
* mapping.
*
* @param {string} notificationName
* the name of the Notification to remove the command mapping for
* @return {void}
*/
Controller.prototype.removeCommand= function(notificationName)
{
if(this.hasCommand(notificationName))
{
this.view.removeObserver(notificationName, this);
this.commandMap[notificationName]= null;
}
};
/**
* @static
* Remove a Controller instance.
*
* @param {string} key
* multitonKey of Controller instance to remove
* @return {void}
*/
Controller.removeController= function(key)
{
delete this.instanceMap[key];
};
/**
* Local reference to the Controller's View
*
* @protected
* @type {puremvc.View}
*/
Controller.prototype.view= null;
/**
* Note name to command constructor mappings
*
* @protected
* @type {Object}
*/
Controller.prototype.commandMap= null;
/**
* The Controller's multiton key
*
* @protected
* @type {string}
*/
Controller.prototype.multitonKey= null;
/**
* Multiton key to Controller instance mappings
*
* @static
* @protected
* @type {Object}
*/
Controller.instanceMap= [];
/**
* @ignore
*
* Message constants
* @static
* @protected
* @type {string}
*/
Controller.MULTITON_MSG= "controller key for this Multiton key already constructed"
/*
* @author PureMVC JS Native Port by David Foley, Frédéric Saunier, & Alain Duchesneau
* @author Copyright(c) 2006-2012 Futurescale, Inc., Some rights reserved.
*
* @hide
* A an internal helper class used to assist classlet implementation. This
* class is not accessible by client code.
*/
var OopHelp=
{
/*
* @private
* A reference to the global scope. We use this rather than window
* in order to support both browser based and non browser baed
* JavaScript interpreters.
* @type {Object}
*/
global: (function(){return this})()
/*
* @private
* Extend one Function's prototype by another, emulating classic
* inheritance.
*
* @param {Function} child
* The Function to extend (subclass)
*
* @param {Function} parent
* The Function to extend from (superclass)
*
* @return {Function}
*
* A reference to the extended Function (subclass)
*/
, extend: function (child, parent)
{
if ('function' !== typeof child)
throw new TypeError('#extend- child should be Function');
if ('function' !== typeof parent)
throw new TypeError('#extend- parent should be Function');
if (parent === child)
return;
var Transitive= new Function;
Transitive.prototype= parent.prototype;
child.prototype= new Transitive;
return child.prototype.constructor= child;
}
/*
* @private
* Decoarate one object with the properties of another.
*
* @param {Object} object
* The object to decorate.
*
* @param {Object} traits
* The object providing the properites that the first object
* will be decorated with. Note that only properties defined on
* this object will be copied- i.e. inherited properties will
* be ignored.
*
* @return {Object}
* THe decorated object (first argument)
*/
, decorate: function (object, traits)
{
for (var accessor in traits)
{
object[accessor]= traits[accessor];
}
return object;
}
};
/**
* @member puremvc
*
* Declare a namespace and optionally make an Object the referent
* of that namespace.
*
* console.assert(null == window.tld, 'No tld namespace');
* // declare the tld namespace
* puremvc.declare('tld');
* console.assert('object' === typeof tld, 'The tld namespace was declared');
*
* // the method returns a reference to last namespace node in a created hierarchy
* var reference= puremvc.declare('tld.domain.app');
* console.assert(reference === tld.domain.app)
*
* // of course you can also declare your own objects as well
* var AppConstants=
* {
* APP_NAME: 'tld.domain.app.App'
* };
*
* puremvc.declare('tld.domain.app.AppConstants', AppConstants);
* console.assert(AppConstants === tld.domain.app.AppConstants
* , 'AppConstants was exported to the namespace');
*
* Note that you can also #declare within a closure. That way you
* can selectively export Objects to your own namespaces without
* leaking variables into the global scope.
*
* (function(){
* // this var is not accessible outside of this
* // closures call scope
* var hiddenValue= 'defaultValue';
*
* // export an object that references the hidden
* // variable and which can mutate it
* puremvc.declare
* (
* 'tld.domain.app.backdoor'
*
* , {
* setValue: function (value)
* {
* // assigns to the hidden var
* hiddenValue= value;
* }
*
* , getValue: function ()
* {
* // reads from the hidden var
* return hiddenValue;
* }
* }
* );
* })();
* // indirectly retrieve the hidden variables value
* console.assert('defaultValue' === tld.domain.app.backdoor.getValue());
* // indirectly set the hidden variables value
* tld.domain.app.backdoor.setValue('newValue');
* // the hidden var was mutated
* console.assert('newValue' === tld.domain.app.backdoor.getValue());
*
* On occasion, primarily during testing, you may want to use declare,
* but not have the global object be the namespace root. In these cases you
* can supply the optional third scope argument.
*
* var localScope= {}
* , object= {}
*
* puremvc.declare('mock.object', object, localScope);
*
* console.assert(null == window.mock, 'mock namespace is not in global scope');
* console.assert(object === localScope.mock.object, 'mock.object is available in localScope');
*
* @param {string} string
* A qualified object name, e.g. 'com.example.Class'
*
* @param {Object} [object]
* An object to make the referent of the namespace.
*
* @param {Object} [scope]
* The namespace's root node. If not supplied, the global
* scope will be namespaces root node.
*
* @return {Object}
*
* A reference to the last node of the Object hierarchy created.
*/
function declare (qualifiedName, object, scope)
{
var nodes= qualifiedName.split('.')
, node= scope || OopHelp.global
, lastNode
, newNode
, nodeName;
for (var i= 0, n= nodes.length; i < n; i++)
{
lastNode= node;
nodeName= nodes[i];
node= (null == node[nodeName] ? node[nodeName] = {} : node[nodeName]);
}
if (null == object)
return node;
return lastNode[nodeName]= object;
};
/**
* @member puremvc
*
* Define a new classlet. Current editions of JavaScript do not have classes,
* but they can be emulated, and this method does this for you, saving you
* from having to work with Function prototype directly. The method does
* not extend any Native objects and is entirely opt in. Its particularly
* usefull if you want to make your PureMvc applications more portable, by
* decoupling them from a specific OOP abstraction library.
*
*
* puremvc.define
* (
* // the first object supplied is a class descriptor. None of these
* // properties are added to your class, the exception being the
* // constructor property, which if supplied, will be your classes
* // constructor.
* {
* // your classes namespace- if supplied, it will be
* // created for you
* name: 'com.example.UserMediator'
*
* // your classes parent class. If supplied, inheritance
* // will be taken care of for you
* , parent: puremvc.Mediator
*
* // your classes constructor. If not supplied, one will be
* // created for you
* , constructor: function UserMediator (component)
* {
* puremvc.Mediator.call(this, this.constructor.NAME, component);
* }
* }
*
* // the second object supplied defines your class traits, that is
* // the properties that will be defined on your classes prototype
* // and thereby on all instances of this class
* , {
* businessMethod: function ()
* {
* // impl
* }
* }
*
* // the third object supplied defines your classes 'static' traits
* // that is, the methods and properties which will be defined on
* // your classes constructor
* , {
* NAME: 'userMediator'
* }
* );
*
* @param {Object} [classinfo]
* An object describing the class. This object can have any or all of
* the following properties:
*
* - name: String
* The classlets name. This can be any arbitrary qualified object
* name. 'com.example.Classlet' or simply 'MyClasslet' for example
* The method will automatically create an object hierarchy refering
* to your class for you. Note that you will need to capture the
* methods return value to retrieve a reference to your class if the
* class name property is not defined.
* - parent: Function
* The classlets 'superclass'. Your class will be extended from this
* if supplied.
*
* - constructor: Function
* The classlets constructor. Note this is *not* a post construct
* initialize method, but your classes constructor Function.
* If this attribute is not defined, a constructor will be created for
* you automatically. If you have supplied a parent class
* value and not defined the classes constructor, the automatically
* created constructor will invoke the super class constructor
* automatically. If you have supplied your own constructor and you
* wish to invoke it's super constructor, you must do this manually, as
* there is no reference to the classes parent added to the constructor
* prototype.
*
* - scope: Object.
* For use in advanced scenarios. If the name attribute has been supplied,
* this value will be the root of the object hierarchy created for you.
* Use it do define your own class hierarchies in private scopes,
* accross iFrames, in your unit tests, or avoid collision with third
* party library namespaces.
*
* @param {Object} [traits]
* An Object, the properties of which will be added to the
* class constructors prototype.
*
* @param {Object} [staitcTraits]
* An Object, the properties of which will be added directly
* to this class constructor
*
* @return {Function}
* A reference to the classlets constructor
*/
function define (classInfo, traits, staticTraits)
{
if (!classInfo)
{
classInfo= {}
}
var className= classInfo.name
, classParent= classInfo.parent
, doExtend= 'function' === typeof classParent
, classConstructor
, classScope= classInfo.scope || null
, prototype
if ('parent' in classInfo && !doExtend)
{
throw new TypeError('Class parent must be Function');
}
if (classInfo.hasOwnProperty('constructor'))
{
classConstructor= classInfo.constructor
if ('function' !== typeof classConstructor)
{
throw new TypeError('Class constructor must be Function')
}
}
else // there is no constructor, create one
{
if (doExtend) // ensure to call the super constructor
{
classConstructor= function ()
{
classParent.apply(this, arguments);
}
}
else // just create a Function
{
classConstructor= new Function;
}
}
if (doExtend)
{
OopHelp.extend(classConstructor, classParent);
}
if (traits)
{
prototype= classConstructor.prototype
OopHelp.decorate(prototype, traits);
// reassign constructor
prototype.constructor= classConstructor;
}
if (staticTraits)
{
OopHelp.decorate(classConstructor, staticTraits)
}
if (className)
{
if ('string' !== typeof className)
{
throw new TypeError('Class name must be primitive string');
}
declare (className, classConstructor, classScope);
}
return classConstructor;
};
/* implementation end */
// define the puremvc global namespace and export the actors
scope.puremvc=
{
View: View
, Model: Model
, Controller: Controller
, SimpleCommand: SimpleCommand
, MacroCommand: MacroCommand
, Facade: Facade
, Mediator: Mediator
, Observer: Observer
, Notification: Notification
, Notifier: Notifier
, Proxy: Proxy
, define: define
, declare: declare
};
})(this); // the 'this' parameter will resolve to global scope in all environments
html,
body {
margin: 0;
padding: 0;
}
button {
margin: 0;
padding: 0;
border: 0;
background: none;
font-size: 100%;
vertical-align: baseline;
font-family: inherit;
color: inherit;
-webkit-appearance: none;
/*-moz-appearance: none;*/
-ms-appearance: none;
-o-appearance: none;
appearance: none;
}
body {
font: 14px 'Helvetica Neue', Helvetica, Arial, sans-serif;
line-height: 1.4em;
background: #eaeaea url('bg.png');
color: #4d4d4d;
width: 550px;
margin: 0 auto;
-webkit-font-smoothing: antialiased;
-moz-font-smoothing: antialiased;
-ms-font-smoothing: antialiased;
-o-font-smoothing: antialiased;
font-smoothing: antialiased;
}
#todoapp {
background: #fff;
background: rgba(255, 255, 255, 0.9);
margin: 130px 0 40px 0;
border: 1px solid #ccc;
position: relative;
border-top-left-radius: 2px;
border-top-right-radius: 2px;
box-shadow: 0 2px 6px 0 rgba(0, 0, 0, 0.2),
0 25px 50px 0 rgba(0, 0, 0, 0.15);
}
#todoapp:before {
content: '';
border-left: 1px solid #f5d6d6;
border-right: 1px solid #f5d6d6;
width: 2px;
position: absolute;
top: 0;
left: 40px;
height: 100%;
}
#todoapp input::-webkit-input-placeholder {
font-style: italic;
}
#todoapp input:-moz-placeholder {
font-style: italic;
color: #a9a9a9;
}
#todoapp h1 {
position: absolute;
top: -120px;
width: 100%;
font-size: 70px;
font-weight: bold;
text-align: center;
color: #b3b3b3;
color: rgba(255, 255, 255, 0.3);
text-shadow: -1px -1px rgba(0, 0, 0, 0.2);
-webkit-text-rendering: optimizeLegibility;
-moz-text-rendering: optimizeLegibility;
-ms-text-rendering: optimizeLegibility;
-o-text-rendering: optimizeLegibility;
text-rendering: optimizeLegibility;
}
#header {
padding-top: 15px;
border-radius: inherit;
}
#header:before {
content: '';
position: absolute;
top: 0;
right: 0;
left: 0;
height: 15px;
z-index: 2;
border-bottom: 1px solid #6c615c;
background: #8d7d77;
background: -webkit-gradient(linear, left top, left bottom, from(rgba(132, 110, 100, 0.8)),to(rgba(101, 84, 76, 0.8)));
background: -webkit-linear-gradient(top, rgba(132, 110, 100, 0.8), rgba(101, 84, 76, 0.8));
background: -moz-linear-gradient(top, rgba(132, 110, 100, 0.8), rgba(101, 84, 76, 0.8));
background: -o-linear-gradient(top, rgba(132, 110, 100, 0.8), rgba(101, 84, 76, 0.8));
background: -ms-linear-gradient(top, rgba(132, 110, 100, 0.8), rgba(101, 84, 76, 0.8));
background: linear-gradient(top, rgba(132, 110, 100, 0.8), rgba(101, 84, 76, 0.8));
filter: progid:DXImageTransform.Microsoft.gradient(GradientType=0,StartColorStr='#9d8b83', EndColorStr='#847670');
border-top-left-radius: 1px;
border-top-right-radius: 1px;
}
#new-todo,
.edit {
position: relative;
margin: 0;
width: 100%;
font-size: 24px;
font-family: inherit;
line-height: 1.4em;
border: 0;
outline: none;
color: inherit;
padding: 6px;
border: 1px solid #999;
box-shadow: inset 0 -1px 5px 0 rgba(0, 0, 0, 0.2);
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
-ms-box-sizing: border-box;
-o-box-sizing: border-box;
box-sizing: border-box;
-webkit-font-smoothing: antialiased;
-moz-font-smoothing: antialiased;
-ms-font-smoothing: antialiased;
-o-font-smoothing: antialiased;
font-smoothing: antialiased;
}
#new-todo {
padding: 16px 16px 16px 60px;
border: none;
background: rgba(0, 0, 0, 0.02);
z-index: 2;
box-shadow: none;
}
#main {
position: relative;
z-index: 2;
border-top: 1px dotted #adadad;
}
label[for='toggle-all'] {
display: none;
}
#toggle-all {
position: absolute;
top: -42px;
left: -4px;
width: 40px;
text-align: center;
border: none; /* Mobile Safari */
}
#toggle-all:before {
content: '»';
font-size: 28px;
color: #d9d9d9;
padding: 0 25px 7px;
}
#toggle-all:checked:before {
color: #737373;
}
#todo-list {
margin: 0;
padding: 0;
list-style: none;
}
#todo-list li {
position: relative;
font-size: 24px;
border-bottom: 1px dotted #ccc;
}
#todo-list li:last-child {
border-bottom: none;
}
#todo-list li.editing {
border-bottom: none;
padding: 0;
}
#todo-list li.editing .edit {
display: block;
width: 506px;
padding: 13px 17px 12px 17px;
margin: 0 0 0 43px;
}
#todo-list li.editing .view {
display: none;
}
#todo-list li .toggle {
text-align: center;
width: 40px;
/* auto, since non-WebKit browsers doesn't support input styling */
height: auto;
position: absolute;
top: 0;
bottom: 0;
margin: auto 0;
border: none; /* Mobile Safari */
-webkit-appearance: none;
/*-moz-appearance: none;*/
-ms-appearance: none;
-o-appearance: none;
appearance: none;
}
#todo-list li .toggle:after {
content: '✔';
line-height: 43px; /* 40 + a couple of pixels visual adjustment */
font-size: 20px;
color: #d9d9d9;
text-shadow: 0 -1px 0 #bfbfbf;
}
#todo-list li .toggle:checked:after {
color: #85ada7;
text-shadow: 0 1px 0 #669991;
bottom: 1px;
position: relative;
}
#todo-list li label {
word-break: break-word;
padding: 15px;
margin-left: 45px;
display: block;
line-height: 1.2;
-webkit-transition: color 0.4s;
-moz-transition: color 0.4s;
-ms-transition: color 0.4s;
-o-transition: color 0.4s;
transition: color 0.4s;
}
#todo-list li.completed label {
color: #a9a9a9;
text-decoration: line-through;
}
#todo-list li .destroy {
display: none;
position: absolute;
top: 0;
right: 10px;
bottom: 0;
width: 40px;
height: 40px;
margin: auto 0;
font-size: 22px;
color: #a88a8a;
-webkit-transition: all 0.2s;
-moz-transition: all 0.2s;
-ms-transition: all 0.2s;
-o-transition: all 0.2s;
transition: all 0.2s;
}
#todo-list li .destroy:hover {
text-shadow: 0 0 1px #000,
0 0 10px rgba(199, 107, 107, 0.8);
-webkit-transform: scale(1.3);
-moz-transform: scale(1.3);
-ms-transform: scale(1.3);
-o-transform: scale(1.3);
transform: scale(1.3);
}
#todo-list li .destroy:after {
content: '✖';
}
#todo-list li:hover .destroy {
display: block;
}
#todo-list li .edit {
display: none;
}
#todo-list li.editing:last-child {
margin-bottom: -1px;
}
#footer {
color: #777;
padding: 0 15px;
position: absolute;
right: 0;
bottom: -31px;
left: 0;
height: 20px;
z-index: 1;
text-align: center;
}
#footer:before {
content: '';
position: absolute;
right: 0;
bottom: 31px;
left: 0;
height: 50px;
z-index: -1;
box-shadow: 0 1px 1px rgba(0, 0, 0, 0.3),
0 6px 0 -3px rgba(255, 255, 255, 0.8),
0 7px 1px -3px rgba(0, 0, 0, 0.3),
0 43px 0 -6px rgba(255, 255, 255, 0.8),
0 44px 2px -6px rgba(0, 0, 0, 0.2);
}
#todo-count {
float: left;
text-align: left;
}
#filters {
margin: 0;
padding: 0;
list-style: none;
position: absolute;
right: 0;
left: 0;
}
#filters li {
display: inline;
}
#filters li a {
color: #83756f;
margin: 2px;
text-decoration: none;
}
#filters li a.selected {
font-weight: bold;
}
#clear-completed {
float: right;
position: relative;
line-height: 20px;
text-decoration: none;
background: rgba(0, 0, 0, 0.1);
font-size: 11px;
padding: 0 10px;
border-radius: 3px;
box-shadow: 0 -1px 0 0 rgba(0, 0, 0, 0.2);
}
#clear-completed:hover {
background: rgba(0, 0, 0, 0.15);
box-shadow: 0 -1px 0 0 rgba(0, 0, 0, 0.3);
}
#info {
margin: 65px auto 0;
color: #a6a6a6;
font-size: 12px;
text-shadow: 0 1px 0 rgba(255, 255, 255, 0.7);
text-align: center;
}
#info a {
color: inherit;
}
/*
Hack to remove background from Mobile Safari.
Can't use it globally since it destroys checkboxes in Firefox and Opera
*/
@media screen and (-webkit-min-device-pixel-ratio:0) {
#toggle-all,
#todo-list li .toggle {
background: none;
}
#todo-list li .toggle {
height: 40px;
}
#toggle-all {
top: -56px;
left: -15px;
width: 65px;
height: 41px;
-webkit-transform: rotate(90deg);
transform: rotate(90deg);
-webkit-appearance: none;
appearance: none;
}
}
.hidden{
display:none;
}
(function () {
'use strict';
if (location.hostname === 'todomvc.com') {
window._gaq = [['_setAccount','UA-31081062-1'],['_trackPageview']];(function(d,t){var g=d.createElement(t),s=d.getElementsByTagName(t)[0];g.src='//www.google-analytics.com/ga.js';s.parentNode.insertBefore(g,s)}(document,'script'));
}
function getSourcePath() {
// If accessed via addyosmani.github.com/todomvc/, strip the project
// path.
if (location.hostname.indexOf('github.com') > 0) {
return location.pathname.replace(/todomvc\//, '');
}
return location.pathname;
}
function appendSourceLink() {
var sourceLink = document.createElement('a');
var paragraph = document.createElement('p');
var footer = document.getElementById('info');
var urlBase = 'https://github.com/addyosmani/todomvc/tree/gh-pages';
if (footer) {
sourceLink.href = urlBase + getSourcePath();
sourceLink.appendChild(document.createTextNode('Check out the source'));
paragraph.appendChild(sourceLink);
footer.appendChild(paragraph);
}
}
function redirect() {
if (location.hostname === 'addyosmani.github.com') {
location.href = location.href.replace('addyosmani.github.com/todomvc',
'todomvc.com');
}
}
appendSourceLink();
redirect();
})();
...@@ -4,10 +4,7 @@ ...@@ -4,10 +4,7 @@
<meta charset="utf-8"> <meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"> <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<title>PureMVC • TodoMVC</title> <title>PureMVC • TodoMVC</title>
<link rel="stylesheet" href="../../../assets/base.css"> <link rel="stylesheet" href="components/todomvc-common/base.css">
<!--[if IE]>
<script src="assets/ie.js"></script>
<![endif]-->
</head> </head>
<body> <body>
<section id="todoapp"> <section id="todoapp">
...@@ -44,13 +41,13 @@ ...@@ -44,13 +41,13 @@
</footer> </footer>
<!-- TODOMVC PROJECT BASE --> <!-- TODOMVC PROJECT BASE -->
<script src="../../../assets/base.js"></script> <script src="components/todomvc-common/base.js"></script>
<!-- FLATIRION DIRECTOR ROUTING LIBRARY --> <!-- FLATIRION DIRECTOR ROUTING LIBRARY -->
<script src="../../../assets/director.min.js"></script> <script src="components/director/director.js"></script>
<!-- PUREMVC LIBRARY --> <!-- PUREMVC LIBRARY -->
<script src="js/lib/puremvc.min.js"></script> <script src="components/puremvc/puremvc-1.0.1.js"></script>
<!-- APPLICATION CONSTANTS --> <!-- APPLICATION CONSTANTS -->
<script src="js/AppConstants.js"></script> <script src="js/AppConstants.js"></script>
......
...@@ -194,7 +194,7 @@ puremvc.define({ ...@@ -194,7 +194,7 @@ puremvc.define({
li.appendChild( divDisplay ); li.appendChild( divDisplay );
li.appendChild( inputEditTodo ); li.appendChild( inputEditTodo );
if ( todo.completed ) { if ( todo.completed ) {
li.className += 'complete'; li.className += 'completed';
checkbox.checked = true; checkbox.checked = true;
} }
this.todoList.appendChild( li ); this.todoList.appendChild( li );
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment