Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F15410857
D8973.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
16 KB
Referenced Files
None
Subscribers
None
D8973.diff
View Options
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
Details
Attached
Mime Type
text/plain
Expires
Thu, Mar 20, 8:35 AM (1 d, 9 m ago)
Storage Engine
blob
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
7661151
Default Alt Text
D8973.diff (16 KB)
Attached To
Mode
D8973: Begin rebuilding dropdown menus on ActionList
Attached
Detach File
Event Timeline
Log In to Comment