use the very last version of the mounter (1.4.1) + remove guard-livereload from Wagon (it has to be used separately)
did
committed May 26, 2014
commit 0143d733d50a88ad2a180ea8859917a78d04ccc3
Showing 13
changed files with
35 additions
and 1310 deletions
locomotive/wagon.rb b/lib/locomotive/wagon.rb
+23
-19
| @@ | @@ -77,10 +77,6 @@ module Locomotive |
| use_listen = !options[:disable_listen] | |
| - | # initialize the guard livereload server |
| - | require 'locomotive/wagon/misc/livereload' |
| - | livereload = Locomotive::Wagon::LiveReload.new(options.slice(:host)) |
| - | |
| if options[:force] | |
| begin | |
| self.stop(path) | |
| @@ | @@ -90,39 +86,47 @@ module Locomotive |
| end | |
| # TODO: new feature -> pick the right Rack handler (Thin, Puma, ...etc) | |
| - | server = self.thin_server(reader, options.slice(:host, :port, :disable_listen).merge(live_reload_port: livereload.port)) |
| + | server = self.thin_server(reader, options.slice(:host, :port, :disable_listen, :live_reload_port)) |
| if options[:daemonize] | |
| # very important to get the parent pid in order to differenciate the sub process from the parent one | |
| parent_pid = Process.pid | |
| - | server.log_file = File.join(File.expand_path(path), 'log', 'thin.log') |
| - | server.pid_file = File.join(File.expand_path(path), 'log', 'thin.pid') |
| + | # The Daemons gem closes all file descriptors when it daemonizes the process. So any logfiles that were opened before the Daemons block will be closed inside the forked process. |
| + | # So, close the current logger and set it up again when daemonized. |
| + | Locomotive::Wagon::Logger.close |
| + | |
| + | server.log_file = File.join(File.expand_path(path), 'log', 'server.log') |
| + | server.pid_file = File.join(File.expand_path(path), 'log', 'server.pid') |
| server.daemonize | |
| use_listen = Process.pid != parent_pid && !options[:disable_listen] | |
| - | end |
| - | listen_thread = Thread.new do |
| - | if use_listen |
| - | Locomotive::Wagon::Listen.instance.start(reader, livereload) |
| - | livereload.start |
| + | if Process.pid != parent_pid |
| + | # A "new logger" inside the daemon. |
| + | Locomotive::Wagon::Logger.setup(path, false) |
| end | |
| end | |
| - | server_thread = Thread.new { server.start } |
| + | # listen_thread = Thread.new do |
| + | Locomotive::Wagon::Listen.instance.start(reader) if use_listen |
| + | |
| + | server.start |
| + | # end |
| + | |
| + | # server_thread = Thread.new { server.start } |
| # hit Control + C to stop | |
| - | Signal.trap('INT') { EventMachine.stop } |
| - | Signal.trap('TERM') { EventMachine.stop } |
| + | # Signal.trap('INT') { EventMachine.stop } |
| + | # Signal.trap('TERM') { EventMachine.stop } |
| - | listen_thread.join |
| - | server_thread.join |
| + | # listen_thread.join |
| + | # server_thread.join |
| end | |
| end | |
| def self.stop(path) | |
| - | pid_file = File.join(File.expand_path(path), 'log', 'thin.pid') |
| + | pid_file = File.join(File.expand_path(path), 'log', 'server.pid') |
| pid = File.read(pid_file).to_i | |
| Process.kill('TERM', pid) | |
| end | |
| @@ | @@ -269,7 +273,7 @@ module Locomotive |
| # TODO: new feature -> pick the right Rack handler (Thin, Puma, ...etc) | |
| require 'thin' | |
| - | Thin::Server.new(options[:host], options[:port], { signals: false }, app).tap do |server| |
| + | Thin::Server.new(options[:host], options[:port], { signals: true }, app).tap do |server| |
| server.threaded = true | |
| end | |
| end | |
locomotive/wagon/cli.rb b/lib/locomotive/wagon/cli.rb
+1
-0
| @@ | @@ -238,6 +238,7 @@ module Locomotive |
| method_option :host, aliases: '-h', type: 'string', default: '0.0.0.0', desc: 'The host (address) of the Thin server' | |
| method_option :port, aliases: '-p', type: 'string', default: '3333', desc: 'The port of the Thin server' | |
| method_option :daemonize, aliases: '-d', type: 'boolean', default: false, desc: 'Run daemonized Thin server in the background' | |
| + | method_option :live_reload_port, aliases: '-l', type: 'string', default: false, desc: 'Include the Livereload javascript in each page' |
| method_option :force, aliases: '-f', type: 'boolean', default: false, desc: 'Stop the current daemonized Thin server if found before starting a new one' | |
| method_option :verbose, aliases: '-v', type: 'boolean', default: false, desc: 'display the full error stack trace if an error occurs' | |
| def serve(path = '.') | |
locomotive/wagon/listen.rb b/lib/locomotive/wagon/listen.rb
+3
-25
| @@ | @@ -3,15 +3,14 @@ require 'listen' |
| module Locomotive::Wagon | |
| class Listen | |
| - | attr_accessor :reader, :livereload |
| + | attr_accessor :reader |
| def self.instance | |
| @@instance = new | |
| end | |
| - | def start(reader, livereload) |
| - | self.reader = reader |
| - | self.livereload = livereload |
| + | def start(reader) |
| + | @reader = reader |
| self.definitions.each do |definition| | |
| self.apply(definition) | |
| @@ | @@ -35,8 +34,6 @@ module Locomotive::Wagon |
| resources = [*definition.last] | |
| names = resources.map { |n| "\"#{n}\"" }.join(', ') | |
| - | notify_livereload(definition, added + modified) |
| - | |
| unless resources.empty? | |
| Locomotive::Wagon::Logger.info "* Reloaded #{names} at #{Time.now}" | |
| @@ | @@ -58,25 +55,6 @@ module Locomotive::Wagon |
| listener.start | |
| end | |
| - | def notify_livereload(definition, files) |
| - | transformer = (case definition.first |
| - | when 'public' then lambda { |m| "/#{m[1]}"} |
| - | when 'app/views' then lambda { |m| "/#{m[2]}".sub(/\.liquid$/, '.html') } |
| - | else |
| - | nil |
| - | end) |
| - | |
| - | paths = files.map do |file| |
| - | if transformer && (matches = file.match(definition[1])) |
| - | transformer.call(matches) |
| - | else |
| - | file |
| - | end |
| - | end |
| - | |
| - | livereload.run_on_modifications(paths) |
| - | end |
| - | |
| def relative_path(path) | |
| base_path = self.reader.mounting_point.path | |
| relative_path = path.sub(base_path, '') | |
locomotive/wagon/logger.rb b/lib/locomotive/wagon/logger.rb
+4
-0
| @@ | @@ -40,6 +40,10 @@ module Locomotive |
| self.instance.setup(path, stdout) | |
| end | |
| + | def self.close |
| + | self.instance.logger.close |
| + | end |
| + | |
| class << self | |
| %w(debug info warn error fatal unknown).each do |name| | |
| define_method(name) do |message| | |
locomotive/wagon/server.rb b/lib/locomotive/wagon/server.rb
+1
-1
| @@ | @@ -44,7 +44,7 @@ module Locomotive::Wagon |
| def create_rack_app(reader, options) | |
| Rack::Builder.new do | |
| - | use Rack::LiveReload, live_reload_port: options[:live_reload_port] unless options[:use_listen] |
| + | use Rack::LiveReload, live_reload_port: options[:live_reload_port] if options[:live_reload_port] |
| use Rack::Lint | |
locomotivecms_wagon.gemspec
+3
-5
| @@ | @@ -15,12 +15,12 @@ Gem::Specification.new do |gem| |
| gem.files = `git ls-files`.split($/) | |
| gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) } | |
| gem.test_files = gem.files.grep(%r{^(test|spec|features)/}) | |
| - | gem.require_paths = ['lib', 'vendor'] |
| + | gem.require_paths = ['lib'] |
| gem.executables = ['wagon'] | |
| gem.add_dependency 'thor' | |
| gem.add_dependency 'thin', '~> 1.6.1' | |
| - | gem.add_dependency 'activesupport', '~> 3.2.11' |
| + | gem.add_dependency 'activesupport', '~> 3.2.18' |
| gem.add_dependency 'locomotivecms-solid', '~> 0.2.2.1' | |
| gem.add_dependency 'RedCloth', '~> 4.2.8' | |
| gem.add_dependency 'redcarpet', '~> 3.0.0' | |
| @@ | @@ -33,13 +33,11 @@ Gem::Specification.new do |gem| |
| gem.add_dependency 'netrc', '~> 0.7.7' | |
| gem.add_dependency 'listen', '~> 2.7.5' | |
| - | gem.add_dependency 'em-websocket', '~> 0.5' |
| gem.add_dependency 'rack-livereload', '~> 0.3.15' | |
| - | # gem.add_dependency 'multi_json', '~> 1.8' |
| gem.add_dependency 'httmultiparty', '0.3.10' | |
| gem.add_dependency 'will_paginate', '~> 3.0.3' | |
| - | gem.add_dependency 'locomotivecms_mounter', '~> 1.4.0' |
| + | gem.add_dependency 'locomotivecms_mounter', '~> 1.4.1' |
| gem.add_dependency 'faker', '~> 0.9.5' | |
vendor/guard/LICENSE.txt
+0
-22
| @@ | @@ -1,22 +0,0 @@ |
| - | Copyright (c) 2013 Thibaud Guillaume-Gentil |
| - | |
| - | MIT License |
| - | |
| - | Permission is hereby granted, free of charge, to any person obtaining |
| - | a copy of this software and associated documentation files (the |
| - | "Software"), to deal in the Software without restriction, including |
| - | without limitation the rights to use, copy, modify, merge, publish, |
| - | distribute, sublicense, and/or sell copies of the Software, and to |
| - | permit persons to whom the Software is furnished to do so, subject to |
| - | the following conditions: |
| - | |
| - | The above copyright notice and this permission notice shall be |
| - | included in all copies or substantial portions of the Software. |
| - | |
| - | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
| - | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
| - | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
| - | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE |
| - | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION |
| - | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION |
| - | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
vendor/guard/livereload.rb
+0
-36
| @@ | @@ -1,36 +0,0 @@ |
| - | # Copied from https://github.com/guard/guard-livereload |
| - | # and customized to make it work outside the whole Guard stack. |
| - | |
| - | module Guard |
| - | class LiveReload < Plugin |
| - | require 'guard/livereload/websocket' |
| - | require 'guard/livereload/reactor' |
| - | |
| - | attr_accessor :reactor, :options |
| - | |
| - | def initialize(options = {}) |
| - | super |
| - | @options = { |
| - | host: '0.0.0.0', |
| - | port: '35729', |
| - | apply_css_live: true, |
| - | override_url: false, |
| - | grace_period: 0 |
| - | }.merge(options) |
| - | end |
| - | |
| - | def start |
| - | @reactor = Reactor.new(options) |
| - | end |
| - | |
| - | def stop |
| - | reactor.stop |
| - | end |
| - | |
| - | def run_on_modifications(paths) |
| - | sleep options[:grace_period] |
| - | reactor.reload_browser(paths) |
| - | end |
| - | |
| - | end |
| - | end |
vendor/guard/livereload/js/livereload.js
+0
-1055
| @@ | @@ -1,1055 +0,0 @@ |
| - | (function() { |
| - | var __customevents = {}, __protocol = {}, __connector = {}, __timer = {}, __options = {}, __reloader = {}, __livereload = {}, __less = {}, __startup = {}; |
| - | |
| - | // customevents |
| - | var CustomEvents; |
| - | CustomEvents = { |
| - | bind: function(element, eventName, handler) { |
| - | if (element.addEventListener) { |
| - | return element.addEventListener(eventName, handler, false); |
| - | } else if (element.attachEvent) { |
| - | element[eventName] = 1; |
| - | return element.attachEvent('onpropertychange', function(event) { |
| - | if (event.propertyName === eventName) { |
| - | return handler(); |
| - | } |
| - | }); |
| - | } else { |
| - | throw new Error("Attempt to attach custom event " + eventName + " to something which isn't a DOMElement"); |
| - | } |
| - | }, |
| - | fire: function(element, eventName) { |
| - | var event; |
| - | if (element.addEventListener) { |
| - | event = document.createEvent('HTMLEvents'); |
| - | event.initEvent(eventName, true, true); |
| - | return document.dispatchEvent(event); |
| - | } else if (element.attachEvent) { |
| - | if (element[eventName]) { |
| - | return element[eventName]++; |
| - | } |
| - | } else { |
| - | throw new Error("Attempt to fire custom event " + eventName + " on something which isn't a DOMElement"); |
| - | } |
| - | } |
| - | }; |
| - | __customevents.bind = CustomEvents.bind; |
| - | __customevents.fire = CustomEvents.fire; |
| - | |
| - | // protocol |
| - | var PROTOCOL_6, PROTOCOL_7, Parser, ProtocolError; |
| - | var __indexOf = Array.prototype.indexOf || function(item) { |
| - | for (var i = 0, l = this.length; i < l; i++) { |
| - | if (this[i] === item) return i; |
| - | } |
| - | return -1; |
| - | }; |
| - | __protocol.PROTOCOL_6 = PROTOCOL_6 = 'http://livereload.com/protocols/official-6'; |
| - | __protocol.PROTOCOL_7 = PROTOCOL_7 = 'http://livereload.com/protocols/official-7'; |
| - | __protocol.ProtocolError = ProtocolError = (function() { |
| - | function ProtocolError(reason, data) { |
| - | this.message = "LiveReload protocol error (" + reason + ") after receiving data: \"" + data + "\"."; |
| - | } |
| - | return ProtocolError; |
| - | })(); |
| - | __protocol.Parser = Parser = (function() { |
| - | function Parser(handlers) { |
| - | this.handlers = handlers; |
| - | this.reset(); |
| - | } |
| - | Parser.prototype.reset = function() { |
| - | return this.protocol = null; |
| - | }; |
| - | Parser.prototype.process = function(data) { |
| - | var command, message, options, _ref; |
| - | try { |
| - | if (!(this.protocol != null)) { |
| - | if (data.match(/^!!ver:([\d.]+)$/)) { |
| - | this.protocol = 6; |
| - | } else if (message = this._parseMessage(data, ['hello'])) { |
| - | if (!message.protocols.length) { |
| - | throw new ProtocolError("no protocols specified in handshake message"); |
| - | } else if (__indexOf.call(message.protocols, PROTOCOL_7) >= 0) { |
| - | this.protocol = 7; |
| - | } else if (__indexOf.call(message.protocols, PROTOCOL_6) >= 0) { |
| - | this.protocol = 6; |
| - | } else { |
| - | throw new ProtocolError("no supported protocols found"); |
| - | } |
| - | } |
| - | return this.handlers.connected(this.protocol); |
| - | } else if (this.protocol === 6) { |
| - | message = JSON.parse(data); |
| - | if (!message.length) { |
| - | throw new ProtocolError("protocol 6 messages must be arrays"); |
| - | } |
| - | command = message[0], options = message[1]; |
| - | if (command !== 'refresh') { |
| - | throw new ProtocolError("unknown protocol 6 command"); |
| - | } |
| - | return this.handlers.message({ |
| - | command: 'reload', |
| - | path: options.path, |
| - | liveCSS: (_ref = options.apply_css_live) != null ? _ref : true |
| - | }); |
| - | } else { |
| - | message = this._parseMessage(data, ['reload', 'alert']); |
| - | return this.handlers.message(message); |
| - | } |
| - | } catch (e) { |
| - | if (e instanceof ProtocolError) { |
| - | return this.handlers.error(e); |
| - | } else { |
| - | throw e; |
| - | } |
| - | } |
| - | }; |
| - | Parser.prototype._parseMessage = function(data, validCommands) { |
| - | var message, _ref; |
| - | try { |
| - | message = JSON.parse(data); |
| - | } catch (e) { |
| - | throw new ProtocolError('unparsable JSON', data); |
| - | } |
| - | if (!message.command) { |
| - | throw new ProtocolError('missing "command" key', data); |
| - | } |
| - | if (_ref = message.command, __indexOf.call(validCommands, _ref) < 0) { |
| - | throw new ProtocolError("invalid command '" + message.command + "', only valid commands are: " + (validCommands.join(', ')) + ")", data); |
| - | } |
| - | return message; |
| - | }; |
| - | return Parser; |
| - | })(); |
| - | |
| - | // connector |
| - | // Generated by CoffeeScript 1.3.3 |
| - | var Connector, PROTOCOL_6, PROTOCOL_7, Parser, Version, _ref; |
| - | |
| - | _ref = __protocol, Parser = _ref.Parser, PROTOCOL_6 = _ref.PROTOCOL_6, PROTOCOL_7 = _ref.PROTOCOL_7; |
| - | |
| - | 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; |
| - | this.handlers = handlers; |
| - | this._uri = "ws://" + this.options.host + ":" + this.options.port + "/livereload"; |
| - | this._nextDelay = this.options.mindelay; |
| - | this._connectionDesired = false; |
| - | this.protocol = 0; |
| - | this.protocolParser = new Parser({ |
| - | 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(function() { |
| - | if (!_this._isSocketConnected()) { |
| - | return; |
| - | } |
| - | _this._disconnectionReason = 'handshake-timeout'; |
| - | return _this.socket.close(); |
| - | }); |
| - | this._reconnectTimer = new Timer(function() { |
| - | if (!_this._connectionDesired) { |
| - | return; |
| - | } |
| - | 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; |
| - | } |
| - | this._reconnectTimer.stop(); |
| - | this._disconnectionReason = 'cannot-connect'; |
| - | this.protocolParser.reset(); |
| - | this.handlers.connecting(); |
| - | this.socket = new this.WebSocket(this._uri); |
| - | 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(); |
| - | if (!this._isSocketConnected()) { |
| - | return; |
| - | } |
| - | this._disconnectionReason = 'manual'; |
| - | return this.socket.close(); |
| - | }; |
| - | |
| - | Connector.prototype._scheduleReconnection = function() { |
| - | if (!this._connectionDesired) { |
| - | return; |
| - | } |
| - | if (!this._reconnectTimer.running) { |
| - | this._reconnectTimer.start(this._nextDelay); |
| - | 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(); |
| - | this._disconnectionReason = 'handshake-failed'; |
| - | hello = { |
| - | command: 'hello', |
| - | protocols: [PROTOCOL_6, PROTOCOL_7] |
| - | }; |
| - | hello.ver = Version; |
| - | if (this.options.ext) { |
| - | hello.ext = this.options.ext; |
| - | } |
| - | if (this.options.extver) { |
| - | hello.extver = this.options.extver; |
| - | } |
| - | if (this.options.snipver) { |
| - | hello.snipver = this.options.snipver; |
| - | } |
| - | this._sendCommand(hello); |
| - | return this._handshakeTimeout.start(this.options.handshake_timeout); |
| - | }; |
| - | |
| - | 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 |
| - | var Timer; |
| - | var __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }; |
| - | __timer.Timer = Timer = (function() { |
| - | function Timer(func) { |
| - | this.func = func; |
| - | this.running = false; |
| - | this.id = null; |
| - | this._handler = __bind(function() { |
| - | this.running = false; |
| - | this.id = null; |
| - | return this.func(); |
| - | }, this); |
| - | } |
| - | Timer.prototype.start = function(timeout) { |
| - | if (this.running) { |
| - | clearTimeout(this.id); |
| - | } |
| - | this.id = setTimeout(this._handler, timeout); |
| - | return this.running = true; |
| - | }; |
| - | Timer.prototype.stop = function() { |
| - | if (this.running) { |
| - | clearTimeout(this.id); |
| - | this.running = false; |
| - | return this.id = null; |
| - | } |
| - | }; |
| - | return Timer; |
| - | })(); |
| - | Timer.start = function(timeout, func) { |
| - | return setTimeout(func, timeout); |
| - | }; |
| - | |
| - | // options |
| - | var Options; |
| - | __options.Options = Options = (function() { |
| - | function Options() { |
| - | this.host = null; |
| - | this.port = 35729; |
| - | this.snipver = null; |
| - | this.ext = null; |
| - | this.extver = null; |
| - | this.mindelay = 1000; |
| - | this.maxdelay = 60000; |
| - | this.handshake_timeout = 5000; |
| - | } |
| - | Options.prototype.set = function(name, value) { |
| - | switch (typeof this[name]) { |
| - | case 'undefined': |
| - | break; |
| - | case 'number': |
| - | return this[name] = +value; |
| - | default: |
| - | return this[name] = value; |
| - | } |
| - | }; |
| - | return Options; |
| - | })(); |
| - | Options.extract = function(document) { |
| - | var element, keyAndValue, m, mm, options, pair, src, _i, _j, _len, _len2, _ref, _ref2; |
| - | _ref = document.getElementsByTagName('script'); |
| - | for (_i = 0, _len = _ref.length; _i < _len; _i++) { |
| - | element = _ref[_i]; |
| - | if ((src = element.src) && (m = src.match(/^[^:]+:\/\/(.*)\/z?livereload\.js(?:\?(.*))?$/))) { |
| - | options = new Options(); |
| - | if (mm = m[1].match(/^([^\/:]+)(?::(\d+))?$/)) { |
| - | options.host = mm[1]; |
| - | if (mm[2]) { |
| - | options.port = parseInt(mm[2], 10); |
| - | } |
| - | } |
| - | if (m[2]) { |
| - | _ref2 = m[2].split('&'); |
| - | for (_j = 0, _len2 = _ref2.length; _j < _len2; _j++) { |
| - | pair = _ref2[_j]; |
| - | if ((keyAndValue = pair.split('=')).length > 1) { |
| - | options.set(keyAndValue[0].replace(/-/g, '_'), keyAndValue.slice(1).join('=')); |
| - | } |
| - | } |
| - | } |
| - | return options; |
| - | } |
| - | } |
| - | return null; |
| - | }; |
| - | |
| - | // reloader |
| - | // 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 ((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 |
| - | }; |
| - | } |
| - | } |
| - | 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.liveCSS) { |
| - | if (path.match(/\.css$/i)) { |
| - | if (this.reloadStylesheet(path)) { |
| - | 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, _len1, _len2, _len3, _ref, _ref1, _ref2, _ref3, _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, _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); |
| - | } |
| - | } |
| - | } |
| - | 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; |
| - | } |
| - | }; |
| - | |
| - | 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) { |
| - | 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, _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; |
| - | 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); |
| - | 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(); |
| - | } |
| - | _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; |
| - | |
| - | 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.location.href.match(/LR-verbose/) && this.window.console && this.window.console.log && this.window.console.error ? this.window.console : { |
| - | log: function() {}, |
| - | error: function() {} |
| - | }; |
| - | if (!(this.WebSocket = this.window.WebSocket || this.window.MozWebSocket)) { |
| - | console.error("LiveReload disabled because the browser does not seem to support web sockets"); |
| - | return; |
| - | } |
| - | if (!(this.options = Options.extract(this.window.document))) { |
| - | console.error("LiveReload disabled because it could not find its own <SCRIPT> tag"); |
| - | return; |
| - | } |
| - | this.reloader = new Reloader(this.window, this.console, Timer); |
| - | this.connector = new Connector(this.options, this.WebSocket, Timer, { |
| - | connecting: function() {}, |
| - | socketConnected: function() {}, |
| - | connected: function(protocol) { |
| - | var _base; |
| - | 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(); |
| - | }, |
| - | error: function(e) { |
| - | if (e instanceof ProtocolError) { |
| - | return console.log("" + e.message + "."); |
| - | } else { |
| - | return console.log("LiveReload internal error: " + e.message); |
| - | } |
| - | }, |
| - | disconnected: function(reason, nextDelay) { |
| - | var _base; |
| - | 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."); |
| - | case 'broken': |
| - | 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."); |
| - | case 'handshake-failed': |
| - | 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."); |
| - | } |
| - | }, |
| - | message: function(message) { |
| - | switch (message.command) { |
| - | case 'reload': |
| - | return _this.performReload(message); |
| - | case 'alert': |
| - | return _this.performAlert(message); |
| - | } |
| - | } |
| - | }); |
| - | } |
| - | |
| - | 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 || '', |
| - | 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; |
| - | var _this = this; |
| - | if (this.hasPlugin(pluginClass.identifier)) return; |
| - | this.pluginIdentifiers[pluginClass.identifier] = true; |
| - | plugin = new pluginClass(this.window, { |
| - | _livereload: this, |
| - | _reloader: this.reloader, |
| - | _connector: this.connector, |
| - | console: this.console, |
| - | Timer: Timer, |
| - | generateCacheBustUrl: 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; |
| - | pluginsData = {}; |
| - | _ref = this.plugins; |
| - | for (_i = 0, _len = _ref.length; _i < _len; _i++) { |
| - | plugin = _ref[_i]; |
| - | pluginsData[plugin.constructor.identifier] = pluginData = (typeof plugin.analyze === "function" ? plugin.analyze() : void 0) || {}; |
| - | pluginData.version = plugin.constructor.version; |
| - | } |
| - | this.connector.sendCommand({ |
| - | command: 'info', |
| - | plugins: pluginsData, |
| - | url: this.window.location.href |
| - | }); |
| - | }; |
| - | |
| - | return LiveReload; |
| - | |
| - | })(); |
| - | |
| - | // less |
| - | var LessPlugin; |
| - | __less = LessPlugin = (function() { |
| - | LessPlugin.identifier = 'less'; |
| - | LessPlugin.version = '1.0'; |
| - | function LessPlugin(window, host) { |
| - | this.window = window; |
| - | this.host = host; |
| - | } |
| - | LessPlugin.prototype.reload = function(path, options) { |
| - | if (this.window.less && this.window.less.refresh) { |
| - | if (path.match(/\.less$/i)) { |
| - | return this.reloadLess(path); |
| - | } |
| - | if (options.originalPath.match(/\.less$/i)) { |
| - | return this.reloadLess(options.originalPath); |
| - | } |
| - | } |
| - | return false; |
| - | }; |
| - | LessPlugin.prototype.reloadLess = function(path) { |
| - | var link, links, _i, _len; |
| - | links = (function() { |
| - | var _i, _len, _ref, _results; |
| - | _ref = document.getElementsByTagName('link'); |
| - | _results = []; |
| - | for (_i = 0, _len = _ref.length; _i < _len; _i++) { |
| - | link = _ref[_i]; |
| - | if (link.href && link.rel === 'stylesheet/less' || (link.rel.match(/stylesheet/) && link.type.match(/^text\/(x-)?less$/))) { |
| - | _results.push(link); |
| - | } |
| - | } |
| - | return _results; |
| - | })(); |
| - | if (links.length === 0) { |
| - | return false; |
| - | } |
| - | for (_i = 0, _len = links.length; _i < _len; _i++) { |
| - | link = links[_i]; |
| - | link.href = this.host.generateCacheBustUrl(link.href); |
| - | } |
| - | this.host.console.log("LiveReload is asking LESS to recompile all stylesheets"); |
| - | this.window.less.refresh(true); |
| - | return true; |
| - | }; |
| - | LessPlugin.prototype.analyze = function() { |
| - | return { |
| - | disable: !!(this.window.less && this.window.less.refresh) |
| - | }; |
| - | }; |
| - | return LessPlugin; |
| - | })(); |
| - | |
| - | // startup |
| - | var CustomEvents, LiveReload, k; |
| - | CustomEvents = __customevents; |
| - | LiveReload = window.LiveReload = new (__livereload.LiveReload)(window); |
| - | for (k in window) { |
| - | if (k.match(/^LiveReloadPlugin/)) { |
| - | LiveReload.addPlugin(window[k]); |
| - | } |
| - | } |
| - | LiveReload.addPlugin(__less); |
| - | LiveReload.on('shutdown', function() { |
| - | return delete window.LiveReload; |
| - | }); |
| - | LiveReload.on('connect', function() { |
| - | return CustomEvents.fire(document, 'LiveReloadConnect'); |
| - | }); |
| - | LiveReload.on('disconnect', function() { |
| - | return CustomEvents.fire(document, 'LiveReloadDisconnect'); |
| - | }); |
| - | CustomEvents.bind(document, 'LiveReloadShutDown', function() { |
| - | return LiveReload.shutDown(); |
| - | }); |
| - | })(); |
| \ No newline at end of file | |
vendor/guard/livereload/reactor.rb
+0
-80
| @@ | @@ -1,80 +0,0 @@ |
| - | require 'multi_json' |
| - | |
| - | module Guard |
| - | class LiveReload |
| - | class Reactor |
| - | attr_reader :web_sockets, :thread, :options, :connections_count |
| - | |
| - | def initialize(options) |
| - | @web_sockets = [] |
| - | @options = options |
| - | @thread = Thread.new { _start_reactor } |
| - | @connections_count = 0 |
| - | end |
| - | |
| - | def stop |
| - | thread.kill |
| - | end |
| - | |
| - | def reload_browser(paths = []) |
| - | UI.info "Reloading browser: #{paths.join(' ')}" |
| - | paths.each do |path| |
| - | data = _data(path) |
| - | UI.debug(data) |
| - | web_sockets.each { |ws| ws.send(MultiJson.encode(data)) } |
| - | end |
| - | end |
| - | |
| - | private |
| - | |
| - | def _data(path) |
| - | data = { |
| - | command: 'reload', |
| - | path: "#{Dir.pwd}/#{path}", |
| - | liveCSS: options[:apply_css_live] |
| - | } |
| - | if options[:override_url] && File.exist?(path) |
| - | data[:overrideURL] = '/' + path |
| - | end |
| - | data |
| - | end |
| - | |
| - | def _start_reactor |
| - | EventMachine.epoll |
| - | EventMachine.run do |
| - | EventMachine.start_server(options[:host], options[:port], WebSocket, {}) do |ws| |
| - | ws.onopen { _connect(ws) } |
| - | ws.onclose { _disconnect(ws) } |
| - | ws.onmessage { |msg| _print_message(msg) } |
| - | end |
| - | UI.info "LiveReload is waiting for a browser to connect." |
| - | end |
| - | end |
| - | |
| - | def _connect(ws) |
| - | @connections_count += 1 |
| - | UI.info "Browser connected." if connections_count == 1 |
| - | |
| - | ws.send MultiJson.encode( |
| - | command: 'hello', |
| - | protocols: ['http://livereload.com/protocols/official-7'], |
| - | serverName: 'guard-livereload' |
| - | ) |
| - | @web_sockets << ws |
| - | rescue |
| - | UI.error $! |
| - | UI.error $!.backtrace |
| - | end |
| - | |
| - | def _disconnect(ws) |
| - | @web_sockets.delete(ws) |
| - | end |
| - | |
| - | def _print_message(message) |
| - | message = MultiJson.decode(message) |
| - | UI.info "Browser URL: #{message['url']}" if message['command'] == 'url' |
| - | end |
| - | |
| - | end |
| - | end |
| - | end |
vendor/guard/livereload/templates/Guardfile
+0
-8
| @@ | @@ -1,8 +0,0 @@ |
| - | guard 'livereload' do |
| - | watch(%r{app/views/.+\.(erb|haml|slim)$}) |
| - | watch(%r{app/helpers/.+\.rb}) |
| - | watch(%r{public/.+\.(css|js|html)}) |
| - | watch(%r{config/locales/.+\.yml}) |
| - | # Rails Assets Pipeline |
| - | watch(%r{(app|vendor)(/assets/\w+/(.+\.(css|js|html|png|jpg))).*}) { |m| "/assets/#{m[3]}" } |
| - | end |
vendor/guard/livereload/version.rb
+0
-5
| @@ | @@ -1,5 +0,0 @@ |
| - | module Guard |
| - | module LiveReloadVersion |
| - | VERSION = '2.2.0' |
| - | end |
| - | end |
vendor/guard/livereload/websocket.rb
+0
-54
| @@ | @@ -1,54 +0,0 @@ |
| - | require 'eventmachine' |
| - | require 'em-websocket' |
| - | require 'http/parser' |
| - | require 'uri' |
| - | |
| - | module Guard |
| - | class LiveReload |
| - | class WebSocket < EventMachine::WebSocket::Connection |
| - | |
| - | def dispatch(data) |
| - | parser = Http::Parser.new |
| - | parser << data |
| - | # prepend with '.' to make request url usable as a file path |
| - | request_path = '.' + URI.parse(parser.request_url).path |
| - | request_path += '/index.html' if File.directory? request_path |
| - | if parser.http_method != 'GET' || parser.upgrade? |
| - | super #pass the request to websocket |
| - | elsif request_path == './livereload.js' |
| - | _serve_file(_livereload_js_file) |
| - | elsif File.readable?(request_path) && !File.directory?(request_path) |
| - | _serve_file(request_path) |
| - | else |
| - | send_data("HTTP/1.1 404 Not Found\r\nContent-Type: text/plain\r\nContent-Length: 13\r\n\r\n404 Not Found") |
| - | close_connection_after_writing |
| - | end |
| - | end |
| - | |
| - | private |
| - | |
| - | def _serve_file(path) |
| - | UI.debug "Serving file #{path}" |
| - | send_data "HTTP/1.1 200 OK\r\nContent-Type: #{_content_type(path)}\r\nContent-Length: #{File.size path}\r\n\r\n" |
| - | stream_file_data(path).callback { close_connection_after_writing } |
| - | end |
| - | |
| - | def _content_type(path) |
| - | case File.extname(path).downcase |
| - | when '.html', '.htm' then 'text/html' |
| - | when '.css' then 'text/css' |
| - | when '.js' then 'application/ecmascript' |
| - | when '.gif' then 'image/gif' |
| - | when '.jpeg', '.jpg' then 'image/jpeg' |
| - | when '.png' then 'image/png' |
| - | else; 'text/plain' |
| - | end |
| - | end |
| - | |
| - | def _livereload_js_file |
| - | File.expand_path("../js/livereload.js", __FILE__) |
| - | end |
| - | |
| - | end |
| - | end |
| - | end |