livecss 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,4 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in livecss.gemspec
4
+ gemspec
data/README.md ADDED
@@ -0,0 +1,10 @@
1
+ Based on this awesome work https://github.com/ooyala/livecss
2
+
3
+ Rails 3
4
+ -------
5
+ To start using simply add gem to :development section of your Gemfile
6
+
7
+ group :development do
8
+ gem 'livecss'
9
+ end
10
+
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,4 @@
1
+ module Livecss
2
+ class Engine < ::Rails::Engine
3
+ end
4
+ end
@@ -0,0 +1,3 @@
1
+ module Livecss
2
+ VERSION = "0.0.1"
3
+ end
data/lib/livecss.rb ADDED
@@ -0,0 +1,2 @@
1
+ require 'livecss/engine'
2
+ require 'livecss/version'
data/livecss.gemspec ADDED
@@ -0,0 +1,22 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "livecss/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "livecss"
7
+ s.version = Livecss::VERSION
8
+ s.authors = ["Alex K"]
9
+ s.email = ["flskif@gmail.com"]
10
+ s.homepage = ""
11
+ s.summary = %q{Live CSS - instantly see your CSS changes in browser}
12
+ s.description = %q{}
13
+
14
+ s.rubyforge_project = "livecss"
15
+ s.required_rubygems_version = ">= 1.3.6"
16
+ s.add_dependency "railties", ">= 3.2.0", "< 5.0"
17
+
18
+ s.files = `git ls-files`.split("\n")
19
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
20
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
21
+ s.require_paths = ["lib"]
22
+ end
@@ -0,0 +1,174 @@
1
+ $(document).ready(function() { livecss.watchAll(); })
2
+
3
+ /*
4
+ * Live CSS will monitor <link> tags on the page and poll the server for changes to the CSS. This enables you
5
+ * to refresh styles without disrupting the state of the view, and the page updates itself without you
6
+ * having to switch from your editor to the browser and hit refresh.
7
+ *
8
+ * Usage:
9
+ * livecss.watchAll() - starts polling all <link> tags in the current page for changes.
10
+ *
11
+ * If you want more fine grained control over which CSS is being autoreloaded:
12
+ * livecss.watch(linkElement) - start watching a single <link> element for changes.
13
+ * livecss.unwatchAll()
14
+ * livecss.unwatch(linkElement)
15
+ *
16
+ * For convenience, livecss will call watchAll() right away if the page has "startlivecss=true" in the URL's
17
+ * query string.
18
+ */
19
+ var livecss = {
20
+ // How often to poll for changes to the CSS.
21
+ pollFrequency: 1000,
22
+ outstandingRequests: {}, // stylesheet url => boolean
23
+ filesLastModified: {}, // stylesheet url => last modified timestamp
24
+ watchTimers: {}, // stylesheet url => timer ID
25
+
26
+ /*
27
+ * Begins polling all link elements on the current page for changes.
28
+ */
29
+ watchAll: function() {
30
+ this.unwatchAll();
31
+ var timerId = setInterval(this.proxy(function() {
32
+ var linkElements = document.getElementsByTagName("link");
33
+ var validMediaTypes = ["screen", "handheld", "all", ""];
34
+ for (var i = 0; i < linkElements.length; i++) {
35
+ var media = (linkElements[i].getAttribute("media") || "").toLowerCase();
36
+ if (linkElements[i].getAttribute("rel") == "stylesheet"
37
+ && livecss.indexOf(validMediaTypes, media) >= 0
38
+ && this.isLocalLink(linkElements[i])) {
39
+ this.refreshLinkElement(linkElements[i]);
40
+ }
41
+ }
42
+ }), this.pollFrequency);
43
+ this.watchTimers["all"] = timerId;
44
+ },
45
+
46
+ watch: function(linkElement) {
47
+ var url = linkElement.getAttribute("href");
48
+ this.unwatch(url);
49
+ this.watchTimers[url] = setInterval(this.proxy(function() {
50
+ var linkElement = this.linkElementWithHref(url);
51
+ this.refreshLinkElement(linkElement);
52
+ }), this.pollFrequency);
53
+ },
54
+
55
+ unwatchAll: function() {
56
+ for (var url in this.watchTimers)
57
+ this.unwatch(url);
58
+ },
59
+
60
+ unwatch: function(url) {
61
+ if (this.watchTimers[url] != null) {
62
+ clearInterval(this.watchTimers[url]);
63
+ delete this.watchTimers[url];
64
+ delete this.outstandingRequests[url];
65
+ }
66
+ },
67
+
68
+ linkElementWithHref: function(url) {
69
+ var linkElements = document.getElementsByTagName("link");
70
+ for (var i = 0; i < linkElements.length; i++)
71
+ if (linkElements[i].href == url)
72
+ return linkElements[i]
73
+ },
74
+
75
+ /*
76
+ * Replaces a link element with a new one for the given URL. This has to wait for the new <link> to fully
77
+ * load, because simply changing the href on an existing <link> causes the page to flicker.
78
+ */
79
+ replaceLinkElement: function(linkElement, stylesheetUrl) {
80
+ var parent = linkElement.parentNode;
81
+ var sibling = linkElement.nextSibling;
82
+ var url = this.addCacheBust(linkElement.href);
83
+
84
+ var newLinkElement = document.createElement("link");
85
+ newLinkElement.href = url;
86
+ newLinkElement.setAttribute("rel", "stylesheet");
87
+
88
+ if (sibling)
89
+ parent.insertBefore(newLinkElement, sibling);
90
+ else
91
+ parent.appendChild(newLinkElement);
92
+
93
+ // We're polling to check whether the CSS is loaded, because firefox doesn't support an onload event
94
+ // for <link> elements.
95
+ var loadingTimer = setInterval(this.proxy(function() {
96
+ if (!this.isCssElementLoaded(newLinkElement)) return;
97
+ if (typeof(console) != "undefined")
98
+ console.log("CSS refreshed:", this.removeCacheBust(url));
99
+ clearInterval(loadingTimer);
100
+ delete this.outstandingRequests[this.removeCacheBust(url)];
101
+ parent.removeChild(linkElement);
102
+ }), 100);
103
+ },
104
+
105
+ /*
106
+ * Refreshes the provided linkElement if it's changed. We issue a HEAD request for the CSS. If its
107
+ * last-modified header is changed, we remove and re-add the <link> element to the DOM which trigger a
108
+ * re-render from the browser. This uses a cache-bust querystring parameter to ensure we always bust through
109
+ * the browser's cache.
110
+ */
111
+ refreshLinkElement: function(linkElement) {
112
+ var url = this.removeCacheBust(linkElement.getAttribute("href"));
113
+ if (this.outstandingRequests[url]) return;
114
+ var request = new XMLHttpRequest();
115
+ this.outstandingRequests[url] = request;
116
+ var cacheBustUrl = this.addCacheBust(url);
117
+
118
+ request.onreadystatechange = this.proxy(function(event) {
119
+ if (request.readyState != 4) return;
120
+ delete this.outstandingRequests[url];
121
+ if (request.status != 200 && request.status != 304) return;
122
+ var lastModified = Date.parse(request.getResponseHeader("Last-Modified"));
123
+ if (!this.filesLastModified[url] || this.filesLastModified[url] < lastModified) {
124
+ this.filesLastModified[url] = lastModified;
125
+ this.replaceLinkElement(linkElement, cacheBustUrl);
126
+ }
127
+ });
128
+ request.open("HEAD", cacheBustUrl);
129
+ request.send(null);
130
+ },
131
+
132
+ isCssElementLoaded: function(cssElement) {
133
+ // cssElement.sheet.cssRules will throw an error in firefox when the css file is not yet loaded.
134
+ try { return (cssElement.sheet && cssElement.sheet.cssRules.length > 0); } catch(error) { }
135
+ return false;
136
+ },
137
+
138
+ /* returns true for local urls such as: '/screen.css', 'http://mydomain.com/screen.css', 'css/screen.css'
139
+ */
140
+ isLocalLink: function(linkElement) {
141
+ //On all tested browsers, this javascript property returns a normalized URL
142
+ var url = linkElement.href;
143
+ var regexp = new RegExp("^\/|^" +
144
+ document.location.protocol + "//" + document.location.host);
145
+ return (url.search(regexp) == 0);
146
+ },
147
+
148
+ /*
149
+ * Adds and removes a "cache_bust" querystring parameter to the given URLs. This is so we always bust
150
+ * through the browser's cache when checking for updated CSS.
151
+ */
152
+ addCacheBust: function(url) { return this.removeCacheBust(url) + "?cache_bust=" + (new Date()).getTime(); },
153
+ removeCacheBust: function(url) { return url.replace(/\?cache_bust=[^&]+/, ""); },
154
+
155
+ /* A utility method to bind the value of "this". Equivalent to jQuery's proxy() function. */
156
+ proxy: function(fn) {
157
+ var self = this;
158
+ return function() { return fn.apply(self, []); };
159
+ },
160
+
161
+ /* Unfortunately IE7 doesn't have this built-in. */
162
+ indexOf: function(array, item) {
163
+ for (var i = 0; i < array.length; i++) { if (array[i] == item) return i; }
164
+ return -1;
165
+ },
166
+
167
+ /* A utility function for abstracting the difference between event listening in IE and other browsers. */
168
+ addEventListener: function(object, event, fn) {
169
+ object.attachEvent ? object.attachEvent("on" + event, fn) : object.addEventListener(event, fn, false);
170
+ }
171
+ };
172
+
173
+ if (window.location.search.toString().indexOf("startlivecss=true") >= 0)
174
+ livecss.addEventListener(window, "load", function() { livecss.watchAll(); });
metadata ADDED
@@ -0,0 +1,68 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: livecss
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Alex K
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-03-07 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: railties
16
+ requirement: &70205702935160 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: 3.2.0
22
+ - - <
23
+ - !ruby/object:Gem::Version
24
+ version: '5.0'
25
+ type: :runtime
26
+ prerelease: false
27
+ version_requirements: *70205702935160
28
+ description: ''
29
+ email:
30
+ - flskif@gmail.com
31
+ executables: []
32
+ extensions: []
33
+ extra_rdoc_files: []
34
+ files:
35
+ - .gitignore
36
+ - Gemfile
37
+ - README.md
38
+ - Rakefile
39
+ - lib/livecss.rb
40
+ - lib/livecss/engine.rb
41
+ - lib/livecss/version.rb
42
+ - livecss.gemspec
43
+ - vendor/assets/javascripts/livecss.js
44
+ homepage: ''
45
+ licenses: []
46
+ post_install_message:
47
+ rdoc_options: []
48
+ require_paths:
49
+ - lib
50
+ required_ruby_version: !ruby/object:Gem::Requirement
51
+ none: false
52
+ requirements:
53
+ - - ! '>='
54
+ - !ruby/object:Gem::Version
55
+ version: '0'
56
+ required_rubygems_version: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ! '>='
60
+ - !ruby/object:Gem::Version
61
+ version: 1.3.6
62
+ requirements: []
63
+ rubyforge_project: livecss
64
+ rubygems_version: 1.8.17
65
+ signing_key:
66
+ specification_version: 3
67
+ summary: Live CSS - instantly see your CSS changes in browser
68
+ test_files: []