Page MenuHomePhabricator

D8973.diff
No OneTemporary

D8973.diff

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
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)

Event Timeline