From 683647f1fb9091b8928056d068be7bb954c127c9 Mon Sep 17 00:00:00 2001 From: epriestley Date: Tue, 30 May 2017 14:47:50 -0700 Subject: [PATCH] Add PHUIXButtonView and a UIExample Summary: Ref T12733. Ref M1476. This adds `PHUIXButtonView`, for client-side button rendering. It also adds a PHUIX example which renders the server and client versions of each component side-by-side so it's easier to see if they're messed up. Test Plan: {F4984128} Reviewers: chad Reviewed By: chad Maniphest Tasks: T12733 Differential Revision: https://secure.phabricator.com/D18051 --- resources/celerity/map.php | 13 ++ src/__phutil_library_map__.php | 2 + .../examples/PHUIXComponentsExample.php | 122 ++++++++++++++++++ webroot/rsrc/js/phuix/PHUIXButtonView.js | 109 ++++++++++++++++ webroot/rsrc/js/phuix/PHUIXExample.js | 65 ++++++++++ 5 files changed, 311 insertions(+) create mode 100644 src/applications/uiexample/examples/PHUIXComponentsExample.php create mode 100644 webroot/rsrc/js/phuix/PHUIXButtonView.js create mode 100644 webroot/rsrc/js/phuix/PHUIXExample.js diff --git a/resources/celerity/map.php b/resources/celerity/map.php index 56a38061a1..cbebfa5aef 100644 --- a/resources/celerity/map.php +++ b/resources/celerity/map.php @@ -523,7 +523,9 @@ return array( 'rsrc/js/phuix/PHUIXActionListView.js' => 'b5c256b8', 'rsrc/js/phuix/PHUIXActionView.js' => 'b3465b9b', 'rsrc/js/phuix/PHUIXAutocomplete.js' => 'f6699267', + 'rsrc/js/phuix/PHUIXButtonView.js' => 'da1c2a6b', 'rsrc/js/phuix/PHUIXDropdownMenu.js' => '8018ee50', + 'rsrc/js/phuix/PHUIXExample.js' => '68af71ca', 'rsrc/js/phuix/PHUIXFormControl.js' => '83e03671', 'rsrc/js/phuix/PHUIXIconView.js' => 'bff6884b', ), @@ -667,6 +669,7 @@ return array( 'javelin-behavior-phui-hovercards' => 'bcaccd64', 'javelin-behavior-phui-submenu' => 'a6f7a73b', 'javelin-behavior-phui-tab-group' => '0a0b10e9', + 'javelin-behavior-phuix-example' => '68af71ca', 'javelin-behavior-policy-control' => 'd0c516d5', 'javelin-behavior-policy-rule-editor' => '5e9f347c', 'javelin-behavior-project-boards' => '4250a34e', @@ -869,6 +872,7 @@ return array( 'phuix-action-list-view' => 'b5c256b8', 'phuix-action-view' => 'b3465b9b', 'phuix-autocomplete' => 'f6699267', + 'phuix-button-view' => 'da1c2a6b', 'phuix-dropdown-menu' => '8018ee50', 'phuix-form-control-view' => '83e03671', 'phuix-icon-view' => 'bff6884b', @@ -1371,6 +1375,11 @@ return array( '6882e80a' => array( 'javelin-dom', ), + '68af71ca' => array( + 'javelin-install', + 'javelin-dom', + 'phuix-button-view', + ), '69adf288' => array( 'javelin-install', ), @@ -1988,6 +1997,10 @@ return array( 'javelin-util', 'phabricator-shaped-request', ), + 'da1c2a6b' => array( + 'javelin-install', + 'javelin-dom', + ), 'de2e896f' => array( 'javelin-behavior', 'javelin-dom', diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index 5bf2681b1f..13e447c48d 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -1806,6 +1806,7 @@ phutil_register_library_map(array( 'PHUIUserAvailabilityView' => 'applications/calendar/view/PHUIUserAvailabilityView.php', 'PHUIWorkboardView' => 'view/phui/PHUIWorkboardView.php', 'PHUIWorkpanelView' => 'view/phui/PHUIWorkpanelView.php', + 'PHUIXComponentsExample' => 'applications/uiexample/examples/PHUIXComponentsExample.php', 'PassphraseAbstractKey' => 'applications/passphrase/keys/PassphraseAbstractKey.php', 'PassphraseConduitAPIMethod' => 'applications/passphrase/conduit/PassphraseConduitAPIMethod.php', 'PassphraseController' => 'applications/passphrase/controller/PassphraseController.php', @@ -6938,6 +6939,7 @@ phutil_register_library_map(array( 'PHUIUserAvailabilityView' => 'AphrontTagView', 'PHUIWorkboardView' => 'AphrontTagView', 'PHUIWorkpanelView' => 'AphrontTagView', + 'PHUIXComponentsExample' => 'PhabricatorUIExample', 'PassphraseAbstractKey' => 'Phobject', 'PassphraseConduitAPIMethod' => 'ConduitAPIMethod', 'PassphraseController' => 'PhabricatorController', diff --git a/src/applications/uiexample/examples/PHUIXComponentsExample.php b/src/applications/uiexample/examples/PHUIXComponentsExample.php new file mode 100644 index 0000000000..a5c76a1e77 --- /dev/null +++ b/src/applications/uiexample/examples/PHUIXComponentsExample.php @@ -0,0 +1,122 @@ + 'fa-rocket', + ), + array( + 'icon' => 'fa-cloud', + 'color' => 'indigo', + ), + ); + + foreach ($icons as $spec) { + $icon = new PHUIIconView(); + + $icon->setIcon(idx($spec, 'icon'), idx($spec, 'color')); + + $client_id = celerity_generate_unique_node_id(); + + $server_view = $icon; + $client_view = javelin_tag( + 'div', + array( + 'id' => $client_id, + )); + + Javelin::initBehavior( + 'phuix-example', + array( + 'type' => 'icon', + 'id' => $client_id, + 'spec' => $spec, + )); + + $content[] = id(new AphrontMultiColumnView()) + ->addColumn($server_view) + ->addColumn($client_view); + } + + + $buttons = array( + array( + 'text' => pht('Submit'), + ), + array( + 'text' => pht('Activate'), + 'icon' => 'fa-rocket', + ), + array( + 'type' => PHUIButtonView::BUTTONTYPE_SIMPLE, + 'text' => pht('3 / 5 Comments'), + 'icon' => 'fa-comment', + ), + array( + 'color' => PHUIButtonView::GREEN, + 'text' => pht('Environmental!'), + ), + ); + + foreach ($buttons as $spec) { + $button = new PHUIButtonView(); + + if (idx($spec, 'text') !== null) { + $button->setText($spec['text']); + } + + if (idx($spec, 'icon') !== null) { + $button->setIcon($spec['icon']); + } + + if (idx($spec, 'type') !== null) { + $button->setButtonType($spec['type']); + } + + if (idx($spec, 'color') !== null) { + $button->setColor($spec['color']); + } + + $client_id = celerity_generate_unique_node_id(); + + $server_view = $button; + $client_view = javelin_tag( + 'div', + array( + 'id' => $client_id, + )); + + Javelin::initBehavior( + 'phuix-example', + array( + 'type' => 'button', + 'id' => $client_id, + 'spec' => $spec, + )); + + $content[] = id(new AphrontMultiColumnView()) + ->addColumn($server_view) + ->addColumn($client_view); + } + + return id(new PHUIBoxView()) + ->appendChild($content) + ->addMargin(PHUI::MARGIN_LARGE); + } +} diff --git a/webroot/rsrc/js/phuix/PHUIXButtonView.js b/webroot/rsrc/js/phuix/PHUIXButtonView.js new file mode 100644 index 0000000000..9fbefb8b1a --- /dev/null +++ b/webroot/rsrc/js/phuix/PHUIXButtonView.js @@ -0,0 +1,109 @@ +/** + * @provides phuix-button-view + * @requires javelin-install + * javelin-dom + */ +JX.install('PHUIXButtonView', { + + statics: { + BUTTONTYPE_DEFAULT: 'buttontype.default', + BUTTONTYPE_SIMPLE: 'buttontype.simple' + }, + + members: { + _node: null, + _textNode: null, + + _iconView: null, + _color: null, + _buttonType: null, + + setIcon: function(icon) { + this.getIconView().setIcon(icon); + return this; + }, + + getIconView: function() { + if (!this._iconView) { + this._iconView = new JX.PHUIXIconView(); + this._redraw(); + } + return this._iconView; + }, + + setColor: function(color) { + var node = this.getNode(); + + if (this._color) { + JX.DOM.alterClass(node, this._color, false); + } + this._color = color; + JX.DOM.alterClass(node, this._color, true); + + return this; + }, + + setButtonType: function(button_type) { + var self = JX.PHUIXButtonView; + + this._buttonType = button_type; + var node = this.getNode(); + + var is_simple = (this._buttonType == self.BUTTONTYPE_SIMPLE); + JX.DOM.alterClass(node, 'simple', is_simple); + + return this; + }, + + setText: function(text) { + JX.DOM.setContent(this._getTextNode(), text); + return this; + }, + + getNode: function() { + if (!this._node) { + var attrs = { + className: 'button' + }; + + this._node = JX.$N('button', attrs); + + this._redraw(); + } + + return this._node; + }, + + _getTextNode: function() { + if (!this._textNode) { + var attrs = { + className: 'phui-button-text' + }; + + this._textNode = JX.$N('div', attrs); + } + + return this._textNode; + }, + + _redraw: function() { + var node = this.getNode(); + + var icon = this._iconView; + var text = this._textNode; + + var content = []; + if (icon) { + content.push(icon.getNode()); + } + + if (text) { + content.push(text); + } + + JX.DOM.alterClass(node, 'has-icon', !!icon); + JX.DOM.setContent(node, content); + } + } + +}); diff --git a/webroot/rsrc/js/phuix/PHUIXExample.js b/webroot/rsrc/js/phuix/PHUIXExample.js new file mode 100644 index 0000000000..87f36b04c3 --- /dev/null +++ b/webroot/rsrc/js/phuix/PHUIXExample.js @@ -0,0 +1,65 @@ +/** + * @provides javelin-behavior-phuix-example + * @requires javelin-install + * javelin-dom + * phuix-button-view + */ + +JX.behavior('phuix-example', function(config) { + var node; + var spec; + var defaults; + + switch (config.type) { + case 'button': + var button = new JX.PHUIXButtonView(); + defaults = { + text: null, + icon: null, + type: null, + color: null + }; + + spec = JX.copy(defaults, config.spec); + + if (spec.text !== null) { + button.setText(spec.text); + } + + if (spec.icon !== null) { + button.setIcon(spec.icon); + } + + if (spec.type !== null) { + button.setButtonType(spec.type); + } + + if (spec.color !== null) { + button.setColor(spec.color); + } + + node = button.getNode(); + break; + case 'icon': + var icon = new JX.PHUIXIconView(); + defaults = { + icon: null, + color: null + }; + + spec = JX.copy(defaults, config.spec); + + if (spec.icon !== null) { + icon.setIcon(spec.icon); + } + + if (spec.color !== null) { + icon.setColor(spec.color); + } + + node = icon.getNode(); + break; + } + + JX.DOM.setContent(JX.$(config.id), node); +});