Commit fef2cdab authored by epriestley's avatar epriestley
Browse files

Add a "FormationView" to support dynamic flank panels

Summary:
Ref T13516. Currently, the "File Tree" element is a semi-dynamic side panel that's implemented as a special mode of a side nav panel.

This implementation is fairly clunky, and arose from organic growth out of the side nav. As such, it has some weird behaviors, doesn't have builtin support for show/hide, and can't generalize easily.

Introduce a "FormationView" which supports loading a page up with piles of side panels in various modes.

Test Plan: No callers and no user-visible impact.

Maniphest Tasks: T13516

Differential Revision: https://secure.phabricator.com/D21150
parent ef69c796
......@@ -155,6 +155,7 @@ return array(
'rsrc/css/phui/phui-fontkit.css' => '1ec937e5',
'rsrc/css/phui/phui-form-view.css' => '01b796c0',
'rsrc/css/phui/phui-form.css' => '1f177cb7',
'rsrc/css/phui/phui-formation-view.css' => 'aec68a01',
'rsrc/css/phui/phui-head-thing.css' => 'd7f293df',
'rsrc/css/phui/phui-header-view.css' => '36c86a58',
'rsrc/css/phui/phui-hovercard.css' => '6ca90fa0',
......@@ -519,6 +520,7 @@ return array(
'rsrc/js/phui/behavior-phui-submenu.js' => 'b5e9bff9',
'rsrc/js/phui/behavior-phui-tab-group.js' => '242aa08b',
'rsrc/js/phui/behavior-phui-timer-control.js' => 'f84bcbf4',
'rsrc/js/phui/behavior-phuix-formation-view.js' => '1a12beef',
'rsrc/js/phuix/PHUIXActionListView.js' => 'c68f183f',
'rsrc/js/phuix/PHUIXActionView.js' => 'aaa08f3b',
'rsrc/js/phuix/PHUIXAutocomplete.js' => '2fbe234d',
......@@ -526,6 +528,9 @@ return array(
'rsrc/js/phuix/PHUIXDropdownMenu.js' => '7acfd98b',
'rsrc/js/phuix/PHUIXExample.js' => 'c2c500a7',
'rsrc/js/phuix/PHUIXFormControl.js' => '38c1f3fb',
'rsrc/js/phuix/PHUIXFormationColumnView.js' => '08fc09e9',
'rsrc/js/phuix/PHUIXFormationFlankView.js' => '6648270a',
'rsrc/js/phuix/PHUIXFormationView.js' => '0113c54c',
'rsrc/js/phuix/PHUIXIconView.js' => 'a5257c4e',
),
'symbols' => array(
......@@ -667,6 +672,7 @@ return array(
'javelin-behavior-phui-tab-group' => '242aa08b',
'javelin-behavior-phui-timer-control' => 'f84bcbf4',
'javelin-behavior-phuix-example' => 'c2c500a7',
'javelin-behavior-phuix-formation-view' => '1a12beef',
'javelin-behavior-policy-control' => '0eaa33a9',
'javelin-behavior-policy-rule-editor' => '9347f172',
'javelin-behavior-project-boards' => '58cb6a88',
......@@ -844,6 +850,7 @@ return array(
'phui-fontkit-css' => '1ec937e5',
'phui-form-css' => '1f177cb7',
'phui-form-view-css' => '01b796c0',
'phui-formation-view-css' => 'aec68a01',
'phui-head-thing-view-css' => 'd7f293df',
'phui-header-view-css' => '36c86a58',
'phui-hovercard' => '074f0783',
......@@ -886,6 +893,9 @@ return array(
'phuix-button-view' => '55a24e84',
'phuix-dropdown-menu' => '7acfd98b',
'phuix-form-control-view' => '38c1f3fb',
'phuix-formation-column-view' => '08fc09e9',
'phuix-formation-flank-view' => '6648270a',
'phuix-formation-view' => '0113c54c',
'phuix-icon-view' => 'a5257c4e',
'policy-css' => 'ceb56a08',
'policy-edit-css' => '8794e2ed',
......@@ -912,6 +922,10 @@ return array(
'unhandled-exception-css' => '9ecfc00d',
),
'requires' => array(
'0113c54c' => array(
'javelin-install',
'javelin-dom',
),
'0116d3e8' => array(
'javelin-behavior',
'javelin-dom',
......@@ -984,6 +998,10 @@ return array(
'javelin-util',
'javelin-magical-init',
),
'08fc09e9' => array(
'javelin-install',
'javelin-dom',
),
'0922e81d' => array(
'herald-rule-editor',
'javelin-behavior',
......@@ -1036,6 +1054,12 @@ return array(
'16e97ebc' => array(
'javelin-dom',
),
'1a12beef' => array(
'javelin-behavior',
'phuix-formation-view',
'phuix-formation-column-view',
'phuix-formation-flank-view',
),
'1a844c06' => array(
'javelin-install',
'javelin-util',
......@@ -1520,6 +1544,10 @@ return array(
'javelin-stratcom',
'javelin-dom',
),
'6648270a' => array(
'javelin-install',
'javelin-dom',
),
'6a1583a8' => array(
'javelin-behavior',
'javelin-history',
......
......@@ -179,6 +179,7 @@ phutil_register_library_map(array(
'AphrontAccessDeniedQueryException' => 'infrastructure/storage/exception/AphrontAccessDeniedQueryException.php',
'AphrontAjaxResponse' => 'aphront/response/AphrontAjaxResponse.php',
'AphrontApplicationConfiguration' => 'aphront/configuration/AphrontApplicationConfiguration.php',
'AphrontAutoIDView' => 'view/AphrontAutoIDView.php',
'AphrontBarView' => 'view/widget/bars/AphrontBarView.php',
'AphrontBaseMySQLDatabaseConnection' => 'infrastructure/storage/connection/mysql/AphrontBaseMySQLDatabaseConnection.php',
'AphrontBoolHTTPParameterType' => 'aphront/httpparametertype/AphrontBoolHTTPParameterType.php',
......@@ -2035,6 +2036,14 @@ phutil_register_library_map(array(
'PHUIFormLayoutView' => 'view/form/PHUIFormLayoutView.php',
'PHUIFormNumberControl' => 'view/form/control/PHUIFormNumberControl.php',
'PHUIFormTimerControl' => 'view/form/control/PHUIFormTimerControl.php',
'PHUIFormationColumnDynamicView' => 'view/formation/PHUIFormationColumnDynamicView.php',
'PHUIFormationColumnItem' => 'view/formation/PHUIFormationColumnItem.php',
'PHUIFormationColumnView' => 'view/formation/PHUIFormationColumnView.php',
'PHUIFormationContentView' => 'view/formation/PHUIFormationContentView.php',
'PHUIFormationExpanderView' => 'view/formation/PHUIFormationExpanderView.php',
'PHUIFormationFlankView' => 'view/formation/PHUIFormationFlankView.php',
'PHUIFormationResizerView' => 'view/formation/PHUIFormationResizerView.php',
'PHUIFormationView' => 'view/formation/PHUIFormationView.php',
'PHUIHandleListView' => 'applications/phid/view/PHUIHandleListView.php',
'PHUIHandleTagListView' => 'applications/phid/view/PHUIHandleTagListView.php',
'PHUIHandleView' => 'applications/phid/view/PHUIHandleView.php',
......@@ -6193,6 +6202,7 @@ phutil_register_library_map(array(
'AphrontAccessDeniedQueryException' => 'AphrontQueryException',
'AphrontAjaxResponse' => 'AphrontResponse',
'AphrontApplicationConfiguration' => 'Phobject',
'AphrontAutoIDView' => 'AphrontView',
'AphrontBarView' => 'AphrontView',
'AphrontBaseMySQLDatabaseConnection' => 'AphrontDatabaseConnection',
'AphrontBoolHTTPParameterType' => 'AphrontHTTPParameterType',
......@@ -8315,6 +8325,14 @@ phutil_register_library_map(array(
'PHUIFormLayoutView' => 'AphrontView',
'PHUIFormNumberControl' => 'AphrontFormControl',
'PHUIFormTimerControl' => 'AphrontFormControl',
'PHUIFormationColumnDynamicView' => 'PHUIFormationColumnView',
'PHUIFormationColumnItem' => 'Phobject',
'PHUIFormationColumnView' => 'AphrontAutoIDView',
'PHUIFormationContentView' => 'PHUIFormationColumnView',
'PHUIFormationExpanderView' => 'AphrontAutoIDView',
'PHUIFormationFlankView' => 'PHUIFormationColumnDynamicView',
'PHUIFormationResizerView' => 'PHUIFormationColumnView',
'PHUIFormationView' => 'AphrontView',
'PHUIHandleListView' => 'AphrontTagView',
'PHUIHandleTagListView' => 'AphrontTagView',
'PHUIHandleView' => 'AphrontView',
<?php
abstract class AphrontAutoIDView
extends AphrontView {
private $id;
final public function getID() {
if (!$this->id) {
$this->id = celerity_generate_unique_node_id();
}
return $this->id;
}
}
<?php
abstract class PHUIFormationColumnDynamicView
extends PHUIFormationColumnView {
private $isVisible = true;
private $isResizable;
private $width;
public function setIsVisible($is_visible) {
$this->isVisible = $is_visible;
return $this;
}
public function getIsVisible() {
return $this->isVisible;
}
public function setIsResizable($is_resizable) {
$this->isResizable = $is_resizable;
return $this;
}
public function getIsResizable() {
return $this->isResizable;
}
public function setWidth($width) {
$this->width = $width;
return $this;
}
public function getWidth() {
return $this->width;
}
}
<?php
final class PHUIFormationColumnItem
extends Phobject {
private $id;
private $column;
private $controlItem;
private $resizerItem;
private $isRightAligned;
private $expander;
private $expanders = array();
public function getID() {
if (!$this->id) {
$this->id = celerity_generate_unique_node_id();
}
return $this->id;
}
public function setColumn(PHUIFormationColumnView $column) {
$this->column = $column;
return $this;
}
public function getColumn() {
return $this->column;
}
public function setControlItem(PHUIFormationColumnItem $control_item) {
$this->controlItem = $control_item;
return $this;
}
public function getControlItem() {
return $this->controlItem;
}
public function setIsRightAligned($is_right_aligned) {
$this->isRightAligned = $is_right_aligned;
return $this;
}
public function getIsRightAligned() {
return $this->isRightAligned;
}
public function setResizerItem(PHUIFormationColumnItem $resizer_item) {
$this->resizerItem = $resizer_item;
return $this;
}
public function getResizerItem() {
return $this->resizerItem;
}
public function setExpander(PHUIFormationExpanderView $expander) {
$this->expander = $expander;
return $this;
}
public function getExpander() {
return $this->expander;
}
public function appendExpander(PHUIFormationExpanderView $expander) {
$this->expanders[] = $expander;
return $this;
}
public function getExpanders() {
return $this->expanders;
}
public function newClientProperties() {
$expander_id = null;
$expander = $this->getExpander();
if ($expander) {
$expander_id = $expander->getID();
}
$resizer_details = null;
$resizer_item = $this->getResizerItem();
if ($resizer_item) {
$resizer_details = array(
'itemID' => $resizer_item->getID(),
'controlID' => $resizer_item->getColumn()->getID(),
);
}
$column = $this->getColumn();
$width = $column->getWidth();
if ($width !== null) {
$width = (int)$width;
}
$is_visible = (bool)$column->getIsVisible();
$is_right_aligned = $this->getIsRightAligned();
$column_details = $column->newClientProperties();
return array(
'itemID' => $this->getID(),
'width' => $width,
'isVisible' => $is_visible,
'isRightAligned' => $is_right_aligned,
'expanderID' => $expander_id,
'resizer' => $resizer_details,
'column' => $column_details,
);
}
}
<?php
abstract class PHUIFormationColumnView
extends AphrontAutoIDView {
private $item;
final public function setColumnItem(PHUIFormationColumnItem $item) {
$this->item = $item;
return $this;
}
final public function getColumnItem() {
return $this->item;
}
public function getWidth() {
return null;
}
public function getIsResizable() {
return false;
}
public function getIsVisible() {
return true;
}
public function getIsControlColumn() {
return false;
}
public function newClientProperties() {
return null;
}
}
<?php
final class PHUIFormationContentView
extends PHUIFormationColumnView {
public function getIsControlColumn() {
return true;
}
public function render() {
require_celerity_resource('phui-formation-view-css');
return phutil_tag(
'div',
array(
'class' => 'phui-formation-view-content',
),
$this->renderChildren());
}
}
<?php
final class PHUIFormationExpanderView
extends AphrontAutoIDView {
private $tooltip;
private $columnItem;
public function setTooltip($tooltip) {
$this->tooltip = $tooltip;
return $this;
}
public function getTooltip() {
return $this->tooltip;
}
public function setColumnItem($column_item) {
$this->columnItem = $column_item;
return $this;
}
public function getColumnItem() {
return $this->columnItem;
}
public function render() {
$classes = array();
$classes[] = 'phui-formation-view-expander';
$is_right = $this->getColumnItem()->getIsRightAligned();
if ($is_right) {
$icon = id(new PHUIIconView())
->setIcon('fa-chevron-left grey');
$classes[] = 'phui-formation-view-expander-right';
} else {
$icon = id(new PHUIIconView())
->setIcon('fa-chevron-right grey');
$classes[] = 'phui-formation-view-expander-left';
}
$icon_view = phutil_tag(
'div',
array(
'class' => 'phui-formation-view-expander-icon',
),
$icon);
return javelin_tag(
'div',
array(
'id' => $this->getID(),
'class' => implode(' ', $classes),
'sigil' => 'has-tooltip',
'style' => 'display: none',
'meta' => array(
'tip' => $this->getTooltip(),
'align' => 'E',
),
),
$icon_view);
}
}
<?php
final class PHUIFormationFlankView
extends PHUIFormationColumnDynamicView {
private $isFixed;
private $head;
private $body;
private $tail;
private $headID;
private $bodyID;
private $tailID;
private $headerText;
public function setIsFixed($fixed) {
$this->isFixed = $fixed;
return $this;
}
public function getIsFixed() {
return $this->isFixed;
}
public function setHead($head) {
$this->head = $head;
return $this;
}
public function setBody($body) {
$this->body = $body;
return $this;
}
public function setTail($tail) {
$this->tail = $tail;
return $this;
}
public function getHeadID() {
if (!$this->headID) {
$this->headID = celerity_generate_unique_node_id();
}
return $this->headID;
}
public function getBodyID() {
if (!$this->bodyID) {
$this->bodyID = celerity_generate_unique_node_id();
}
return $this->bodyID;
}
public function getTailID() {
if (!$this->tailID) {
$this->tailID = celerity_generate_unique_node_id();
}
return $this->tailID;
}
public function setHeaderText($header_text) {
$this->headerText = $header_text;
return $this;
}
public function getHeaderText() {
return $this->headerText;
}
public function newClientProperties() {
return array(
'type' => 'flank',
'nodeID' => $this->getID(),
'isFixed' => (bool)$this->getIsFixed(),
'headID' => $this->getHeadID(),
'bodyID' => $this->getBodyID(),
'tailID' => $this->getTailID(),
);
}
public function render() {
require_celerity_resource('phui-formation-view-css');
$width = $this->getWidth();
$style = array();
$style[] = sprintf('width: %dpx;', $width);
$classes = array();
$classes[] = 'phui-flank-view';
if ($this->getIsFixed()) {
$classes[] = 'phui-flank-view-fixed';
}
$head_id = $this->getHeadID();
$body_id = $this->getBodyID();
$tail_id = $this->getTailID();
$head_content = phutil_tag(
'div',
array(
'class' => 'phui-flank-header',
),
array(
phutil_tag(
'div',
array(
'class' => 'phui-flank-header-text',
),
$this->getHeaderText()),
$this->newHideButton(),
));
$content = phutil_tag(
'div',
array(
'id' => $this->getID(),
'class' => implode(' ', $classes),
'style' => implode(' ', $style),
),
array(
phutil_tag(
'div',
array(
'id' => $head_id,
'class' => 'phui-flank-view-head',
),
$head_content),
phutil_tag(
'div',
array(
'id' => $body_id,
'class' => 'phui-flank-view-body',
),
$this->getBody()),
phutil_tag(
'div',
array(
'id' => $tail_id,
'class' => 'phui-flank-view-tail',
),
$this->getTail()),
));
return $content;
}
private function newHideButton() {
$item = $this->getColumnItem();
$is_right = $item->getIsRightAligned();
$hide_classes = array();
$hide_classes[] = 'phui-flank-header-hide';
if ($is_right) {
$hide_icon = id(new PHUIIconView())
->setIcon('fa-chevron-right grey');
$hide_classes[] = 'phui-flank-header-hide-right';
} else {
$hide_icon = id(new PHUIIconView())
->setIcon('fa-chevron-left grey');
$hide_classes[] = 'phui-flank-header-hide-left';
}
return javelin_tag(
'div',
array(
'sigil' => 'phui-flank-header-hide',
'class' => implode(' ', $hide_classes),
),