hawkins 0.1.0 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/.rubocop.yml +31 -6
- data/LICENSE.txt +2 -0
- data/README.md +43 -14
- data/Rakefile +13 -10
- data/hawkins.gemspec +7 -11
- data/js/WebSocketMain.swf +0 -0
- data/js/livereload.js +1055 -0
- data/js/swfobject.js +4 -0
- data/js/web_socket.js +379 -0
- data/lib/hawkins.rb +6 -40
- data/lib/hawkins/liveserve.rb +250 -0
- data/lib/hawkins/post.rb +86 -0
- data/lib/hawkins/servlet.rb +154 -0
- data/lib/hawkins/version.rb +1 -1
- data/lib/hawkins/websockets.rb +160 -0
- data/lib/mime.types +800 -0
- data/test/resources/test.crt +18 -0
- data/test/resources/test.key +28 -0
- data/test/spec_helper.rb +13 -10
- data/test/test_liveserve.rb +166 -0
- data/test/test_post.rb +171 -0
- metadata +50 -94
- data/lib/hawkins/cli.rb +0 -190
- data/lib/hawkins/guard.rb +0 -268
- data/lib/hawkins/isolation.rb +0 -116
- data/test/test_hawkins.rb +0 -134
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 67d903c96d4b57977e6b7239154a4ab38e45861d
|
4
|
+
data.tar.gz: 72d3dd1f828db27edeb7ca02e001543b144266b3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2efb3ba62d00d3de12e718ceb1bae29ab3fb7617fbb5a7875c5a321f0d2662a397cdc554b9ba1c4cab6acbde1b343eb86a4ffc31af8f7255d04d9c4c02e313ad
|
7
|
+
data.tar.gz: 3fd3f1bb25e2da6a05a26b4c30a6501c008e8e721f130293bf0326b968b30c389f19eb325b91011853b3e17e7b0179ef3e091f2c7e9f2f2cb24efbe6560b5642
|
data/.gitignore
CHANGED
data/.rubocop.yml
CHANGED
@@ -1,3 +1,9 @@
|
|
1
|
+
# http://www.rubydoc.info/gems/rubocop/0.36.0/RuboCop/Cop/Style/
|
2
|
+
|
3
|
+
AbcSize:
|
4
|
+
Enabled: false
|
5
|
+
AlignParameters:
|
6
|
+
EnforcedStyle: with_fixed_indentation
|
1
7
|
ClassLength:
|
2
8
|
# It's not worth bending over backwards to avoid long classes.
|
3
9
|
Enabled: false
|
@@ -7,11 +13,21 @@ CollectionMethods:
|
|
7
13
|
reduce: 'inject'
|
8
14
|
detect: 'find'
|
9
15
|
find_all: 'select'
|
16
|
+
CommandLiteral:
|
17
|
+
EnforcedStyle: percent_x
|
18
|
+
CommentAnnotation:
|
19
|
+
Enabled: false
|
20
|
+
ConditionalAssignment:
|
21
|
+
Enabled: false
|
10
22
|
CyclomaticComplexity:
|
11
23
|
Enabled: false
|
12
24
|
Documentation:
|
13
25
|
# TODO: We need to add a bunch of docs before we can enable this.
|
14
26
|
Enabled: false
|
27
|
+
EmptyLinesAroundAccessModifier:
|
28
|
+
Enabled: false
|
29
|
+
GuardClause:
|
30
|
+
Enabled: false
|
15
31
|
HashSyntax:
|
16
32
|
EnforcedStyle: hash_rockets
|
17
33
|
IfUnlessModifier:
|
@@ -20,13 +36,20 @@ LineLength:
|
|
20
36
|
Enabled: true
|
21
37
|
Max: 100
|
22
38
|
MethodLength:
|
23
|
-
|
24
|
-
CountComments: false
|
39
|
+
Enabled: false
|
25
40
|
ModuleFunction:
|
26
41
|
# The module_function declaration makes methods private so it means you can't use the module as a module.
|
27
42
|
Enabled: false
|
43
|
+
ModuleLength:
|
44
|
+
Enabled: false
|
45
|
+
NegatedWhile:
|
46
|
+
Enabled: false
|
47
|
+
NumericLiterals:
|
48
|
+
Enabled: false
|
28
49
|
ParenthesesAroundCondition:
|
29
50
|
AllowSafeAssignment: false
|
51
|
+
PerceivedComplexity:
|
52
|
+
Enabled: false
|
30
53
|
PerlBackrefs:
|
31
54
|
Enabled: false
|
32
55
|
RaiseArgs:
|
@@ -40,15 +63,17 @@ SignalException:
|
|
40
63
|
SpaceAroundEqualsInParameterDefault:
|
41
64
|
EnforcedStyle: no_space
|
42
65
|
SpaceInsideHashLiteralBraces:
|
43
|
-
EnforcedStyle:
|
66
|
+
EnforcedStyle: space
|
44
67
|
StringLiterals:
|
45
68
|
# They say to not use double quoted strings unless there is interpolation.
|
46
69
|
# While this gives a marginal parse time speedup, it makes working with
|
47
70
|
# strings annoying.
|
48
71
|
Enabled: false
|
49
|
-
|
50
|
-
Enabled:
|
51
|
-
|
72
|
+
TrailingCommaInArguments:
|
73
|
+
Enabled: false
|
74
|
+
TrailingCommaInLiteral:
|
75
|
+
EnforcedStyleForMultiline: comma
|
76
|
+
TrivialAccessors:
|
52
77
|
Enabled: false
|
53
78
|
WhileUntilModifier:
|
54
79
|
Enabled: false
|
data/LICENSE.txt
CHANGED
data/README.md
CHANGED
@@ -1,19 +1,48 @@
|
|
1
|
-
|
1
|
+
# Hawkins
|
2
|
+
Hawkins is a [Jekyll](http://jekyllrb.com) 3 plugin that incorporates
|
3
|
+
[LiveReload](http://www.livereload.com) into the Jekyll "serve" process.
|
2
4
|
|
3
|
-
|
5
|
+
## How to Use
|
6
|
+
Add the following into your `Gemfile`
|
4
7
|
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
* Start a feature/bugfix branch.
|
11
|
-
* Commit and push until you are happy with your contribution.
|
12
|
-
* Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
|
13
|
-
* Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.
|
8
|
+
```
|
9
|
+
group :jekyll_plugins do
|
10
|
+
gem 'hawkins'
|
11
|
+
end
|
12
|
+
```
|
14
13
|
|
15
|
-
|
14
|
+
Then run `jekyll liveserve` to serve your files. The `liveserve` commands takes
|
15
|
+
all the arguments that `serve` does but with a few extras that allow you to
|
16
|
+
specify the port that LiveReload runs on or how long LiveReload will wait. See
|
17
|
+
the --help for more information.
|
16
18
|
|
17
|
-
|
18
|
-
|
19
|
+
## How It Works
|
20
|
+
Hawkins uses a WEBrick servlet that automatically inserts a script tag into a
|
21
|
+
page's `head` section. The script tag points to a LiveReload server running on
|
22
|
+
the same host (by default on port 35729). That server serves `livereload.js`
|
23
|
+
over HTTP and also acts as a WebSockets server that speaks the LiveReload
|
24
|
+
protocol.
|
25
|
+
|
26
|
+
If you don't have a browser that implements WebSockets, you can use the
|
27
|
+
`--swf` option that will have Hawkins load a Flash file that implements
|
28
|
+
WebSockets.
|
29
|
+
|
30
|
+
## A Note on SSL/TLS
|
31
|
+
If you tell Jekyll to serve your files over SSL/TLS (by specifying the
|
32
|
+
`--ssl-cert` and `--ssl-key` options), then LiveReload will attempt to use
|
33
|
+
SSL/TLS as well. If you are using a certificate that a browser would not
|
34
|
+
normally accept (e.g. self-signed or issued by an unknown certificate
|
35
|
+
authority), you will need to create an exception for the server and port
|
36
|
+
that Jekyll is serving content over and also for the server and port that
|
37
|
+
LiveReload is running on. Generally speaking, these exceptions will be
|
38
|
+
"127.0.0.1:4000" and "127.0.0.1:35729".
|
39
|
+
|
40
|
+
## Thanks
|
41
|
+
Lots of thanks to [guard-livereload](https://github.com/guard/guard-livereload)
|
42
|
+
and [rack-livereload](https://github.com/johnbintz/rack-livereload) which
|
43
|
+
provided a lot of the code and ideas that Hawkins uses. And of course thanks to
|
44
|
+
the Jekyll team and LiveReload team for providing outstanding software.
|
45
|
+
|
46
|
+
## Copyright
|
47
|
+
Copyright (c) 2014 Alex Wood. See LICENSE.txt for further details.
|
19
48
|
|
data/Rakefile
CHANGED
@@ -16,17 +16,14 @@ require './lib/hawkins/version'
|
|
16
16
|
require 'rake'
|
17
17
|
require 'rdoc/task'
|
18
18
|
require 'rubocop/rake_task'
|
19
|
+
require 'rspec/core/rake_task'
|
19
20
|
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
t.rspec_opts = "--tag #{task_args[:tag]}" if task_args.key?(:tag)
|
24
|
-
t.pattern = "test/**/*.rb"
|
25
|
-
end
|
26
|
-
task :default => :spec
|
27
|
-
task :test => :spec
|
28
|
-
rescue LoadError
|
21
|
+
RSpec::Core::RakeTask.new(:spec, :tag) do |t, task_args|
|
22
|
+
t.rspec_opts = "--tag #{task_args[:tag]}" if task_args.key?(:tag)
|
23
|
+
t.pattern = "test/**/*.rb"
|
29
24
|
end
|
25
|
+
task :default => :spec
|
26
|
+
task :test => :spec
|
30
27
|
|
31
28
|
desc "Code coverage detail"
|
32
29
|
task :simplecov do
|
@@ -43,4 +40,10 @@ Rake::RDocTask.new do |rdoc|
|
|
43
40
|
rdoc.rdoc_files.include('lib/**/*.rb')
|
44
41
|
end
|
45
42
|
|
46
|
-
RuboCop::RakeTask.new
|
43
|
+
RuboCop::RakeTask.new do |task|
|
44
|
+
task.formatters = ['fuubar']
|
45
|
+
task.options = ['-D']
|
46
|
+
end
|
47
|
+
|
48
|
+
desc "Pre-commit checks"
|
49
|
+
task :check => [:rubocop, :spec]
|
data/hawkins.gemspec
CHANGED
@@ -8,7 +8,7 @@ Gem::Specification.new do |spec|
|
|
8
8
|
spec.version = Hawkins::VERSION
|
9
9
|
spec.authors = ["Alex Wood"]
|
10
10
|
spec.email = ["awood@redhat.com"]
|
11
|
-
spec.summary = "A Jekyll extension that adds in Live Reload
|
11
|
+
spec.summary = "A Jekyll extension that adds in Live Reload"
|
12
12
|
spec.homepage = "http://github.com/awood/hawkins"
|
13
13
|
spec.license = "MIT"
|
14
14
|
|
@@ -17,24 +17,20 @@ Gem::Specification.new do |spec|
|
|
17
17
|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
18
18
|
spec.require_paths = ["lib"]
|
19
19
|
|
20
|
-
spec.add_runtime_dependency("
|
21
|
-
spec.add_runtime_dependency("
|
22
|
-
spec.add_runtime_dependency("jekyll", "~> 2.5")
|
23
|
-
spec.add_runtime_dependency("rack")
|
24
|
-
spec.add_runtime_dependency("rack-livereload")
|
25
|
-
spec.add_runtime_dependency("safe_yaml")
|
26
|
-
spec.add_runtime_dependency("stringex")
|
27
|
-
spec.add_runtime_dependency("thin")
|
28
|
-
spec.add_runtime_dependency("thor")
|
20
|
+
spec.add_runtime_dependency("jekyll", "~> 3.0")
|
21
|
+
spec.add_runtime_dependency("em-websocket", "~> 0.5")
|
29
22
|
|
30
23
|
spec.add_development_dependency("bundler", "~> 1.6")
|
24
|
+
spec.add_development_dependency("httpclient")
|
31
25
|
spec.add_development_dependency("rspec-core")
|
32
26
|
spec.add_development_dependency("rspec-expectations")
|
33
27
|
spec.add_development_dependency("rspec-mocks")
|
28
|
+
spec.add_development_dependency("fuubar")
|
34
29
|
spec.add_development_dependency("rake")
|
35
30
|
spec.add_development_dependency("rdoc", "~> 3.12")
|
31
|
+
spec.add_development_dependency("pry-byebug")
|
36
32
|
# Rubocop can issue new releases with new checks which can result
|
37
33
|
# in errors we don't want. We'll manage the version very strictly.
|
38
|
-
spec.add_development_dependency("rubocop", "= 0.
|
34
|
+
spec.add_development_dependency("rubocop", "= 0.36.0")
|
39
35
|
spec.add_development_dependency("simplecov")
|
40
36
|
end
|
Binary file
|
data/js/livereload.js
ADDED
@@ -0,0 +1,1055 @@
|
|
1
|
+
(function() {
|
2
|
+
var __customevents = {}, __protocol = {}, __connector = {}, __timer = {}, __options = {}, __reloader = {}, __livereload = {}, __less = {}, __startup = {};
|
3
|
+
|
4
|
+
// customevents
|
5
|
+
var CustomEvents;
|
6
|
+
CustomEvents = {
|
7
|
+
bind: function(element, eventName, handler) {
|
8
|
+
if (element.addEventListener) {
|
9
|
+
return element.addEventListener(eventName, handler, false);
|
10
|
+
} else if (element.attachEvent) {
|
11
|
+
element[eventName] = 1;
|
12
|
+
return element.attachEvent('onpropertychange', function(event) {
|
13
|
+
if (event.propertyName === eventName) {
|
14
|
+
return handler();
|
15
|
+
}
|
16
|
+
});
|
17
|
+
} else {
|
18
|
+
throw new Error("Attempt to attach custom event " + eventName + " to something which isn't a DOMElement");
|
19
|
+
}
|
20
|
+
},
|
21
|
+
fire: function(element, eventName) {
|
22
|
+
var event;
|
23
|
+
if (element.addEventListener) {
|
24
|
+
event = document.createEvent('HTMLEvents');
|
25
|
+
event.initEvent(eventName, true, true);
|
26
|
+
return document.dispatchEvent(event);
|
27
|
+
} else if (element.attachEvent) {
|
28
|
+
if (element[eventName]) {
|
29
|
+
return element[eventName]++;
|
30
|
+
}
|
31
|
+
} else {
|
32
|
+
throw new Error("Attempt to fire custom event " + eventName + " on something which isn't a DOMElement");
|
33
|
+
}
|
34
|
+
}
|
35
|
+
};
|
36
|
+
__customevents.bind = CustomEvents.bind;
|
37
|
+
__customevents.fire = CustomEvents.fire;
|
38
|
+
|
39
|
+
// protocol
|
40
|
+
var PROTOCOL_6, PROTOCOL_7, Parser, ProtocolError;
|
41
|
+
var __indexOf = Array.prototype.indexOf || function(item) {
|
42
|
+
for (var i = 0, l = this.length; i < l; i++) {
|
43
|
+
if (this[i] === item) return i;
|
44
|
+
}
|
45
|
+
return -1;
|
46
|
+
};
|
47
|
+
__protocol.PROTOCOL_6 = PROTOCOL_6 = 'http://livereload.com/protocols/official-6';
|
48
|
+
__protocol.PROTOCOL_7 = PROTOCOL_7 = 'http://livereload.com/protocols/official-7';
|
49
|
+
__protocol.ProtocolError = ProtocolError = (function() {
|
50
|
+
function ProtocolError(reason, data) {
|
51
|
+
this.message = "LiveReload protocol error (" + reason + ") after receiving data: \"" + data + "\".";
|
52
|
+
}
|
53
|
+
return ProtocolError;
|
54
|
+
})();
|
55
|
+
__protocol.Parser = Parser = (function() {
|
56
|
+
function Parser(handlers) {
|
57
|
+
this.handlers = handlers;
|
58
|
+
this.reset();
|
59
|
+
}
|
60
|
+
Parser.prototype.reset = function() {
|
61
|
+
return this.protocol = null;
|
62
|
+
};
|
63
|
+
Parser.prototype.process = function(data) {
|
64
|
+
var command, message, options, _ref;
|
65
|
+
try {
|
66
|
+
if (!(this.protocol != null)) {
|
67
|
+
if (data.match(/^!!ver:([\d.]+)$/)) {
|
68
|
+
this.protocol = 6;
|
69
|
+
} else if (message = this._parseMessage(data, ['hello'])) {
|
70
|
+
if (!message.protocols.length) {
|
71
|
+
throw new ProtocolError("no protocols specified in handshake message");
|
72
|
+
} else if (__indexOf.call(message.protocols, PROTOCOL_7) >= 0) {
|
73
|
+
this.protocol = 7;
|
74
|
+
} else if (__indexOf.call(message.protocols, PROTOCOL_6) >= 0) {
|
75
|
+
this.protocol = 6;
|
76
|
+
} else {
|
77
|
+
throw new ProtocolError("no supported protocols found");
|
78
|
+
}
|
79
|
+
}
|
80
|
+
return this.handlers.connected(this.protocol);
|
81
|
+
} else if (this.protocol === 6) {
|
82
|
+
message = JSON.parse(data);
|
83
|
+
if (!message.length) {
|
84
|
+
throw new ProtocolError("protocol 6 messages must be arrays");
|
85
|
+
}
|
86
|
+
command = message[0], options = message[1];
|
87
|
+
if (command !== 'refresh') {
|
88
|
+
throw new ProtocolError("unknown protocol 6 command");
|
89
|
+
}
|
90
|
+
return this.handlers.message({
|
91
|
+
command: 'reload',
|
92
|
+
path: options.path,
|
93
|
+
liveCSS: (_ref = options.apply_css_live) != null ? _ref : true
|
94
|
+
});
|
95
|
+
} else {
|
96
|
+
message = this._parseMessage(data, ['reload', 'alert']);
|
97
|
+
return this.handlers.message(message);
|
98
|
+
}
|
99
|
+
} catch (e) {
|
100
|
+
if (e instanceof ProtocolError) {
|
101
|
+
return this.handlers.error(e);
|
102
|
+
} else {
|
103
|
+
throw e;
|
104
|
+
}
|
105
|
+
}
|
106
|
+
};
|
107
|
+
Parser.prototype._parseMessage = function(data, validCommands) {
|
108
|
+
var message, _ref;
|
109
|
+
try {
|
110
|
+
message = JSON.parse(data);
|
111
|
+
} catch (e) {
|
112
|
+
throw new ProtocolError('unparsable JSON', data);
|
113
|
+
}
|
114
|
+
if (!message.command) {
|
115
|
+
throw new ProtocolError('missing "command" key', data);
|
116
|
+
}
|
117
|
+
if (_ref = message.command, __indexOf.call(validCommands, _ref) < 0) {
|
118
|
+
throw new ProtocolError("invalid command '" + message.command + "', only valid commands are: " + (validCommands.join(', ')) + ")", data);
|
119
|
+
}
|
120
|
+
return message;
|
121
|
+
};
|
122
|
+
return Parser;
|
123
|
+
})();
|
124
|
+
|
125
|
+
// connector
|
126
|
+
// Generated by CoffeeScript 1.3.3
|
127
|
+
var Connector, PROTOCOL_6, PROTOCOL_7, Parser, Version, _ref;
|
128
|
+
|
129
|
+
_ref = __protocol, Parser = _ref.Parser, PROTOCOL_6 = _ref.PROTOCOL_6, PROTOCOL_7 = _ref.PROTOCOL_7;
|
130
|
+
|
131
|
+
Version = '2.0.8';
|
132
|
+
|
133
|
+
__connector.Connector = Connector = (function() {
|
134
|
+
|
135
|
+
function Connector(options, WebSocket, Timer, handlers) {
|
136
|
+
var _this = this;
|
137
|
+
this.options = options;
|
138
|
+
this.WebSocket = WebSocket;
|
139
|
+
this.Timer = Timer;
|
140
|
+
this.handlers = handlers;
|
141
|
+
this._uri = HAWKINS_LIVERELOAD_PROTOCOL + this.options.host + ":" + this.options.port + "/livereload";
|
142
|
+
this._nextDelay = this.options.mindelay;
|
143
|
+
this._connectionDesired = false;
|
144
|
+
this.protocol = 0;
|
145
|
+
this.protocolParser = new Parser({
|
146
|
+
connected: function(protocol) {
|
147
|
+
_this.protocol = protocol;
|
148
|
+
_this._handshakeTimeout.stop();
|
149
|
+
_this._nextDelay = _this.options.mindelay;
|
150
|
+
_this._disconnectionReason = 'broken';
|
151
|
+
return _this.handlers.connected(protocol);
|
152
|
+
},
|
153
|
+
error: function(e) {
|
154
|
+
_this.handlers.error(e);
|
155
|
+
return _this._closeOnError();
|
156
|
+
},
|
157
|
+
message: function(message) {
|
158
|
+
return _this.handlers.message(message);
|
159
|
+
}
|
160
|
+
});
|
161
|
+
this._handshakeTimeout = new Timer(function() {
|
162
|
+
if (!_this._isSocketConnected()) {
|
163
|
+
return;
|
164
|
+
}
|
165
|
+
_this._disconnectionReason = 'handshake-timeout';
|
166
|
+
return _this.socket.close();
|
167
|
+
});
|
168
|
+
this._reconnectTimer = new Timer(function() {
|
169
|
+
if (!_this._connectionDesired) {
|
170
|
+
return;
|
171
|
+
}
|
172
|
+
return _this.connect();
|
173
|
+
});
|
174
|
+
this.connect();
|
175
|
+
}
|
176
|
+
|
177
|
+
Connector.prototype._isSocketConnected = function() {
|
178
|
+
return this.socket && this.socket.readyState === this.WebSocket.OPEN;
|
179
|
+
};
|
180
|
+
|
181
|
+
Connector.prototype.connect = function() {
|
182
|
+
var _this = this;
|
183
|
+
this._connectionDesired = true;
|
184
|
+
if (this._isSocketConnected()) {
|
185
|
+
return;
|
186
|
+
}
|
187
|
+
this._reconnectTimer.stop();
|
188
|
+
this._disconnectionReason = 'cannot-connect';
|
189
|
+
this.protocolParser.reset();
|
190
|
+
this.handlers.connecting();
|
191
|
+
this.socket = new this.WebSocket(this._uri);
|
192
|
+
this.socket.onopen = function(e) {
|
193
|
+
return _this._onopen(e);
|
194
|
+
};
|
195
|
+
this.socket.onclose = function(e) {
|
196
|
+
return _this._onclose(e);
|
197
|
+
};
|
198
|
+
this.socket.onmessage = function(e) {
|
199
|
+
return _this._onmessage(e);
|
200
|
+
};
|
201
|
+
return this.socket.onerror = function(e) {
|
202
|
+
return _this._onerror(e);
|
203
|
+
};
|
204
|
+
};
|
205
|
+
|
206
|
+
Connector.prototype.disconnect = function() {
|
207
|
+
this._connectionDesired = false;
|
208
|
+
this._reconnectTimer.stop();
|
209
|
+
if (!this._isSocketConnected()) {
|
210
|
+
return;
|
211
|
+
}
|
212
|
+
this._disconnectionReason = 'manual';
|
213
|
+
return this.socket.close();
|
214
|
+
};
|
215
|
+
|
216
|
+
Connector.prototype._scheduleReconnection = function() {
|
217
|
+
if (!this._connectionDesired) {
|
218
|
+
return;
|
219
|
+
}
|
220
|
+
if (!this._reconnectTimer.running) {
|
221
|
+
this._reconnectTimer.start(this._nextDelay);
|
222
|
+
return this._nextDelay = Math.min(this.options.maxdelay, this._nextDelay * 2);
|
223
|
+
}
|
224
|
+
};
|
225
|
+
|
226
|
+
Connector.prototype.sendCommand = function(command) {
|
227
|
+
if (this.protocol == null) {
|
228
|
+
return;
|
229
|
+
}
|
230
|
+
return this._sendCommand(command);
|
231
|
+
};
|
232
|
+
|
233
|
+
Connector.prototype._sendCommand = function(command) {
|
234
|
+
return this.socket.send(JSON.stringify(command));
|
235
|
+
};
|
236
|
+
|
237
|
+
Connector.prototype._closeOnError = function() {
|
238
|
+
this._handshakeTimeout.stop();
|
239
|
+
this._disconnectionReason = 'error';
|
240
|
+
return this.socket.close();
|
241
|
+
};
|
242
|
+
|
243
|
+
Connector.prototype._onopen = function(e) {
|
244
|
+
var hello;
|
245
|
+
this.handlers.socketConnected();
|
246
|
+
this._disconnectionReason = 'handshake-failed';
|
247
|
+
hello = {
|
248
|
+
command: 'hello',
|
249
|
+
protocols: [PROTOCOL_6, PROTOCOL_7]
|
250
|
+
};
|
251
|
+
hello.ver = Version;
|
252
|
+
if (this.options.ext) {
|
253
|
+
hello.ext = this.options.ext;
|
254
|
+
}
|
255
|
+
if (this.options.extver) {
|
256
|
+
hello.extver = this.options.extver;
|
257
|
+
}
|
258
|
+
if (this.options.snipver) {
|
259
|
+
hello.snipver = this.options.snipver;
|
260
|
+
}
|
261
|
+
this._sendCommand(hello);
|
262
|
+
return this._handshakeTimeout.start(this.options.handshake_timeout);
|
263
|
+
};
|
264
|
+
|
265
|
+
Connector.prototype._onclose = function(e) {
|
266
|
+
this.protocol = 0;
|
267
|
+
this.handlers.disconnected(this._disconnectionReason, this._nextDelay);
|
268
|
+
return this._scheduleReconnection();
|
269
|
+
};
|
270
|
+
|
271
|
+
Connector.prototype._onerror = function(e) {};
|
272
|
+
|
273
|
+
Connector.prototype._onmessage = function(e) {
|
274
|
+
return this.protocolParser.process(e.data);
|
275
|
+
};
|
276
|
+
|
277
|
+
return Connector;
|
278
|
+
|
279
|
+
})();
|
280
|
+
|
281
|
+
// timer
|
282
|
+
var Timer;
|
283
|
+
var __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; };
|
284
|
+
__timer.Timer = Timer = (function() {
|
285
|
+
function Timer(func) {
|
286
|
+
this.func = func;
|
287
|
+
this.running = false;
|
288
|
+
this.id = null;
|
289
|
+
this._handler = __bind(function() {
|
290
|
+
this.running = false;
|
291
|
+
this.id = null;
|
292
|
+
return this.func();
|
293
|
+
}, this);
|
294
|
+
}
|
295
|
+
Timer.prototype.start = function(timeout) {
|
296
|
+
if (this.running) {
|
297
|
+
clearTimeout(this.id);
|
298
|
+
}
|
299
|
+
this.id = setTimeout(this._handler, timeout);
|
300
|
+
return this.running = true;
|
301
|
+
};
|
302
|
+
Timer.prototype.stop = function() {
|
303
|
+
if (this.running) {
|
304
|
+
clearTimeout(this.id);
|
305
|
+
this.running = false;
|
306
|
+
return this.id = null;
|
307
|
+
}
|
308
|
+
};
|
309
|
+
return Timer;
|
310
|
+
})();
|
311
|
+
Timer.start = function(timeout, func) {
|
312
|
+
return setTimeout(func, timeout);
|
313
|
+
};
|
314
|
+
|
315
|
+
// options
|
316
|
+
var Options;
|
317
|
+
__options.Options = Options = (function() {
|
318
|
+
function Options() {
|
319
|
+
this.host = null;
|
320
|
+
this.port = HAWKINS_LIVERELOAD_PORT;
|
321
|
+
this.snipver = null;
|
322
|
+
this.ext = null;
|
323
|
+
this.extver = null;
|
324
|
+
this.mindelay = 1000;
|
325
|
+
this.maxdelay = 60000;
|
326
|
+
this.handshake_timeout = 5000;
|
327
|
+
}
|
328
|
+
Options.prototype.set = function(name, value) {
|
329
|
+
switch (typeof this[name]) {
|
330
|
+
case 'undefined':
|
331
|
+
break;
|
332
|
+
case 'number':
|
333
|
+
return this[name] = +value;
|
334
|
+
default:
|
335
|
+
return this[name] = value;
|
336
|
+
}
|
337
|
+
};
|
338
|
+
return Options;
|
339
|
+
})();
|
340
|
+
Options.extract = function(document) {
|
341
|
+
var element, keyAndValue, m, mm, options, pair, src, _i, _j, _len, _len2, _ref, _ref2;
|
342
|
+
_ref = document.getElementsByTagName('script');
|
343
|
+
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
344
|
+
element = _ref[_i];
|
345
|
+
if ((src = element.src) && (m = src.match(/^[^:]+:\/\/(.*)\/z?livereload\.js(?:\?(.*))?$/))) {
|
346
|
+
options = new Options();
|
347
|
+
if (mm = m[1].match(/^([^\/:]+)(?::(\d+))?$/)) {
|
348
|
+
options.host = mm[1];
|
349
|
+
if (mm[2]) {
|
350
|
+
options.port = parseInt(mm[2], 10);
|
351
|
+
}
|
352
|
+
}
|
353
|
+
if (m[2]) {
|
354
|
+
_ref2 = m[2].split('&');
|
355
|
+
for (_j = 0, _len2 = _ref2.length; _j < _len2; _j++) {
|
356
|
+
pair = _ref2[_j];
|
357
|
+
if ((keyAndValue = pair.split('=')).length > 1) {
|
358
|
+
options.set(keyAndValue[0].replace(/-/g, '_'), keyAndValue.slice(1).join('='));
|
359
|
+
}
|
360
|
+
}
|
361
|
+
}
|
362
|
+
return options;
|
363
|
+
}
|
364
|
+
}
|
365
|
+
return null;
|
366
|
+
};
|
367
|
+
|
368
|
+
// reloader
|
369
|
+
// Generated by CoffeeScript 1.3.1
|
370
|
+
(function() {
|
371
|
+
var IMAGE_STYLES, Reloader, numberOfMatchingSegments, pathFromUrl, pathsMatch, pickBestMatch, splitUrl;
|
372
|
+
|
373
|
+
splitUrl = function(url) {
|
374
|
+
var hash, index, params;
|
375
|
+
if ((index = url.indexOf('#')) >= 0) {
|
376
|
+
hash = url.slice(index);
|
377
|
+
url = url.slice(0, index);
|
378
|
+
} else {
|
379
|
+
hash = '';
|
380
|
+
}
|
381
|
+
if ((index = url.indexOf('?')) >= 0) {
|
382
|
+
params = url.slice(index);
|
383
|
+
url = url.slice(0, index);
|
384
|
+
} else {
|
385
|
+
params = '';
|
386
|
+
}
|
387
|
+
return {
|
388
|
+
url: url,
|
389
|
+
params: params,
|
390
|
+
hash: hash
|
391
|
+
};
|
392
|
+
};
|
393
|
+
|
394
|
+
pathFromUrl = function(url) {
|
395
|
+
var path;
|
396
|
+
url = splitUrl(url).url;
|
397
|
+
if (url.indexOf('file://') === 0) {
|
398
|
+
path = url.replace(/^file:\/\/(localhost)?/, '');
|
399
|
+
} else {
|
400
|
+
path = url.replace(/^([^:]+:)?\/\/([^:\/]+)(:\d*)?\//, '/');
|
401
|
+
}
|
402
|
+
return decodeURIComponent(path);
|
403
|
+
};
|
404
|
+
|
405
|
+
pickBestMatch = function(path, objects, pathFunc) {
|
406
|
+
var bestMatch, object, score, _i, _len;
|
407
|
+
bestMatch = {
|
408
|
+
score: 0
|
409
|
+
};
|
410
|
+
for (_i = 0, _len = objects.length; _i < _len; _i++) {
|
411
|
+
object = objects[_i];
|
412
|
+
score = numberOfMatchingSegments(path, pathFunc(object));
|
413
|
+
if (score > bestMatch.score) {
|
414
|
+
bestMatch = {
|
415
|
+
object: object,
|
416
|
+
score: score
|
417
|
+
};
|
418
|
+
}
|
419
|
+
}
|
420
|
+
if (bestMatch.score > 0) {
|
421
|
+
return bestMatch;
|
422
|
+
} else {
|
423
|
+
return null;
|
424
|
+
}
|
425
|
+
};
|
426
|
+
|
427
|
+
numberOfMatchingSegments = function(path1, path2) {
|
428
|
+
var comps1, comps2, eqCount, len;
|
429
|
+
path1 = path1.replace(/^\/+/, '').toLowerCase();
|
430
|
+
path2 = path2.replace(/^\/+/, '').toLowerCase();
|
431
|
+
if (path1 === path2) {
|
432
|
+
return 10000;
|
433
|
+
}
|
434
|
+
comps1 = path1.split('/').reverse();
|
435
|
+
comps2 = path2.split('/').reverse();
|
436
|
+
len = Math.min(comps1.length, comps2.length);
|
437
|
+
eqCount = 0;
|
438
|
+
while (eqCount < len && comps1[eqCount] === comps2[eqCount]) {
|
439
|
+
++eqCount;
|
440
|
+
}
|
441
|
+
return eqCount;
|
442
|
+
};
|
443
|
+
|
444
|
+
pathsMatch = function(path1, path2) {
|
445
|
+
return numberOfMatchingSegments(path1, path2) > 0;
|
446
|
+
};
|
447
|
+
|
448
|
+
IMAGE_STYLES = [
|
449
|
+
{
|
450
|
+
selector: 'background',
|
451
|
+
styleNames: ['backgroundImage']
|
452
|
+
}, {
|
453
|
+
selector: 'border',
|
454
|
+
styleNames: ['borderImage', 'webkitBorderImage', 'MozBorderImage']
|
455
|
+
}
|
456
|
+
];
|
457
|
+
|
458
|
+
__reloader.Reloader = Reloader = (function() {
|
459
|
+
|
460
|
+
Reloader.name = 'Reloader';
|
461
|
+
|
462
|
+
function Reloader(window, console, Timer) {
|
463
|
+
this.window = window;
|
464
|
+
this.console = console;
|
465
|
+
this.Timer = Timer;
|
466
|
+
this.document = this.window.document;
|
467
|
+
this.importCacheWaitPeriod = 200;
|
468
|
+
this.plugins = [];
|
469
|
+
}
|
470
|
+
|
471
|
+
Reloader.prototype.addPlugin = function(plugin) {
|
472
|
+
return this.plugins.push(plugin);
|
473
|
+
};
|
474
|
+
|
475
|
+
Reloader.prototype.analyze = function(callback) {
|
476
|
+
return results;
|
477
|
+
};
|
478
|
+
|
479
|
+
Reloader.prototype.reload = function(path, options) {
|
480
|
+
var plugin, _base, _i, _len, _ref;
|
481
|
+
this.options = options;
|
482
|
+
if ((_base = this.options).stylesheetReloadTimeout == null) {
|
483
|
+
_base.stylesheetReloadTimeout = 15000;
|
484
|
+
}
|
485
|
+
_ref = this.plugins;
|
486
|
+
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
487
|
+
plugin = _ref[_i];
|
488
|
+
if (plugin.reload && plugin.reload(path, options)) {
|
489
|
+
return;
|
490
|
+
}
|
491
|
+
}
|
492
|
+
if (options.liveCSS) {
|
493
|
+
if (path.match(/\.css$/i)) {
|
494
|
+
if (this.reloadStylesheet(path)) {
|
495
|
+
return;
|
496
|
+
}
|
497
|
+
}
|
498
|
+
}
|
499
|
+
if (options.liveImg) {
|
500
|
+
if (path.match(/\.(jpe?g|png|gif)$/i)) {
|
501
|
+
this.reloadImages(path);
|
502
|
+
return;
|
503
|
+
}
|
504
|
+
}
|
505
|
+
return this.reloadPage();
|
506
|
+
};
|
507
|
+
|
508
|
+
Reloader.prototype.reloadPage = function() {
|
509
|
+
return this.window.document.location.reload();
|
510
|
+
};
|
511
|
+
|
512
|
+
Reloader.prototype.reloadImages = function(path) {
|
513
|
+
var expando, img, selector, styleNames, styleSheet, _i, _j, _k, _l, _len, _len1, _len2, _len3, _ref, _ref1, _ref2, _ref3, _results;
|
514
|
+
expando = this.generateUniqueString();
|
515
|
+
_ref = this.document.images;
|
516
|
+
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
517
|
+
img = _ref[_i];
|
518
|
+
if (pathsMatch(path, pathFromUrl(img.src))) {
|
519
|
+
img.src = this.generateCacheBustUrl(img.src, expando);
|
520
|
+
}
|
521
|
+
}
|
522
|
+
if (this.document.querySelectorAll) {
|
523
|
+
for (_j = 0, _len1 = IMAGE_STYLES.length; _j < _len1; _j++) {
|
524
|
+
_ref1 = IMAGE_STYLES[_j], selector = _ref1.selector, styleNames = _ref1.styleNames;
|
525
|
+
_ref2 = this.document.querySelectorAll("[style*=" + selector + "]");
|
526
|
+
for (_k = 0, _len2 = _ref2.length; _k < _len2; _k++) {
|
527
|
+
img = _ref2[_k];
|
528
|
+
this.reloadStyleImages(img.style, styleNames, path, expando);
|
529
|
+
}
|
530
|
+
}
|
531
|
+
}
|
532
|
+
if (this.document.styleSheets) {
|
533
|
+
_ref3 = this.document.styleSheets;
|
534
|
+
_results = [];
|
535
|
+
for (_l = 0, _len3 = _ref3.length; _l < _len3; _l++) {
|
536
|
+
styleSheet = _ref3[_l];
|
537
|
+
_results.push(this.reloadStylesheetImages(styleSheet, path, expando));
|
538
|
+
}
|
539
|
+
return _results;
|
540
|
+
}
|
541
|
+
};
|
542
|
+
|
543
|
+
Reloader.prototype.reloadStylesheetImages = function(styleSheet, path, expando) {
|
544
|
+
var rule, rules, styleNames, _i, _j, _len, _len1;
|
545
|
+
try {
|
546
|
+
rules = styleSheet != null ? styleSheet.cssRules : void 0;
|
547
|
+
} catch (e) {
|
548
|
+
|
549
|
+
}
|
550
|
+
if (!rules) {
|
551
|
+
return;
|
552
|
+
}
|
553
|
+
for (_i = 0, _len = rules.length; _i < _len; _i++) {
|
554
|
+
rule = rules[_i];
|
555
|
+
switch (rule.type) {
|
556
|
+
case CSSRule.IMPORT_RULE:
|
557
|
+
this.reloadStylesheetImages(rule.styleSheet, path, expando);
|
558
|
+
break;
|
559
|
+
case CSSRule.STYLE_RULE:
|
560
|
+
for (_j = 0, _len1 = IMAGE_STYLES.length; _j < _len1; _j++) {
|
561
|
+
styleNames = IMAGE_STYLES[_j].styleNames;
|
562
|
+
this.reloadStyleImages(rule.style, styleNames, path, expando);
|
563
|
+
}
|
564
|
+
break;
|
565
|
+
case CSSRule.MEDIA_RULE:
|
566
|
+
this.reloadStylesheetImages(rule, path, expando);
|
567
|
+
}
|
568
|
+
}
|
569
|
+
};
|
570
|
+
|
571
|
+
Reloader.prototype.reloadStyleImages = function(style, styleNames, path, expando) {
|
572
|
+
var newValue, styleName, value, _i, _len,
|
573
|
+
_this = this;
|
574
|
+
for (_i = 0, _len = styleNames.length; _i < _len; _i++) {
|
575
|
+
styleName = styleNames[_i];
|
576
|
+
value = style[styleName];
|
577
|
+
if (typeof value === 'string') {
|
578
|
+
newValue = value.replace(/\burl\s*\(([^)]*)\)/, function(match, src) {
|
579
|
+
if (pathsMatch(path, pathFromUrl(src))) {
|
580
|
+
return "url(" + (_this.generateCacheBustUrl(src, expando)) + ")";
|
581
|
+
} else {
|
582
|
+
return match;
|
583
|
+
}
|
584
|
+
});
|
585
|
+
if (newValue !== value) {
|
586
|
+
style[styleName] = newValue;
|
587
|
+
}
|
588
|
+
}
|
589
|
+
}
|
590
|
+
};
|
591
|
+
|
592
|
+
Reloader.prototype.reloadStylesheet = function(path) {
|
593
|
+
var imported, link, links, match, style, _i, _j, _k, _l, _len, _len1, _len2, _len3, _ref, _ref1,
|
594
|
+
_this = this;
|
595
|
+
links = (function() {
|
596
|
+
var _i, _len, _ref, _results;
|
597
|
+
_ref = this.document.getElementsByTagName('link');
|
598
|
+
_results = [];
|
599
|
+
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
600
|
+
link = _ref[_i];
|
601
|
+
if (link.rel === 'stylesheet' && !link.__LiveReload_pendingRemoval) {
|
602
|
+
_results.push(link);
|
603
|
+
}
|
604
|
+
}
|
605
|
+
return _results;
|
606
|
+
}).call(this);
|
607
|
+
imported = [];
|
608
|
+
_ref = this.document.getElementsByTagName('style');
|
609
|
+
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
610
|
+
style = _ref[_i];
|
611
|
+
if (style.sheet) {
|
612
|
+
this.collectImportedStylesheets(style, style.sheet, imported);
|
613
|
+
}
|
614
|
+
}
|
615
|
+
for (_j = 0, _len1 = links.length; _j < _len1; _j++) {
|
616
|
+
link = links[_j];
|
617
|
+
this.collectImportedStylesheets(link, link.sheet, imported);
|
618
|
+
}
|
619
|
+
if (this.window.StyleFix && this.document.querySelectorAll) {
|
620
|
+
_ref1 = this.document.querySelectorAll('style[data-href]');
|
621
|
+
for (_k = 0, _len2 = _ref1.length; _k < _len2; _k++) {
|
622
|
+
style = _ref1[_k];
|
623
|
+
links.push(style);
|
624
|
+
}
|
625
|
+
}
|
626
|
+
this.console.log("LiveReload found " + links.length + " LINKed stylesheets, " + imported.length + " @imported stylesheets");
|
627
|
+
match = pickBestMatch(path, links.concat(imported), function(l) {
|
628
|
+
return pathFromUrl(_this.linkHref(l));
|
629
|
+
});
|
630
|
+
if (match) {
|
631
|
+
if (match.object.rule) {
|
632
|
+
this.console.log("LiveReload is reloading imported stylesheet: " + match.object.href);
|
633
|
+
this.reattachImportedRule(match.object);
|
634
|
+
} else {
|
635
|
+
this.console.log("LiveReload is reloading stylesheet: " + (this.linkHref(match.object)));
|
636
|
+
this.reattachStylesheetLink(match.object);
|
637
|
+
}
|
638
|
+
} else {
|
639
|
+
this.console.log("LiveReload will reload all stylesheets because path '" + path + "' did not match any specific one");
|
640
|
+
for (_l = 0, _len3 = links.length; _l < _len3; _l++) {
|
641
|
+
link = links[_l];
|
642
|
+
this.reattachStylesheetLink(link);
|
643
|
+
}
|
644
|
+
}
|
645
|
+
return true;
|
646
|
+
};
|
647
|
+
|
648
|
+
Reloader.prototype.collectImportedStylesheets = function(link, styleSheet, result) {
|
649
|
+
var index, rule, rules, _i, _len;
|
650
|
+
try {
|
651
|
+
rules = styleSheet != null ? styleSheet.cssRules : void 0;
|
652
|
+
} catch (e) {
|
653
|
+
|
654
|
+
}
|
655
|
+
if (rules && rules.length) {
|
656
|
+
for (index = _i = 0, _len = rules.length; _i < _len; index = ++_i) {
|
657
|
+
rule = rules[index];
|
658
|
+
switch (rule.type) {
|
659
|
+
case CSSRule.CHARSET_RULE:
|
660
|
+
continue;
|
661
|
+
case CSSRule.IMPORT_RULE:
|
662
|
+
result.push({
|
663
|
+
link: link,
|
664
|
+
rule: rule,
|
665
|
+
index: index,
|
666
|
+
href: rule.href
|
667
|
+
});
|
668
|
+
this.collectImportedStylesheets(link, rule.styleSheet, result);
|
669
|
+
break;
|
670
|
+
default:
|
671
|
+
break;
|
672
|
+
}
|
673
|
+
}
|
674
|
+
}
|
675
|
+
};
|
676
|
+
|
677
|
+
Reloader.prototype.waitUntilCssLoads = function(clone, func) {
|
678
|
+
var callbackExecuted, executeCallback, poll,
|
679
|
+
_this = this;
|
680
|
+
callbackExecuted = false;
|
681
|
+
executeCallback = function() {
|
682
|
+
if (callbackExecuted) {
|
683
|
+
return;
|
684
|
+
}
|
685
|
+
callbackExecuted = true;
|
686
|
+
return func();
|
687
|
+
};
|
688
|
+
clone.onload = function() {
|
689
|
+
console.log("onload!");
|
690
|
+
_this.knownToSupportCssOnLoad = true;
|
691
|
+
return executeCallback();
|
692
|
+
};
|
693
|
+
if (!this.knownToSupportCssOnLoad) {
|
694
|
+
(poll = function() {
|
695
|
+
if (clone.sheet) {
|
696
|
+
console.log("polling!");
|
697
|
+
return executeCallback();
|
698
|
+
} else {
|
699
|
+
return _this.Timer.start(50, poll);
|
700
|
+
}
|
701
|
+
})();
|
702
|
+
}
|
703
|
+
return this.Timer.start(this.options.stylesheetReloadTimeout, executeCallback);
|
704
|
+
};
|
705
|
+
|
706
|
+
Reloader.prototype.linkHref = function(link) {
|
707
|
+
return link.href || link.getAttribute('data-href');
|
708
|
+
};
|
709
|
+
|
710
|
+
Reloader.prototype.reattachStylesheetLink = function(link) {
|
711
|
+
var clone, parent,
|
712
|
+
_this = this;
|
713
|
+
if (link.__LiveReload_pendingRemoval) {
|
714
|
+
return;
|
715
|
+
}
|
716
|
+
link.__LiveReload_pendingRemoval = true;
|
717
|
+
if (link.tagName === 'STYLE') {
|
718
|
+
clone = this.document.createElement('link');
|
719
|
+
clone.rel = 'stylesheet';
|
720
|
+
clone.media = link.media;
|
721
|
+
clone.disabled = link.disabled;
|
722
|
+
} else {
|
723
|
+
clone = link.cloneNode(false);
|
724
|
+
}
|
725
|
+
clone.href = this.generateCacheBustUrl(this.linkHref(link));
|
726
|
+
parent = link.parentNode;
|
727
|
+
if (parent.lastChild === link) {
|
728
|
+
parent.appendChild(clone);
|
729
|
+
} else {
|
730
|
+
parent.insertBefore(clone, link.nextSibling);
|
731
|
+
}
|
732
|
+
return this.waitUntilCssLoads(clone, function() {
|
733
|
+
var additionalWaitingTime;
|
734
|
+
if (/AppleWebKit/.test(navigator.userAgent)) {
|
735
|
+
additionalWaitingTime = 5;
|
736
|
+
} else {
|
737
|
+
additionalWaitingTime = 200;
|
738
|
+
}
|
739
|
+
return _this.Timer.start(additionalWaitingTime, function() {
|
740
|
+
var _ref;
|
741
|
+
if (!link.parentNode) {
|
742
|
+
return;
|
743
|
+
}
|
744
|
+
link.parentNode.removeChild(link);
|
745
|
+
clone.onreadystatechange = null;
|
746
|
+
return (_ref = _this.window.StyleFix) != null ? _ref.link(clone) : void 0;
|
747
|
+
});
|
748
|
+
});
|
749
|
+
};
|
750
|
+
|
751
|
+
Reloader.prototype.reattachImportedRule = function(_arg) {
|
752
|
+
var href, index, link, media, newRule, parent, rule, tempLink,
|
753
|
+
_this = this;
|
754
|
+
rule = _arg.rule, index = _arg.index, link = _arg.link;
|
755
|
+
parent = rule.parentStyleSheet;
|
756
|
+
href = this.generateCacheBustUrl(rule.href);
|
757
|
+
media = rule.media.length ? [].join.call(rule.media, ', ') : '';
|
758
|
+
newRule = "@import url(\"" + href + "\") " + media + ";";
|
759
|
+
rule.__LiveReload_newHref = href;
|
760
|
+
tempLink = this.document.createElement("link");
|
761
|
+
tempLink.rel = 'stylesheet';
|
762
|
+
tempLink.href = href;
|
763
|
+
tempLink.__LiveReload_pendingRemoval = true;
|
764
|
+
if (link.parentNode) {
|
765
|
+
link.parentNode.insertBefore(tempLink, link);
|
766
|
+
}
|
767
|
+
return this.Timer.start(this.importCacheWaitPeriod, function() {
|
768
|
+
if (tempLink.parentNode) {
|
769
|
+
tempLink.parentNode.removeChild(tempLink);
|
770
|
+
}
|
771
|
+
if (rule.__LiveReload_newHref !== href) {
|
772
|
+
return;
|
773
|
+
}
|
774
|
+
parent.insertRule(newRule, index);
|
775
|
+
parent.deleteRule(index + 1);
|
776
|
+
rule = parent.cssRules[index];
|
777
|
+
rule.__LiveReload_newHref = href;
|
778
|
+
return _this.Timer.start(_this.importCacheWaitPeriod, function() {
|
779
|
+
if (rule.__LiveReload_newHref !== href) {
|
780
|
+
return;
|
781
|
+
}
|
782
|
+
parent.insertRule(newRule, index);
|
783
|
+
return parent.deleteRule(index + 1);
|
784
|
+
});
|
785
|
+
});
|
786
|
+
};
|
787
|
+
|
788
|
+
Reloader.prototype.generateUniqueString = function() {
|
789
|
+
return 'livereload=' + Date.now();
|
790
|
+
};
|
791
|
+
|
792
|
+
Reloader.prototype.generateCacheBustUrl = function(url, expando) {
|
793
|
+
var hash, oldParams, params, _ref;
|
794
|
+
if (expando == null) {
|
795
|
+
expando = this.generateUniqueString();
|
796
|
+
}
|
797
|
+
_ref = splitUrl(url), url = _ref.url, hash = _ref.hash, oldParams = _ref.params;
|
798
|
+
if (this.options.overrideURL) {
|
799
|
+
if (url.indexOf(this.options.serverURL) < 0) {
|
800
|
+
url = this.options.serverURL + this.options.overrideURL + "?url=" + encodeURIComponent(url);
|
801
|
+
}
|
802
|
+
}
|
803
|
+
params = oldParams.replace(/(\?|&)livereload=(\d+)/, function(match, sep) {
|
804
|
+
return "" + sep + expando;
|
805
|
+
});
|
806
|
+
if (params === oldParams) {
|
807
|
+
if (oldParams.length === 0) {
|
808
|
+
params = "?" + expando;
|
809
|
+
} else {
|
810
|
+
params = "" + oldParams + "&" + expando;
|
811
|
+
}
|
812
|
+
}
|
813
|
+
return url + params + hash;
|
814
|
+
};
|
815
|
+
|
816
|
+
return Reloader;
|
817
|
+
|
818
|
+
})();
|
819
|
+
|
820
|
+
}).call(this);
|
821
|
+
|
822
|
+
// livereload
|
823
|
+
var Connector, LiveReload, Options, Reloader, Timer;
|
824
|
+
|
825
|
+
Connector = __connector.Connector;
|
826
|
+
|
827
|
+
Timer = __timer.Timer;
|
828
|
+
|
829
|
+
Options = __options.Options;
|
830
|
+
|
831
|
+
Reloader = __reloader.Reloader;
|
832
|
+
|
833
|
+
__livereload.LiveReload = LiveReload = (function() {
|
834
|
+
|
835
|
+
function LiveReload(window) {
|
836
|
+
var _this = this;
|
837
|
+
this.window = window;
|
838
|
+
this.listeners = {};
|
839
|
+
this.plugins = [];
|
840
|
+
this.pluginIdentifiers = {};
|
841
|
+
this.console = this.window.location.href.match(/LR-verbose/) && this.window.console && this.window.console.log && this.window.console.error ? this.window.console : {
|
842
|
+
log: function() {},
|
843
|
+
error: function() {}
|
844
|
+
};
|
845
|
+
if (!(this.WebSocket = this.window.WebSocket || this.window.MozWebSocket)) {
|
846
|
+
console.error("LiveReload disabled because the browser does not seem to support web sockets");
|
847
|
+
return;
|
848
|
+
}
|
849
|
+
if (!(this.options = Options.extract(this.window.document))) {
|
850
|
+
console.error("LiveReload disabled because it could not find its own <SCRIPT> tag");
|
851
|
+
return;
|
852
|
+
}
|
853
|
+
this.reloader = new Reloader(this.window, this.console, Timer);
|
854
|
+
this.connector = new Connector(this.options, this.WebSocket, Timer, {
|
855
|
+
connecting: function() {},
|
856
|
+
socketConnected: function() {},
|
857
|
+
connected: function(protocol) {
|
858
|
+
var _base;
|
859
|
+
if (typeof (_base = _this.listeners).connect === "function") {
|
860
|
+
_base.connect();
|
861
|
+
}
|
862
|
+
_this.log("LiveReload is connected to " + _this.options.host + ":" + _this.options.port + " (protocol v" + protocol + ").");
|
863
|
+
return _this.analyze();
|
864
|
+
},
|
865
|
+
error: function(e) {
|
866
|
+
if (e instanceof ProtocolError) {
|
867
|
+
return console.log("" + e.message + ".");
|
868
|
+
} else {
|
869
|
+
return console.log("LiveReload internal error: " + e.message);
|
870
|
+
}
|
871
|
+
},
|
872
|
+
disconnected: function(reason, nextDelay) {
|
873
|
+
var _base;
|
874
|
+
if (typeof (_base = _this.listeners).disconnect === "function") {
|
875
|
+
_base.disconnect();
|
876
|
+
}
|
877
|
+
switch (reason) {
|
878
|
+
case 'cannot-connect':
|
879
|
+
return _this.log("LiveReload cannot connect to " + _this.options.host + ":" + _this.options.port + ", will retry in " + nextDelay + " sec.");
|
880
|
+
case 'broken':
|
881
|
+
return _this.log("LiveReload disconnected from " + _this.options.host + ":" + _this.options.port + ", reconnecting in " + nextDelay + " sec.");
|
882
|
+
case 'handshake-timeout':
|
883
|
+
return _this.log("LiveReload cannot connect to " + _this.options.host + ":" + _this.options.port + " (handshake timeout), will retry in " + nextDelay + " sec.");
|
884
|
+
case 'handshake-failed':
|
885
|
+
return _this.log("LiveReload cannot connect to " + _this.options.host + ":" + _this.options.port + " (handshake failed), will retry in " + nextDelay + " sec.");
|
886
|
+
case 'manual':
|
887
|
+
break;
|
888
|
+
case 'error':
|
889
|
+
break;
|
890
|
+
default:
|
891
|
+
return _this.log("LiveReload disconnected from " + _this.options.host + ":" + _this.options.port + " (" + reason + "), reconnecting in " + nextDelay + " sec.");
|
892
|
+
}
|
893
|
+
},
|
894
|
+
message: function(message) {
|
895
|
+
switch (message.command) {
|
896
|
+
case 'reload':
|
897
|
+
return _this.performReload(message);
|
898
|
+
case 'alert':
|
899
|
+
return _this.performAlert(message);
|
900
|
+
}
|
901
|
+
}
|
902
|
+
});
|
903
|
+
}
|
904
|
+
|
905
|
+
LiveReload.prototype.on = function(eventName, handler) {
|
906
|
+
return this.listeners[eventName] = handler;
|
907
|
+
};
|
908
|
+
|
909
|
+
LiveReload.prototype.log = function(message) {
|
910
|
+
return this.console.log("" + message);
|
911
|
+
};
|
912
|
+
|
913
|
+
LiveReload.prototype.performReload = function(message) {
|
914
|
+
var _ref, _ref2;
|
915
|
+
this.log("LiveReload received reload request for " + message.path + ".");
|
916
|
+
return this.reloader.reload(message.path, {
|
917
|
+
liveCSS: (_ref = message.liveCSS) != null ? _ref : true,
|
918
|
+
liveImg: (_ref2 = message.liveImg) != null ? _ref2 : true,
|
919
|
+
originalPath: message.originalPath || '',
|
920
|
+
overrideURL: message.overrideURL || '',
|
921
|
+
serverURL: "http://" + this.options.host + ":" + this.options.port
|
922
|
+
});
|
923
|
+
};
|
924
|
+
|
925
|
+
LiveReload.prototype.performAlert = function(message) {
|
926
|
+
return alert(message.message);
|
927
|
+
};
|
928
|
+
|
929
|
+
LiveReload.prototype.shutDown = function() {
|
930
|
+
var _base;
|
931
|
+
this.connector.disconnect();
|
932
|
+
this.log("LiveReload disconnected.");
|
933
|
+
return typeof (_base = this.listeners).shutdown === "function" ? _base.shutdown() : void 0;
|
934
|
+
};
|
935
|
+
|
936
|
+
LiveReload.prototype.hasPlugin = function(identifier) {
|
937
|
+
return !!this.pluginIdentifiers[identifier];
|
938
|
+
};
|
939
|
+
|
940
|
+
LiveReload.prototype.addPlugin = function(pluginClass) {
|
941
|
+
var plugin;
|
942
|
+
var _this = this;
|
943
|
+
if (this.hasPlugin(pluginClass.identifier)) return;
|
944
|
+
this.pluginIdentifiers[pluginClass.identifier] = true;
|
945
|
+
plugin = new pluginClass(this.window, {
|
946
|
+
_livereload: this,
|
947
|
+
_reloader: this.reloader,
|
948
|
+
_connector: this.connector,
|
949
|
+
console: this.console,
|
950
|
+
Timer: Timer,
|
951
|
+
generateCacheBustUrl: function(url) {
|
952
|
+
return _this.reloader.generateCacheBustUrl(url);
|
953
|
+
}
|
954
|
+
});
|
955
|
+
this.plugins.push(plugin);
|
956
|
+
this.reloader.addPlugin(plugin);
|
957
|
+
};
|
958
|
+
|
959
|
+
LiveReload.prototype.analyze = function() {
|
960
|
+
var plugin, pluginData, pluginsData, _i, _len, _ref;
|
961
|
+
if (!(this.connector.protocol >= 7)) return;
|
962
|
+
pluginsData = {};
|
963
|
+
_ref = this.plugins;
|
964
|
+
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
965
|
+
plugin = _ref[_i];
|
966
|
+
pluginsData[plugin.constructor.identifier] = pluginData = (typeof plugin.analyze === "function" ? plugin.analyze() : void 0) || {};
|
967
|
+
pluginData.version = plugin.constructor.version;
|
968
|
+
}
|
969
|
+
this.connector.sendCommand({
|
970
|
+
command: 'info',
|
971
|
+
plugins: pluginsData,
|
972
|
+
url: this.window.location.href
|
973
|
+
});
|
974
|
+
};
|
975
|
+
|
976
|
+
return LiveReload;
|
977
|
+
|
978
|
+
})();
|
979
|
+
|
980
|
+
// less
|
981
|
+
var LessPlugin;
|
982
|
+
__less = LessPlugin = (function() {
|
983
|
+
LessPlugin.identifier = 'less';
|
984
|
+
LessPlugin.version = '1.0';
|
985
|
+
function LessPlugin(window, host) {
|
986
|
+
this.window = window;
|
987
|
+
this.host = host;
|
988
|
+
}
|
989
|
+
LessPlugin.prototype.reload = function(path, options) {
|
990
|
+
if (this.window.less && this.window.less.refresh) {
|
991
|
+
if (path.match(/\.less$/i)) {
|
992
|
+
return this.reloadLess(path);
|
993
|
+
}
|
994
|
+
if (options.originalPath.match(/\.less$/i)) {
|
995
|
+
return this.reloadLess(options.originalPath);
|
996
|
+
}
|
997
|
+
}
|
998
|
+
return false;
|
999
|
+
};
|
1000
|
+
LessPlugin.prototype.reloadLess = function(path) {
|
1001
|
+
var link, links, _i, _len;
|
1002
|
+
links = (function() {
|
1003
|
+
var _i, _len, _ref, _results;
|
1004
|
+
_ref = document.getElementsByTagName('link');
|
1005
|
+
_results = [];
|
1006
|
+
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
1007
|
+
link = _ref[_i];
|
1008
|
+
if (link.href && link.rel === 'stylesheet/less' || (link.rel.match(/stylesheet/) && link.type.match(/^text\/(x-)?less$/))) {
|
1009
|
+
_results.push(link);
|
1010
|
+
}
|
1011
|
+
}
|
1012
|
+
return _results;
|
1013
|
+
})();
|
1014
|
+
if (links.length === 0) {
|
1015
|
+
return false;
|
1016
|
+
}
|
1017
|
+
for (_i = 0, _len = links.length; _i < _len; _i++) {
|
1018
|
+
link = links[_i];
|
1019
|
+
link.href = this.host.generateCacheBustUrl(link.href);
|
1020
|
+
}
|
1021
|
+
this.host.console.log("LiveReload is asking LESS to recompile all stylesheets");
|
1022
|
+
this.window.less.refresh(true);
|
1023
|
+
return true;
|
1024
|
+
};
|
1025
|
+
LessPlugin.prototype.analyze = function() {
|
1026
|
+
return {
|
1027
|
+
disable: !!(this.window.less && this.window.less.refresh)
|
1028
|
+
};
|
1029
|
+
};
|
1030
|
+
return LessPlugin;
|
1031
|
+
})();
|
1032
|
+
|
1033
|
+
// startup
|
1034
|
+
var CustomEvents, LiveReload, k;
|
1035
|
+
CustomEvents = __customevents;
|
1036
|
+
LiveReload = window.LiveReload = new (__livereload.LiveReload)(window);
|
1037
|
+
for (k in window) {
|
1038
|
+
if (k.match(/^LiveReloadPlugin/)) {
|
1039
|
+
LiveReload.addPlugin(window[k]);
|
1040
|
+
}
|
1041
|
+
}
|
1042
|
+
LiveReload.addPlugin(__less);
|
1043
|
+
LiveReload.on('shutdown', function() {
|
1044
|
+
return delete window.LiveReload;
|
1045
|
+
});
|
1046
|
+
LiveReload.on('connect', function() {
|
1047
|
+
return CustomEvents.fire(document, 'LiveReloadConnect');
|
1048
|
+
});
|
1049
|
+
LiveReload.on('disconnect', function() {
|
1050
|
+
return CustomEvents.fire(document, 'LiveReloadDisconnect');
|
1051
|
+
});
|
1052
|
+
CustomEvents.bind(document, 'LiveReloadShutDown', function() {
|
1053
|
+
return LiveReload.shutDown();
|
1054
|
+
});
|
1055
|
+
})();
|