From 7e5169ae116d476588db70307f18d61cbe5eccba Mon Sep 17 00:00:00 2001 From: Chad Little Date: Sun, 27 Jan 2013 07:59:05 -0800 Subject: [PATCH 01/17] Mobile CSS fixies. Summary: Fixing some of my own issues, but also consolidated menu styles and enlarged the search box. Test Plan: iOS and Chrome, checked core menu and app menu (config). Reviewers: epriestley, btrahan Reviewed By: epriestley CC: aran, Korvin Maniphest Tasks: T2426 Differential Revision: https://secure.phabricator.com/D4681 --- src/__celerity_resource_map__.php | 84 +++++++++---------- .../rsrc/css/aphront/phabricator-nav-view.css | 6 -- .../css/application/base/main-menu-view.css | 41 ++++----- 3 files changed, 63 insertions(+), 68 deletions(-) diff --git a/src/__celerity_resource_map__.php b/src/__celerity_resource_map__.php index 6edcdb0feb..82b1b7f65e 100644 --- a/src/__celerity_resource_map__.php +++ b/src/__celerity_resource_map__.php @@ -2713,7 +2713,7 @@ celerity_register_resource_map(array( ), 'phabricator-main-menu-view' => array( - 'uri' => '/res/38ec42d4/rsrc/css/application/base/main-menu-view.css', + 'uri' => '/res/b2087794/rsrc/css/application/base/main-menu-view.css', 'type' => 'css', 'requires' => array( @@ -2733,7 +2733,7 @@ celerity_register_resource_map(array( ), 'phabricator-nav-view-css' => array( - 'uri' => '/res/df20ec17/rsrc/css/aphront/phabricator-nav-view.css', + 'uri' => '/res/f3c78a53/rsrc/css/aphront/phabricator-nav-view.css', 'type' => 'css', 'requires' => array( @@ -3346,7 +3346,7 @@ celerity_register_resource_map(array( ), array( 'packages' => array( - '023adc14' => + 'd5fb4b74' => array( 'name' => 'core.pkg.css', 'symbols' => @@ -3390,7 +3390,7 @@ celerity_register_resource_map(array( 36 => 'phabricator-object-item-list-view-css', 37 => 'global-drag-and-drop-css', ), - 'uri' => '/res/pkg/023adc14/core.pkg.css', + 'uri' => '/res/pkg/d5fb4b74/core.pkg.css', 'type' => 'css', ), '66dca903' => @@ -3580,19 +3580,19 @@ celerity_register_resource_map(array( 'reverse' => array( 'aphront-attached-file-view-css' => 'e30a3fa8', - 'aphront-crumbs-view-css' => '023adc14', - 'aphront-dialog-view-css' => '023adc14', - 'aphront-error-view-css' => '023adc14', - 'aphront-form-view-css' => '023adc14', + 'aphront-crumbs-view-css' => 'd5fb4b74', + 'aphront-dialog-view-css' => 'd5fb4b74', + 'aphront-error-view-css' => 'd5fb4b74', + 'aphront-form-view-css' => 'd5fb4b74', 'aphront-headsup-action-list-view-css' => 'ec01d039', - 'aphront-headsup-view-css' => '023adc14', - 'aphront-list-filter-view-css' => '023adc14', - 'aphront-pager-view-css' => '023adc14', - 'aphront-panel-view-css' => '023adc14', - 'aphront-table-view-css' => '023adc14', - 'aphront-tokenizer-control-css' => '023adc14', - 'aphront-tooltip-css' => '023adc14', - 'aphront-typeahead-control-css' => '023adc14', + 'aphront-headsup-view-css' => 'd5fb4b74', + 'aphront-list-filter-view-css' => 'd5fb4b74', + 'aphront-pager-view-css' => 'd5fb4b74', + 'aphront-panel-view-css' => 'd5fb4b74', + 'aphront-table-view-css' => 'd5fb4b74', + 'aphront-tokenizer-control-css' => 'd5fb4b74', + 'aphront-tooltip-css' => 'd5fb4b74', + 'aphront-typeahead-control-css' => 'd5fb4b74', 'differential-changeset-view-css' => 'ec01d039', 'differential-core-view-css' => 'ec01d039', 'differential-inline-comment-editor' => '310cd201', @@ -3606,7 +3606,7 @@ celerity_register_resource_map(array( 'differential-table-of-contents-css' => 'ec01d039', 'diffusion-commit-view-css' => 'c8ce2d88', 'diffusion-icons-css' => 'c8ce2d88', - 'global-drag-and-drop-css' => '023adc14', + 'global-drag-and-drop-css' => 'd5fb4b74', 'inline-comment-summary-css' => 'ec01d039', 'javelin-aphlict' => '66dca903', 'javelin-behavior' => 'fbeded59', @@ -3676,48 +3676,48 @@ celerity_register_resource_map(array( 'javelin-util' => 'fbeded59', 'javelin-vector' => 'fbeded59', 'javelin-workflow' => 'fbeded59', - 'lightbox-attachment-css' => '023adc14', + 'lightbox-attachment-css' => 'd5fb4b74', 'maniphest-task-summary-css' => 'e30a3fa8', 'maniphest-transaction-detail-css' => 'e30a3fa8', 'phabricator-busy' => '66dca903', 'phabricator-content-source-view-css' => 'ec01d039', - 'phabricator-core-buttons-css' => '023adc14', - 'phabricator-core-css' => '023adc14', - 'phabricator-crumbs-view-css' => '023adc14', - 'phabricator-directory-css' => '023adc14', + 'phabricator-core-buttons-css' => 'd5fb4b74', + 'phabricator-core-css' => 'd5fb4b74', + 'phabricator-crumbs-view-css' => 'd5fb4b74', + 'phabricator-directory-css' => 'd5fb4b74', 'phabricator-drag-and-drop-file-upload' => '310cd201', 'phabricator-dropdown-menu' => '66dca903', 'phabricator-file-upload' => '66dca903', - 'phabricator-filetree-view-css' => '023adc14', - 'phabricator-flag-css' => '023adc14', - 'phabricator-form-view-css' => '023adc14', - 'phabricator-header-view-css' => '023adc14', - 'phabricator-jump-nav' => '023adc14', + 'phabricator-filetree-view-css' => 'd5fb4b74', + 'phabricator-flag-css' => 'd5fb4b74', + 'phabricator-form-view-css' => 'd5fb4b74', + 'phabricator-header-view-css' => 'd5fb4b74', + 'phabricator-jump-nav' => 'd5fb4b74', 'phabricator-keyboard-shortcut' => '66dca903', 'phabricator-keyboard-shortcut-manager' => '66dca903', - 'phabricator-main-menu-view' => '023adc14', + 'phabricator-main-menu-view' => 'd5fb4b74', 'phabricator-menu-item' => '66dca903', - 'phabricator-nav-view-css' => '023adc14', + 'phabricator-nav-view-css' => 'd5fb4b74', 'phabricator-notification' => '66dca903', - 'phabricator-notification-css' => '023adc14', - 'phabricator-notification-menu-css' => '023adc14', - 'phabricator-object-item-list-view-css' => '023adc14', + 'phabricator-notification-css' => 'd5fb4b74', + 'phabricator-notification-menu-css' => 'd5fb4b74', + 'phabricator-object-item-list-view-css' => 'd5fb4b74', 'phabricator-object-selector-css' => 'ec01d039', 'phabricator-paste-file-upload' => '66dca903', 'phabricator-prefab' => '66dca903', 'phabricator-project-tag-css' => 'e30a3fa8', - 'phabricator-remarkup-css' => '023adc14', + 'phabricator-remarkup-css' => 'd5fb4b74', 'phabricator-shaped-request' => '310cd201', - 'phabricator-side-menu-view-css' => '023adc14', - 'phabricator-standard-page-view' => '023adc14', + 'phabricator-side-menu-view-css' => 'd5fb4b74', + 'phabricator-standard-page-view' => 'd5fb4b74', 'phabricator-textareautils' => '66dca903', 'phabricator-tooltip' => '66dca903', - 'phabricator-transaction-view-css' => '023adc14', - 'phabricator-zindex-css' => '023adc14', - 'sprite-apps-large-css' => '023adc14', - 'sprite-gradient-css' => '023adc14', - 'sprite-icon-css' => '023adc14', - 'sprite-menu-css' => '023adc14', - 'syntax-highlighting-css' => '023adc14', + 'phabricator-transaction-view-css' => 'd5fb4b74', + 'phabricator-zindex-css' => 'd5fb4b74', + 'sprite-apps-large-css' => 'd5fb4b74', + 'sprite-gradient-css' => 'd5fb4b74', + 'sprite-icon-css' => 'd5fb4b74', + 'sprite-menu-css' => 'd5fb4b74', + 'syntax-highlighting-css' => 'd5fb4b74', ), )); diff --git a/webroot/rsrc/css/aphront/phabricator-nav-view.css b/webroot/rsrc/css/aphront/phabricator-nav-view.css index a9338387fb..5c1da125a9 100644 --- a/webroot/rsrc/css/aphront/phabricator-nav-view.css +++ b/webroot/rsrc/css/aphront/phabricator-nav-view.css @@ -83,9 +83,3 @@ .device-desktop .phabricator-side-menu-home .phabricator-nav-content { margin-left: 240px; } - -/* Chrome annoyingly has a url display over the nav - if the nav is the tallest page (home) */ -.phabricator-menu-view { - margin-bottom: 40px; -} diff --git a/webroot/rsrc/css/application/base/main-menu-view.css b/webroot/rsrc/css/application/base/main-menu-view.css index 6ce50a0004..acaf614709 100644 --- a/webroot/rsrc/css/application/base/main-menu-view.css +++ b/webroot/rsrc/css/application/base/main-menu-view.css @@ -152,6 +152,7 @@ } .device .phabricator-main-menu-search-container { + padding: 0; margin: 0 18px 0 60px; } @@ -172,6 +173,12 @@ padding: 6px 32px 6px 10px; } +.device .phabricator-main-menu-search input { + height: 16px; + font-size: 15px; + border-radius: 15px; +} + .phabricator-main-menu-search input:focus { background: #c9c9c9; } @@ -196,6 +203,11 @@ right: 6px; } +.device .phabricator-main-menu-search button { + top: 3px; +} + + .phabricator-main-menu-search-target div.jx-typeahead-results { border-radius: 4px; box-shadow: 1px 1px 4px rgba(0, 0, 0, 0.35); @@ -299,23 +311,16 @@ a:hover .phabricator-main-search-typeahead-result .result-type { .device .phabricator-dark-menu, .device .phabricator-dark-menu a.phabricator-menu-item-type-link { color: #fff; -} -.device .phabricator-dark-menu .phabricator-menu-item-view { - display: block; - padding: 4px 0; } .device .phabricator-dark-menu .phabricator-menu-item-type-label { text-transform: uppercase; - font-size: 11px; + font-size: 12px; background-color: #151719; padding: 0 0 0 12px; - height: 24px; -} - -.device .phabricator-dark-menu .phabricator-menu-item-type-spacer { - display: none; + height: 25px; + font-weight: bold; } .device .phabricator-dark-menu .phabricator-menu-item-type-label @@ -329,6 +334,8 @@ a:hover .phabricator-main-search-typeahead-result .result-type { border-style: solid; border-color: #34373b transparent #282c2d; background-image: url(/rsrc/image/texture/dark-menu.png); + padding: 4px 0; + display: block; } @@ -355,18 +362,18 @@ a:hover .phabricator-main-search-typeahead-result .result-type { .device .phabricator-core-menu-expanded .phabricator-core-menu { display: block; - padding-top: 44px; + padding-top: 4px; } -.device .phabricator-core-menu .phabricator-menu-item-type-link { +.device .phabricator-dark-menu .phabricator-menu-item-type-link { font-size: 15px; min-height: 30px; + line-height: 28px; } .device .phabricator-core-menu .phabricator-menu-item-type-link .phabricator-menu-item-name { margin-left: 40px; - line-height: 28px; } .device-desktop .phabricator-core-menu { @@ -417,7 +424,7 @@ a:hover .phabricator-main-search-typeahead-result .result-type { .device .phabricator-application-menu-expanded .phabricator-application-menu { display: block; - padding-top: 44px; + padding-top: 4px; } .phabricator-application-menu { @@ -428,9 +435,3 @@ a:hover .phabricator-main-search-typeahead-result .result-type { .phabricator-menu-item-name { padding-left: 12px; } - -.device .phabricator-application-menu-expanded .phabricator-application-menu { - display: block; - padding-top: 44px; -} - From 116537eb19ef5ff12146654c4bb3dfae58ae1af4 Mon Sep 17 00:00:00 2001 From: Chad Little Date: Sun, 27 Jan 2013 08:00:20 -0800 Subject: [PATCH 02/17] CSS tweaks to mobile maniphest. Summary: Some minor cleanup, remove preview, widen transactions, remove timestamps (i could go either way). I mainly want to interact more on mobile but am finding its pretty crowded. I still need to think more about these views. Test Plan: Review on iOS and Chrome Reviewers: epriestley, btrahan Reviewed By: epriestley CC: aran, Korvin Differential Revision: https://secure.phabricator.com/D4680 --- src/__celerity_resource_map__.php | 84 ++++++++++++------------ webroot/rsrc/css/aphront/panel-view.css | 4 ++ webroot/rsrc/css/aphront/transaction.css | 16 ++++- 3 files changed, 59 insertions(+), 45 deletions(-) diff --git a/src/__celerity_resource_map__.php b/src/__celerity_resource_map__.php index 82b1b7f65e..3a778c1f1a 100644 --- a/src/__celerity_resource_map__.php +++ b/src/__celerity_resource_map__.php @@ -670,7 +670,7 @@ celerity_register_resource_map(array( ), 'aphront-panel-view-css' => array( - 'uri' => '/res/789ff5e5/rsrc/css/aphront/panel-view.css', + 'uri' => '/res/3d1420b3/rsrc/css/aphront/panel-view.css', 'type' => 'css', 'requires' => array( @@ -2987,7 +2987,7 @@ celerity_register_resource_map(array( ), 'phabricator-transaction-view-css' => array( - 'uri' => '/res/d3599152/rsrc/css/aphront/transaction.css', + 'uri' => '/res/4c5c16dc/rsrc/css/aphront/transaction.css', 'type' => 'css', 'requires' => array( @@ -3346,7 +3346,7 @@ celerity_register_resource_map(array( ), array( 'packages' => array( - 'd5fb4b74' => + '5f46c4fd' => array( 'name' => 'core.pkg.css', 'symbols' => @@ -3390,7 +3390,7 @@ celerity_register_resource_map(array( 36 => 'phabricator-object-item-list-view-css', 37 => 'global-drag-and-drop-css', ), - 'uri' => '/res/pkg/d5fb4b74/core.pkg.css', + 'uri' => '/res/pkg/5f46c4fd/core.pkg.css', 'type' => 'css', ), '66dca903' => @@ -3580,19 +3580,19 @@ celerity_register_resource_map(array( 'reverse' => array( 'aphront-attached-file-view-css' => 'e30a3fa8', - 'aphront-crumbs-view-css' => 'd5fb4b74', - 'aphront-dialog-view-css' => 'd5fb4b74', - 'aphront-error-view-css' => 'd5fb4b74', - 'aphront-form-view-css' => 'd5fb4b74', + 'aphront-crumbs-view-css' => '5f46c4fd', + 'aphront-dialog-view-css' => '5f46c4fd', + 'aphront-error-view-css' => '5f46c4fd', + 'aphront-form-view-css' => '5f46c4fd', 'aphront-headsup-action-list-view-css' => 'ec01d039', - 'aphront-headsup-view-css' => 'd5fb4b74', - 'aphront-list-filter-view-css' => 'd5fb4b74', - 'aphront-pager-view-css' => 'd5fb4b74', - 'aphront-panel-view-css' => 'd5fb4b74', - 'aphront-table-view-css' => 'd5fb4b74', - 'aphront-tokenizer-control-css' => 'd5fb4b74', - 'aphront-tooltip-css' => 'd5fb4b74', - 'aphront-typeahead-control-css' => 'd5fb4b74', + 'aphront-headsup-view-css' => '5f46c4fd', + 'aphront-list-filter-view-css' => '5f46c4fd', + 'aphront-pager-view-css' => '5f46c4fd', + 'aphront-panel-view-css' => '5f46c4fd', + 'aphront-table-view-css' => '5f46c4fd', + 'aphront-tokenizer-control-css' => '5f46c4fd', + 'aphront-tooltip-css' => '5f46c4fd', + 'aphront-typeahead-control-css' => '5f46c4fd', 'differential-changeset-view-css' => 'ec01d039', 'differential-core-view-css' => 'ec01d039', 'differential-inline-comment-editor' => '310cd201', @@ -3606,7 +3606,7 @@ celerity_register_resource_map(array( 'differential-table-of-contents-css' => 'ec01d039', 'diffusion-commit-view-css' => 'c8ce2d88', 'diffusion-icons-css' => 'c8ce2d88', - 'global-drag-and-drop-css' => 'd5fb4b74', + 'global-drag-and-drop-css' => '5f46c4fd', 'inline-comment-summary-css' => 'ec01d039', 'javelin-aphlict' => '66dca903', 'javelin-behavior' => 'fbeded59', @@ -3676,48 +3676,48 @@ celerity_register_resource_map(array( 'javelin-util' => 'fbeded59', 'javelin-vector' => 'fbeded59', 'javelin-workflow' => 'fbeded59', - 'lightbox-attachment-css' => 'd5fb4b74', + 'lightbox-attachment-css' => '5f46c4fd', 'maniphest-task-summary-css' => 'e30a3fa8', 'maniphest-transaction-detail-css' => 'e30a3fa8', 'phabricator-busy' => '66dca903', 'phabricator-content-source-view-css' => 'ec01d039', - 'phabricator-core-buttons-css' => 'd5fb4b74', - 'phabricator-core-css' => 'd5fb4b74', - 'phabricator-crumbs-view-css' => 'd5fb4b74', - 'phabricator-directory-css' => 'd5fb4b74', + 'phabricator-core-buttons-css' => '5f46c4fd', + 'phabricator-core-css' => '5f46c4fd', + 'phabricator-crumbs-view-css' => '5f46c4fd', + 'phabricator-directory-css' => '5f46c4fd', 'phabricator-drag-and-drop-file-upload' => '310cd201', 'phabricator-dropdown-menu' => '66dca903', 'phabricator-file-upload' => '66dca903', - 'phabricator-filetree-view-css' => 'd5fb4b74', - 'phabricator-flag-css' => 'd5fb4b74', - 'phabricator-form-view-css' => 'd5fb4b74', - 'phabricator-header-view-css' => 'd5fb4b74', - 'phabricator-jump-nav' => 'd5fb4b74', + 'phabricator-filetree-view-css' => '5f46c4fd', + 'phabricator-flag-css' => '5f46c4fd', + 'phabricator-form-view-css' => '5f46c4fd', + 'phabricator-header-view-css' => '5f46c4fd', + 'phabricator-jump-nav' => '5f46c4fd', 'phabricator-keyboard-shortcut' => '66dca903', 'phabricator-keyboard-shortcut-manager' => '66dca903', - 'phabricator-main-menu-view' => 'd5fb4b74', + 'phabricator-main-menu-view' => '5f46c4fd', 'phabricator-menu-item' => '66dca903', - 'phabricator-nav-view-css' => 'd5fb4b74', + 'phabricator-nav-view-css' => '5f46c4fd', 'phabricator-notification' => '66dca903', - 'phabricator-notification-css' => 'd5fb4b74', - 'phabricator-notification-menu-css' => 'd5fb4b74', - 'phabricator-object-item-list-view-css' => 'd5fb4b74', + 'phabricator-notification-css' => '5f46c4fd', + 'phabricator-notification-menu-css' => '5f46c4fd', + 'phabricator-object-item-list-view-css' => '5f46c4fd', 'phabricator-object-selector-css' => 'ec01d039', 'phabricator-paste-file-upload' => '66dca903', 'phabricator-prefab' => '66dca903', 'phabricator-project-tag-css' => 'e30a3fa8', - 'phabricator-remarkup-css' => 'd5fb4b74', + 'phabricator-remarkup-css' => '5f46c4fd', 'phabricator-shaped-request' => '310cd201', - 'phabricator-side-menu-view-css' => 'd5fb4b74', - 'phabricator-standard-page-view' => 'd5fb4b74', + 'phabricator-side-menu-view-css' => '5f46c4fd', + 'phabricator-standard-page-view' => '5f46c4fd', 'phabricator-textareautils' => '66dca903', 'phabricator-tooltip' => '66dca903', - 'phabricator-transaction-view-css' => 'd5fb4b74', - 'phabricator-zindex-css' => 'd5fb4b74', - 'sprite-apps-large-css' => 'd5fb4b74', - 'sprite-gradient-css' => 'd5fb4b74', - 'sprite-icon-css' => 'd5fb4b74', - 'sprite-menu-css' => 'd5fb4b74', - 'syntax-highlighting-css' => 'd5fb4b74', + 'phabricator-transaction-view-css' => '5f46c4fd', + 'phabricator-zindex-css' => '5f46c4fd', + 'sprite-apps-large-css' => '5f46c4fd', + 'sprite-gradient-css' => '5f46c4fd', + 'sprite-icon-css' => '5f46c4fd', + 'sprite-menu-css' => '5f46c4fd', + 'syntax-highlighting-css' => '5f46c4fd', ), )); diff --git a/webroot/rsrc/css/aphront/panel-view.css b/webroot/rsrc/css/aphront/panel-view.css index ce5d3944a3..fd6a3aaa91 100644 --- a/webroot/rsrc/css/aphront/panel-view.css +++ b/webroot/rsrc/css/aphront/panel-view.css @@ -86,6 +86,10 @@ padding: 15px 20px; } +.device-phone .aphront-panel-preview { + display: none; +} + .aphront-panel-preview-wide { width: 1080px; margin-left: auto; diff --git a/webroot/rsrc/css/aphront/transaction.css b/webroot/rsrc/css/aphront/transaction.css index 6eb4052f77..2c8c3618ab 100644 --- a/webroot/rsrc/css/aphront/transaction.css +++ b/webroot/rsrc/css/aphront/transaction.css @@ -9,6 +9,10 @@ padding: 2px 0px; } +.device-phone .phabricator-transaction-view { + margin: 10px 0; +} + .phabricator-transaction-detail { border-color: #dddddd; border-width: 1px 10px; @@ -18,6 +22,8 @@ .device-phone .phabricator-transaction-detail { margin: 0; + min-height: 50px; + background: #fff; } .phabricator-transaction-header { @@ -30,9 +36,13 @@ } .phabricator-transaction-info { - color: #666666; - float: right; - font-size: 11px; + color: #777; + float: right; + font-size: 11px; +} + +.device-phone .phabricator-transaction-info { + display: none; } .phabricator-transaction-content { From 5dc48c2b4ad932b600677f939fd137d829a74722 Mon Sep 17 00:00:00 2001 From: Chad Little Date: Mon, 28 Jan 2013 10:48:01 -0800 Subject: [PATCH 03/17] pht, panels and mobile for metamta Summary: Added phts, tested forms on mobile. Test Plan: Review each page in Chrome and iOS. Reviewers: epriestley, btrahan Reviewed By: epriestley CC: aran, Korvin Differential Revision: https://secure.phabricator.com/D4702 --- ...rentialBlameRevisionFieldSpecification.php | 7 +-- .../PhabricatorApplicationMetaMTA.php | 2 +- .../PhabricatorMetaMTAController.php | 12 ++--- .../PhabricatorMetaMTAListController.php | 20 +++---- .../PhabricatorMetaMTAReceiveController.php | 22 ++++---- ...abricatorMetaMTAReceivedListController.php | 18 ++++--- .../PhabricatorMetaMTASendController.php | 52 ++++++++++--------- ...icatorMetaMTASendGridReceiveController.php | 2 +- .../PhabricatorMetaMTAViewController.php | 20 +++---- 9 files changed, 83 insertions(+), 72 deletions(-) diff --git a/src/applications/differential/field/specification/DifferentialBlameRevisionFieldSpecification.php b/src/applications/differential/field/specification/DifferentialBlameRevisionFieldSpecification.php index 27573da141..a246aa1a31 100644 --- a/src/applications/differential/field/specification/DifferentialBlameRevisionFieldSpecification.php +++ b/src/applications/differential/field/specification/DifferentialBlameRevisionFieldSpecification.php @@ -29,8 +29,9 @@ final class DifferentialBlameRevisionFieldSpecification public function renderEditControl() { return id(new AphrontFormTextControl()) - ->setLabel('Blame Revision') - ->setCaption('Revision which broke the stuff which this change fixes.') + ->setLabel(pht('Blame Revision')) + ->setCaption( + pht('Revision which broke the stuff which this change fixes.')) ->setName($this->getStorageKey()) ->setValue($this->value); } @@ -40,7 +41,7 @@ final class DifferentialBlameRevisionFieldSpecification } public function renderLabelForRevisionView() { - return 'Blame Revision:'; + return pht('Blame Revision:'); } public function renderValueForRevisionView() { diff --git a/src/applications/metamta/application/PhabricatorApplicationMetaMTA.php b/src/applications/metamta/application/PhabricatorApplicationMetaMTA.php index 9c8acf9863..6aed7502c8 100644 --- a/src/applications/metamta/application/PhabricatorApplicationMetaMTA.php +++ b/src/applications/metamta/application/PhabricatorApplicationMetaMTA.php @@ -7,7 +7,7 @@ final class PhabricatorApplicationMetaMTA extends PhabricatorApplication { } public function getShortDescription() { - return 'View Mail Logs'; + return pht('View Mail Logs'); } public function getIconName() { diff --git a/src/applications/metamta/controller/PhabricatorMetaMTAController.php b/src/applications/metamta/controller/PhabricatorMetaMTAController.php index 1978cdaa1a..48acdf86ce 100644 --- a/src/applications/metamta/controller/PhabricatorMetaMTAController.php +++ b/src/applications/metamta/controller/PhabricatorMetaMTAController.php @@ -10,14 +10,14 @@ abstract class PhabricatorMetaMTAController extends PhabricatorController { $nav = new AphrontSideNavFilterView(); $nav->setBaseURI(new PhutilURI($this->getApplicationURI())); - $nav->addLabel('Mail Logs'); - $nav->addFilter('sent', 'Sent Mail', $this->getApplicationURI()); - $nav->addFilter('received', 'Received Mail'); + $nav->addLabel(pht('Mail Logs')); + $nav->addFilter('sent', pht('Sent Mail'), $this->getApplicationURI()); + $nav->addFilter('received', pht('Received Mail')); if ($this->getRequest()->getUser()->getIsAdmin()) { - $nav->addLabel('Diagnostics'); - $nav->addFilter('send', 'Send Test'); - $nav->addFilter('receive', 'Receive Test'); + $nav->addLabel(pht('Diagnostics')); + $nav->addFilter('send', pht('Send Test')); + $nav->addFilter('receive', pht('Receive Test')); } return $nav; diff --git a/src/applications/metamta/controller/PhabricatorMetaMTAListController.php b/src/applications/metamta/controller/PhabricatorMetaMTAListController.php index bcd6897ea0..4f840f03c1 100644 --- a/src/applications/metamta/controller/PhabricatorMetaMTAListController.php +++ b/src/applications/metamta/controller/PhabricatorMetaMTAListController.php @@ -74,19 +74,19 @@ final class PhabricatorMetaMTAListController 'class' => 'button small grey', 'href' => $this->getApplicationURI('/view/'.$mail->getID().'/'), ), - 'View'), + pht('View')), ); } $table = new AphrontTableView($rows); $table->setHeaders( array( - 'Status', - 'Retry', - 'Next', - 'Created', - 'Updated', - 'Subject', + pht('Status'), + pht('Retry'), + pht('Next'), + pht('Created'), + pht('Updated'), + pht('Subject'), '', )); $table->setColumnClasses( @@ -103,8 +103,9 @@ final class PhabricatorMetaMTAListController // Render the whole page. $panel = new AphrontPanelView(); $panel->appendChild($table); - $panel->setHeader('MetaMTA Messages'); + $panel->setHeader(pht('MetaMTA Messages')); $panel->appendChild($pager); + $panel->setNoBackground(); $nav = $this->buildSideNavView(); $nav->selectFilter('sent'); @@ -113,7 +114,8 @@ final class PhabricatorMetaMTAListController return $this->buildApplicationPage( $nav, array( - 'title' => 'Sent Mail', + 'title' => pht('Sent Mail'), + 'device' => true, )); } } diff --git a/src/applications/metamta/controller/PhabricatorMetaMTAReceiveController.php b/src/applications/metamta/controller/PhabricatorMetaMTAReceiveController.php index 2ae211e2ad..2d4591408c 100644 --- a/src/applications/metamta/controller/PhabricatorMetaMTAReceiveController.php +++ b/src/applications/metamta/controller/PhabricatorMetaMTAReceiveController.php @@ -12,7 +12,7 @@ final class PhabricatorMetaMTAReceiveController $receiver = PhabricatorMetaMTAReceivedMail::loadReceiverObject( $request->getStr('obj')); if (!$receiver) { - throw new Exception("No such task or revision!"); + throw new Exception(pht("No such task or revision!")); } $hash = PhabricatorMetaMTAReceivedMail::computeMailHash( @@ -50,25 +50,26 @@ final class PhabricatorMetaMTAReceiveController $form->setAction($this->getApplicationURI('/receive/')); $form ->appendChild( - '

