diff --git a/polygerrit-ui/app/elements/change-list/gr-change-list/gr-change-list.html b/polygerrit-ui/app/elements/change-list/gr-change-list/gr-change-list.html index 152ef3d2f4..27d3a429a7 100644 --- a/polygerrit-ui/app/elements/change-list/gr-change-list/gr-change-list.html +++ b/polygerrit-ui/app/elements/change-list/gr-change-list/gr-change-list.html @@ -22,6 +22,7 @@ limitations under the License. + @@ -101,11 +102,17 @@ limitations under the License. visible-change-table-columns="[[visibleChangeTableColumns]]" show-number="[[showNumber]]" show-star="[[showStar]]" + tabindex="0" label-names="[[labelNames]]"> + diff --git a/polygerrit-ui/app/elements/change-list/gr-change-list/gr-change-list.js b/polygerrit-ui/app/elements/change-list/gr-change-list/gr-change-list.js index 262d1dc0ec..f66d8c8a89 100644 --- a/polygerrit-ui/app/elements/change-list/gr-change-list/gr-change-list.js +++ b/polygerrit-ui/app/elements/change-list/gr-change-list/gr-change-list.js @@ -113,6 +113,10 @@ keydown: '_scopedKeydownHandler', }, + observers: [ + '_sectionsChanged(sections.*)', + ], + /** * Iron-a11y-keys-behavior catches keyboard events globally. Some keyboard * events must be scoped to a component level (e.g. `enter`) in order to not @@ -194,7 +198,7 @@ }, _sectionHref(query) { - return `${this.getBaseUrl()}/q/${this.encodeURL(query, true)}`; + return Gerrit.Nav.getUrlForSearchQuery(query); }, /** @@ -234,10 +238,7 @@ this.modifierPressed(e)) { return; } e.preventDefault(); - // Compute absolute index of item that would come after final item. - const len = this._computeItemAbsoluteIndex(this.sections.length, 0); - if (this.selectedIndex === len - 1) { return; } - this.selectedIndex += 1; + this.$.cursor.next(); }, _handleKKey(e) { @@ -245,8 +246,7 @@ this.modifierPressed(e)) { return; } e.preventDefault(); - if (this.selectedIndex === 0) { return; } - this.selectedIndex -= 1; + this.$.cursor.previous(); }, _handleOKey(e) { @@ -317,5 +317,12 @@ _getListItems() { return Polymer.dom(this.root).querySelectorAll('gr-change-list-item'); }, + + _sectionsChanged() { + // Flush DOM operations so that the list item elements will be loaded. + Polymer.dom.flush(); + this.$.cursor.stops = this._getListItems(); + this.$.cursor.moveToStart(); + }, }); })(); diff --git a/polygerrit-ui/app/elements/change-list/gr-change-list/gr-change-list_test.html b/polygerrit-ui/app/elements/change-list/gr-change-list/gr-change-list_test.html index bded5f6242..7b9fadf31c 100644 --- a/polygerrit-ui/app/elements/change-list/gr-change-list/gr-change-list_test.html +++ b/polygerrit-ui/app/elements/change-list/gr-change-list/gr-change-list_test.html @@ -473,16 +473,6 @@ limitations under the License. } }); - test('_sectionHref', () => { - assert.equal( - element._sectionHref('is:open owner:self'), - '/q/is:open+owner:self'); - assert.equal( - element._sectionHref( - 'is:open ((reviewer:self -is:ignored) OR assignee:self)'), - '/q/is:open+((reviewer:self+-is:ignored)+OR+assignee:self)'); - }); - test('_computeItemAbsoluteIndex', () => { sandbox.stub(element, '_computeLabelNames'); element.sections = [ diff --git a/polygerrit-ui/app/elements/core/gr-navigation/gr-navigation.html b/polygerrit-ui/app/elements/core/gr-navigation/gr-navigation.html index f30cc1ca4d..b59ad9dc9b 100644 --- a/polygerrit-ui/app/elements/core/gr-navigation/gr-navigation.html +++ b/polygerrit-ui/app/elements/core/gr-navigation/gr-navigation.html @@ -26,6 +26,9 @@ limitations under the License. // - `changeNum`, required, String: the numeric ID of the change. // // - Gerrit.Nav.View.SEARCH: + // - `query`, optional, String: the literal search query. If provided, + // the string will be used as the query, and all other params will be + // ignored. // - `owner`, optional, String: the owner name. // - `project`, optional, String: the project name. // - `branch`, optional, String: the branch name. @@ -136,6 +139,13 @@ limitations under the License. return this._generateUrl(params); }, + getUrlForSearchQuery(query) { + return this._getUrlFor({ + view: Gerrit.Nav.View.SEARCH, + query, + }); + }, + /** * @param {!string} project The name of the project. * @param {boolean=} opt_openOnly When true, only search open changes in diff --git a/polygerrit-ui/app/elements/core/gr-router/gr-router.js b/polygerrit-ui/app/elements/core/gr-router/gr-router.js index 60fd109ab9..5d26cb63cf 100644 --- a/polygerrit-ui/app/elements/core/gr-router/gr-router.js +++ b/polygerrit-ui/app/elements/core/gr-router/gr-router.js @@ -322,6 +322,10 @@ * @return {string} */ _generateSearchUrl(params) { + if (params.query) { + return '/q/' + this.encodeURL(params.query, true); + } + const operators = []; if (params.owner) { operators.push('owner:' + this.encodeURL(params.owner, false)); diff --git a/polygerrit-ui/app/elements/core/gr-router/gr-router_test.html b/polygerrit-ui/app/elements/core/gr-router/gr-router_test.html index 909235b840..7159e0aebc 100644 --- a/polygerrit-ui/app/elements/core/gr-router/gr-router_test.html +++ b/polygerrit-ui/app/elements/core/gr-router/gr-router_test.html @@ -226,6 +226,10 @@ limitations under the License. '/q/owner:a%2525b+project:c%2525d+branch:e%2525f+' + 'topic:"g%2525h"+status:op%2525en'); + // The presence of the query param overrides other params. + params.query = 'foo$bar'; + assert.equal(element._generateUrl(params), '/q/foo%2524bar'); + params = { view: Gerrit.Nav.View.SEARCH, statuses: ['a', 'b', 'c'],