Skip to content

Commit

Permalink
Initial entry of PureMVC JavaScript (old style) implementation.
Browse files Browse the repository at this point in the history
  • Loading branch information
guilhermeblanco committed Jan 8, 2012
1 parent f67607f commit 5192b87
Show file tree
Hide file tree
Showing 30 changed files with 3,050 additions and 0 deletions.
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Original file line Diff line number Diff line change
@@ -0,0 +1,3 @@
[submodule "tests/vendors/qunit"]
path = tests/vendors/qunit
url = https://github.com/jquery/qunit.git
129 changes: 129 additions & 0 deletions src/org/puremvc/js/Init.js
Original file line number Original file line Diff line number Diff line change
@@ -0,0 +1,129 @@
var org = {
puremvc: {
js: {
core: {},
patterns: {}
}
}
},
Relegate = {};

Object.extend = function (child, parent)
{
var tmp = function () {};

tmp.prototype = parent.prototype;

child.superClass = parent.prototype;
child.prototype = new tmp();

child.prototype.constructor = child;
};

Object.declare = function (fqcn, obj, scope)
{
var parts = fqcn.split('.'),
curPart,
curScope,
curObj;

scope = scope || window;
obj = obj || {};

curScope = scope;

while ((curPart = parts.shift()) !== undefined) {
curObj = (parts.length > 0)
? ((typeof curScope[curPart] !== 'undefined') ? curScope[curPart] : {})
: obj;

curScope[curPart] = curObj;

curScope = curScope[curPart];
}

return curScope;
};

Relegate.create = function (scope, func)
{
var ctorParams = [],
i, iLength;

for (i = 2, iLength = arguments.length; i < iLength; i += 1) {
ctorParams.push(arguments[i]);
}

return function ()
{
var funcParams = [],
j, jLength;

for (j = 0, jLength = arguments.length; j < jLength; j += 1) {
funcParams.push(arguments[j]);
}

return func.apply(scope, funcParams.concat(ctorParams));
};
};

Date.fromISO8601 = function (str)
{
var regexp = /(\d\d\d\d)(-)?(\d\d)(-)?(\d\d)(T)?(\d\d)(:)?(\d\d)(:)?(\d\d)(\.\d+)?(Z|([+-])(\d\d)(:)?(\d\d))/,
date = new Date(),
offset,
match;

if ( ! str.toString().match(new RegExp(regexp))) {
date.setTime(Date.parse(str));

return date;
}

match = str.match(new RegExp(regexp));
offset = 0;

date.setUTCDate(1);
date.setUTCFullYear(parseInt(match[1],10));
date.setUTCMonth(parseInt(match[3],10) - 1);
date.setUTCDate(parseInt(match[5],10));
date.setUTCHours(parseInt(match[7],10));
date.setUTCMinutes(parseInt(match[9],10));
date.setUTCSeconds(parseInt(match[11],10));
date.setUTCMilliseconds((match[12]) ? parseFloat(match[12]) * 1000 : 0);

if (match[13] != 'Z') {
offset = (match[15] * 60) + parseInt(match[17],10);
offset *= ((match[14] == '-') ? -1 : 1);

date.setTime(date.getTime() - offset * 60 * 1000);
}

return date;
};

Object.declare('org.puremvc.js.Init', function (d, path) {
var lastPathChar = path.substr(path.length - 1),
scriptOpenTag = '<script type="text/javascript" src="',
scriptCloseTag = '"></script>',
puremvcPath = ((lastPathChar === '/' || lastPathChar === '\\') ? path : path + '/'),
puremvcFiles = [
'org/puremvc/js/patterns/observer/Notifier.js',
'org/puremvc/js/patterns/observer/Notification.js',
'org/puremvc/js/patterns/observer/Observer.js',
'org/puremvc/js/patterns/command/SimpleCommand.js',
'org/puremvc/js/patterns/command/MacroCommand.js',
'org/puremvc/js/patterns/mediator/Mediator.js',
'org/puremvc/js/patterns/proxy/Proxy.js',
'org/puremvc/js/patterns/facade/Facade.js',
'org/puremvc/js/core/Model.js',
'org/puremvc/js/core/View.js',
'org/puremvc/js/core/Controller.js',
],
filesLength = puremvcFiles.length,
i;

for (i = 0; i < filesLength; i = i + 1) {
d.write(scriptOpenTag + puremvcPath + puremvcFiles[i] + scriptCloseTag);
}
});
207 changes: 207 additions & 0 deletions src/org/puremvc/js/core/Controller.js
Original file line number Original file line Diff line number Diff line change
@@ -0,0 +1,207 @@
/**
* A Singleton <code>Controller</code> implementation.
*
* <P>
* In PureMVC, the <code>Controller</code> class follows the 'Command and Controller' strategy, and assumes
* these responsibilities:
*
* <UL>
* <LI>
* Remembering which <code>Command</code>s are intended to handle which <code>Notifications</code>.
* </LI>
*
* <LI>
* Registering itself as an <code>Observer</code> with the <code>View</code> for each
* <code>Notification</code> that it has an <code>Command</code> mapping for.
* </LI>
*
* <LI>
* Creating a new instance of the proper <code>Command</code> to handle a given <code>Notification</code>
* when notified by the <code>View</code>.
* </LI>
*
* <LI>
* Calling the <code>Command</code>'s <code>execute</code> method, passing in the <code>Notification</code>.
* </LI>
* </UL>
* </P>
*
* <P>
* Your application must register <code>Command</code>s with the Controller.
* </P>
*
* <P>
* The simplest way is to subclass <code>Facade</code>, and use its <code>_initializeController</code> method
* to add your registrations.
* </P>
*
* @see org.puremvc.js.core.View
* @see org.puremvc.js.patterns.observer.Observer
* @see org.puremvc.js.patterns.observer.Notification
* @see org.puremvc.js.patterns.command.SimpleCommand
* @see org.puremvc.js.patterns.command.MacroCommand
*/
Object.declare('org.puremvc.js.core.Controller');