This form will simulate '. - 'sending mail to an object.

') + '

'. + pht('This form will simulate sending mail to an object.'). + '

') ->appendChild( id(new AphrontFormTextControl()) - ->setLabel('To') + ->setLabel(pht('To')) ->setName('obj') - ->setCaption('e.g. D1234 or T1234')) + ->setCaption(pht('e.g. D1234 or T1234'))) ->appendChild( id(new AphrontFormTextAreaControl()) - ->setLabel('Body') + ->setLabel(pht('Body')) ->setName('body')) ->appendChild( id(new AphrontFormSubmitControl()) - ->setValue('Receive Mail')); + ->setValue(pht('Receive Mail'))); $panel = new AphrontPanelView(); - $panel->setHeader('Receive Email'); + $panel->setHeader(pht('Receive Email')); $panel->appendChild($form); - $panel->setWidth(AphrontPanelView::WIDTH_FORM); + $panel->setNoBackground(); $nav = $this->buildSideNavView(); $nav->selectFilter('receive'); @@ -77,7 +78,8 @@ final class PhabricatorMetaMTAReceiveController return $this->buildApplicationPage( $nav, array( - 'title' => 'Receive Test', + 'title' => pht('Receive Test'), + 'device' => true, )); } diff --git a/src/applications/metamta/controller/PhabricatorMetaMTAReceivedListController.php b/src/applications/metamta/controller/PhabricatorMetaMTAReceivedListController.php index 926bfb0be4..d55f4b7174 100644 --- a/src/applications/metamta/controller/PhabricatorMetaMTAReceivedListController.php +++ b/src/applications/metamta/controller/PhabricatorMetaMTAReceivedListController.php @@ -45,12 +45,12 @@ final class PhabricatorMetaMTAReceivedListController $table = new AphrontTableView($rows); $table->setHeaders( array( - 'ID', - 'Date', - 'Time', - 'Author', - 'Object', - 'Message', + pht('ID'), + pht('Date'), + pht('Time'), + pht('Author'), + pht('Object'), + pht('Message'), )); $table->setColumnClasses( array( @@ -63,9 +63,10 @@ final class PhabricatorMetaMTAReceivedListController )); $panel = new AphrontPanelView(); - $panel->setHeader('Received Mail'); + $panel->setHeader(pht('Received Mail')); $panel->appendChild($table); $panel->appendChild($pager); + $panel->setNoBackground(); $nav = $this->buildSideNavView(); $nav->selectFilter('received'); @@ -74,7 +75,8 @@ final class PhabricatorMetaMTAReceivedListController return $this->buildApplicationPage( $nav, array( - 'title' => 'Received Mail', + 'title' => pht('Received Mail'), + 'device' => true, )); } } diff --git a/src/applications/metamta/controller/PhabricatorMetaMTASendController.php b/src/applications/metamta/controller/PhabricatorMetaMTASendController.php index ae3b1afc68..d79685df3b 100644 --- a/src/applications/metamta/controller/PhabricatorMetaMTASendController.php +++ b/src/applications/metamta/controller/PhabricatorMetaMTASendController.php @@ -42,8 +42,8 @@ final class PhabricatorMetaMTASendController } $failure_caption = - "Enter a number to simulate that many consecutive send failures before ". - "really attempting to deliver via the underlying MTA."; + pht("Enter a number to simulate that many consecutive send failures ". + "brefore really attempting to deliver via the underlying MTA."); $doclink_href = PhabricatorEnv::getDoclink( 'article/Configuring_Outbound_Email.html'); @@ -54,11 +54,12 @@ final class PhabricatorMetaMTASendController 'href' => $doclink_href, 'target' => '_blank', ), - 'Configuring Outbound Email'); + pht('Configuring Outbound Email')); $instructions = - '

This form will send a normal '. - 'email using the settings you have configured for Phabricator. For more '. - 'information, see '.$doclink.'.

'; + '

'. + pht('This form will send a normal email using the settings you have '. + 'configured for Phabricator. For more information, see %s.', $doclink). + '

'; $adapter = PhabricatorEnv::getEnvConfig('metamta.mail-adapter'); $warning = null; @@ -67,11 +68,11 @@ final class PhabricatorMetaMTASendController $warning->setTitle('Email is Disabled'); $warning->setSeverity(AphrontErrorView::SEVERITY_WARNING); $warning->appendChild( - '

This installation of Phabricator is currently set to use '. + '

'.pht('This installation of Phabricator is currently set to use '. 'PhabricatorMailImplementationTestAdapter to deliver '. 'outbound email. This completely disables outbound email! All '. 'outbound email will be thrown in a deep, dark hole until you '. - 'configure a real adapter.

'); + 'configure a real adapter.').'

'); } $phdlink_href = PhabricatorEnv::getDoclink( @@ -91,49 +92,49 @@ final class PhabricatorMetaMTASendController ->appendChild($instructions) ->appendChild( id(new AphrontFormStaticControl()) - ->setLabel('Adapter') + ->setLabel(pht('Adapter')) ->setValue($adapter)) ->appendChild( id(new AphrontFormTokenizerControl()) - ->setLabel('To') + ->setLabel(pht('To')) ->setName('to') ->setDatasource('/typeahead/common/mailable/')) ->appendChild( id(new AphrontFormTokenizerControl()) - ->setLabel('CC') + ->setLabel(pht('CC')) ->setName('cc') ->setDatasource('/typeahead/common/mailable/')) ->appendChild( id(new AphrontFormTextControl()) - ->setLabel('Subject') + ->setLabel(pht('Subject')) ->setName('subject')) ->appendChild( id(new AphrontFormTextAreaControl()) - ->setLabel('Body') + ->setLabel(pht('Body')) ->setName('body')) ->appendChild( id(new AphrontFormTextControl()) - ->setLabel('Mail Tags') + ->setLabel(pht('Mail Tags')) ->setName('mailtags') ->setCaption( - 'Example: differential-cc, differential-comment')) + pht('Example:').' differential-cc, differential-comment')) ->appendChild( id(new AphrontFormDragAndDropUploadControl()) - ->setLabel('Attach Files') + ->setLabel(pht('Attach Files')) ->setName('files') ->setActivatedClass('aphront-panel-view-drag-and-drop')) ->appendChild( id(new AphrontFormTextControl()) - ->setLabel('Simulate Failures') + ->setLabel(pht('Simulate Failures')) ->setName('failures') ->setCaption($failure_caption)) ->appendChild( id(new AphrontFormCheckboxControl()) - ->setLabel('HTML') + ->setLabel(pht('HTML')) ->addCheckbox('html', '1', 'Send as HTML email.')) ->appendChild( id(new AphrontFormCheckboxControl()) - ->setLabel('Bulk') + ->setLabel(pht('Bulk')) ->addCheckbox('bulk', '1', 'Send with bulk email headers.')) ->appendChild( id(new AphrontFormCheckboxControl()) @@ -141,18 +142,18 @@ final class PhabricatorMetaMTASendController ->addCheckbox( 'immediately', '1', - 'Send immediately. (Do not enqueue for daemons.)', + pht('Send immediately. (Do not enqueue for daemons.)'), PhabricatorEnv::getEnvConfig('metamta.send-immediately')) - ->setCaption('Daemons can be started with '.$phdlink.'.') + ->setCaption(pht('Daemons can be started with %s.', $phdlink)) ) ->appendChild( id(new AphrontFormSubmitControl()) - ->setValue('Send Mail')); + ->setValue(pht('Send Mail'))); $panel = new AphrontPanelView(); - $panel->setHeader('Send Email'); + $panel->setHeader(pht('Send Email')); $panel->appendChild($form); - $panel->setWidth(AphrontPanelView::WIDTH_FORM); + $panel->setNoBackground(); $nav = $this->buildSideNavView(); $nav->selectFilter('send'); @@ -165,7 +166,8 @@ final class PhabricatorMetaMTASendController return $this->buildApplicationPage( $nav, array( - 'title' => 'Send Test', + 'title' => pht('Send Test'), + 'device' => true, )); } diff --git a/src/applications/metamta/controller/PhabricatorMetaMTASendGridReceiveController.php b/src/applications/metamta/controller/PhabricatorMetaMTASendGridReceiveController.php index fbd86a2871..ae75b348c2 100644 --- a/src/applications/metamta/controller/PhabricatorMetaMTASendGridReceiveController.php +++ b/src/applications/metamta/controller/PhabricatorMetaMTASendGridReceiveController.php @@ -61,7 +61,7 @@ final class PhabricatorMetaMTASendGridReceiveController $received->processReceivedMail(); $response = new AphrontWebpageResponse(); - $response->setContent("Got it! Thanks, SendGrid!\n"); + $response->setContent(pht("Got it! Thanks, SendGrid!\n")); return $response; } diff --git a/src/applications/metamta/controller/PhabricatorMetaMTAViewController.php b/src/applications/metamta/controller/PhabricatorMetaMTAViewController.php index dd15b099e1..537678c381 100644 --- a/src/applications/metamta/controller/PhabricatorMetaMTAViewController.php +++ b/src/applications/metamta/controller/PhabricatorMetaMTAViewController.php @@ -26,41 +26,43 @@ final class PhabricatorMetaMTAViewController $form ->appendChild( id(new AphrontFormStaticControl()) - ->setLabel('Subject') + ->setLabel(pht('Subject')) ->setValue($mail->getSubject())) ->appendChild( id(new AphrontFormStaticControl()) - ->setLabel('Created') + ->setLabel(pht('Created')) ->setValue(phabricator_datetime($mail->getDateCreated(), $user))) ->appendChild( id(new AphrontFormStaticControl()) - ->setLabel('Status') + ->setLabel(pht('Status')) ->setValue($status)) ->appendChild( id(new AphrontFormStaticControl()) - ->setLabel('Retry Count') + ->setLabel(pht('Retry Count')) ->setValue($mail->getRetryCount())) ->appendChild( id(new AphrontFormStaticControl()) - ->setLabel('Message') + ->setLabel(pht('Message')) ->setValue($mail->getMessage())) ->appendChild( id(new AphrontFormStaticControl()) - ->setLabel('Related PHID') + ->setLabel(pht('Related PHID')) ->setValue($mail->getRelatedPHID())) ->appendChild( id(new AphrontFormSubmitControl()) - ->addCancelButton($this->getApplicationURI(), 'Done')); + ->addCancelButton($this->getApplicationURI(), pht('Done'))); $panel = new AphrontPanelView(); - $panel->setHeader('View Email'); + $panel->setHeader(pht('View Email')); $panel->appendChild($form); $panel->setWidth(AphrontPanelView::WIDTH_WIDE); + $panel->setNoBackground(); return $this->buildApplicationPage( $panel, array( - 'title' => 'View Mail', + 'title' => pht('View Mail'), + 'device' => true, )); } From 8ac1afc81aa89750e931a6aa9422d82206516ba9 Mon Sep 17 00:00:00 2001 From: Lauri-Henrik Jalonen Date: Mon, 28 Jan 2013 11:18:50 -0800 Subject: [PATCH 04/17] Show all photos in a Pholio mock and allow switching between them Summary: Mock page now shows all images. Switching between images is done by clicking thumbnails. Test Plan: Verified that all images are shown. Verified that by clicking thumbnail the image clicked will show. Reviewers: epriestley Reviewed By: epriestley CC: aran, Korvin, AnhNhan Maniphest Tasks: T2427 Differential Revision: https://secure.phabricator.com/D4698 --- src/__celerity_resource_map__.php | 13 ++++- .../controller/PholioMockViewController.php | 5 +- .../pholio/view/PholioMockImagesView.php | 55 ++++++++++++++++--- .../rsrc/css/application/pholio/pholio.css | 16 +++++- .../pholio/behavior-pholio-mock-view.js | 17 ++++++ 5 files changed, 90 insertions(+), 16 deletions(-) create mode 100644 webroot/rsrc/js/application/pholio/behavior-pholio-mock-view.js diff --git a/src/__celerity_resource_map__.php b/src/__celerity_resource_map__.php index 3a778c1f1a..a613d82359 100644 --- a/src/__celerity_resource_map__.php +++ b/src/__celerity_resource_map__.php @@ -1834,6 +1834,17 @@ celerity_register_resource_map(array( ), 'disk' => '/rsrc/js/application/phame/phame-post-preview.js', ), + 'javelin-behavior-pholio-mock-view' => + array( + 'uri' => '/res/10fbdca1/rsrc/js/application/pholio/behavior-pholio-mock-view.js', + 'type' => 'js', + 'requires' => + array( + 0 => 'javelin-behavior', + 1 => 'javelin-stratcom', + ), + 'disk' => '/rsrc/js/application/pholio/behavior-pholio-mock-view.js', + ), 'javelin-behavior-phriction-document-preview' => array( 'uri' => '/res/f1665ecd/rsrc/js/application/phriction/phriction-document-preview.js', @@ -3165,7 +3176,7 @@ celerity_register_resource_map(array( ), 'pholio-css' => array( - 'uri' => '/res/e454c33f/rsrc/css/application/pholio/pholio.css', + 'uri' => '/res/8d8d99c1/rsrc/css/application/pholio/pholio.css', 'type' => 'css', 'requires' => array( diff --git a/src/applications/pholio/controller/PholioMockViewController.php b/src/applications/pholio/controller/PholioMockViewController.php index 0bf0022fe1..0742bd0a8b 100644 --- a/src/applications/pholio/controller/PholioMockViewController.php +++ b/src/applications/pholio/controller/PholioMockViewController.php @@ -67,8 +67,6 @@ final class PholioMockViewController extends PholioController { $output = new PholioMockImagesView(); $output->setMock($mock); - $carousel = $output->render(); - $xaction_view = id(new PhabricatorApplicationTransactionView()) ->setUser($this->getRequest()->getUser()) ->setTransactions($xactions) @@ -80,11 +78,12 @@ final class PholioMockViewController extends PholioController { $header, $actions, $properties, - $carousel, + $output->render(), $xaction_view, $add_comment, ); + return $this->buildApplicationPage( $content, array( diff --git a/src/applications/pholio/view/PholioMockImagesView.php b/src/applications/pholio/view/PholioMockImagesView.php index 103b751a6b..d073347616 100644 --- a/src/applications/pholio/view/PholioMockImagesView.php +++ b/src/applications/pholio/view/PholioMockImagesView.php @@ -13,22 +13,59 @@ final class PholioMockImagesView extends AphrontView { throw new Exception("Call setMock() before render()!"); } + $mockview = ""; + $file = head($this->mock->getImages())->getFile(); - $image_tag = phutil_render_tag( - 'img', - array( - 'src' => $file->getBestURI(), - 'class' => 'pholio-mock-image', - ), - ''); + $main_image_id = celerity_generate_unique_node_id(); - return phutil_render_tag( + $main_image_tag = phutil_render_tag( + 'img', + array( + 'src' => $file->getBestURI(), + 'class' => 'pholio-mock-image', + 'id' => $main_image_id, + )); + + $mockview .= phutil_render_tag( 'div', array( 'class' => 'pholio-mock-image-container', ), - $image_tag); + $main_image_tag); + + if (count($this->mock->getImages()) > 1) { + require_celerity_resource('javelin-behavior-pholio-mock-view'); + $config = array('mainID' => $main_image_id); + Javelin::initBehavior('pholio-mock-view', $config); + + $thumbnails = array(); + foreach ($this->mock->getImages() as $image) { + $thumbfile = $image->getFile(); + + $tag = javelin_render_tag( + 'img', + array( + 'src' => $thumbfile->getThumb160x120URI(), + 'sigil' => 'mock-thumbnail', + 'class' => 'pholio-mock-carousel-thumbnail', + 'meta' => array( + 'fullSizeURI' => $thumbfile->getBestURI(), + 'imageID' => $image->getID(), + ), + )); + $thumbnails[] = $tag; + } + + $mockview .= phutil_render_tag( + 'div', + array( + 'class' => 'pholio-mock-carousel', + ), + implode($thumbnails)); + } + + return $mockview; } } diff --git a/webroot/rsrc/css/application/pholio/pholio.css b/webroot/rsrc/css/application/pholio/pholio.css index 38e81f19ed..686603a082 100644 --- a/webroot/rsrc/css/application/pholio/pholio.css +++ b/webroot/rsrc/css/application/pholio/pholio.css @@ -6,7 +6,17 @@ text-align: center; } -.pholio-mock-image { - margin: 10px 0px; - display: inline-block; +.pholio-mock-carousel { + background-color: #282828; + text-align: center; +} + +.pholio-mock-carousel-thumbnail { + margin-right: 5px; + display: inline-block; +} + +.pholio-mock-image { + margin: 10px 0px; + display: inline-block; } diff --git a/webroot/rsrc/js/application/pholio/behavior-pholio-mock-view.js b/webroot/rsrc/js/application/pholio/behavior-pholio-mock-view.js new file mode 100644 index 0000000000..c9953e33d6 --- /dev/null +++ b/webroot/rsrc/js/application/pholio/behavior-pholio-mock-view.js @@ -0,0 +1,17 @@ +/** + * @provides javelin-behavior-pholio-mock-view + * @requires javelin-behavior + * javelin-stratcom + */ +JX.behavior('pholio-mock-view', function(config) { + JX.Stratcom.listen( + 'click', // Listen for clicks... + 'mock-thumbnail', // ...on nodes with sigil "mock-thumbnail". + function(e) { + var data = e.getNodeData('mock-thumbnail'); + + var main = JX.$(config.mainID); + main.src = data.fullSizeURI; + }); +}); + From a9fb828635b298c13acafeb70d2fa91ccd7cdeee Mon Sep 17 00:00:00 2001 From: vrana Date: Mon, 28 Jan 2013 13:32:56 -0800 Subject: [PATCH 05/17] Display proper number in too large diff Summary: Also avoid trailing space in translation. Test Plan: Displayed diff with 7000 files. Reviewers: chad, epriestley Reviewed By: epriestley CC: aran, Korvin Differential Revision: https://secure.phabricator.com/D4705 --- .../controller/DifferentialRevisionViewController.php | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/applications/differential/controller/DifferentialRevisionViewController.php b/src/applications/differential/controller/DifferentialRevisionViewController.php index 9cbead02b4..1dffc8ff1b 100644 --- a/src/applications/differential/controller/DifferentialRevisionViewController.php +++ b/src/applications/differential/controller/DifferentialRevisionViewController.php @@ -176,14 +176,17 @@ final class DifferentialRevisionViewController extends DifferentialController { $limit = 100; $large = $request->getStr('large'); if (count($changesets) > $limit && !$large) { - $count = number_format(count($changesets)); + $count = count($changesets); $warning = new AphrontErrorView(); $warning->setTitle('Very Large Diff'); $warning->setSeverity(AphrontErrorView::SEVERITY_WARNING); $warning->appendChild( - '

