Skip to content

Instantly share code, notes, and snippets.

@toruta39
Last active August 29, 2015 13:55
Show Gist options
  • Save toruta39/8786483 to your computer and use it in GitHub Desktop.
Save toruta39/8786483 to your computer and use it in GitHub Desktop.
Tiny MPA (Multipage Page Application) Framework
(function(global) {
function App () {
this.controllers = {};
this.modules = {};
this.router = new Router(this);
$(window).on('load', this.init.bind(this));
};
App.prototype = {
constructor: App,
init: function() {
this.router.match();
},
controller: function(id, func) {
if (this.controllers[id] !== undefined) {
throw new Error('Controller ' + id + ' already exists.');
}
this.controllers[id] = new Controller(func);
return this;
},
module: function(id, Constructor) {
if (this.modules[id] !== undefined) {
throw new Error('Module ' + id + ' already exists.');
}
this.modules[id] = new Constructor(app);
return this;
},
getController: function(id) {
if (this.controllers[id] === undefined) {
throw new Error('Controller ' + id + ' cannot be found.');
}
return this.controllers[id];
},
getModule: function(id) {
if (this.modules[id] === undefined) {
throw new Error('Module ' + id + ' cannot be found.');
}
return this.modules[id];
}
};
function Controller (func) {
this.func = func;
}
Controller.prototype = {
constructor: Controller,
exec: function(params) {
this.func.call(null, params);
}
};
function Router (app) {
this.app = app;
this.routes = [];
};
Router.prototype = {
constructor: Router,
when: function(path, opt) {
if (typeof opt.controller !== 'string') {
throw new Error('Please provide a valid controller id for "' +
path + '".');
}
opt.path = path;
this.routes.push(opt);
return this;
},
matchPath: function(path) {
var pathRegExp,
paramNames,
matches,
params = {},
currentPath = location.pathname;
// If there's a '/' in the end of path, trim it.
currentPath = currentPath.replace(/\/$/, '');
pathRegExp = path.replace(/\/$/, '')
.replace(/\/:([^?\/])+/g, '(/[^/]+)')
.replace(/\//g, '\\/');
pathRegExp = new RegExp('^' + pathRegExp + '$');
paramNames = path.match(/:([^?\/])+/g);
if (paramNames) {
for (i = 0, len = paramNames.length; i < len; i++) {
paramNames[i] = paramNames[i].substr(1);
}
}
matches = pathRegExp.exec(currentPath);
if (matches === null) {
return false;
} else {
matches.shift();
for (i = 0, len = matches.length; i < len; i++) {
if (matches[i]) {
params[paramNames[i]] = matches[i].substr(1);
}
}
return params;
}
},
match: function() {
var route,
params,
i,
len;
for (i = 0, len = this.routes.length; i < len; i++) {
route = this.routes[i];
params = this.matchPath(route.path);
if (params) {
this.app.getController(route.controller).exec(params);
break;
}
}
}
};
global.app = new App();
}).call(this, window);
(function(global, app) {
app.module('env', function() {
this.isMobile = /Android|iPhone|iPod/gi.test(navigator.userAgent);
this.isAndroid = this.isSP && /Android/gi.test(navigator.userAgent);
});
}).call(this, window, app);
(function(global, app) {
app.router.when('/videos/:appId?', {
controller: 'videoListCtrl'
});
}).call(this, window, app);
(function(global, app, $) {
app.controller('videoListCtrl', function(params) {
var env = app.getModule('env');
// Do something...
});
}).call(this, window, app, $);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment