From f049dbb06859053867db6dd2f91cfa92e233c92d Mon Sep 17 00:00:00 2001 From: Tyom Semonov Date: Thu, 22 Jan 2015 21:47:33 +0000 Subject: [PATCH 1/5] Implement animated change transitions --- README.md | 4 ++++ src/livereload.coffee | 25 +++++++++++++++++++++++++ src/options.coffee | 3 +++ src/startup.coffee | 1 + 4 files changed, 33 insertions(+) diff --git a/README.md b/README.md index c6c5cf6..1cfb7ff 100644 --- a/README.md +++ b/README.md @@ -120,6 +120,10 @@ Alternatively, instead of loading livereload.js from the LiveReload server, you ``` +### Animated transitions + +LiveReload can animate changes. To enable animated transitions pass `animate=true` to `livereload.js` when including in the script tag. The default transition duration is 280ms and is configurable via `animation_duration`. The value is integer in milliseconds. + Issues & Limitations -------------------- diff --git a/src/livereload.coffee b/src/livereload.coffee index dbfd025..4244ddb 100644 --- a/src/livereload.coffee +++ b/src/livereload.coffee @@ -82,10 +82,19 @@ exports.LiveReload = class LiveReload originalPath: message.originalPath || '' overrideURL: message.overrideURL || '' serverURL: "http://#{@options.host}:#{@options.port}" + @performTransition() if !!(/true|1$/).test(LiveReload.options.animate) performAlert: (message) -> alert message.message + performTransition: -> + html = document.body.parentNode + reloadedClass = ' livereload-reloaded ' + existingHtmlClass = html.getAttribute('class') ? '' + html.setAttribute('class', "#{existingHtmlClass.replace(reloadedClass, '')} #{reloadedClass}") + setTimeout (-> html.setAttribute('class', existingHtmlClass.replace(reloadedClass, ''))), + parseInt(@options.animation_duration, 10) + 20 + shutDown: -> @connector.disconnect() @log "LiveReload disconnected." @@ -143,3 +152,19 @@ exports.LiveReload = class LiveReload @connector.sendCommand { command: 'info', plugins: pluginsData, url: @window.location.href } return + + setUpCSSTransitions: -> + prefixer = (declaration) -> + (['-webkit-', '-moz-', ''].map (item) -> ("#{item}#{declaration}")).join(' ') + + head = document.getElementsByTagName('head')[0] + styleNode = document.createElement("style") + cssText = ".livereload-reloaded * { #{prefixer('transition: all ' + + @options.animation_duration + 'ms ease-out;')} }" + + if styleNode.styleSheet + styleNode.styleSheet.cssText = cssText + else + styleNode.appendChild(document.createTextNode(cssText)) + + head.appendChild(styleNode) diff --git a/src/options.coffee b/src/options.coffee index 1175e51..1bc2c46 100644 --- a/src/options.coffee +++ b/src/options.coffee @@ -11,6 +11,9 @@ exports.Options = class Options @maxdelay = 60000 @handshake_timeout = 5000 + @animate = false + @animation_duration = 280 # ms + set: (name, value) -> if typeof value is 'undefined' return diff --git a/src/startup.coffee b/src/startup.coffee index e8882c4..96e7bd5 100644 --- a/src/startup.coffee +++ b/src/startup.coffee @@ -8,6 +8,7 @@ LiveReload.addPlugin require('./less') LiveReload.on 'shutdown', -> delete window.LiveReload LiveReload.on 'connect', -> + LiveReload.setUpCSSTransitions() if !!(/true|1$/).test(LiveReload.options.animate) CustomEvents.fire document, 'LiveReloadConnect' LiveReload.on 'disconnect', -> CustomEvents.fire document, 'LiveReloadDisconnect' From 8ca0340fdf8de912293c2f923af6c27bed5ba274 Mon Sep 17 00:00:00 2001 From: Tyom Semonov Date: Thu, 22 Jan 2015 21:48:00 +0000 Subject: [PATCH 2/5] Rebuild JS --- dist/livereload.js | 39 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 37 insertions(+), 2 deletions(-) diff --git a/dist/livereload.js b/dist/livereload.js index f6c3b7f..09a9861 100644 --- a/dist/livereload.js +++ b/dist/livereload.js @@ -385,19 +385,31 @@ LiveReload.prototype.performReload = function(message) { var _ref, _ref1; this.log("LiveReload received reload request: " + (JSON.stringify(message, null, 2))); - return this.reloader.reload(message.path, { + this.reloader.reload(message.path, { liveCSS: (_ref = message.liveCSS) != null ? _ref : true, liveImg: (_ref1 = message.liveImg) != null ? _ref1 : true, originalPath: message.originalPath || '', overrideURL: message.overrideURL || '', - serverURL: "http://" + this.options.host + ":" + this.options.port + serverURL: "//" + this.options.host + ":" + this.options.port }); + return this.performTransition(); }; LiveReload.prototype.performAlert = function(message) { return alert(message.message); }; + LiveReload.prototype.performTransition = function() { + var existingHtmlClass, html, reloadedClass, _ref; + html = document.body.parentNode; + reloadedClass = ' livereload-reloaded '; + existingHtmlClass = (_ref = html.getAttribute('class')) != null ? _ref : ''; + html.setAttribute('class', "" + (existingHtmlClass.replace(reloadedClass, '')) + " " + reloadedClass); + return setTimeout((function() { + return html.setAttribute('class', existingHtmlClass.replace(reloadedClass, '')); + }), parseInt(this.options.animation_duration, 10) + 20); + }; + LiveReload.prototype.shutDown = function() { var _base; this.connector.disconnect(); @@ -450,6 +462,24 @@ }); }; + LiveReload.prototype.setUpCSSTransitions = function() { + var cssText, head, prefixer, styleNode; + prefixer = function(declaration) { + return (['-webkit-', '-moz-', ''].map(function(item) { + return "" + item + declaration; + })).join(' '); + }; + head = document.getElementsByTagName('head')[0]; + styleNode = document.createElement("style"); + cssText = ".livereload-reloaded * { " + (prefixer('transition: all ' + this.options.animation_duration + 'ms ease-out;')) + " }"; + if (styleNode.styleSheet) { + styleNode.styleSheet.cssText = cssText; + } else { + styleNode.appendChild(document.createTextNode(cssText)); + } + return head.appendChild(styleNode); + }; + return LiveReload; })(); @@ -470,6 +500,8 @@ this.mindelay = 1000; this.maxdelay = 60000; this.handshake_timeout = 5000; + this.animate = false; + this.animation_duration = 280; } Options.prototype.set = function(name, value) { @@ -1095,6 +1127,9 @@ }); LiveReload.on('connect', function() { + if (!!/true|1$/.test(LiveReload.options.animate)) { + LiveReload.setUpCSSTransitions(); + } return CustomEvents.fire(document, 'LiveReloadConnect'); }); From 006f793091ff6eafa19150b4e6e37a73654bbf4b Mon Sep 17 00:00:00 2001 From: Tyom Semonov Date: Thu, 22 Jan 2015 21:48:34 +0000 Subject: [PATCH 3/5] Add HTML test case for animated transitions --- test/html/animation/test.css | 3 +++ test/html/animation/test.html | 11 +++++++++++ 2 files changed, 14 insertions(+) create mode 100644 test/html/animation/test.css create mode 100644 test/html/animation/test.html diff --git a/test/html/animation/test.css b/test/html/animation/test.css new file mode 100644 index 0000000..e541a38 --- /dev/null +++ b/test/html/animation/test.css @@ -0,0 +1,3 @@ +body { + background: green; +} diff --git a/test/html/animation/test.html b/test/html/animation/test.html new file mode 100644 index 0000000..a250652 --- /dev/null +++ b/test/html/animation/test.html @@ -0,0 +1,11 @@ + + + + LiveReload Test + + + +

Test animated transitions

+ + + From 92d6346cfeabcc43ed8ae62361c3b3a125319fdd Mon Sep 17 00:00:00 2001 From: Tyom Semonov Date: Sat, 24 Jan 2015 11:34:34 +0000 Subject: [PATCH 4/5] Revert "Rebuild JS" This reverts commit 8ca0340fdf8de912293c2f923af6c27bed5ba274. --- dist/livereload.js | 39 ++------------------------------------- 1 file changed, 2 insertions(+), 37 deletions(-) diff --git a/dist/livereload.js b/dist/livereload.js index 09a9861..f6c3b7f 100644 --- a/dist/livereload.js +++ b/dist/livereload.js @@ -385,31 +385,19 @@ LiveReload.prototype.performReload = function(message) { var _ref, _ref1; this.log("LiveReload received reload request: " + (JSON.stringify(message, null, 2))); - this.reloader.reload(message.path, { + return this.reloader.reload(message.path, { liveCSS: (_ref = message.liveCSS) != null ? _ref : true, liveImg: (_ref1 = message.liveImg) != null ? _ref1 : true, originalPath: message.originalPath || '', overrideURL: message.overrideURL || '', - serverURL: "//" + this.options.host + ":" + this.options.port + serverURL: "http://" + this.options.host + ":" + this.options.port }); - return this.performTransition(); }; LiveReload.prototype.performAlert = function(message) { return alert(message.message); }; - LiveReload.prototype.performTransition = function() { - var existingHtmlClass, html, reloadedClass, _ref; - html = document.body.parentNode; - reloadedClass = ' livereload-reloaded '; - existingHtmlClass = (_ref = html.getAttribute('class')) != null ? _ref : ''; - html.setAttribute('class', "" + (existingHtmlClass.replace(reloadedClass, '')) + " " + reloadedClass); - return setTimeout((function() { - return html.setAttribute('class', existingHtmlClass.replace(reloadedClass, '')); - }), parseInt(this.options.animation_duration, 10) + 20); - }; - LiveReload.prototype.shutDown = function() { var _base; this.connector.disconnect(); @@ -462,24 +450,6 @@ }); }; - LiveReload.prototype.setUpCSSTransitions = function() { - var cssText, head, prefixer, styleNode; - prefixer = function(declaration) { - return (['-webkit-', '-moz-', ''].map(function(item) { - return "" + item + declaration; - })).join(' '); - }; - head = document.getElementsByTagName('head')[0]; - styleNode = document.createElement("style"); - cssText = ".livereload-reloaded * { " + (prefixer('transition: all ' + this.options.animation_duration + 'ms ease-out;')) + " }"; - if (styleNode.styleSheet) { - styleNode.styleSheet.cssText = cssText; - } else { - styleNode.appendChild(document.createTextNode(cssText)); - } - return head.appendChild(styleNode); - }; - return LiveReload; })(); @@ -500,8 +470,6 @@ this.mindelay = 1000; this.maxdelay = 60000; this.handshake_timeout = 5000; - this.animate = false; - this.animation_duration = 280; } Options.prototype.set = function(name, value) { @@ -1127,9 +1095,6 @@ }); LiveReload.on('connect', function() { - if (!!/true|1$/.test(LiveReload.options.animate)) { - LiveReload.setUpCSSTransitions(); - } return CustomEvents.fire(document, 'LiveReloadConnect'); }); From 98f813611b5ba599002e5b946ffe510c9f6d4b2a Mon Sep 17 00:00:00 2001 From: Tyom Semonov Date: Sat, 24 Jan 2015 12:35:04 +0000 Subject: [PATCH 5/5] fixup! Implement animated change transitions --- README.md | 2 +- src/livereload.coffee | 6 +++--- src/options.coffee | 7 +++++-- src/startup.coffee | 2 +- 4 files changed, 10 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 1cfb7ff..0925a05 100644 --- a/README.md +++ b/README.md @@ -122,7 +122,7 @@ Alternatively, instead of loading livereload.js from the LiveReload server, you ### Animated transitions -LiveReload can animate changes. To enable animated transitions pass `animate=true` to `livereload.js` when including in the script tag. The default transition duration is 280ms and is configurable via `animation_duration`. The value is integer in milliseconds. +LiveReload can animate changes. To enable animated transitions pass `animate=true` to `livereload.js` when including in the script tag. The default transition duration is 280ms and configurable when an integer is passed as value to `animate`, e.g. `animate=400` (in milliseconds). Issues & Limitations diff --git a/src/livereload.coffee b/src/livereload.coffee index 4244ddb..ee03f30 100644 --- a/src/livereload.coffee +++ b/src/livereload.coffee @@ -82,7 +82,7 @@ exports.LiveReload = class LiveReload originalPath: message.originalPath || '' overrideURL: message.overrideURL || '' serverURL: "http://#{@options.host}:#{@options.port}" - @performTransition() if !!(/true|1$/).test(LiveReload.options.animate) + @performTransition() if @options.animate performAlert: (message) -> alert message.message @@ -93,7 +93,7 @@ exports.LiveReload = class LiveReload existingHtmlClass = html.getAttribute('class') ? '' html.setAttribute('class', "#{existingHtmlClass.replace(reloadedClass, '')} #{reloadedClass}") setTimeout (-> html.setAttribute('class', existingHtmlClass.replace(reloadedClass, ''))), - parseInt(@options.animation_duration, 10) + 20 + parseInt(@options.animate, 10) shutDown: -> @connector.disconnect() @@ -160,7 +160,7 @@ exports.LiveReload = class LiveReload head = document.getElementsByTagName('head')[0] styleNode = document.createElement("style") cssText = ".livereload-reloaded * { #{prefixer('transition: all ' + - @options.animation_duration + 'ms ease-out;')} }" + @options.animate + 'ms ease-out;')} }" if styleNode.styleSheet styleNode.styleSheet.cssText = cssText diff --git a/src/options.coffee b/src/options.coffee index 1bc2c46..965321e 100644 --- a/src/options.coffee +++ b/src/options.coffee @@ -11,8 +11,7 @@ exports.Options = class Options @maxdelay = 60000 @handshake_timeout = 5000 - @animate = false - @animation_duration = 280 # ms + @animate = false # true or value in milliseconds, e.g. 420 set: (name, value) -> if typeof value is 'undefined' @@ -21,6 +20,10 @@ exports.Options = class Options if not isNaN(+value) value = +value + if name == 'animate' + value = 280 if value is 'true' # default animation duration + return if !/true|^\d+$/.test(value) + @[name] = value Options.extract = (document) -> diff --git a/src/startup.coffee b/src/startup.coffee index 96e7bd5..744cc6f 100644 --- a/src/startup.coffee +++ b/src/startup.coffee @@ -8,7 +8,7 @@ LiveReload.addPlugin require('./less') LiveReload.on 'shutdown', -> delete window.LiveReload LiveReload.on 'connect', -> - LiveReload.setUpCSSTransitions() if !!(/true|1$/).test(LiveReload.options.animate) + LiveReload.setUpCSSTransitions() if LiveReload.options.animate CustomEvents.fire document, 'LiveReloadConnect' LiveReload.on 'disconnect', -> CustomEvents.fire document, 'LiveReloadDisconnect'