/**
* Constructor.
*
* <P>
* This <code>Controller</code> implementation is a Singleton, so you should not call the constructor
* directly, but instead call the static Singleton Factory method <code>Controller.getInstance()</code>
* </P>
*
* @throws Error Error if Singleton instance has already been constructed
*/
org.puremvc.js.core.Controller = function ()
{
if (org.puremvc.js.core.Controller.instance !== null) {
throw new Error(org.puremvc.js.core.Controller.SINGLETON_MESSAGE);
}

org.puremvc.js.core.Controller.instance = this;

this._commandMap = {};

this._initializeController();
};

// Singleton instance
org.puremvc.js.core.Controller.instance = null;

// Contant messages
org.puremvc.js.core.Controller.SINGLETON_MESSAGE = 'Controller Singleton already constructed!';

/**
* <code>Controller</code> Singleton Factory method.
*
* @return Controller the Singleton instance of <code>Controller</code>
*/
org.puremvc.js.core.Controller.getInstance = function ()
{
if (org.puremvc.js.core.Controller.instance === null) {
org.puremvc.js.core.Controller.instance = new org.puremvc.js.core.Controller();
}

return org.puremvc.js.core.Controller.instance;
};

var _p = org.puremvc.js.core.Controller.prototype;

// Mapping of Notification names to Command Class references
_p._commandMap = null;

// Local reference to View
_p._view = null;

/**
* Initialize the Singleton <code>Controller</code> instance.
*
* <P>Called automatically by the constructor.</P>
*
* <P>Note that if you are using a subclass of <code>View</code>
* in your application, you should <i>also</i> subclass <code>Controller</code>
* and override the <code>_initializeController</code> method in the
* following way:</P>
*
* <listing>
* // ensure that the Controller is talking to my View implementation
* _p._initializeController = function ()
* {
* this._view = MyView.getInstance();
* };
* </listing>
*
* @return void
*/
_p._initializeController = function ()
{
this._view = org.puremvc.js.core.View.getInstance();
};

/**
* If an <code>Command</code> has previously been registered to handle a the given
* <code>Notification</code>, then it is executed.
*
* @param notification <code>Notification</code>
*
* @return void
*/
_p.executeCommand = function (notification)
{
var notificationName = notification.getName(),
commandClassRef,
commandInstance;

if ( ! this.hasCommand(notificationName)) {
return;
}

commandClassRef = this._commandMap[notificationName],
commandInstance = new commandClassRef();

commandInstance.execute(notification);
};

/**
* Register a particular <code>Command</code> class as the handler for a particular
* <code>Notification</code>.
*
* <P>
* If an <code>Command</code> has already been registered to handle <code>Notification</code>s
* with this name, it is no longer used, the new <code>Command</code> is used instead.
* </P>
*
* <P>
* The Observer for the new ICommand is only created if this the first time an ICommand has been
* regisered for this Notification name.
* </P>
*
* @param notificationName the name of the <code>Notification</code>
* @param commandClassRef the <code>Class</code> of the <code>Command</code>
*
* @return void
*/
_p.registerCommand = function (notificationName, commandClassRef)
{
if ( ! this.hasCommand(notificationName)) {
this._view.registerObserver(
notificationName,
new org.puremvc.js.patterns.observer.Observer(this.executeCommand, this)
);
}

this._commandMap[notificationName] = commandClassRef;
};

/**
* Check if a Command is registered for a given Notification
*
* @param notificationName
*
* @return boolean Whether a Command is currently registered for the given <code>notificationName</code>.
*/
_p.hasCommand = function (notificationName)
{
return (typeof this._commandMap[notificationName] !== 'undefined');
};

/**
* Remove a previously registered <code>Command</code> to <code>Notification</code> mapping.
*
* @param notificationName The name of the <code>Notification</code> to remove the <code>Command</code> mapping for.
*
* @return void
*/
_p.removeCommand = function (notificationName)
{
// If the Command is registered...
if (this.hasCommand(notificationName)) {
// Remove the observer
this._view.removeObserver(notificationName, this);

// Remove the command
this._commandMap[notificationName] = null;
delete this._commandMap[notificationName];
}
};
Loading

0 comments on commit 5192b87

Please sign in to comment.