livereload_rails 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (45) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +9 -0
  3. data/.rspec +2 -0
  4. data/CODE_OF_CONDUCT.md +13 -0
  5. data/Gemfile +3 -0
  6. data/LICENSE.txt +21 -0
  7. data/README.md +40 -0
  8. data/Rakefile +6 -0
  9. data/bin/console +7 -0
  10. data/bin/setup +5 -0
  11. data/example/Gemfile +8 -0
  12. data/example/Gemfile.lock +119 -0
  13. data/example/Rakefile +6 -0
  14. data/example/app/assets/images/.keep +0 -0
  15. data/example/app/assets/javascripts/application.js +1 -0
  16. data/example/app/assets/stylesheets/application.css +3 -0
  17. data/example/app/controllers/application_controller.rb +8 -0
  18. data/example/app/views/application/home.html.erb +10 -0
  19. data/example/app/views/layouts/application.html.erb +14 -0
  20. data/example/bin/bundle +3 -0
  21. data/example/bin/rails +4 -0
  22. data/example/bin/rake +4 -0
  23. data/example/bin/setup +29 -0
  24. data/example/config.ru +4 -0
  25. data/example/config/application.rb +26 -0
  26. data/example/config/boot.rb +3 -0
  27. data/example/config/environment.rb +5 -0
  28. data/example/config/environments/development.rb +35 -0
  29. data/example/config/initializers/livereload_rails.rb +5 -0
  30. data/example/config/routes.rb +3 -0
  31. data/example/config/secrets.yml +14 -0
  32. data/example/log/.gitignore +2 -0
  33. data/example/public/favicon.ico +0 -0
  34. data/example/tmp/.gitignore +2 -0
  35. data/lib/livereload_rails.rb +48 -0
  36. data/lib/livereload_rails/client.rb +67 -0
  37. data/lib/livereload_rails/middleware.rb +56 -0
  38. data/lib/livereload_rails/railtie.rb +10 -0
  39. data/lib/livereload_rails/stream.rb +145 -0
  40. data/lib/livereload_rails/version.rb +3 -0
  41. data/lib/livereload_rails/watcher.rb +40 -0
  42. data/lib/livereload_rails/web_socket.rb +150 -0
  43. data/livereload_rails.gemspec +32 -0
  44. data/vendor/assets/javascripts/livereload.js +1183 -0
  45. metadata +229 -0
@@ -0,0 +1,32 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'livereload_rails/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "livereload_rails"
8
+ spec.version = LivereloadRails::VERSION
9
+ spec.authors = ["Kim Burgestrand", "Elabs"]
10
+ spec.email = ["kim@burgestrand.se", "dev@elabs.se"]
11
+
12
+ spec.summary = %q{Easy livereloading of assets for Rails.}
13
+ spec.homepage = "https://github.com/Burgestrand/livereload_rails"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
17
+ spec.bindir = "exe"
18
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_runtime_dependency "filewatcher", "~> 0"
22
+ spec.add_runtime_dependency "websocket", "~> 0"
23
+ spec.add_runtime_dependency "nio4r", "~> 0"
24
+ spec.add_runtime_dependency "puma", "~> 0"
25
+ spec.add_runtime_dependency "rack-livereload", "~> 0"
26
+ spec.add_runtime_dependency "railties", "~> 4.0"
27
+
28
+ spec.add_development_dependency "pry"
29
+ spec.add_development_dependency "bundler", "~> 1.8"
30
+ spec.add_development_dependency "rake", "~> 10.0"
31
+ spec.add_development_dependency "rspec", "~> 3.0"
32
+ end
@@ -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]);