Page MenuHomePhabricator

D8973.id21291.diff
No OneTemporary

D8973.id21291.diff

diff --git a/resources/celerity/map.php b/resources/celerity/map.php
--- a/resources/celerity/map.php
+++ b/resources/celerity/map.php
@@ -7,14 +7,14 @@
return array(
'names' =>
array(
- 'core.pkg.css' => '159b5ecd',
+ 'core.pkg.css' => '665d1122',
'core.pkg.js' => '417722ff',
'darkconsole.pkg.js' => 'ca8671ce',
'differential.pkg.css' => '8a064eb7',
- 'differential.pkg.js' => '11a5b750',
+ 'differential.pkg.js' => 'a2f45b5f',
'diffusion.pkg.css' => '3783278d',
'diffusion.pkg.js' => '5b4010f4',
- 'javelin.pkg.js' => '0452e69d',
+ 'javelin.pkg.js' => '4883ff39',
'maniphest.pkg.css' => 'f1887d71',
'maniphest.pkg.js' => '2fe8af22',
'rsrc/css/aphront/aphront-bars.css' => '231ac33c',
@@ -108,7 +108,7 @@
'rsrc/css/core/core.css' => '7dff07c3',
'rsrc/css/core/remarkup.css' => '80c3a48c',
'rsrc/css/core/syntax.css' => '3c18c1cb',
- 'rsrc/css/core/z-index.css' => '7e4989ed',
+ 'rsrc/css/core/z-index.css' => 'e057ae95',
'rsrc/css/diviner/diviner-shared.css' => '38813222',
'rsrc/css/font/font-awesome.css' => '62bc244d',
'rsrc/css/font/font-glyphicons-halflings.css' => 'c4c1c6b6',
@@ -126,7 +126,7 @@
'rsrc/css/phui/calendar/phui-calendar-month.css' => 'a92e47d2',
'rsrc/css/phui/calendar/phui-calendar.css' => '5e1ad989',
'rsrc/css/phui/phui-box.css' => '7b3a2eed',
- 'rsrc/css/phui/phui-button.css' => '653ac588',
+ 'rsrc/css/phui/phui-button.css' => 'c43a9c3f',
'rsrc/css/phui/phui-document.css' => '3b078dc0',
'rsrc/css/phui/phui-feed-story.css' => '3a59c2cf',
'rsrc/css/phui/phui-fontkit.css' => 'de84aa4a',
@@ -200,7 +200,7 @@
'rsrc/externals/javelin/ext/view/__tests__/ViewInterpreter.js' => '7a94d6a5',
'rsrc/externals/javelin/ext/view/__tests__/ViewRenderer.js' => '5426001c',
'rsrc/externals/javelin/lib/Cookie.js' => '6b3dcf44',
- 'rsrc/externals/javelin/lib/DOM.js' => '32a4d380',
+ 'rsrc/externals/javelin/lib/DOM.js' => '07d99a3d',
'rsrc/externals/javelin/lib/History.js' => 'c60f4327',
'rsrc/externals/javelin/lib/JSON.js' => '08e56a4e',
'rsrc/externals/javelin/lib/Mask.js' => 'b9f26029',
@@ -362,7 +362,7 @@
'rsrc/js/application/differential/behavior-comment-jump.js' => '71755c79',
'rsrc/js/application/differential/behavior-comment-preview.js' => '127f2018',
'rsrc/js/application/differential/behavior-diff-radios.js' => 'e1ff79b1',
- 'rsrc/js/application/differential/behavior-dropdown-menus.js' => '5f004630',
+ 'rsrc/js/application/differential/behavior-dropdown-menus.js' => '7f93ef26',
'rsrc/js/application/differential/behavior-edit-inline-comments.js' => '00861799',
'rsrc/js/application/differential/behavior-keyboard-nav.js' => '173ce7e7',
'rsrc/js/application/differential/behavior-populate.js' => 'ce0c217a',
@@ -481,6 +481,9 @@
'rsrc/js/core/behavior-workflow.js' => 'fee00761',
'rsrc/js/core/phtize.js' => 'd254d646',
'rsrc/js/phui/behavior-phui-object-box-tabs.js' => 'a3e2244e',
+ 'rsrc/js/phuix/PHUIXActionListView.js' => 'b5c256b8',
+ 'rsrc/js/phuix/PHUIXActionView.js' => '20793977',
+ 'rsrc/js/phuix/PHUIXDropdownMenu.js' => '8d57e61c',
'rsrc/swf/aphlict.swf' => 'abac967d',
),
'symbols' =>
@@ -552,7 +555,7 @@
'javelin-behavior-differential-add-reviewers-and-ccs' => '533a187b',
'javelin-behavior-differential-comment-jump' => '71755c79',
'javelin-behavior-differential-diff-radios' => 'e1ff79b1',
- 'javelin-behavior-differential-dropdown-menus' => '5f004630',
+ 'javelin-behavior-differential-dropdown-menus' => '7f93ef26',
'javelin-behavior-differential-edit-inline-comments' => '00861799',
'javelin-behavior-differential-feedback-preview' => '127f2018',
'javelin-behavior-differential-keyboard-navigation' => '173ce7e7',
@@ -636,7 +639,7 @@
'javelin-behavior-workflow' => 'fee00761',
'javelin-color' => '7e41274a',
'javelin-cookie' => '6b3dcf44',
- 'javelin-dom' => '32a4d380',
+ 'javelin-dom' => '07d99a3d',
'javelin-dynval' => 'f6555212',
'javelin-event' => '79473b62',
'javelin-fx' => '54b612ba',
@@ -735,7 +738,7 @@
'phabricator-uiexample-reactor-select' => '189e4fe3',
'phabricator-uiexample-reactor-sendclass' => 'bf97561d',
'phabricator-uiexample-reactor-sendproperties' => '551add57',
- 'phabricator-zindex-css' => '7e4989ed',
+ 'phabricator-zindex-css' => 'e057ae95',
'phame-css' => '19ecc703',
'pholio-css' => '2fa97dbe',
'pholio-edit-css' => 'b9e59b6d',
@@ -745,7 +748,7 @@
'phrequent-css' => 'ffc185ad',
'phriction-document-css' => '7d7f0071',
'phui-box-css' => '7b3a2eed',
- 'phui-button-css' => '653ac588',
+ 'phui-button-css' => 'c43a9c3f',
'phui-calendar-css' => '5e1ad989',
'phui-calendar-day-css' => 'de035c8a',
'phui-calendar-list-css' => 'c1d0ca59',
@@ -772,6 +775,9 @@
'phui-timeline-view-css' => '27b280ca',
'phui-workboard-view-css' => '84f2c272',
'phui-workpanel-view-css' => '97b69459',
+ 'phuix-action-list-view' => 'b5c256b8',
+ 'phuix-action-view' => '20793977',
+ 'phuix-dropdown-menu' => '8d57e61c',
'policy-css' => '957ea14c',
'policy-edit-css' => '05cca26a',
'policy-transaction-detail-css' => '82100a43',
@@ -863,6 +869,14 @@
2 => 'javelin-dom',
3 => 'javelin-vector',
),
+ '07d99a3d' =>
+ array(
+ 0 => 'javelin-magical-init',
+ 1 => 'javelin-install',
+ 2 => 'javelin-util',
+ 3 => 'javelin-vector',
+ 4 => 'javelin-stratcom',
+ ),
'08e56a4e' =>
array(
0 => 'javelin-install',
@@ -1031,14 +1045,6 @@
3 => 'javelin-stratcom',
4 => 'javelin-request',
),
- '32a4d380' =>
- array(
- 0 => 'javelin-magical-init',
- 1 => 'javelin-install',
- 2 => 'javelin-util',
- 3 => 'javelin-vector',
- 4 => 'javelin-stratcom',
- ),
'356de121' =>
array(
0 => 'javelin-util',
@@ -1187,16 +1193,6 @@
3 => 'javelin-stratcom',
4 => 'javelin-vector',
),
- '5f004630' =>
- array(
- 0 => 'javelin-behavior',
- 1 => 'javelin-dom',
- 2 => 'javelin-util',
- 3 => 'javelin-stratcom',
- 4 => 'phabricator-dropdown-menu',
- 5 => 'phabricator-menu-item',
- 6 => 'phabricator-phtize',
- ),
'5f850b5c' =>
array(
0 => 'javelin-install',
@@ -1208,6 +1204,13 @@
2 => 'javelin-util',
3 => 'phabricator-shaped-request',
),
+ '62e18640' =>
+ array(
+ 0 => 'javelin-install',
+ 1 => 'javelin-util',
+ 2 => 'javelin-dom',
+ 3 => 'javelin-typeahead-normalizer',
+ ),
'6453c869' =>
array(
0 => 'javelin-install',
@@ -1241,13 +1244,6 @@
0 => 'javelin-behavior',
1 => 'javelin-dom',
),
- '62e18640' =>
- array(
- 0 => 'javelin-install',
- 1 => 'javelin-util',
- 2 => 'javelin-dom',
- 3 => 'javelin-typeahead-normalizer',
- ),
'75903ee1' =>
array(
0 => 'javelin-behavior',
@@ -1313,6 +1309,17 @@
0 => 'javelin-behavior',
1 => 'javelin-history',
),
+ '7f93ef26' =>
+ array(
+ 0 => 'javelin-behavior',
+ 1 => 'javelin-dom',
+ 2 => 'javelin-util',
+ 3 => 'javelin-stratcom',
+ 4 => 'phuix-dropdown-menu',
+ 5 => 'phuix-action-list-view',
+ 6 => 'phuix-action-view',
+ 7 => 'phabricator-phtize',
+ ),
'82f568cd' =>
array(
0 => 'javelin-install',
@@ -1367,6 +1374,14 @@
2 => 'javelin-stratcom',
3 => 'javelin-uri',
),
+ '8d57e61c' =>
+ array(
+ 0 => 'javelin-install',
+ 1 => 'javelin-util',
+ 2 => 'javelin-dom',
+ 3 => 'javelin-vector',
+ 4 => 'javelin-stratcom',
+ ),
'8ef9ab58' =>
array(
0 => 'javelin-behavior',
@@ -1558,6 +1573,11 @@
6 => 'javelin-request',
7 => 'javelin-util',
),
+ 'b5c256b8' =>
+ array(
+ 0 => 'javelin-install',
+ 1 => 'javelin-dom',
+ ),
'b657bdf8' =>
array(
0 => 'javelin-behavior',
@@ -1986,6 +2006,12 @@
2 => 'javelin-workflow',
3 => 'javelin-dom',
),
+ 20793977 =>
+ array(
+ 0 => 'javelin-install',
+ 1 => 'javelin-dom',
+ 2 => 'javelin-util',
+ ),
28497740 =>
array(
0 => 'javelin-behavior',
diff --git a/webroot/rsrc/css/core/z-index.css b/webroot/rsrc/css/core/z-index.css
--- a/webroot/rsrc/css/core/z-index.css
+++ b/webroot/rsrc/css/core/z-index.css
@@ -133,7 +133,8 @@
z-index: 20;
}
-.dropdown-menu-frame {
+.dropdown-menu-frame,
+.phuix-dropdown-menu {
z-index: 32;
}
diff --git a/webroot/rsrc/css/phui/phui-button.css b/webroot/rsrc/css/phui/phui-button.css
--- a/webroot/rsrc/css/phui/phui-button.css
+++ b/webroot/rsrc/css/phui/phui-button.css
@@ -166,7 +166,8 @@
text-decoration: underline;
}
-.dropdown-menu-frame {
+.dropdown-menu-frame,
+.phuix-dropdown-menu {
position: absolute;
width: 240px;
background: #fff;
diff --git a/webroot/rsrc/externals/javelin/lib/DOM.js b/webroot/rsrc/externals/javelin/lib/DOM.js
--- a/webroot/rsrc/externals/javelin/lib/DOM.js
+++ b/webroot/rsrc/externals/javelin/lib/DOM.js
@@ -944,6 +944,7 @@
try { node.focus(); } catch (lol_ie) {}
},
+
/**
* Scroll to the position of an element in the document.
* @task view
diff --git a/webroot/rsrc/js/application/differential/behavior-dropdown-menus.js b/webroot/rsrc/js/application/differential/behavior-dropdown-menus.js
--- a/webroot/rsrc/js/application/differential/behavior-dropdown-menus.js
+++ b/webroot/rsrc/js/application/differential/behavior-dropdown-menus.js
@@ -4,13 +4,13 @@
* javelin-dom
* javelin-util
* javelin-stratcom
- * phabricator-dropdown-menu
- * phabricator-menu-item
+ * phuix-dropdown-menu
+ * phuix-action-list-view
+ * phuix-action-view
* phabricator-phtize
*/
JX.behavior('differential-dropdown-menus', function(config) {
-
var pht = JX.phtize(config.pht);
function show_more(container) {
@@ -30,121 +30,138 @@
}
}
- function build_menu(button, data) {
-
- function link_to(name, uri) {
- var item = new JX.PhabricatorMenuItem(
- name,
- JX.bind(null, window.open, uri),
- uri);
- item.setDisabled(!uri);
- return item;
- }
-
- var reveal_item = new JX.PhabricatorMenuItem('', function () {
- show_more(JX.$(data.containerID));
- });
-
- var diffusion_item;
- if (data.diffusionURI) {
- // Show this only if we have a link, since when this appears in Diffusion
- // it is otherwise potentially confusing.
- diffusion_item = link_to(pht('Browse in Diffusion'), data.diffusionURI);
- }
-
- var menu = new JX.PhabricatorDropdownMenu(buttons[ii])
- .addItem(reveal_item);
-
- var visible_item = new JX.PhabricatorMenuItem('', function () {
- JX.Stratcom.invoke('differential-toggle-file', null, {
- diff: JX.DOM.scry(JX.$(data.containerID), 'table', 'differential-diff')
- });
+ JX.Stratcom.listen(
+ 'click',
+ 'differential-reveal-all',
+ function(e) {
+ var containers = JX.DOM.scry(
+ JX.$('differential-review-stage'),
+ 'div',
+ 'differential-changeset');
+ for (var i=0; i < containers.length; i++) {
+ show_more(containers[i]);
+ }
+ e.kill();
});
- menu.addItem(visible_item);
-
- if (diffusion_item) {
- menu.addItem(diffusion_item);
- }
- menu.addItem(link_to(pht('View Standalone'), data.standaloneURI));
+ var buildmenu = function(e) {
+ var button = e.getNode('differential-view-options');
+ var data = JX.Stratcom.getData(button);
- if (data.leftURI) {
- menu.addItem(link_to(pht('Show Raw File (Left)'), data.leftURI));
+ if (data.menu) {
+ return;
}
- if (data.rightURI) {
- menu.addItem(link_to(pht('Show Raw File (Right)'), data.rightURI));
- }
+ e.prevent();
- if (data.editor) {
- menu.addItem(new JX.PhabricatorMenuItem(
- pht('Open in Editor'),
- // Open in the same window.
- JX.bind(location, location.assign, data.editor),
- data.editor));
- }
+ var menu = new JX.PHUIXDropdownMenu(button);
+ var list = new JX.PHUIXActionListView();
- if (data.editorConfigure) {
- menu.addItem(link_to(pht('Configure Editor'), data.editorConfigure));
- }
-
- menu.listen(
- 'open',
- function() {
-
- // When the user opens the menu, check if there are any "Show More"
- // links in the changeset body. If there aren't, disable the "Show
- // Entire File" menu item since it won't change anything.
-
- var nodes = JX.DOM.scry(JX.$(data.containerID), 'a', 'show-more');
- if (nodes.length) {
- reveal_item.setDisabled(false);
- reveal_item.setName(pht('Show Entire File'));
- } else {
- reveal_item.setDisabled(true);
- reveal_item.setName(pht('Entire File Shown'));
- }
+ var add_link = function(icon, name, href, local) {
+ if (!href) {
+ return;
+ }
- visible_item.setDisabled(true);
- visible_item.setName(pht("Can't Toggle Unloaded File"));
- var diffs = JX.DOM.scry(JX.$(data.containerID),
- 'table', 'differential-diff');
- if (diffs.length > 1) {
- JX.$E(
- 'More than one node with sigil "differential-diff" was found in "'+
- data.containerID+'."');
- } else if (diffs.length == 1) {
- diff = diffs[0];
- visible_item.setDisabled(false);
- if (JX.Stratcom.getData(diff).hidden) {
- visible_item.setName(pht('Expand File'));
+ var link = new JX.PHUIXActionView()
+ .setIcon(icon)
+ .setName(name)
+ .setHref(href)
+ .setHandler(function(e) {
+ if (local) {
+ window.location.assign(href);
} else {
- visible_item.setName(pht('Collapse File'));
+ window.open(href);
}
- } else {
- // Do nothing when there is no diff shown in the table. For example,
- // the file is binary.
- }
+ menu.close();
+ e.prevent();
+ });
+
+ list.addItem(link);
+ return link;
+ };
+
+ var reveal_item = new JX.PHUIXActionView()
+ .setIcon('preview');
+ list.addItem(reveal_item);
+
+ var visible_item = new JX.PHUIXActionView()
+ .setHandler(function(e) {
+ var diff = JX.DOM.scry(
+ JX.$(data.containerID),
+ 'table',
+ 'differential-diff');
+
+ JX.Stratcom.invoke('differential-toggle-file', null, {diff: diff});
+ e.prevent();
+ menu.close();
});
- }
-
- var buttons = JX.DOM.scry(window.document, 'a', 'differential-view-options');
- for (var ii = 0; ii < buttons.length; ii++) {
- build_menu(buttons[ii], JX.Stratcom.getData(buttons[ii]));
- }
+ list.addItem(visible_item);
+
+ add_link('file', pht('Browse in Diffusion'), data.diffusionURI);
+ add_link('transcript', pht('View Standalone'), data.standaloneURI);
+ add_link('arrow_left', pht('Show Raw File (Left)'), data.leftURI);
+ add_link('arrow_right', pht('Show Raw File (Right)'), data.rightURI);
+ add_link('edit', pht('Open in Editor'), data.editor, true);
+ add_link('wrench', pht('Configure Editor'), data.editorConfigure);
+
+
+ menu.setContent(list.getNode());
+
+ menu.listen('open', function() {
+
+ // When the user opens the menu, check if there are any "Show More"
+ // links in the changeset body. If there aren't, disable the "Show
+ // Entire File" menu item since it won't change anything.
+
+ var nodes = JX.DOM.scry(JX.$(data.containerID), 'a', 'show-more');
+ if (nodes.length) {
+ reveal_item
+ .setDisabled(false)
+ .setName(pht('Show Entire File'))
+ .setHandler(function(e) {
+ show_more(JX.$(data.containerID));
+ e.prevent();
+ menu.close();
+ });
+ } else {
+ reveal_item
+ .setDisabled(true)
+ .setName(pht('Entire File Shown'))
+ .setHandler(function(e) { e.prevent(); });
+ }
- JX.Stratcom.listen(
- 'click',
- 'differential-reveal-all',
- function(e) {
- var containers = JX.DOM.scry(
- JX.$('differential-review-stage'),
- 'div',
- 'differential-changeset');
- for (var i=0; i < containers.length; i++) {
- show_more(containers[i]);
+ visible_item.setDisabled(true);
+ visible_item.setName(pht("Can't Toggle Unloaded File"));
+ var diffs = JX.DOM.scry(
+ JX.$(data.containerID),
+ 'table',
+ 'differential-diff');
+
+ if (diffs.length > 1) {
+ JX.$E(
+ 'More than one node with sigil "differential-diff" was found in "'+
+ data.containerID+'."');
+ } else if (diffs.length == 1) {
+ diff = diffs[0];
+ visible_item.setDisabled(false);
+ if (JX.Stratcom.getData(diff).hidden) {
+ visible_item
+ .setName(pht('Expand File'))
+ .setIcon('unmerge');
+ } else {
+ visible_item
+ .setName(pht('Collapse File'))
+ .setIcon('merge');
+ }
+ } else {
+ // Do nothing when there is no diff shown in the table. For example,
+ // the file is binary.
}
- e.kill();
+
});
+ data.menu = menu;
+ menu.open();
+ };
+ JX.Stratcom.listen('click', 'differential-view-options', buildmenu);
});
diff --git a/webroot/rsrc/js/phuix/PHUIXActionListView.js b/webroot/rsrc/js/phuix/PHUIXActionListView.js
new file mode 100644
--- /dev/null
+++ b/webroot/rsrc/js/phuix/PHUIXActionListView.js
@@ -0,0 +1,36 @@
+/**
+ * @provides phuix-action-list-view
+ * @requires javelin-install
+ * javelin-dom
+ */
+
+JX.install('PHUIXActionListView', {
+
+ construct: function() {
+ this._items = [];
+ },
+
+ members: {
+ _items: null,
+ _node: null,
+
+ addItem: function(item) {
+ this._items.push(item);
+ this.getNode().appendChild(item.getNode());
+ return this;
+ },
+
+ getNode: function() {
+ if (!this._node) {
+ var attrs = {
+ className: 'phabricator-action-list-view'
+ };
+
+ this._node = JX.$N('ul', attrs);
+ }
+
+ return this._node;
+ }
+ }
+
+});
diff --git a/webroot/rsrc/js/phuix/PHUIXActionView.js b/webroot/rsrc/js/phuix/PHUIXActionView.js
new file mode 100644
--- /dev/null
+++ b/webroot/rsrc/js/phuix/PHUIXActionView.js
@@ -0,0 +1,138 @@
+/**
+ * @provides phuix-action-view
+ * @requires javelin-install
+ * javelin-dom
+ * javelin-util
+ * @javelin
+ */
+
+JX.install('PHUIXActionView', {
+
+ members: {
+ _node: null,
+ _name: null,
+ _icon: 'none',
+ _disabled: false,
+ _handler: null,
+
+ _iconNode: null,
+ _nameNode: null,
+
+ setDisabled: function(disabled) {
+ this._disabled = disabled;
+ JX.DOM.alterClass(
+ this.getNode(),
+ 'phabricator-action-view-disabled',
+ disabled);
+
+ this._buildIconNode(true);
+
+ return this;
+ },
+
+ getDisabled: function() {
+ return this._disabled;
+ },
+
+ setName: function(name) {
+ this._name = name;
+ this._buildNameNode(true);
+ return this;
+ },
+
+ setHandler: function(handler) {
+ this._handler = handler;
+ this._buildNameNode(true);
+ return this;
+ },
+
+ setIcon: function(icon) {
+ this._icon = icon;
+ this._buildIconNode(true);
+ return this;
+ },
+
+ setHref: function(href) {
+ this._href = href;
+ this._buildNameNode(true);
+ return this;
+ },
+
+ getNode: function() {
+ if (!this._node) {
+ var attr = {
+ className: 'phabricator-action-view'
+ };
+
+ var content = [
+ this._buildIconNode(),
+ this._buildNameNode()
+ ];
+
+ this._node = JX.$N('li', attr, content);
+ }
+
+ return this._node;
+ },
+
+ _buildIconNode: function(dirty) {
+ if (!this._iconNode || dirty) {
+ var attr = {
+ className: 'phui-icon-view sprite-icons phabricator-action-view-icon'
+ };
+ var node = JX.$N('span', attr);
+
+ var icon_class = 'icons-' + this._icon;
+ if (this._disabled) {
+ icon_class = icon_class + '-grey';
+ }
+
+ JX.DOM.alterClass(node, icon_class, true);
+
+ if (this._iconNode && this._iconNode.parentNode) {
+ JX.DOM.replace(this._iconNode, node);
+ }
+ this._iconNode = node;
+ }
+
+ return this._iconNode;
+ },
+
+ _buildNameNode: function(dirty) {
+ if (!this._nameNode || dirty) {
+ var attr = {
+ className: 'phabricator-action-view-item'
+ };
+
+ var href = this._href;
+ if (!href && this._handler) {
+ href = '#';
+ }
+ if (href) {
+ attr.href = href;
+
+ }
+
+ var tag = href ? 'a' : 'span';
+
+ var node = JX.$N(tag, attr, this._name);
+ JX.DOM.listen(node, 'click', null, JX.bind(this, this._onclick));
+
+ if (this._nameNode && this._nameNode.parentNode) {
+ JX.DOM.replace(this._nameNode, node);
+ }
+ this._nameNode = node;
+ }
+
+ return this._nameNode;
+ },
+
+ _onclick: function(e) {
+ if (this._handler) {
+ this._handler(e);
+ }
+ }
+
+ }
+
+});
diff --git a/webroot/rsrc/js/phuix/PHUIXDropdownMenu.js b/webroot/rsrc/js/phuix/PHUIXDropdownMenu.js
new file mode 100644
--- /dev/null
+++ b/webroot/rsrc/js/phuix/PHUIXDropdownMenu.js
@@ -0,0 +1,177 @@
+/**
+ * @provides phuix-dropdown-menu
+ * @requires javelin-install
+ * javelin-util
+ * javelin-dom
+ * javelin-vector
+ * javelin-stratcom
+ * @javelin
+ */
+
+
+/**
+ * Basic interaction for a dropdown menu.
+ *
+ * The menu is unaware of the content inside it, so it can not close itself
+ * when an item is selected. Callers must make a call to @{method:close} after
+ * an item is chosen in order to close the menu.
+ */
+JX.install('PHUIXDropdownMenu', {
+
+ construct : function(node) {
+ this._node = node;
+
+ JX.DOM.listen(
+ this._node,
+ 'click',
+ null,
+ JX.bind(this, this._onclick));
+
+ JX.Stratcom.listen(
+ 'mousedown',
+ null,
+ JX.bind(this, this._onanyclick));
+
+ JX.Stratcom.listen(
+ 'resize',
+ null,
+ JX.bind(this, this._adjustposition));
+
+ JX.Stratcom.listen('phuix.dropdown.open', null, JX.bind(this, this.close));
+ },
+
+ events: ['open'],
+
+ properties: {
+ width: null,
+ align: 'right'
+ },
+
+ members: {
+ _node: null,
+ _menu: null,
+ _open: false,
+ _content: null,
+
+ setContent: function(content) {
+ JX.DOM.setContent(this._getMenuNode(), content);
+ return this;
+ },
+
+ open: function() {
+ if (this._open) {
+ return;
+ }
+
+ this.invoke('open');
+ JX.Stratcom.invoke('phuix.dropdown.open');
+
+ this._open = true;
+ this._show();
+
+ return this;
+ },
+
+ close: function() {
+ if (!this._open) {
+ return;
+ }
+ this._open = false;
+ this._hide();
+
+ return this;
+ },
+
+ _getMenuNode: function() {
+ if (!this._menu) {
+ var attrs = {
+ className: 'phuix-dropdown-menu',
+ role: 'button'
+ };
+
+ var menu = JX.$N('div', attrs);
+
+ this._node.setAttribute('aria-haspopup', 'true');
+ this._node.setAttribute('aria-expanded', 'false');
+
+ this._menu = menu;
+ }
+
+ return this._menu;
+ },
+
+ _onclick : function(e) {
+ if (this._open) {
+ this.close();
+ } else {
+ this.open();
+ }
+ e.prevent();
+ },
+
+ _onanyclick : function(e) {
+ if (!this._open) {
+ return;
+ }
+
+ if (JX.Stratcom.pass(e)) {
+ return;
+ }
+
+ var t = e.getTarget();
+ while (t) {
+ if (t == this._menu || t == this._node) {
+ return;
+ }
+ t = t.parentNode;
+ }
+
+ this.close();
+ },
+
+ _show : function() {
+ document.body.appendChild(this._menu);
+
+ if (this.getWidth()) {
+ new JX.Vector(this.getWidth(), null).setDim(this._menu);
+ }
+
+ this._adjustposition();
+
+ JX.DOM.alterClass(this._node, 'phuix-dropdown-open', true);
+
+ this._node.setAttribute('aria-expanded', 'true');
+ },
+
+ _hide : function() {
+ JX.DOM.remove(this._menu);
+
+ JX.DOM.alterClass(this._node, 'phuix-dropdown-open', false);
+
+ this._node.setAttribute('aria-expanded', 'false');
+ },
+
+ _adjustposition : function() {
+ if (!this._open) {
+ return;
+ }
+
+ var m = JX.Vector.getDim(this._menu);
+
+ var v = JX.$V(this._node);
+ var d = JX.Vector.getDim(this._node);
+
+ switch (this.getAlign()) {
+ case 'right':
+ v = v.add(d)
+ .add(JX.$V(-m.x, 0));
+ break;
+ default:
+ v = v.add(0, d.y);
+ break;
+ }
+
+ v.setPos(this._menu);
+ }
+ }
+});

File Metadata

Mime Type
text/plain
Expires
Mar 15 2025, 5:33 PM (6 w, 15 h ago)
Storage Engine
blob
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
7227249
Default Alt Text
D8973.id21291.diff (25 KB)

Event Timeline