livecss 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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: []