From 4dd7a2a304416241eacdb12cc9c8b3ec10af97e2 Mon Sep 17 00:00:00 2001 From: Nikita Vasilyev Date: Tue, 17 Sep 2013 22:47:29 -0400 Subject: [PATCH] Share and Enjoy! --- .gitignore | 6 ++ FlyingFocus.safariextension/Icon-64.png | Bin 0 -> 1550 bytes FlyingFocus.safariextension/Info.plist | 54 ++++++++++++++++++ MIT-LICENSE.txt | 20 +++++++ README.markdown | 22 ++++++++ Rakefile | 28 ++++++++++ chrome/flying-focus.css | 28 ++++++++++ chrome/flying-focus.js | 70 ++++++++++++++++++++++++ chrome/icon_128.png | Bin 0 -> 1679 bytes chrome/icon_48.png | Bin 0 -> 1038 bytes chrome/manifest.json | 17 ++++++ standalone/flying-focus.jspp.js | 11 ++++ 12 files changed, 256 insertions(+) create mode 100644 .gitignore create mode 100644 FlyingFocus.safariextension/Icon-64.png create mode 100644 FlyingFocus.safariextension/Info.plist create mode 100644 MIT-LICENSE.txt create mode 100644 README.markdown create mode 100644 Rakefile create mode 100644 chrome/flying-focus.css create mode 100644 chrome/flying-focus.js create mode 100644 chrome/icon_128.png create mode 100644 chrome/icon_48.png create mode 100644 chrome/manifest.json create mode 100644 standalone/flying-focus.jspp.js diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ac52de0 --- /dev/null +++ b/.gitignore @@ -0,0 +1,6 @@ +# rake standalone +standalone/flying-focus.js + +# rake safari +FlyingFocus.safariextension/flying-focus.css +FlyingFocus.safariextension/flying-focus.js diff --git a/FlyingFocus.safariextension/Icon-64.png b/FlyingFocus.safariextension/Icon-64.png new file mode 100644 index 0000000000000000000000000000000000000000..5bdca83c5950447adc3a2491bb89ebf39ecd8542 GIT binary patch literal 1550 zcmV+p2J!icP)`uy+q`|I=i>ht>d`~2te`P%9B*XQ-v==J{p|I_94+UfP+?Dya7 z_x=9h|sR`}+L;`~Cj#_xsf5^ycyT`1<|){QmFt`{3>O z*XZ@u=JeL*^w;S0&*JmH+3&g5?Z@8n*y!}nY>NyoyF#- z%jmGs>$1}8{r>;o?f13R?5WG>!P@V@+3&#G@443QsLSZH((Jz3@4?&e*y;7J&+4_) z?C$mZ;_mm*GJvQ^!l;U?C$jY`1}3g?)cg0_3QNd`~3an@A%#8_VD)m z#N6<-)9u{q_V@bz?)CcF>Gsm(^!WS!(S%$^Y{Gu`~La-{>$O=z1Z%$ z*Y2py>7>c%uh8nc*6qC4?y%76mcZnWyyB$E=egDFzS-{N@cFOM>xH-Ad$HYpv)+EP z-g~j$cdy)auG@LA+<&v)d9dAas@iR-*>$bleX`wtv)=sv{>$LzG_WQ%!@Z0J3{{H^5((K;s_xt?**yr__!Q{Hu z?&I$F?e+S%)a`q+-IKrL`TYH@&g$ar_^Hk5i@M>(-SFe@_@2e)sLScv==P<_=yk5# zh`8b0>GsIp@wC$H@%Q_%(d&=B;??H$u+Z%E`TV=q?%eD4z1Qx(*ze%&__5IIyVvb- zs@km1>BQUctIiBl3A_l3PL?EUfj5>K9ZYOtU3LX8WDjneiFIKR zW+4`Iz-|gD!Ud18P(rCBlY$p@5ndTf2eN$CbetLIo$=XyN1lr({*SNWO^DxH;WOYf z`2PtyX8#)iaFT=&dcch%0V1IT(vAp3H9%I(a61Y1=UcvQ9teaDx7!g&BrLzl11`fb zTz}Ky6(lXoO6mdkUk*TF;+Q}Xz#rrY1boB?Bn%)Sh+?K5xCeGTV7HSM7k0nsfO|8v zuZe^9?DyPV)c}vDK7=RsUG`597u%V)i63~tRSPUtEbkCg<|D8RJ-qms5Z@(vp!lDs zHUg8x*Mx7f?N?|t^S;ggT@S3R6JJ517PBT%e)*xm*5V%Vy#P$aiKrRCm*fbPRFm4S zABfIXQZ`aWh~|FN1MQo6KuiI=KRpP*^2EKcGkrpAhu zw0dfA?N3r0!HxP>BJzAT-OxfrMFV0s{)Gkz1WP{-k(zO5x$ni7iSi$4KOadFJ<;*& znyCjocfF+fgW|2oNqvz_@yWnEGqPAf&b;cCk*>jKE0!lB88da~Rq#F@TU0hXdruDjWn5y6-B#6y(Ta06Fuf@WDlVUsW%N zNzObDkV7-Jgink5J3nFpIW$>7X1~JtIB9bLnB&T%99K2wymQI(&H(Db;1kNgP-7+z z11J+mjTu=?%E(e;M1& literal 0 HcmV?d00001 diff --git a/FlyingFocus.safariextension/Info.plist b/FlyingFocus.safariextension/Info.plist new file mode 100644 index 0000000..4c8dbd6 --- /dev/null +++ b/FlyingFocus.safariextension/Info.plist @@ -0,0 +1,54 @@ + + + + + Author + Nikita Vasilyev + Builder Version + 9537.66 + CFBundleDisplayName + Flying Focus + CFBundleIdentifier + com.n12v.flying-focus + CFBundleInfoDictionaryVersion + 6.0 + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1.0 + Chrome + + Content + + Scripts + + End + + flying-focus.js + + + Stylesheets + + flying-focus.css + + + Description + Smooth focus transition + ExtensionInfoDictionaryVersion + 1.0 + Permissions + + Website Access + + Include Secure Pages + + Level + All + + + Update Manifest URL + http://n12v.com/focus-transition/update.plist + Website + http://n12v.com/focus-transition/ + + diff --git a/MIT-LICENSE.txt b/MIT-LICENSE.txt new file mode 100644 index 0000000..bc57aac --- /dev/null +++ b/MIT-LICENSE.txt @@ -0,0 +1,20 @@ +Copyright (c) Nikita Vasilyev + +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. diff --git a/README.markdown b/README.markdown new file mode 100644 index 0000000..84d7e96 --- /dev/null +++ b/README.markdown @@ -0,0 +1,22 @@ +# [Focus Transition](http://n12v.com/focus-transition/) + +![Flying Focus icon](http://nv.github.io/flying-focus/chrome/icon_128.png) + +Flying Focus is a UI concept. + +# How to build + +## A single-file library + +Create a flying-focus.js that can be included to any web page. +It includes all necessary CSS and has no external dependencies. + + rake standalone + +## Safari extension + + rake safari + +## Chrome extension + +No build step required. Just load it as an unpacked extension from `chrome/`. diff --git a/Rakefile b/Rakefile new file mode 100644 index 0000000..287e626 --- /dev/null +++ b/Rakefile @@ -0,0 +1,28 @@ +task :default => [:safari, :standalone] + +desc 'Build standalone file' +task :standalone => ['chrome/flying-focus.js', 'chrome/flying-focus.css'] do + require 'jspp' + File.open('standalone/flying-focus.js', 'w') { |file| + text = JSPP('standalone/flying-focus.jspp.js') + file.write(text) + } + puts 'standalone/flying-focus.js' +end + + +desc 'Build Safari extension to ./FlyingFocus.safariextension/' +task :safari => ['chrome/flying-focus.js', 'chrome/flying-focus.css'] do + cp_r ['chrome/flying-focus.js', 'chrome/flying-focus.css'], 'FlyingFocus.safariextension' + puts 'FlyingFocus.safariextension' +end + +#FIXME +#task :firefox do +# +#end + +#FIXME +#task :ie do +# +#end diff --git a/chrome/flying-focus.css b/chrome/flying-focus.css new file mode 100644 index 0000000..4cf379b --- /dev/null +++ b/chrome/flying-focus.css @@ -0,0 +1,28 @@ +#flying-focus { + position: absolute; + margin: 0; + background: transparent; + -webkit-transition-property: left, top, width, height, opacity; + transition-property: left, top, width, height, opacity; + -webkit-transition-timing-function: cubic-bezier(0, 0.2, 0, 1); + transition-timing-function: cubic-bezier(0, 0.2, 0, 1); + visibility: hidden; + pointer-events: none; + box-shadow: 0 0 2px 3px #78aeda, 0 0 2px #78aeda inset; border-radius: 2px; +} +#flying-focus.flying-focus_visible { + visibility: visible; + z-index: 9999; +} +.flying-focus_target { + outline: none !important; /* Doens't work in Firefox :( */ +} + +/* Replace it with @supports rule when browsers catch up */ +@media screen and (-webkit-min-device-pixel-ratio: 0) { + #flying-focus { + box-shadow: none; + outline: 5px auto -webkit-focus-ring-color; + outline-offset: -3px; + } +} diff --git a/chrome/flying-focus.js b/chrome/flying-focus.js new file mode 100644 index 0000000..0bea586 --- /dev/null +++ b/chrome/flying-focus.js @@ -0,0 +1,70 @@ +var flyingFocus = document.createElement('flying-focus'); // use uniq element name to decrease the chances of a conflict with website styles +flyingFocus.id = 'flying-focus'; +document.body.appendChild(flyingFocus); + +var DURATION = 100; +flyingFocus.style.transitionDuration = flyingFocus.style.WebkitTransitionDuration = DURATION / 1000 + 's'; + +function offsetOf(elem) { + var rect = elem.getBoundingClientRect(); + var docElem = document.documentElement; + var win = document.defaultView; + var body = document.body; + + var clientTop = docElem.clientTop || body.clientTop || 0, + clientLeft = docElem.clientLeft || body.clientLeft || 0, + scrollTop = win.pageYOffset || docElem.scrollTop || body.scrollTop, + scrollLeft = win.pageXOffset || docElem.scrollLeft || body.scrollLeft, + top = rect.top + scrollTop - clientTop, + left = rect.left + scrollLeft - clientLeft; + + return {top: top, left: left}; +} + +var movingId = 0; + +var prevFocused; + +document.documentElement.addEventListener('focus', function(event) { + var target = event.target; + if (target.id === 'flying-focus') { + return; + } + var offset = offsetOf(target); + flyingFocus.style.left = offset.left + 'px'; + flyingFocus.style.top = offset.top + 'px'; + flyingFocus.style.width = target.offsetWidth + 'px'; + flyingFocus.style.height = target.offsetHeight + 'px'; + + // Would be nice to use: + // + // flyingFocus.style['outline-offset'] = getComputedStyle(target, null)['outline-offset'] + // + // but it always '0px' in WebKit and Blink for some reason :( + + if (prevFocused) { + target.classList.add('flying-focus_target'); + show(); + if (movingId) { + clearTimeout(movingId); + } + movingId = setTimeout(function() { + target.classList.remove('flying-focus_target'); + hide(); + }, DURATION); + } + prevFocused = target; +}, true); + +document.documentElement.addEventListener('blur', function() { + hide(); +}, true); + + +function hide() { + flyingFocus.classList.remove('flying-focus_visible'); +} + +function show() { + flyingFocus.classList.add('flying-focus_visible'); +} diff --git a/chrome/icon_128.png b/chrome/icon_128.png new file mode 100644 index 0000000000000000000000000000000000000000..41d1177d82633933fdda4eafa1dae9d398c33974 GIT binary patch literal 1679 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 IM6N<$g7tWSa{vGU literal 0 HcmV?d00001 diff --git a/chrome/manifest.json b/chrome/manifest.json new file mode 100644 index 0000000..9daa421 --- /dev/null +++ b/chrome/manifest.json @@ -0,0 +1,17 @@ +{ + "manifest_version": 2, + "name": "Flying Focus", + "version": "1.0", + "description": "Smooth focus transition", + "content_scripts": [ + { + "js": ["flying-focus.js"], + "css": ["flying-focus.css"], + "matches": [ + "" + ] + } + ], + "author": "Nikita Vasilyev", + "homepage_url": "http://n12v.com/focus-transition/" +} diff --git a/standalone/flying-focus.jspp.js b/standalone/flying-focus.jspp.js new file mode 100644 index 0000000..b652ca8 --- /dev/null +++ b/standalone/flying-focus.jspp.js @@ -0,0 +1,11 @@ +(function() { + +if (document.getElementById('flying-focus')) return; + +/*> ../chrome/flying-focus.js */ + +var style = document.createElement('style'); +style.textContent = "/*> ../chrome/flying-focus.css */"; +document.body.appendChild(style); + +})();