Skip to content

Commit 977aa62

Browse files
committedMay 19, 2015
client side of livereload
1 parent 24676f9 commit 977aa62

File tree

1 file changed

+1183
-0
lines changed

1 file changed

+1183
-0
lines changed
 
+1,183
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,1183 @@
1+
(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
2+
(function() {
3+
var Connector, PROTOCOL_6, PROTOCOL_7, Parser, Version, _ref;
4+
5+
_ref = require('./protocol'), Parser = _ref.Parser, PROTOCOL_6 = _ref.PROTOCOL_6, PROTOCOL_7 = _ref.PROTOCOL_7;
6+
7+
Version = '2.2.2';
8+
9+
exports.Connector = Connector = (function() {
10+
function Connector(options, WebSocket, Timer, handlers) {
11+
this.options = options;
12+
this.WebSocket = WebSocket;
13+
this.Timer = Timer;
14+
this.handlers = handlers;
15+
this._uri = "ws" + (this.options.https ? "s" : "") + "://" + this.options.host + ":" + this.options.port + "/livereload";
16+
this._nextDelay = this.options.mindelay;
17+
this._connectionDesired = false;
18+
this.protocol = 0;
19+
this.protocolParser = new Parser({
20+
connected: (function(_this) {
21+
return function(protocol) {
22+
_this.protocol = protocol;
23+
_this._handshakeTimeout.stop();
24+
_this._nextDelay = _this.options.mindelay;
25+
_this._disconnectionReason = 'broken';
26+
return _this.handlers.connected(protocol);
27+
};
28+
})(this),
29+
error: (function(_this) {
30+
return function(e) {
31+
_this.handlers.error(e);
32+
return _this._closeOnError();
33+
};
34+
})(this),
35+
message: (function(_this) {
36+
return function(message) {
37+
return _this.handlers.message(message);
38+
};
39+
})(this)
40+
});
41+
this._handshakeTimeout = new Timer((function(_this) {
42+
return function() {
43+
if (!_this._isSocketConnected()) {
44+
return;
45+
}
46+
_this._disconnectionReason = 'handshake-timeout';
47+
return _this.socket.close();
48+
};
49+
})(this));
50+
this._reconnectTimer = new Timer((function(_this) {
51+
return function() {
52+
if (!_this._connectionDesired) {
53+
return;
54+
}
55+
return _this.connect();
56+
};
57+
})(this));
58+
this.connect();
59+
}
60+
61+
Connector.prototype._isSocketConnected = function() {
62+
return this.socket && this.socket.readyState === this.WebSocket.OPEN;
63+
};
64+
65+
Connector.prototype.connect = function() {
66+
this._connectionDesired = true;
67+
if (this._isSocketConnected()) {
68+
return;
69+
}
70+
this._reconnectTimer.stop();
71+
this._disconnectionReason = 'cannot-connect';
72+
this.protocolParser.reset();
73+
this.handlers.connecting();
74+
this.socket = new this.WebSocket(this._uri);
75+
this.socket.onopen = (function(_this) {
76+
return function(e) {
77+
return _this._onopen(e);
78+
};
79+
})(this);
80+
this.socket.onclose = (function(_this) {
81+
return function(e) {
82+
return _this._onclose(e);
83+
};
84+
})(this);
85+
this.socket.onmessage = (function(_this) {
86+
return function(e) {
87+
return _this._onmessage(e);
88+
};
89+
})(this);
90+
return this.socket.onerror = (function(_this) {
91+
return function(e) {
92+
return _this._onerror(e);
93+
};
94+
})(this);
95+
};
96+
97+
Connector.prototype.disconnect = function() {
98+
this._connectionDesired = false;
99+
this._reconnectTimer.stop();
100+
if (!this._isSocketConnected()) {
101+
return;
102+
}
103+
this._disconnectionReason = 'manual';
104+
return this.socket.close();
105+
};
106+
107+
Connector.prototype._scheduleReconnection = function() {
108+
if (!this._connectionDesired) {
109+
return;
110+
}
111+
if (!this._reconnectTimer.running) {
112+
this._reconnectTimer.start(this._nextDelay);
113+
return this._nextDelay = Math.min(this.options.maxdelay, this._nextDelay * 2);
114+
}
115+
};
116+
117+
Connector.prototype.sendCommand = function(command) {
118+
if (this.protocol == null) {
119+
return;
120+
}
121+
return this._sendCommand(command);
122+
};
123+
124+
Connector.prototype._sendCommand = function(command) {
125+
return this.socket.send(JSON.stringify(command));
126+
};
127+
128+
Connector.prototype._closeOnError = function() {
129+
this._handshakeTimeout.stop();
130+
this._disconnectionReason = 'error';
131+
return this.socket.close();
132+
};
133+
134+
Connector.prototype._onopen = function(e) {
135+
var hello;
136+
this.handlers.socketConnected();
137+
this._disconnectionReason = 'handshake-failed';
138+
hello = {
139+
command: 'hello',
140+
protocols: [PROTOCOL_6, PROTOCOL_7]
141+
};
142+
hello.ver = Version;
143+
if (this.options.ext) {
144+
hello.ext = this.options.ext;
145+
}
146+
if (this.options.extver) {
147+
hello.extver = this.options.extver;
148+
}
149+
if (this.options.snipver) {
150+
hello.snipver = this.options.snipver;
151+
}
152+
this._sendCommand(hello);
153+
return this._handshakeTimeout.start(this.options.handshake_timeout);
154+
};
155+
156+
Connector.prototype._onclose = function(e) {
157+
this.protocol = 0;
158+
this.handlers.disconnected(this._disconnectionReason, this._nextDelay);
159+
return this._scheduleReconnection();
160+
};
161+
162+
Connector.prototype._onerror = function(e) {};
163+
164+
Connector.prototype._onmessage = function(e) {
165+
return this.protocolParser.process(e.data);
166+
};
167+
168+
return Connector;
169+
170+
})();
171+
172+
}).call(this);
173+
174+
},{"./protocol":6}],2:[function(require,module,exports){
175+
(function() {
176+
var CustomEvents;
177+
178+
CustomEvents = {
179+
bind: function(element, eventName, handler) {
180+
if (element.addEventListener) {
181+
return element.addEventListener(eventName, handler, false);
182+
} else if (element.attachEvent) {
183+
element[eventName] = 1;
184+
return element.attachEvent('onpropertychange', function(event) {
185+
if (event.propertyName === eventName) {
186+
return handler();
187+
}
188+
});
189+
} else {
190+
throw new Error("Attempt to attach custom event " + eventName + " to something which isn't a DOMElement");
191+
}
192+
},
193+
fire: function(element, eventName) {
194+
var event;
195+
if (element.addEventListener) {
196+
event = document.createEvent('HTMLEvents');
197+
event.initEvent(eventName, true, true);
198+
return document.dispatchEvent(event);
199+
} else if (element.attachEvent) {
200+
if (element[eventName]) {
201+
return element[eventName]++;
202+
}
203+
} else {
204+
throw new Error("Attempt to fire custom event " + eventName + " on something which isn't a DOMElement");
205+
}
206+
}
207+
};
208+
209+
exports.bind = CustomEvents.bind;
210+
211+
exports.fire = CustomEvents.fire;
212+
213+
}).call(this);
214+
215+
},{}],3:[function(require,module,exports){
216+
(function() {
217+
var LessPlugin;
218+
219+
module.exports = LessPlugin = (function() {
220+
LessPlugin.identifier = 'less';
221+
222+
LessPlugin.version = '1.0';
223+
224+
function LessPlugin(window, host) {
225+
this.window = window;
226+
this.host = host;
227+
}
228+
229+
LessPlugin.prototype.reload = function(path, options) {
230+
if (this.window.less && this.window.less.refresh) {
231+
if (path.match(/\.less$/i)) {
232+
return this.reloadLess(path);
233+
}
234+
if (options.originalPath.match(/\.less$/i)) {
235+
return this.reloadLess(options.originalPath);
236+
}
237+
}
238+
return false;
239+
};
240+
241+
LessPlugin.prototype.reloadLess = function(path) {
242+
var link, links, _i, _len;
243+
links = (function() {
244+
var _i, _len, _ref, _results;
245+
_ref = document.getElementsByTagName('link');
246+
_results = [];
247+
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
248+
link = _ref[_i];
249+
if (link.href && link.rel.match(/^stylesheet\/less$/i) || (link.rel.match(/stylesheet/i) && link.type.match(/^text\/(x-)?less$/i))) {
250+
_results.push(link);
251+
}
252+
}
253+
return _results;
254+
})();
255+
if (links.length === 0) {
256+
return false;
257+
}
258+
for (_i = 0, _len = links.length; _i < _len; _i++) {
259+
link = links[_i];
260+
link.href = this.host.generateCacheBustUrl(link.href);
261+
}
262+
this.host.console.log("LiveReload is asking LESS to recompile all stylesheets");
263+
this.window.less.refresh(true);
264+
return true;
265+
};
266+
267+
LessPlugin.prototype.analyze = function() {
268+
return {
269+
disable: !!(this.window.less && this.window.less.refresh)
270+
};
271+
};
272+
273+
return LessPlugin;
274+
275+
})();
276+
277+
}).call(this);
278+
279+
},{}],4:[function(require,module,exports){
280+
(function() {
281+
var Connector, LiveReload, Options, Reloader, Timer,
282+
__hasProp = {}.hasOwnProperty;
283+
284+
Connector = require('./connector').Connector;
285+
286+
Timer = require('./timer').Timer;
287+
288+
Options = require('./options').Options;
289+
290+
Reloader = require('./reloader').Reloader;
291+
292+
exports.LiveReload = LiveReload = (function() {
293+
function LiveReload(window) {
294+
var k, v, _ref;
295+
this.window = window;
296+
this.listeners = {};
297+
this.plugins = [];
298+
this.pluginIdentifiers = {};
299+
this.console = this.window.console && this.window.console.log && this.window.console.error ? this.window.location.href.match(/LR-verbose/) ? this.window.console : {
300+
log: function() {},
301+
error: this.window.console.error.bind(this.window.console)
302+
} : {
303+
log: function() {},
304+
error: function() {}
305+
};
306+
if (!(this.WebSocket = this.window.WebSocket || this.window.MozWebSocket)) {
307+
this.console.error("LiveReload disabled because the browser does not seem to support web sockets");
308+
return;
309+
}
310+
if ('LiveReloadOptions' in window) {
311+
this.options = new Options();
312+
_ref = window['LiveReloadOptions'];
313+
for (k in _ref) {
314+
if (!__hasProp.call(_ref, k)) continue;
315+
v = _ref[k];
316+
this.options.set(k, v);
317+
}
318+
} else {
319+
this.options = Options.extract(this.window.document);
320+
if (!this.options) {
321+
this.console.error("LiveReload disabled because it could not find its own <SCRIPT> tag");
322+
return;
323+
}
324+
}
325+
this.reloader = new Reloader(this.window, this.console, Timer);
326+
this.connector = new Connector(this.options, this.WebSocket, Timer, {
327+
connecting: (function(_this) {
328+
return function() {};
329+
})(this),
330+
socketConnected: (function(_this) {
331+
return function() {};
332+
})(this),
333+
connected: (function(_this) {
334+
return function(protocol) {
335+
var _base;
336+
if (typeof (_base = _this.listeners).connect === "function") {
337+
_base.connect();
338+
}
339+
_this.log("LiveReload is connected to " + _this.options.host + ":" + _this.options.port + " (protocol v" + protocol + ").");
340+
return _this.analyze();
341+
};
342+
})(this),
343+
error: (function(_this) {
344+
return function(e) {
345+
if (e instanceof ProtocolError) {
346+
if (typeof console !== "undefined" && console !== null) {
347+
return console.log("" + e.message + ".");
348+
}
349+
} else {
350+
if (typeof console !== "undefined" && console !== null) {
351+
return console.log("LiveReload internal error: " + e.message);
352+
}
353+
}
354+
};
355+
})(this),
356+
disconnected: (function(_this) {
357+
return function(reason, nextDelay) {
358+
var _base;
359+
if (typeof (_base = _this.listeners).disconnect === "function") {
360+
_base.disconnect();
361+
}
362+
switch (reason) {
363+
case 'cannot-connect':
364+
return _this.log("LiveReload cannot connect to " + _this.options.host + ":" + _this.options.port + ", will retry in " + nextDelay + " sec.");
365+
case 'broken':
366+
return _this.log("LiveReload disconnected from " + _this.options.host + ":" + _this.options.port + ", reconnecting in " + nextDelay + " sec.");
367+
case 'handshake-timeout':
368+
return _this.log("LiveReload cannot connect to " + _this.options.host + ":" + _this.options.port + " (handshake timeout), will retry in " + nextDelay + " sec.");
369+
case 'handshake-failed':
370+
return _this.log("LiveReload cannot connect to " + _this.options.host + ":" + _this.options.port + " (handshake failed), will retry in " + nextDelay + " sec.");
371+
case 'manual':
372+
break;
373+
case 'error':
374+
break;
375+
default:
376+
return _this.log("LiveReload disconnected from " + _this.options.host + ":" + _this.options.port + " (" + reason + "), reconnecting in " + nextDelay + " sec.");
377+
}
378+
};
379+
})(this),
380+
message: (function(_this) {
381+
return function(message) {
382+
switch (message.command) {
383+
case 'reload':
384+
return _this.performReload(message);
385+
case 'alert':
386+
return _this.performAlert(message);
387+
}
388+
};
389+
})(this)
390+
});
391+
this.initialized = true;
392+
}
393+
394+
LiveReload.prototype.on = function(eventName, handler) {
395+
return this.listeners[eventName] = handler;
396+
};
397+
398+
LiveReload.prototype.log = function(message) {
399+
return this.console.log("" + message);
400+
};
401+
402+
LiveReload.prototype.performReload = function(message) {
403+
var _ref, _ref1;
404+
this.log("LiveReload received reload request: " + (JSON.stringify(message, null, 2)));
405+
return this.reloader.reload(message.path, {
406+
liveCSS: (_ref = message.liveCSS) != null ? _ref : true,
407+
liveImg: (_ref1 = message.liveImg) != null ? _ref1 : true,
408+
originalPath: message.originalPath || '',
409+
overrideURL: message.overrideURL || '',
410+
serverURL: "http://" + this.options.host + ":" + this.options.port
411+
});
412+
};
413+
414+
LiveReload.prototype.performAlert = function(message) {
415+
return alert(message.message);
416+
};
417+
418+
LiveReload.prototype.shutDown = function() {
419+
var _base;
420+
if (!this.initialized) {
421+
return;
422+
}
423+
this.connector.disconnect();
424+
this.log("LiveReload disconnected.");
425+
return typeof (_base = this.listeners).shutdown === "function" ? _base.shutdown() : void 0;
426+
};
427+
428+
LiveReload.prototype.hasPlugin = function(identifier) {
429+
return !!this.pluginIdentifiers[identifier];
430+
};
431+
432+
LiveReload.prototype.addPlugin = function(pluginClass) {
433+
var plugin;
434+
if (!this.initialized) {
435+
return;
436+
}
437+
if (this.hasPlugin(pluginClass.identifier)) {
438+
return;
439+
}
440+
this.pluginIdentifiers[pluginClass.identifier] = true;
441+
plugin = new pluginClass(this.window, {
442+
_livereload: this,
443+
_reloader: this.reloader,
444+
_connector: this.connector,
445+
console: this.console,
446+
Timer: Timer,
447+
generateCacheBustUrl: (function(_this) {
448+
return function(url) {
449+
return _this.reloader.generateCacheBustUrl(url);
450+
};
451+
})(this)
452+
});
453+
this.plugins.push(plugin);
454+
this.reloader.addPlugin(plugin);
455+
};
456+
457+
LiveReload.prototype.analyze = function() {
458+
var plugin, pluginData, pluginsData, _i, _len, _ref;
459+
if (!this.initialized) {
460+
return;
461+
}
462+
if (!(this.connector.protocol >= 7)) {
463+
return;
464+
}
465+
pluginsData = {};
466+
_ref = this.plugins;
467+
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
468+
plugin = _ref[_i];
469+
pluginsData[plugin.constructor.identifier] = pluginData = (typeof plugin.analyze === "function" ? plugin.analyze() : void 0) || {};
470+
pluginData.version = plugin.constructor.version;
471+
}
472+
this.connector.sendCommand({
473+
command: 'info',
474+
plugins: pluginsData,
475+
url: this.window.location.href
476+
});
477+
};
478+
479+
return LiveReload;
480+
481+
})();
482+
483+
}).call(this);
484+
485+
},{"./connector":1,"./options":5,"./reloader":7,"./timer":9}],5:[function(require,module,exports){
486+
(function() {
487+
var Options;
488+
489+
exports.Options = Options = (function() {
490+
function Options() {
491+
this.https = false;
492+
this.host = null;
493+
this.port = 35729;
494+
this.snipver = null;
495+
this.ext = null;
496+
this.extver = null;
497+
this.mindelay = 1000;
498+
this.maxdelay = 60000;
499+
this.handshake_timeout = 5000;
500+
}
501+
502+
Options.prototype.set = function(name, value) {
503+
if (typeof value === 'undefined') {
504+
return;
505+
}
506+
if (!isNaN(+value)) {
507+
value = +value;
508+
}
509+
return this[name] = value;
510+
};
511+
512+
return Options;
513+
514+
})();
515+
516+
Options.extract = function(document) {
517+
var element, keyAndValue, m, mm, options, pair, src, _i, _j, _len, _len1, _ref, _ref1;
518+
_ref = document.getElementsByTagName('script');
519+
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
520+
element = _ref[_i];
521+
if ((src = element.src) && (m = src.match(/^[^:]+:\/\/(.*)\/z?livereload\.js(?:\?(.*))?$/))) {
522+
options = new Options();
523+
options.https = src.indexOf("https") === 0;
524+
if (mm = m[1].match(/^([^\/:]+)(?::(\d+))?$/)) {
525+
options.host = mm[1];
526+
if (mm[2]) {
527+
options.port = parseInt(mm[2], 10);
528+
}
529+
}
530+
if (m[2]) {
531+
_ref1 = m[2].split('&');
532+
for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) {
533+
pair = _ref1[_j];
534+
if ((keyAndValue = pair.split('=')).length > 1) {
535+
options.set(keyAndValue[0].replace(/-/g, '_'), keyAndValue.slice(1).join('='));
536+
}
537+
}
538+
}
539+
return options;
540+
}
541+
}
542+
return null;
543+
};
544+
545+
}).call(this);
546+
547+
},{}],6:[function(require,module,exports){
548+
(function() {
549+
var PROTOCOL_6, PROTOCOL_7, Parser, ProtocolError,
550+
__indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; };
551+
552+
exports.PROTOCOL_6 = PROTOCOL_6 = 'http://livereload.com/protocols/official-6';
553+
554+
exports.PROTOCOL_7 = PROTOCOL_7 = 'http://livereload.com/protocols/official-7';
555+
556+
exports.ProtocolError = ProtocolError = (function() {
557+
function ProtocolError(reason, data) {
558+
this.message = "LiveReload protocol error (" + reason + ") after receiving data: \"" + data + "\".";
559+
}
560+
561+
return ProtocolError;
562+
563+
})();
564+
565+
exports.Parser = Parser = (function() {
566+
function Parser(handlers) {
567+
this.handlers = handlers;
568+
this.reset();
569+
}
570+
571+
Parser.prototype.reset = function() {
572+
return this.protocol = null;
573+
};
574+
575+
Parser.prototype.process = function(data) {
576+
var command, e, message, options, _ref;
577+
try {
578+
if (this.protocol == null) {
579+
if (data.match(/^!!ver:([\d.]+)$/)) {
580+
this.protocol = 6;
581+
} else if (message = this._parseMessage(data, ['hello'])) {
582+
if (!message.protocols.length) {
583+
throw new ProtocolError("no protocols specified in handshake message");
584+
} else if (__indexOf.call(message.protocols, PROTOCOL_7) >= 0) {
585+
this.protocol = 7;
586+
} else if (__indexOf.call(message.protocols, PROTOCOL_6) >= 0) {
587+
this.protocol = 6;
588+
} else {
589+
throw new ProtocolError("no supported protocols found");
590+
}
591+
}
592+
return this.handlers.connected(this.protocol);
593+
} else if (this.protocol === 6) {
594+
message = JSON.parse(data);
595+
if (!message.length) {
596+
throw new ProtocolError("protocol 6 messages must be arrays");
597+
}
598+
command = message[0], options = message[1];
599+
if (command !== 'refresh') {
600+
throw new ProtocolError("unknown protocol 6 command");
601+
}
602+
return this.handlers.message({
603+
command: 'reload',
604+
path: options.path,
605+
liveCSS: (_ref = options.apply_css_live) != null ? _ref : true
606+
});
607+
} else {
608+
message = this._parseMessage(data, ['reload', 'alert']);
609+
return this.handlers.message(message);
610+
}
611+
} catch (_error) {
612+
e = _error;
613+
if (e instanceof ProtocolError) {
614+
return this.handlers.error(e);
615+
} else {
616+
throw e;
617+
}
618+
}
619+
};
620+
621+
Parser.prototype._parseMessage = function(data, validCommands) {
622+
var e, message, _ref;
623+
try {
624+
message = JSON.parse(data);
625+
} catch (_error) {
626+
e = _error;
627+
throw new ProtocolError('unparsable JSON', data);
628+
}
629+
if (!message.command) {
630+
throw new ProtocolError('missing "command" key', data);
631+
}
632+
if (_ref = message.command, __indexOf.call(validCommands, _ref) < 0) {
633+
throw new ProtocolError("invalid command '" + message.command + "', only valid commands are: " + (validCommands.join(', ')) + ")", data);
634+
}
635+
return message;
636+
};
637+
638+
return Parser;
639+
640+
})();
641+
642+
}).call(this);
643+
644+
},{}],7:[function(require,module,exports){
645+
(function() {
646+
var IMAGE_STYLES, Reloader, numberOfMatchingSegments, pathFromUrl, pathsMatch, pickBestMatch, splitUrl;
647+
648+
splitUrl = function(url) {
649+
var hash, index, params;
650+
if ((index = url.indexOf('#')) >= 0) {
651+
hash = url.slice(index);
652+
url = url.slice(0, index);
653+
} else {
654+
hash = '';
655+
}
656+
if ((index = url.indexOf('?')) >= 0) {
657+
params = url.slice(index);
658+
url = url.slice(0, index);
659+
} else {
660+
params = '';
661+
}
662+
return {
663+
url: url,
664+
params: params,
665+
hash: hash
666+
};
667+
};
668+
669+
pathFromUrl = function(url) {
670+
var path;
671+
url = splitUrl(url).url;
672+
if (url.indexOf('file://') === 0) {
673+
path = url.replace(/^file:\/\/(localhost)?/, '');
674+
} else {
675+
path = url.replace(/^([^:]+:)?\/\/([^:\/]+)(:\d*)?\//, '/');
676+
}
677+
return decodeURIComponent(path);
678+
};
679+
680+
pickBestMatch = function(path, objects, pathFunc) {
681+
var bestMatch, object, score, _i, _len;
682+
bestMatch = {
683+
score: 0
684+
};
685+
for (_i = 0, _len = objects.length; _i < _len; _i++) {
686+
object = objects[_i];
687+
score = numberOfMatchingSegments(path, pathFunc(object));
688+
if (score > bestMatch.score) {
689+
bestMatch = {
690+
object: object,
691+
score: score
692+
};
693+
}
694+
}
695+
if (bestMatch.score > 0) {
696+
return bestMatch;
697+
} else {
698+
return null;
699+
}
700+
};
701+
702+
numberOfMatchingSegments = function(path1, path2) {
703+
var comps1, comps2, eqCount, len;
704+
path1 = path1.replace(/^\/+/, '').toLowerCase();
705+
path2 = path2.replace(/^\/+/, '').toLowerCase();
706+
if (path1 === path2) {
707+
return 10000;
708+
}
709+
comps1 = path1.split('/').reverse();
710+
comps2 = path2.split('/').reverse();
711+
len = Math.min(comps1.length, comps2.length);
712+
eqCount = 0;
713+
while (eqCount < len && comps1[eqCount] === comps2[eqCount]) {
714+
++eqCount;
715+
}
716+
return eqCount;
717+
};
718+
719+
pathsMatch = function(path1, path2) {
720+
return numberOfMatchingSegments(path1, path2) > 0;
721+
};
722+
723+
IMAGE_STYLES = [
724+
{
725+
selector: 'background',
726+
styleNames: ['backgroundImage']
727+
}, {
728+
selector: 'border',
729+
styleNames: ['borderImage', 'webkitBorderImage', 'MozBorderImage']
730+
}
731+
];
732+
733+
exports.Reloader = Reloader = (function() {
734+
function Reloader(window, console, Timer) {
735+
this.window = window;
736+
this.console = console;
737+
this.Timer = Timer;
738+
this.document = this.window.document;
739+
this.importCacheWaitPeriod = 200;
740+
this.plugins = [];
741+
}
742+
743+
Reloader.prototype.addPlugin = function(plugin) {
744+
return this.plugins.push(plugin);
745+
};
746+
747+
Reloader.prototype.analyze = function(callback) {
748+
return results;
749+
};
750+
751+
Reloader.prototype.reload = function(path, options) {
752+
var plugin, _base, _i, _len, _ref;
753+
this.options = options;
754+
if ((_base = this.options).stylesheetReloadTimeout == null) {
755+
_base.stylesheetReloadTimeout = 15000;
756+
}
757+
_ref = this.plugins;
758+
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
759+
plugin = _ref[_i];
760+
if (plugin.reload && plugin.reload(path, options)) {
761+
return;
762+
}
763+
}
764+
if (options.liveCSS) {
765+
if (path.match(/\.css$/i)) {
766+
if (this.reloadStylesheet(path)) {
767+
return;
768+
}
769+
}
770+
}
771+
if (options.liveImg) {
772+
if (path.match(/\.(jpe?g|png|gif)$/i)) {
773+
this.reloadImages(path);
774+
return;
775+
}
776+
}
777+
return this.reloadPage();
778+
};
779+
780+
Reloader.prototype.reloadPage = function() {
781+
return this.window.document.location.reload();
782+
};
783+
784+
Reloader.prototype.reloadImages = function(path) {
785+
var expando, img, selector, styleNames, styleSheet, _i, _j, _k, _l, _len, _len1, _len2, _len3, _ref, _ref1, _ref2, _ref3, _results;
786+
expando = this.generateUniqueString();
787+
_ref = this.document.images;
788+
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
789+
img = _ref[_i];
790+
if (pathsMatch(path, pathFromUrl(img.src))) {
791+
img.src = this.generateCacheBustUrl(img.src, expando);
792+
}
793+
}
794+
if (this.document.querySelectorAll) {
795+
for (_j = 0, _len1 = IMAGE_STYLES.length; _j < _len1; _j++) {
796+
_ref1 = IMAGE_STYLES[_j], selector = _ref1.selector, styleNames = _ref1.styleNames;
797+
_ref2 = this.document.querySelectorAll("[style*=" + selector + "]");
798+
for (_k = 0, _len2 = _ref2.length; _k < _len2; _k++) {
799+
img = _ref2[_k];
800+
this.reloadStyleImages(img.style, styleNames, path, expando);
801+
}
802+
}
803+
}
804+
if (this.document.styleSheets) {
805+
_ref3 = this.document.styleSheets;
806+
_results = [];
807+
for (_l = 0, _len3 = _ref3.length; _l < _len3; _l++) {
808+
styleSheet = _ref3[_l];
809+
_results.push(this.reloadStylesheetImages(styleSheet, path, expando));
810+
}
811+
return _results;
812+
}
813+
};
814+
815+
Reloader.prototype.reloadStylesheetImages = function(styleSheet, path, expando) {
816+
var e, rule, rules, styleNames, _i, _j, _len, _len1;
817+
try {
818+
rules = styleSheet != null ? styleSheet.cssRules : void 0;
819+
} catch (_error) {
820+
e = _error;
821+
}
822+
if (!rules) {
823+
return;
824+
}
825+
for (_i = 0, _len = rules.length; _i < _len; _i++) {
826+
rule = rules[_i];
827+
switch (rule.type) {
828+
case CSSRule.IMPORT_RULE:
829+
this.reloadStylesheetImages(rule.styleSheet, path, expando);
830+
break;
831+
case CSSRule.STYLE_RULE:
832+
for (_j = 0, _len1 = IMAGE_STYLES.length; _j < _len1; _j++) {
833+
styleNames = IMAGE_STYLES[_j].styleNames;
834+
this.reloadStyleImages(rule.style, styleNames, path, expando);
835+
}
836+
break;
837+
case CSSRule.MEDIA_RULE:
838+
this.reloadStylesheetImages(rule, path, expando);
839+
}
840+
}
841+
};
842+
843+
Reloader.prototype.reloadStyleImages = function(style, styleNames, path, expando) {
844+
var newValue, styleName, value, _i, _len;
845+
for (_i = 0, _len = styleNames.length; _i < _len; _i++) {
846+
styleName = styleNames[_i];
847+
value = style[styleName];
848+
if (typeof value === 'string') {
849+
newValue = value.replace(/\burl\s*\(([^)]*)\)/, (function(_this) {
850+
return function(match, src) {
851+
if (pathsMatch(path, pathFromUrl(src))) {
852+
return "url(" + (_this.generateCacheBustUrl(src, expando)) + ")";
853+
} else {
854+
return match;
855+
}
856+
};
857+
})(this));
858+
if (newValue !== value) {
859+
style[styleName] = newValue;
860+
}
861+
}
862+
}
863+
};
864+
865+
Reloader.prototype.reloadStylesheet = function(path) {
866+
var imported, link, links, match, style, _i, _j, _k, _l, _len, _len1, _len2, _len3, _ref, _ref1;
867+
links = (function() {
868+
var _i, _len, _ref, _results;
869+
_ref = this.document.getElementsByTagName('link');
870+
_results = [];
871+
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
872+
link = _ref[_i];
873+
if (link.rel.match(/^stylesheet$/i) && !link.__LiveReload_pendingRemoval) {
874+
_results.push(link);
875+
}
876+
}
877+
return _results;
878+
}).call(this);
879+
imported = [];
880+
_ref = this.document.getElementsByTagName('style');
881+
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
882+
style = _ref[_i];
883+
if (style.sheet) {
884+
this.collectImportedStylesheets(style, style.sheet, imported);
885+
}
886+
}
887+
for (_j = 0, _len1 = links.length; _j < _len1; _j++) {
888+
link = links[_j];
889+
this.collectImportedStylesheets(link, link.sheet, imported);
890+
}
891+
if (this.window.StyleFix && this.document.querySelectorAll) {
892+
_ref1 = this.document.querySelectorAll('style[data-href]');
893+
for (_k = 0, _len2 = _ref1.length; _k < _len2; _k++) {
894+
style = _ref1[_k];
895+
links.push(style);
896+
}
897+
}
898+
this.console.log("LiveReload found " + links.length + " LINKed stylesheets, " + imported.length + " @imported stylesheets");
899+
match = pickBestMatch(path, links.concat(imported), (function(_this) {
900+
return function(l) {
901+
return pathFromUrl(_this.linkHref(l));
902+
};
903+
})(this));
904+
if (match) {
905+
if (match.object.rule) {
906+
this.console.log("LiveReload is reloading imported stylesheet: " + match.object.href);
907+
this.reattachImportedRule(match.object);
908+
} else {
909+
this.console.log("LiveReload is reloading stylesheet: " + (this.linkHref(match.object)));
910+
this.reattachStylesheetLink(match.object);
911+
}
912+
} else {
913+
this.console.log("LiveReload will reload all stylesheets because path '" + path + "' did not match any specific one");
914+
for (_l = 0, _len3 = links.length; _l < _len3; _l++) {
915+
link = links[_l];
916+
this.reattachStylesheetLink(link);
917+
}
918+
}
919+
return true;
920+
};
921+
922+
Reloader.prototype.collectImportedStylesheets = function(link, styleSheet, result) {
923+
var e, index, rule, rules, _i, _len;
924+
try {
925+
rules = styleSheet != null ? styleSheet.cssRules : void 0;
926+
} catch (_error) {
927+
e = _error;
928+
}
929+
if (rules && rules.length) {
930+
for (index = _i = 0, _len = rules.length; _i < _len; index = ++_i) {
931+
rule = rules[index];
932+
switch (rule.type) {
933+
case CSSRule.CHARSET_RULE:
934+
continue;
935+
case CSSRule.IMPORT_RULE:
936+
result.push({
937+
link: link,
938+
rule: rule,
939+
index: index,
940+
href: rule.href
941+
});
942+
this.collectImportedStylesheets(link, rule.styleSheet, result);
943+
break;
944+
default:
945+
break;
946+
}
947+
}
948+
}
949+
};
950+
951+
Reloader.prototype.waitUntilCssLoads = function(clone, func) {
952+
var callbackExecuted, executeCallback, poll;
953+
callbackExecuted = false;
954+
executeCallback = (function(_this) {
955+
return function() {
956+
if (callbackExecuted) {
957+
return;
958+
}
959+
callbackExecuted = true;
960+
return func();
961+
};
962+
})(this);
963+
clone.onload = (function(_this) {
964+
return function() {
965+
_this.console.log("LiveReload: the new stylesheet has finished loading");
966+
_this.knownToSupportCssOnLoad = true;
967+
return executeCallback();
968+
};
969+
})(this);
970+
if (!this.knownToSupportCssOnLoad) {
971+
(poll = (function(_this) {
972+
return function() {
973+
if (clone.sheet) {
974+
_this.console.log("LiveReload is polling until the new CSS finishes loading...");
975+
return executeCallback();
976+
} else {
977+
return _this.Timer.start(50, poll);
978+
}
979+
};
980+
})(this))();
981+
}
982+
return this.Timer.start(this.options.stylesheetReloadTimeout, executeCallback);
983+
};
984+
985+
Reloader.prototype.linkHref = function(link) {
986+
return link.href || link.getAttribute('data-href');
987+
};
988+
989+
Reloader.prototype.reattachStylesheetLink = function(link) {
990+
var clone, parent;
991+
if (link.__LiveReload_pendingRemoval) {
992+
return;
993+
}
994+
link.__LiveReload_pendingRemoval = true;
995+
if (link.tagName === 'STYLE') {
996+
clone = this.document.createElement('link');
997+
clone.rel = 'stylesheet';
998+
clone.media = link.media;
999+
clone.disabled = link.disabled;
1000+
} else {
1001+
clone = link.cloneNode(false);
1002+
}
1003+
clone.href = this.generateCacheBustUrl(this.linkHref(link));
1004+
parent = link.parentNode;
1005+
if (parent.lastChild === link) {
1006+
parent.appendChild(clone);
1007+
} else {
1008+
parent.insertBefore(clone, link.nextSibling);
1009+
}
1010+
return this.waitUntilCssLoads(clone, (function(_this) {
1011+
return function() {
1012+
var additionalWaitingTime;
1013+
if (/AppleWebKit/.test(navigator.userAgent)) {
1014+
additionalWaitingTime = 5;
1015+
} else {
1016+
additionalWaitingTime = 200;
1017+
}
1018+
return _this.Timer.start(additionalWaitingTime, function() {
1019+
var _ref;
1020+
if (!link.parentNode) {
1021+
return;
1022+
}
1023+
link.parentNode.removeChild(link);
1024+
clone.onreadystatechange = null;
1025+
return (_ref = _this.window.StyleFix) != null ? _ref.link(clone) : void 0;
1026+
});
1027+
};
1028+
})(this));
1029+
};
1030+
1031+
Reloader.prototype.reattachImportedRule = function(_arg) {
1032+
var href, index, link, media, newRule, parent, rule, tempLink;
1033+
rule = _arg.rule, index = _arg.index, link = _arg.link;
1034+
parent = rule.parentStyleSheet;
1035+
href = this.generateCacheBustUrl(rule.href);
1036+
media = rule.media.length ? [].join.call(rule.media, ', ') : '';
1037+
newRule = "@import url(\"" + href + "\") " + media + ";";
1038+
rule.__LiveReload_newHref = href;
1039+
tempLink = this.document.createElement("link");
1040+
tempLink.rel = 'stylesheet';
1041+
tempLink.href = href;
1042+
tempLink.__LiveReload_pendingRemoval = true;
1043+
if (link.parentNode) {
1044+
link.parentNode.insertBefore(tempLink, link);
1045+
}
1046+
return this.Timer.start(this.importCacheWaitPeriod, (function(_this) {
1047+
return function() {
1048+
if (tempLink.parentNode) {
1049+
tempLink.parentNode.removeChild(tempLink);
1050+
}
1051+
if (rule.__LiveReload_newHref !== href) {
1052+
return;
1053+
}
1054+
parent.insertRule(newRule, index);
1055+
parent.deleteRule(index + 1);
1056+
rule = parent.cssRules[index];
1057+
rule.__LiveReload_newHref = href;
1058+
return _this.Timer.start(_this.importCacheWaitPeriod, function() {
1059+
if (rule.__LiveReload_newHref !== href) {
1060+
return;
1061+
}
1062+
parent.insertRule(newRule, index);
1063+
return parent.deleteRule(index + 1);
1064+
});
1065+
};
1066+
})(this));
1067+
};
1068+
1069+
Reloader.prototype.generateUniqueString = function() {
1070+
return 'livereload=' + Date.now();
1071+
};
1072+
1073+
Reloader.prototype.generateCacheBustUrl = function(url, expando) {
1074+
var hash, oldParams, originalUrl, params, _ref;
1075+
if (expando == null) {
1076+
expando = this.generateUniqueString();
1077+
}
1078+
_ref = splitUrl(url), url = _ref.url, hash = _ref.hash, oldParams = _ref.params;
1079+
if (this.options.overrideURL) {
1080+
if (url.indexOf(this.options.serverURL) < 0) {
1081+
originalUrl = url;
1082+
url = this.options.serverURL + this.options.overrideURL + "?url=" + encodeURIComponent(url);
1083+
this.console.log("LiveReload is overriding source URL " + originalUrl + " with " + url);
1084+
}
1085+
}
1086+
params = oldParams.replace(/(\?|&)livereload=(\d+)/, function(match, sep) {
1087+
return "" + sep + expando;
1088+
});
1089+
if (params === oldParams) {
1090+
if (oldParams.length === 0) {
1091+
params = "?" + expando;
1092+
} else {
1093+
params = "" + oldParams + "&" + expando;
1094+
}
1095+
}
1096+
return url + params + hash;
1097+
};
1098+
1099+
return Reloader;
1100+
1101+
})();
1102+
1103+
}).call(this);
1104+
1105+
},{}],8:[function(require,module,exports){
1106+
(function() {
1107+
var CustomEvents, LiveReload, k;
1108+
1109+
CustomEvents = require('./customevents');
1110+
1111+
LiveReload = window.LiveReload = new (require('./livereload').LiveReload)(window);
1112+
1113+
for (k in window) {
1114+
if (k.match(/^LiveReloadPlugin/)) {
1115+
LiveReload.addPlugin(window[k]);
1116+
}
1117+
}
1118+
1119+
LiveReload.addPlugin(require('./less'));
1120+
1121+
LiveReload.on('shutdown', function() {
1122+
return delete window.LiveReload;
1123+
});
1124+
1125+
LiveReload.on('connect', function() {
1126+
return CustomEvents.fire(document, 'LiveReloadConnect');
1127+
});
1128+
1129+
LiveReload.on('disconnect', function() {
1130+
return CustomEvents.fire(document, 'LiveReloadDisconnect');
1131+
});
1132+
1133+
CustomEvents.bind(document, 'LiveReloadShutDown', function() {
1134+
return LiveReload.shutDown();
1135+
});
1136+
1137+
}).call(this);
1138+
1139+
},{"./customevents":2,"./less":3,"./livereload":4}],9:[function(require,module,exports){
1140+
(function() {
1141+
var Timer;
1142+
1143+
exports.Timer = Timer = (function() {
1144+
function Timer(func) {
1145+
this.func = func;
1146+
this.running = false;
1147+
this.id = null;
1148+
this._handler = (function(_this) {
1149+
return function() {
1150+
_this.running = false;
1151+
_this.id = null;
1152+
return _this.func();
1153+
};
1154+
})(this);
1155+
}
1156+
1157+
Timer.prototype.start = function(timeout) {
1158+
if (this.running) {
1159+
clearTimeout(this.id);
1160+
}
1161+
this.id = setTimeout(this._handler, timeout);
1162+
return this.running = true;
1163+
};
1164+
1165+
Timer.prototype.stop = function() {
1166+
if (this.running) {
1167+
clearTimeout(this.id);
1168+
this.running = false;
1169+
return this.id = null;
1170+
}
1171+
};
1172+
1173+
return Timer;
1174+
1175+
})();
1176+
1177+
Timer.start = function(timeout, func) {
1178+
return setTimeout(func, timeout);
1179+
};
1180+
1181+
}).call(this);
1182+
1183+
},{}]},{},[8]);

0 commit comments

Comments
 (0)
Please sign in to comment.