'.pht('This diff is very large and affects %d files. Load '. - 'each file individually. ', $count). - "". + pht( + 'This diff is very large and affects %2$s files. Load each file '. + 'individually.', + $count, + PhutilTranslator::getInstance()->formatNumber($count)). + " ". phutil_render_tag( 'a', array( From bb745731171f55eb7dbc5ff322f9d84dc2596d4d Mon Sep 17 00:00:00 2001 From: vrana Date: Thu, 24 Jan 2013 17:37:20 -0800 Subject: [PATCH 06/17] Limit meme text height to half of the image Test Plan: Looked at meme with short text. Reviewers: DeedyDas Reviewed By: DeedyDas CC: aran, epriestley Differential Revision: https://secure.phabricator.com/D4632 --- src/applications/files/PhabricatorImageTransformer.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/applications/files/PhabricatorImageTransformer.php b/src/applications/files/PhabricatorImageTransformer.php index 4f0f86edee..173b92b6c9 100644 --- a/src/applications/files/PhabricatorImageTransformer.php +++ b/src/applications/files/PhabricatorImageTransformer.php @@ -228,7 +228,7 @@ final class PhabricatorImageTransformer { $text_height = abs($bbox[3] - $bbox[5]); $text_width = abs($bbox[0] - $bbox[2]); return array( - "doesfit" => ($text_height * 1.05 <= imagesy($img) + "doesfit" => ($text_height * 1.05 <= imagesy($img) / 2 && $text_width * 1.05 <= imagesx($img)), "txtwidth" => $text_width, "txtheight" => $text_height, From bc5617954a641620ccb6d3e654dd5e9bd09e1da4 Mon Sep 17 00:00:00 2001 From: epriestley Date: Mon, 28 Jan 2013 14:11:32 -0800 Subject: [PATCH 07/17] Make control + enter submit forms if a textarea is focused Summary: This is straightforward, except that `form.submit()` does not call onsubmit handlers. Create a `didSyntheticSubmit` event and have everything which listens for form submits listen for it too. Fixes T704. Test Plan: Hit control + enter in inline comments, main commetns, Pholio, conpherence. Verified it triggered appropriate JS (workflow / special behaviors). Reviewers: btrahan Reviewed By: btrahan CC: aran Maniphest Tasks: T704 Differential Revision: https://secure.phabricator.com/D4704 --- src/__celerity_resource_map__.php | 120 +++++++++--------- .../rsrc/js/application/core/behavior-form.js | 44 +++++-- .../js/application/core/behavior-workflow.js | 6 +- .../DifferentialInlineCommentEditor.js | 6 +- .../transactions/behavior-transaction-list.js | 29 +++-- 5 files changed, 121 insertions(+), 84 deletions(-) diff --git a/src/__celerity_resource_map__.php b/src/__celerity_resource_map__.php index a613d82359..2dd4e743a2 100644 --- a/src/__celerity_resource_map__.php +++ b/src/__celerity_resource_map__.php @@ -797,7 +797,7 @@ celerity_register_resource_map(array( ), 'differential-inline-comment-editor' => array( - 'uri' => '/res/1bc649b7/rsrc/js/application/differential/DifferentialInlineCommentEditor.js', + 'uri' => '/res/e0ad34ac/rsrc/js/application/differential/DifferentialInlineCommentEditor.js', 'type' => 'js', 'requires' => array( @@ -1057,7 +1057,7 @@ celerity_register_resource_map(array( ), 'javelin-behavior-aphront-form-disable-on-submit' => array( - 'uri' => '/res/ca54e8b9/rsrc/js/application/core/behavior-form.js', + 'uri' => '/res/f5cb51f1/rsrc/js/application/core/behavior-form.js', 'type' => 'js', 'requires' => array( @@ -1796,7 +1796,7 @@ celerity_register_resource_map(array( ), 'javelin-behavior-phabricator-transaction-list' => array( - 'uri' => '/res/307a71af/rsrc/js/application/transactions/behavior-transaction-list.js', + 'uri' => '/res/f1fbb474/rsrc/js/application/transactions/behavior-transaction-list.js', 'type' => 'js', 'requires' => array( @@ -1963,7 +1963,7 @@ celerity_register_resource_map(array( ), 'javelin-behavior-workflow' => array( - 'uri' => '/res/2b0e2754/rsrc/js/application/core/behavior-workflow.js', + 'uri' => '/res/2c99beaf/rsrc/js/application/core/behavior-workflow.js', 'type' => 'js', 'requires' => array( @@ -3404,7 +3404,7 @@ celerity_register_resource_map(array( 'uri' => '/res/pkg/5f46c4fd/core.pkg.css', 'type' => 'css', ), - '66dca903' => + '4bf2be0a' => array( 'name' => 'core.pkg.js', 'symbols' => @@ -3443,7 +3443,7 @@ celerity_register_resource_map(array( 31 => 'javelin-behavior-global-drag-and-drop', 32 => 'javelin-behavior-phabricator-home-reveal-tiles', ), - 'uri' => '/res/pkg/66dca903/core.pkg.js', + 'uri' => '/res/pkg/4bf2be0a/core.pkg.js', 'type' => 'js', ), '8edbada5' => @@ -3481,7 +3481,7 @@ celerity_register_resource_map(array( 'uri' => '/res/pkg/ec01d039/differential.pkg.css', 'type' => 'css', ), - '310cd201' => + '9dae5f20' => array( 'name' => 'differential.pkg.js', 'symbols' => @@ -3506,7 +3506,7 @@ celerity_register_resource_map(array( 17 => 'javelin-behavior-differential-toggle-files', 18 => 'javelin-behavior-differential-user-select', ), - 'uri' => '/res/pkg/310cd201/differential.pkg.js', + 'uri' => '/res/pkg/9dae5f20/differential.pkg.js', 'type' => 'js', ), 'c8ce2d88' => @@ -3606,7 +3606,7 @@ celerity_register_resource_map(array( 'aphront-typeahead-control-css' => '5f46c4fd', 'differential-changeset-view-css' => 'ec01d039', 'differential-core-view-css' => 'ec01d039', - 'differential-inline-comment-editor' => '310cd201', + 'differential-inline-comment-editor' => '9dae5f20', 'differential-local-commits-view-css' => 'ec01d039', 'differential-results-table-css' => 'ec01d039', 'differential-revision-add-comment-css' => 'ec01d039', @@ -3619,56 +3619,56 @@ celerity_register_resource_map(array( 'diffusion-icons-css' => 'c8ce2d88', 'global-drag-and-drop-css' => '5f46c4fd', 'inline-comment-summary-css' => 'ec01d039', - 'javelin-aphlict' => '66dca903', + 'javelin-aphlict' => '4bf2be0a', 'javelin-behavior' => 'fbeded59', - 'javelin-behavior-aphlict-dropdown' => '66dca903', - 'javelin-behavior-aphlict-listen' => '66dca903', - 'javelin-behavior-aphront-basic-tokenizer' => '66dca903', - 'javelin-behavior-aphront-drag-and-drop' => '310cd201', - 'javelin-behavior-aphront-drag-and-drop-textarea' => '310cd201', - 'javelin-behavior-aphront-form-disable-on-submit' => '66dca903', + 'javelin-behavior-aphlict-dropdown' => '4bf2be0a', + 'javelin-behavior-aphlict-listen' => '4bf2be0a', + 'javelin-behavior-aphront-basic-tokenizer' => '4bf2be0a', + 'javelin-behavior-aphront-drag-and-drop' => '9dae5f20', + 'javelin-behavior-aphront-drag-and-drop-textarea' => '9dae5f20', + 'javelin-behavior-aphront-form-disable-on-submit' => '4bf2be0a', 'javelin-behavior-audit-preview' => 'f96657b8', 'javelin-behavior-dark-console' => '8edbada5', 'javelin-behavior-dark-console-ajax' => '8edbada5', - 'javelin-behavior-device' => '66dca903', - 'javelin-behavior-differential-accept-with-errors' => '310cd201', - 'javelin-behavior-differential-add-reviewers-and-ccs' => '310cd201', - 'javelin-behavior-differential-comment-jump' => '310cd201', - 'javelin-behavior-differential-diff-radios' => '310cd201', - 'javelin-behavior-differential-dropdown-menus' => '310cd201', - 'javelin-behavior-differential-edit-inline-comments' => '310cd201', - 'javelin-behavior-differential-feedback-preview' => '310cd201', - 'javelin-behavior-differential-keyboard-navigation' => '310cd201', - 'javelin-behavior-differential-populate' => '310cd201', - 'javelin-behavior-differential-show-more' => '310cd201', - 'javelin-behavior-differential-toggle-files' => '310cd201', - 'javelin-behavior-differential-user-select' => '310cd201', + 'javelin-behavior-device' => '4bf2be0a', + 'javelin-behavior-differential-accept-with-errors' => '9dae5f20', + 'javelin-behavior-differential-add-reviewers-and-ccs' => '9dae5f20', + 'javelin-behavior-differential-comment-jump' => '9dae5f20', + 'javelin-behavior-differential-diff-radios' => '9dae5f20', + 'javelin-behavior-differential-dropdown-menus' => '9dae5f20', + 'javelin-behavior-differential-edit-inline-comments' => '9dae5f20', + 'javelin-behavior-differential-feedback-preview' => '9dae5f20', + 'javelin-behavior-differential-keyboard-navigation' => '9dae5f20', + 'javelin-behavior-differential-populate' => '9dae5f20', + 'javelin-behavior-differential-show-more' => '9dae5f20', + 'javelin-behavior-differential-toggle-files' => '9dae5f20', + 'javelin-behavior-differential-user-select' => '9dae5f20', 'javelin-behavior-diffusion-commit-graph' => 'f96657b8', 'javelin-behavior-diffusion-pull-lastmodified' => 'f96657b8', 'javelin-behavior-error-log' => '8edbada5', - 'javelin-behavior-global-drag-and-drop' => '66dca903', - 'javelin-behavior-konami' => '66dca903', - 'javelin-behavior-lightbox-attachments' => '66dca903', + 'javelin-behavior-global-drag-and-drop' => '4bf2be0a', + 'javelin-behavior-konami' => '4bf2be0a', + 'javelin-behavior-lightbox-attachments' => '4bf2be0a', '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' => '66dca903', - 'javelin-behavior-phabricator-autofocus' => '66dca903', - 'javelin-behavior-phabricator-home-reveal-tiles' => '66dca903', - 'javelin-behavior-phabricator-keyboard-shortcuts' => '66dca903', - 'javelin-behavior-phabricator-nav' => '66dca903', - 'javelin-behavior-phabricator-object-selector' => '310cd201', - 'javelin-behavior-phabricator-oncopy' => '66dca903', - 'javelin-behavior-phabricator-remarkup-assist' => '66dca903', - 'javelin-behavior-phabricator-search-typeahead' => '66dca903', - 'javelin-behavior-phabricator-tooltips' => '66dca903', - 'javelin-behavior-phabricator-watch-anchor' => '66dca903', - 'javelin-behavior-refresh-csrf' => '66dca903', - 'javelin-behavior-repository-crossreference' => '310cd201', - 'javelin-behavior-toggle-class' => '66dca903', - 'javelin-behavior-workflow' => '66dca903', + 'javelin-behavior-phabricator-active-nav' => '4bf2be0a', + 'javelin-behavior-phabricator-autofocus' => '4bf2be0a', + 'javelin-behavior-phabricator-home-reveal-tiles' => '4bf2be0a', + 'javelin-behavior-phabricator-keyboard-shortcuts' => '4bf2be0a', + 'javelin-behavior-phabricator-nav' => '4bf2be0a', + 'javelin-behavior-phabricator-object-selector' => '9dae5f20', + 'javelin-behavior-phabricator-oncopy' => '4bf2be0a', + 'javelin-behavior-phabricator-remarkup-assist' => '4bf2be0a', + 'javelin-behavior-phabricator-search-typeahead' => '4bf2be0a', + 'javelin-behavior-phabricator-tooltips' => '4bf2be0a', + 'javelin-behavior-phabricator-watch-anchor' => '4bf2be0a', + 'javelin-behavior-refresh-csrf' => '4bf2be0a', + 'javelin-behavior-repository-crossreference' => '9dae5f20', + 'javelin-behavior-toggle-class' => '4bf2be0a', + 'javelin-behavior-workflow' => '4bf2be0a', 'javelin-dom' => 'fbeded59', 'javelin-event' => 'fbeded59', 'javelin-install' => 'fbeded59', @@ -3690,39 +3690,39 @@ celerity_register_resource_map(array( 'lightbox-attachment-css' => '5f46c4fd', 'maniphest-task-summary-css' => 'e30a3fa8', 'maniphest-transaction-detail-css' => 'e30a3fa8', - 'phabricator-busy' => '66dca903', + 'phabricator-busy' => '4bf2be0a', 'phabricator-content-source-view-css' => 'ec01d039', 'phabricator-core-buttons-css' => '5f46c4fd', 'phabricator-core-css' => '5f46c4fd', 'phabricator-crumbs-view-css' => '5f46c4fd', 'phabricator-directory-css' => '5f46c4fd', - 'phabricator-drag-and-drop-file-upload' => '310cd201', - 'phabricator-dropdown-menu' => '66dca903', - 'phabricator-file-upload' => '66dca903', + 'phabricator-drag-and-drop-file-upload' => '9dae5f20', + 'phabricator-dropdown-menu' => '4bf2be0a', + 'phabricator-file-upload' => '4bf2be0a', 'phabricator-filetree-view-css' => '5f46c4fd', 'phabricator-flag-css' => '5f46c4fd', 'phabricator-form-view-css' => '5f46c4fd', 'phabricator-header-view-css' => '5f46c4fd', 'phabricator-jump-nav' => '5f46c4fd', - 'phabricator-keyboard-shortcut' => '66dca903', - 'phabricator-keyboard-shortcut-manager' => '66dca903', + 'phabricator-keyboard-shortcut' => '4bf2be0a', + 'phabricator-keyboard-shortcut-manager' => '4bf2be0a', 'phabricator-main-menu-view' => '5f46c4fd', - 'phabricator-menu-item' => '66dca903', + 'phabricator-menu-item' => '4bf2be0a', 'phabricator-nav-view-css' => '5f46c4fd', - 'phabricator-notification' => '66dca903', + 'phabricator-notification' => '4bf2be0a', 'phabricator-notification-css' => '5f46c4fd', 'phabricator-notification-menu-css' => '5f46c4fd', 'phabricator-object-item-list-view-css' => '5f46c4fd', 'phabricator-object-selector-css' => 'ec01d039', - 'phabricator-paste-file-upload' => '66dca903', - 'phabricator-prefab' => '66dca903', + 'phabricator-paste-file-upload' => '4bf2be0a', + 'phabricator-prefab' => '4bf2be0a', 'phabricator-project-tag-css' => 'e30a3fa8', 'phabricator-remarkup-css' => '5f46c4fd', - 'phabricator-shaped-request' => '310cd201', + 'phabricator-shaped-request' => '9dae5f20', 'phabricator-side-menu-view-css' => '5f46c4fd', 'phabricator-standard-page-view' => '5f46c4fd', - 'phabricator-textareautils' => '66dca903', - 'phabricator-tooltip' => '66dca903', + 'phabricator-textareautils' => '4bf2be0a', + 'phabricator-tooltip' => '4bf2be0a', 'phabricator-transaction-view-css' => '5f46c4fd', 'phabricator-zindex-css' => '5f46c4fd', 'sprite-apps-large-css' => '5f46c4fd', diff --git a/webroot/rsrc/js/application/core/behavior-form.js b/webroot/rsrc/js/application/core/behavior-form.js index 25ebb59e74..5147e8d7ba 100644 --- a/webroot/rsrc/js/application/core/behavior-form.js +++ b/webroot/rsrc/js/application/core/behavior-form.js @@ -14,6 +14,39 @@ JX.behavior('aphront-form-disable-on-submit', function(config) { new_tab = (raw.altKey || raw.ctrlKey || raw.metaKey || raw.shiftKey); }); + + JX.Stratcom.listen('keypress', ['tag:form', 'tag:textarea'], function(e) { + var raw = e.getRawEvent(); + if (e.getSpecialKey() != 'return' || !raw.ctrlKey) { + return; + } + + e.kill(); + + var form = e.getNode('tag:form'); + + // This allows 'workflow' and similar actions to take effect. + var r = JX.DOM.invoke(form, 'didSyntheticSubmit'); + if (r.getPrevented()) { + return; + } + + // If nothing handled the synthetic submit, submit normally. + form.submit(); + }); + + function will_submit(root) { + root._disabled = true; + var buttons = JX.DOM.scry(root, 'button'); + for (var ii = 0; ii < buttons.length; ii++) { + if (!buttons[ii].disabled) { + buttons[ii].disabled = 'disabled'; + JX.DOM.alterClass(buttons[ii], 'disabled', true); + restore.push(buttons[ii]); + } + } + } + JX.Stratcom.listen('submit', 'tag:form', function(e) { if (e.getNode('workflow')) { // Don't activate for forms with workflow, the workflow behavior will @@ -34,15 +67,8 @@ JX.behavior('aphront-form-disable-on-submit', function(config) { if (root._disabled) { e.kill(); } - root._disabled = true; - var buttons = JX.DOM.scry(root, 'button'); - for (var ii = 0; ii < buttons.length; ii++) { - if (!buttons[ii].disabled) { - buttons[ii].disabled = 'disabled'; - JX.DOM.alterClass(buttons[ii], 'disabled', true); - restore.push(buttons[ii]); - } - } + + will_submit(root); }); JX.Stratcom.listen('unload', null, function(e) { diff --git a/webroot/rsrc/js/application/core/behavior-workflow.js b/webroot/rsrc/js/application/core/behavior-workflow.js index 82c0cfb0b8..c55c8e9317 100644 --- a/webroot/rsrc/js/application/core/behavior-workflow.js +++ b/webroot/rsrc/js/application/core/behavior-workflow.js @@ -7,8 +7,10 @@ */ JX.behavior('workflow', function() { + + // Listen for both real JX.Stratcom.listen( - 'submit', + ['submit', 'didSyntheticSubmit'], ['workflow', 'tag:form'], function(e) { if (JX.Stratcom.pass()) { @@ -18,6 +20,7 @@ JX.behavior('workflow', function() { e.prevent(); JX.Workflow.newFromForm(target).start(); }); + JX.Stratcom.listen( 'click', ['workflow', 'tag:a'], @@ -40,4 +43,5 @@ JX.behavior('workflow', function() { e.prevent(); JX.Workflow.newFromLink(target).start(); }); + }); diff --git a/webroot/rsrc/js/application/differential/DifferentialInlineCommentEditor.js b/webroot/rsrc/js/application/differential/DifferentialInlineCommentEditor.js index 6e544fe787..08339e1585 100644 --- a/webroot/rsrc/js/application/differential/DifferentialInlineCommentEditor.js +++ b/webroot/rsrc/js/application/differential/DifferentialInlineCommentEditor.js @@ -119,7 +119,11 @@ JX.install('DifferentialInlineCommentEditor', { JX.DOM.alterClass(drawn[0], 'differential-inline-loading', true); }); - JX.DOM.listen(drawn[0], 'submit', 'inline-edit-form', onsubmit); + JX.DOM.listen( + drawn[0], + ['submit', 'didSyntheticSubmit'], + 'inline-edit-form', + onsubmit); }, _didCompleteWorkflow : function(response) { var op = this.getOperation(); diff --git a/webroot/rsrc/js/application/transactions/behavior-transaction-list.js b/webroot/rsrc/js/application/transactions/behavior-transaction-list.js index 0658ac2ebf..64195ad18e 100644 --- a/webroot/rsrc/js/application/transactions/behavior-transaction-list.js +++ b/webroot/rsrc/js/application/transactions/behavior-transaction-list.js @@ -75,21 +75,24 @@ JX.behavior('phabricator-transaction-list', function(config) { e.kill(); }); - JX.Stratcom.listen('submit', 'transaction-append', function(e) { - var form = e.getTarget(); + JX.Stratcom.listen( + ['submit', 'didSyntheticSubmit'], + 'transaction-append', + function(e) { + var form = e.getTarget(); - JX.Workflow.newFromForm(form, {anchor: next_anchor}) - .setHandler(function(response) { - ontransactions(response); + JX.Workflow.newFromForm(form, {anchor: next_anchor}) + .setHandler(function(response) { + ontransactions(response); - var e = JX.DOM.invoke(form, 'willClear'); - if (!e.getPrevented()) { - form.reset(); - } - }) - .start(); + var e = JX.DOM.invoke(form, 'willClear'); + if (!e.getPrevented()) { + form.reset(); + } + }) + .start(); - e.kill(); - }); + e.kill(); + }); }); From add39effb9203f25257422e8fa0ee8ab0d70f3a6 Mon Sep 17 00:00:00 2001 From: Chad Little Date: Mon, 28 Jan 2013 15:43:15 -0800 Subject: [PATCH 08/17] Fix hover color on logo. Summary: Fix the hover color behind the logo. Test Plan: Test iOS, Chrome, and Firefox. Hover over logo, get background. Open Home menu on mobile, see proper spacing. Check app menu in Config. Reviewers: epriestley Reviewed By: epriestley CC: aran, Korvin Maniphest Tasks: T2440 Differential Revision: https://secure.phabricator.com/D4714 --- src/__celerity_resource_map__.php | 82 +++++++++---------- .../css/application/base/main-menu-view.css | 7 +- 2 files changed, 46 insertions(+), 43 deletions(-) diff --git a/src/__celerity_resource_map__.php b/src/__celerity_resource_map__.php index 2dd4e743a2..dbf8c28a02 100644 --- a/src/__celerity_resource_map__.php +++ b/src/__celerity_resource_map__.php @@ -2724,7 +2724,7 @@ celerity_register_resource_map(array( ), 'phabricator-main-menu-view' => array( - 'uri' => '/res/b2087794/rsrc/css/application/base/main-menu-view.css', + 'uri' => '/res/597e394b/rsrc/css/application/base/main-menu-view.css', 'type' => 'css', 'requires' => array( @@ -3357,7 +3357,7 @@ celerity_register_resource_map(array( ), array( 'packages' => array( - '5f46c4fd' => + 'd24a3d26' => array( 'name' => 'core.pkg.css', 'symbols' => @@ -3401,7 +3401,7 @@ celerity_register_resource_map(array( 36 => 'phabricator-object-item-list-view-css', 37 => 'global-drag-and-drop-css', ), - 'uri' => '/res/pkg/5f46c4fd/core.pkg.css', + 'uri' => '/res/pkg/d24a3d26/core.pkg.css', 'type' => 'css', ), '4bf2be0a' => @@ -3591,19 +3591,19 @@ celerity_register_resource_map(array( 'reverse' => array( 'aphront-attached-file-view-css' => 'e30a3fa8', - 'aphront-crumbs-view-css' => '5f46c4fd', - 'aphront-dialog-view-css' => '5f46c4fd', - 'aphront-error-view-css' => '5f46c4fd', - 'aphront-form-view-css' => '5f46c4fd', + 'aphront-crumbs-view-css' => 'd24a3d26', + 'aphront-dialog-view-css' => 'd24a3d26', + 'aphront-error-view-css' => 'd24a3d26', + 'aphront-form-view-css' => 'd24a3d26', 'aphront-headsup-action-list-view-css' => 'ec01d039', - 'aphront-headsup-view-css' => '5f46c4fd', - 'aphront-list-filter-view-css' => '5f46c4fd', - 'aphront-pager-view-css' => '5f46c4fd', - 'aphront-panel-view-css' => '5f46c4fd', - 'aphront-table-view-css' => '5f46c4fd', - 'aphront-tokenizer-control-css' => '5f46c4fd', - 'aphront-tooltip-css' => '5f46c4fd', - 'aphront-typeahead-control-css' => '5f46c4fd', + 'aphront-headsup-view-css' => 'd24a3d26', + 'aphront-list-filter-view-css' => 'd24a3d26', + 'aphront-pager-view-css' => 'd24a3d26', + 'aphront-panel-view-css' => 'd24a3d26', + 'aphront-table-view-css' => 'd24a3d26', + 'aphront-tokenizer-control-css' => 'd24a3d26', + 'aphront-tooltip-css' => 'd24a3d26', + 'aphront-typeahead-control-css' => 'd24a3d26', 'differential-changeset-view-css' => 'ec01d039', 'differential-core-view-css' => 'ec01d039', 'differential-inline-comment-editor' => '9dae5f20', @@ -3617,7 +3617,7 @@ celerity_register_resource_map(array( 'differential-table-of-contents-css' => 'ec01d039', 'diffusion-commit-view-css' => 'c8ce2d88', 'diffusion-icons-css' => 'c8ce2d88', - 'global-drag-and-drop-css' => '5f46c4fd', + 'global-drag-and-drop-css' => 'd24a3d26', 'inline-comment-summary-css' => 'ec01d039', 'javelin-aphlict' => '4bf2be0a', 'javelin-behavior' => 'fbeded59', @@ -3687,48 +3687,48 @@ celerity_register_resource_map(array( 'javelin-util' => 'fbeded59', 'javelin-vector' => 'fbeded59', 'javelin-workflow' => 'fbeded59', - 'lightbox-attachment-css' => '5f46c4fd', + 'lightbox-attachment-css' => 'd24a3d26', 'maniphest-task-summary-css' => 'e30a3fa8', 'maniphest-transaction-detail-css' => 'e30a3fa8', 'phabricator-busy' => '4bf2be0a', 'phabricator-content-source-view-css' => 'ec01d039', - 'phabricator-core-buttons-css' => '5f46c4fd', - 'phabricator-core-css' => '5f46c4fd', - 'phabricator-crumbs-view-css' => '5f46c4fd', - 'phabricator-directory-css' => '5f46c4fd', + 'phabricator-core-buttons-css' => 'd24a3d26', + 'phabricator-core-css' => 'd24a3d26', + 'phabricator-crumbs-view-css' => 'd24a3d26', + 'phabricator-directory-css' => 'd24a3d26', 'phabricator-drag-and-drop-file-upload' => '9dae5f20', 'phabricator-dropdown-menu' => '4bf2be0a', 'phabricator-file-upload' => '4bf2be0a', - 'phabricator-filetree-view-css' => '5f46c4fd', - 'phabricator-flag-css' => '5f46c4fd', - 'phabricator-form-view-css' => '5f46c4fd', - 'phabricator-header-view-css' => '5f46c4fd', - 'phabricator-jump-nav' => '5f46c4fd', + 'phabricator-filetree-view-css' => 'd24a3d26', + 'phabricator-flag-css' => 'd24a3d26', + 'phabricator-form-view-css' => 'd24a3d26', + 'phabricator-header-view-css' => 'd24a3d26', + 'phabricator-jump-nav' => 'd24a3d26', 'phabricator-keyboard-shortcut' => '4bf2be0a', 'phabricator-keyboard-shortcut-manager' => '4bf2be0a', - 'phabricator-main-menu-view' => '5f46c4fd', + 'phabricator-main-menu-view' => 'd24a3d26', 'phabricator-menu-item' => '4bf2be0a', - 'phabricator-nav-view-css' => '5f46c4fd', + 'phabricator-nav-view-css' => 'd24a3d26', 'phabricator-notification' => '4bf2be0a', - 'phabricator-notification-css' => '5f46c4fd', - 'phabricator-notification-menu-css' => '5f46c4fd', - 'phabricator-object-item-list-view-css' => '5f46c4fd', + 'phabricator-notification-css' => 'd24a3d26', + 'phabricator-notification-menu-css' => 'd24a3d26', + 'phabricator-object-item-list-view-css' => 'd24a3d26', 'phabricator-object-selector-css' => 'ec01d039', 'phabricator-paste-file-upload' => '4bf2be0a', 'phabricator-prefab' => '4bf2be0a', 'phabricator-project-tag-css' => 'e30a3fa8', - 'phabricator-remarkup-css' => '5f46c4fd', + 'phabricator-remarkup-css' => 'd24a3d26', 'phabricator-shaped-request' => '9dae5f20', - 'phabricator-side-menu-view-css' => '5f46c4fd', - 'phabricator-standard-page-view' => '5f46c4fd', + 'phabricator-side-menu-view-css' => 'd24a3d26', + 'phabricator-standard-page-view' => 'd24a3d26', 'phabricator-textareautils' => '4bf2be0a', 'phabricator-tooltip' => '4bf2be0a', - 'phabricator-transaction-view-css' => '5f46c4fd', - 'phabricator-zindex-css' => '5f46c4fd', - 'sprite-apps-large-css' => '5f46c4fd', - 'sprite-gradient-css' => '5f46c4fd', - 'sprite-icon-css' => '5f46c4fd', - 'sprite-menu-css' => '5f46c4fd', - 'syntax-highlighting-css' => '5f46c4fd', + 'phabricator-transaction-view-css' => 'd24a3d26', + 'phabricator-zindex-css' => 'd24a3d26', + 'sprite-apps-large-css' => 'd24a3d26', + 'sprite-gradient-css' => 'd24a3d26', + 'sprite-icon-css' => 'd24a3d26', + 'sprite-menu-css' => 'd24a3d26', + 'syntax-highlighting-css' => 'd24a3d26', ), )); diff --git a/webroot/rsrc/css/application/base/main-menu-view.css b/webroot/rsrc/css/application/base/main-menu-view.css index acaf614709..ad3f65c090 100644 --- a/webroot/rsrc/css/application/base/main-menu-view.css +++ b/webroot/rsrc/css/application/base/main-menu-view.css @@ -42,6 +42,8 @@ .phabricator-main-menu-logo { display: inline-block; width: 139px; + height: 44px; + float: left; margin-right: 6px; padding-right: 6px; padding-left: 6px; @@ -265,6 +267,7 @@ a:hover .phabricator-main-search-typeahead-result .result-type { .phabricator-main-menu-alerts { display: inline-block; border-radius: 15px; + float: left; background: rgba(0,0,0,.2); height: 20px; padding: 3px 10px; @@ -362,7 +365,7 @@ a:hover .phabricator-main-search-typeahead-result .result-type { .device .phabricator-core-menu-expanded .phabricator-core-menu { display: block; - padding-top: 4px; + padding-top: 44px; } .device .phabricator-dark-menu .phabricator-menu-item-type-link { @@ -424,7 +427,7 @@ a:hover .phabricator-main-search-typeahead-result .result-type { .device .phabricator-application-menu-expanded .phabricator-application-menu { display: block; - padding-top: 4px; + padding-top: 44px; } .phabricator-application-menu { From 93eac1f9d3448b3004cc7b8b4767f665eab579d7 Mon Sep 17 00:00:00 2001 From: Chad Little Date: Mon, 28 Jan 2013 15:56:29 -0800 Subject: [PATCH 09/17] Add Conpherence sprites. Summary: Let's see if I did this right. This adds on and off state icons (1 and 2x) for conpherence. I think I need to tweak and add more CSS to have the off hover state be the on icon. Will check. Test Plan: spritegen Reviewers: epriestley, btrahan Reviewed By: epriestley CC: aran, Korvin Maniphest Tasks: T2400 Differential Revision: https://secure.phabricator.com/D4709 --- resources/sprite/conpher_1x/calendar_off.png | Bin 0 -> 263 bytes resources/sprite/conpher_1x/calendar_on.png | Bin 0 -> 272 bytes resources/sprite/conpher_1x/files_off.png | Bin 0 -> 886 bytes resources/sprite/conpher_1x/files_on.png | Bin 0 -> 895 bytes resources/sprite/conpher_1x/list_off.png | Bin 0 -> 177 bytes resources/sprite/conpher_1x/list_on.png | Bin 0 -> 199 bytes resources/sprite/conpher_1x/more_off.png | Bin 0 -> 385 bytes resources/sprite/conpher_1x/more_on.png | Bin 0 -> 410 bytes resources/sprite/conpher_1x/people_off.png | Bin 0 -> 1005 bytes resources/sprite/conpher_1x/people_on.png | Bin 0 -> 965 bytes resources/sprite/conpher_1x/settings_off.png | Bin 0 -> 1025 bytes resources/sprite/conpher_1x/settings_on.png | Bin 0 -> 1126 bytes resources/sprite/conpher_2x/calendar_off.png | Bin 0 -> 418 bytes resources/sprite/conpher_2x/calendar_on.png | Bin 0 -> 421 bytes .../sprite/conpher_2x/conversation_off.png | Bin 0 -> 1771 bytes .../sprite/conpher_2x/conversation_on.png | Bin 0 -> 1592 bytes resources/sprite/conpher_2x/files_off.png | Bin 0 -> 1706 bytes resources/sprite/conpher_2x/files_on.png | Bin 0 -> 1596 bytes resources/sprite/conpher_2x/list_off.png | Bin 0 -> 306 bytes resources/sprite/conpher_2x/list_on.png | Bin 0 -> 295 bytes resources/sprite/conpher_2x/more_off.png | Bin 0 -> 776 bytes resources/sprite/conpher_2x/more_on.png | Bin 0 -> 923 bytes resources/sprite/conpher_2x/people_off.png | Bin 0 -> 1668 bytes resources/sprite/conpher_2x/people_on.png | Bin 0 -> 1548 bytes resources/sprite/conpher_2x/settings_off.png | Bin 0 -> 1885 bytes resources/sprite/conpher_2x/settings_on.png | Bin 0 -> 1489 bytes resources/sprite/manifest/conph.json | 71 ++++++++++++++++++ scripts/celerity/generate_sprites.php | 1 + .../celerity/CeleritySpriteGenerator.php | 36 +++++++++ webroot/rsrc/css/sprite-conph.css | 67 +++++++++++++++++ webroot/rsrc/image/sprite-conph-X2.png | Bin 0 -> 11685 bytes webroot/rsrc/image/sprite-conph.png | Bin 0 -> 5527 bytes 32 files changed, 175 insertions(+) create mode 100644 resources/sprite/conpher_1x/calendar_off.png create mode 100644 resources/sprite/conpher_1x/calendar_on.png create mode 100644 resources/sprite/conpher_1x/files_off.png create mode 100644 resources/sprite/conpher_1x/files_on.png create mode 100644 resources/sprite/conpher_1x/list_off.png create mode 100644 resources/sprite/conpher_1x/list_on.png create mode 100644 resources/sprite/conpher_1x/more_off.png create mode 100644 resources/sprite/conpher_1x/more_on.png create mode 100644 resources/sprite/conpher_1x/people_off.png create mode 100644 resources/sprite/conpher_1x/people_on.png create mode 100644 resources/sprite/conpher_1x/settings_off.png create mode 100644 resources/sprite/conpher_1x/settings_on.png create mode 100644 resources/sprite/conpher_2x/calendar_off.png create mode 100644 resources/sprite/conpher_2x/calendar_on.png create mode 100644 resources/sprite/conpher_2x/conversation_off.png create mode 100644 resources/sprite/conpher_2x/conversation_on.png create mode 100644 resources/sprite/conpher_2x/files_off.png create mode 100644 resources/sprite/conpher_2x/files_on.png create mode 100644 resources/sprite/conpher_2x/list_off.png create mode 100644 resources/sprite/conpher_2x/list_on.png create mode 100644 resources/sprite/conpher_2x/more_off.png create mode 100644 resources/sprite/conpher_2x/more_on.png create mode 100644 resources/sprite/conpher_2x/people_off.png create mode 100644 resources/sprite/conpher_2x/people_on.png create mode 100644 resources/sprite/conpher_2x/settings_off.png create mode 100644 resources/sprite/conpher_2x/settings_on.png create mode 100644 resources/sprite/manifest/conph.json create mode 100644 webroot/rsrc/css/sprite-conph.css create mode 100644 webroot/rsrc/image/sprite-conph-X2.png create mode 100644 webroot/rsrc/image/sprite-conph.png diff --git a/resources/sprite/conpher_1x/calendar_off.png b/resources/sprite/conpher_1x/calendar_off.png new file mode 100644 index 0000000000000000000000000000000000000000..d4bbae5dfe50a4a3d1a22fae19dab21b7ff44ed9 GIT binary patch literal 263 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE3?yBabR7dymH|E?uK)l4udHoYuw=#3m1`F+ zUAb!Artbbp>o#u(iqti>Y}&rNy}NJ5oCW=pr%j$dYs!q-bxo~nH*MRvZCBc7gE>G$ zm`j5Ef*Ibw7goI@0_0YCx;TbZ#69i1&DCPSK1V6A|ljX`7M zcmdj^6dDjpsly1KgZ^76*U#!gO7qN1XjnwmjDL3(<6o}QjS#eso=A|fI-Ha1VitU7^4 zF_#4S1v9*VFRXe+1jw!Rba4!+h++hb<>Ny!&4k(b_5NaZPH5S$Aed2mh>T!gb62D?tun N@O1TaS?83{1OOB@VY>hT literal 0 HcmV?d00001 diff --git a/resources/sprite/conpher_1x/files_off.png b/resources/sprite/conpher_1x/files_off.png new file mode 100644 index 0000000000000000000000000000000000000000..0eb7e3996dbc4f241df3fe7632597474d3056584 GIT binary patch literal 886 zcmV-+1Bv{JP)DFBy}rGZ^wo`C zdaQe=q+5}pRS{Hqcw2lBEW@3`mQv(;s5VTuA`MQBa{aj@qk`Ds&zXvzF{n1%1`JsU z){0{!ex#|4_g>rW#=7Qy9Vf)Pho5)UNKkaJ( zr5|FpRi2)W_|b6~R4K>_>!wiBXk?}Vm$Ks(D8fKMBO0HxNM}r$oR_~ZYrCHxvW#)#;oQC`i500ebR=H!18AfiDaoM#x3@PHsKvJG;? z4g}ycjycBg3K(iqnYtQqC38fO2exk#qLFG$F1KT@lT@a|5C(CqfRal&7TuR?A>S%M z``4Ky%<4*`y)x@+f;#>X7pE?+qa5-|mAW-efvtvv-@J~e0ni5k1cTv<%klCePVAcl zxB?P~O(5)xSGj^<7IMl5SJP9D5rq%{f7c6zK^o<)gfNUu#DGm+}Ha50Pmo9a7cCKH){?n&V ze0+RBhMb%nP*zY-@Xeby5)u-#XV2#6=Wl3em_L8MkdTmtg@vi9X?}h_&_-EV+1ra*Gc(h~#Khj--p$R;!^1;gU*Fi+SW{C|U0r?q z_U+Ej&U$)!Kwn(EcoFExojZ4mii#E&7h79fM@L8Z^z@XLmKqru9X)zfSXekLEKEsB z$=uvLAt3=6p1XGK%F4!1H%z5db%cb)Cxz=Wae>Eakt5qI`fs6Vr#MC-$RD^{=Rx+10J zKoGfhxAePrdi68Se9Z*Xsy!>#`+bu6F+Vl5rp;+L>rJCI?{<~DNVw(y&rqxKepZ%{ zef+)swU6h7n$)#xVbgymY}&Rxa~{8v%JYwYp7_LO?ZX4tID8*1oU{5&nEBmT z4{ixr1XnVoqe$RIAPs>>9yj}mQFy^4V5~5By85}Sb4q9e E09M?7umAu6 literal 0 HcmV?d00001 diff --git a/resources/sprite/conpher_1x/list_off.png b/resources/sprite/conpher_1x/list_off.png new file mode 100644 index 0000000000000000000000000000000000000000..5f64e19b7453fd94f7c8673c0a35788d4c47bc5e GIT binary patch literal 177 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnF3?v&v(vJfv=>VS)*Z=?j7nN1iHMMTqzPqZf zVaklzQ)kXuxOC;hWh+B>NE-r`F_i@Q1vAM1o_*jfkmu~_;uum9clP{lP6h=57f0rL z)`-R%jg2cK8fWHmC~ec1k&b=$uw}MQnC+#kjtLnOcja!Fta)iX<-Yc;aGv!RFZG@D Y4qR7FKlozqPM~oNp00i_>zopr0Fuu^od5s; literal 0 HcmV?d00001 diff --git a/resources/sprite/conpher_1x/list_on.png b/resources/sprite/conpher_1x/list_on.png new file mode 100644 index 0000000000000000000000000000000000000000..5f104f217d3f9abafeaa02a2e7e0de301e6db276 GIT binary patch literal 199 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnF3?v&v(vJfvl>na**Z*L^#>OTpDjF0N#Lv&K zr>7?%AOIA$wY9agv(wkt|FL$;L!f%*k|4ie26_2iD#y11x&EFmjv*CsXU}isJfI-Z znkelWdyrAa;m!fIxeu7ODxv8$Pue7+MsH~NloUF05gNBKqq^PK^v4x0>mzG`O}|1H@QcvlOrs3Sos00000NkvXXu0mjf{zAFC literal 0 HcmV?d00001 diff --git a/resources/sprite/conpher_1x/more_on.png b/resources/sprite/conpher_1x/more_on.png new file mode 100644 index 0000000000000000000000000000000000000000..d6c1c6b12a1dba49b903b235938137f02105786e GIT binary patch literal 410 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE3?yBabR7dy>jHd2T>rxW3kwS~Gc%AUA|fIn zARsF%%gV~i&dwek9Ss!Rv}u!)k`faWlb@d-kZWXQBrh+27v~)l~fP;gBzP|q9!-s)}*x1;#wze7@8&8}# z(b3Uy!h{LFzP@&LcFoPrQc_Y27cTVn_6FJ_BO|kB%^Ej1H+y?~cXxL_i^(BCm&=v} z`2{oh@3+_I|8RaOzyACF%TM{A=l}d)D*xk@z~ z2sk`6ap>K3TP5OZ?7RAn%bfQoRyFHX%&!03Qu=hK-)DdJrCLir?~QosrV%=Ce_7)9 z^yV{Jw#*hS$sxJR7JW9mcjJLJg9lqi!JE#9mv$sM|K$=`zxT>o^87unbVzJnN9)#h&7e!V{@4@+L6DCZ zK@dR%zp#MvQ9cAk5JYX=54NOs>8gEKoBf#U!aD0*vo_SGn`yI*9kb-T_nzG6+~+*! zxo_XeCN?#hh^9%kts$lJKH)Wy1xGQ zj!rnVPk3z(m&4^%b@z12m0c=zpV=yvt2(=s8l6F_?}IDGfk9x?8_gmKaBHC$0=fgL z?KLXY+HRe}7m7^JCS%E~v-8)0$~QR;lHjg&^s>6Ax3yi=V=zG&%~p>;|02DNM1L1Hq9-CVX&BTEx3Q1%ZsO1iY7+w%M z9M|9a93JvQ2e;`I?1+Xigm|zB5W!1l5CLZvgiSl3eH6-x>W7Z~_0?^aRosKDVn^%Qo7Y9#zMYn4k5fnf=BpZN zygi@XZsOi~;t`yuQv?de-(Sitwfv)b4%G+<5)+wpQPDyF>fc&>VR}cMeJ50Lz zc(tdpCGS8ICpMOtZdEP6>?K(qf6BBRC_ngWQAM0>alfm(zp=IF+#Y6aHrG_pyieaK zkEQu{7Ppj)*z?VT`e%Xy`Ue=ffH86#bAR`h+o=0COU;OqbZ literal 0 HcmV?d00001 diff --git a/resources/sprite/conpher_1x/people_on.png b/resources/sprite/conpher_1x/people_on.png new file mode 100644 index 0000000000000000000000000000000000000000..87fd8859510668539f4bc4813d2d0acb6689d587 GIT binary patch literal 965 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE3?yBabRA=0V4NM`6XN>+|9_weBO@ad6B8dF zpQxxPGcz+A8yh=2I|~a7KR-Vg7ng*D1W+6(0^|w_2?4bL0gwSy$;!&g!^6YP%`Ge} zEFd5N6c-T@(bCci3=E8pj*g0ol9ZGL8VfWeHa1pDN=i^rP(wols2FIbn3&kQb?fZy z?SZ=V_4R=&f#w7S1p&E{k&!@Sy}Z1DB0!ZuAS){?EiHZN(j}lQ1hllYaB^}2b;-%e zDJUo?D=PyPdwO~TRjyvWnwOUsXfM!4pgXOtt&bl+&cVUa+1Uvc*Vfk7)YJqrfOgs1 z+5(;G?(Pm$+9?9?;j8l0Cbh3qobRf8_;A`RaKy;92^{+ot>?$taNpCZES2T zEG$%1RE&&_TwGj$rp=o-59n(T4-a*9^$Qm+7#JA5c<};gk)@?2(0L{%CT3=4eSLj? zetyl(&A^b+)6-kAVuh=#tGT&3(3`;EH8eC#O-%&`4$yabd3lYEjTyJQd4O>fQWE4B z45Y!po}a<~VLZe6_xAY={0t2J=NaZR+B+fhx81=25E{-7;aaSjWma8ZV zxZOTh`{>;}z1Q#fww&5={BG{s^yRbDCV6iAZoAVz^r-EJgN?hmFNpP6PqFZCxx-V- ztz@w8Z4*Q5p>6#e#hcDHbub9E3QoUR`RY(-!QACRAH-Y|l;R3ZVlT&?N-bWxa~9V^ zPlpHxC;7AAWL_Fg`udgs&DIAE2biof!l$R*(lC|XA|AId>fqBz@3ngmY@KMcHm-VM zV$7kZ{{jwg4Jg$~cC=fU#2g*AHs$x+aHsSs$C>2U{@obmav*D(^^Hvj?0l0HZ`xj+ zJ*BaA&C%l$N>iKQioHFqr-)5H;a;nyQ>TNb|`z}1cuwuit6Oq;-=g*{hw4M2L zDCsft=Xs9~y9=JnOiP&m!#i`{ohE;Mdv2R}qg_|H&mEQ6o^a>u&pCb5J2#2e|4n<$ zul4MH)tT}N@!OhS93dOx@7(?K!*j|N-~Z`t%j#5JS@N1(-ab0b8Svxsjd1m;VF&hW z7%Y-pv}D>VO^!DK`&U{_nD?`vVZZaI#ufL!1%w~1eITUpVqL-ie!2OeSoU=Fb6Mw< G&;$U=d~2xy literal 0 HcmV?d00001 diff --git a/resources/sprite/conpher_1x/settings_off.png b/resources/sprite/conpher_1x/settings_off.png new file mode 100644 index 0000000000000000000000000000000000000000..d75b0f1fb7e0d9a3bb374416f801316abfd70f8b GIT binary patch literal 1025 zcmV+c1pfPpP)R+QGokh?t&@>w%$B+4K@CvEaG4-wllXLCH?%9NmQC zpmgRDuY2?0<@SpP_f#w{nqUS31*fGSFFM*%AwIw4(Rs@Hx0KhUaDH`LLrtY7h0}6H zr*?B1mQ+gxgWA1`TvTqIuNz6pe9_gGAajMH9i5#M7nM8xtQU*{@*p~Lv+Fn|(;0@s zq+&ah*O`1lcWmJD`rgDcND~q-m|qGEMcNujXY-PZ^)aVx?PQg2)P51c;qkd-*#(AB zSq9O`Wu+f^lBg~VrS5iBE0m?xb%(~B;<2Dy-Tlys#V>YOSs=3fVM!w{ng+T;&{Mg; zzX7tt@Ytk4#J#Q!%)}Ft)rXqUY_W~hj%H{zrn9PE0W9*QaGo^)|Eqq}7;Yk? zlc$2|fP2~20J<)O$oJC->z=R;Rl@}|negdTw@qVWX(dE%C;6E-g9!1kXD7GSe(}T@ zE*za|W~<{$#AK0dA{bSEOcad_j*fT6iGVHm=H0!5F_6maRe6td*>Nubfnqk8YQ_c# z)IT+o>lYMaAU;kz|K9+>01}&vf>g(*q9J77W+K@kC@%{;Py`g@Q3o6*UkyO8Dq(Vj z3#C)dL66a7Du{he;Wb;7OoJxz050@tcuX{|SzQAFFG{qv$Ic@c2D8y`YnHQ3;Wf|r z8z(w-*N_jR5O1)2A_J z6#u_WMrW%-qZ6Vl0LZa`SF&zdH=#zFgue_(>iE~c89CMhqM>kY^V`2?)YO|WA-oGS zEsTWw$O}%xG_rWk;zpO~sTnK$CR7XnRUd#x8Wi{G`Q=r`dLd!8YUfu4kaZ5L<;RdK v0wII)+rQ`E$m+WdBQT~qy#j|&d!dRnVE@+Y3I(JK*8A9*!=wbB}jPB^3JTiT*i=?lIypJ5Ter^C)D&nVQ17*C*BToepFDXYD=RA}CkIpsbil)h5B2o) zR8>`hB2rRPLPA2kyu7TetU$K4wKdS$X=!Od20J^uiHQl2tD~dy_U+r0l$3ygfavIG zd3kv&D=RK8E=ftrz`(%z`ub_prWqL-UAS<;)zuZ~1t7V4^=btL1)%d}WMqIg0yPE& z1w}+eL`Fsext~9O{_x?$&6_uYY@oP@hX>FcKR-WTUtgd~Pft%nLqnjy+}+)Q-t_YF z^7r@m_VxyP(AnA9$HzxkSGTvf*Uilh=p^+O-Sl;Qs!8pnH;& zlYt=&v=r#tq@<+d$B)mNHEZ_l*+Az39oE;^2MnbN6DGWP@j^mE;>(vW&z?O?O-%** z9q344$d{Lw&zLboU0q#UTRSr|^W3>}z;M_*(f$Q6Ddd#|`2{oZ%RlVD|3S9?{zskp z^8QQtxll|K0Tdi~Pes$N%ZvwwM28^|5^? ze|*N$kLT~-KhLlKUSH=k|DX4tmwx}NGyk7{f7s{uUS6O1pNBoHzrX(H@1H-T zUes>xJz(lv@9E+gQW1CdOz>tEM}fA7Yi7-KPVT?9E%)}ewK`j?dy@5Y|D5d=-YhOF zdiVS9m|DS~ZioIa*(-Z1PM1BSt>EkGw740mQQm3ge(T!}X8)gI&o(ocZ~w^)6BbCO z)qE{(`^2Nxd${;{y2lcixy4pQDSH;pd%81ssl8gyRaC}ID-^}r_ElIv5xE6Ix*Z+-AM zyY=0|PxBrx{uOtH$?CrA!z;e$b_F)ROS+H~pRb%ARvH?*^{B-rQSGe@ib|yd4b>+X z&TyKNecd$o1_xux<=uAtI}2hDUVQy~Lu=04`)rQEFZyKuCBMJ3wfg*q-1!v5S)SrcQN##ao;2_d0O6EIz+Ad&~Y+D_S*< TN6nZEOf(Fhu6{1-oD!Mt<7U)R*SaOukK{z*$$ zuFWkds;+A+DX%K8u5It`1Cn`#B|vUnV@qvAGf=9axODdX#p^e3pTA@|Q2n~i+acOF zZQl(vVcw!;3zn?tn=}omxT>yU%8c2w<}C#3-MDSnJKvvQfR>7s1o;I6X&`v-zy3Xh z#Ss7geCMr@Rv_<+r;B4q#jUqjZ*w&p@UT4ydHd|#@+((1fBq|9)VhiL;+iT$HRb!h z2M+LGOmJ9pzU=dvS6^1C%hc!#YXX+A=Z#`Z8T-G@yGywo$Ouw)I literal 0 HcmV?d00001 diff --git a/resources/sprite/conpher_2x/calendar_on.png b/resources/sprite/conpher_2x/calendar_on.png new file mode 100644 index 0000000000000000000000000000000000000000..b60e94dc0246c6f11eb78b5a76118b857ca4af86 GIT binary patch literal 421 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!@&kNAT>t<7FDfbutgL)}eSz8o0s?^AgMxxg zO-+Fc^z`)j`S~?8G$JD-fw~eB5`ac+*|H@tFz{VQU? literal 0 HcmV?d00001 diff --git a/resources/sprite/conpher_2x/conversation_off.png b/resources/sprite/conpher_2x/conversation_off.png new file mode 100644 index 0000000000000000000000000000000000000000..5c50e5ccfdafbb5047d24cef9dcf516e04e045dd GIT binary patch literal 1771 zcmX9-2~bm46n!9ZG=Py-QLz%8ao6&3sg|+?#RVNU5k@VRAZ~RdAcQ0=34|S$pb)kI zAwqya$R~gV0Vg1XrC=x6sbi<8ao2H+b)#q3Cs+ zI3+jlJfghQe6ch`tG^^pO|MX?1qsPjHTB4++d3L_EqLXN5>wJL&*m4@Y3X=TQc_A< zT4qjkEWfFx9krzuDm(yLl$?SbRjmg2SWz*t054WlO42ga4Z0eQHYQF`U9Z)*cM1}d zqvPUb1w}x{N|H!LNfMN6^=+BC=g=DMipnanRZU@uLZ#L~ zLP>emL{qgUIVJ79yp%6YK$ocr^ zg$ZdAX=+9`LdXZ_iTs?i3S~726cj7K4TWf(o_z-Sh{9610fCLpZOxZ1g8=xzL)0Q4 zCW8;?PljMJBp?JnXoNvbIsiF%1>p%ai8Q~k7?L$QJvhK*3;qtNywWcZi ztPEn&0!`sOxZauevvu1iNqQvHG~|^@}~BmbF8_uWSjHbeBKvz;Z5*?B-6y!v6x zA8T`h77eZznZm<;QvKg|glIO~xq6bo50`Vh#J>JE{sys}={9%z!X2i&?F(F*qyBzk z%UZ`AaCj6Tovs}TttUsAe6R5;QLk#-Y&WvbK5%_QmYY@emyL^huB#mVT=lGI=k>Ry zp30x$`mWyV^p}^I?x$hxqCap$ zzvaCRJVEnyE`LeJ1I~Uhq_Z_^MvbR2enbKW$l`&_h{~^I;Va~i`Q|9b< zoOh*nHr;sZq{fc9|6Xa`m%Fb&+3y)w2*<(z<| zqE_K!6IkQXF9;K;PLJriet N$JT%?y3G;N{{WR+V@?17 literal 0 HcmV?d00001 diff --git a/resources/sprite/conpher_2x/conversation_on.png b/resources/sprite/conpher_2x/conversation_on.png new file mode 100644 index 0000000000000000000000000000000000000000..8d1bf1435d352f5c689f8d948c11ce8fbec78385 GIT binary patch literal 1592 zcmX9-3pCVO82@_=Lm0;Uk-^9-jPaZbV;FD7BV!dIvS(^HuWh#(DX*+G>$#JSPN-0; zNuxy)H7aMtXpL$dg+|42NW;+CRayHv?m7Q^zx(?h_xJto|CUD50@YQGR1pMG4-TS6 z!|JpBp%q}R?=JX&AoA6bVKM$&TU$y>N&qS=D}%i=NqhYI}qB1ct zp`)XttE-E_V2q880R#hPO-)UCdHG$tc0oLBcjDF5)D#pHR8>{6SS)~G^LRYiLYRSp z0fWJSFcTA#*49=H4GnE=Z7P)tHhA6L-64Me{{0ZVwzfv6(}5uzBo>PShiVW5DYmw@ zAt51seSL5=l!D^`1TUM-*3;8dR8%xHGz4P%_U!|3rxA!59UX<)!omXj1xhlRtfi&J z+}s>0+t}DZWqo~pFxuPOV`F0vA3p5o=Lg(?Nql^~y1F{#0u!i4p-?~>7yyD4AP(RO z2?-#My}doC1e}3`m6a8^BoawjSQxkfiHwX44Go0~adC0L)5pgrC@2U>LJF{j7J`F= zqoSh1!^5Maqaz|BXfzt6KsuRB1~Q-$C<7_}{{CiWW9Mh~%*@Qv(o$DfR|0_mBEVf_ zXJ>=vF)=YcJw4xahD5>dSaK?wb`VyCPrxDMBn*P&Au`xLZ{%n2kvy_ENxJRDU}7_n zm2PrpBL;c)w(?132w{aoCJ&DCd3^5ki6IOcI zOB;*)JZWPF50{PMBdcVb6vq$~kagVZ6DfI~gKXlmxt|FL!mef!2jIPo22&|9%*5py zQT${i63FRnanL=cb6TlPCDpjByr*}22+GG%r%%`S_I^p~_$k-0+->ftI5DR|D)pS5 zwGxsamtb({UsbA&J(eCzXeuwtOXE7@D%NRLI&Ej@YfYlnjo?)OlZOVoyE|MY>%LBB zqffLp^+!fiuPV~6TzK^d{}78{KN(74%E~l2#qzbr`HYXJ;=0q<0%pjISBJ_{O%Ty~ z+CQdQ1$m9R_<~hmJ+H36we^HwUVodfQgHWzl>@b-mnI4e);jcnSu>gE&A9a`-ZdGi=mu5p-LF8HIZoaSC-_q zY!B&ay%NSF`PyvT+=pHPX9@dq(`W#-U^U+0Sm|NKP-fyM2C>39%I3LyJW7I3c-qG^ z!yYF~HWQI3$`JGVl^cC~j&P02*vpR`3{$1C4R(`U`Z?tkEs3An)G+6>2rGJ;FnZ?e z?K0a;Led5D!FT#Aq8AOhnySPsLWCYKuC)fmWLEwAN%I#}lV=p)$tCgbY{g8mGog6G zNzimXt!{B(&b`+sT!5;`r<*SSnO;z&8y!zKmmW#PWF^-G#xJ@zx6;{F2JyX{0o`9; zbxn#+E<56*?iAsZFAkP>jn^Ol?FdD++;#C8E~VM8=G>)QGGDb$lYCOUK;h=lQLox8 zbOnZnR?EhcY)G;4H!M$7(5rucpCH%mc}1gL97dXwIe|WxlE{Z*one~X}HS?fb zbm)>TVzrXyl9Kg|5f^*q=td?VDWq EKP(}EP5=M^ literal 0 HcmV?d00001 diff --git a/resources/sprite/conpher_2x/files_off.png b/resources/sprite/conpher_2x/files_off.png new file mode 100644 index 0000000000000000000000000000000000000000..b593b1437fc363dceb124a8d6f82047e4c56cc65 GIT binary patch literal 1706 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 literal 0 HcmV?d00001 diff --git a/resources/sprite/conpher_2x/list_off.png b/resources/sprite/conpher_2x/list_off.png new file mode 100644 index 0000000000000000000000000000000000000000..a9add168df36aa2491d60036e25e3608608fcb25 GIT binary patch literal 306 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!TmyVUT>t<7pIcB=*VJ0q*s@^B ziptssASx^=&nqmhZ*E<Cpdrt$RT$ zOI^h|Owy;in(WqoEGx)+*}{)mLA<{8&+{1L(Ch;r|C#Vc9-dR0ZdXwCg_o!J)?B7d zxen9WC)Jq+?9y&XsXxj!&13JqbJ_wEozG^nDhd6V-ME8w+X1l~hZ57dgKqB=Q@MRk lY|_6R?wrQ*#`1^1JK}6beE;@X-^l_w($m$?Wt~$(699qBemnpG literal 0 HcmV?d00001 diff --git a/resources/sprite/conpher_2x/list_on.png b/resources/sprite/conpher_2x/list_on.png new file mode 100644 index 0000000000000000000000000000000000000000..0214b6b0caca95cbbbebd5ff4d8c0b6185ae4b34 GIT binary patch literal 295 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!>;rs4T>t<74`hmnhyWSh$jAsJfr8D=&9=6-o}QjSaa~>Apr9a#VmmuKJw3gsl{d`}aVC zfuCP?y-rvakk#$!;uum9_x9>(zC#8)E`ipWx0uc?KJdR@d$Vd#p`wse#<^47Sz&v- zY?K#eYNyV2`O`22*qb_vr-gS+63vrQS&IHv)2N#OwC6R_tyqbm4bC V=kr-i-pvl=LQhvemvv4FO#tt3XH@_I literal 0 HcmV?d00001 diff --git a/resources/sprite/conpher_2x/more_off.png b/resources/sprite/conpher_2x/more_off.png new file mode 100644 index 0000000000000000000000000000000000000000..ce90ebc722eb576d827f4b8e5f708ee32694edb8 GIT binary patch literal 776 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+yeRz!(h}pnDdtfSL)^0yJUG#w{%!-9Xv-OO^wz13Is( zZ(`4c$v_tZ9kX=Ry1K@ex~A6Vwoah3H5<3C-L!4}mK{JY&|hs`y+B(a>U$?n0a`a< z>I|TnK#Qi%nmcXQJc!qTjs&_5;z6J-3zx2h7!Gs^#DhRvAie;)bH&Fv{eR%tXD~pUoZnd5XggpJ`~u4fj*55Fo~A$pt_-$_rzS2EA3yATYSQvC zBi;Dxr_bL@FE)Lwyzn#aUfn;tbF+4Q`Mj&`$nvG?$62Htf95UB__KjU!QScsM?2%R zi#J(YTU&pwJh&>OrqbZP8QUrTNk>-2YuPLp;NhC|_TrB+g?&ygdQ;|Sv|eR+yM(Eu z>ChgHvXD9z;R*Q@m>xfGOEz^-XV!|3n4r*hs$ZP-)7i}r{zR-{dy#fXL`1D{!6)IF zjWvgJEbRGKGhX75mc96cPhp?ZA=Ya*k`J=IOE)#yCp6Kb*8)J>r4+-|b)m8^c|;R$H#` SJI@0Hp25@A&t;ucLK6UDHh^pZ literal 0 HcmV?d00001 diff --git a/resources/sprite/conpher_2x/more_on.png b/resources/sprite/conpher_2x/more_on.png new file mode 100644 index 0000000000000000000000000000000000000000..9b2b0f43213e724a71378106c5a5d9b686ab15c9 GIT binary patch literal 923 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+yeRz_>8LC&cyt|NlS{Mn*;^CMITP zW=>8{pa>fq8<2zp4h{}hR#pg?ot<3}4B)btFJBfC65{9Q2Py+HfO_TR`iJhHYczC#*o14A8y|=fwzrVk{ynI4Jg0;0Z(2qc)0s;a&Jw07r zT}@3*qobpN?)UQY0y+lhcx7c}pw&Bf?sRu|kBW*aFE8)v>RPvMT}4HOmX?->hsT8r z7qqptJ3BjVZEcSpJ!)oVmYSNXuC6XADQRM2a_7z+X=!OcKfgb#%bI{O6j&1E7Yw9< zK%c?CK3=}we!qSEd+4~e1DaosW*(cj*_(6Woc!yXM8CfJu6g@iX+!Ws zz6+l9@9!F|cyzn&22Wz>>dD#i2UhM`6xn#Ahe?Z7R&M&?S0`)NZD;g5tUULToJ`Z+ zL-WE9^c}UhzMf%upS|HCXLErq*IV)~oWGyI{a}Ut4%wcl3w%Ge^-Esl+u|P6&#|bZGd0bv;YN?i(eKyl~A)BO&05E+1hbJ|1JyBV69u#e!u6{1-oD!M< Dttn_i literal 0 HcmV?d00001 diff --git a/resources/sprite/conpher_2x/people_off.png b/resources/sprite/conpher_2x/people_off.png new file mode 100644 index 0000000000000000000000000000000000000000..ad51a2427d1bed651b4a368dc7310bef48d8f55d GIT binary patch literal 1668 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 X+>W>HiM>&(00000NkvXXu0mjf>mPC+ literal 0 HcmV?d00001 diff --git a/resources/sprite/conpher_2x/settings_on.png b/resources/sprite/conpher_2x/settings_on.png new file mode 100644 index 0000000000000000000000000000000000000000..2aa6501876a6c2c8215b5241d6aa7c868fccf8b2 GIT binary patch literal 1489 zcmV;?1upuDP)^**2-Yq)Br*IY$Q0jAc$4qSJ0N5EU1lOoszI z|7?h0*sKhutf*tm4VE8uOb{t#h|^ZWm|Mk7YFZUKk!L@era5U^+os1~eb1ldJLi1w z^L_92JAyDJQ!*vvkYp*Hd8CtUdVxx(dy@2nzbzNnQcW?9zQK`c`Xnu3W|}fO7Lpy% zg%RrRTT!rJ2@d?%>E{LJGuN*(XaumVyBH%y}Y}j4G%0R z$Vd^Fi@x0Kk2@~mKtiSg=gkBG9tO6@Rk4Xy?m-WJ=;Ao8IM2vz= zCpR!NW@Ra+WxdrnRW)(v!^!A`#l;V6P^aQ1N-;2}MHhz9iF)5sDsjXV<#Mup2?H2< zE3geKMs`fBBA0CDk&OY7^)c!dT$ou!dP{-;`}=Kin+_LNYB5rckvf{P_+L#0iAq-B34l;JZBLmTV)pdugNR3OD{5 z>@1f&&f{fPUYJN28U|`Vp7UcuaB!=4Ao?$F9n1pDx0Pb1mZJWI%(3@d>lgqUIP#hx z2tukjKa?3v^Q3w*J62#uL86-6V5(QAPw~tSCXYWq+5=-b7t~=pCJ4!f#l6L>rGR`& zA|17jO7b!ADyvz_?C~NLVn@Nnaqe)2eUadFvzIpRunQRlGfe?OIJB+=d-%u}eTZ|? zNF8RHFj8}UoB+4jgT$xcL&S^!Eo2lVKIz9#Gh!&P0|_skmjwaC$Ipoy3qQ7xyDH%C zgh+Pt_DLw%IMqHFF~9xZ0c`_LyS>vsDu6U%Yxf+8q2DLln^0)r%I+w{@T7AMMc5+= z=`dZuJz67iBx7QMC(%0TVL*m8o-+(9&l$reaPbASAqoNpygx(`>Z!XfXd|=t<4FK>EJQH>{ClzEx*;y~H2_JN1n)wBKG;+j1 zizTea%yQ7X=j2k?Hc9Nm5 z`Og{CJ=M_2(3t#G({IXod#XmQ1uiPdk~9Rkbj%s|)6P(1yPkbVGz37r*0-7C+@Y1N zQ7D^e;U~7>}bH3BAr;ldq!7a0W?A3+a3JOpoR>w>Xz`mO^78*NwPRn-?D*ADq; r<+RqDK5A#}#XERLn35@(lF{UUJHQ4!3TH $generator->buildIconSheet(), 'menu' => $generator->buildMenuSheet(), 'apps' => $generator->buildAppsSheet(), + 'conph' => $generator->buildConpherenceSheet(), 'apps-large' => $generator->buildAppsLargeSheet(), // TODO: @chad: should we actually remove this? // 'apps-xlarge' => $generator->buildAppsXLargeSheet(), diff --git a/src/infrastructure/celerity/CeleritySpriteGenerator.php b/src/infrastructure/celerity/CeleritySpriteGenerator.php index c6b2ac23d0..bc25743b83 100644 --- a/src/infrastructure/celerity/CeleritySpriteGenerator.php +++ b/src/infrastructure/celerity/CeleritySpriteGenerator.php @@ -176,6 +176,42 @@ final class CeleritySpriteGenerator { return $sheet; } + public function buildConpherenceSheet() { + $icons = $this->getDirectoryList('conpher_1x'); + $scales = array( + '1x' => 1, + '2x' => 2, + ); + $template = id(new PhutilSprite()) + ->setSourceSize(32, 32); + + $sprites = array(); + foreach ($icons as $icon) { + $color = preg_match('/_on/', $icon) ? 'on' : 'off'; + + $prefix = 'conpher_'; + + $sprite = id(clone $template) + ->setName($prefix.$icon); + + $sprite->setTargetCSS($prefix.$icon); + + foreach ($scales as $scale_key => $scale) { + $path = $this->getPath($prefix.$scale_key.'/'.$icon.'.png'); + $sprite->setSourceFile($path, $scale); + } + $sprites[] = $sprite; + } + + $sheet = $this->buildSheet('conpher', true); + $sheet->setScales($scales); + foreach ($sprites as $sprite) { + $sheet->addSprite($sprite); + } + + return $sheet; + } + public function buildGradientSheet() { $gradients = $this->getDirectoryList('gradients'); diff --git a/webroot/rsrc/css/sprite-conph.css b/webroot/rsrc/css/sprite-conph.css new file mode 100644 index 0000000000..6b02619ebf --- /dev/null +++ b/webroot/rsrc/css/sprite-conph.css @@ -0,0 +1,67 @@ +/** + * @provides sprite-conpher-css + * @generated + */ + +.sprite-conpher { + background-image: url(/rsrc/image/sprite-conpher.png); + background-repeat: no-repeat; +} + +@media +only screen and (min-device-pixel-ratio: 1.5), +only screen and (-webkit-min-device-pixel-ratio: 1.5) { + .sprite-conpher { + background-image: url(/rsrc/image/sprite-conpher-X2.png); + background-size: 99px 132px; + } +} + + +conpher_calendar_off { + background-position: 0px 0px; +} + +conpher_calendar_on { + background-position: -33px 0px; +} + +conpher_files_off { + background-position: -66px 0px; +} + +conpher_files_on { + background-position: 0px -33px; +} + +conpher_list_off { + background-position: -33px -33px; +} + +conpher_list_on { + background-position: -66px -33px; +} + +conpher_more_off { + background-position: 0px -66px; +} + +conpher_more_on { + background-position: -33px -66px; +} + +conpher_people_off { + background-position: -66px -66px; +} + +conpher_people_on { + background-position: 0px -99px; +} + +conpher_settings_off { + background-position: -33px -99px; +} + +conpher_settings_on { + background-position: -66px -99px; +} diff --git a/webroot/rsrc/image/sprite-conph-X2.png b/webroot/rsrc/image/sprite-conph-X2.png new file mode 100644 index 0000000000000000000000000000000000000000..df789c68efa849394c3c62e208df3cc8c122404e GIT binary patch literal 11685 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 z z!SBnhw~-yrqy=O}O3(D>f6PXX`=2?MeXV!nxYch2Me-|fIel!aKd5@-FxFoD(3qG$ z>dqwCj$I{~^tignO?1#sM+NFII#>=|PA}XT9Ir~!1ouAuxj{o(Jhe&(2eVRrBvLW{ zX1YY1{xCtvOtg|-_sHr+|$br8;$jBaM4HL{*Hd-ZAAS5iqFxhOy3qH;WJPP zQ5GKf(H9;g>ZTE(xhMmV&xFp4!mACQ6kAZ*mRK&#tnXInMN$h{t33qXU0;1d!YdVQ zSiXq{8ja&==B|9~h=_?JytVsukjy!L!W@3V!8k3>EJ+qmAC zwqQ+4BxSksTKAwhTKEzmBAiAWn!-Uhm1Q5r1M+oh+CT(fTCLE8t2GL!e>!)*^26h6&!+mE%r()7l1ORq%j*Zn^&VfLw3>$wz?ZgEuhfRiulODI|g^v z3HXQ!?NkTc0v{XEURjs;;g13ZTu?Wffk}uBB1Xk0pP19|LAEv7wc)D{0TY`?mICi>uS&3!D z#lrm7@yDQX2UNv;!np)2OCD1u$S7|*#w@uIzFESN#?3$3&VjY1;vg;o-6^N(rmE#I z?u*-puq(67a$W=}{;ViG?PP)?^2IY7q5bwXlj|bpT@|*nnBWj?;R9*c)vkI{==yJK z+OJ7ZsHI0mCTb56+(xU=jZUyY@idH@*}Jz!FHhwVh& z%-!rbknqJ%y6$=m2>M^mAHP?Ja3JU|D_L$!d1yNktCP91R% z^sdA+Lv2+5>3afF%Ri{hiGg1>AEbcY09C0ynt+~ou|FA0|A+75$GspaBFq6N(xmKn z9gNft`0PSaNZy;LB?L}${V`ukIb6b1OfZ1486hXEzRj%|9)_ke0)^w=6BAE2P9sLB zczAg3oLctk;|kps%vZ$YY}?#c48Ywhw*E z9-Tr`|I8OYYt^MMs+)yJ2{@FMwdJROLP-VrZPm$B9{$pWQP5d3BbvwSInJpz2S~lP&%6J*4U`oG|c8ultdZ-30&LXqAMVxOY zR5+H4i_M^NeD<*@j8cWK9*^C~1>=ITpGDa%i?qLQxvvJ?yq*>Q$Gj%s=KPHP95t^^ zP4^bw!H}OZK~^(>;87hbNTuyQ02>-f8uI~t&h?dI2kfRPs2VG67OfnzoZo3(s?)t+ z#Wl#*wU~XMDwO1yF&5$nc&C=K4w`FR%}_dEWa+6+b!t1)KX~+KkFv6}1FGd8t?-Qr zJ@vjKue`!DS<#|DRJ9RDD*{<)YR4zcjNNjZghG9*Nw}JcmU-iH$xwJ0IUm&X)aG)V z{#170G=q8!>bBni7e-8v=JZhSLbD5xB$B1HM|i*MO=)fy~8A zgS01`TbWQ2dHtM>gQb8A6XQUKH(BkB3d-%2+7RQHy#8t@dO?Q^?&FWYSyMX6=0U_U zutOGRCvKX0sP&i1*iZ*bDIV*u7$<4y32wn6Su+~GKwA0X50|USrB0+HB~nGX5W5bd zV0Tw_jm3p~9N0Q-$WNv$gtI<15ql{y-Vhk;$-P7mIU;FPGZp9htSGeNpe~ zUG3%!Ck!~x0x$&Z0qXw6+NR%d;2UarFBb}t8d0ggQ~N$B{g=OsY`o1)Ti?JFC)SmW zK*_h6#!*!{MI#b^$W%WBR%vTV|JHSBWiOEbL)#x0ETwc^+bM0wO^K~r9Cwnv&IqED z&&D{D;ndcz4R@}(DT_-5^Xe_$2@gNTgrUqANgKihlvN`IhtEoZ>k39fnLe*X@uAE< zp|n)m_-rYiy}?RXGfQgeoSu~tfIn9gitsM2cmW(8&Mgu)!kL2i2!}!;dqqMF(y^e9 zI~R01;=3sEx6tGU?T4}5CA2OcyX`8Z8(nm(+>4E2lgtM25{g6ULbII18nldQsg-hUeos`nXkJq45-+ZO<$J$I;8 z09{`1R;CABZx_>-1*5lF6o4Fwdo_z$xY4-{w>WR5YZ!jkDyXe&Jbt*MDJy8mSIE8% F`5&5ps<8k7 literal 0 HcmV?d00001 From 13eb77fe6cd0244cae27e3cfed3e6763cb1910e6 Mon Sep 17 00:00:00 2001 From: vrana Date: Mon, 28 Jan 2013 16:44:15 -0800 Subject: [PATCH 10/17] Deduplicate handle code Summary: There's quite some duplicate code here. Test Plan: Searched for a commit. Reviewers: epriestley Reviewed By: epriestley CC: aran, Korvin Differential Revision: https://secure.phabricator.com/D4665 --- .../handle/PhabricatorObjectHandleData.php | 499 ++++++++---------- .../view/PhabricatorSearchResultView.php | 7 +- 2 files changed, 228 insertions(+), 278 deletions(-) diff --git a/src/applications/phid/handle/PhabricatorObjectHandleData.php b/src/applications/phid/handle/PhabricatorObjectHandleData.php index 8b216e8f5a..52c1bb7d0c 100644 --- a/src/applications/phid/handle/PhabricatorObjectHandleData.php +++ b/src/applications/phid/handle/PhabricatorObjectHandleData.php @@ -26,143 +26,171 @@ final class PhabricatorObjectHandleData { } public function loadObjects() { - $types = array(); - foreach ($this->phids as $phid) { - $type = phid_get_type($phid); - $types[$type][] = $phid; - } + $types = phid_group_by_type($this->phids); $objects = array(); foreach ($types as $type => $phids) { - switch ($type) { - case PhabricatorPHIDConstants::PHID_TYPE_USER: - $user_dao = new PhabricatorUser(); - $users = $user_dao->loadAllWhere( - 'phid in (%Ls)', - $phids); - foreach ($users as $user) { - $objects[$user->getPHID()] = $user; - } - break; - case PhabricatorPHIDConstants::PHID_TYPE_CMIT: - $commit_dao = new PhabricatorRepositoryCommit(); - $commits = $commit_dao->loadAllWhere( - 'phid IN (%Ls)', - $phids); - $commit_data = array(); - if ($commits) { - $data_dao = new PhabricatorRepositoryCommitData(); - $commit_data = $data_dao->loadAllWhere( - 'commitID IN (%Ld)', - mpull($commits, 'getID')); - $commit_data = mpull($commit_data, null, 'getCommitID'); - } - foreach ($commits as $commit) { - $data = idx($commit_data, $commit->getID()); - if ($data) { - $commit->attachCommitData($data); - $objects[$commit->getPHID()] = $commit; - } else { - // If we couldn't load the commit data, just act as though we - // couldn't load the object at all so we don't load half an object. - } - } - break; - case PhabricatorPHIDConstants::PHID_TYPE_TASK: - $task_dao = new ManiphestTask(); - $tasks = $task_dao->loadAllWhere( - 'phid IN (%Ls)', - $phids); - foreach ($tasks as $task) { - $objects[$task->getPHID()] = $task; - } - break; - case PhabricatorPHIDConstants::PHID_TYPE_CONF: - $config_dao = new PhabricatorConfigEntry(); - $entries = $config_dao->loadAllWhere( - 'phid IN (%Ls)', - $phids); - foreach ($entries as $entry) { - $objects[$entry->getPHID()] = $entry; - } - break; - case PhabricatorPHIDConstants::PHID_TYPE_DREV: - $revision_dao = new DifferentialRevision(); - $revisions = $revision_dao->loadAllWhere( - 'phid IN (%Ls)', - $phids); - foreach ($revisions as $revision) { - $objects[$revision->getPHID()] = $revision; - } - break; - case PhabricatorPHIDConstants::PHID_TYPE_WIKI: - $document_dao = new PhrictionDocument(); - $documents = $document_dao->loadAllWhere( - 'phid IN (%Ls)', - $phids); - foreach ($documents as $document) { - $objects[$document->getPHID()] = $document; - } - break; - case PhabricatorPHIDConstants::PHID_TYPE_QUES: - $questions = id(new PonderQuestionQuery()) - ->setViewer($this->viewer) - ->withPHIDs($phids) - ->execute(); - foreach ($questions as $question) { - $objects[$question->getPHID()] = $question; - } - break; - case PhabricatorPHIDConstants::PHID_TYPE_MOCK: - $mocks = id(new PholioMockQuery()) - ->setViewer($this->viewer) - ->withPHIDs($phids) - ->execute(); - foreach ($mocks as $mock) { - $objects[$mock->getPHID()] = $mock; - } - break; - case PhabricatorPHIDConstants::PHID_TYPE_XACT: - $subtypes = array(); - foreach ($phids as $phid) { - $subtypes[phid_get_subtype($phid)][] = $phid; - } - $xactions = array(); - foreach ($subtypes as $subtype => $subtype_phids) { - // TODO: Do this magically. - switch ($subtype) { - case PhabricatorPHIDConstants::PHID_TYPE_MOCK: - $results = id(new PholioTransactionQuery()) - ->setViewer($this->viewer) - ->withPHIDs($subtype_phids) - ->execute(); - $xactions += mpull($results, null, 'getPHID'); - break; - case PhabricatorPHIDConstants::PHID_TYPE_MCRO: - $results = id(new PhabricatorMacroTransactionQuery()) - ->setViewer($this->viewer) - ->withPHIDs($subtype_phids) - ->execute(); - $xactions += mpull($results, null, 'getPHID'); - break; - } - } - foreach ($xactions as $xaction) { - $objects[$xaction->getPHID()] = $xaction; - } - break; - case PhabricatorPHIDConstants::PHID_TYPE_MCRO: - $macros = id(new PhabricatorFileImageMacro())->loadAllWhere( - 'phid IN (%Ls)', - $phids); - $objects += mpull($macros, null, 'getPHID'); - break; - } + $objects += $this->loadObjectsOfType($type, $phids); } return $objects; } + private function loadObjectsOfType($type, array $phids) { + switch ($type) { + + case PhabricatorPHIDConstants::PHID_TYPE_USER: + $user_dao = new PhabricatorUser(); + $users = $user_dao->loadAllWhere( + 'phid in (%Ls)', + $phids); + return mpull($users, null, 'getPHID'); + + case PhabricatorPHIDConstants::PHID_TYPE_CMIT: + $commit_dao = new PhabricatorRepositoryCommit(); + $commits = $commit_dao->putInSet(new LiskDAOSet())->loadAllWhere( + 'phid IN (%Ls)', + $phids); + return mpull($commits, null, 'getPHID'); + + case PhabricatorPHIDConstants::PHID_TYPE_TASK: + $task_dao = new ManiphestTask(); + $tasks = $task_dao->loadAllWhere( + 'phid IN (%Ls)', + $phids); + return mpull($tasks, null, 'getPHID'); + + case PhabricatorPHIDConstants::PHID_TYPE_CONF: + $config_dao = new PhabricatorConfigEntry(); + $entries = $config_dao->loadAllWhere( + 'phid IN (%Ls)', + $phids); + return mpull($entries, null, 'getPHID'); + + case PhabricatorPHIDConstants::PHID_TYPE_FILE: + $object = new PhabricatorFile(); + $files = $object->loadAllWhere('phid IN (%Ls)', $phids); + return mpull($files, null, 'getPHID'); + + case PhabricatorPHIDConstants::PHID_TYPE_PROJ: + $object = new PhabricatorProject(); + if ($this->viewer) { + $projects = id(new PhabricatorProjectQuery()) + ->setViewer($this->viewer) + ->withPHIDs($phids) + ->execute(); + } else { + $projects = $object->loadAllWhere('phid IN (%Ls)', $phids); + } + return mpull($projects, null, 'getPHID'); + + case PhabricatorPHIDConstants::PHID_TYPE_REPO: + $object = new PhabricatorRepository(); + $repositories = $object->loadAllWhere('phid in (%Ls)', $phids); + return mpull($repositories, null, 'getPHID'); + + case PhabricatorPHIDConstants::PHID_TYPE_OPKG: + $object = new PhabricatorOwnersPackage(); + $packages = $object->loadAllWhere('phid in (%Ls)', $phids); + return mpull($packages, null, 'getPHID'); + + case PhabricatorPHIDConstants::PHID_TYPE_APRJ: + $project_dao = new PhabricatorRepositoryArcanistProject(); + $projects = $project_dao->loadAllWhere( + 'phid IN (%Ls)', + $phids); + return mpull($projects, null, 'getPHID'); + + case PhabricatorPHIDConstants::PHID_TYPE_MLST: + $object = new PhabricatorMetaMTAMailingList(); + $lists = $object->loadAllWhere('phid IN (%Ls)', $phids); + return mpull($lists, null, 'getPHID'); + + case PhabricatorPHIDConstants::PHID_TYPE_DREV: + $revision_dao = new DifferentialRevision(); + $revisions = $revision_dao->loadAllWhere( + 'phid IN (%Ls)', + $phids); + return mpull($revisions, null, 'getPHID'); + + case PhabricatorPHIDConstants::PHID_TYPE_WIKI: + $document_dao = new PhrictionDocument(); + $documents = $document_dao->loadAllWhere( + 'phid IN (%Ls)', + $phids); + return mpull($documents, null, 'getPHID'); + + case PhabricatorPHIDConstants::PHID_TYPE_QUES: + $questions = id(new PonderQuestionQuery()) + ->setViewer($this->viewer) + ->withPHIDs($phids) + ->execute(); + return mpull($questions, null, 'getPHID'); + + case PhabricatorPHIDConstants::PHID_TYPE_MOCK: + $mocks = id(new PholioMockQuery()) + ->setViewer($this->viewer) + ->withPHIDs($phids) + ->execute(); + return mpull($mocks, null, 'getPHID'); + + case PhabricatorPHIDConstants::PHID_TYPE_XACT: + $subtypes = array(); + foreach ($phids as $phid) { + $subtypes[phid_get_subtype($phid)][] = $phid; + } + $xactions = array(); + foreach ($subtypes as $subtype => $subtype_phids) { + // TODO: Do this magically. + switch ($subtype) { + case PhabricatorPHIDConstants::PHID_TYPE_MOCK: + $results = id(new PholioTransactionQuery()) + ->setViewer($this->viewer) + ->withPHIDs($subtype_phids) + ->execute(); + $xactions += mpull($results, null, 'getPHID'); + break; + case PhabricatorPHIDConstants::PHID_TYPE_MCRO: + $results = id(new PhabricatorMacroTransactionQuery()) + ->setViewer($this->viewer) + ->withPHIDs($subtype_phids) + ->execute(); + $xactions += mpull($results, null, 'getPHID'); + break; + } + } + return mpull($xactions, null, 'getPHID'); + + case PhabricatorPHIDConstants::PHID_TYPE_MCRO: + $macros = id(new PhabricatorFileImageMacro())->loadAllWhere( + 'phid IN (%Ls)', + $phids); + return mpull($macros, null, 'getPHID'); + + case PhabricatorPHIDConstants::PHID_TYPE_PSTE: + $pastes = id(new PhabricatorPasteQuery()) + ->withPHIDs($phids) + ->setViewer($this->viewer) + ->execute(); + return mpull($pastes, null, 'getPHID'); + + case PhabricatorPHIDConstants::PHID_TYPE_BLOG: + $blogs = id(new PhameBlogQuery()) + ->withPHIDs($phids) + ->setViewer($this->viewer) + ->execute(); + return mpull($blogs, null, 'getPHID'); + + case PhabricatorPHIDConstants::PHID_TYPE_POST: + $posts = id(new PhamePostQuery()) + ->withPHIDs($phids) + ->setViewer($this->viewer) + ->execute(); + return mpull($posts, null, 'getPHID'); + + } + } + public function loadHandles() { $types = phid_group_by_type($this->phids); @@ -172,7 +200,10 @@ final class PhabricatorObjectHandleData { $external_loaders = PhabricatorEnv::getEnvConfig('phid.external-loaders'); foreach ($types as $type => $phids) { + $objects = $this->loadObjectsOfType($type, $phids); + switch ($type) { + case PhabricatorPHIDConstants::PHID_TYPE_MAGIC: // Black magic! foreach ($phids as $phid) { @@ -197,13 +228,9 @@ final class PhabricatorObjectHandleData { $handles[$phid] = $handle; } break; + case PhabricatorPHIDConstants::PHID_TYPE_USER: - $object = new PhabricatorUser(); - - $users = $object->loadAllWhere('phid IN (%Ls)', $phids); - $users = mpull($users, null, 'getPHID'); - - $image_phids = mpull($users, 'getProfileImagePHID'); + $image_phids = mpull($objects, 'getProfileImagePHID'); $image_phids = array_unique(array_filter($image_phids)); $images = array(); @@ -221,10 +248,10 @@ final class PhabricatorObjectHandleData { $handle = new PhabricatorObjectHandle(); $handle->setPHID($phid); $handle->setType($type); - if (empty($users[$phid])) { + if (empty($objects[$phid])) { $handle->setName('Unknown User'); } else { - $user = $users[$phid]; + $user = $objects[$phid]; $handle->setName($user->getUsername()); $handle->setURI('/p/'.$user->getUsername().'/'); $handle->setFullName( @@ -251,20 +278,16 @@ final class PhabricatorObjectHandleData { $handles[$phid] = $handle; } break; + case PhabricatorPHIDConstants::PHID_TYPE_MLST: - $object = new PhabricatorMetaMTAMailingList(); - - $lists = $object->loadAllWhere('phid IN (%Ls)', $phids); - $lists = mpull($lists, null, 'getPHID'); - foreach ($phids as $phid) { $handle = new PhabricatorObjectHandle(); $handle->setPHID($phid); $handle->setType($type); - if (empty($lists[$phid])) { + if (empty($objects[$phid])) { $handle->setName('Unknown Mailing List'); } else { - $list = $lists[$phid]; + $list = $objects[$phid]; $handle->setName($list->getName()); $handle->setURI($list->getURI()); $handle->setFullName($list->getName()); @@ -273,20 +296,16 @@ final class PhabricatorObjectHandleData { $handles[$phid] = $handle; } break; + case PhabricatorPHIDConstants::PHID_TYPE_DREV: - $object = new DifferentialRevision(); - - $revs = $object->loadAllWhere('phid in (%Ls)', $phids); - $revs = mpull($revs, null, 'getPHID'); - foreach ($phids as $phid) { $handle = new PhabricatorObjectHandle(); $handle->setPHID($phid); $handle->setType($type); - if (empty($revs[$phid])) { + if (empty($objects[$phid])) { $handle->setName('Unknown Revision'); } else { - $rev = $revs[$phid]; + $rev = $objects[$phid]; $handle->setName($rev->getTitle()); $handle->setURI('/D'.$rev->getID()); $handle->setFullName('D'.$rev->getID().': '.$rev->getTitle()); @@ -303,36 +322,28 @@ final class PhabricatorObjectHandleData { $handles[$phid] = $handle; } break; + case PhabricatorPHIDConstants::PHID_TYPE_CMIT: - $object = new PhabricatorRepositoryCommit(); - - $commits = $object->loadAllWhere('phid in (%Ls)', $phids); - $commits = mpull($commits, null, 'getPHID'); - - $repository_ids = array(); - $callsigns = array(); - if ($commits) { - $repository_ids = mpull($commits, 'getRepositoryID'); - $repositories = id(new PhabricatorRepository())->loadAllWhere( - 'id in (%Ld)', array_unique($repository_ids)); - $callsigns = mpull($repositories, 'getCallsign'); - } - foreach ($phids as $phid) { $handle = new PhabricatorObjectHandle(); $handle->setPHID($phid); $handle->setType($type); - if (empty($commits[$phid]) || - !isset($callsigns[$repository_ids[$phid]])) { + $repository = null; + if (!empty($objects[$phid])) { + $repository = $objects[$phid]->loadOneRelative( + new PhabricatorRepository(), + 'id', + 'getRepositoryID'); + } + if (!$repository) { $handle->setName('Unknown Commit'); } else { - $commit = $commits[$phid]; - $callsign = $callsigns[$repository_ids[$phid]]; - $repository = $repositories[$repository_ids[$phid]]; + $commit = $objects[$phid]; + $callsign = $repository->getCallsign(); $commit_identifier = $commit->getCommitIdentifier(); // In case where the repository for the commit was deleted, - // we don't have have info about the repository anymore. + // we don't have info about the repository anymore. if ($repository) { $name = $repository->formatCommitName($commit_identifier); $handle->setName($name); @@ -348,20 +359,16 @@ final class PhabricatorObjectHandleData { $handles[$phid] = $handle; } break; + case PhabricatorPHIDConstants::PHID_TYPE_TASK: - $object = new ManiphestTask(); - - $tasks = $object->loadAllWhere('phid in (%Ls)', $phids); - $tasks = mpull($tasks, null, 'getPHID'); - foreach ($phids as $phid) { $handle = new PhabricatorObjectHandle(); $handle->setPHID($phid); $handle->setType($type); - if (empty($tasks[$phid])) { + if (empty($objects[$phid])) { $handle->setName('Unknown Task'); } else { - $task = $tasks[$phid]; + $task = $objects[$phid]; $handle->setName($task->getTitle()); $handle->setURI('/T'.$task->getID()); $handle->setFullName('T'.$task->getID().': '.$task->getTitle()); @@ -375,20 +382,16 @@ final class PhabricatorObjectHandleData { $handles[$phid] = $handle; } break; + case PhabricatorPHIDConstants::PHID_TYPE_CONF: - $object = new PhabricatorConfigEntry(); - - $entries = $object->loadAllWhere('phid in (%Ls)', $phids); - $entries = mpull($entries, null, 'getPHID'); - foreach ($phids as $phid) { $handle = new PhabricatorObjectHandle(); $handle->setPHID($phid); $handle->setType($type); - if (empty($entries[$phid])) { + if (empty($objects[$phid])) { $handle->setName('Unknown Config Entry'); } else { - $entry = $entries[$phid]; + $entry = $objects[$phid]; $handle->setName($entry->getKey()); $handle->setURI('/config/edit/'.$entry->getKey()); $handle->setFullName($entry->getKey()); @@ -397,20 +400,16 @@ final class PhabricatorObjectHandleData { $handles[$phid] = $handle; } break; + case PhabricatorPHIDConstants::PHID_TYPE_FILE: - $object = new PhabricatorFile(); - - $files = $object->loadAllWhere('phid IN (%Ls)', $phids); - $files = mpull($files, null, 'getPHID'); - foreach ($phids as $phid) { $handle = new PhabricatorObjectHandle(); $handle->setPHID($phid); $handle->setType($type); - if (empty($files[$phid])) { + if (empty($objects[$phid])) { $handle->setName('Unknown File'); } else { - $file = $files[$phid]; + $file = $objects[$phid]; $handle->setName($file->getName()); $handle->setURI($file->getBestURI()); $handle->setComplete(true); @@ -421,28 +420,16 @@ final class PhabricatorObjectHandleData { $handles[$phid] = $handle; } break; + case PhabricatorPHIDConstants::PHID_TYPE_PROJ: - $object = new PhabricatorProject(); - - if ($this->viewer) { - $projects = id(new PhabricatorProjectQuery()) - ->setViewer($this->viewer) - ->withPHIDs($phids) - ->execute(); - } else { - $projects = $object->loadAllWhere('phid IN (%Ls)', $phids); - } - - $projects = mpull($projects, null, 'getPHID'); - foreach ($phids as $phid) { $handle = new PhabricatorObjectHandle(); $handle->setPHID($phid); $handle->setType($type); - if (empty($projects[$phid])) { + if (empty($objects[$phid])) { $handle->setName('Unknown Project'); } else { - $project = $projects[$phid]; + $project = $objects[$phid]; $handle->setName($project->getName()); $handle->setURI('/project/view/'.$project->getID().'/'); $handle->setComplete(true); @@ -450,20 +437,16 @@ final class PhabricatorObjectHandleData { $handles[$phid] = $handle; } break; + case PhabricatorPHIDConstants::PHID_TYPE_REPO: - $object = new PhabricatorRepository(); - - $repositories = $object->loadAllWhere('phid in (%Ls)', $phids); - $repositories = mpull($repositories, null, 'getPHID'); - foreach ($phids as $phid) { $handle = new PhabricatorObjectHandle(); $handle->setPHID($phid); $handle->setType($type); - if (empty($repositories[$phid])) { + if (empty($objects[$phid])) { $handle->setName('Unknown Repository'); } else { - $repository = $repositories[$phid]; + $repository = $objects[$phid]; $handle->setName($repository->getCallsign()); $handle->setURI('/diffusion/'.$repository->getCallsign().'/'); $handle->setComplete(true); @@ -471,20 +454,16 @@ final class PhabricatorObjectHandleData { $handles[$phid] = $handle; } break; + case PhabricatorPHIDConstants::PHID_TYPE_OPKG: - $object = new PhabricatorOwnersPackage(); - - $packages = $object->loadAllWhere('phid in (%Ls)', $phids); - $packages = mpull($packages, null, 'getPHID'); - foreach ($phids as $phid) { $handle = new PhabricatorObjectHandle(); $handle->setPHID($phid); $handle->setType($type); - if (empty($packages[$phid])) { + if (empty($objects[$phid])) { $handle->setName('Unknown Package'); } else { - $package = $packages[$phid]; + $package = $objects[$phid]; $handle->setName($package->getName()); $handle->setURI('/owners/package/'.$package->getID().'/'); $handle->setComplete(true); @@ -492,27 +471,23 @@ final class PhabricatorObjectHandleData { $handles[$phid] = $handle; } break; - case PhabricatorPHIDConstants::PHID_TYPE_APRJ: - $project_dao = new PhabricatorRepositoryArcanistProject(); - $projects = $project_dao->loadAllWhere( - 'phid IN (%Ls)', - $phids); - $projects = mpull($projects, null, 'getPHID'); + case PhabricatorPHIDConstants::PHID_TYPE_APRJ: foreach ($phids as $phid) { $handle = new PhabricatorObjectHandle(); $handle->setPHID($phid); $handle->setType($type); - if (empty($projects[$phid])) { + if (empty($objects[$phid])) { $handle->setName('Unknown Arcanist Project'); } else { - $project = $projects[$phid]; + $project = $objects[$phid]; $handle->setName($project->getName()); $handle->setComplete(true); } $handles[$phid] = $handle; } break; + case PhabricatorPHIDConstants::PHID_TYPE_WIKI: $document_dao = new PhrictionDocument(); $content_dao = new PhrictionContent(); @@ -547,21 +522,16 @@ final class PhabricatorObjectHandleData { $handles[$phid] = $handle; } break; - case PhabricatorPHIDConstants::PHID_TYPE_QUES: - $questions = id(new PonderQuestionQuery()) - ->setViewer($this->viewer) - ->withPHIDs($phids) - ->execute(); - $questions = mpull($questions, null, 'getPHID'); + case PhabricatorPHIDConstants::PHID_TYPE_QUES: foreach ($phids as $phid) { $handle = new PhabricatorObjectHandle(); $handle->setPHID($phid); $handle->setType($type); - if (empty($questions[$phid])) { + if (empty($objects[$phid])) { $handle->setName('Unknown Ponder Question'); } else { - $question = $questions[$phid]; + $question = $objects[$phid]; $handle->setName(phutil_utf8_shorten($question->getTitle(), 60)); $handle->setURI(new PhutilURI('/Q' . $question->getID())); $handle->setComplete(true); @@ -569,21 +539,16 @@ final class PhabricatorObjectHandleData { $handles[$phid] = $handle; } break; - case PhabricatorPHIDConstants::PHID_TYPE_PSTE: - $pastes = id(new PhabricatorPasteQuery()) - ->withPHIDs($phids) - ->setViewer($this->viewer) - ->execute(); - $pastes = mpull($pastes, null, 'getPHID'); + case PhabricatorPHIDConstants::PHID_TYPE_PSTE: foreach ($phids as $phid) { $handle = new PhabricatorObjectHandle(); $handle->setPHID($phid); $handle->setType($type); - if (empty($pastes[$phid])) { + if (empty($objects[$phid])) { $handle->setName('Unknown Paste'); } else { - $paste = $pastes[$phid]; + $paste = $objects[$phid]; $handle->setName($paste->getTitle()); $handle->setFullName($paste->getFullName()); $handle->setURI('/P'.$paste->getID()); @@ -592,21 +557,16 @@ final class PhabricatorObjectHandleData { $handles[$phid] = $handle; } break; - case PhabricatorPHIDConstants::PHID_TYPE_BLOG: - $blogs = id(new PhameBlogQuery()) - ->withPHIDs($phids) - ->setViewer($this->viewer) - ->execute(); - $blogs = mpull($blogs, null, 'getPHID'); + case PhabricatorPHIDConstants::PHID_TYPE_BLOG: foreach ($phids as $phid) { $handle = new PhabricatorObjectHandle(); $handle->setPHID($phid); $handle->setType($type); - if (empty($blogs[$phid])) { + if (empty($objects[$phid])) { $handle->setName('Unknown Blog'); } else { - $blog = $blogs[$phid]; + $blog = $objects[$phid]; $handle->setName($blog->getName()); $handle->setFullName($blog->getName()); $handle->setURI('/phame/blog/view/'.$blog->getID().'/'); @@ -615,21 +575,16 @@ final class PhabricatorObjectHandleData { $handles[$phid] = $handle; } break; - case PhabricatorPHIDConstants::PHID_TYPE_POST: - $posts = id(new PhamePostQuery()) - ->withPHIDs($phids) - ->setViewer($this->viewer) - ->execute(); - $posts = mpull($posts, null, 'getPHID'); + case PhabricatorPHIDConstants::PHID_TYPE_POST: foreach ($phids as $phid) { $handle = new PhabricatorObjectHandle(); $handle->setPHID($phid); $handle->setType($type); - if (empty($posts[$phid])) { + if (empty($objects[$phid])) { $handle->setName('Unknown Post'); } else { - $post = $posts[$phid]; + $post = $objects[$phid]; $handle->setName($post->getTitle()); $handle->setFullName($post->getTitle()); $handle->setURI('/phame/post/view/'.$post->getID().'/'); @@ -638,21 +593,16 @@ final class PhabricatorObjectHandleData { $handles[$phid] = $handle; } break; - case PhabricatorPHIDConstants::PHID_TYPE_MOCK: - $mocks = id(new PholioMockQuery()) - ->withPHIDs($phids) - ->setViewer($this->viewer) - ->execute(); - $mocks = mpull($mocks, null, 'getPHID'); + case PhabricatorPHIDConstants::PHID_TYPE_MOCK: foreach ($phids as $phid) { $handle = new PhabricatorObjectHandle(); $handle->setPHID($phid); $handle->setType($type); - if (empty($mocks[$phid])) { + if (empty($objects[$phid])) { $handle->setName('Unknown Mock'); } else { - $mock = $mocks[$phid]; + $mock = $objects[$phid]; $handle->setName($mock->getName()); $handle->setFullName('M'.$mock->getID().': '.$mock->getName()); $handle->setURI('/M'.$mock->getID()); @@ -661,19 +611,16 @@ final class PhabricatorObjectHandleData { $handles[$phid] = $handle; } break; + case PhabricatorPHIDConstants::PHID_TYPE_MCRO: - $macros = id(new PhabricatorFileImageMacro())->loadAllWhere( - 'phid IN (%Ls)', - $phids); - $macros = mpull($macros, null, 'getPHID'); foreach ($phids as $phid) { $handle = new PhabricatorObjectHandle(); $handle->setPHID($phid); $handle->setType($type); - if (empty($macros[$phid])) { + if (empty($objects[$phid])) { $handle->setName('Unknown Macro'); } else { - $macro = $macros[$phid]; + $macro = $objects[$phid]; $handle->setName($macro->getName()); $handle->setFullName('Image Macro "'.$macro->getName().'"'); $handle->setURI('/macro/view/'.$macro->getID().'/'); @@ -682,6 +629,7 @@ final class PhabricatorObjectHandleData { $handles[$phid] = $handle; } break; + default: $loader = null; if (isset($external_loaders[$type])) { @@ -706,6 +654,7 @@ final class PhabricatorObjectHandleData { $handles[$phid] = $handle; } break; + } } diff --git a/src/applications/search/view/PhabricatorSearchResultView.php b/src/applications/search/view/PhabricatorSearchResultView.php index 555f602d40..b13ae41bc1 100644 --- a/src/applications/search/view/PhabricatorSearchResultView.php +++ b/src/applications/search/view/PhabricatorSearchResultView.php @@ -57,9 +57,10 @@ final class PhabricatorSearchResultView extends AphrontView { case PhabricatorPHIDConstants::PHID_TYPE_CMIT: $object_name = $handle->getName(); if ($this->object) { - $data = $this->object->getCommitData(); - $summary = $data->getSummary(); - if (strlen($summary)) { + $data = $this->object->loadOneRelative( + new PhabricatorRepositoryCommitData(), + 'commitID'); + if ($data && strlen($data->getSummary())) { $object_name = $handle->getName().': '.$data->getSummary(); } } From 15e284caa9534a12e2a1b11717937fd78427e183 Mon Sep 17 00:00:00 2001 From: Bryan Cuccioli Date: Mon, 28 Jan 2013 17:34:59 -0800 Subject: [PATCH 11/17] Add loading state to notification menu. Summary: Notification menu shows a loading message before the menu is populated with the actual response. Test Plan: Checked by having the function sleep between getting the response and populating the menu. Reviewers: epriestley Reviewed By: epriestley CC: aran, Korvin Differential Revision: https://secure.phabricator.com/D4696 --- .../page/menu/PhabricatorMainMenuView.php | 1 + .../application/base/notification-menu.css | 6 +++++ .../aphlict/behavior-aphlict-dropdown.js | 23 +++++++++++++++++-- 3 files changed, 28 insertions(+), 2 deletions(-) diff --git a/src/view/page/menu/PhabricatorMainMenuView.php b/src/view/page/menu/PhabricatorMainMenuView.php index 1283e7d897..73c8ff9789 100644 --- a/src/view/page/menu/PhabricatorMainMenuView.php +++ b/src/view/page/menu/PhabricatorMainMenuView.php @@ -390,6 +390,7 @@ final class PhabricatorMainMenuView extends AphrontView { 'bubbleID' => $bubble_id, 'countID' => $count_id, 'dropdownID' => $dropdown_id, + 'loadingText' => pht('Loading...'), )); $notification_dropdown = javelin_render_tag( diff --git a/webroot/rsrc/css/application/base/notification-menu.css b/webroot/rsrc/css/application/base/notification-menu.css index 3782456789..e3766ed4dd 100644 --- a/webroot/rsrc/css/application/base/notification-menu.css +++ b/webroot/rsrc/css/application/base/notification-menu.css @@ -9,6 +9,12 @@ overflow-y: auto; } +.phabricator-notification-menu-loading { + text-align: center; + padding: 10px 0; + color: #888888; +} + .device-desktop .phabricator-notification-menu { position: fixed; width: 360px; diff --git a/webroot/rsrc/js/application/aphlict/behavior-aphlict-dropdown.js b/webroot/rsrc/js/application/aphlict/behavior-aphlict-dropdown.js index f75fc3b53c..5fd59a0f5f 100644 --- a/webroot/rsrc/js/application/aphlict/behavior-aphlict-dropdown.js +++ b/webroot/rsrc/js/application/aphlict/behavior-aphlict-dropdown.js @@ -14,8 +14,17 @@ JX.behavior('aphlict-dropdown', function(config) { var bubble = JX.$(config.bubbleID); var visible = false; var request = null; + var dirty = true; function refresh() { + if (dirty) { + JX.DOM.setContent(dropdown, config.loadingText); + JX.DOM.alterClass( + dropdown, + 'phabricator-notification-menu-loading', + true); + } + if (request) { //already fetching return; } @@ -30,6 +39,11 @@ JX.behavior('aphlict-dropdown', function(config) { } else { JX.DOM.alterClass(bubble, 'alert-unread', true); } + dirty = false; + JX.DOM.alterClass( + dropdown, + 'phabricator-notification-menu-loading', + false); JX.DOM.setContent(dropdown, JX.$H(response.content)); request = null; }); @@ -74,7 +88,9 @@ JX.behavior('aphlict-dropdown', function(config) { if (visible) { JX.DOM.hide(dropdown); } else { - refresh(); + if (dirty) { + refresh(); + } var p = JX.$V(bubble); p.y = null; @@ -88,5 +104,8 @@ JX.behavior('aphlict-dropdown', function(config) { } ) - JX.Stratcom.listen('notification-panel-update', null, refresh); + JX.Stratcom.listen('notification-panel-update', null, function() { + dirty = true; + refresh(); + }); }); From 1fc0c3b1e8493ad30358554a8249ccb34e007228 Mon Sep 17 00:00:00 2001 From: Bryan Cuccioli Date: Mon, 28 Jan 2013 17:45:56 -0800 Subject: [PATCH 12/17] Add installation check for dot in domain. Summary: Add installation check for a dot in the domain, which is necessary for some browsers to set cookies. Test Plan: Restart web server to force the setup procedures to run again. Reviewers: epriestley Reviewed By: epriestley CC: aran, Korvin Differential Revision: https://secure.phabricator.com/D4710 --- .../check/PhabricatorSetupCheckBaseURI.php | 20 +++++++++++++++++++ .../configuration/configuration_guide.diviner | 3 +++ 2 files changed, 23 insertions(+) diff --git a/src/applications/config/check/PhabricatorSetupCheckBaseURI.php b/src/applications/config/check/PhabricatorSetupCheckBaseURI.php index 34bcfb9599..1a5671a737 100644 --- a/src/applications/config/check/PhabricatorSetupCheckBaseURI.php +++ b/src/applications/config/check/PhabricatorSetupCheckBaseURI.php @@ -4,6 +4,26 @@ final class PhabricatorSetupCheckBaseURI extends PhabricatorSetupCheck { protected function executeChecks() { $base_uri = PhabricatorEnv::getEnvConfig('phabricator.base-uri'); + + if (strpos($_SERVER['HTTP_HOST'], '.') === false) { + $summary = pht( + 'The domain does not contain a dot. This is necessary for some web '. + 'browsers to be able to set cookies.'); + + $message = pht( + 'The domain in the base URI must contain a dot ("."), e.g. '. + '"http://example.com", not just a bare name like "http://example/". '. + 'Some web browsers will not set cookies on domains with no TLD.'); + + $this + ->newIssue('config.phabricator.domain') + ->setShortName(pht('Dotless Domain')) + ->setName(pht('No Dot Character in Domain')) + ->setSummary($summary) + ->setMessage($message) + ->setIsFatal(true); + } + if ($base_uri) { return; } diff --git a/src/docs/configuration/configuration_guide.diviner b/src/docs/configuration/configuration_guide.diviner index e8a2e5765b..b5e2c5c69d 100644 --- a/src/docs/configuration/configuration_guide.diviner +++ b/src/docs/configuration/configuration_guide.diviner @@ -30,6 +30,9 @@ some subdirectory of an existing website. Navigate to whatever domain you're going to use and make sure Apache serves you something to verify that DNS is correctly configured. +NOTE: The domain must contain a dot ('.'), i.e. not be just a bare name like +'http://example/'. Some web browsers will not set cookies otherwise. + Now, either create a VirtualHost entry (to put Phabricator on a subdomain) or edit the Directory entry for the DocumentRoot. It should look something like this: From 2bb61132a68af2c073322baa6fb073dec8b8ba85 Mon Sep 17 00:00:00 2001 From: epriestley Date: Mon, 28 Jan 2013 17:49:09 -0800 Subject: [PATCH 13/17] Minor, update Celerity map. --- src/__celerity_resource_map__.php | 177 +++++++++++++++++------------- 1 file changed, 100 insertions(+), 77 deletions(-) diff --git a/src/__celerity_resource_map__.php b/src/__celerity_resource_map__.php index dbf8c28a02..d2bd94d2c7 100644 --- a/src/__celerity_resource_map__.php +++ b/src/__celerity_resource_map__.php @@ -476,6 +476,20 @@ celerity_register_resource_map(array( 'disk' => '/rsrc/image/sprite-apps.png', 'type' => 'png', ), + '/rsrc/image/sprite-conph-X2.png' => + array( + 'hash' => 'c80e0b09360be71addfeaee622ac4bf0', + 'uri' => '/res/c80e0b09/rsrc/image/sprite-conph-X2.png', + 'disk' => '/rsrc/image/sprite-conph-X2.png', + 'type' => 'png', + ), + '/rsrc/image/sprite-conph.png' => + array( + 'hash' => '0b1d46b6c7369e09dc4b9e26010b74d6', + 'uri' => '/res/0b1d46b6/rsrc/image/sprite-conph.png', + 'disk' => '/rsrc/image/sprite-conph.png', + 'type' => 'png', + ), '/rsrc/image/sprite-gradient.png' => array( 'hash' => '92aebaab67dcc6baf2ea99294368d895', @@ -987,7 +1001,7 @@ celerity_register_resource_map(array( ), 'javelin-behavior-aphlict-dropdown' => array( - 'uri' => '/res/f09bc90d/rsrc/js/application/aphlict/behavior-aphlict-dropdown.js', + 'uri' => '/res/2418f448/rsrc/js/application/aphlict/behavior-aphlict-dropdown.js', 'type' => 'js', 'requires' => array( @@ -2776,7 +2790,7 @@ celerity_register_resource_map(array( ), 'phabricator-notification-menu-css' => array( - 'uri' => '/res/d0d0264c/rsrc/css/application/base/notification-menu.css', + 'uri' => '/res/b7cc25af/rsrc/css/application/base/notification-menu.css', 'type' => 'css', 'requires' => array( @@ -3300,6 +3314,15 @@ celerity_register_resource_map(array( ), 'disk' => '/rsrc/css/sprite-apps-xlarge.css', ), + 'sprite-conpher-css' => + array( + 'uri' => '/res/14e5d74c/rsrc/css/sprite-conph.css', + 'type' => 'css', + 'requires' => + array( + ), + 'disk' => '/rsrc/css/sprite-conph.css', + ), 'sprite-gradient-css' => array( 'uri' => '/res/e62e7a0f/rsrc/css/sprite-gradient.css', @@ -3357,7 +3380,7 @@ celerity_register_resource_map(array( ), array( 'packages' => array( - 'd24a3d26' => + 'feecd595' => array( 'name' => 'core.pkg.css', 'symbols' => @@ -3401,10 +3424,10 @@ celerity_register_resource_map(array( 36 => 'phabricator-object-item-list-view-css', 37 => 'global-drag-and-drop-css', ), - 'uri' => '/res/pkg/d24a3d26/core.pkg.css', + 'uri' => '/res/pkg/feecd595/core.pkg.css', 'type' => 'css', ), - '4bf2be0a' => + '8a3f0fbd' => array( 'name' => 'core.pkg.js', 'symbols' => @@ -3443,7 +3466,7 @@ celerity_register_resource_map(array( 31 => 'javelin-behavior-global-drag-and-drop', 32 => 'javelin-behavior-phabricator-home-reveal-tiles', ), - 'uri' => '/res/pkg/4bf2be0a/core.pkg.js', + 'uri' => '/res/pkg/8a3f0fbd/core.pkg.js', 'type' => 'js', ), '8edbada5' => @@ -3591,19 +3614,19 @@ celerity_register_resource_map(array( 'reverse' => array( 'aphront-attached-file-view-css' => 'e30a3fa8', - 'aphront-crumbs-view-css' => 'd24a3d26', - 'aphront-dialog-view-css' => 'd24a3d26', - 'aphront-error-view-css' => 'd24a3d26', - 'aphront-form-view-css' => 'd24a3d26', + 'aphront-crumbs-view-css' => 'feecd595', + 'aphront-dialog-view-css' => 'feecd595', + 'aphront-error-view-css' => 'feecd595', + 'aphront-form-view-css' => 'feecd595', 'aphront-headsup-action-list-view-css' => 'ec01d039', - 'aphront-headsup-view-css' => 'd24a3d26', - 'aphront-list-filter-view-css' => 'd24a3d26', - 'aphront-pager-view-css' => 'd24a3d26', - 'aphront-panel-view-css' => 'd24a3d26', - 'aphront-table-view-css' => 'd24a3d26', - 'aphront-tokenizer-control-css' => 'd24a3d26', - 'aphront-tooltip-css' => 'd24a3d26', - 'aphront-typeahead-control-css' => 'd24a3d26', + 'aphront-headsup-view-css' => 'feecd595', + 'aphront-list-filter-view-css' => 'feecd595', + 'aphront-pager-view-css' => 'feecd595', + 'aphront-panel-view-css' => 'feecd595', + 'aphront-table-view-css' => 'feecd595', + 'aphront-tokenizer-control-css' => 'feecd595', + 'aphront-tooltip-css' => 'feecd595', + 'aphront-typeahead-control-css' => 'feecd595', 'differential-changeset-view-css' => 'ec01d039', 'differential-core-view-css' => 'ec01d039', 'differential-inline-comment-editor' => '9dae5f20', @@ -3617,20 +3640,20 @@ celerity_register_resource_map(array( 'differential-table-of-contents-css' => 'ec01d039', 'diffusion-commit-view-css' => 'c8ce2d88', 'diffusion-icons-css' => 'c8ce2d88', - 'global-drag-and-drop-css' => 'd24a3d26', + 'global-drag-and-drop-css' => 'feecd595', 'inline-comment-summary-css' => 'ec01d039', - 'javelin-aphlict' => '4bf2be0a', + 'javelin-aphlict' => '8a3f0fbd', 'javelin-behavior' => 'fbeded59', - 'javelin-behavior-aphlict-dropdown' => '4bf2be0a', - 'javelin-behavior-aphlict-listen' => '4bf2be0a', - 'javelin-behavior-aphront-basic-tokenizer' => '4bf2be0a', + 'javelin-behavior-aphlict-dropdown' => '8a3f0fbd', + 'javelin-behavior-aphlict-listen' => '8a3f0fbd', + 'javelin-behavior-aphront-basic-tokenizer' => '8a3f0fbd', 'javelin-behavior-aphront-drag-and-drop' => '9dae5f20', 'javelin-behavior-aphront-drag-and-drop-textarea' => '9dae5f20', - 'javelin-behavior-aphront-form-disable-on-submit' => '4bf2be0a', + 'javelin-behavior-aphront-form-disable-on-submit' => '8a3f0fbd', 'javelin-behavior-audit-preview' => 'f96657b8', 'javelin-behavior-dark-console' => '8edbada5', 'javelin-behavior-dark-console-ajax' => '8edbada5', - 'javelin-behavior-device' => '4bf2be0a', + 'javelin-behavior-device' => '8a3f0fbd', 'javelin-behavior-differential-accept-with-errors' => '9dae5f20', 'javelin-behavior-differential-add-reviewers-and-ccs' => '9dae5f20', 'javelin-behavior-differential-comment-jump' => '9dae5f20', @@ -3646,29 +3669,29 @@ celerity_register_resource_map(array( 'javelin-behavior-diffusion-commit-graph' => 'f96657b8', 'javelin-behavior-diffusion-pull-lastmodified' => 'f96657b8', 'javelin-behavior-error-log' => '8edbada5', - 'javelin-behavior-global-drag-and-drop' => '4bf2be0a', - 'javelin-behavior-konami' => '4bf2be0a', - 'javelin-behavior-lightbox-attachments' => '4bf2be0a', + 'javelin-behavior-global-drag-and-drop' => '8a3f0fbd', + 'javelin-behavior-konami' => '8a3f0fbd', + 'javelin-behavior-lightbox-attachments' => '8a3f0fbd', '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' => '4bf2be0a', - 'javelin-behavior-phabricator-autofocus' => '4bf2be0a', - 'javelin-behavior-phabricator-home-reveal-tiles' => '4bf2be0a', - 'javelin-behavior-phabricator-keyboard-shortcuts' => '4bf2be0a', - 'javelin-behavior-phabricator-nav' => '4bf2be0a', + 'javelin-behavior-phabricator-active-nav' => '8a3f0fbd', + 'javelin-behavior-phabricator-autofocus' => '8a3f0fbd', + 'javelin-behavior-phabricator-home-reveal-tiles' => '8a3f0fbd', + 'javelin-behavior-phabricator-keyboard-shortcuts' => '8a3f0fbd', + 'javelin-behavior-phabricator-nav' => '8a3f0fbd', 'javelin-behavior-phabricator-object-selector' => '9dae5f20', - 'javelin-behavior-phabricator-oncopy' => '4bf2be0a', - 'javelin-behavior-phabricator-remarkup-assist' => '4bf2be0a', - 'javelin-behavior-phabricator-search-typeahead' => '4bf2be0a', - 'javelin-behavior-phabricator-tooltips' => '4bf2be0a', - 'javelin-behavior-phabricator-watch-anchor' => '4bf2be0a', - 'javelin-behavior-refresh-csrf' => '4bf2be0a', + 'javelin-behavior-phabricator-oncopy' => '8a3f0fbd', + 'javelin-behavior-phabricator-remarkup-assist' => '8a3f0fbd', + 'javelin-behavior-phabricator-search-typeahead' => '8a3f0fbd', + 'javelin-behavior-phabricator-tooltips' => '8a3f0fbd', + 'javelin-behavior-phabricator-watch-anchor' => '8a3f0fbd', + 'javelin-behavior-refresh-csrf' => '8a3f0fbd', 'javelin-behavior-repository-crossreference' => '9dae5f20', - 'javelin-behavior-toggle-class' => '4bf2be0a', - 'javelin-behavior-workflow' => '4bf2be0a', + 'javelin-behavior-toggle-class' => '8a3f0fbd', + 'javelin-behavior-workflow' => '8a3f0fbd', 'javelin-dom' => 'fbeded59', 'javelin-event' => 'fbeded59', 'javelin-install' => 'fbeded59', @@ -3687,48 +3710,48 @@ celerity_register_resource_map(array( 'javelin-util' => 'fbeded59', 'javelin-vector' => 'fbeded59', 'javelin-workflow' => 'fbeded59', - 'lightbox-attachment-css' => 'd24a3d26', + 'lightbox-attachment-css' => 'feecd595', 'maniphest-task-summary-css' => 'e30a3fa8', 'maniphest-transaction-detail-css' => 'e30a3fa8', - 'phabricator-busy' => '4bf2be0a', + 'phabricator-busy' => '8a3f0fbd', 'phabricator-content-source-view-css' => 'ec01d039', - 'phabricator-core-buttons-css' => 'd24a3d26', - 'phabricator-core-css' => 'd24a3d26', - 'phabricator-crumbs-view-css' => 'd24a3d26', - 'phabricator-directory-css' => 'd24a3d26', + 'phabricator-core-buttons-css' => 'feecd595', + 'phabricator-core-css' => 'feecd595', + 'phabricator-crumbs-view-css' => 'feecd595', + 'phabricator-directory-css' => 'feecd595', 'phabricator-drag-and-drop-file-upload' => '9dae5f20', - 'phabricator-dropdown-menu' => '4bf2be0a', - 'phabricator-file-upload' => '4bf2be0a', - 'phabricator-filetree-view-css' => 'd24a3d26', - 'phabricator-flag-css' => 'd24a3d26', - 'phabricator-form-view-css' => 'd24a3d26', - 'phabricator-header-view-css' => 'd24a3d26', - 'phabricator-jump-nav' => 'd24a3d26', - 'phabricator-keyboard-shortcut' => '4bf2be0a', - 'phabricator-keyboard-shortcut-manager' => '4bf2be0a', - 'phabricator-main-menu-view' => 'd24a3d26', - 'phabricator-menu-item' => '4bf2be0a', - 'phabricator-nav-view-css' => 'd24a3d26', - 'phabricator-notification' => '4bf2be0a', - 'phabricator-notification-css' => 'd24a3d26', - 'phabricator-notification-menu-css' => 'd24a3d26', - 'phabricator-object-item-list-view-css' => 'd24a3d26', + 'phabricator-dropdown-menu' => '8a3f0fbd', + 'phabricator-file-upload' => '8a3f0fbd', + 'phabricator-filetree-view-css' => 'feecd595', + 'phabricator-flag-css' => 'feecd595', + 'phabricator-form-view-css' => 'feecd595', + 'phabricator-header-view-css' => 'feecd595', + 'phabricator-jump-nav' => 'feecd595', + 'phabricator-keyboard-shortcut' => '8a3f0fbd', + 'phabricator-keyboard-shortcut-manager' => '8a3f0fbd', + 'phabricator-main-menu-view' => 'feecd595', + 'phabricator-menu-item' => '8a3f0fbd', + 'phabricator-nav-view-css' => 'feecd595', + 'phabricator-notification' => '8a3f0fbd', + 'phabricator-notification-css' => 'feecd595', + 'phabricator-notification-menu-css' => 'feecd595', + 'phabricator-object-item-list-view-css' => 'feecd595', 'phabricator-object-selector-css' => 'ec01d039', - 'phabricator-paste-file-upload' => '4bf2be0a', - 'phabricator-prefab' => '4bf2be0a', + 'phabricator-paste-file-upload' => '8a3f0fbd', + 'phabricator-prefab' => '8a3f0fbd', 'phabricator-project-tag-css' => 'e30a3fa8', - 'phabricator-remarkup-css' => 'd24a3d26', + 'phabricator-remarkup-css' => 'feecd595', 'phabricator-shaped-request' => '9dae5f20', - 'phabricator-side-menu-view-css' => 'd24a3d26', - 'phabricator-standard-page-view' => 'd24a3d26', - 'phabricator-textareautils' => '4bf2be0a', - 'phabricator-tooltip' => '4bf2be0a', - 'phabricator-transaction-view-css' => 'd24a3d26', - 'phabricator-zindex-css' => 'd24a3d26', - 'sprite-apps-large-css' => 'd24a3d26', - 'sprite-gradient-css' => 'd24a3d26', - 'sprite-icon-css' => 'd24a3d26', - 'sprite-menu-css' => 'd24a3d26', - 'syntax-highlighting-css' => 'd24a3d26', + 'phabricator-side-menu-view-css' => 'feecd595', + 'phabricator-standard-page-view' => 'feecd595', + 'phabricator-textareautils' => '8a3f0fbd', + 'phabricator-tooltip' => '8a3f0fbd', + 'phabricator-transaction-view-css' => 'feecd595', + 'phabricator-zindex-css' => 'feecd595', + 'sprite-apps-large-css' => 'feecd595', + 'sprite-gradient-css' => 'feecd595', + 'sprite-icon-css' => 'feecd595', + 'sprite-menu-css' => 'feecd595', + 'syntax-highlighting-css' => 'feecd595', ), )); From 683df86d54e05026712d07052f3b0b3673426362 Mon Sep 17 00:00:00 2001 From: Lauri-Henrik Jalonen Date: Tue, 29 Jan 2013 04:19:33 -0800 Subject: [PATCH 14/17] Pointer to show on pholio thumbnails Summary: Pointer to show on pholio thumbnails Test Plan: Pointer is shown Reviewers: epriestley Reviewed By: epriestley CC: aran, Korvin Differential Revision: https://secure.phabricator.com/D4720 --- src/__celerity_resource_map__.php | 2 +- webroot/rsrc/css/application/pholio/pholio.css | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/__celerity_resource_map__.php b/src/__celerity_resource_map__.php index d2bd94d2c7..7ff5dbf85f 100644 --- a/src/__celerity_resource_map__.php +++ b/src/__celerity_resource_map__.php @@ -3190,7 +3190,7 @@ celerity_register_resource_map(array( ), 'pholio-css' => array( - 'uri' => '/res/8d8d99c1/rsrc/css/application/pholio/pholio.css', + 'uri' => '/res/f101ad7c/rsrc/css/application/pholio/pholio.css', 'type' => 'css', 'requires' => array( diff --git a/webroot/rsrc/css/application/pholio/pholio.css b/webroot/rsrc/css/application/pholio/pholio.css index 686603a082..5cf10e93dc 100644 --- a/webroot/rsrc/css/application/pholio/pholio.css +++ b/webroot/rsrc/css/application/pholio/pholio.css @@ -14,6 +14,7 @@ .pholio-mock-carousel-thumbnail { margin-right: 5px; display: inline-block; + cursor: pointer; } .pholio-mock-image { From 5017c80b31036039bb4c8ffd286f2fd2f5110c36 Mon Sep 17 00:00:00 2001 From: Afaque Hussain Date: Tue, 29 Jan 2013 09:14:03 -0800 Subject: [PATCH 15/17] Installation & Uninstallion of Applications Summary: Created Applications application which allows uninstallation & installation of application. Test Plan: In "Applications" application, clicked on uninstalled the application by cliking Uninstall and chekcing whether they are really uninstalled(Disabling URI & in appearance in the side pane). Then Clicked on the install button of the uninstalled application to check whether they are installed. Reviewers: epriestley CC: aran, Korvin Differential Revision: https://secure.phabricator.com/D4715 --- conf/default.conf.php | 3 + src/__phutil_library_map__.php | 2 + .../PhabricatorApplicationAuth.php | 4 + .../base/PhabricatorApplication.php | 63 +++++++++++-- .../PhabricatorApplicationConfig.php | 4 + .../option/PhabricatorCoreConfigOptions.php | 5 + .../PhabricatorApplicationDaemons.php | 4 + .../PhabricatorApplicationFeed.php | 4 + .../PhabricatorApplicationFiles.php | 4 + .../PhabricatorApplicationApplications.php | 7 +- ...ricatorApplicationDetailViewController.php | 76 +++++++++------ ...bricatorApplicationUninstallController.php | 93 +++++++++++++++++++ .../PhabricatorApplicationsListController.php | 2 +- .../PhabricatorApplicationMetaMTA.php | 4 + .../PhabricatorApplicationPeople.php | 4 + .../PhabricatorApplicationSettings.php | 4 + .../PhabricatorApplicationSubscriptions.php | 4 + .../PhabricatorApplicationTransactions.php | 4 + 18 files changed, 253 insertions(+), 38 deletions(-) create mode 100644 src/applications/meta/controller/PhabricatorApplicationUninstallController.php diff --git a/conf/default.conf.php b/conf/default.conf.php index 1217dc6238..6cc166c323 100644 --- a/conf/default.conf.php +++ b/conf/default.conf.php @@ -839,6 +839,9 @@ return array( // Should Phabricator show beta applications on the homepage 'phabricator.show-beta-applications' => false, + // Contains a list of uninstalled applications + 'phabricator.uninstalled-applications' => array(), + // -- Files ----------------------------------------------------------------- // // Lists which uploaded file types may be viewed in the browser. If a file diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index 5090f256e3..c900d24f47 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -673,6 +673,7 @@ phutil_register_library_map(array( 'PhabricatorApplicationTransactionView' => 'applications/transactions/view/PhabricatorApplicationTransactionView.php', 'PhabricatorApplicationTransactions' => 'applications/transactions/application/PhabricatorApplicationTransactions.php', 'PhabricatorApplicationUIExamples' => 'applications/uiexample/application/PhabricatorApplicationUIExamples.php', + 'PhabricatorApplicationUninstallController' => 'applications/meta/controller/PhabricatorApplicationUninstallController.php', 'PhabricatorApplicationsController' => 'applications/meta/controller/PhabricatorApplicationsController.php', 'PhabricatorApplicationsListController' => 'applications/meta/controller/PhabricatorApplicationsListController.php', 'PhabricatorAuditActionConstants' => 'applications/audit/constants/PhabricatorAuditActionConstants.php', @@ -2103,6 +2104,7 @@ phutil_register_library_map(array( 'PhabricatorApplicationTransactionView' => 'AphrontView', 'PhabricatorApplicationTransactions' => 'PhabricatorApplication', 'PhabricatorApplicationUIExamples' => 'PhabricatorApplication', + 'PhabricatorApplicationUninstallController' => 'PhabricatorApplicationsController', 'PhabricatorApplicationsController' => 'PhabricatorController', 'PhabricatorApplicationsListController' => 'PhabricatorApplicationsController', 'PhabricatorAuditAddCommentController' => 'PhabricatorAuditController', diff --git a/src/applications/auth/application/PhabricatorApplicationAuth.php b/src/applications/auth/application/PhabricatorApplicationAuth.php index 18819a9410..acd98344ea 100644 --- a/src/applications/auth/application/PhabricatorApplicationAuth.php +++ b/src/applications/auth/application/PhabricatorApplicationAuth.php @@ -6,6 +6,10 @@ final class PhabricatorApplicationAuth extends PhabricatorApplication { return false; } + public function canUninstall() { + return false; + } + public function buildMainMenuItems( PhabricatorUser $user, PhabricatorController $controller = null) { diff --git a/src/applications/base/PhabricatorApplication.php b/src/applications/base/PhabricatorApplication.php index 9642a57fba..6bed54389a 100644 --- a/src/applications/base/PhabricatorApplication.php +++ b/src/applications/base/PhabricatorApplication.php @@ -62,10 +62,25 @@ abstract class PhabricatorApplication { return true; } + public function isInstalled() { + $uninstalled = + PhabricatorEnv::getEnvConfig('phabricator.uninstalled-applications'); + + if (isset($uninstalled[get_class($this)])) { + return false; + } else { + return true; + } + } + public function isBeta() { return false; } + public function canUninstall() { + return true; + } + public function getPHID() { return 'PHID-APPS-'.get_class($this); } @@ -212,6 +227,22 @@ abstract class PhabricatorApplication { /* -( Application Management )--------------------------------------------- */ + public static function getAllApplications() { + + $classes = id(new PhutilSymbolLoader()) + ->setAncestorClass(__CLASS__) + ->setConcreteOnly(true) + ->selectAndLoadSymbols(); + + $apps = array(); + + foreach ($classes as $class) { + $app = newv($class['name'], array()); + $apps[] = $app; + } + + return $apps; + } public static function getAllInstalledApplications() { static $applications; @@ -219,6 +250,11 @@ abstract class PhabricatorApplication { $show_beta = PhabricatorEnv::getEnvConfig('phabricator.show-beta-applications'); + $uninstalled = + PhabricatorEnv::getEnvConfig('phabricator.uninstalled-applications'); + + + if (empty($applications)) { $classes = id(new PhutilSymbolLoader()) ->setAncestorClass(__CLASS__) @@ -227,22 +263,29 @@ abstract class PhabricatorApplication { $apps = array(); foreach ($classes as $class) { - $app = newv($class['name'], array()); - if (!$app->isEnabled()) { - continue; - } - if (!$show_beta && $app->isBeta()) { - continue; - } - - $apps[] = $app; + if (isset($uninstalled[$class['name']])) { + continue; } + + $app = newv($class['name'], array()); + + if (!$app->isEnabled()) { + continue; + } + + if (!$show_beta && $app->isBeta()) { + continue; + } + + $apps[] = $app; + } + $applications = $apps; } return $applications; } - } + diff --git a/src/applications/config/application/PhabricatorApplicationConfig.php b/src/applications/config/application/PhabricatorApplicationConfig.php index 70c542c217..5c78cef272 100644 --- a/src/applications/config/application/PhabricatorApplicationConfig.php +++ b/src/applications/config/application/PhabricatorApplicationConfig.php @@ -18,6 +18,10 @@ final class PhabricatorApplicationConfig extends PhabricatorApplication { return self::GROUP_ADMIN; } + public function canUninstall() { + return false; + } + public function getRoutes() { return array( '/config/' => array( diff --git a/src/applications/config/option/PhabricatorCoreConfigOptions.php b/src/applications/config/option/PhabricatorCoreConfigOptions.php index c1dddac3d1..6dadb5c816 100644 --- a/src/applications/config/option/PhabricatorCoreConfigOptions.php +++ b/src/applications/config/option/PhabricatorCoreConfigOptions.php @@ -128,6 +128,11 @@ final class PhabricatorCoreConfigOptions $this->newOption('test.value', 'wild', null) ->setLocked(true) ->setDescription(pht('Unit test value.')), + $this->newOption('phabricator.uninstalled-applications', 'set', array()) + ->setLocked(true) + ->setDescription( + pht('Array containing list of Uninstalled applications.') + ), ); } diff --git a/src/applications/daemon/application/PhabricatorApplicationDaemons.php b/src/applications/daemon/application/PhabricatorApplicationDaemons.php index 4d02d15680..344a80ebcd 100644 --- a/src/applications/daemon/application/PhabricatorApplicationDaemons.php +++ b/src/applications/daemon/application/PhabricatorApplicationDaemons.php @@ -26,6 +26,10 @@ final class PhabricatorApplicationDaemons extends PhabricatorApplication { return self::GROUP_ADMIN; } + public function canUninstall() { + return false; + } + public function getRoutes() { return array( '/daemon/' => array( diff --git a/src/applications/feed/application/PhabricatorApplicationFeed.php b/src/applications/feed/application/PhabricatorApplicationFeed.php index 2c089ac344..d1c0e0cf3e 100644 --- a/src/applications/feed/application/PhabricatorApplicationFeed.php +++ b/src/applications/feed/application/PhabricatorApplicationFeed.php @@ -14,6 +14,10 @@ final class PhabricatorApplicationFeed extends PhabricatorApplication { return 'feed'; } + public function canUninstall() { + return false; + } + public function getRoutes() { return array( '/feed/' => array( diff --git a/src/applications/files/application/PhabricatorApplicationFiles.php b/src/applications/files/application/PhabricatorApplicationFiles.php index 9c8491a4ca..2d79ac1003 100644 --- a/src/applications/files/application/PhabricatorApplicationFiles.php +++ b/src/applications/files/application/PhabricatorApplicationFiles.php @@ -30,6 +30,10 @@ final class PhabricatorApplicationFiles extends PhabricatorApplication { return $this->getBaseURI().'upload/'; } + public function canUninstall() { + return false; + } + public function getRoutes() { return array( '/F(?P[1-9]\d*)' => 'PhabricatorFileShortcutController', diff --git a/src/applications/meta/application/PhabricatorApplicationApplications.php b/src/applications/meta/application/PhabricatorApplicationApplications.php index 6139945b6f..58a50e4cbe 100644 --- a/src/applications/meta/application/PhabricatorApplicationApplications.php +++ b/src/applications/meta/application/PhabricatorApplicationApplications.php @@ -2,6 +2,10 @@ final class PhabricatorApplicationApplications extends PhabricatorApplication { + public function canUninstall() { + return false; + } + public function getBaseURI() { return '/applications/'; } @@ -28,7 +32,8 @@ final class PhabricatorApplicationApplications extends PhabricatorApplication { '' => 'PhabricatorApplicationsListController', 'view/(?P\w+)/' => 'PhabricatorApplicationDetailViewController', - + '(?P\w+)/(?Pinstall|uninstall)/' => + 'PhabricatorApplicationUninstallController', ), ); diff --git a/src/applications/meta/controller/PhabricatorApplicationDetailViewController.php b/src/applications/meta/controller/PhabricatorApplicationDetailViewController.php index db9cd66199..460dd6b0f1 100644 --- a/src/applications/meta/controller/PhabricatorApplicationDetailViewController.php +++ b/src/applications/meta/controller/PhabricatorApplicationDetailViewController.php @@ -14,12 +14,12 @@ final class PhabricatorApplicationDetailViewController $user = $request->getUser(); $selected = null; - $applications = PhabricatorApplication::getAllInstalledApplications(); + $applications = PhabricatorApplication::getAllApplications(); foreach ($applications as $application) { if (get_class($application) == $this->application) { - $selected = $application; - break; + $selected = $application; + break; } } @@ -35,27 +35,33 @@ final class PhabricatorApplicationDetailViewController ->setName(pht('Applications')) ->setHref($this->getApplicationURI())); - $properties = $this->buildPropertyView($selected); - $actions = $this->buildActionView($user); + $properties = $this->buildPropertyView($selected); + $actions = $this->buildActionView($user, $selected); - return $this->buildApplicationPage( - array( - $crumbs, - id(new PhabricatorHeaderView())->setHeader($title), - $actions, - $properties, - ), - array( - 'title' => $title, - 'device' => true, - )); + return $this->buildApplicationPage( + array( + $crumbs, + id(new PhabricatorHeaderView())->setHeader($title), + $actions, + $properties, + ), + array( + 'title' => $title, + 'device' => true, + )); } private function buildPropertyView(PhabricatorApplication $selected) { $properties = new PhabricatorPropertyListView(); - $properties->addProperty( - pht('Status'), pht('Installed')); + if ($selected->isInstalled()) { + $properties->addProperty( + pht('Status'), pht('Installed')); + + } else { + $properties->addProperty( + pht('Status'), pht('Uninstalled')); + } $properties->addProperty( pht('Description'), $selected->getShortDescription()); @@ -63,15 +69,33 @@ final class PhabricatorApplicationDetailViewController return $properties; } - private function buildActionView(PhabricatorUser $user) { + private function buildActionView( + PhabricatorUser $user, PhabricatorApplication $selected) { - return id(new PhabricatorActionListView()) - ->setUser($user) - ->addAction( - id(new PhabricatorActionView()) - ->setName(pht('Uninstall')) - ->setIcon('delete') - ); + if ($selected->canUninstall()) { + if ($selected->isInstalled()) { + + return id(new PhabricatorActionListView()) + ->setUser($user) + ->addAction( + id(new PhabricatorActionView()) + ->setName(pht('Uninstall')) + ->setIcon('delete') + ->setHref( + $this->getApplicationURI(get_class($selected).'/uninstall/')) + ); + } else { + return id(new PhabricatorActionListView()) + ->setUser($user) + ->addAction( + id(new PhabricatorActionView()) + ->setName(pht('Install')) + ->setIcon('new') + ->setHref( + $this->getApplicationURI(get_class($selected).'/install/')) + ); + } + } } } diff --git a/src/applications/meta/controller/PhabricatorApplicationUninstallController.php b/src/applications/meta/controller/PhabricatorApplicationUninstallController.php new file mode 100644 index 0000000000..7ba660d3cf --- /dev/null +++ b/src/applications/meta/controller/PhabricatorApplicationUninstallController.php @@ -0,0 +1,93 @@ +application = $data['application']; + $this->action = $data['action']; + } + + public function processRequest() { + $request = $this->getRequest(); + $user = $request->getUser(); + $app_name = substr($this->application, strlen('PhabricatorApplication')); + + if ($request->isDialogFormPost()) { + $this->manageApplication(); + return id(new AphrontRedirectResponse())->setURI('/applications/'); + } + + if ($this->action == 'install') { + + $dialog = id(new AphrontDialogView()) + ->setUser($user) + ->setTitle('Confirmation') + ->appendChild('Install '. $app_name. ' application ?') + ->addSubmitButton('Install') + ->addCancelButton('/applications/view/'.$this->application); + } else { + $dialog = id(new AphrontDialogView()) + ->setUser($user) + ->setTitle('Confirmation') + ->appendChild('Really Uninstall '. $app_name. ' application ?') + ->addSubmitButton('Uninstall') + ->addCancelButton('/applications/view/'.$this->application); + } + + return id(new AphrontDialogResponse())->setDialog($dialog); + } + + public function manageApplication() { + $key = 'phabricator.uninstalled-applications'; + + $config_entry = id(new PhabricatorConfigEntry()) + ->loadOneWhere( + 'configKey = %s AND namespace = %s', + $key, + 'default'); + + if (!$config_entry) { + $config_entry = id(new PhabricatorConfigEntry()) + ->setConfigKey($key) + ->setNamespace('default'); + } + + $list = $config_entry->getValue(); + + $uninstalled = PhabricatorEnv::getEnvConfig($key); + + if ($uninstalled[$this->application]) { + unset($list[$this->application]); + } else { + $list[$this->application] = true; + } + + $xaction = id(new PhabricatorConfigTransaction()) + ->setTransactionType(PhabricatorConfigTransaction::TYPE_EDIT) + ->setNewValue( + array( + 'deleted' => false, + 'value' => $list + )); + + $editor = id(new PhabricatorConfigEditor()) + ->setActor($this->getRequest()->getUser()) + ->setContinueOnNoEffect(true) + ->setContentSource( + PhabricatorContentSource::newForSource( + PhabricatorContentSource::SOURCE_WEB, + array( + 'ip' => $this->getRequest()->getRemoteAddr(), + ))); + + + $editor->applyTransactions($config_entry, array($xaction)); + + } + +} + diff --git a/src/applications/meta/controller/PhabricatorApplicationsListController.php b/src/applications/meta/controller/PhabricatorApplicationsListController.php index 3ef64b24bd..a6b3ef1fce 100644 --- a/src/applications/meta/controller/PhabricatorApplicationsListController.php +++ b/src/applications/meta/controller/PhabricatorApplicationsListController.php @@ -10,7 +10,7 @@ final class PhabricatorApplicationsListController $nav = $this->buildSideNavView(); $nav->selectFilter('/'); - $applications = PhabricatorApplication::getAllInstalledApplications(); + $applications = PhabricatorApplication::getAllApplications(); $list = $this->buildInstalledApplicationsList($applications); diff --git a/src/applications/metamta/application/PhabricatorApplicationMetaMTA.php b/src/applications/metamta/application/PhabricatorApplicationMetaMTA.php index 6aed7502c8..0ac2afd146 100644 --- a/src/applications/metamta/application/PhabricatorApplicationMetaMTA.php +++ b/src/applications/metamta/application/PhabricatorApplicationMetaMTA.php @@ -22,6 +22,10 @@ final class PhabricatorApplicationMetaMTA extends PhabricatorApplication { return self::GROUP_ADMIN; } + public function canUninstall() { + return false; + } + public function getRoutes() { return array( $this->getBaseURI() => array( diff --git a/src/applications/people/application/PhabricatorApplicationPeople.php b/src/applications/people/application/PhabricatorApplicationPeople.php index ad9754bc1c..0f0f05385e 100644 --- a/src/applications/people/application/PhabricatorApplicationPeople.php +++ b/src/applications/people/application/PhabricatorApplicationPeople.php @@ -26,6 +26,10 @@ final class PhabricatorApplicationPeople extends PhabricatorApplication { return self::GROUP_ADMIN; } + public function canUninstall() { + return false; + } + public function getRoutes() { return array( '/people/' => array( diff --git a/src/applications/settings/application/PhabricatorApplicationSettings.php b/src/applications/settings/application/PhabricatorApplicationSettings.php index 36abbb47c4..613ec7168a 100644 --- a/src/applications/settings/application/PhabricatorApplicationSettings.php +++ b/src/applications/settings/application/PhabricatorApplicationSettings.php @@ -14,6 +14,10 @@ final class PhabricatorApplicationSettings extends PhabricatorApplication { return 'settings'; } + public function canUninstall() { + return false; + } + public function getRoutes() { return array( '/settings/' => array( diff --git a/src/applications/subscriptions/application/PhabricatorApplicationSubscriptions.php b/src/applications/subscriptions/application/PhabricatorApplicationSubscriptions.php index 21543d4eb9..ad4b4eea15 100644 --- a/src/applications/subscriptions/application/PhabricatorApplicationSubscriptions.php +++ b/src/applications/subscriptions/application/PhabricatorApplicationSubscriptions.php @@ -6,6 +6,10 @@ final class PhabricatorApplicationSubscriptions extends PhabricatorApplication { return false; } + public function canUninstall() { + return false; + } + public function getEventListeners() { return array( new PhabricatorSubscriptionsUIEventListener(), diff --git a/src/applications/transactions/application/PhabricatorApplicationTransactions.php b/src/applications/transactions/application/PhabricatorApplicationTransactions.php index b597b394dd..ac0b4e1bc9 100644 --- a/src/applications/transactions/application/PhabricatorApplicationTransactions.php +++ b/src/applications/transactions/application/PhabricatorApplicationTransactions.php @@ -6,6 +6,10 @@ final class PhabricatorApplicationTransactions extends PhabricatorApplication { return false; } + public function canUninstall() { + return false; + } + public function getRoutes() { return array( '/transactions/' => array( From 830c2410eb05c5ca8949e3953ea598f67c4697cc Mon Sep 17 00:00:00 2001 From: Chad Little Date: Tue, 29 Jan 2013 10:20:17 -0800 Subject: [PATCH 16/17] Allows a button type for menus, used in Conpherence Summary: This adds a new menu item, TYPEBUTTON, for use in Conpherence and maybe others over time. Note I need to add icon support, but I'll make them later tonight. I also changed the front facing names to 'Conversations' which is way more natural. Basically, Pholio has Mocks, Differential has Diffs, Conpherence has Conversations. Test Plan: Tested Conpherence on mobile and desktop. Reviewers: epriestley, btrahan Reviewed By: epriestley CC: aran, Korvin Maniphest Tasks: T2430 Differential Revision: https://secure.phabricator.com/D4691 --- src/__celerity_resource_map__.php | 82 +++++++++---------- .../controller/ConpherenceController.php | 8 +- .../controller/ConpherenceNewController.php | 2 +- src/view/layout/AphrontSideNavFilterView.php | 18 +++- src/view/layout/PhabricatorMenuItemView.php | 1 + src/view/layout/PhabricatorMenuView.php | 11 +++ .../css/layout/phabricator-side-menu-view.css | 19 +++++ 7 files changed, 92 insertions(+), 49 deletions(-) diff --git a/src/__celerity_resource_map__.php b/src/__celerity_resource_map__.php index 7ff5dbf85f..158c033447 100644 --- a/src/__celerity_resource_map__.php +++ b/src/__celerity_resource_map__.php @@ -2935,7 +2935,7 @@ celerity_register_resource_map(array( ), 'phabricator-side-menu-view-css' => array( - 'uri' => '/res/2013e94f/rsrc/css/layout/phabricator-side-menu-view.css', + 'uri' => '/res/28a1e092/rsrc/css/layout/phabricator-side-menu-view.css', 'type' => 'css', 'requires' => array( @@ -3380,7 +3380,7 @@ celerity_register_resource_map(array( ), array( 'packages' => array( - 'feecd595' => + '0cb71c48' => array( 'name' => 'core.pkg.css', 'symbols' => @@ -3424,7 +3424,7 @@ celerity_register_resource_map(array( 36 => 'phabricator-object-item-list-view-css', 37 => 'global-drag-and-drop-css', ), - 'uri' => '/res/pkg/feecd595/core.pkg.css', + 'uri' => '/res/pkg/0cb71c48/core.pkg.css', 'type' => 'css', ), '8a3f0fbd' => @@ -3614,19 +3614,19 @@ celerity_register_resource_map(array( 'reverse' => array( 'aphront-attached-file-view-css' => 'e30a3fa8', - 'aphront-crumbs-view-css' => 'feecd595', - 'aphront-dialog-view-css' => 'feecd595', - 'aphront-error-view-css' => 'feecd595', - 'aphront-form-view-css' => 'feecd595', + 'aphront-crumbs-view-css' => '0cb71c48', + 'aphront-dialog-view-css' => '0cb71c48', + 'aphront-error-view-css' => '0cb71c48', + 'aphront-form-view-css' => '0cb71c48', 'aphront-headsup-action-list-view-css' => 'ec01d039', - 'aphront-headsup-view-css' => 'feecd595', - 'aphront-list-filter-view-css' => 'feecd595', - 'aphront-pager-view-css' => 'feecd595', - 'aphront-panel-view-css' => 'feecd595', - 'aphront-table-view-css' => 'feecd595', - 'aphront-tokenizer-control-css' => 'feecd595', - 'aphront-tooltip-css' => 'feecd595', - 'aphront-typeahead-control-css' => 'feecd595', + 'aphront-headsup-view-css' => '0cb71c48', + 'aphront-list-filter-view-css' => '0cb71c48', + 'aphront-pager-view-css' => '0cb71c48', + 'aphront-panel-view-css' => '0cb71c48', + 'aphront-table-view-css' => '0cb71c48', + 'aphront-tokenizer-control-css' => '0cb71c48', + 'aphront-tooltip-css' => '0cb71c48', + 'aphront-typeahead-control-css' => '0cb71c48', 'differential-changeset-view-css' => 'ec01d039', 'differential-core-view-css' => 'ec01d039', 'differential-inline-comment-editor' => '9dae5f20', @@ -3640,7 +3640,7 @@ celerity_register_resource_map(array( 'differential-table-of-contents-css' => 'ec01d039', 'diffusion-commit-view-css' => 'c8ce2d88', 'diffusion-icons-css' => 'c8ce2d88', - 'global-drag-and-drop-css' => 'feecd595', + 'global-drag-and-drop-css' => '0cb71c48', 'inline-comment-summary-css' => 'ec01d039', 'javelin-aphlict' => '8a3f0fbd', 'javelin-behavior' => 'fbeded59', @@ -3710,48 +3710,48 @@ celerity_register_resource_map(array( 'javelin-util' => 'fbeded59', 'javelin-vector' => 'fbeded59', 'javelin-workflow' => 'fbeded59', - 'lightbox-attachment-css' => 'feecd595', + 'lightbox-attachment-css' => '0cb71c48', 'maniphest-task-summary-css' => 'e30a3fa8', 'maniphest-transaction-detail-css' => 'e30a3fa8', 'phabricator-busy' => '8a3f0fbd', 'phabricator-content-source-view-css' => 'ec01d039', - 'phabricator-core-buttons-css' => 'feecd595', - 'phabricator-core-css' => 'feecd595', - 'phabricator-crumbs-view-css' => 'feecd595', - 'phabricator-directory-css' => 'feecd595', + 'phabricator-core-buttons-css' => '0cb71c48', + 'phabricator-core-css' => '0cb71c48', + 'phabricator-crumbs-view-css' => '0cb71c48', + 'phabricator-directory-css' => '0cb71c48', 'phabricator-drag-and-drop-file-upload' => '9dae5f20', 'phabricator-dropdown-menu' => '8a3f0fbd', 'phabricator-file-upload' => '8a3f0fbd', - 'phabricator-filetree-view-css' => 'feecd595', - 'phabricator-flag-css' => 'feecd595', - 'phabricator-form-view-css' => 'feecd595', - 'phabricator-header-view-css' => 'feecd595', - 'phabricator-jump-nav' => 'feecd595', + 'phabricator-filetree-view-css' => '0cb71c48', + 'phabricator-flag-css' => '0cb71c48', + 'phabricator-form-view-css' => '0cb71c48', + 'phabricator-header-view-css' => '0cb71c48', + 'phabricator-jump-nav' => '0cb71c48', 'phabricator-keyboard-shortcut' => '8a3f0fbd', 'phabricator-keyboard-shortcut-manager' => '8a3f0fbd', - 'phabricator-main-menu-view' => 'feecd595', + 'phabricator-main-menu-view' => '0cb71c48', 'phabricator-menu-item' => '8a3f0fbd', - 'phabricator-nav-view-css' => 'feecd595', + 'phabricator-nav-view-css' => '0cb71c48', 'phabricator-notification' => '8a3f0fbd', - 'phabricator-notification-css' => 'feecd595', - 'phabricator-notification-menu-css' => 'feecd595', - 'phabricator-object-item-list-view-css' => 'feecd595', + 'phabricator-notification-css' => '0cb71c48', + 'phabricator-notification-menu-css' => '0cb71c48', + 'phabricator-object-item-list-view-css' => '0cb71c48', 'phabricator-object-selector-css' => 'ec01d039', 'phabricator-paste-file-upload' => '8a3f0fbd', 'phabricator-prefab' => '8a3f0fbd', 'phabricator-project-tag-css' => 'e30a3fa8', - 'phabricator-remarkup-css' => 'feecd595', + 'phabricator-remarkup-css' => '0cb71c48', 'phabricator-shaped-request' => '9dae5f20', - 'phabricator-side-menu-view-css' => 'feecd595', - 'phabricator-standard-page-view' => 'feecd595', + 'phabricator-side-menu-view-css' => '0cb71c48', + 'phabricator-standard-page-view' => '0cb71c48', 'phabricator-textareautils' => '8a3f0fbd', 'phabricator-tooltip' => '8a3f0fbd', - 'phabricator-transaction-view-css' => 'feecd595', - 'phabricator-zindex-css' => 'feecd595', - 'sprite-apps-large-css' => 'feecd595', - 'sprite-gradient-css' => 'feecd595', - 'sprite-icon-css' => 'feecd595', - 'sprite-menu-css' => 'feecd595', - 'syntax-highlighting-css' => 'feecd595', + 'phabricator-transaction-view-css' => '0cb71c48', + 'phabricator-zindex-css' => '0cb71c48', + 'sprite-apps-large-css' => '0cb71c48', + 'sprite-gradient-css' => '0cb71c48', + 'sprite-icon-css' => '0cb71c48', + 'sprite-menu-css' => '0cb71c48', + 'syntax-highlighting-css' => '0cb71c48', ), )); diff --git a/src/applications/conpherence/controller/ConpherenceController.php b/src/applications/conpherence/controller/ConpherenceController.php index be09bc39f5..7151c0fcc4 100644 --- a/src/applications/conpherence/controller/ConpherenceController.php +++ b/src/applications/conpherence/controller/ConpherenceController.php @@ -107,9 +107,9 @@ abstract class ConpherenceController extends PhabricatorController { $nav->addClass('conpherence-menu'); $nav->setMenuID('conpherence-menu'); - $nav->addFilter( + $nav->addButton( 'new', - pht('New Conpherence'), + pht('New Conversation'), $this->getApplicationURI('new/') ); $nav->addLabel(pht('Unread')); @@ -171,7 +171,7 @@ abstract class ConpherenceController extends PhabricatorController { array( 'class' => 'no-conpherences-menu-item' ), - pht('No more conpherences.') + pht('No more conversations.') ); } @@ -185,7 +185,7 @@ abstract class ConpherenceController extends PhabricatorController { $crumbs ->addAction( id(new PhabricatorMenuItemView()) - ->setName(pht('New Conpherence')) + ->setName(pht('New Conversation')) ->setHref($this->getApplicationURI('new/')) ->setIcon('create') ) diff --git a/src/applications/conpherence/controller/ConpherenceNewController.php b/src/applications/conpherence/controller/ConpherenceNewController.php index 6e2600b794..43f1ae87f9 100644 --- a/src/applications/conpherence/controller/ConpherenceNewController.php +++ b/src/applications/conpherence/controller/ConpherenceNewController.php @@ -12,7 +12,7 @@ final class ConpherenceNewController extends ConpherenceController { $conpherence = id(new ConpherenceThread()) ->attachParticipants(array()) ->attachFilePHIDs(array()); - $title = pht('New Conpherence'); + $title = pht('New Conversation'); $participants = array(); $message = ''; $files = array(); diff --git a/src/view/layout/AphrontSideNavFilterView.php b/src/view/layout/AphrontSideNavFilterView.php index bceb20e981..b754ea5608 100644 --- a/src/view/layout/AphrontSideNavFilterView.php +++ b/src/view/layout/AphrontSideNavFilterView.php @@ -83,13 +83,25 @@ final class AphrontSideNavFilterView extends AphrontView { return $this->menu; } - public function addFilter( + public function addFilter($key, $name, $uri = null) { + return $this->addThing( + $key, $name, $uri, PhabricatorMenuItemView::TYPE_LINK); + } + + public function addButton($key, $name, $uri = null) { + return $this->addThing( + $key, $name, $uri, PhabricatorMenuItemView::TYPE_BUTTON); + } + + private function addThing( $key, $name, - $uri = null) { + $uri = null, + $type) { $item = id(new PhabricatorMenuItemView()) - ->setName($name); + ->setName($name) + ->setType($type); if (strlen($key)) { $item->setKey($key); diff --git a/src/view/layout/PhabricatorMenuItemView.php b/src/view/layout/PhabricatorMenuItemView.php index 69f4d1db76..e66abecb8a 100644 --- a/src/view/layout/PhabricatorMenuItemView.php +++ b/src/view/layout/PhabricatorMenuItemView.php @@ -5,6 +5,7 @@ final class PhabricatorMenuItemView extends AphrontTagView { const TYPE_LINK = 'type-link'; const TYPE_SPACER = 'type-spacer'; const TYPE_LABEL = 'type-label'; + const TYPE_BUTTON = 'type-button'; private $name; private $href; diff --git a/src/view/layout/PhabricatorMenuView.php b/src/view/layout/PhabricatorMenuView.php index 334c5e3ab0..b5e7fc8a8d 100644 --- a/src/view/layout/PhabricatorMenuView.php +++ b/src/view/layout/PhabricatorMenuView.php @@ -25,6 +25,17 @@ final class PhabricatorMenuView extends AphrontTagView { return $item; } + public function newButton($name, $href) { + $item = id(new PhabricatorMenuItemView()) + ->setType(PhabricatorMenuItemView::TYPE_BUTTON) + ->setName($name) + ->setHref($href); + + $this->addMenuItem($item); + + return $item; + } + public function addMenuItem(PhabricatorMenuItemView $item) { $key = $item->getKey(); $this->items[] = $item; diff --git a/webroot/rsrc/css/layout/phabricator-side-menu-view.css b/webroot/rsrc/css/layout/phabricator-side-menu-view.css index d06a7e5609..2aa467d6ec 100644 --- a/webroot/rsrc/css/layout/phabricator-side-menu-view.css +++ b/webroot/rsrc/css/layout/phabricator-side-menu-view.css @@ -25,6 +25,25 @@ background-color: #000; } +.phabricator-dark-menu .phabricator-menu-item-type-button, +.phabricator-side-menu .phabricator-menu-item-type-button { + width: 50%; + padding: 5px 8px; + display: block; + border-radius: 4px; + border: 2px solid #000; + margin: 10px auto; + color: #fff; + font-size: 14px; + text-shadow: 0px 1px 1px #000000; + font-weight: bold; + text-align: center; +} + +.phabricator-side-menu .phabricator-menu-item-type-button:hover { + background-image: url(/rsrc/image/texture/dark-menu-hover.png); +} + .device-desktop .phabricator-side-menu a.phabricator-menu-item-type-link:hover { text-decoration: none; } From 3e7a7518faf62f0ee0978f2406a72072020c96fc Mon Sep 17 00:00:00 2001 From: Chad Little Date: Tue, 29 Jan 2013 10:56:01 -0800 Subject: [PATCH 17/17] Add missing Conpherence icon + generate hovers Summary: Added missing sprite images and added hover classes to sprite generator class. Test Plan: read the CSS Reviewers: epriestley, btrahan Reviewed By: epriestley CC: aran, Korvin Differential Revision: https://secure.phabricator.com/D4721 --- .../sprite/conpher_1x/conversation_off.png | Bin 0 -> 1827 bytes .../sprite/conpher_1x/conversation_on.png | Bin 0 -> 1822 bytes resources/sprite/manifest/conph.json | 58 ++++++++++-------- src/__celerity_resource_map__.php | 10 +-- .../celerity/CeleritySpriteGenerator.php | 9 ++- webroot/rsrc/css/sprite-conph.css | 34 ++++++---- webroot/rsrc/image/sprite-conph-X2.png | Bin 11685 -> 14625 bytes webroot/rsrc/image/sprite-conph.png | Bin 5527 -> 6823 bytes 8 files changed, 68 insertions(+), 43 deletions(-) create mode 100644 resources/sprite/conpher_1x/conversation_off.png create mode 100644 resources/sprite/conpher_1x/conversation_on.png diff --git a/resources/sprite/conpher_1x/conversation_off.png b/resources/sprite/conpher_1x/conversation_off.png new file mode 100644 index 0000000000000000000000000000000000000000..2a0310bca2a32a2aa590c46c8f56db9a11725e46 GIT binary patch literal 1827 zcmbVNX;2eq7~T|vir|H`9L}%=M68lzb1X?pgd9Wzgd^N2Xh;^aNU~wGK!`I~MN#YM zC|Jh|Xt9ceiWdSxD=;cmrXrVkpr8zRfGE(SgSKKfBDOyqJJa3$_B-}{p7);J9u~5~ z&c@jW002ArN~w~ZLCct7O}>q0^B6ff5dpD81eQ!>sc-}kX|N;&l@1)6kedZWN3q`l`AkZa2^g9g4AA=U|L zlSaiV!axazBOsT~_Es|?2!vre#Nom)v5C3dKiaz41e!$dEBiDgy(eGZ{La#jp3$MnZ}FW5y??jgi>~ zgrP)?SO%^p^O5X61tw$nc|{gM(i%Z1j*>}HrAaY$h7Qpaa;cC;exYknjesX%bJ>t2 zfGJ@yVIBnWSS%5bE90<4VlJ1<;ZJdV3M=EX#V`jJ!7SJZf&y3~zJw)avUwsInHZjk zIfa$$jf6_CMyB+lq}~r${%5fQ367`;43EUHw5bXR(_#c>)M5ru5&?r=3Y8kwTMm|3 z5;W58iO>3VJVM)mCMu-S%a44$Koe9AKM4f zlRblz&GAD@z605F;c}@c($qB+)17KBax6~EZ{ARg=6l~M9G{kO2pkoM%`J%UN-Fns zSZcE+@7ArV!0p=tgBtr2nN;dLn^C(#`~7tyvwGz4bNxg`VYkV%D=9+W;rMimlVj%V z{OehD#yUQ`t@Bw1elXYViLV*3+_uFNBclc1pJ~(DI@wxpR5`k~4LFb1mhL%lTz`83 z|EO2s;PYSK=uc!2DO{Sz?5?z`3*EgVz4BmBHf2WtJF0(Yq_R9(UKZ=oDBidrsL@oZ z+)mjx)&lH1Se}<~YC=lf#&3-s@R5n`S_mZ(vi_eY;N!UOG-md zIzRXU|AxaKzx$^1im!TMcYAFm%YcWO>$hEfW_R-Ba@W)yl&3@0@#XUBt9=Cs{}%8N zpSd?P{&k!+)y8^T$K4ek;kIt)JLWgEcXTpaJ-b`uPW$YB`}U%&s9nBvSQ9pPng9MX zvY?r}?}rwwaa=eJ@jYMVx+tI!sXg;N!khB#W1b(g^~W8a$&SLKMeVZc=-`OXUFX`1 zORnMOoXq57TwvEXr4^J=;_L{nb02@$)7`8r+dI_%#ZO-6_P0Ed9E*p#SsMng0|0e% zNJyQj66Qde#^YgL(x@nhdx}$+?D3k_V{KzMUz7m{GD@4(qP_+bkJAhLk1v*OwP$|m zT12y3svrlg8h4 z2Kk&yXp`rA^c!pZ>5HjXa;;`VUp;Qb%NBHUqNHvmRV|xBSCwJWClp%PIS`>t9L%j0 zho)Aeo2y4Ja?GB&$1d=E)*o)_S>!hs_4T7`*Dnu9R~;+y`i^o(n};aw%RP(i{0y(s zkF2K895GX50nC6%7Zi39yjbB`_HJ?4@?D~mmH`7Ub6DLw(M`tDP%v|Cw^rYUF{{_>u;o6ips_08sNRzb$z{i1d_r?WVs0 DJFCQz literal 0 HcmV?d00001 diff --git a/resources/sprite/conpher_1x/conversation_on.png b/resources/sprite/conpher_1x/conversation_on.png new file mode 100644 index 0000000000000000000000000000000000000000..11e8437a0a6f8dbba8cbea69d81bd50f95f321b0 GIT binary patch literal 1822 zcmbVNdrT8|9KS*2KpJ=)S%3Y3=eP%5tpSYed*pat41?Fog+L?)9r zP9%b$8*DH|6sMv%1p%W-oXBQTArQpqh=L#su&@E{%ERpsuKE+Qh91p z2kHg@rV3?fI36CblPkkikklvx=~Ws64FGN)dW}?;fZ|{b8mCnAC}Y=eQb47gM+svF zzyTTos!;l-Y0;20ai}aULB^3&JlsJyJ(nO*p|}*(s}j{ZuAWDk=j9S><1vi_&Wqp) zJj#Mm;Q@i50Mnu%6LO)-U^*RSu^>8w$zsvBfe1`TXfW}xsB{LG$>Jie;NnFgv}xtB z++d+-Q5Uh}Q4~0?;nHX+DJf8j3xsLoXmk#TW8^>(Dj`ADrK)kMo~qV4E-?sEolL9L z;7Uvl8X2WA*gl*`AuL^RL8S=@ct@<(Ee47R8BH(M(C83MQ>l!8%}eX>VDuj|-YcyO zP1T^ZU{r_g)5?f^#5yj4iP(Kukx`JahPz9vB$6Uc6k@V{DpZa833(La3nW*{xom+8 z(}gbZh6M=BV$qRm;#Ny-GswB9`$%ELWgKr8uSy#jwPs3J6qSIHprz8c-0z0-XY+GNsyh z;A~9Lg1=|36Wq5ysGr&qri3IXo{nH#RpfZ+Ie&S8oaWlAex?e4)$3>}&L|_h(MUmDqV|ns2n}$w2UeYWbv*y!k7 zS?%>TCYO5L9^Bz{j_~5H-g~j?w7I!?dPV<(wH4+K4Go5#p6Tfz;MTFwEc0DH?sk8;^_rty#E=PeeV_lnN^8&>GTnE(I) literal 0 HcmV?d00001 diff --git a/resources/sprite/manifest/conph.json b/resources/sprite/manifest/conph.json index f6cdb6dbb8..9554b39997 100644 --- a/resources/sprite/manifest/conph.json +++ b/resources/sprite/manifest/conph.json @@ -1,64 +1,74 @@ { "version" : 1, "sprites" : { - "conpher_calendar_off" : { + "conpher_calendar_off" : { "name" : "conpher_calendar_off", - "rule" : "conpher_calendar_off", + "rule" : ".conpher_calendar_off", "hash" : "a8228ab90fd90f4c2500d9285179bf26" }, - "conpher_calendar_on" : { + "conpher_calendar_on" : { "name" : "conpher_calendar_on", - "rule" : "conpher_calendar_on", + "rule" : ".conpher_calendar_on, .device-desktop .conpher_calendar_off:hover ", "hash" : "931243bc3c414782ddb2d1d9607908ba" }, - "conpher_files_off" : { + "conpher_conversation_off" : { + "name" : "conpher_conversation_off", + "rule" : ".conpher_conversation_off", + "hash" : "931abb0377898297a9a603a6d280b977" + }, + "conpher_conversation_on" : { + "name" : "conpher_conversation_on", + "rule" : ".conpher_conversation_on, .device-desktop .conpher_conversation_off:hover ", + "hash" : "0b8a39dc5019dac1975b7be2ca0ccbfa" + }, + "conpher_files_off" : { "name" : "conpher_files_off", - "rule" : "conpher_files_off", + "rule" : ".conpher_files_off", "hash" : "de1aee01b9b47b354e6ac280ae68bae1" }, - "conpher_files_on" : { + "conpher_files_on" : { "name" : "conpher_files_on", - "rule" : "conpher_files_on", + "rule" : ".conpher_files_on, .device-desktop .conpher_files_off:hover ", "hash" : "9ccbbd5e86fd4ec87a11aee0c9ec8c60" }, - "conpher_list_off" : { + "conpher_list_off" : { "name" : "conpher_list_off", - "rule" : "conpher_list_off", + "rule" : ".conpher_list_off", "hash" : "2611311d0c2aec04416433be74d3a30e" }, - "conpher_list_on" : { + "conpher_list_on" : { "name" : "conpher_list_on", - "rule" : "conpher_list_on", + "rule" : ".conpher_list_on, .device-desktop .conpher_list_off:hover ", "hash" : "cee6de0301c84b0d195282642642afa0" }, - "conpher_more_off" : { + "conpher_more_off" : { "name" : "conpher_more_off", - "rule" : "conpher_more_off", + "rule" : ".conpher_more_off", "hash" : "3b7099bdde20a13864b48552b11e92c3" }, - "conpher_more_on" : { + "conpher_more_on" : { "name" : "conpher_more_on", - "rule" : "conpher_more_on", + "rule" : ".conpher_more_on, .device-desktop .conpher_more_off:hover ", "hash" : "b146f0cff9c2e5f0b57f7ebcfe0704d3" }, - "conpher_people_off" : { + "conpher_people_off" : { "name" : "conpher_people_off", - "rule" : "conpher_people_off", + "rule" : ".conpher_people_off", "hash" : "641a6a21aa32a12416e85caf8a22e340" }, - "conpher_people_on" : { + "conpher_people_on" : { "name" : "conpher_people_on", - "rule" : "conpher_people_on", + "rule" : ".conpher_people_on, .device-desktop .conpher_people_off:hover ", "hash" : "f13745fd7036564eefb1c0ebc3502a92" }, - "conpher_settings_off" : { + "conpher_settings_off" : { "name" : "conpher_settings_off", - "rule" : "conpher_settings_off", + "rule" : ".conpher_settings_off", "hash" : "aa9ab000d9e33e3c50c2fe70367f30b4" }, - "conpher_settings_on" : { + "conpher_settings_on" : { "name" : "conpher_settings_on", - "rule" : "conpher_settings_on", + "rule" : ".conpher_settings_on, .device-desktop .conpher_settings_off:hover ", "hash" : "a5fe22965997f9559800ca7db5ea32c8" } }, diff --git a/src/__celerity_resource_map__.php b/src/__celerity_resource_map__.php index 158c033447..47dff6fcbe 100644 --- a/src/__celerity_resource_map__.php +++ b/src/__celerity_resource_map__.php @@ -478,15 +478,15 @@ celerity_register_resource_map(array( ), '/rsrc/image/sprite-conph-X2.png' => array( - 'hash' => 'c80e0b09360be71addfeaee622ac4bf0', - 'uri' => '/res/c80e0b09/rsrc/image/sprite-conph-X2.png', + 'hash' => '8f79b9888577dab95d6019d1b7f2a204', + 'uri' => '/res/8f79b988/rsrc/image/sprite-conph-X2.png', 'disk' => '/rsrc/image/sprite-conph-X2.png', 'type' => 'png', ), '/rsrc/image/sprite-conph.png' => array( - 'hash' => '0b1d46b6c7369e09dc4b9e26010b74d6', - 'uri' => '/res/0b1d46b6/rsrc/image/sprite-conph.png', + 'hash' => 'a6329b4baa648b57c00de65f6758cbd2', + 'uri' => '/res/a6329b4b/rsrc/image/sprite-conph.png', 'disk' => '/rsrc/image/sprite-conph.png', 'type' => 'png', ), @@ -3316,7 +3316,7 @@ celerity_register_resource_map(array( ), 'sprite-conpher-css' => array( - 'uri' => '/res/14e5d74c/rsrc/css/sprite-conph.css', + 'uri' => '/res/f640f0c5/rsrc/css/sprite-conph.css', 'type' => 'css', 'requires' => array( diff --git a/src/infrastructure/celerity/CeleritySpriteGenerator.php b/src/infrastructure/celerity/CeleritySpriteGenerator.php index bc25743b83..4f9f4f26b7 100644 --- a/src/infrastructure/celerity/CeleritySpriteGenerator.php +++ b/src/infrastructure/celerity/CeleritySpriteGenerator.php @@ -194,7 +194,14 @@ final class CeleritySpriteGenerator { $sprite = id(clone $template) ->setName($prefix.$icon); - $sprite->setTargetCSS($prefix.$icon); + $tcss = array(); + $tcss[] = '.'.$prefix.$icon; + if ($color == 'on') { + $class = str_replace('_on', '_off', $prefix.$icon); + $tcss[] = '.device-desktop .'.$class.':hover '; + } + + $sprite->setTargetCSS(implode(', ', $tcss)); foreach ($scales as $scale_key => $scale) { $path = $this->getPath($prefix.$scale_key.'/'.$icon.'.png'); diff --git a/webroot/rsrc/css/sprite-conph.css b/webroot/rsrc/css/sprite-conph.css index 6b02619ebf..d11ae477c5 100644 --- a/webroot/rsrc/css/sprite-conph.css +++ b/webroot/rsrc/css/sprite-conph.css @@ -13,55 +13,63 @@ only screen and (min-device-pixel-ratio: 1.5), only screen and (-webkit-min-device-pixel-ratio: 1.5) { .sprite-conpher { background-image: url(/rsrc/image/sprite-conpher-X2.png); - background-size: 99px 132px; + background-size: 132px 132px; } } -conpher_calendar_off { +.conpher_calendar_off { background-position: 0px 0px; } -conpher_calendar_on { +.conpher_calendar_on, .device-desktop .conpher_calendar_off:hover { background-position: -33px 0px; } -conpher_files_off { +.conpher_conversation_off { background-position: -66px 0px; } -conpher_files_on { +.conpher_conversation_on, .device-desktop .conpher_conversation_off:hover { + background-position: -99px 0px; +} + +.conpher_files_off { background-position: 0px -33px; } -conpher_list_off { +.conpher_files_on, .device-desktop .conpher_files_off:hover { background-position: -33px -33px; } -conpher_list_on { +.conpher_list_off { background-position: -66px -33px; } -conpher_more_off { +.conpher_list_on, .device-desktop .conpher_list_off:hover { + background-position: -99px -33px; +} + +.conpher_more_off { background-position: 0px -66px; } -conpher_more_on { +.conpher_more_on, .device-desktop .conpher_more_off:hover { background-position: -33px -66px; } -conpher_people_off { +.conpher_people_off { background-position: -66px -66px; } -conpher_people_on { +.conpher_people_on, .device-desktop .conpher_people_off:hover { background-position: 0px -99px; } -conpher_settings_off { +.conpher_settings_off { background-position: -33px -99px; } -conpher_settings_on { +.conpher_settings_on, .device-desktop .conpher_settings_off:hover { background-position: -66px -99px; } diff --git a/webroot/rsrc/image/sprite-conph-X2.png b/webroot/rsrc/image/sprite-conph-X2.png index df789c68efa849394c3c62e208df3cc8c122404e..ef32a410db6dd78a217eb4e529cc312156d19c1c 100644 GIT binary patch literal 14625 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 literal 11685 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 z z!SBnhw~-yrqy=O}O3(D>f6PXX`=2?MeXV!nxYch2Me-|fIel!aKd5@-FxFoD(3qG$ z>dqwCj$I{~^tignO?1#sM+NFII#>=|PA}XT9Ir~!1ouAuxj{o(Jhe&(2eVRrBvLW{ zX1YY1{xCtvOtg|-_sHr+|$br8;$jBaM4HL{*Hd-ZAAS5iqFxhOy3qH;WJPP zQ5GKf(H9;g>ZTE(xhMmV&xFp4!mACQ6kAZ*mRK&#tnXInMN$h{t33qXU0;1d!YdVQ zSiXq{8ja&==B|9~h=_?JytVsukjy!L!W@3V!8k3>EJ+qmAC zwqQ+4BxSksTKAwhTKEzmBAiAWn!-Uhm1Q5r1M+oh+CT(fTCLE8t2GL!e>!)*^26h6&!+mE%r()7l1ORq%j*Zn^&VfLw3>$wz?ZgEuhfRiulODI|g^v z3HXQ!?NkTc0v{XEURjs;;g13ZTu?Wffk}uBB1Xk0pP19|LAEv7wc)D{0TY`?mICi>uS&3!D z#lrm7@yDQX2UNv;!np)2OCD1u$S7|*#w@uIzFESN#?3$3&VjY1;vg;o-6^N(rmE#I z?u*-puq(67a$W=}{;ViG?PP)?^2IY7q5bwXlj|bpT@|*nnBWj?;R9*c)vkI{==yJK z+OJ7ZsHI0mCTb56+(xU=jZUyY@idH@*}Jz!FHhwVh& z%-!rbknqJ%y6$=m2>M^mAHP?Ja3JU|D_L$!d1yNktCP91R% z^sdA+Lv2+5>3afF%Ri{hiGg1>AEbcY09C0ynt+~ou|FA0|A+75$GspaBFq6N(xmKn z9gNft`0PSaNZy;LB?L}${V`ukIb6b1OfZ1486hXEzRj%|9)_ke0)^w=6BAE2P9sLB zczAg3oLctk;|kps%vZ$YY}?#c48Ywhw*E z9-Tr`|I8OYYt^MMs+)yJ2{@FMwdJROLP-VrZPm$B9{$pWQP5d3BbvwSInJpz2S~lP&%6J*4U`oG|c8ultdZ-30&LXqAMVxOY zR5+H4i_M^NeD<*@j8cWK9*^C~1>=ITpGDa%i?qLQxvvJ?yq*>Q$Gj%s=KPHP95t^^ zP4^bw!H}OZK~^(>;87hbNTuyQ02>-f8uI~t&h?dI2kfRPs2VG67OfnzoZo3(s?)t+ z#Wl#*wU~XMDwO1yF&5$nc&C=K4w`FR%}_dEWa+6+b!t1)KX~+KkFv6}1FGd8t?-Qr zJ@vjKue`!DS<#|DRJ9RDD*{<)YR4zcjNNjZghG9*Nw}JcmU-iH$xwJ0IUm&X)aG)V z{#170G=q8!>bBni7e-8v=JZhSLbD5xB$B1HM|i*MO=)fy~8A zgS01`TbWQ2dHtM>gQb8A6XQUKH(BkB3d-%2+7RQHy#8t@dO?Q^?&FWYSyMX6=0U_U zutOGRCvKX0sP&i1*iZ*bDIV*u7$<4y32wn6Su+~GKwA0X50|USrB0+HB~nGX5W5bd zV0Tw_jm3p~9N0Q-$WNv$gtI<15ql{y-Vhk;$-P7mIU;FPGZp9htSGeNpe~ zUG3%!Ck!~x0x$&Z0qXw6+NR%d;2UarFBb}t8d0ggQ~N$B{g=OsY`o1)Ti?JFC)SmW zK*_h6#!*!{MI#b^$W%WBR%vTV|JHSBWiOEbL)#x0ETwc^+bM0wO^K~r9Cwnv&IqED z&&D{D;ndcz4R@}(DT_-5^Xe_$2@gNTgrUqANgKihlvN`IhtEoZ>k39fnLe*X@uAE< zp|n)m_-rYiy}?RXGfQgeoSu~tfIn9gitsM2cmW(8&Mgu)!kL2i2!}!;dqqMF(y^e9 zI~R01;=3sEx6tGU?T4}5CA2OcyX`8Z8(nm(+>4E2lgtM25{g6ULbII18nldQsg-hUeos`nXkJq45-+ZO<$J$I;8 z09{`1R;CABZx_>-1*5lF6o4Fwdo_z$xY4-{w>WR5YZ!jkDyXe&Jbt*MDJy8mSIE8% F`5&5ps<8k7