Index: src/__celerity_resource_map__.php =================================================================== --- src/__celerity_resource_map__.php +++ src/__celerity_resource_map__.php @@ -2265,6 +2265,20 @@ ), 'disk' => '/rsrc/js/application/pholio/behavior-pholio-mock-view.js', ), + 'javelin-behavior-policy-control' => + array( + 'uri' => '/res/afc2c3fc/rsrc/js/application/policy/behavior-policy-control.js', + 'type' => 'js', + 'requires' => + array( + 0 => 'javelin-behavior', + 1 => 'javelin-dom', + 2 => 'javelin-util', + 3 => 'phabricator-dropdown-menu', + 4 => 'phabricator-menu-item', + ), + 'disk' => '/rsrc/js/application/policy/behavior-policy-control.js', + ), 'javelin-behavior-policy-rule-editor' => array( 'uri' => '/res/4ae4249d/rsrc/js/application/policy/behavior-policy-rule-editor.js', @@ -3141,7 +3155,7 @@ ), 'phabricator-dropdown-menu' => array( - 'uri' => '/res/a248b7f4/rsrc/js/core/DropdownMenu.js', + 'uri' => '/res/9e33be73/rsrc/js/core/DropdownMenu.js', 'type' => 'js', 'requires' => array( @@ -3742,7 +3756,7 @@ ), 'phui-button-css' => array( - 'uri' => '/res/3718b375/rsrc/css/phui/phui-button.css', + 'uri' => '/res/c18af87b/rsrc/css/phui/phui-button.css', 'type' => 'css', 'requires' => array( @@ -4220,7 +4234,7 @@ ), array( 'packages' => array( - '09637a26' => + 'a4d97d37' => array( 'name' => 'core.pkg.css', 'symbols' => @@ -4269,10 +4283,10 @@ 41 => 'phabricator-tag-view-css', 42 => 'phui-list-view-css', ), - 'uri' => '/res/pkg/09637a26/core.pkg.css', + 'uri' => '/res/pkg/a4d97d37/core.pkg.css', 'type' => 'css', ), - '64eeda79' => + '4e506e2b' => array( 'name' => 'core.pkg.js', 'symbols' => @@ -4317,7 +4331,7 @@ 37 => 'javelin-color', 38 => 'javelin-fx', ), - 'uri' => '/res/pkg/64eeda79/core.pkg.js', + 'uri' => '/res/pkg/4e506e2b/core.pkg.js', 'type' => 'js', ), '4ccfeb47' => @@ -4461,15 +4475,15 @@ ), 'reverse' => array( - 'aphront-dialog-view-css' => '09637a26', - 'aphront-error-view-css' => '09637a26', - 'aphront-list-filter-view-css' => '09637a26', - 'aphront-pager-view-css' => '09637a26', - 'aphront-panel-view-css' => '09637a26', - 'aphront-table-view-css' => '09637a26', - 'aphront-tokenizer-control-css' => '09637a26', - 'aphront-tooltip-css' => '09637a26', - 'aphront-typeahead-control-css' => '09637a26', + 'aphront-dialog-view-css' => 'a4d97d37', + 'aphront-error-view-css' => 'a4d97d37', + 'aphront-list-filter-view-css' => 'a4d97d37', + 'aphront-pager-view-css' => 'a4d97d37', + 'aphront-panel-view-css' => 'a4d97d37', + 'aphront-table-view-css' => 'a4d97d37', + 'aphront-tokenizer-control-css' => 'a4d97d37', + 'aphront-tooltip-css' => 'a4d97d37', + 'aphront-typeahead-control-css' => 'a4d97d37', 'differential-changeset-view-css' => '4dc2311c', 'differential-core-view-css' => '4dc2311c', 'differential-inline-comment-editor' => '5e9e5c4e', @@ -4483,18 +4497,18 @@ 'differential-table-of-contents-css' => '4dc2311c', 'diffusion-commit-view-css' => 'c8ce2d88', 'diffusion-icons-css' => 'c8ce2d88', - 'global-drag-and-drop-css' => '09637a26', + 'global-drag-and-drop-css' => 'a4d97d37', 'inline-comment-summary-css' => '4dc2311c', - 'javelin-aphlict' => '64eeda79', + 'javelin-aphlict' => '4e506e2b', 'javelin-behavior' => '9564fa17', - 'javelin-behavior-aphlict-dropdown' => '64eeda79', - 'javelin-behavior-aphlict-listen' => '64eeda79', - 'javelin-behavior-aphront-basic-tokenizer' => '64eeda79', + 'javelin-behavior-aphlict-dropdown' => '4e506e2b', + 'javelin-behavior-aphlict-listen' => '4e506e2b', + 'javelin-behavior-aphront-basic-tokenizer' => '4e506e2b', 'javelin-behavior-aphront-drag-and-drop-textarea' => '5e9e5c4e', - 'javelin-behavior-aphront-form-disable-on-submit' => '64eeda79', + 'javelin-behavior-aphront-form-disable-on-submit' => '4e506e2b', 'javelin-behavior-audit-preview' => '96909266', 'javelin-behavior-dark-console' => '4ccfeb47', - 'javelin-behavior-device' => '64eeda79', + 'javelin-behavior-device' => '4e506e2b', 'javelin-behavior-differential-accept-with-errors' => '5e9e5c4e', 'javelin-behavior-differential-add-reviewers-and-ccs' => '5e9e5c4e', 'javelin-behavior-differential-comment-jump' => '5e9e5c4e', @@ -4510,37 +4524,37 @@ 'javelin-behavior-diffusion-commit-graph' => '96909266', 'javelin-behavior-diffusion-pull-lastmodified' => '96909266', 'javelin-behavior-error-log' => '4ccfeb47', - 'javelin-behavior-global-drag-and-drop' => '64eeda79', - 'javelin-behavior-history-install' => '64eeda79', - 'javelin-behavior-konami' => '64eeda79', - 'javelin-behavior-lightbox-attachments' => '64eeda79', + 'javelin-behavior-global-drag-and-drop' => '4e506e2b', + 'javelin-behavior-history-install' => '4e506e2b', + 'javelin-behavior-konami' => '4e506e2b', + 'javelin-behavior-lightbox-attachments' => '4e506e2b', 'javelin-behavior-load-blame' => '5e9e5c4e', 'javelin-behavior-maniphest-batch-selector' => '0a694954', 'javelin-behavior-maniphest-subpriority-editor' => '0a694954', 'javelin-behavior-maniphest-transaction-controls' => '0a694954', 'javelin-behavior-maniphest-transaction-expand' => '0a694954', 'javelin-behavior-maniphest-transaction-preview' => '0a694954', - 'javelin-behavior-phabricator-active-nav' => '64eeda79', - 'javelin-behavior-phabricator-autofocus' => '64eeda79', - 'javelin-behavior-phabricator-gesture' => '64eeda79', - 'javelin-behavior-phabricator-hovercards' => '64eeda79', - 'javelin-behavior-phabricator-keyboard-shortcuts' => '64eeda79', - 'javelin-behavior-phabricator-nav' => '64eeda79', + 'javelin-behavior-phabricator-active-nav' => '4e506e2b', + 'javelin-behavior-phabricator-autofocus' => '4e506e2b', + 'javelin-behavior-phabricator-gesture' => '4e506e2b', + 'javelin-behavior-phabricator-hovercards' => '4e506e2b', + 'javelin-behavior-phabricator-keyboard-shortcuts' => '4e506e2b', + 'javelin-behavior-phabricator-nav' => '4e506e2b', 'javelin-behavior-phabricator-object-selector' => '5e9e5c4e', - 'javelin-behavior-phabricator-oncopy' => '64eeda79', - 'javelin-behavior-phabricator-remarkup-assist' => '64eeda79', - 'javelin-behavior-phabricator-reveal-content' => '64eeda79', - 'javelin-behavior-phabricator-search-typeahead' => '64eeda79', - 'javelin-behavior-phabricator-tooltips' => '64eeda79', - 'javelin-behavior-phabricator-watch-anchor' => '64eeda79', - 'javelin-behavior-refresh-csrf' => '64eeda79', + 'javelin-behavior-phabricator-oncopy' => '4e506e2b', + 'javelin-behavior-phabricator-remarkup-assist' => '4e506e2b', + 'javelin-behavior-phabricator-reveal-content' => '4e506e2b', + 'javelin-behavior-phabricator-search-typeahead' => '4e506e2b', + 'javelin-behavior-phabricator-tooltips' => '4e506e2b', + 'javelin-behavior-phabricator-watch-anchor' => '4e506e2b', + 'javelin-behavior-refresh-csrf' => '4e506e2b', 'javelin-behavior-repository-crossreference' => '5e9e5c4e', - 'javelin-behavior-toggle-class' => '64eeda79', - 'javelin-behavior-workflow' => '64eeda79', - 'javelin-color' => '64eeda79', + 'javelin-behavior-toggle-class' => '4e506e2b', + 'javelin-behavior-workflow' => '4e506e2b', + 'javelin-color' => '4e506e2b', 'javelin-dom' => '9564fa17', 'javelin-event' => '9564fa17', - 'javelin-fx' => '64eeda79', + 'javelin-fx' => '4e506e2b', 'javelin-history' => '9564fa17', 'javelin-install' => '9564fa17', 'javelin-json' => '9564fa17', @@ -4558,56 +4572,56 @@ 'javelin-util' => '9564fa17', 'javelin-vector' => '9564fa17', 'javelin-workflow' => '9564fa17', - 'lightbox-attachment-css' => '09637a26', + 'lightbox-attachment-css' => 'a4d97d37', 'maniphest-task-summary-css' => '49898640', - 'phabricator-action-list-view-css' => '09637a26', - 'phabricator-application-launch-view-css' => '09637a26', - 'phabricator-busy' => '64eeda79', + 'phabricator-action-list-view-css' => 'a4d97d37', + 'phabricator-application-launch-view-css' => 'a4d97d37', + 'phabricator-busy' => '4e506e2b', 'phabricator-content-source-view-css' => '4dc2311c', - 'phabricator-core-css' => '09637a26', - 'phabricator-crumbs-view-css' => '09637a26', + 'phabricator-core-css' => 'a4d97d37', + 'phabricator-crumbs-view-css' => 'a4d97d37', 'phabricator-drag-and-drop-file-upload' => '5e9e5c4e', - 'phabricator-dropdown-menu' => '64eeda79', - 'phabricator-file-upload' => '64eeda79', - 'phabricator-filetree-view-css' => '09637a26', - 'phabricator-flag-css' => '09637a26', - 'phabricator-hovercard' => '64eeda79', - 'phabricator-jump-nav' => '09637a26', - 'phabricator-keyboard-shortcut' => '64eeda79', - 'phabricator-keyboard-shortcut-manager' => '64eeda79', - 'phabricator-main-menu-view' => '09637a26', - 'phabricator-menu-item' => '64eeda79', - 'phabricator-nav-view-css' => '09637a26', - 'phabricator-notification' => '64eeda79', - 'phabricator-notification-css' => '09637a26', - 'phabricator-notification-menu-css' => '09637a26', + 'phabricator-dropdown-menu' => '4e506e2b', + 'phabricator-file-upload' => '4e506e2b', + 'phabricator-filetree-view-css' => 'a4d97d37', + 'phabricator-flag-css' => 'a4d97d37', + 'phabricator-hovercard' => '4e506e2b', + 'phabricator-jump-nav' => 'a4d97d37', + 'phabricator-keyboard-shortcut' => '4e506e2b', + 'phabricator-keyboard-shortcut-manager' => '4e506e2b', + 'phabricator-main-menu-view' => 'a4d97d37', + 'phabricator-menu-item' => '4e506e2b', + 'phabricator-nav-view-css' => 'a4d97d37', + 'phabricator-notification' => '4e506e2b', + 'phabricator-notification-css' => 'a4d97d37', + 'phabricator-notification-menu-css' => 'a4d97d37', 'phabricator-object-selector-css' => '4dc2311c', - 'phabricator-phtize' => '64eeda79', - 'phabricator-prefab' => '64eeda79', + 'phabricator-phtize' => '4e506e2b', + 'phabricator-prefab' => '4e506e2b', 'phabricator-project-tag-css' => '49898640', - 'phabricator-remarkup-css' => '09637a26', + 'phabricator-remarkup-css' => 'a4d97d37', 'phabricator-shaped-request' => '5e9e5c4e', - 'phabricator-side-menu-view-css' => '09637a26', - 'phabricator-standard-page-view' => '09637a26', - 'phabricator-tag-view-css' => '09637a26', - 'phabricator-textareautils' => '64eeda79', - 'phabricator-tooltip' => '64eeda79', - 'phabricator-transaction-view-css' => '09637a26', - 'phabricator-zindex-css' => '09637a26', - 'phui-button-css' => '09637a26', - 'phui-form-css' => '09637a26', - 'phui-form-view-css' => '09637a26', - 'phui-header-view-css' => '09637a26', - 'phui-icon-view-css' => '09637a26', - 'phui-list-view-css' => '09637a26', - 'phui-object-item-list-view-css' => '09637a26', - 'phui-property-list-view-css' => '09637a26', - 'phui-spacing-css' => '09637a26', - 'sprite-apps-large-css' => '09637a26', - 'sprite-gradient-css' => '09637a26', - 'sprite-icons-css' => '09637a26', - 'sprite-menu-css' => '09637a26', - 'sprite-status-css' => '09637a26', - 'syntax-highlighting-css' => '09637a26', + 'phabricator-side-menu-view-css' => 'a4d97d37', + 'phabricator-standard-page-view' => 'a4d97d37', + 'phabricator-tag-view-css' => 'a4d97d37', + 'phabricator-textareautils' => '4e506e2b', + 'phabricator-tooltip' => '4e506e2b', + 'phabricator-transaction-view-css' => 'a4d97d37', + 'phabricator-zindex-css' => 'a4d97d37', + 'phui-button-css' => 'a4d97d37', + 'phui-form-css' => 'a4d97d37', + 'phui-form-view-css' => 'a4d97d37', + 'phui-header-view-css' => 'a4d97d37', + 'phui-icon-view-css' => 'a4d97d37', + 'phui-list-view-css' => 'a4d97d37', + 'phui-object-item-list-view-css' => 'a4d97d37', + 'phui-property-list-view-css' => 'a4d97d37', + 'phui-spacing-css' => 'a4d97d37', + 'sprite-apps-large-css' => 'a4d97d37', + 'sprite-gradient-css' => 'a4d97d37', + 'sprite-icons-css' => 'a4d97d37', + 'sprite-menu-css' => 'a4d97d37', + 'sprite-status-css' => 'a4d97d37', + 'syntax-highlighting-css' => 'a4d97d37', ), )); Index: src/applications/policy/constants/PhabricatorPolicyType.php =================================================================== --- src/applications/policy/constants/PhabricatorPolicyType.php +++ src/applications/policy/constants/PhabricatorPolicyType.php @@ -18,9 +18,9 @@ public static function getPolicyTypeName($type) { switch ($type) { case self::TYPE_GLOBAL: - return pht('Global Policies'); + return pht('Basic Policies'); case self::TYPE_PROJECT: - return pht('Members of Project'); + return pht('Members of Project...'); case self::TYPE_MASKED: default: return pht('Other Policies'); Index: src/view/form/control/AphrontFormPolicyControl.php =================================================================== --- src/view/form/control/AphrontFormPolicyControl.php +++ src/view/form/control/AphrontFormPolicyControl.php @@ -48,8 +48,11 @@ } } - $type_name = PhabricatorPolicyType::getPolicyTypeName($policy->getType()); - $options[$type_name][$policy->getPHID()] = $policy->getFullName(); + $options[$policy->getType()][$policy->getPHID()] = array( + 'name' => phutil_utf8_shorten($policy->getName(), 28), + 'full' => $policy->getName(), + 'icon' => $policy->getIcon(), + ); } return $options; } @@ -69,6 +72,88 @@ } $this->setValue($policy); + + $control_id = celerity_generate_unique_node_id(); + $input_id = celerity_generate_unique_node_id(); + + $caret = phutil_tag( + 'span', + array( + 'class' => 'caret', + )); + + $input = phutil_tag( + 'input', + array( + 'type' => 'hidden', + 'id' => $input_id, + 'name' => $this->getName(), + 'value' => $this->getValue(), + )); + + $options = $this->getOptions(); + + $order = array(); + $labels = array(); + foreach ($options as $key => $values) { + $order[$key] = array_keys($values); + $labels[$key] = PhabricatorPolicyType::getPolicyTypeName($key); + } + + $flat_options = array_mergev($options); + + $icons = array(); + foreach (igroup($flat_options, 'icon') as $icon => $ignored) { + $icons[$icon] = id(new PHUIIconView()) + ->setSpriteSheet(PHUIIconView::SPRITE_STATUS) + ->setSpriteIcon($icon); + } + + + Javelin::initBehavior( + 'policy-control', + array( + 'controlID' => $control_id, + 'inputID' => $input_id, + 'options' => $flat_options, + 'groups' => array_keys($options), + 'order' => $order, + 'icons' => $icons, + 'labels' => $labels, + )); + + $selected = $flat_options[$this->getValue()]; + + return phutil_tag( + 'div', + array( + ), + array( + javelin_tag( + 'a', + array( + 'class' => 'grey button dropdown has-icon policy-control', + 'href' => '#', + 'mustcapture' => true, + 'sigil' => 'policy-control', + 'id' => $control_id, + ), + array( + $caret, + javelin_tag( + 'span', + array( + 'sigil' => 'policy-label', + 'class' => 'phui-button-text', + ), + array( + $icons[$selected['icon']], + $selected['name'], + )), + )), + $input, + )); + return AphrontFormSelectControl::renderSelectTag( $this->getValue(), $this->getOptions(), Index: webroot/rsrc/css/phui/phui-button.css =================================================================== --- webroot/rsrc/css/phui/phui-button.css +++ webroot/rsrc/css/phui/phui-button.css @@ -170,6 +170,28 @@ color: {$lightgreytext}; } +.dropdown-menu-frame span.phui-icon-view { + display: inline-block; + padding: 0; + margin: 2px 8px -2px 4px; +} + +a.policy-control { + width: 240px; + text-align: left; +} + +a.policy-control .caret { + float: right; +} + +a.policy-control span.phui-icon-view { + /* NOTE: Nudge these icons a little bit. Should this be for all + dropdown buttons? */ + top: 4px; + left: 7px; +} + .dropdown-menu-frame a:hover { background: #005588; background-image: linear-gradient(to bottom, #3b86c4, #2b628f); Index: webroot/rsrc/js/application/policy/behavior-policy-control.js =================================================================== --- /dev/null +++ webroot/rsrc/js/application/policy/behavior-policy-control.js @@ -0,0 +1,50 @@ +/** + * @provides javelin-behavior-policy-control + * @requires javelin-behavior + * javelin-dom + * javelin-util + * phabricator-dropdown-menu + * phabricator-menu-item + * @javelin + */ +JX.behavior('policy-control', function(config) { + var control = JX.$(config.controlID); + var input = JX.$(config.inputID); + + var menu = new JX.PhabricatorDropdownMenu(control) + .setWidth(260); + + menu.toggleAlignDropdownRight(false); + + menu.listen('open', function() { + menu.clear(); + + for (var ii = 0; ii < config.groups.length; ii++) { + var group = config.groups[ii]; + + var header = new JX.PhabricatorMenuItem(config.labels[group]); + header.setDisabled(true); + menu.addItem(header); + + for (var jj = 0; jj < config.order[group].length; jj++) { + var phid = config.order[group][jj]; + var option = config.options[phid]; + + var render = [JX.$H(config.icons[option.icon]), option.name]; + + var item = new JX.PhabricatorMenuItem( + render, + JX.bind(null, function(phid, render) { + JX.DOM.setContent( + JX.DOM.find(control, 'span', 'policy-label'), + render); + input.value = phid; + }, phid, render)); + + menu.addItem(item); + } + } + + }); + +}); Index: webroot/rsrc/js/core/DropdownMenu.js =================================================================== --- webroot/rsrc/js/core/DropdownMenu.js +++ webroot/rsrc/js/core/DropdownMenu.js @@ -33,6 +33,11 @@ null, JX.bind(this, this._onclickglobal)); + JX.Stratcom.listen( + 'resize', + null, + JX.bind(this, this._onresize)); + JX.PhabricatorDropdownMenu.listen( 'open', JX.bind(this, this.close)); @@ -40,6 +45,10 @@ events : ['open'], + properties : { + width : null + }, + members : { _node : null, _menu : null, @@ -78,6 +87,11 @@ this._hide(); }, + clear : function() { + this._items = []; + return this; + }, + addItem : function(item) { if (__DEV__) { if (!(item instanceof JX.PhabricatorMenuItem)) { @@ -132,6 +146,20 @@ _show : function() { document.body.appendChild(this._menu); + if (this.getWidth()) { + new JX.Vector(this.getWidth(), null).setDim(this._menu); + } + + this._onresize(); + + JX.DOM.alterClass(this._node, 'dropdown-open', true); + }, + + _onresize : function() { + if (!this._open) { + return; + } + var m = JX.Vector.getDim(this._menu); var v = JX.$V(this._node); @@ -143,8 +171,6 @@ v = v.add(0, d.y); } v.setPos(this._menu); - - JX.DOM.alterClass(this._node, 'dropdown-open', true); }, _hide : function() {