From c3913f59956a396446dc864c392a9e00f47139ce Mon Sep 17 00:00:00 2001 From: epriestley Date: Mon, 26 Jan 2015 09:34:57 -0800 Subject: [PATCH] Make scroll keys active immediately upon page load Summary: When JX.Scrollbar activates, the page needs to be clicked before scrolling keys work. Instead, set focus into the content after we set the page frame (if something else isn't already focused). Also fixes T7042. Test Plan: In Safari, Chrome and Firefox, scrolling with key commands is now immediately active. Reviewers: btrahan, chad Reviewed By: chad Subscribers: epriestley Maniphest Tasks: T7042 Differential Revision: https://secure.phabricator.com/D11508 --- resources/celerity/map.php | 46 +++++++++---------- .../application/base/standard-page-view.css | 5 ++ webroot/rsrc/css/core/z-index.css | 8 ++-- .../rsrc/externals/javelin/lib/Scrollbar.js | 23 ++++++++++ 4 files changed, 55 insertions(+), 27 deletions(-) diff --git a/resources/celerity/map.php b/resources/celerity/map.php index ed8c1a3e47..957910a984 100644 --- a/resources/celerity/map.php +++ b/resources/celerity/map.php @@ -7,8 +7,8 @@ */ return array( 'names' => array( - 'core.pkg.css' => 'a793698c', - 'core.pkg.js' => '63963771', + 'core.pkg.css' => '30ec4610', + 'core.pkg.js' => '55716d41', 'darkconsole.pkg.js' => '8ab24e01', 'differential.pkg.css' => '8af45893', 'differential.pkg.js' => 'f437e70e', @@ -39,7 +39,7 @@ return array( 'rsrc/css/application/base/main-menu-view.css' => '7bb9c588', 'rsrc/css/application/base/notification-menu.css' => '6aa0a74b', 'rsrc/css/application/base/phabricator-application-launch-view.css' => '16ca323f', - 'rsrc/css/application/base/standard-page-view.css' => '6dafdb3b', + 'rsrc/css/application/base/standard-page-view.css' => '661ae3e3', 'rsrc/css/application/chatlog/chatlog.css' => '852140ff', 'rsrc/css/application/config/config-options.css' => '7fedf08b', 'rsrc/css/application/config/config-template.css' => '25d446d6', @@ -107,7 +107,7 @@ return array( 'rsrc/css/core/core.css' => 'd7f6ec35', 'rsrc/css/core/remarkup.css' => '0ee3d256', 'rsrc/css/core/syntax.css' => '56c1ba38', - 'rsrc/css/core/z-index.css' => '07df2e53', + 'rsrc/css/core/z-index.css' => '40eb7003', 'rsrc/css/diviner/diviner-shared.css' => '38813222', 'rsrc/css/font/font-awesome.css' => '21b0ced7', 'rsrc/css/font/font-source-sans-pro.css' => '91d53463', @@ -188,7 +188,7 @@ return array( 'rsrc/externals/javelin/ext/view/__tests__/ViewInterpreter.js' => '7a94d6a5', 'rsrc/externals/javelin/ext/view/__tests__/ViewRenderer.js' => '6ea96ac9', 'rsrc/externals/javelin/lib/Cookie.js' => '62dfea03', - 'rsrc/externals/javelin/lib/DOM.js' => 'c5ca25cf', + 'rsrc/externals/javelin/lib/DOM.js' => '2d66f6ec', 'rsrc/externals/javelin/lib/History.js' => 'c60f4327', 'rsrc/externals/javelin/lib/JSON.js' => '69adf288', 'rsrc/externals/javelin/lib/Leader.js' => '331b1611', @@ -197,7 +197,7 @@ return array( 'rsrc/externals/javelin/lib/Resource.js' => '44959b73', 'rsrc/externals/javelin/lib/Routable.js' => 'b3e7d692', 'rsrc/externals/javelin/lib/Router.js' => '29274e2b', - 'rsrc/externals/javelin/lib/Scrollbar.js' => '814d9ea1', + 'rsrc/externals/javelin/lib/Scrollbar.js' => '479fd9f1', 'rsrc/externals/javelin/lib/URI.js' => '6eff08aa', 'rsrc/externals/javelin/lib/Vector.js' => 'cc1bd0b0', 'rsrc/externals/javelin/lib/WebSocket.js' => '3f840822', @@ -648,7 +648,7 @@ return array( 'javelin-color' => '7e41274a', 'javelin-cookie' => '62dfea03', 'javelin-diffusion-locate-file-source' => 'b42eddc7', - 'javelin-dom' => 'c5ca25cf', + 'javelin-dom' => '2d66f6ec', 'javelin-dynval' => 'f6555212', 'javelin-event' => '85ea0626', 'javelin-fx' => '54b612ba', @@ -666,7 +666,7 @@ return array( 'javelin-resource' => '44959b73', 'javelin-routable' => 'b3e7d692', 'javelin-router' => '29274e2b', - 'javelin-scrollbar' => '814d9ea1', + 'javelin-scrollbar' => '479fd9f1', 'javelin-stratcom' => '8b0ad945', 'javelin-tokenizer' => '7644823e', 'javelin-typeahead' => '70baed2f', @@ -731,7 +731,7 @@ return array( 'phabricator-side-menu-view-css' => '7e8c6341', 'phabricator-slowvote-css' => '266df6a1', 'phabricator-source-code-view-css' => '7d346aa4', - 'phabricator-standard-page-view' => '6dafdb3b', + 'phabricator-standard-page-view' => '661ae3e3', 'phabricator-textareautils' => '5c93c52c', 'phabricator-title' => '5c1c758c', 'phabricator-tooltip' => '1d298e3a', @@ -747,7 +747,7 @@ return array( 'phabricator-uiexample-reactor-select' => 'a155550f', 'phabricator-uiexample-reactor-sendclass' => '1def2711', 'phabricator-uiexample-reactor-sendproperties' => 'b1f0ccee', - 'phabricator-zindex-css' => '07df2e53', + 'phabricator-zindex-css' => '40eb7003', 'phame-css' => '19ecc703', 'pholio-css' => '95174bdd', 'pholio-edit-css' => '3ad9d1ee', @@ -999,6 +999,13 @@ return array( 'javelin-stratcom', 'phabricator-keyboard-shortcut', ), + '2d66f6ec' => array( + 'javelin-magical-init', + 'javelin-install', + 'javelin-util', + 'javelin-vector', + 'javelin-stratcom', + ), '2f6efe18' => array( 'javelin-behavior', 'javelin-dom', @@ -1109,6 +1116,12 @@ return array( 'javelin-view-renderer', 'javelin-install', ), + '479fd9f1' => array( + 'javelin-install', + 'javelin-dom', + 'javelin-stratcom', + 'javelin-vector', + ), '47c794d8' => array( 'javelin-install', 'javelin-dom', @@ -1372,12 +1385,6 @@ return array( 'javelin-behavior', 'javelin-history', ), - '814d9ea1' => array( - 'javelin-install', - 'javelin-dom', - 'javelin-stratcom', - 'javelin-vector', - ), 82439934 => array( 'javelin-behavior', 'javelin-dom', @@ -1689,13 +1696,6 @@ return array( 'javelin-stratcom', 'javelin-vector', ), - 'c5ca25cf' => array( - 'javelin-magical-init', - 'javelin-install', - 'javelin-util', - 'javelin-vector', - 'javelin-stratcom', - ), 'c60f4327' => array( 'javelin-stratcom', 'javelin-install', diff --git a/webroot/rsrc/css/application/base/standard-page-view.css b/webroot/rsrc/css/application/base/standard-page-view.css index ac7b125697..8fb217fd66 100644 --- a/webroot/rsrc/css/application/base/standard-page-view.css +++ b/webroot/rsrc/css/application/base/standard-page-view.css @@ -194,3 +194,8 @@ a.handle-disabled { .jx-scrollbar-bar .jx-scrollbar-visible { opacity: 0.7; } + +.jx-scrollbar-link { + position: absolute; + left: -50px; +} diff --git a/webroot/rsrc/css/core/z-index.css b/webroot/rsrc/css/core/z-index.css index 4eb282803e..ca82849aea 100644 --- a/webroot/rsrc/css/core/z-index.css +++ b/webroot/rsrc/css/core/z-index.css @@ -97,6 +97,10 @@ z-index: 9; } +.jx-scrollbar-bar { + z-index: 9; +} + .jx-mask { z-index: 10; } @@ -129,10 +133,6 @@ div.jx-typeahead-results { z-index: 17; } -.jx-scrollbar-bar { - z-index: 18; -} - .pholio-device-lightbox { z-index: 20; } diff --git a/webroot/rsrc/externals/javelin/lib/Scrollbar.js b/webroot/rsrc/externals/javelin/lib/Scrollbar.js index 573ddb1daf..f0373e58ca 100644 --- a/webroot/rsrc/externals/javelin/lib/Scrollbar.js +++ b/webroot/rsrc/externals/javelin/lib/Scrollbar.js @@ -147,6 +147,29 @@ JX.install('Scrollbar', { // If we activated the scrollbar, the viewport and content nodes become // the new scroll and content frames. JX.DOM.setContentFrame(this._viewport, this._content); + + // If nothing is focused, or the document body is focused, change focus + // to the viewport. This makes the arrow keys, spacebar, and page + // up/page down keys work immediately after the page loads, without + // requiring a click. + + // Focusing the
itself doesn't work on any browser, so we + // add a fake, focusable element and focus that instead. + var focus = document.activeElement; + if (!focus || focus == window.document.body) { + var link = JX.$N('a', {href: '#', className: 'jx-scrollbar-link'}); + JX.DOM.listen(link, 'blur', null, function() { + // When the user clicks anything else, remove this. + JX.DOM.remove(link); + }); + JX.DOM.listen(link, 'click', null, function(e) { + // Don't respond to clicks. Since the link isn't visible, this + // most likely means the user hit enter or something like that. + e.kill(); + }); + JX.DOM.prependContent(this._viewport, link); + JX.DOM.focus(link); + } } else { // Otherwise, the unaltered content frame is both the scroll frame and // content frame.