Commit 4b0fde0c authored by Sindre Sorhus's avatar Sindre Sorhus

Minify JS and some cleap

parent bf17b6e5
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -28,4 +28,4 @@ d.isBrowser=G)if(x=v.head=document.getElementsByTagName("head")[0],y=document.ge
null,a=c.getAttribute("data-requirecontext"),h=c.getAttribute("data-requiremodule"),t[a].completeLoad(h),c.detachEvent&&!da?c.detachEvent("onreadystatechange",d.onScriptLoad):c.removeEventListener("load",d.onScriptLoad,!1)};d.attach=function(a,c,h,k,j,n){var o;if(G)return k=k||d.onScriptLoad,o=c&&c.config&&c.config.xhtml?document.createElementNS("http://www.w3.org/1999/xhtml","html:script"):document.createElement("script"),o.type=j||"text/javascript",o.charset="utf-8",o.async=!v.skipAsync[a],c&&o.setAttribute("data-requirecontext",
c.contextName),o.setAttribute("data-requiremodule",h),o.attachEvent&&!da?(O=!0,n?o.onreadystatechange=function(){if(o.readyState==="loaded")o.onreadystatechange=null,o.attachEvent("onreadystatechange",k),n(o)}:o.attachEvent("onreadystatechange",k)):o.addEventListener("load",k,!1),o.src=a,n||d.addScriptToDom(o),o;else ca&&(importScripts(a),c.completeLoad(h));return null};if(G){u=document.getElementsByTagName("script");for(H=u.length-1;H>-1&&(z=u[H]);H--){if(!x)x=z.parentNode;if(A=z.getAttribute("data-main")){if(!r.baseUrl)u=
A.split("/"),z=u.pop(),u=u.length?u.join("/")+"/":"./",r.baseUrl=u,A=z.replace(aa,"");r.deps=r.deps?r.deps.concat(A):[A];break}}}d.checkReadyState=function(){var a=v.contexts,c;for(c in a)if(!(c in K)&&a[c].waitCount)return;d.resourcesReady(!0)};d.resourcesReady=function(a){var c,h;d.resourcesDone=a;if(d.resourcesDone)for(h in a=v.contexts,a)if(!(h in K)&&(c=a[h],c.jQueryIncremented))V(c.jQuery,!1),c.jQueryIncremented=!1};d.pageLoaded=function(){if(document.readyState!=="complete")document.readyState=
"complete"};if(G&&document.addEventListener&&!document.readyState)document.readyState="loading",window.addEventListener("load",d.pageLoaded,!1);d(r);if(d.isAsync&&typeof setTimeout!=="undefined")B=v.contexts[r.context||"_"],B.requireWait=!0,setTimeout(function(){B.requireWait=!1;B.takeGlobalQueue();B.jQueryCheck();B.scriptCount||B.resume();d.checkReadyState()},0)}})();
"complete"};if(G&&document.addEventListener&&!document.readyState)document.readyState="loading",window.addEventListener("load",d.pageLoaded,!1);d(r);if(d.isAsync&&typeof setTimeout!=="undefined")B=v.contexts[r.context||"_"],B.requireWait=!0,setTimeout(function(){B.requireWait=!1;B.takeGlobalQueue();B.jQueryCheck();B.scriptCount||B.resume();d.checkReadyState()},0)}})();
\ No newline at end of file
......@@ -8,4 +8,4 @@ function(){c.readyState===4&&b(c.responseText)};c.send(null)}:typeof process!=="
f.charAt(0)===65279&&(f=f.substring(1));for(d.append(f);(f=c.readLine())!==null;)d.append(e),d.append(f);g=String(d.toString())}finally{c.close()}b(g)});return g={version:"0.27.0",strip:function(a){if(a){var a=a.replace(n,""),b=a.match(o);b&&(a=b[1])}else a="";return a},jsEscape:function(a){return a.replace(/(['\\])/g,"\\$1").replace(/[\f]/g,"\\f").replace(/[\b]/g,"\\b").replace(/[\n]/g,"\\n").replace(/[\t]/g,"\\t").replace(/[\r]/g,"\\r")},createXhr:function(){var a,b,c;if(typeof XMLHttpRequest!==
"undefined")return new XMLHttpRequest;else for(b=0;b<3;b++){c=k[b];try{a=new ActiveXObject(c)}catch(e){}if(a){k=[c];break}}if(!a)throw Error("createXhr(): XMLHttpRequest not available");return a},get:h,parseName:function(a){var b=!1,c=a.indexOf("."),e=a.substring(0,c),a=a.substring(c+1,a.length),c=a.indexOf("!");c!==-1&&(b=a.substring(c+1,a.length),b=b==="strip",a=a.substring(0,c));return{moduleName:e,ext:a,strip:b}},xdRegExp:/^((\w+)\:)?\/\/([^\/\\]+)/,useXhr:function(a,b,c,e){var d=g.xdRegExp.exec(a),
f;if(!d)return!0;a=d[2];d=d[3];d=d.split(":");f=d[1];d=d[0];return(!a||a===b)&&(!d||d===c)&&(!f&&!d||f===e)},finishLoad:function(a,b,c,e,d){c=b?g.strip(c):c;d.isBuild&&d.inlineText&&(j[a]=c);e(c)},load:function(a,b,c,e){var d=g.parseName(a),f=d.moduleName+"."+d.ext,m=b.toUrl(f),h=e&&e.text&&e.text.useXhr||g.useXhr;!i||h(m,p,q,r)?g.get(m,function(b){g.finishLoad(a,d.strip,b,c,e)}):b([f],function(a){g.finishLoad(d.moduleName+"."+d.ext,d.strip,a,c,e)})},write:function(a,b,c){if(b in j){var e=g.jsEscape(j[b]);
c.asModule(a+"!"+b,"define(function () { return '"+e+"';});\n")}},writeFile:function(a,b,c,e,d){var b=g.parseName(b),f=b.moduleName+"."+b.ext,h=c.toUrl(b.moduleName+"."+b.ext)+".js";g.load(f,c,function(){var b=function(a){return e(h,a)};b.asModule=function(a,b){return e.asModule(a,h,b)};g.write(a,f,b,d)},d)}}})})();
c.asModule(a+"!"+b,"define(function () { return '"+e+"';});\n")}},writeFile:function(a,b,c,e,d){var b=g.parseName(b),f=b.moduleName+"."+b.ext,h=c.toUrl(b.moduleName+"."+b.ext)+".js";g.load(f,c,function(){var b=function(a){return e(h,a)};b.asModule=function(a,b){return e.asModule(a,h,b)};g.write(a,f,b,d)},d)}}})})();
\ No newline at end of file
# Batman • [TodoMVC](http://todomvc.com)
# Batman TodoMVC app
A todo app built using [Batman](http://batmanjs.org)
......
......@@ -145,7 +145,7 @@ body {
cursor: pointer;
width: 20px;
height: 20px;
background: url(../images/destroy.png) no-repeat 0 0;
background: url(destroy.png) no-repeat 0 0;
}
#todo-list li:hover .todo-destroy {
display: block;
......
......@@ -4,7 +4,7 @@
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<title>Fidel</title>
<link href="stylesheets/todos.css" rel="stylesheet">
<link href="css/app.css" rel="stylesheet">
<!--[if IE]>
<script src="../../../assets/ie.js"></script>
<![endif]-->
......@@ -27,9 +27,9 @@
<div id="credits">
<p>Created by
<br />
<a href="http://jga.me/">Greg Allen</a> (<a href="http://twitter.com/jgaui">jgaui</a>).</p>
<a href="http://jga.me/">Greg Allen</a> (<a href="http://twitter.com/jgaui">jgaui</a>)</p>
<br />
<p>Part of <a href="http://todomvc.com">TodoMVC</a>.</p>
<p>Part of <a href="http://todomvc.com">TodoMVC</a></p>
</div>
<script type="text/template" id="item-template">
<li class="todo {!= todo.done ? 'done' : '' !}" data-todoid="{!= todo.guid !}">
......@@ -61,7 +61,7 @@
</script>
<script src="../../../assets/base.js"></script>
<script src="../../../assets/jquery.min.js"></script>
<script src="vendor/fidel.js"></script>
<script src="app.js"></script>
<script src="js/lib/fidel.js"></script>
<script src="js/app.js"></script>
</body>
</html>
\ No newline at end of file
......@@ -22,7 +22,7 @@ var Todo = Fidel.Class.extend({
defaults: {
name: "empty todo...",
done: false,
order: 0
order: 0
},
init: function() {
},
......@@ -45,7 +45,7 @@ var TodoView = Fidel.ViewController.extend({
this.renderAll();
},
addOnEnter: function(e) {
if (e.keyCode == 13)
if (e.keyCode == 13)
this.add();
},
add: function() {
......@@ -103,7 +103,7 @@ var TodoView = Fidel.ViewController.extend({
},
complete: function(e) {
var complete = (e.target.value == "on");
var el = $(e.target);
el.parents('li').toggleClass('done');
var todoId = el.parents('li').attr('data-todoid');
......@@ -130,4 +130,4 @@ var TodoView = Fidel.ViewController.extend({
//app
var todos = new TodoView({ el: $("#todoapp") });
var todos = new TodoView({ el: $("#todoapp") });
\ No newline at end of file
/*!
* Fidel - A javascript controller
* v1.2.2
* https://github.com/jgallen23/fidel
* copyright JGA 2011
* MIT License
*/
!function(h,b){"undefined"!=typeof module&&module.exports?module.exports=b():"function"==typeof define&&"object"==typeof define.amd?define(b):this[h]=b()}("Fidel",function(){var h=this,b={guid:function(){return"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,function(a){var c=16*Math.random()|0;return("x"===a?c:c&3|8).toString(16)}).toUpperCase()},extend:function(){throw Error("Fidel.extend is deprecated, please use Fidel.ViewController.extend");}},j=h.Fidel;b.noConflict=function(){h.Fidel=
j;return this};var i=!1,k=/xyz/.test(function(){xyz})?/\b_super\b/:/.*/;b.Class=function(){};b.Class.extend=function(a){function c(a){if(!i){if(this.defaults)for(var c in this.defaults)if("object"!==typeof a||!a[c])this[c]=this.defaults[c];if("object"===typeof a)for(var d in a)this[d]=a[d];this.guid||(this.guid=b.guid());this._initialize&&this._initialize.apply(this,arguments);this.init&&this.init.apply(this,arguments)}}var d=this.prototype;i=!0;var e=new this;i=!1;for(var f in a)e[f]="function"==
typeof a[f]&&"function"==typeof d[f]&&k.test(a[f])?function(a,c){return function(){var b=this._super;this._super=d[a];var e=c.apply(this,arguments);this._super=b;return e}}(f,a[f]):a[f];c.prototype=e;c.prototype.proxy=function(a){var c=this;return function(){if(a)return a.apply(c,arguments)}};c.constructor=c;c.extend=arguments.callee;return c};var g={};b.publish=function(a,c){for(var d=g[a],b=d?d.length:0;b--;)d[b].apply(this,c||[])};b.subscribe=function(a,c){g[a]||(g[a]=[]);g[a].push(c);return[a,
c]};b.unsubscribe=function(a){for(var c=g[a[0]],a=a[1],b=c?c.length:0;b--;)c[b]===a&&c.splice(b,1)};b.Class.prototype.on=b.Class.prototype.bind=function(a,c){return b.subscribe(this.guid+"."+a,this.proxy(c))};b.Class.prototype.emit=b.Class.prototype.trigger=function(a,c){b.publish(this.guid+"."+a,c);b.publish(a,c)};b.Class.prototype.removeListener=b.Class.prototype.unbind=function(a){b.unsubscribe(a)};!function(){var a={};b.template=function d(b,f){var g=!/\W/.test(b)?a[b]=a[b]||d(b):new Function("obj",
"var p=[],print=function(){p.push.apply(p,arguments);};with(obj){p.push('"+b.replace(/[\r\t\n]/g,"").split("{!").join("\t").replace(/((^|!})[^\t]*)'/g,"$1\r").replace(/\t=(.*?)!}/g,"',$1,'").split("\t").join("');").split("!}").join("p.push('").split("\r").join("\\'")+"');}return p.join('');");return f?g(f):g}}();var l=/^(\w+)\s*(.*)$/,m=b.Class.extend({_initialize:function(){if(!this.el)throw"el is required";this._subscribeHandles={};this.events&&this.delegateEvents();this.elements&&this.refreshElements();
this.templates&&this.loadTemplates();this.actionEvent||(this.actionEvent="click");this.subscribe&&this.bindSubscriptions();this.delegateActions();this.getDataElements()},template:b.template,delegateEvents:function(){for(var a in this.events){var c=this.events[a],b=a.match(l),e=b[1],b=b[2],c=this.proxy(this[c]);""===b?this.el.bind(e,c):this.el.delegate(b,e,c)}},delegateActions:function(){var a=this;this.el.delegate("[data-action]",this.actionEvent,function(b){var d=$(this),e=d.attr("data-action");
a[e]&&a[e].call(a,d,b)})},refreshElements:function(){for(var a in this.elements)this[a]=this.find(this.elements[a])},getDataElements:function(){for(var a=this.find("[data-element]"),b=0,d=a.length;b<d;b++){var e=a[b].getAttribute("data-element");if(!this[e]){var f=this.find('[data-element="'+e+'"]');this[e]=f}}},bindSubscriptions:function(){for(var a in this.subscribe)this._subscribeHandles[a]=b.subscribe(a,this.proxy(this[this.subscribe[a]]))},loadTemplates:function(){for(var a in this.templates)this.templates[a]=
$(this.templates[a]).html()},find:function(a){return $(a,this.el[0])},render:function(a,b,d){1==arguments.length&&(b=a,a=this.primaryTemplate);if(template=this.templates[a]){var e=this.template(template,b),d=d?$(d):this.el;d.html(e)}},destroy:function(){for(var a in this._subscribeHandles)b.unsubscribe(this._subscribeHandles[a]);this.el.undelegate("[data-action]",this.actionEvent);this.el=null}});b.ViewController=m;return b});
\ No newline at end of file
/*!
* Fidel - A javascript controller
* v1.2.2
* https://github.com/jgallen23/fidel
* copyright JGA 2011
* MIT License
*/
!function (name, definition) {
if (typeof module != 'undefined' && module.exports) module.exports = definition();
else if (typeof define == 'function' && typeof define.amd == 'object') define(definition);
else this[name] = definition();
}('Fidel', function() {
var context = this;
var Fidel = {};
Fidel.guid = function(){
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
var r = Math.random()*16|0, v = c === 'x' ? r : (r&0x3|0x8);
return v.toString(16);
}).toUpperCase();
};
Fidel.extend = function() {
throw new Error("Fidel.extend is deprecated, please use Fidel.ViewController.extend");
};
var o = context.Fidel;
Fidel.noConflict = function() {
context.Fidel = o;
return this;
};
var initializing = false, fnTest = /xyz/.test(function(){xyz;}) ? /\b_super\b/ : /.*/;
// The base Class implementation (does nothing)
Fidel.Class = function(){};
// Create a new Class that inherits from this class
Fidel.Class.extend = function(prop) {
var _super = this.prototype;
// Instantiate a base class (but only create the instance,
// don't run the init constructor)
initializing = true;
var prototype = new this();
initializing = false;
// Copy the properties over onto the new prototype
for (var name in prop) {
// Check if we're overwriting an existing function
prototype[name] = typeof prop[name] == "function" &&
typeof _super[name] == "function" && fnTest.test(prop[name]) ?
(function(name, fn){
return function() {
var tmp = this._super;
// Add a new ._super() method that is the same method
// but on the super-class
this._super = _super[name];
// The method only need to be bound temporarily, so we
// remove it when we're done executing
var ret = fn.apply(this, arguments);
this._super = tmp;
return ret;
};
})(name, prop[name]) :
prop[name];
}
// The dummy class constructor
function Class(opt) {
// All construction is actually done in the init method
if (!initializing) {
if (this.defaults) {
for (var key in this.defaults) {
if (typeof opt !== 'object' || !opt[key]) this[key] = this.defaults[key];
}
}
if (typeof opt === 'object') {
for (var okey in opt) {
this[okey] = opt[okey];
}
}
if (!this.guid) this.guid = Fidel.guid();
if (this._initialize) this._initialize.apply(this, arguments);
if (this.init) this.init.apply(this, arguments);
}
}
// Populate our constructed prototype object
Class.prototype = prototype;
Class.prototype.proxy = function(func) {
var thisObject = this;
return(function(){
if (!func) return;
return func.apply(thisObject, arguments);
});
};
// Enforce the constructor to be what we expect
Class.constructor = Class;
// And make this class extendable
Class.extend = arguments.callee;
return Class;
};
var cache = {}; //check for "c_" cache for unit testing
//publish("/some/topic", ["a","b","c"]);
Fidel.publish = function(topic, args){
var subs = cache[topic], len = subs ? subs.length : 0;
//can change loop or reverse array if the order matters
while(len--){
subs[len].apply(this, args || []);
}
};
//subscribe("/some/topic", function(a, b, c){ /* handle data */ });
Fidel.subscribe = function(topic, callback){
if(!cache[topic]){
cache[topic] = [];
}
cache[topic].push(callback);
return [topic, callback]; // Array
};
//var handle = subscribe("/some/topic", function(){});
//unsubscribe(handle);
Fidel.unsubscribe = function(handle){
var subs = cache[handle[0]],
callback = handle[1],
len = subs ? subs.length : 0;
while(len--){
if(subs[len] === callback){
subs.splice(len, 1);
}
}
};
Fidel.Class.prototype.on = Fidel.Class.prototype.bind = function(name, callback) {
return Fidel.subscribe(this.guid+"."+name, this.proxy(callback));
};
Fidel.Class.prototype.emit = Fidel.Class.prototype.trigger = function(name, data) {
Fidel.publish(this.guid+"."+name, data);
Fidel.publish(name, data);
};
Fidel.Class.prototype.removeListener = Fidel.Class.prototype.unbind = function(handle) {
Fidel.unsubscribe(handle);
};
!function() {
var templateCache = {};
Fidel.template = function tmpl(template, data) {
var fn = !/\W/.test(template) ?
templateCache[template] = templateCache[template] ||
tmpl(template) :
new Function("obj",
"var p=[],print=function(){p.push.apply(p,arguments);};" +
"with(obj){p.push('" +
template
.replace(/[\r\t\n]/g, "")
.split("{!").join("\t")
.replace(/((^|!})[^\t]*)'/g, "$1\r")
.replace(/\t=(.*?)!}/g, "',$1,'")
.split("\t").join("');")
.split("!}").join("p.push('")
.split("\r").join("\\'")
+ "');}return p.join('');");
return data ? fn( data ) : fn;
};
}();
var eventSplitter = /^(\w+)\s*(.*)$/;
var ViewController = Fidel.Class.extend({
_initialize: function(options) {
if (!this.el) throw "el is required";
this._subscribeHandles = {};
if (this.events) this.delegateEvents();
if (this.elements) this.refreshElements();
if (this.templates) this.loadTemplates();
if (!this.actionEvent) this.actionEvent = "click";
if (this.subscribe) this.bindSubscriptions();
this.delegateActions();
this.getDataElements();
},
template: Fidel.template,
delegateEvents: function() {
for (var key in this.events) {
var methodName = this.events[key];
var match = key.match(eventSplitter);
var eventName = match[1], selector = match[2];
var method = this.proxy(this[methodName]);
if (selector === '') {
this.el.bind(eventName, method);
} else {
this.el.delegate(selector, eventName, method);
}
}
},
delegateActions: function() {
var self = this;
this.el.delegate('[data-action]', this.actionEvent, function(e) {
var el = $(this);
var methodName = el.attr('data-action');
if (self[methodName]) self[methodName].call(self, el, e);
});
},
refreshElements: function() {
for (var key in this.elements) {
this[key] = this.find(this.elements[key]);
}
},
getDataElements: function() {
var self = this;
var elements = this.find("[data-element]");
for (var i = 0, c = elements.length; i < c; i++) {
var name = elements[i].getAttribute('data-element');
if (!self[name]) {
var elem = this.find('[data-element="'+name+'"]');
self[name] = elem;
}
}
},
bindSubscriptions: function() {
for (var key in this.subscribe) {
this._subscribeHandles[key] = Fidel.subscribe(key, this.proxy(this[this.subscribe[key]]));
}
},
loadTemplates: function() {
for (var name in this.templates) {
this.templates[name] = $(this.templates[name]).html();
}
},
find: function(selector) {
return $(selector, this.el[0]);
},
render: function(templateName, data, selector) {
if (arguments.length == 1) {
data = templateName;
templateName = this.primaryTemplate;
}
template = this.templates[templateName];
if (!template) return;
var tmp = this.template(template, data);
selector = (selector)?$(selector):this.el;
selector.html(tmp);
},
destroy: function() {
for (var key in this._subscribeHandles) {
Fidel.unsubscribe(this._subscribeHandles[key]);
}
this.el.undelegate('[data-action]', this.actionEvent);
this.el = null;
}
});
Fidel.ViewController = ViewController;
return Fidel;
});
This diff is collapsed.
/*
Live.js - One script closer to Designing in the Browser
Written for Handcraft.com by Martin Kool (@mrtnkl).
Version 4.
Recent change: Made stylesheet and mimetype checks case insensitive.
http://livejs.com
http://livejs.com/license (MIT)
@livejs
Include live.js#css to monitor css changes only.
Include live.js#js to monitor js changes only.
Include live.js#html to monitor html changes only.
Mix and match to monitor a preferred combination such as live.js#html,css
By default, just include live.js to monitor all css, js and html changes.
Live.js can also be loaded as a bookmarklet. It is best to only use it for CSS then,
as a page reload due to a change in html or css would not re-include the bookmarklet.
To monitor CSS and be notified that it has loaded, include it as: live.js#css,notify
*/
(function () {
var headers = { "Etag": 1, "Last-Modified": 1, "Content-Length": 1, "Content-Type": 1 },
resources = {},
pendingRequests = {},
currentLinkElements = {},
oldLinkElements = {},
interval = 1000,
loaded = false,
active = { "html": 1, "css": 1, "js": 1 };
var Live = {
// performs a cycle per interval
heartbeat: function () {
if (document.body) {
// make sure all resources are loaded on first activation
if (!loaded) Live.loadresources();
Live.checkForChanges();
}
setTimeout(Live.heartbeat, interval);
},
// loads all local css and js resources upon first activation
loadresources: function () {
// helper method to assert if a given url is local
function isLocal(url) {
var loc = document.location,
reg = new RegExp("^\\.|^\/(?!\/)|^[\\w]((?!://).)*$|" + loc.protocol + "//" + loc.host);
return url.match(reg);
}
// gather all resources
var scripts = document.getElementsByTagName("script"),
links = document.getElementsByTagName("link"),
uris = [];
// track local js urls
for (var i = 0; i < scripts.length; i++) {
var script = scripts[i], src = script.getAttribute("src");
if (src && isLocal(src))
uris.push(src);
if (src && src.match(/\blive.js#/)) {
for (var type in active)
active[type] = src.match("[#,|]" + type) != null
if (src.match("notify"))
alert("Live.js is loaded.");
}
}
if (!active.js) uris = [];
if (active.html) uris.push(document.location.href);
// track local css urls
for (var i = 0; i < links.length && active.css; i++) {
var link = links[i], rel = link.getAttribute("rel"), href = link.getAttribute("href", 2);
if (href && rel && rel.match(new RegExp("stylesheet", "i")) && isLocal(href)) {
uris.push(href);
currentLinkElements[href] = link;
}
}
// initialize the resources info
for (var i = 0; i < uris.length; i++) {
var url = uris[i];
Live.getHead(url, function (url, info) {
resources[url] = info;
});
}
// add rule for morphing between old and new css files
var head = document.getElementsByTagName("head")[0],
style = document.createElement("style"),
rule = "transition: all .3s ease-out;"
css = [".livejs-loading * { ", rule, " -webkit-", rule, "-moz-", rule, "-o-", rule, "}"].join('');
style.setAttribute("type", "text/css");
head.appendChild(style);
style.styleSheet ? style.styleSheet.cssText = css : style.appendChild(document.createTextNode(css));
// yep
loaded = true;
},
// check all tracking resources for changes
checkForChanges: function () {
for (var url in resources) {
if (pendingRequests[url])
continue;
Live.getHead(url, function (url, newInfo) {
var oldInfo = resources[url],
hasChanged = false;
resources[url] = newInfo;
for (var header in oldInfo) {
// do verification based on the header type
var oldValue = oldInfo[header],
newValue = newInfo[header],
contentType = newInfo["Content-Type"];
switch (header.toLowerCase()) {
case "etag":
if (!newValue) break;
// fall through to default
default:
hasChanged = oldValue != newValue;
break;
}
// if changed, act
if (hasChanged) {
Live.refreshResource(url, contentType);
break;
}
}
});
}
},
// act upon a changed url of certain content type
refreshResource: function (url, type) {
switch (type.toLowerCase()) {
// css files can be reloaded dynamically by replacing the link element
case "text/css":
var link = currentLinkElements[url],
html = document.body.parentNode,
head = link.parentNode,
next = link.nextSibling,
newLink = document.createElement("link");
html.className = html.className.replace(/\s*livejs\-loading/gi, '') + ' livejs-loading';
newLink.setAttribute("type", "text/css");
newLink.setAttribute("rel", "stylesheet");
newLink.setAttribute("href", url + "?now=" + new Date() * 1);
next ? head.insertBefore(newLink, next) : head.appendChild(newLink);
currentLinkElements[url] = newLink;
oldLinkElements[url] = link;
// schedule removal of the old link
Live.removeoldLinkElements();
break;
// check if an html resource is our current url, then reload
case "text/html":
if (url != document.location.href)
return;
// local javascript changes cause a reload as well
case "text/javascript":
case "application/javascript":
case "application/x-javascript":
document.location.reload();
}
},
// removes the old stylesheet rules only once the new one has finished loading
removeoldLinkElements: function () {
var pending = 0;
for (var url in oldLinkElements) {
// if this sheet has any cssRules, delete the old link
try {
var link = currentLinkElements[url],
oldLink = oldLinkElements[url],
html = document.body.parentNode,
sheet = link.sheet || link.styleSheet,
rules = sheet.rules || sheet.cssRules;
if (rules.length >= 0) {
oldLink.parentNode.removeChild(oldLink);
delete oldLinkElements[url];
setTimeout(function () {
html.className = html.className.replace(/\s*livejs\-loading/gi, '');
}, 100);
}
} catch (e) {
pending++;
}
if (pending) setTimeout(Live.removeoldLinkElements, 50);
}
},
// performs a HEAD request and passes the header info to the given callback
getHead: function (url, callback) {
pendingRequests[url] = true;
var xhr = window.XMLHttpRequest ? new XMLHttpRequest() : new ActiveXObject("Microsoft.XmlHttp");
xhr.open("HEAD", url, true);
xhr.onreadystatechange = function () {
delete pendingRequests[url];
if (xhr.readyState == 4 && xhr.status != 304) {
xhr.getAllResponseHeaders();
var info = {};
for (var h in headers) {
var value = xhr.getResponseHeader(h);
// adjust the simple Etag variant to match on its significant part
if (h.toLowerCase() == "etag" && value) value = value.replace(/^W\//, '');
if (h.toLowerCase() == "content-type" && value) value = value.replace(/^(.*?);.*?$/i, "$1");
info[h] = value;
}
callback(url, info);
}
}
xhr.send();
}
};
// start listening
if (document.location.protocol != "file:") {
if (!window.liveJsLoaded)
Live.heartbeat();
window.liveJsLoaded = true;
}
else if (window.console)
console.log("Live.js doesn't support the file protocol. It needs http.");
})();
\ No newline at end of file
// An example Backbone application contributed by
// [Jérôme Gravel-Niquet](http://jgn.me/). This demo uses a simple
// [LocalStorage adapter](backbone-localstorage.html)
// to persist Backbone models within your browser.
// Load the application once the DOM is ready, using `jQuery.ready`:
$(function(){
// Todo Model
// ----------
// Our basic **Todo** model has `content`, `order`, and `done` attributes.
window.Todo = Backbone.Model.extend({
// Default attributes for the todo.
defaults: {
content: "empty todo...",
done: false
},
// Ensure that each todo created has `content`.
initialize: function() {
if (!this.get("content")) {
this.set({"content": this.defaults.content});
}
},
// Toggle the `done` state of this todo item.
toggle: function() {
this.save({done: !this.get("done")});
},
// Remove this Todo from *localStorage* and delete its view.
clear: function() {
this.destroy();
this.view.remove();
}
});
// Todo Collection
// ---------------
// The collection of todos is backed by *localStorage* instead of a remote
// server.
window.TodoList = Backbone.Collection.extend({
// Reference to this collection's model.
model: Todo,
// Save all of the todo items under the `"todos"` namespace.
localStorage: new Store("todos"),
// Filter down the list of all todo items that are finished.
done: function() {
return this.filter(function(todo){ return todo.get('done'); });
},
// Filter down the list to only todo items that are still not finished.
remaining: function() {
return this.without.apply(this, this.done());
},
// We keep the Todos in sequential order, despite being saved by unordered
// GUID in the database. This generates the next order number for new items.
nextOrder: function() {
if (!this.length) return 1;
return this.last().get('order') + 1;
},
// Todos are sorted by their original insertion order.
comparator: function(todo) {
return todo.get('order');
}
});
// Create our global collection of **Todos**.
window.Todos = new TodoList;
// Todo Item View
// --------------
// The DOM element for a todo item...
window.TodoView = Backbone.View.extend({
//... is a list tag.
tagName: "li",
// Cache the template function for a single item.
template: _.template($('#item-template').html()),
// The DOM events specific to an item.
events: {
"click .check" : "toggleDone",
"dblclick div.todo-content" : "edit",
"click span.todo-destroy" : "clear",
"keypress .todo-input" : "updateOnEnter"
},
// The TodoView listens for changes to its model, re-rendering. Since there's
// a one-to-one correspondence between a **Todo** and a **TodoView** in this
// app, we set a direct reference on the model for convenience.
initialize: function() {
_.bindAll(this, 'render', 'close');
this.model.bind('change', this.render);
this.model.view = this;
},
// Re-render the contents of the todo item.
render: function() {
$(this.el).html(this.template(this.model.toJSON()));
this.setContent();
return this;
},
// To avoid XSS (not that it would be harmful in this particular app),
// we use `jQuery.text` to set the contents of the todo item.
setContent: function() {
var content = this.model.get('content');
this.$('.todo-content').text(content);
this.input = this.$('.todo-input');
this.input.bind('blur', this.close);
this.input.val(content);
},
// Toggle the `"done"` state of the model.
toggleDone: function() {
this.model.toggle();
},
// Switch this view into `"editing"` mode, displaying the input field.
edit: function() {
$(this.el).addClass("editing");
this.input.focus();
},
// Close the `"editing"` mode, saving changes to the todo.
close: function() {
this.model.save({content: this.input.val()});
$(this.el).removeClass("editing");
},
// If you hit `enter`, we're through editing the item.
updateOnEnter: function(e) {
if (e.keyCode == 13) this.close();
},
// Remove this view from the DOM.
remove: function() {
$(this.el).remove();
},
// Remove the item, destroy the model.
clear: function() {
this.model.clear();
}
});
// The Application
// ---------------
// Our overall **AppView** is the top-level piece of UI.
window.AppView = Backbone.View.extend({
// Instead of generating a new element, bind to the existing skeleton of
// the App already present in the HTML.
el: $("#todoapp"),
// Our template for the line of statistics at the bottom of the app.
statsTemplate: _.template($('#stats-template').html()),
// Delegated events for creating new items, and clearing completed ones.
events: {
"keypress #new-todo": "createOnEnter",
"keyup #new-todo": "showTooltip",
"click .todo-clear a": "clearCompleted"
},
// At initialization we bind to the relevant events on the `Todos`
// collection, when items are added or changed. Kick things off by
// loading any preexisting todos that might be saved in *localStorage*.
initialize: function() {
_.bindAll(this, 'addOne', 'addAll', 'render');
this.input = this.$("#new-todo");
Todos.bind('add', this.addOne);
Todos.bind('reset', this.addAll);
Todos.bind('all', this.render);
Todos.fetch();
},
// Re-rendering the App just means refreshing the statistics -- the rest
// of the app doesn't change.
render: function() {
var done = Todos.done().length;
this.$('#todo-stats').html(this.statsTemplate({
total: Todos.length,
done: Todos.done().length,
remaining: Todos.remaining().length
}));
},
// Add a single todo item to the list by creating a view for it, and
// appending its element to the `<ul>`.
addOne: function(todo) {
var view = new TodoView({model: todo});
this.$("#todo-list").append(view.render().el);
},
// Add all items in the **Todos** collection at once.
addAll: function() {
Todos.each(this.addOne);
},
// Generate the attributes for a new Todo item.
newAttributes: function() {
return {
content: this.input.val(),
order: Todos.nextOrder(),
done: false
};
},
// If you hit return in the main input field, create new **Todo** model,
// persisting it to *localStorage*.
createOnEnter: function(e) {
if (e.keyCode != 13) return;
Todos.create(this.newAttributes());
this.input.val('');
},
// Clear all done todo items, destroying their models.
clearCompleted: function() {
_.each(Todos.done(), function(todo){ todo.clear(); });
return false;
},
// Lazily show the tooltip that tells you to press `enter` to save
// a new todo item, after one second.
showTooltip: function(e) {
var tooltip = this.$(".ui-tooltip-top");
var val = this.input.val();
tooltip.fadeOut();
if (this.tooltipTimeout) clearTimeout(this.tooltipTimeout);
if (val == '' || val == this.input.attr('placeholder')) return;
var show = function(){ tooltip.show().fadeIn(); };
this.tooltipTimeout = _.delay(show, 1000);
}
});
// Finally, we kick things off by creating the **App**.
window.App = new AppView;
});
/*
* Router
* ======
*
* Very simple router using #hashes
* designed to work with o_O
*/
;(function() {
var namedParam = /:\w+/g,
splatParam = /\*\w+/g,
escapeRegExp = /[-[\]{}()+?.,\\^$|#\s]/g,
routeStripper = /^[#\/]/;
function regexRoute(str) {
str = str.replace(escapeRegExp, "\\$&")
.replace(namedParam, "([^\/]+)")
.replace(splatParam, "(.*?)")
return new RegExp('^' + str + '$')
}
o_O.router = o_O.model.extend({}, {
initialize: function() {
this.routes = []
},
add: function(param, handler) {
if(param === 404) {
this.routing_404 = {
handler: handler
}
}
else {
this.routes.push({
regex: regexRoute(param),
handler: handler
})
}
return this
},
runRouting: function(hash) {
var routes = []
for(var i = 0; i < this.routes.length; i++) {
var route = this.routes[i];
if(route.regex.test(hash))
routes.push(route)
}
for(var i = 0; i < routes.length; i++) {
var params = route.regex.exec(hash).slice(1)
this.runRoute(routes[i], params)
}
if(routes.length == 0 && this.routing_404)
this.runRoute(this.routing_404, [])
},
runRoute: function(route, params) {
if(typeof route.handler == 'string') {
params.unshift(route.handler)
this.emit.apply(this, params)
}
else
route.handler.apply(null, params)
},
getHash: function() {
var match = window.location.href.match(/#(.*)$/);
return match ? match[1] : '';
},
go: function() {
this.location = this.getHash().replace(routeStripper, '');
this.runRouting(this.location)
},
start: function() {
var self = this;
this.go()
$(window).bind('hashchange', function() {
self.go()
})
},
redirect: function(url, changeUrlHash) {
if(changeUrlHash === false)
this.runRouting(url)
else {
var hash = "#!" + url
document.location.hash == hash
? this.go()
: document.location.hash = hash
}
}
})
o_O.extend(o_O.router.prototype, o_O.Events)
}).call(this)
(function(){function d(a){a=a.replace(f,"\\$&").replace(g,"([^/]+)").replace(h,"(.*?)");return RegExp("^"+a+"$")}var g=/:\w+/g,h=/\*\w+/g,f=/[-[\]{}()+?.,\\^$|#\s]/g,i=/^[#\/]/;o_O.router=o_O.model.extend({},{initialize:function(){this.routes=[]},add:function(a,b){404===a?this.routing_404={handler:b}:this.routes.push({regex:d(a),handler:b});return this},runRouting:function(a){for(var b=[],c=0;c<this.routes.length;c++){var e=this.routes[c];e.regex.test(a)&&b.push(e)}for(c=0;c<b.length;c++){var d=e.regex.exec(a).slice(1);
this.runRoute(b[c],d)}0==b.length&&this.routing_404&&this.runRoute(this.routing_404,[])},runRoute:function(a,b){"string"==typeof a.handler?(b.unshift(a.handler),this.emit.apply(this,b)):a.handler.apply(null,b)},getHash:function(){var a=window.location.href.match(/#(.*)$/);return a?a[1]:""},go:function(){this.location=this.getHash().replace(i,"");this.runRouting(this.location)},start:function(){var a=this;this.go();$(window).bind("hashchange",function(){a.go()})},redirect:function(a,b){if(!1===b)this.runRouting(a);
else{var c="#!"+a;document.location.hash==c?this.go():document.location.hash=c}}});o_O.extend(o_O.router.prototype,o_O.Events)}).call(this);
\ No newline at end of file
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