update livereload.js

This commit is contained in:
John Bintz 2011-11-29 14:00:55 -05:00
parent 1e884ba174
commit e1d0ada7d6
1 changed files with 848 additions and 726 deletions

View File

@ -1,10 +1,9 @@
(function() { (function() {
var __customevents = {}, __protocol = {}, __connector = {}, __timer = {}, __options = {}, __reloader = {}, __livereload = {}, __startup = {}; var __customevents = {}, __protocol = {}, __connector = {}, __timer = {}, __options = {}, __reloader = {}, __livereload = {}, __less = {}, __startup = {};
// customevents // customevents
(function() { var CustomEvents;
var CustomEvents; CustomEvents = {
CustomEvents = {
bind: function(element, eventName, handler) { bind: function(element, eventName, handler) {
if (element.addEventListener) { if (element.addEventListener) {
return element.addEventListener(eventName, handler, false); return element.addEventListener(eventName, handler, false);
@ -33,29 +32,27 @@ var __customevents = {}, __protocol = {}, __connector = {}, __timer = {}, __opti
throw new Error("Attempt to fire custom event " + eventName + " on something which isn't a DOMElement"); throw new Error("Attempt to fire custom event " + eventName + " on something which isn't a DOMElement");
} }
} }
}; };
__customevents.bind = CustomEvents.bind; __customevents.bind = CustomEvents.bind;
__customevents.fire = CustomEvents.fire; __customevents.fire = CustomEvents.fire;
}).call(this);
// protocol // protocol
(function() { var PROTOCOL_6, PROTOCOL_7, Parser, ProtocolError;
var PROTOCOL_6, PROTOCOL_7, Parser, ProtocolError; var __indexOf = Array.prototype.indexOf || function(item) {
var __indexOf = Array.prototype.indexOf || function(item) {
for (var i = 0, l = this.length; i < l; i++) { for (var i = 0, l = this.length; i < l; i++) {
if (this[i] === item) return i; if (this[i] === item) return i;
} }
return -1; return -1;
}; };
__protocol.PROTOCOL_6 = PROTOCOL_6 = 'http://livereload.com/protocols/official-6'; __protocol.PROTOCOL_6 = PROTOCOL_6 = 'http://livereload.com/protocols/official-6';
__protocol.PROTOCOL_7 = PROTOCOL_7 = 'http://livereload.com/protocols/official-7'; __protocol.PROTOCOL_7 = PROTOCOL_7 = 'http://livereload.com/protocols/official-7';
__protocol.ProtocolError = ProtocolError = (function() { __protocol.ProtocolError = ProtocolError = (function() {
function ProtocolError(reason, data) { function ProtocolError(reason, data) {
this.message = "LiveReload protocol error (" + reason + ") after receiving data: \"" + data + "\"."; this.message = "LiveReload protocol error (" + reason + ") after receiving data: \"" + data + "\".";
} }
return ProtocolError; return ProtocolError;
})(); })();
__protocol.Parser = Parser = (function() { __protocol.Parser = Parser = (function() {
function Parser(handlers) { function Parser(handlers) {
this.handlers = handlers; this.handlers = handlers;
this.reset(); this.reset();
@ -123,15 +120,14 @@ var __customevents = {}, __protocol = {}, __connector = {}, __timer = {}, __opti
return message; return message;
}; };
return Parser; return Parser;
})(); })();
}).call(this);
// connector // connector
(function() { var Connector, PROTOCOL_6, PROTOCOL_7, Parser, Version, _ref;
var Connector, PROTOCOL_6, PROTOCOL_7, Parser, _ref; var __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; };
var __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }; _ref = __protocol, Parser = _ref.Parser, PROTOCOL_6 = _ref.PROTOCOL_6, PROTOCOL_7 = _ref.PROTOCOL_7;
_ref = __protocol, Parser = _ref.Parser, PROTOCOL_6 = _ref.PROTOCOL_6, PROTOCOL_7 = _ref.PROTOCOL_7; Version = '2.0.3';
__connector.Connector = Connector = (function() { __connector.Connector = Connector = (function() {
function Connector(options, WebSocket, Timer, handlers) { function Connector(options, WebSocket, Timer, handlers) {
this.options = options; this.options = options;
this.WebSocket = WebSocket; this.WebSocket = WebSocket;
@ -140,8 +136,10 @@ var __customevents = {}, __protocol = {}, __connector = {}, __timer = {}, __opti
this._uri = "ws://" + this.options.host + ":" + this.options.port + "/livereload"; this._uri = "ws://" + this.options.host + ":" + this.options.port + "/livereload";
this._nextDelay = this.options.mindelay; this._nextDelay = this.options.mindelay;
this._connectionDesired = false; this._connectionDesired = false;
this.protocol = 0;
this.protocolParser = new Parser({ this.protocolParser = new Parser({
connected: __bind(function(protocol) { connected: __bind(function(protocol) {
this.protocol = protocol;
this._handshakeTimeout.stop(); this._handshakeTimeout.stop();
this._nextDelay = this.options.mindelay; this._nextDelay = this.options.mindelay;
this._disconnectionReason = 'broken'; this._disconnectionReason = 'broken';
@ -231,15 +229,28 @@ var __customevents = {}, __protocol = {}, __connector = {}, __timer = {}, __opti
return this.socket.close(); return this.socket.close();
}; };
Connector.prototype._onopen = function(e) { Connector.prototype._onopen = function(e) {
var hello;
this.handlers.socketConnected(); this.handlers.socketConnected();
this._disconnectionReason = 'handshake-failed'; this._disconnectionReason = 'handshake-failed';
this._sendCommand({ hello = {
command: 'hello', command: 'hello',
protocols: [PROTOCOL_6, PROTOCOL_7] protocols: [PROTOCOL_6, PROTOCOL_7]
}); };
hello.ver = Version;
if (this.options.ext) {
hello.ext = this.options.ext;
}
if (this.options.extver) {
hello.extver = this.options.extver;
}
if (this.options.snipver) {
hello.snipver = this.options.snipver;
}
this._sendCommand(hello);
return this._handshakeTimeout.start(this.options.handshake_timeout); return this._handshakeTimeout.start(this.options.handshake_timeout);
}; };
Connector.prototype._onclose = function(e) { Connector.prototype._onclose = function(e) {
this.protocol = 0;
this.handlers.disconnected(this._disconnectionReason, this._nextDelay); this.handlers.disconnected(this._disconnectionReason, this._nextDelay);
return this._scheduleReconnection(); return this._scheduleReconnection();
}; };
@ -248,14 +259,12 @@ var __customevents = {}, __protocol = {}, __connector = {}, __timer = {}, __opti
return this.protocolParser.process(e.data); return this.protocolParser.process(e.data);
}; };
return Connector; return Connector;
})(); })();
}).call(this);
// timer // timer
(function() { var Timer;
var Timer; var __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; };
var __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }; __timer.Timer = Timer = (function() {
__timer.Timer = Timer = (function() {
function Timer(func) { function Timer(func) {
this.func = func; this.func = func;
this.running = false; this.running = false;
@ -281,16 +290,14 @@ var __customevents = {}, __protocol = {}, __connector = {}, __timer = {}, __opti
} }
}; };
return Timer; return Timer;
})(); })();
Timer.start = function(timeout, func) { Timer.start = function(timeout, func) {
return setTimeout(func, timeout); return setTimeout(func, timeout);
}; };
}).call(this);
// options // options
(function() { var Options;
var Options; __options.Options = Options = (function() {
__options.Options = Options = (function() {
function Options() { function Options() {
this.host = null; this.host = null;
this.port = 35729; this.port = 35729;
@ -312,8 +319,8 @@ var __customevents = {}, __protocol = {}, __connector = {}, __timer = {}, __opti
} }
}; };
return Options; return Options;
})(); })();
Options.extract = function(document) { Options.extract = function(document) {
var element, keyAndValue, m, mm, options, pair, src, _i, _j, _len, _len2, _ref, _ref2; var element, keyAndValue, m, mm, options, pair, src, _i, _j, _len, _len2, _ref, _ref2;
_ref = document.getElementsByTagName('script'); _ref = document.getElementsByTagName('script');
for (_i = 0, _len = _ref.length; _i < _len; _i++) { for (_i = 0, _len = _ref.length; _i < _len; _i++) {
@ -339,14 +346,12 @@ var __customevents = {}, __protocol = {}, __connector = {}, __timer = {}, __opti
} }
} }
return null; return null;
}; };
}).call(this);
// reloader // reloader
(function() { var IMAGE_STYLES, Reloader, numberOfMatchingSegments, pathFromUrl, pathsMatch, pickBestMatch, splitUrl;
var IMAGE_STYLES, Reloader, numberOfMatchingSegments, pathFromUrl, pathsMatch, pickBestMatch, splitUrl; var __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; };
var __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }; splitUrl = function(url) {
splitUrl = function(url) {
var hash, index, params; var hash, index, params;
if ((index = url.indexOf('#')) >= 0) { if ((index = url.indexOf('#')) >= 0) {
hash = url.slice(index); hash = url.slice(index);
@ -365,8 +370,8 @@ var __customevents = {}, __protocol = {}, __connector = {}, __timer = {}, __opti
params: params, params: params,
hash: hash hash: hash
}; };
}; };
pathFromUrl = function(url) { pathFromUrl = function(url) {
var path; var path;
url = splitUrl(url).url; url = splitUrl(url).url;
if (url.indexOf('file://') === 0) { if (url.indexOf('file://') === 0) {
@ -375,8 +380,8 @@ var __customevents = {}, __protocol = {}, __connector = {}, __timer = {}, __opti
path = url.replace(/^([^:]+:)?\/\/([^:\/]+)(:\d*)?\//, '/'); path = url.replace(/^([^:]+:)?\/\/([^:\/]+)(:\d*)?\//, '/');
} }
return decodeURIComponent(path); return decodeURIComponent(path);
}; };
pickBestMatch = function(path, objects, pathFunc) { pickBestMatch = function(path, objects, pathFunc) {
var bestMatch, object, score, _i, _len; var bestMatch, object, score, _i, _len;
bestMatch = { bestMatch = {
score: 0 score: 0
@ -396,8 +401,8 @@ var __customevents = {}, __protocol = {}, __connector = {}, __timer = {}, __opti
} else { } else {
return null; return null;
} }
}; };
numberOfMatchingSegments = function(path1, path2) { numberOfMatchingSegments = function(path1, path2) {
var comps1, comps2, eqCount, len; var comps1, comps2, eqCount, len;
path1 = path1.replace(/^\/+/, '').toLowerCase(); path1 = path1.replace(/^\/+/, '').toLowerCase();
path2 = path2.replace(/^\/+/, '').toLowerCase(); path2 = path2.replace(/^\/+/, '').toLowerCase();
@ -412,11 +417,11 @@ var __customevents = {}, __protocol = {}, __connector = {}, __timer = {}, __opti
++eqCount; ++eqCount;
} }
return eqCount; return eqCount;
}; };
pathsMatch = function(path1, path2) { pathsMatch = function(path1, path2) {
return numberOfMatchingSegments(path1, path2) > 0; return numberOfMatchingSegments(path1, path2) > 0;
}; };
IMAGE_STYLES = [ IMAGE_STYLES = [
{ {
selector: 'background', selector: 'background',
styleNames: ['backgroundImage'] styleNames: ['backgroundImage']
@ -424,8 +429,8 @@ var __customevents = {}, __protocol = {}, __connector = {}, __timer = {}, __opti
selector: 'border', selector: 'border',
styleNames: ['borderImage', 'webkitBorderImage', 'MozBorderImage'] styleNames: ['borderImage', 'webkitBorderImage', 'MozBorderImage']
} }
]; ];
__reloader.Reloader = Reloader = (function() { __reloader.Reloader = Reloader = (function() {
function Reloader(window, console, Timer) { function Reloader(window, console, Timer) {
this.window = window; this.window = window;
this.console = console; this.console = console;
@ -433,18 +438,29 @@ var __customevents = {}, __protocol = {}, __connector = {}, __timer = {}, __opti
this.document = this.window.document; this.document = this.window.document;
this.stylesheetGracePeriod = 200; this.stylesheetGracePeriod = 200;
this.importCacheWaitPeriod = 200; this.importCacheWaitPeriod = 200;
this.plugins = [];
} }
Reloader.prototype.addPlugin = function(plugin) {
return this.plugins.push(plugin);
};
Reloader.prototype.analyze = function(callback) {
return results;
};
Reloader.prototype.reload = function(path, options) { Reloader.prototype.reload = function(path, options) {
var plugin, _i, _len, _ref;
_ref = this.plugins;
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
plugin = _ref[_i];
if (plugin.reload && plugin.reload(path, options)) {
return;
}
}
if (options.liveCSS) { if (options.liveCSS) {
if (path.match(/\.css$/i)) { if (path.match(/\.css$/i)) {
if (this.reloadStylesheet(path)) { if (this.reloadStylesheet(path)) {
return; return;
} }
} }
if (path.match(/\.less$/i) && this.window.less && this.window.less.refresh) {
this.window.less.refresh(true);
return;
}
} }
if (options.liveImg) { if (options.liveImg) {
if (path.match(/\.(jpe?g|png|gif)$/i)) { if (path.match(/\.(jpe?g|png|gif)$/i)) {
@ -534,7 +550,7 @@ var __customevents = {}, __protocol = {}, __connector = {}, __timer = {}, __opti
} }
}; };
Reloader.prototype.reloadStylesheet = function(path) { Reloader.prototype.reloadStylesheet = function(path) {
var imported, link, links, match, _i, _j, _len, _len2; var imported, link, links, match, style, _i, _j, _k, _len, _len2, _len3, _ref;
links = (function() { links = (function() {
var _i, _len, _ref, _results; var _i, _len, _ref, _results;
_ref = this.document.getElementsByTagName('link'); _ref = this.document.getElementsByTagName('link');
@ -548,8 +564,15 @@ var __customevents = {}, __protocol = {}, __connector = {}, __timer = {}, __opti
return _results; return _results;
}).call(this); }).call(this);
imported = []; imported = [];
for (_i = 0, _len = links.length; _i < _len; _i++) { _ref = this.document.getElementsByTagName('style');
link = links[_i]; for (_i = 0, _len = _ref.length; _i < _len; _i++) {
style = _ref[_i];
if (style.sheet) {
this.collectImportedStylesheets(style, style.sheet, imported);
}
}
for (_j = 0, _len2 = links.length; _j < _len2; _j++) {
link = links[_j];
this.collectImportedStylesheets(link, link.sheet, imported); this.collectImportedStylesheets(link, link.sheet, imported);
} }
this.console.log("LiveReload found " + links.length + " LINKed stylesheets, " + imported.length + " @imported stylesheets"); this.console.log("LiveReload found " + links.length + " LINKed stylesheets, " + imported.length + " @imported stylesheets");
@ -566,8 +589,8 @@ var __customevents = {}, __protocol = {}, __connector = {}, __timer = {}, __opti
} }
} else { } else {
this.console.log("LiveReload will reload all stylesheets because path '" + path + "' did not match any specific one"); this.console.log("LiveReload will reload all stylesheets because path '" + path + "' did not match any specific one");
for (_j = 0, _len2 = links.length; _j < _len2; _j++) { for (_k = 0, _len3 = links.length; _k < _len3; _k++) {
link = links[_j]; link = links[_k];
this.reattachStylesheetLink(link); this.reattachStylesheetLink(link);
} }
} }
@ -679,21 +702,21 @@ var __customevents = {}, __protocol = {}, __connector = {}, __timer = {}, __opti
return url + params + hash; return url + params + hash;
}; };
return Reloader; return Reloader;
})(); })();
}).call(this);
// livereload // livereload
(function() { var Connector, LiveReload, Options, Reloader, Timer;
var Connector, LiveReload, Options, Reloader, Timer; var __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; };
var __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }; Connector = __connector.Connector;
Connector = __connector.Connector; Timer = __timer.Timer;
Timer = __timer.Timer; Options = __options.Options;
Options = __options.Options; Reloader = __reloader.Reloader;
Reloader = __reloader.Reloader; __livereload.LiveReload = LiveReload = (function() {
__livereload.LiveReload = LiveReload = (function() {
function LiveReload(window) { function LiveReload(window) {
this.window = window; this.window = window;
this.listeners = {}; this.listeners = {};
this.plugins = [];
this.pluginIdentifiers = {};
this.console = this.window.console && this.window.console.log && this.window.console.error ? this.window.console : { this.console = this.window.console && this.window.console.log && this.window.console.error ? this.window.console : {
log: function() {}, log: function() {},
error: function() {} error: function() {}
@ -715,7 +738,8 @@ var __customevents = {}, __protocol = {}, __connector = {}, __timer = {}, __opti
if (typeof (_base = this.listeners).connect === "function") { if (typeof (_base = this.listeners).connect === "function") {
_base.connect(); _base.connect();
} }
return this.log("LiveReload is connected to " + this.options.host + ":" + this.options.port + " (protocol v" + protocol + ")."); this.log("LiveReload is connected to " + this.options.host + ":" + this.options.port + " (protocol v" + protocol + ").");
return this.analyze();
}, this), }, this),
error: __bind(function(e) { error: __bind(function(e) {
if (e instanceof ProtocolError) { if (e instanceof ProtocolError) {
@ -767,7 +791,8 @@ var __customevents = {}, __protocol = {}, __connector = {}, __timer = {}, __opti
this.log("LiveReload received reload request for " + message.path + "."); this.log("LiveReload received reload request for " + message.path + ".");
return this.reloader.reload(message.path, { return this.reloader.reload(message.path, {
liveCSS: (_ref = message.liveCSS) != null ? _ref : true, liveCSS: (_ref = message.liveCSS) != null ? _ref : true,
liveImg: (_ref2 = message.liveImg) != null ? _ref2 : true liveImg: (_ref2 = message.liveImg) != null ? _ref2 : true,
originalPath: message.originalPath || ''
}); });
}; };
LiveReload.prototype.performAlert = function(message) { LiveReload.prototype.performAlert = function(message) {
@ -779,26 +804,123 @@ var __customevents = {}, __protocol = {}, __connector = {}, __timer = {}, __opti
this.log("LiveReload disconnected."); this.log("LiveReload disconnected.");
return typeof (_base = this.listeners).shutdown === "function" ? _base.shutdown() : void 0; return typeof (_base = this.listeners).shutdown === "function" ? _base.shutdown() : void 0;
}; };
LiveReload.prototype.hasPlugin = function(identifier) {
return !!this.pluginIdentifiers[identifier];
};
LiveReload.prototype.addPlugin = function(pluginClass) {
var plugin;
if (this.hasPlugin(pluginClass.identifier)) {
return;
}
this.pluginIdentifiers[pluginClass.identifier] = true;
plugin = new pluginClass(this.window, {
_livereload: this,
_reloader: this.reloader,
_connector: this.connector,
console: this.console,
Timer: Timer,
generateCacheBustUrl: __bind(function(url) {
return this.reloader.generateCacheBustUrl(url);
}, this)
});
this.plugins.push(plugin);
this.reloader.addPlugin(plugin);
};
LiveReload.prototype.analyze = function() {
var plugin, pluginData, pluginsData, _i, _len, _ref;
if (!(this.connector.protocol >= 7)) {
return;
}
pluginsData = {};
_ref = this.plugins;
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
plugin = _ref[_i];
pluginsData[plugin.constructor.identifier] = pluginData = (typeof plugin.analyze === "function" ? plugin.analyze() : void 0) || {};
pluginData.version = plugin.constructor.version;
}
this.connector.sendCommand({
command: 'info',
plugins: pluginsData,
url: this.window.location.href
});
};
return LiveReload; return LiveReload;
})();
// less
var LessPlugin;
__less = LessPlugin = (function() {
LessPlugin.identifier = 'less';
LessPlugin.version = '1.0';
function LessPlugin(window, host) {
this.window = window;
this.host = host;
}
LessPlugin.prototype.reload = function(path, options) {
if (this.window.less && this.window.less.refresh) {
if (path.match(/\.less$/i)) {
return this.reloadLess(path);
}
if (options.originalPath.match(/\.less$/i)) {
return this.reloadLess(options.originalPath);
}
}
return false;
};
LessPlugin.prototype.reloadLess = function(path) {
var link, links, _i, _len;
links = (function() {
var _i, _len, _ref, _results;
_ref = document.getElementsByTagName('link');
_results = [];
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
link = _ref[_i];
if (link.href && link.rel === 'stylesheet/less' || (link.rel.match(/stylesheet/) && link.type.match(/^text\/(x-)?less$/))) {
_results.push(link);
}
}
return _results;
})(); })();
}).call(this); if (links.length === 0) {
return false;
}
for (_i = 0, _len = links.length; _i < _len; _i++) {
link = links[_i];
link.href = this.host.generateCacheBustUrl(link.href);
}
this.host.console.log("LiveReload is asking LESS to recompile all stylesheets");
this.window.less.refresh(true);
return true;
};
LessPlugin.prototype.analyze = function() {
return {
disable: !!(this.window.less && this.window.less.refresh)
};
};
return LessPlugin;
})();
// startup // startup
(function() { var CustomEvents, LiveReload, k, v;
var CustomEvents, LiveReload; CustomEvents = __customevents;
CustomEvents = __customevents; LiveReload = window.LiveReload = new (__livereload.LiveReload)(window);
LiveReload = window.LiveReload = new (__livereload.LiveReload)(window); for (k in window) {
LiveReload.on('shutdown', function() { v = window[k];
if (k.match(/^LiveReloadPlugin/)) {
LiveReload.addPlugin(v);
}
}
LiveReload.addPlugin(__less);
LiveReload.on('shutdown', function() {
return delete window.LiveReload; return delete window.LiveReload;
}); });
LiveReload.on('connect', function() { LiveReload.on('connect', function() {
return CustomEvents.fire(document, 'LiveReloadConnect'); return CustomEvents.fire(document, 'LiveReloadConnect');
}); });
LiveReload.on('disconnect', function() { LiveReload.on('disconnect', function() {
return CustomEvents.fire(document, 'LiveReloadDisconnect'); return CustomEvents.fire(document, 'LiveReloadDisconnect');
}); });
CustomEvents.bind(document, 'LiveReloadShutDown', function() { CustomEvents.bind(document, 'LiveReloadShutDown', function() {
return LiveReload.shutDown(); return LiveReload.shutDown();
}); });
}).call(this);
})(); })();