V5.js | |
|---|---|
V5.js 0.2.0
http://html5ify.com
(c) 2011-2013 Jackson Tian
V5 may be freely distributed under the MIT license
|
(function (global) { |
|
The Framework's top object. all components will be register under it. |
var V5 = global.V5 = new EventProxy(); |
|
默认选项 |
V5.options = { |
|
Debug mode. If debug is true, don't cache anything |
debug: false, |
|
资源版本,如果服务端静态资源有更改,修改它可以用于客户端静态资源的更新 如果debug模式开启,静态资源将会每次更新 |
version: '', |
|
Assets resources path prefix |
prefix: '' }; |
Card定义 |
|
|
卡片页定义,每个卡片页具有声明周期,在初始化、收缩、重打开、销毁时分别调用。 |
var Card = function (module) { |
|
The Initialize method. |
this.initialize = function () {}; |
|
The Shrink method, will be invoked when hide current card. |
this.shrink = function () {}; |
|
The Reappear method, when card reappear after shrink, this function will be invoked. |
this.reappear = function () {}; |
|
The Destroy method, should be invoked manually when necessary. |
this.destroy = function () {}; |
|
Parameters, store the parameters, for check the card whether changed. |
this.parameters = null; |
|
Flag whether enable localization. |
this.enableL10N = false; |
|
Merge the module's methods |
_.extend(this, module); }; |
|
Mixin the eventproxy's prototype |
_.extend(Card.prototype, EventProxy.prototype); |
|
Open an another card from current column or next column. |
Card.prototype.openCard = function (hash, blank) {
var effectColumn;
if (blank) {
effectColumn = this.columnIndex + 1;
} else {
effectColumn = this.columnIndex;
}
var args = hash.split("/");
var cardName = args.shift();
V5.trigger("openCard", cardName, effectColumn, args, this.viewport);
}; |
|
Open a viewport and display a card. |
Card.prototype.openViewport = function (hash) {
var args = hash.split("/");
var cardName = args.shift();
var viewport = $("").addClass("viewport");
body.append(viewport);
V5.trigger("openCard", cardName, 0, args, viewport);
}; |
|
Destroy current card and close current viewport. |
Card.prototype.closeViewport = function () {
this.destroy();
this.node.remove();
delete this.node;
this.initialized = false;
this.viewport.remove();
delete this.viewport;
}; |
|
Post message to current Card. |
Card.prototype.postMessage = function (event, data) {
return this.trigger("card:" + event, data);
}; |
|
Bind message event. |
Card.prototype.onMessage = function (event, callback) {
return this.bind("card:" + event, callback);
}; |
|
Define a card component. Card will be displayed in a view colomn. |
V5.Card = Card; |
|
Lets callback execute at a safely moment. |
V5.ready = function (callback) {
if (document.readyState === "complete") {
callback();
} else {
var ready = function () {
if (document.readyState === "complete") {
callback(); |
|
Remove the callback listener from readystatechange event. |
document.removeEventListener("readystatechange", ready);
}
}; |
|
Bind callback to readystatechange |
document.addEventListener("readystatechange", ready);
}
}; |
|
Gets the V5 mode, detects the V5 runing in which devices. |
V5.mode = window.innerWidth < 768 ? "phone" : "tablet"; |
|
Default viewport reference. Viewport could contains many view columns, it's detected by mode. |
V5.viewport = null; |
|
Startups V5 framework. |
V5.init = function (options) { |
|
更新选项设置 |
_.extend(V5.options, options);
V5.ready(function () {
V5.viewport = $("#container");
V5.setOrientation(); |
|
Disable touch move events for integrate with iScroll. |
window.addEventListener("touchmove", function (e) {e.preventDefault(); }, false); |
|
Use popstate to handle history go/back. |
window.addEventListener('popstate', function (event) {
var params = event.state;
if (params) {
var args = params.split("/");
var currentHash = args.shift();
console.log("Hash Changed: " + currentHash);
if (V5.hashHistory.length) {
console.log(V5.hashHistory);
if (currentHash !== undefined) {
var topHash = _.map(V5.hashMap, function (val, key) {
return _.last(val);
});
if (_.include(topHash, params)) {
console.log("changed, but no action.");
} else {
var hashStack = _.compact(_.map(V5.hashMap, function (val, key) {
return _.include(val, currentHash) ? key : null;
}));
console.log(hashStack);
V5.hashMap[hashStack[0]].pop();
V5.trigger("openCard", currentHash, V5.columns.indexOf(hashStack[0]));
console.log("Forward or back");
}
}
}
}
}, false);
|
|
Handle refresh case or first visit. if (V5.hashHistory.length === 0) { var map = V5.hashMap; if (_.size(map)) { Restore view from session. console.log("Restore from session."); V5.restoreViews(); } else { Init card. |
console.log("Init card.");
V5.initCard(); |
|
} } |
}); }; |
|
全局body对象 |
var body = $("body"); |
|
Handle orient change events. |
V5.setOrientation = function () {
var _setOrientation = function () {
var orient = Math.abs(window.orientation) === 90 ? 'landscape' : 'portrait';
var aspect = orient === 'landscape' ? 'portrait' : 'landscape';
body.removeClass(aspect).addClass(orient);
};
_setOrientation();
window.addEventListener('orientationchange', _setOrientation, false);
}; |
|
Cache the card html. |
V5._cardCache = {}; |
|
Predefined view columns. |
V5.columns = ["alpha", "beta", "gamma"]; |
|
Predefined viewport's state. |
V5.columnModes = ["single", "double", "triple"];
V5.bind("openCard", function (cardName, effectColumn, args, viewport) {
if (V5.mode === "phone") {
effectColumn = 0;
}
args = args || [];
viewport = viewport || V5.viewport;
V5.displayCard(cardName, effectColumn, args, viewport);
var hash = [cardName].concat(args).join("/");
history.pushState(hash, cardName, "#" + hash);
}); |
|
Initializes views when first time visit. |
V5.initCard = function () {
V5.trigger("openCard", "index", 0);
}; |
|
Restores views from session storage. |
V5.restoreViews = function () {
var map = V5.hashMap;
console.log(map);
_.each(map, function (viewNames, columnName) {
var hash = viewNames.pop();
var args = hash.split("/");
V5.trigger("openCard", args.shift(), _.indexOf(V5.columns, columnName), args, V5.viewport);
});
}; |
|
Gets Card from cache or server. If the card file comes from server, |
V5.getCard = function (cardName, enableL10N, callback) {
var _cardCache = V5._cardCache;
var card = V5._cards[cardName];
var proxy = new EventProxy();
proxy.all("l10n", "card", function (l10n, card) {
var html = l10n ? V5.localize(card, l10n) : card;
card.resources = l10n;
callback($(html));
});
if (_cardCache[cardName]) {
proxy.trigger("card", _cardCache[cardName]);
} else {
var url = V5.prefix + "cards/" + cardName + ".html?_=";
url += V5.options.debug ? new Date().getTime() : V5.options.version;
$.get(url, function (text) { |
|
Save into cache. |
_cardCache[cardName] = text;
proxy.trigger("card", _cardCache[cardName]);
});
}
|
|
Fetch the localize resources. |
if (card.enableL10N) {
V5.fetchL10N(cardName, function () {
proxy.trigger("l10n", V5.L10N[V5.langCode][cardName]);
});
} else {
proxy.trigger("l10n", null);
}
}; |
|
Display card in view column. |
V5.displayCard = function (hash, effectColumn, args, viewport) {
var columnName = V5.columns[effectColumn];
var column = viewport.find("." + columnName);
if (column.size() < 1) {
column = $(" |
History |
|
|
History implementation. Stores history actions. |
V5.hashHistory = []; |
|
Store hash and keep in session storage. |
V5.hashMap = (function () {
var session = getStorage("session");
var hashMap = session.get("hashMap");
if (!hashMap) {
hashMap = {};
} else {
session.remove("hashMap");
} |
|
Save hash state into session storeage when unload page |
$(window).bind("unload", function () {
session.put("hashMap", V5.hashMap);
});
return hashMap;
}()); |
View |
|
var View = function (el) {
this.el = $(el);
};
_.extend(View.prototype, EventProxy.prototype); |
|
|
Cached regex to split keys for |
var eventSplitter = /^(\S+)\s*(.*)$/;
View.prototype.method = function (eventName) {
var that = this;
return function () {
that.emit.apply(that, [eventName].concat([].slice.call(arguments, 0)));
};
};
View.prototype.$ = function (selector) {
return this.el.find(selector);
};
|
|
Set callbacks, where |
|
{"event selector": "callback"}
{
'mousedown .title': 'edit',
'click .button': 'save'
}
pairs. Callbacks will be bound to the view, with |
View.prototype.delegateEvents = function (events) {
if (!(events || (events = this.events))) {
return;
}
if (_.isFunction(events)) {
events = events.call(this);
}
var that = this;
this.el.unbind('.delegateEvents');
for (var key in events) {
var match = key.match(eventSplitter);
var eventName = match[1], selector = match[2];
var method = that.method(events[key]);
eventName += '.delegateEvents';
if (selector === '') {
this.el.bind(eventName, method);
} else {
this.el.delegate(selector, eventName, method);
}
}
}; |
|
undelegate all events |
View.prototype.undelegateEvents = function () {
$(this.el).unbind();
}; |
|
A factory method to generate View object. Packaged on Backbone.View. |
V5.View = function (el) {
return new View(el);
};
|
|
Card defined |
|
|
Card namespace. All card module will be stored at here. |
V5._cards = {}; |
|
Register a card to V5. |
V5.registerCard = function (name, module) {
if (typeof module === "function") {
V5._cards[name] = new V5.Card(module());
}
}; |
Common Module |
V5._modules = {}; |
|
Register a common module. |
V5.registerModule = function (moduleId, module) {
V5._modules[moduleId] = module;
}; |
|
Call a common module. |
V5.Card.prototype.invoke = function (moduleId) {
var module = V5._modules[moduleId];
if (module) {
var args = [].slice.call(arguments, 1);
module.apply(this, args);
} else {
throw new Error(moduleId + " Module doesn't exist");
}
}; |
Localization |
|
|
Local code. |
V5.langCode = "en-US"; |
|
All localization resources will be stored at here by locale code. |
V5.L10N = {}; |
|
Gets localization resources by card name. |
V5.fetchL10N = function (cardName, callback) {
var code = V5.langCode;
var url = V5.options.prefix + "languages/" + cardName + "_" + code + ".lang?_=";
url += V5.options.debug ? new Date().getTime() : V5.options.version;
$.getJSON(url, function (data) { |
|
Sets l10n resources to V5.L10N |
V5.L10N[code] = V5.L10N[code] || {};
_.extend(V5.L10N[code], data);
callback(V5.L10N[code]);
});
}; |
|
A wrapper method to localize template with the resources |
V5.localize = function (tpl, resources) {
var settings = {
interpolate : /\{\{(.+?)\}\}/g
};
return _.template(tpl, resources, settings);
}; |
Message mechanism |
|
|
V5 message mechanism. |
V5.postMessage = function (hash, event, data) {
var card = V5._cards[hash];
if (card) {
card.postMessage(event, data);
}
}; |
Model |
|
|
V5 model layer. |
V5.Model = new Scape(); }(window)); |