diff --git a/resources/celerity/map.php b/resources/celerity/map.php --- a/resources/celerity/map.php +++ b/resources/celerity/map.php @@ -9,8 +9,8 @@ 'names' => array( 'conpherence.pkg.css' => '0b64e988', 'conpherence.pkg.js' => '6249a1cf', - 'core.pkg.css' => '2f1ecc57', - 'core.pkg.js' => 'ba34ebda', + 'core.pkg.css' => '40efb208', + 'core.pkg.js' => 'ac2b12fd', 'darkconsole.pkg.js' => 'e7393ebb', 'differential.pkg.css' => 'a4ba74b5', 'differential.pkg.js' => '634399e9', @@ -22,7 +22,6 @@ 'rsrc/css/aphront/aphront-bars.css' => '231ac33c', 'rsrc/css/aphront/dark-console.css' => 'f54bf286', 'rsrc/css/aphront/dialog-view.css' => 'c076ef55', - 'rsrc/css/aphront/lightbox-attachment.css' => '90a84e83', 'rsrc/css/aphront/list-filter-view.css' => '5d6f0526', 'rsrc/css/aphront/multi-column.css' => '84cc6640', 'rsrc/css/aphront/notification.css' => '3f6c89c9', @@ -151,6 +150,7 @@ 'rsrc/css/phui/phui-info-panel.css' => '27ea50a1', 'rsrc/css/phui/phui-info-view.css' => 'ec92802a', 'rsrc/css/phui/phui-invisible-character-view.css' => '6993d9f0', + 'rsrc/css/phui/phui-lightbox.css' => '5c48f810', 'rsrc/css/phui/phui-list.css' => '9da2aa00', 'rsrc/css/phui/phui-object-box.css' => '6b487c57', 'rsrc/css/phui/phui-object-item-list-view.css' => '87278fa0', @@ -504,7 +504,7 @@ 'rsrc/js/core/behavior-hovercard.js' => 'bcaccd64', 'rsrc/js/core/behavior-keyboard-pager.js' => 'a8da01f0', 'rsrc/js/core/behavior-keyboard-shortcuts.js' => '01fca1f0', - 'rsrc/js/core/behavior-lightbox-attachments.js' => 'e50dcfc0', + 'rsrc/js/core/behavior-lightbox-attachments.js' => '1536b69c', 'rsrc/js/core/behavior-line-linker.js' => '1499a8cb', 'rsrc/js/core/behavior-more.js' => 'a80d0378', 'rsrc/js/core/behavior-object-selector.js' => 'e0ec7f2f', @@ -650,7 +650,7 @@ 'javelin-behavior-history-install' => '7ee2b591', 'javelin-behavior-icon-composer' => '8499b6ab', 'javelin-behavior-launch-icon-composer' => '48086888', - 'javelin-behavior-lightbox-attachments' => 'e50dcfc0', + 'javelin-behavior-lightbox-attachments' => '1536b69c', 'javelin-behavior-line-chart' => 'e4232876', 'javelin-behavior-load-blame' => '42126667', 'javelin-behavior-maniphest-batch-editor' => '782ab6e7', @@ -766,7 +766,6 @@ 'javelin-workboard-column' => '21df4ff5', 'javelin-workboard-controller' => '55baf5ed', 'javelin-workflow' => '1e911d0f', - 'lightbox-attachment-css' => '90a84e83', 'maniphest-batch-editor' => 'b0f0b6d5', 'maniphest-report-css' => '9b9580b7', 'maniphest-task-edit-css' => 'fda62a9b', @@ -868,6 +867,7 @@ 'phui-info-view-css' => 'ec92802a', 'phui-inline-comment-view-css' => '5953c28e', 'phui-invisible-character-view-css' => '6993d9f0', + 'phui-lightbox-css' => '5c48f810', 'phui-list-view-css' => '9da2aa00', 'phui-object-box-css' => '6b487c57', 'phui-object-item-list-view-css' => '87278fa0', @@ -1037,6 +1037,15 @@ 'javelin-workflow', 'javelin-workboard-controller', ), + '1536b69c' => array( + 'javelin-behavior', + 'javelin-stratcom', + 'javelin-dom', + 'javelin-mask', + 'javelin-util', + 'phuix-icon-view', + 'phabricator-busy', + ), '1aa4c968' => array( 'javelin-behavior', 'javelin-stratcom', @@ -2099,15 +2108,6 @@ 'javelin-behavior', 'javelin-dom', ), - 'e50dcfc0' => array( - 'javelin-behavior', - 'javelin-stratcom', - 'javelin-dom', - 'javelin-mask', - 'javelin-util', - 'phuix-icon-view', - 'phabricator-busy', - ), 'e5339c43' => array( 'javelin-behavior', 'javelin-dom', @@ -2283,7 +2283,7 @@ 'phabricator-main-menu-view', 'phabricator-notification-css', 'phabricator-notification-menu-css', - 'lightbox-attachment-css', + 'phui-lightbox-css', 'phui-header-view-css', 'phabricator-nav-view-css', 'phui-basic-nav-view-css', diff --git a/resources/celerity/packages.php b/resources/celerity/packages.php --- a/resources/celerity/packages.php +++ b/resources/celerity/packages.php @@ -111,7 +111,7 @@ 'phabricator-main-menu-view', 'phabricator-notification-css', 'phabricator-notification-menu-css', - 'lightbox-attachment-css', + 'phui-lightbox-css', 'phui-header-view-css', 'phabricator-nav-view-css', 'phui-basic-nav-view-css', diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -1609,6 +1609,7 @@ 'PHUICalendarWeekView' => 'view/phui/calendar/PHUICalendarWeekView.php', 'PHUICalendarWidgetView' => 'view/phui/calendar/PHUICalendarWidgetView.php', 'PHUIColorPalletteExample' => 'applications/uiexample/examples/PHUIColorPalletteExample.php', + 'PHUICommentPanelView' => 'view/phui/PHUICommentPanel.php', 'PHUICrumbView' => 'view/phui/PHUICrumbView.php', 'PHUICrumbsView' => 'view/phui/PHUICrumbsView.php', 'PHUICurtainExtension' => 'view/extension/PHUICurtainExtension.php', @@ -2652,6 +2653,7 @@ 'PhabricatorFileImageProxyController' => 'applications/files/controller/PhabricatorFileImageProxyController.php', 'PhabricatorFileImageTransform' => 'applications/files/transform/PhabricatorFileImageTransform.php', 'PhabricatorFileInfoController' => 'applications/files/controller/PhabricatorFileInfoController.php', + 'PhabricatorFileLightboxController' => 'applications/files/controller/PhabricatorFileLightboxController.php', 'PhabricatorFileLinkView' => 'view/layout/PhabricatorFileLinkView.php', 'PhabricatorFileListController' => 'applications/files/controller/PhabricatorFileListController.php', 'PhabricatorFileQuery' => 'applications/files/query/PhabricatorFileQuery.php', @@ -6403,6 +6405,7 @@ 'PHUICalendarWeekView' => 'AphrontView', 'PHUICalendarWidgetView' => 'AphrontTagView', 'PHUIColorPalletteExample' => 'PhabricatorUIExample', + 'PHUICommentPanelView' => 'AphrontTagView', 'PHUICrumbView' => 'AphrontView', 'PHUICrumbsView' => 'AphrontView', 'PHUICurtainExtension' => 'Phobject', @@ -7620,6 +7623,7 @@ 'PhabricatorFileImageProxyController' => 'PhabricatorFileController', 'PhabricatorFileImageTransform' => 'PhabricatorFileTransform', 'PhabricatorFileInfoController' => 'PhabricatorFileController', + 'PhabricatorFileLightboxController' => 'PhabricatorFileController', 'PhabricatorFileLinkView' => 'AphrontView', 'PhabricatorFileListController' => 'PhabricatorFileController', 'PhabricatorFileQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', diff --git a/src/applications/files/application/PhabricatorFilesApplication.php b/src/applications/files/application/PhabricatorFilesApplication.php --- a/src/applications/files/application/PhabricatorFilesApplication.php +++ b/src/applications/files/application/PhabricatorFilesApplication.php @@ -76,6 +76,7 @@ 'dropupload/' => 'PhabricatorFileDropUploadController', 'compose/' => 'PhabricatorFileComposeController', 'comment/(?P[1-9]\d*)/' => 'PhabricatorFileCommentController', + 'thread/(?P[1-9]\d*)/' => 'PhabricatorFileLightboxController', 'delete/(?P[1-9]\d*)/' => 'PhabricatorFileDeleteController', 'edit/(?P[1-9]\d*)/' => 'PhabricatorFileEditController', 'info/(?P[^/]+)/' => 'PhabricatorFileInfoController', diff --git a/src/applications/files/controller/PhabricatorFileLightboxController.php b/src/applications/files/controller/PhabricatorFileLightboxController.php new file mode 100644 --- /dev/null +++ b/src/applications/files/controller/PhabricatorFileLightboxController.php @@ -0,0 +1,28 @@ +getViewer(); + $id = $request->getURIData('id'); + + $file = id(new PhabricatorFileQuery()) + ->setViewer($viewer) + ->withIDs(array($id)) + ->executeOne(); + if (!$file) { + return new Aphront404Response(); + } + + $monogram = $file->getMonogram(); + $content = $this->buildTransactionTimeline( + $file, + id(new PhabricatorFileTransactionQuery()) + ->withTransactionTypes(array(PhabricatorTransactions::TYPE_COMMENT))); + $content->setQuoteRef($monogram); + + return id(new AphrontAjaxResponse()) + ->setContent($content); + } + +} diff --git a/src/applications/files/markup/PhabricatorEmbedFileRemarkupRule.php b/src/applications/files/markup/PhabricatorEmbedFileRemarkupRule.php --- a/src/applications/files/markup/PhabricatorEmbedFileRemarkupRule.php +++ b/src/applications/files/markup/PhabricatorEmbedFileRemarkupRule.php @@ -98,7 +98,7 @@ PhabricatorObjectHandle $handle, array $options) { - require_celerity_resource('lightbox-attachment-css'); + require_celerity_resource('phui-lightbox-css'); $attrs = array(); $image_class = 'phabricator-remarkup-embed-image'; @@ -176,6 +176,7 @@ 'uri' => $file->getBestURI(), 'dUri' => $file->getDownloadURI(), 'viewable' => true, + 'id' => $file->getID(), ), ), $img); @@ -279,7 +280,8 @@ ->setFileName($this->assertFlatText($options['name'])) ->setFileDownloadURI($file->getDownloadURI()) ->setFileViewURI($file->getBestURI()) - ->setFileViewable((bool)$options['viewable']); + ->setFileViewable((bool)$options['viewable']) + ->setFileID($file->getID()); } private function parseDimension($string) { diff --git a/src/view/form/control/PhabricatorRemarkupControl.php b/src/view/form/control/PhabricatorRemarkupControl.php --- a/src/view/form/control/PhabricatorRemarkupControl.php +++ b/src/view/form/control/PhabricatorRemarkupControl.php @@ -29,7 +29,7 @@ // We need to have this if previews render images, since Ajax can not // currently ship JS or CSS. - require_celerity_resource('lightbox-attachment-css'); + require_celerity_resource('phui-lightbox-css'); if (!$this->getDisabled()) { Javelin::initBehavior( diff --git a/src/view/layout/PhabricatorFileLinkView.php b/src/view/layout/PhabricatorFileLinkView.php --- a/src/view/layout/PhabricatorFileLinkView.php +++ b/src/view/layout/PhabricatorFileLinkView.php @@ -7,12 +7,14 @@ private $fileViewURI; private $fileViewable; private $filePHID; + private $fileID; private $customClass; public function setCustomClass($custom_class) { $this->customClass = $custom_class; return $this; } + public function getCustomClass() { return $this->customClass; } @@ -21,14 +23,25 @@ $this->filePHID = $file_phid; return $this; } + private function getFilePHID() { return $this->filePHID; } + public function setFileID($file_id) { + $this->fileID = $file_id; + return $this; + } + + private function getFileID() { + return $this->fileID; + } + public function setFileViewable($file_viewable) { $this->fileViewable = $file_viewable; return $this; } + private function getFileViewable() { return $this->fileViewable; } @@ -37,6 +50,7 @@ $this->fileViewURI = $file_view_uri; return $this; } + private function getFileViewURI() { return $this->fileViewURI; } @@ -45,6 +59,7 @@ $this->fileDownloadURI = $file_download_uri; return $this; } + private function getFileDownloadURI() { return $this->fileDownloadURI; } @@ -53,6 +68,7 @@ $this->fileName = $file_name; return $this; } + private function getFileName() { return $this->fileName; } @@ -64,12 +80,13 @@ 'uri' => $this->getFileViewURI(), 'dUri' => $this->getFileDownloadURI(), 'name' => $this->getFileName(), + 'id' => $this->getFileID(), ); } public function render() { require_celerity_resource('phabricator-remarkup-css'); - require_celerity_resource('lightbox-attachment-css'); + require_celerity_resource('phui-lightbox-css'); $sigil = null; $meta = null; diff --git a/src/view/page/PhabricatorStandardPageView.php b/src/view/page/PhabricatorStandardPageView.php --- a/src/view/page/PhabricatorStandardPageView.php +++ b/src/view/page/PhabricatorStandardPageView.php @@ -271,6 +271,9 @@ $default_img_uri = celerity_get_resource_uri( 'rsrc/image/icon/fatcow/document_black.png'); + $icon = id(new PHUIIconView()) + ->setIcon('fa-download'); + $lightbox_id = celerity_generate_unique_node_id(); $download_form = phabricator_form( $user, array( @@ -281,12 +284,18 @@ ), phutil_tag( 'button', - array('class' => 'button grey'), - pht('Download'))); + array( + 'class' => 'button grey has-icon', + ), + array( + $icon, + pht('Download'), + ))); Javelin::initBehavior( 'lightbox-attachments', array( + 'lightbox_id' => $lightbox_id, 'defaultImageUri' => $default_img_uri, 'downloadForm' => $download_form, )); diff --git a/src/view/phui/PHUICommentPanel.php b/src/view/phui/PHUICommentPanel.php new file mode 100644 --- /dev/null +++ b/src/view/phui/PHUICommentPanel.php @@ -0,0 +1,19 @@ + implode(' ', $classes), + ); + } + + protected function getTagContent() { + $view = null; + + return $view; + } + +} diff --git a/webroot/rsrc/css/aphront/lightbox-attachment.css b/webroot/rsrc/css/phui/phui-lightbox.css rename from webroot/rsrc/css/aphront/lightbox-attachment.css rename to webroot/rsrc/css/phui/phui-lightbox.css --- a/webroot/rsrc/css/aphront/lightbox-attachment.css +++ b/webroot/rsrc/css/phui/phui-lightbox.css @@ -1,5 +1,5 @@ /** - * @provides lightbox-attachment-css + * @provides phui-lightbox-css */ @@ -16,6 +16,10 @@ overflow-y: auto; } +.lightbox-attachment.comment-panel-open { + right: 321px; +} + .lightbox-attachment img { max-width: calc(100% - 44px); max-height: calc(100% - 44px); @@ -27,6 +31,17 @@ margin: auto; } +.comment-panel-open .lightbox-comment-frame { + position: fixed; + top: 44px; + bottom: 0; + right: 0; + width: 320px; + border-left: 1px solid {$thinblueborder}; + overflow-y: auto; + background: #fff; +} + .jx-mask + .lightbox-attachment { background: {$lightgreybackground}; } @@ -58,11 +73,26 @@ float: right; } +.lightbox-download button.has-icon { + padding-left: 28px; +} + .lightbox-attachment .lightbox-status .lightbox-download .lightbox-download-form { display: inline; } +.lightbox-attachment .lightbox-comment { + float: right; + margin: 9px 0 0px 8px; + padding-left: 28px; +} + +.lightbox-attachment.comment-panel-open .lightbox-comment, +.lightbox-attachment.comment-panel-open .lightbox-comment .phui-icon-view { + color: {$sky}; +} + .lightbox-attachment .lightbox-close { float: right; margin: 9px 0 0px 8px; @@ -94,6 +124,10 @@ width: 21px; } +.lightbox-attachment.comment-panel-open .lightbox-right .phui-icon-view { + right: 323px; +} + .lightbox-attachment .lightbox-right .phui-icon-view { font-size: 40px; } diff --git a/webroot/rsrc/js/core/behavior-lightbox-attachments.js b/webroot/rsrc/js/core/behavior-lightbox-attachments.js --- a/webroot/rsrc/js/core/behavior-lightbox-attachments.js +++ b/webroot/rsrc/js/core/behavior-lightbox-attachments.js @@ -14,7 +14,9 @@ var lightbox = null; var prev = null; var next = null; + var shown = false; var downloadForm = JX.$H(config.downloadForm).getFragment().firstChild; + var lightbox_id = config.lightbox_id; function loadLightBox(e) { if (!e.isNormalClick()) { @@ -61,10 +63,13 @@ } else { img_uri = config.defaultImageUri; extra_status = ' Image may not be representative of actual attachment.'; - name_element = JX.$N('div', - { className : 'attachment-name' }, - target_data.name - ); + name_element = + JX.$N('div', + { + className : 'attachment-name' + }, + target_data.name + ); } var alt_name = ''; @@ -72,44 +77,78 @@ alt_name = target_data.name; } - var img = JX.$N('img', - { - className : 'loading', - alt : alt_name - } - ); + var img = + JX.$N('img', + { + className : 'loading', + alt : alt_name + } + ); + + var commentFrame = + JX.$N('div', + { + className : 'lightbox-comment-frame', + id : 'lightbox-comment-frame' + } + ); + + var commentClass = (shown) ? 'comment-panel-open' : ''; + lightbox = + JX.$N('div', + { + className : 'lightbox-attachment ' + commentClass, + sigil : 'lightbox-attachment', + id : lightbox_id + }, + [img, commentFrame] + ); - lightbox = JX.$N('div', - { - className : 'lightbox-attachment', - sigil: 'lightbox-attachment' - }, - img - ); - - var statusSpan = JX.$N('span', - { - className: 'lightbox-status-txt' - }, - 'Image '+current+' of '+total+'.'+extra_status - ); - - var downloadSpan = JX.$N('span', - { - className : 'lightbox-download' - }); - var closeButton = JX.$N('a', - { - className : 'lightbox-close button grey', - href : '#' - }, - 'Close'); - var statusHTML = JX.$N('div', - { - className : 'lightbox-status' - }, - [statusSpan, closeButton, downloadSpan] - ); + var monogram = JX.$N('strong', {}, 'F'+target_data.id); + var statusSpan = + JX.$N('span', + { + className: 'lightbox-status-txt' + }, + [ + monogram, + ' Image ' + current + ' of ' + total + '.' + extra_status + ] + ); + + var downloadSpan = + JX.$N('span', + { + className : 'lightbox-download' + } + ); + + var commentIcon = new JX.PHUIXIconView() + .setIcon('fa-comment-o') + .getNode(); + var commentButton = + JX.$N('a', + { + className : 'lightbox-comment button grey has-icon', + href : '#', + sigil : 'lightbox-comment' + }, + [commentIcon, 'Comment'] + ); + var closeButton = + JX.$N('a', + { + className : 'lightbox-close button grey', + href : '#' + }, + 'Close'); + var statusHTML = + JX.$N('div', + { + className : 'lightbox-status' + }, + [statusSpan, closeButton, commentButton, downloadSpan] + ); JX.DOM.appendContent(lightbox, statusHTML); JX.DOM.appendContent(lightbox, name_element); JX.DOM.listen(closeButton, 'click', null, closeLightBox); @@ -120,12 +159,14 @@ .setIcon('fa-angle-right') .setColor('lightgreytext') .getNode(); - leftIcon = JX.$N('a', - { - className : 'lightbox-right', - href : '#' - }, - r_icon); + leftIcon = + JX.$N('a', + { + className : 'lightbox-right', + href : '#' + }, + r_icon + ); JX.DOM.listen(leftIcon, 'click', null, @@ -139,12 +180,14 @@ .setIcon('fa-angle-left') .setColor('lightgreytext') .getNode(); - rightIcon = JX.$N('a', - { - className : 'lightbox-left', - href : '#' - }, - l_icon); + rightIcon = + JX.$N('a', + { + className : 'lightbox-left', + href : '#' + }, + l_icon + ); JX.DOM.listen(rightIcon, 'click', null, @@ -168,6 +211,7 @@ }; img.src = img_uri; + loadComments(target_data.id); } // TODO - make this work with KeyboardShortcut, which means @@ -225,6 +269,31 @@ el.click(); } + function _toggleComment(e) { + e.kill(); + shown = !shown; + JX.DOM.alterClass(JX.$(lightbox_id), 'comment-panel-open', shown); + } + + function loadComments(id) { + var uri = '/file/thread/' + id + '/'; + new JX.Workflow(uri) + .setHandler(onLoadCommentsResponse) + .start(); + markCommentsLoading(false); + } + + function onLoadCommentsResponse(r) { + var frame = JX.$('lightbox-comment-frame'); + JX.DOM.setContent(frame, JX.$H(r)); + markCommentsLoading(false); + } + + function markCommentsLoading(loading) { + var frame = JX.$('lightbox-comment-frame'); + JX.DOM.alterClass(frame, 'loading', loading); + } + JX.Stratcom.listen( 'click', ['lightboxable'], @@ -252,4 +321,9 @@ e.kill(); }); + JX.Stratcom.listen( + 'click', + 'lightbox-comment', + _toggleComment); + });