From 0d82995d8cf1a308ccd5b620e10a85289cd14c98 Mon Sep 17 00:00:00 2001 From: John Bintz Date: Tue, 10 Jul 2012 17:50:52 -0400 Subject: [PATCH] update livereload.js --- js/livereload.js | 935 +++++++++++++++++++++++------------------ lib/rack-livereload.rb | 2 +- 2 files changed, 533 insertions(+), 404 deletions(-) diff --git a/js/livereload.js b/js/livereload.js index 3d0cb1f..edb2802 100644 --- a/js/livereload.js +++ b/js/livereload.js @@ -123,12 +123,17 @@ __protocol.Parser = Parser = (function() { })(); // connector +// Generated by CoffeeScript 1.3.3 var Connector, PROTOCOL_6, PROTOCOL_7, Parser, Version, _ref; -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; -Version = '2.0.3'; + +Version = '2.0.8'; + __connector.Connector = Connector = (function() { + function Connector(options, WebSocket, Timer, handlers) { + var _this = this; this.options = options; this.WebSocket = WebSocket; this.Timer = Timer; @@ -138,64 +143,66 @@ __connector.Connector = Connector = (function() { this._connectionDesired = false; this.protocol = 0; this.protocolParser = new Parser({ - connected: __bind(function(protocol) { - this.protocol = protocol; - this._handshakeTimeout.stop(); - this._nextDelay = this.options.mindelay; - this._disconnectionReason = 'broken'; - return this.handlers.connected(protocol); - }, this), - error: __bind(function(e) { - this.handlers.error(e); - return this._closeOnError(); - }, this), - message: __bind(function(message) { - return this.handlers.message(message); - }, this) + connected: function(protocol) { + _this.protocol = protocol; + _this._handshakeTimeout.stop(); + _this._nextDelay = _this.options.mindelay; + _this._disconnectionReason = 'broken'; + return _this.handlers.connected(protocol); + }, + error: function(e) { + _this.handlers.error(e); + return _this._closeOnError(); + }, + message: function(message) { + return _this.handlers.message(message); + } }); - this._handshakeTimeout = new Timer(__bind(function() { - if (!this._isSocketConnected()) { + this._handshakeTimeout = new Timer(function() { + if (!_this._isSocketConnected()) { return; } - this._disconnectionReason = 'handshake-timeout'; - return this.socket.close(); - }, this)); - this._reconnectTimer = new Timer(__bind(function() { - if (!this._connectionDesired) { + _this._disconnectionReason = 'handshake-timeout'; + return _this.socket.close(); + }); + this._reconnectTimer = new Timer(function() { + if (!_this._connectionDesired) { return; } - return this.connect(); - }, this)); + return _this.connect(); + }); this.connect(); } + Connector.prototype._isSocketConnected = function() { return this.socket && this.socket.readyState === this.WebSocket.OPEN; }; + Connector.prototype.connect = function() { + var _this = this; this._connectionDesired = true; if (this._isSocketConnected()) { return; } - if (this._reconnectTimer) { - clearTimeout(this._reconnectTimer); - } + this._reconnectTimer.stop(); this._disconnectionReason = 'cannot-connect'; this.protocolParser.reset(); this.handlers.connecting(); this.socket = new this.WebSocket(this._uri); - this.socket.onopen = __bind(function(e) { - return this._onopen(e); - }, this); - this.socket.onclose = __bind(function(e) { - return this._onclose(e); - }, this); - this.socket.onmessage = __bind(function(e) { - return this._onmessage(e); - }, this); - return this.socket.onerror = __bind(function(e) { - return this._onerror(e); - }, this); + this.socket.onopen = function(e) { + return _this._onopen(e); + }; + this.socket.onclose = function(e) { + return _this._onclose(e); + }; + this.socket.onmessage = function(e) { + return _this._onmessage(e); + }; + return this.socket.onerror = function(e) { + return _this._onerror(e); + }; }; + Connector.prototype.disconnect = function() { this._connectionDesired = false; this._reconnectTimer.stop(); @@ -205,6 +212,7 @@ __connector.Connector = Connector = (function() { this._disconnectionReason = 'manual'; return this.socket.close(); }; + Connector.prototype._scheduleReconnection = function() { if (!this._connectionDesired) { return; @@ -214,20 +222,24 @@ __connector.Connector = Connector = (function() { return this._nextDelay = Math.min(this.options.maxdelay, this._nextDelay * 2); } }; + Connector.prototype.sendCommand = function(command) { if (this.protocol == null) { return; } return this._sendCommand(command); }; + Connector.prototype._sendCommand = function(command) { return this.socket.send(JSON.stringify(command)); }; + Connector.prototype._closeOnError = function() { this._handshakeTimeout.stop(); this._disconnectionReason = 'error'; return this.socket.close(); }; + Connector.prototype._onopen = function(e) { var hello; this.handlers.socketConnected(); @@ -249,16 +261,21 @@ __connector.Connector = Connector = (function() { this._sendCommand(hello); return this._handshakeTimeout.start(this.options.handshake_timeout); }; + Connector.prototype._onclose = function(e) { this.protocol = 0; this.handlers.disconnected(this._disconnectionReason, this._nextDelay); return this._scheduleReconnection(); }; + Connector.prototype._onerror = function(e) {}; + Connector.prototype._onmessage = function(e) { return this.protocolParser.process(e.data); }; + return Connector; + })(); // timer @@ -349,375 +366,479 @@ Options.extract = function(document) { }; // reloader -var IMAGE_STYLES, Reloader, numberOfMatchingSegments, pathFromUrl, pathsMatch, pickBestMatch, splitUrl; -var __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }; -splitUrl = function(url) { - var hash, index, params; - if ((index = url.indexOf('#')) >= 0) { - hash = url.slice(index); - url = url.slice(0, index); - } else { - hash = ''; - } - if ((index = url.indexOf('?')) >= 0) { - params = url.slice(index); - url = url.slice(0, index); - } else { - params = ''; - } - return { - url: url, - params: params, - hash: hash - }; -}; -pathFromUrl = function(url) { - var path; - url = splitUrl(url).url; - if (url.indexOf('file://') === 0) { - path = url.replace(/^file:\/\/(localhost)?/, ''); - } else { - path = url.replace(/^([^:]+:)?\/\/([^:\/]+)(:\d*)?\//, '/'); - } - return decodeURIComponent(path); -}; -pickBestMatch = function(path, objects, pathFunc) { - var bestMatch, object, score, _i, _len; - bestMatch = { - score: 0 - }; - for (_i = 0, _len = objects.length; _i < _len; _i++) { - object = objects[_i]; - score = numberOfMatchingSegments(path, pathFunc(object)); - if (score > bestMatch.score) { - bestMatch = { - object: object, - score: score - }; +// Generated by CoffeeScript 1.3.1 +(function() { + var IMAGE_STYLES, Reloader, numberOfMatchingSegments, pathFromUrl, pathsMatch, pickBestMatch, splitUrl; + + splitUrl = function(url) { + var hash, index, params; + if ((index = url.indexOf('#')) >= 0) { + hash = url.slice(index); + url = url.slice(0, index); + } else { + hash = ''; } - } - if (bestMatch.score > 0) { - return bestMatch; - } else { - return null; - } -}; -numberOfMatchingSegments = function(path1, path2) { - var comps1, comps2, eqCount, len; - path1 = path1.replace(/^\/+/, '').toLowerCase(); - path2 = path2.replace(/^\/+/, '').toLowerCase(); - if (path1 === path2) { - return 10000; - } - comps1 = path1.split('/').reverse(); - comps2 = path2.split('/').reverse(); - len = Math.min(comps1.length, comps2.length); - eqCount = 0; - while (eqCount < len && comps1[eqCount] === comps2[eqCount]) { - ++eqCount; - } - return eqCount; -}; -pathsMatch = function(path1, path2) { - return numberOfMatchingSegments(path1, path2) > 0; -}; -IMAGE_STYLES = [ - { - selector: 'background', - styleNames: ['backgroundImage'] - }, { - selector: 'border', - styleNames: ['borderImage', 'webkitBorderImage', 'MozBorderImage'] - } -]; -__reloader.Reloader = Reloader = (function() { - function Reloader(window, console, Timer) { - this.window = window; - this.console = console; - this.Timer = Timer; - this.document = this.window.document; - this.stylesheetGracePeriod = 200; - this.importCacheWaitPeriod = 200; - this.plugins = []; - } - Reloader.prototype.addPlugin = function(plugin) { - return this.plugins.push(plugin); + if ((index = url.indexOf('?')) >= 0) { + params = url.slice(index); + url = url.slice(0, index); + } else { + params = ''; + } + return { + url: url, + params: params, + hash: hash + }; }; - Reloader.prototype.analyze = function(callback) { - return results; + + pathFromUrl = function(url) { + var path; + url = splitUrl(url).url; + if (url.indexOf('file://') === 0) { + path = url.replace(/^file:\/\/(localhost)?/, ''); + } else { + path = url.replace(/^([^:]+:)?\/\/([^:\/]+)(:\d*)?\//, '/'); + } + return decodeURIComponent(path); }; - 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; + + pickBestMatch = function(path, objects, pathFunc) { + var bestMatch, object, score, _i, _len; + bestMatch = { + score: 0 + }; + for (_i = 0, _len = objects.length; _i < _len; _i++) { + object = objects[_i]; + score = numberOfMatchingSegments(path, pathFunc(object)); + if (score > bestMatch.score) { + bestMatch = { + object: object, + score: score + }; } } - if (options.liveCSS) { - if (path.match(/\.css$/i)) { - if (this.reloadStylesheet(path)) { + if (bestMatch.score > 0) { + return bestMatch; + } else { + return null; + } + }; + + numberOfMatchingSegments = function(path1, path2) { + var comps1, comps2, eqCount, len; + path1 = path1.replace(/^\/+/, '').toLowerCase(); + path2 = path2.replace(/^\/+/, '').toLowerCase(); + if (path1 === path2) { + return 10000; + } + comps1 = path1.split('/').reverse(); + comps2 = path2.split('/').reverse(); + len = Math.min(comps1.length, comps2.length); + eqCount = 0; + while (eqCount < len && comps1[eqCount] === comps2[eqCount]) { + ++eqCount; + } + return eqCount; + }; + + pathsMatch = function(path1, path2) { + return numberOfMatchingSegments(path1, path2) > 0; + }; + + IMAGE_STYLES = [ + { + selector: 'background', + styleNames: ['backgroundImage'] + }, { + selector: 'border', + styleNames: ['borderImage', 'webkitBorderImage', 'MozBorderImage'] + } + ]; + + __reloader.Reloader = Reloader = (function() { + + Reloader.name = 'Reloader'; + + function Reloader(window, console, Timer) { + this.window = window; + this.console = console; + this.Timer = Timer; + this.document = this.window.document; + 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) { + var plugin, _base, _i, _len, _ref; + this.options = options; + if ((_base = this.options).stylesheetReloadTimeout == null) { + _base.stylesheetReloadTimeout = 15000; + } + _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.liveImg) { - if (path.match(/\.(jpe?g|png|gif)$/i)) { - this.reloadImages(path); - return; - } - } - return this.reloadPage(); - }; - Reloader.prototype.reloadPage = function() { - return this.window.document.location.reload(); - }; - Reloader.prototype.reloadImages = function(path) { - var expando, img, selector, styleNames, styleSheet, _i, _j, _k, _l, _len, _len2, _len3, _len4, _ref, _ref2, _ref3, _ref4, _results; - expando = this.generateUniqueString(); - _ref = this.document.images; - for (_i = 0, _len = _ref.length; _i < _len; _i++) { - img = _ref[_i]; - if (pathsMatch(path, pathFromUrl(img.src))) { - img.src = this.generateCacheBustUrl(img.src, expando); - } - } - if (this.document.querySelectorAll) { - for (_j = 0, _len2 = IMAGE_STYLES.length; _j < _len2; _j++) { - _ref2 = IMAGE_STYLES[_j], selector = _ref2.selector, styleNames = _ref2.styleNames; - _ref3 = this.document.querySelectorAll("[style*=" + selector + "]"); - for (_k = 0, _len3 = _ref3.length; _k < _len3; _k++) { - img = _ref3[_k]; - this.reloadStyleImages(img.style, styleNames, path, expando); + if (options.liveCSS) { + if (path.match(/\.css$/i)) { + if (this.reloadStylesheet(path)) { + return; + } } } - } - if (this.document.styleSheets) { - _ref4 = this.document.styleSheets; - _results = []; - for (_l = 0, _len4 = _ref4.length; _l < _len4; _l++) { - styleSheet = _ref4[_l]; - _results.push(this.reloadStylesheetImages(styleSheet, path, expando)); + if (options.liveImg) { + if (path.match(/\.(jpe?g|png|gif)$/i)) { + this.reloadImages(path); + return; + } } - return _results; - } - }; - Reloader.prototype.reloadStylesheetImages = function(styleSheet, path, expando) { - var rule, rules, styleNames, _i, _j, _len, _len2; - try { - rules = styleSheet != null ? styleSheet.cssRules : void 0; - } catch (e) { + return this.reloadPage(); + }; - } - if (!rules) { - return; - } - for (_i = 0, _len = rules.length; _i < _len; _i++) { - rule = rules[_i]; - switch (rule.type) { - case CSSRule.IMPORT_RULE: - this.reloadStylesheetImages(rule.styleSheet, path, expando); - break; - case CSSRule.STYLE_RULE: - for (_j = 0, _len2 = IMAGE_STYLES.length; _j < _len2; _j++) { - styleNames = IMAGE_STYLES[_j].styleNames; - this.reloadStyleImages(rule.style, styleNames, path, expando); - } - break; - case CSSRule.MEDIA_RULE: - this.reloadStylesheetImages(rule, path, expando); - } - } - }; - Reloader.prototype.reloadStyleImages = function(style, styleNames, path, expando) { - var newValue, styleName, value, _i, _len; - for (_i = 0, _len = styleNames.length; _i < _len; _i++) { - styleName = styleNames[_i]; - value = style[styleName]; - if (typeof value === 'string') { - newValue = value.replace(/\burl\s*\(([^)]*)\)/, __bind(function(match, src) { - if (pathsMatch(path, pathFromUrl(src))) { - return "url(" + (this.generateCacheBustUrl(src, expando)) + ")"; - } else { - return match; - } - }, this)); - if (newValue !== value) { - style[styleName] = newValue; - } - } - } - }; - Reloader.prototype.reloadStylesheet = function(path) { - var imported, link, links, match, style, _i, _j, _k, _len, _len2, _len3, _ref; - links = (function() { - var _i, _len, _ref, _results; - _ref = this.document.getElementsByTagName('link'); - _results = []; + Reloader.prototype.reloadPage = function() { + return this.window.document.location.reload(); + }; + + Reloader.prototype.reloadImages = function(path) { + var expando, img, selector, styleNames, styleSheet, _i, _j, _k, _l, _len, _len1, _len2, _len3, _ref, _ref1, _ref2, _ref3, _results; + expando = this.generateUniqueString(); + _ref = this.document.images; for (_i = 0, _len = _ref.length; _i < _len; _i++) { - link = _ref[_i]; - if (link.rel === 'stylesheet' && !link.__LiveReload_pendingRemoval) { - _results.push(link); + img = _ref[_i]; + if (pathsMatch(path, pathFromUrl(img.src))) { + img.src = this.generateCacheBustUrl(img.src, expando); } } - return _results; - }).call(this); - imported = []; - _ref = this.document.getElementsByTagName('style'); - for (_i = 0, _len = _ref.length; _i < _len; _i++) { - style = _ref[_i]; - if (style.sheet) { - this.collectImportedStylesheets(style, style.sheet, imported); + if (this.document.querySelectorAll) { + for (_j = 0, _len1 = IMAGE_STYLES.length; _j < _len1; _j++) { + _ref1 = IMAGE_STYLES[_j], selector = _ref1.selector, styleNames = _ref1.styleNames; + _ref2 = this.document.querySelectorAll("[style*=" + selector + "]"); + for (_k = 0, _len2 = _ref2.length; _k < _len2; _k++) { + img = _ref2[_k]; + this.reloadStyleImages(img.style, styleNames, path, expando); + } + } } - } - for (_j = 0, _len2 = links.length; _j < _len2; _j++) { - link = links[_j]; - this.collectImportedStylesheets(link, link.sheet, imported); - } - this.console.log("LiveReload found " + links.length + " LINKed stylesheets, " + imported.length + " @imported stylesheets"); - match = pickBestMatch(path, links.concat(imported), function(l) { - return pathFromUrl(l.href); - }); - if (match) { - if (match.object.rule) { - this.console.log("LiveReload is reloading imported stylesheet: " + match.object.href); - this.reattachImportedRule(match.object); - } else { - this.console.log("LiveReload is reloading stylesheet: " + match.object.href); - this.reattachStylesheetLink(match.object); + if (this.document.styleSheets) { + _ref3 = this.document.styleSheets; + _results = []; + for (_l = 0, _len3 = _ref3.length; _l < _len3; _l++) { + styleSheet = _ref3[_l]; + _results.push(this.reloadStylesheetImages(styleSheet, path, expando)); + } + return _results; } - } else { - this.console.log("LiveReload will reload all stylesheets because path '" + path + "' did not match any specific one"); - for (_k = 0, _len3 = links.length; _k < _len3; _k++) { - link = links[_k]; - this.reattachStylesheetLink(link); - } - } - return true; - }; - Reloader.prototype.collectImportedStylesheets = function(link, styleSheet, result) { - var index, rule, rules, _len; - try { - rules = styleSheet != null ? styleSheet.cssRules : void 0; - } catch (e) { + }; + + Reloader.prototype.reloadStylesheetImages = function(styleSheet, path, expando) { + var rule, rules, styleNames, _i, _j, _len, _len1; + try { + rules = styleSheet != null ? styleSheet.cssRules : void 0; + } catch (e) { - } - if (rules && rules.length) { - for (index = 0, _len = rules.length; index < _len; index++) { - rule = rules[index]; - switch (rule.type) { - case CSSRule.CHARSET_RULE: - continue; - case CSSRule.IMPORT_RULE: - result.push({ - link: link, - rule: rule, - index: index, - href: rule.href - }); - this.collectImportedStylesheets(link, rule.styleSheet, result); - break; - default: - break; - } } - } - }; - Reloader.prototype.reattachStylesheetLink = function(link) { - var clone, parent, timer; - if (link.__LiveReload_pendingRemoval) { - return; - } - link.__LiveReload_pendingRemoval = true; - clone = link.cloneNode(false); - clone.href = this.generateCacheBustUrl(link.href); - parent = link.parentNode; - if (parent.lastChild === link) { - parent.appendChild(clone); - } else { - parent.insertBefore(clone, link.nextSibling); - } - timer = new this.Timer(function() { - if (link.parentNode) { - return link.parentNode.removeChild(link); - } - }); - return timer.start(this.stylesheetGracePeriod); - }; - Reloader.prototype.reattachImportedRule = function(_arg) { - var href, index, link, media, newRule, parent, rule, tempLink; - rule = _arg.rule, index = _arg.index, link = _arg.link; - parent = rule.parentStyleSheet; - href = this.generateCacheBustUrl(rule.href); - media = rule.media.length ? [].join.call(rule.media, ', ') : ''; - newRule = "@import url(\"" + href + "\") " + media + ";"; - rule.__LiveReload_newHref = href; - tempLink = this.document.createElement("link"); - tempLink.rel = 'stylesheet'; - tempLink.href = href; - tempLink.__LiveReload_pendingRemoval = true; - if (link.parentNode) { - link.parentNode.insertBefore(tempLink, link); - } - return this.Timer.start(this.importCacheWaitPeriod, __bind(function() { - if (tempLink.parentNode) { - tempLink.parentNode.removeChild(tempLink); - } - if (rule.__LiveReload_newHref !== href) { + if (!rules) { return; } - parent.insertRule(newRule, index); - parent.deleteRule(index + 1); - rule = parent.cssRules[index]; + for (_i = 0, _len = rules.length; _i < _len; _i++) { + rule = rules[_i]; + switch (rule.type) { + case CSSRule.IMPORT_RULE: + this.reloadStylesheetImages(rule.styleSheet, path, expando); + break; + case CSSRule.STYLE_RULE: + for (_j = 0, _len1 = IMAGE_STYLES.length; _j < _len1; _j++) { + styleNames = IMAGE_STYLES[_j].styleNames; + this.reloadStyleImages(rule.style, styleNames, path, expando); + } + break; + case CSSRule.MEDIA_RULE: + this.reloadStylesheetImages(rule, path, expando); + } + } + }; + + Reloader.prototype.reloadStyleImages = function(style, styleNames, path, expando) { + var newValue, styleName, value, _i, _len, + _this = this; + for (_i = 0, _len = styleNames.length; _i < _len; _i++) { + styleName = styleNames[_i]; + value = style[styleName]; + if (typeof value === 'string') { + newValue = value.replace(/\burl\s*\(([^)]*)\)/, function(match, src) { + if (pathsMatch(path, pathFromUrl(src))) { + return "url(" + (_this.generateCacheBustUrl(src, expando)) + ")"; + } else { + return match; + } + }); + if (newValue !== value) { + style[styleName] = newValue; + } + } + } + }; + + Reloader.prototype.reloadStylesheet = function(path) { + var imported, link, links, match, style, _i, _j, _k, _l, _len, _len1, _len2, _len3, _ref, _ref1, + _this = this; + links = (function() { + var _i, _len, _ref, _results; + _ref = this.document.getElementsByTagName('link'); + _results = []; + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + link = _ref[_i]; + if (link.rel === 'stylesheet' && !link.__LiveReload_pendingRemoval) { + _results.push(link); + } + } + return _results; + }).call(this); + imported = []; + _ref = this.document.getElementsByTagName('style'); + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + style = _ref[_i]; + if (style.sheet) { + this.collectImportedStylesheets(style, style.sheet, imported); + } + } + for (_j = 0, _len1 = links.length; _j < _len1; _j++) { + link = links[_j]; + this.collectImportedStylesheets(link, link.sheet, imported); + } + if (this.window.StyleFix && this.document.querySelectorAll) { + _ref1 = this.document.querySelectorAll('style[data-href]'); + for (_k = 0, _len2 = _ref1.length; _k < _len2; _k++) { + style = _ref1[_k]; + links.push(style); + } + } + this.console.log("LiveReload found " + links.length + " LINKed stylesheets, " + imported.length + " @imported stylesheets"); + match = pickBestMatch(path, links.concat(imported), function(l) { + return pathFromUrl(_this.linkHref(l)); + }); + if (match) { + if (match.object.rule) { + this.console.log("LiveReload is reloading imported stylesheet: " + match.object.href); + this.reattachImportedRule(match.object); + } else { + this.console.log("LiveReload is reloading stylesheet: " + (this.linkHref(match.object))); + this.reattachStylesheetLink(match.object); + } + } else { + this.console.log("LiveReload will reload all stylesheets because path '" + path + "' did not match any specific one"); + for (_l = 0, _len3 = links.length; _l < _len3; _l++) { + link = links[_l]; + this.reattachStylesheetLink(link); + } + } + return true; + }; + + Reloader.prototype.collectImportedStylesheets = function(link, styleSheet, result) { + var index, rule, rules, _i, _len; + try { + rules = styleSheet != null ? styleSheet.cssRules : void 0; + } catch (e) { + + } + if (rules && rules.length) { + for (index = _i = 0, _len = rules.length; _i < _len; index = ++_i) { + rule = rules[index]; + switch (rule.type) { + case CSSRule.CHARSET_RULE: + continue; + case CSSRule.IMPORT_RULE: + result.push({ + link: link, + rule: rule, + index: index, + href: rule.href + }); + this.collectImportedStylesheets(link, rule.styleSheet, result); + break; + default: + break; + } + } + } + }; + + Reloader.prototype.waitUntilCssLoads = function(clone, func) { + var callbackExecuted, executeCallback, poll, + _this = this; + callbackExecuted = false; + executeCallback = function() { + if (callbackExecuted) { + return; + } + callbackExecuted = true; + return func(); + }; + clone.onload = function() { + console.log("onload!"); + _this.knownToSupportCssOnLoad = true; + return executeCallback(); + }; + if (!this.knownToSupportCssOnLoad) { + (poll = function() { + if (clone.sheet) { + console.log("polling!"); + return executeCallback(); + } else { + return _this.Timer.start(50, poll); + } + })(); + } + return this.Timer.start(this.options.stylesheetReloadTimeout, executeCallback); + }; + + Reloader.prototype.linkHref = function(link) { + return link.href || link.getAttribute('data-href'); + }; + + Reloader.prototype.reattachStylesheetLink = function(link) { + var clone, parent, + _this = this; + if (link.__LiveReload_pendingRemoval) { + return; + } + link.__LiveReload_pendingRemoval = true; + if (link.tagName === 'STYLE') { + clone = this.document.createElement('link'); + clone.rel = 'stylesheet'; + clone.media = link.media; + clone.disabled = link.disabled; + } else { + clone = link.cloneNode(false); + } + clone.href = this.generateCacheBustUrl(this.linkHref(link)); + parent = link.parentNode; + if (parent.lastChild === link) { + parent.appendChild(clone); + } else { + parent.insertBefore(clone, link.nextSibling); + } + return this.waitUntilCssLoads(clone, function() { + var additionalWaitingTime; + if (/AppleWebKit/.test(navigator.userAgent)) { + additionalWaitingTime = 5; + } else { + additionalWaitingTime = 200; + } + return _this.Timer.start(additionalWaitingTime, function() { + var _ref; + if (!link.parentNode) { + return; + } + link.parentNode.removeChild(link); + clone.onreadystatechange = null; + return (_ref = _this.window.StyleFix) != null ? _ref.link(clone) : void 0; + }); + }); + }; + + Reloader.prototype.reattachImportedRule = function(_arg) { + var href, index, link, media, newRule, parent, rule, tempLink, + _this = this; + rule = _arg.rule, index = _arg.index, link = _arg.link; + parent = rule.parentStyleSheet; + href = this.generateCacheBustUrl(rule.href); + media = rule.media.length ? [].join.call(rule.media, ', ') : ''; + newRule = "@import url(\"" + href + "\") " + media + ";"; rule.__LiveReload_newHref = href; - return this.Timer.start(this.importCacheWaitPeriod, __bind(function() { + tempLink = this.document.createElement("link"); + tempLink.rel = 'stylesheet'; + tempLink.href = href; + tempLink.__LiveReload_pendingRemoval = true; + if (link.parentNode) { + link.parentNode.insertBefore(tempLink, link); + } + return this.Timer.start(this.importCacheWaitPeriod, function() { + if (tempLink.parentNode) { + tempLink.parentNode.removeChild(tempLink); + } if (rule.__LiveReload_newHref !== href) { return; } parent.insertRule(newRule, index); - return parent.deleteRule(index + 1); - }, this)); - }, this)); - }; - Reloader.prototype.generateUniqueString = function() { - return 'livereload=' + Date.now(); - }; - Reloader.prototype.generateCacheBustUrl = function(url, expando) { - var hash, oldParams, params, _ref; - if (expando == null) { - expando = this.generateUniqueString(); - } - _ref = splitUrl(url), url = _ref.url, hash = _ref.hash, oldParams = _ref.params; - params = oldParams.replace(/(\?|&)livereload=(\d+)/, function(match, sep) { - return "" + sep + expando; - }); - if (params === oldParams) { - if (oldParams.length === 0) { - params = "?" + expando; - } else { - params = "" + oldParams + "&" + expando; + parent.deleteRule(index + 1); + rule = parent.cssRules[index]; + rule.__LiveReload_newHref = href; + return _this.Timer.start(_this.importCacheWaitPeriod, function() { + if (rule.__LiveReload_newHref !== href) { + return; + } + parent.insertRule(newRule, index); + return parent.deleteRule(index + 1); + }); + }); + }; + + Reloader.prototype.generateUniqueString = function() { + return 'livereload=' + Date.now(); + }; + + Reloader.prototype.generateCacheBustUrl = function(url, expando) { + var hash, oldParams, params, _ref; + if (expando == null) { + expando = this.generateUniqueString(); } - } - return url + params + hash; - }; - return Reloader; -})(); + _ref = splitUrl(url), url = _ref.url, hash = _ref.hash, oldParams = _ref.params; + if (this.options.overrideURL) { + if (url.indexOf(this.options.serverURL) < 0) { + url = this.options.serverURL + this.options.overrideURL + "?url=" + encodeURIComponent(url); + } + } + params = oldParams.replace(/(\?|&)livereload=(\d+)/, function(match, sep) { + return "" + sep + expando; + }); + if (params === oldParams) { + if (oldParams.length === 0) { + params = "?" + expando; + } else { + params = "" + oldParams + "&" + expando; + } + } + return url + params + hash; + }; + + return Reloader; + + })(); + +}).call(this); // livereload var Connector, LiveReload, Options, Reloader, Timer; -var __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }; + Connector = __connector.Connector; + Timer = __timer.Timer; + Options = __options.Options; + Reloader = __reloader.Reloader; + __livereload.LiveReload = LiveReload = (function() { + function LiveReload(window) { + var _this = this; this.window = window; 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.location.href.match(/LR-verbose/) && this.window.console && this.window.console.log && this.window.console.error ? this.window.console : { log: function() {}, error: function() {} }; @@ -731,87 +852,95 @@ __livereload.LiveReload = LiveReload = (function() { } this.reloader = new Reloader(this.window, this.console, Timer); this.connector = new Connector(this.options, this.WebSocket, Timer, { - connecting: __bind(function() {}, this), - socketConnected: __bind(function() {}, this), - connected: __bind(function(protocol) { + connecting: function() {}, + socketConnected: function() {}, + connected: function(protocol) { var _base; - if (typeof (_base = this.listeners).connect === "function") { + if (typeof (_base = _this.listeners).connect === "function") { _base.connect(); } - this.log("LiveReload is connected to " + this.options.host + ":" + this.options.port + " (protocol v" + protocol + ")."); - return this.analyze(); - }, this), - error: __bind(function(e) { + _this.log("LiveReload is connected to " + _this.options.host + ":" + _this.options.port + " (protocol v" + protocol + ")."); + return _this.analyze(); + }, + error: function(e) { if (e instanceof ProtocolError) { return console.log("" + e.message + "."); } else { return console.log("LiveReload internal error: " + e.message); } - }, this), - disconnected: __bind(function(reason, nextDelay) { + }, + disconnected: function(reason, nextDelay) { var _base; - if (typeof (_base = this.listeners).disconnect === "function") { + if (typeof (_base = _this.listeners).disconnect === "function") { _base.disconnect(); } switch (reason) { case 'cannot-connect': - return this.log("LiveReload cannot connect to " + this.options.host + ":" + this.options.port + ", will retry in " + nextDelay + " sec."); + return _this.log("LiveReload cannot connect to " + _this.options.host + ":" + _this.options.port + ", will retry in " + nextDelay + " sec."); case 'broken': - return this.log("LiveReload disconnected from " + this.options.host + ":" + this.options.port + ", reconnecting in " + nextDelay + " sec."); + return _this.log("LiveReload disconnected from " + _this.options.host + ":" + _this.options.port + ", reconnecting in " + nextDelay + " sec."); case 'handshake-timeout': - return this.log("LiveReload cannot connect to " + this.options.host + ":" + this.options.port + " (handshake timeout), will retry in " + nextDelay + " sec."); + return _this.log("LiveReload cannot connect to " + _this.options.host + ":" + _this.options.port + " (handshake timeout), will retry in " + nextDelay + " sec."); case 'handshake-failed': - return this.log("LiveReload cannot connect to " + this.options.host + ":" + this.options.port + " (handshake failed), will retry in " + nextDelay + " sec."); + return _this.log("LiveReload cannot connect to " + _this.options.host + ":" + _this.options.port + " (handshake failed), will retry in " + nextDelay + " sec."); case 'manual': break; case 'error': break; default: - return this.log("LiveReload disconnected from " + this.options.host + ":" + this.options.port + " (" + reason + "), reconnecting in " + nextDelay + " sec."); + return _this.log("LiveReload disconnected from " + _this.options.host + ":" + _this.options.port + " (" + reason + "), reconnecting in " + nextDelay + " sec."); } - }, this), - message: __bind(function(message) { + }, + message: function(message) { switch (message.command) { case 'reload': - return this.performReload(message); + return _this.performReload(message); case 'alert': - return this.performAlert(message); + return _this.performAlert(message); } - }, this) + } }); } + LiveReload.prototype.on = function(eventName, handler) { return this.listeners[eventName] = handler; }; + LiveReload.prototype.log = function(message) { return this.console.log("" + message); }; + LiveReload.prototype.performReload = function(message) { var _ref, _ref2; this.log("LiveReload received reload request for " + message.path + "."); return this.reloader.reload(message.path, { liveCSS: (_ref = message.liveCSS) != null ? _ref : true, liveImg: (_ref2 = message.liveImg) != null ? _ref2 : true, - originalPath: message.originalPath || '' + originalPath: message.originalPath || '', + overrideURL: message.overrideURL || '', + serverURL: "http://" + this.options.host + ":" + this.options.port }); }; + LiveReload.prototype.performAlert = function(message) { return alert(message.message); }; + LiveReload.prototype.shutDown = function() { var _base; this.connector.disconnect(); this.log("LiveReload disconnected."); 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; - } + var _this = this; + if (this.hasPlugin(pluginClass.identifier)) return; this.pluginIdentifiers[pluginClass.identifier] = true; plugin = new pluginClass(this.window, { _livereload: this, @@ -819,18 +948,17 @@ __livereload.LiveReload = LiveReload = (function() { _connector: this.connector, console: this.console, Timer: Timer, - generateCacheBustUrl: __bind(function(url) { - return this.reloader.generateCacheBustUrl(url); - }, this) + generateCacheBustUrl: function(url) { + return _this.reloader.generateCacheBustUrl(url); + } }); 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; - } + if (!(this.connector.protocol >= 7)) return; pluginsData = {}; _ref = this.plugins; for (_i = 0, _len = _ref.length; _i < _len; _i++) { @@ -844,7 +972,9 @@ __livereload.LiveReload = LiveReload = (function() { url: this.window.location.href }); }; + return LiveReload; + })(); // less @@ -901,13 +1031,12 @@ __less = LessPlugin = (function() { })(); // startup -var CustomEvents, LiveReload, k, v; +var CustomEvents, LiveReload, k; CustomEvents = __customevents; LiveReload = window.LiveReload = new (__livereload.LiveReload)(window); for (k in window) { - v = window[k]; if (k.match(/^LiveReloadPlugin/)) { - LiveReload.addPlugin(v); + LiveReload.addPlugin(window[k]); } } LiveReload.addPlugin(__less); diff --git a/lib/rack-livereload.rb b/lib/rack-livereload.rb index c342d5a..1d26c7c 100644 --- a/lib/rack-livereload.rb +++ b/lib/rack-livereload.rb @@ -1,6 +1,6 @@ require "rack/livereload" class Rack::LiveReload - VERSION = '0.3.6' + VERSION = '0.3.7' end