From cd5038e973a1af94ef6e552f44563cc0acf563aa Mon Sep 17 00:00:00 2001 From: epriestley Date: Sat, 9 Mar 2013 13:53:32 -0800 Subject: [PATCH] Support basic swipe gestures in Pholio Summary: Ref 2700. No sexy animation yet, but allows you to swipe left and right to switch photos. Generally feels pretty good to me. Also fixes a left/right but and a bug where taps could be interpreted as gestures and simplifies some touch code. derpdog Test Plan: Swiped left and right in Pholio. {F35239} Reviewers: chad Reviewed By: chad CC: aran Differential Revision: https://secure.phabricator.com/D5309 --- src/__celerity_resource_map__.php | 80 +++++++++---------- .../pholio/view/PholioMockImagesView.php | 2 +- .../rsrc/css/application/pholio/pholio.css | 19 +++++ .../js/application/core/behavior-gesture.js | 36 ++++----- .../pholio/behavior-pholio-mock-view.js | 10 +++ 5 files changed, 87 insertions(+), 60 deletions(-) diff --git a/src/__celerity_resource_map__.php b/src/__celerity_resource_map__.php index 7c4a5557f7..23a6dc568e 100644 --- a/src/__celerity_resource_map__.php +++ b/src/__celerity_resource_map__.php @@ -1750,7 +1750,7 @@ celerity_register_resource_map(array( ), 'javelin-behavior-phabricator-gesture' => array( - 'uri' => '/res/1222d486/rsrc/js/application/core/behavior-gesture.js', + 'uri' => '/res/f186161c/rsrc/js/application/core/behavior-gesture.js', 'type' => 'js', 'requires' => array( @@ -1963,7 +1963,7 @@ celerity_register_resource_map(array( ), 'javelin-behavior-pholio-mock-view' => array( - 'uri' => '/res/6b8ca4e4/rsrc/js/application/pholio/behavior-pholio-mock-view.js', + 'uri' => '/res/c0f94452/rsrc/js/application/pholio/behavior-pholio-mock-view.js', 'type' => 'js', 'requires' => array( @@ -3313,7 +3313,7 @@ celerity_register_resource_map(array( ), 'pholio-css' => array( - 'uri' => '/res/4535277b/rsrc/css/application/pholio/pholio.css', + 'uri' => '/res/bc10bf21/rsrc/css/application/pholio/pholio.css', 'type' => 'css', 'requires' => array( @@ -3576,7 +3576,7 @@ celerity_register_resource_map(array( 'uri' => '/res/pkg/fdd3bb5f/core.pkg.css', 'type' => 'css', ), - '9abfe389' => + '95ceba95' => array( 'name' => 'core.pkg.js', 'symbols' => @@ -3617,7 +3617,7 @@ celerity_register_resource_map(array( 33 => 'javelin-behavior-global-drag-and-drop', 34 => 'javelin-behavior-phabricator-reveal-content', ), - 'uri' => '/res/pkg/9abfe389/core.pkg.js', + 'uri' => '/res/pkg/95ceba95/core.pkg.js', 'type' => 'js', ), 'dca4a03d' => @@ -3790,17 +3790,17 @@ celerity_register_resource_map(array( 'diffusion-icons-css' => 'c8ce2d88', 'global-drag-and-drop-css' => 'fdd3bb5f', 'inline-comment-summary-css' => '8aaacd1b', - 'javelin-aphlict' => '9abfe389', + 'javelin-aphlict' => '95ceba95', 'javelin-behavior' => 'cd1d650a', - 'javelin-behavior-aphlict-dropdown' => '9abfe389', - 'javelin-behavior-aphlict-listen' => '9abfe389', - 'javelin-behavior-aphront-basic-tokenizer' => '9abfe389', + 'javelin-behavior-aphlict-dropdown' => '95ceba95', + 'javelin-behavior-aphlict-listen' => '95ceba95', + 'javelin-behavior-aphront-basic-tokenizer' => '95ceba95', 'javelin-behavior-aphront-drag-and-drop' => '322728f3', 'javelin-behavior-aphront-drag-and-drop-textarea' => '322728f3', - 'javelin-behavior-aphront-form-disable-on-submit' => '9abfe389', + 'javelin-behavior-aphront-form-disable-on-submit' => '95ceba95', 'javelin-behavior-audit-preview' => 'f96657b8', 'javelin-behavior-dark-console' => 'dca4a03d', - 'javelin-behavior-device' => '9abfe389', + 'javelin-behavior-device' => '95ceba95', 'javelin-behavior-differential-accept-with-errors' => '322728f3', 'javelin-behavior-differential-add-reviewers-and-ccs' => '322728f3', 'javelin-behavior-differential-comment-jump' => '322728f3', @@ -3816,32 +3816,32 @@ celerity_register_resource_map(array( 'javelin-behavior-diffusion-commit-graph' => 'f96657b8', 'javelin-behavior-diffusion-pull-lastmodified' => 'f96657b8', 'javelin-behavior-error-log' => 'dca4a03d', - 'javelin-behavior-global-drag-and-drop' => '9abfe389', - 'javelin-behavior-history-install' => '9abfe389', - 'javelin-behavior-konami' => '9abfe389', - 'javelin-behavior-lightbox-attachments' => '9abfe389', + 'javelin-behavior-global-drag-and-drop' => '95ceba95', + 'javelin-behavior-history-install' => '95ceba95', + 'javelin-behavior-konami' => '95ceba95', + 'javelin-behavior-lightbox-attachments' => '95ceba95', 'javelin-behavior-load-blame' => '322728f3', 'javelin-behavior-maniphest-batch-selector' => '7707de41', 'javelin-behavior-maniphest-subpriority-editor' => '7707de41', 'javelin-behavior-maniphest-transaction-controls' => '7707de41', 'javelin-behavior-maniphest-transaction-expand' => '7707de41', 'javelin-behavior-maniphest-transaction-preview' => '7707de41', - 'javelin-behavior-phabricator-active-nav' => '9abfe389', - 'javelin-behavior-phabricator-autofocus' => '9abfe389', - 'javelin-behavior-phabricator-gesture' => '9abfe389', - 'javelin-behavior-phabricator-keyboard-shortcuts' => '9abfe389', - 'javelin-behavior-phabricator-nav' => '9abfe389', + 'javelin-behavior-phabricator-active-nav' => '95ceba95', + 'javelin-behavior-phabricator-autofocus' => '95ceba95', + 'javelin-behavior-phabricator-gesture' => '95ceba95', + 'javelin-behavior-phabricator-keyboard-shortcuts' => '95ceba95', + 'javelin-behavior-phabricator-nav' => '95ceba95', 'javelin-behavior-phabricator-object-selector' => '322728f3', - 'javelin-behavior-phabricator-oncopy' => '9abfe389', - 'javelin-behavior-phabricator-remarkup-assist' => '9abfe389', - 'javelin-behavior-phabricator-reveal-content' => '9abfe389', - 'javelin-behavior-phabricator-search-typeahead' => '9abfe389', - 'javelin-behavior-phabricator-tooltips' => '9abfe389', - 'javelin-behavior-phabricator-watch-anchor' => '9abfe389', - 'javelin-behavior-refresh-csrf' => '9abfe389', + 'javelin-behavior-phabricator-oncopy' => '95ceba95', + 'javelin-behavior-phabricator-remarkup-assist' => '95ceba95', + 'javelin-behavior-phabricator-reveal-content' => '95ceba95', + 'javelin-behavior-phabricator-search-typeahead' => '95ceba95', + 'javelin-behavior-phabricator-tooltips' => '95ceba95', + 'javelin-behavior-phabricator-watch-anchor' => '95ceba95', + 'javelin-behavior-refresh-csrf' => '95ceba95', 'javelin-behavior-repository-crossreference' => '322728f3', - 'javelin-behavior-toggle-class' => '9abfe389', - 'javelin-behavior-workflow' => '9abfe389', + 'javelin-behavior-toggle-class' => '95ceba95', + 'javelin-behavior-workflow' => '95ceba95', 'javelin-dom' => 'cd1d650a', 'javelin-event' => 'cd1d650a', 'javelin-install' => 'cd1d650a', @@ -3863,39 +3863,39 @@ celerity_register_resource_map(array( 'lightbox-attachment-css' => 'fdd3bb5f', 'maniphest-task-summary-css' => 'eb35a026', 'maniphest-transaction-detail-css' => 'eb35a026', - 'phabricator-busy' => '9abfe389', + 'phabricator-busy' => '95ceba95', 'phabricator-content-source-view-css' => '8aaacd1b', 'phabricator-core-buttons-css' => 'fdd3bb5f', 'phabricator-core-css' => 'fdd3bb5f', 'phabricator-crumbs-view-css' => 'fdd3bb5f', 'phabricator-directory-css' => 'fdd3bb5f', 'phabricator-drag-and-drop-file-upload' => '322728f3', - 'phabricator-dropdown-menu' => '9abfe389', - 'phabricator-file-upload' => '9abfe389', + 'phabricator-dropdown-menu' => '95ceba95', + 'phabricator-file-upload' => '95ceba95', 'phabricator-filetree-view-css' => 'fdd3bb5f', 'phabricator-flag-css' => 'fdd3bb5f', 'phabricator-form-view-css' => 'fdd3bb5f', 'phabricator-header-view-css' => 'fdd3bb5f', 'phabricator-jump-nav' => 'fdd3bb5f', - 'phabricator-keyboard-shortcut' => '9abfe389', - 'phabricator-keyboard-shortcut-manager' => '9abfe389', + 'phabricator-keyboard-shortcut' => '95ceba95', + 'phabricator-keyboard-shortcut-manager' => '95ceba95', 'phabricator-main-menu-view' => 'fdd3bb5f', - 'phabricator-menu-item' => '9abfe389', + 'phabricator-menu-item' => '95ceba95', 'phabricator-nav-view-css' => 'fdd3bb5f', - 'phabricator-notification' => '9abfe389', + 'phabricator-notification' => '95ceba95', 'phabricator-notification-css' => 'fdd3bb5f', 'phabricator-notification-menu-css' => 'fdd3bb5f', 'phabricator-object-item-list-view-css' => 'fdd3bb5f', 'phabricator-object-selector-css' => '8aaacd1b', - 'phabricator-paste-file-upload' => '9abfe389', - 'phabricator-prefab' => '9abfe389', + 'phabricator-paste-file-upload' => '95ceba95', + 'phabricator-prefab' => '95ceba95', 'phabricator-project-tag-css' => 'eb35a026', 'phabricator-remarkup-css' => 'fdd3bb5f', 'phabricator-shaped-request' => '322728f3', 'phabricator-side-menu-view-css' => 'fdd3bb5f', 'phabricator-standard-page-view' => 'fdd3bb5f', - 'phabricator-textareautils' => '9abfe389', - 'phabricator-tooltip' => '9abfe389', + 'phabricator-textareautils' => '95ceba95', + 'phabricator-tooltip' => '95ceba95', 'phabricator-transaction-view-css' => 'fdd3bb5f', 'phabricator-zindex-css' => 'fdd3bb5f', 'sprite-apps-large-css' => 'fdd3bb5f', diff --git a/src/applications/pholio/view/PholioMockImagesView.php b/src/applications/pholio/view/PholioMockImagesView.php index ef018537b6..8ca08ec93d 100644 --- a/src/applications/pholio/view/PholioMockImagesView.php +++ b/src/applications/pholio/view/PholioMockImagesView.php @@ -94,7 +94,7 @@ final class PholioMockImagesView extends AphrontView { 'div', array( 'id' => $panel_id, - 'sigil' => 'mock-panel', + 'sigil' => 'mock-panel touchable', 'class' => 'pholio-mock-image-panel', ), $mock_wrapper); diff --git a/webroot/rsrc/css/application/pholio/pholio.css b/webroot/rsrc/css/application/pholio/pholio.css index 03f7f94297..1643016ccf 100644 --- a/webroot/rsrc/css/application/pholio/pholio.css +++ b/webroot/rsrc/css/application/pholio/pholio.css @@ -38,6 +38,25 @@ border-color: #686868; } +.device .pholio-mock-carousel-thumb-item { + width: 5px; + height: 5px; + padding: 0px; + border-radius: 5px; + margin: 5px 2px; + background: #383838; + border-color: #686868; +} + +.device .pholio-mock-carousel-thumb-current { + background: #dfdfdf; + border-color: #ffffff; +} + +.device .pholio-mock-carousel-thumb-item img { + display: none; +} + .pholio-mock-carousel-thumbnail { margin: auto; position: relative; diff --git a/webroot/rsrc/js/application/core/behavior-gesture.js b/webroot/rsrc/js/application/core/behavior-gesture.js index 9a352afe85..1c4b930f89 100644 --- a/webroot/rsrc/js/application/core/behavior-gesture.js +++ b/webroot/rsrc/js/application/core/behavior-gesture.js @@ -20,7 +20,7 @@ JX.behavior('phabricator-gesture', function(config) { var p1; JX.Stratcom.listen( - ['touchstart', 'mousedown'], + ['touchstart', 'touchcancel', 'mousedown'], 'touchable', function(e) { if (JX.Device.getDevice() == 'desktop') { @@ -29,14 +29,12 @@ JX.behavior('phabricator-gesture', function(config) { if (JX.Stratcom.pass()) { return; } - - if (target && e.getType() == 'touchstart') { - // This corresponds to a second finger touching while the first finger - // is held: stop the swipe. - var event_data = get_swipe_data(); - var event_target = target; - stop_swipe(); - JX.DOM.invoke(event_target, 'gesture.swipe.cancel', event_data); + if (target) { + try { + JX.DOM.invoke(target, 'gesture.swipe.cancel', get_swipe_data()); + } finally { + stop_swipe(); + } return; } @@ -89,30 +87,30 @@ JX.behavior('phabricator-gesture', function(config) { }); JX.Stratcom.listen( - ['touchend', 'touchcancel', 'mouseup'], + ['touchend', 'mouseup'], null, function(e) { if (!target) { return; } - // NOTE: Clear the event state first so we don't keep swiping if a - // handler throws. - var event_target = target; - var event_data = get_swipe_data(); - stop_swipe(); - - JX.DOM.invoke(event_target, 'gesture.swipe.end', event_data); + try { + if (swiping) { + JX.DOM.invoke(target, 'gesture.swipe.end', get_swipe_data()); + } + } finally { + stop_swipe(); + } }); function get_swipe_data() { - var dir = (p1.x > p0.x) ? 'left' : 'right'; + var direction = (p1.x > p0.x) ? 'right' : 'left'; var length = Math.abs(p1.x - p0.x); return { p0: p0, p1: p1, - dir: dir, + direction: direction, length: length }; } diff --git a/webroot/rsrc/js/application/pholio/behavior-pholio-mock-view.js b/webroot/rsrc/js/application/pholio/behavior-pholio-mock-view.js index b3c2cd6aa4..aaa322f86e 100644 --- a/webroot/rsrc/js/application/pholio/behavior-pholio-mock-view.js +++ b/webroot/rsrc/js/application/pholio/behavior-pholio-mock-view.js @@ -598,6 +598,16 @@ JX.behavior('pholio-mock-view', function(config) { }) .register(); + JX.DOM.listen(panel, 'gesture.swipe.end', null, function(e) { + var data = e.getData(); + + if (data.length <= (JX.Vector.getDim(panel) / 2)) { + // If the user didn't move their finger far enough, don't switch. + return; + } + + switch_image(data.direction == 'right' ? -1 : 1); + }); /* -( Render )------------------------------------------------------------- */