diff --git a/resources/celerity/map.php b/resources/celerity/map.php index 3aef57ca61..43c3f83408 100644 --- a/resources/celerity/map.php +++ b/resources/celerity/map.php @@ -7,8 +7,8 @@ */ return array( 'names' => array( - 'core.pkg.css' => 'c7fc5aec', - 'core.pkg.js' => '10275c16', + 'core.pkg.css' => 'b9e2e1e5', + 'core.pkg.js' => '80f86a0a', 'darkconsole.pkg.js' => 'e7393ebb', 'differential.pkg.css' => 'b3eea3f5', 'differential.pkg.js' => '4b7d8f19', @@ -18,7 +18,7 @@ return array( 'maniphest.pkg.js' => '949a7498', 'rsrc/css/aphront/aphront-bars.css' => '231ac33c', 'rsrc/css/aphront/dark-console.css' => 'f54bf286', - 'rsrc/css/aphront/dialog-view.css' => 'b4334e08', + 'rsrc/css/aphront/dialog-view.css' => '913c172e', 'rsrc/css/aphront/lightbox-attachment.css' => '7acac05d', 'rsrc/css/aphront/list-filter-view.css' => '5d6f0526', 'rsrc/css/aphront/multi-column.css' => 'fd18389d', @@ -245,7 +245,7 @@ return array( 'rsrc/externals/javelin/lib/URI.js' => 'c989ade3', 'rsrc/externals/javelin/lib/Vector.js' => '2caa8fb8', 'rsrc/externals/javelin/lib/WebSocket.js' => 'e292eaf4', - 'rsrc/externals/javelin/lib/Workflow.js' => '0eb34d1d', + 'rsrc/externals/javelin/lib/Workflow.js' => '1e911d0f', 'rsrc/externals/javelin/lib/__tests__/Cookie.js' => '5ed109e8', 'rsrc/externals/javelin/lib/__tests__/DOM.js' => 'c984504b', 'rsrc/externals/javelin/lib/__tests__/JSON.js' => '837a7d68', @@ -339,6 +339,7 @@ return array( 'rsrc/image/people/washington.png' => '40dd301c', 'rsrc/image/phrequent_active.png' => 'a466a8ed', 'rsrc/image/phrequent_inactive.png' => 'bfc15a69', + 'rsrc/image/resize.png' => 'fd476de4', 'rsrc/image/sprite-login-X2.png' => 'e3991e37', 'rsrc/image/sprite-login.png' => '03d5af29', 'rsrc/image/sprite-menu-X2.png' => 'cfd8fca5', @@ -530,7 +531,7 @@ return array( 'almanac-css' => 'dbb9b3af', 'aphront-bars' => '231ac33c', 'aphront-dark-console-css' => 'f54bf286', - 'aphront-dialog-view-css' => 'b4334e08', + 'aphront-dialog-view-css' => '913c172e', 'aphront-list-filter-view-css' => '5d6f0526', 'aphront-multi-column-view-css' => 'fd18389d', 'aphront-panel-view-css' => '8427b78d', @@ -749,7 +750,7 @@ return array( 'javelin-workboard-card' => 'c587b80f', 'javelin-workboard-column' => 'bae58312', 'javelin-workboard-controller' => '55baf5ed', - 'javelin-workflow' => '0eb34d1d', + 'javelin-workflow' => '1e911d0f', 'lightbox-attachment-css' => '7acac05d', 'maniphest-batch-editor' => 'b0f0b6d5', 'maniphest-report-css' => '9b9580b7', @@ -981,17 +982,6 @@ return array( 'javelin-dom', 'javelin-router', ), - '0eb34d1d' => array( - 'javelin-stratcom', - 'javelin-request', - 'javelin-dom', - 'javelin-vector', - 'javelin-install', - 'javelin-util', - 'javelin-mask', - 'javelin-uri', - 'javelin-routable', - ), '0f764c35' => array( 'javelin-install', 'javelin-util', @@ -1071,6 +1061,17 @@ return array( 'javelin-dom', 'javelin-reactor-dom', ), + '1e911d0f' => array( + 'javelin-stratcom', + 'javelin-request', + 'javelin-dom', + 'javelin-vector', + 'javelin-install', + 'javelin-util', + 'javelin-mask', + 'javelin-uri', + 'javelin-routable', + ), '21ba5861' => array( 'javelin-behavior', 'javelin-dom', diff --git a/src/applications/typeahead/controller/PhabricatorTypeaheadModularDatasourceController.php b/src/applications/typeahead/controller/PhabricatorTypeaheadModularDatasourceController.php index 569b1d088e..fd1473aee9 100644 --- a/src/applications/typeahead/controller/PhabricatorTypeaheadModularDatasourceController.php +++ b/src/applications/typeahead/controller/PhabricatorTypeaheadModularDatasourceController.php @@ -250,6 +250,8 @@ final class PhabricatorTypeaheadModularDatasourceController ->setRenderDialogAsDiv(true) ->setTitle($source->getBrowseTitle()) ->appendChild($browser) + ->setResizeX(true) + ->setResizeY($frame_id) ->addFooter($function_help) ->addCancelButton('/', pht('Close')); } diff --git a/src/view/AphrontDialogView.php b/src/view/AphrontDialogView.php index 218839ef6e..4616393813 100644 --- a/src/view/AphrontDialogView.php +++ b/src/view/AphrontDialogView.php @@ -24,6 +24,8 @@ final class AphrontDialogView private $flush; private $validationException; private $objectList; + private $resizeX; + private $resizeY; const WIDTH_DEFAULT = 'default'; @@ -72,6 +74,24 @@ final class AphrontDialogView return $this->shortTitle; } + public function setResizeY($resize_y) { + $this->resizeY = $resize_y; + return $this; + } + + public function getResizeY() { + return $this->resizeY; + } + + public function setResizeX($resize_x) { + $this->resizeX = $resize_x; + return $this; + } + + public function getResizeX() { + return $this->resizeX; + } + public function addSubmitButton($text = null) { if (!$text) { $text = pht('Okay'); @@ -347,6 +367,20 @@ final class AphrontDialogView $this->footers); } + $resize = null; + if ($this->resizeX || $this->resizeY) { + $resize = javelin_tag( + 'div', + array( + 'class' => 'aphront-dialog-resize', + 'sigil' => 'jx-dialog-resize', + 'meta' => array( + 'resizeX' => $this->resizeX, + 'resizeY' => $this->resizeY, + ), + )); + } + $tail = null; if ($buttons || $footer) { $tail = phutil_tag( @@ -357,6 +391,7 @@ final class AphrontDialogView array( $buttons, $footer, + $resize, )); } diff --git a/webroot/rsrc/css/aphront/dialog-view.css b/webroot/rsrc/css/aphront/dialog-view.css index 8909368beb..7328cda5ea 100644 --- a/webroot/rsrc/css/aphront/dialog-view.css +++ b/webroot/rsrc/css/aphront/dialog-view.css @@ -48,6 +48,7 @@ .aphront-dialog-tail { border: none; + position: relative; background: {$lightgreybackground}; padding: 8px 16px; border-top: 1px solid {$thinblueborder}; @@ -55,6 +56,23 @@ border-bottom-right-radius: 3px; } +.device .aphront-dialog-resize { + /* No resizing on devices. */ + display: none; +} + +.aphront-dialog-resize { + position: absolute; + right: -4px; + bottom: -4px; + width: 18px; + height: 18px; + background-image: url(/rsrc/image/resize.png); + background-size: 100%; + cursor: nwse-resize; + pointer-events: all; +} + .aphront-dialog-foot { padding: 6px 0; float: left; diff --git a/webroot/rsrc/externals/javelin/lib/Workflow.js b/webroot/rsrc/externals/javelin/lib/Workflow.js index 2ee7ef1ff0..7f0818d4e0 100644 --- a/webroot/rsrc/externals/javelin/lib/Workflow.js +++ b/webroot/rsrc/externals/javelin/lib/Workflow.js @@ -157,6 +157,80 @@ JX.install('Workflow', { _getActiveWorkflow : function() { var stack = JX.Workflow._stack; return stack[stack.length - 1]; + }, + + _onresizestart: function(e) { + var self = JX.Workflow; + if (self._resizing) { + return; + } + + var workflow = self._getActiveWorkflow(); + if (!workflow) { + return; + } + + e.kill(); + + var form = JX.DOM.find(workflow._root, 'div', 'jx-dialog'); + var resize = e.getNodeData('jx-dialog-resize'); + var node_y = JX.$(resize.resizeY); + + var dim = JX.Vector.getDim(form); + dim.y = JX.Vector.getDim(node_y).y; + + if (!form._minimumSize) { + form._minimumSize = dim; + } + + self._resizing = { + min: form._minimumSize, + form: form, + startPos: JX.$V(e), + startDim: dim, + resizeY: node_y, + resizeX: resize.resizeX + }; + }, + + _onmousemove: function(e) { + var self = JX.Workflow; + if (!self._resizing) { + return; + } + + var spec = self._resizing; + var form = spec.form; + var min = spec.min; + + var delta = JX.$V(e).add(-spec.startPos.x, -spec.startPos.y); + var src_dim = spec.startDim; + var dst_dim = JX.$V(src_dim.x + delta.x, src_dim.y + delta.y); + + if (dst_dim.x < min.x) { + dst_dim.x = min.x; + } + + if (dst_dim.y < min.y) { + dst_dim.y = min.y; + } + + if (spec.resizeX) { + JX.$V(dst_dim.x, null).setDim(form); + } + + if (spec.resizeY) { + JX.$V(null, dst_dim.y).setDim(spec.resizeY); + } + }, + + _onmouseup: function() { + var self = JX.Workflow; + if (!self._resizing) { + return; + } + + self._resizing = false; } }, @@ -220,6 +294,12 @@ JX.install('Workflow', { [], JX.Workflow._onsyntheticsubmit); + JX.DOM.listen( + this._root, + 'mousedown', + 'jx-dialog-resize', + JX.Workflow._onresizestart); + // Note that even in the presence of a content frame, we're doing // everything here at top level: dialogs are fully modal and cover // the entire window. @@ -413,6 +493,9 @@ JX.install('Workflow', { } JX.Stratcom.listen('keydown', null, close_dialog_when_user_presses_escape); + + JX.Stratcom.listen('mousemove', null, JX.Workflow._onmousemove); + JX.Stratcom.listen('mouseup', null, JX.Workflow._onmouseup); } }); diff --git a/webroot/rsrc/image/resize.png b/webroot/rsrc/image/resize.png new file mode 100644 index 0000000000..da44a55cd1 Binary files /dev/null and b/webroot/rsrc/image/resize.png differ