From dc4d5677eb1d0297c2b42dc754d8bd49a0222db0 Mon Sep 17 00:00:00 2001 From: Sam Date: Thu, 17 Aug 2017 12:39:43 -0400 Subject: [PATCH] FEATURE: use `a` when search result is focused to add to composer --- .../discourse/components/d-editor.js.es6 | 18 ++- .../widgets/search-menu-results.js.es6 | 10 +- .../discourse/widgets/search-menu.js.es6 | 107 ++++++++---------- .../stylesheets/common/base/menu-panel.scss | 6 - 4 files changed, 66 insertions(+), 75 deletions(-) diff --git a/app/assets/javascripts/discourse/components/d-editor.js.es6 b/app/assets/javascripts/discourse/components/d-editor.js.es6 index f63b80994f6..574d3b49b5f 100644 --- a/app/assets/javascripts/discourse/components/d-editor.js.es6 +++ b/app/assets/javascripts/discourse/components/d-editor.js.es6 @@ -259,7 +259,7 @@ export default Ember.Component.extend({ if (this.get('composerEvents')) { this.appEvents.on('composer:insert-block', text => this._addBlock(this._getSelected(), text)); - this.appEvents.on('composer:insert-text', text => this._addText(this._getSelected(), text)); + this.appEvents.on('composer:insert-text', (text, options) => this._addText(this._getSelected(), text, options)); this.appEvents.on('composer:replace-text', (oldVal, newVal) => this._replaceText(oldVal, newVal)); } this._mouseTrap = mouseTrap; @@ -613,8 +613,22 @@ export default Ember.Component.extend({ Ember.run.scheduleOnce("afterRender", () => $textarea.focus()); }, - _addText(sel, text) { + _addText(sel, text, options) { const $textarea = this.$('textarea.d-editor-input'); + + if (options && options.ensureSpace) { + if ((sel.pre + '').length > 0) { + if (!sel.pre.match(/\s$/)) { + text = ' ' + text; + } + } + if ((sel.post + '').length > 0) { + if (!sel.post.match(/^\s/)) { + text = text + ' '; + } + } + } + const insert = `${sel.pre}${text}`; const value = `${insert}${sel.post}`; this.set('value', value); diff --git a/app/assets/javascripts/discourse/widgets/search-menu-results.js.es6 b/app/assets/javascripts/discourse/widgets/search-menu-results.js.es6 index 767f192c871..8b10b12e3da 100644 --- a/app/assets/javascripts/discourse/widgets/search-menu-results.js.es6 +++ b/app/assets/javascripts/discourse/widgets/search-menu-results.js.es6 @@ -21,17 +21,12 @@ function createSearchResult({ type, linkField, builder }) { return createWidget(`search-result-${type}`, { html(attrs) { - let i=-1; - return attrs.results.map(r => { - i+=1; let searchResultId; if (type === "topic") { searchResultId = r.get('topic_id'); } - let className = i === attrs.selected ? '.selected' : ''; - - return h('li' + className, { attributes: { tabindex: '-1' } }, this.attach('link', { + return h('li', this.attach('link', { href: r.get(linkField), contents: () => builder.call(this, r, attrs.term), className: 'search-link', @@ -131,8 +126,7 @@ createWidget('search-menu-results', { searchContextEnabled: attrs.searchContextEnabled, searchLogId: attrs.results.grouped_search_result.search_log_id, results: rt.results, - term: attrs.term, - selected: (attrs.selected && attrs.selected.type === rt.type) ? attrs.selected.index : -1 + term: attrs.term })), h('div.no-results', more) ]; diff --git a/app/assets/javascripts/discourse/widgets/search-menu.js.es6 b/app/assets/javascripts/discourse/widgets/search-menu.js.es6 index 08aa8f1b115..3da70746744 100644 --- a/app/assets/javascripts/discourse/widgets/search-menu.js.es6 +++ b/app/assets/javascripts/discourse/widgets/search-menu.js.es6 @@ -9,8 +9,7 @@ const searchData = { noResults: false, term: undefined, typeFilter: null, - invalidTerm: false, - selected: null + invalidTerm: false }; // Helps with debouncing and cancelling promises @@ -134,7 +133,6 @@ export default createWidget('search-menu', { results: searchData.results, invalidTerm: searchData.invalidTerm, searchContextEnabled: searchData.contextEnabled, - selected: searchData.selected })); } } @@ -176,76 +174,67 @@ export default createWidget('search-menu', { return; } - if (e.which === 13 /*enter*/ && searchData.selected) { - searchData.selected = null; - $('header .results li.selected a').click(); + if (e.which === 65 /* a */) { + let focused = $('header .results .search-link:focus'); + if (focused.length === 1) { + if ($('#reply-control.open').length === 1) { + // add a link and focus composer + + this.appEvents.trigger('composer:insert-text', focused[0].href, {ensureSpace: true}); + + e.preventDefault(); + $('#reply-control.open textarea').focus(); + return false; + } + } } - if (e.which === 38 /*arrow up*/ || e.which === 40 /*arrow down*/) { - this.moveSelected(e.which === 38 ? -1 : 1); + const up = e.which === 38; + const down = e.which === 40; + if (up || down) { - this.scheduleRerender(); + let focused = $('header .panel-body *:focus')[0]; - Em.run.next(()=>{ - if (searchData.selected) { + if (!focused) { + return; + } - // so we do not clear selected - $('header .results li').off('blur'); + let links = $('header .panel-body .results a'); + let results = $('header .panel-body .results .search-link'); - let selected = $('header .results li.selected') - .focus() - .on('blur', ()=> { - searchData.selected = null; - this.scheduleRerender(); - selected.off('blur'); - }); + let prevResult; + let result; - } else { - $('#search-term').focus(); - } + links.each((idx,item) => { + if ($(item).hasClass('search-link')) { + prevResult = item; + } + + if (item === focused) { + result = prevResult; + } }); + let index = -1; + + if (result) { + index = results.index(result); + } + + if (index === -1 && down) { + $('header .panel-body .search-link:first').focus(); + } else if (index > -1) { + index += (down ? 1 : -1); + if (index >= 0 && index < results.length) { + $(results[index]).focus(); + } + } + e.preventDefault(); return false; } }, - moveSelected(offset) { - - if (offset === 1 && !searchData.selected) { - searchData.selected = {type: searchData.results.resultTypes[0].type, index: 0}; - return; - } - - if (!searchData.selected) { - return; - } - - let typeIndex = _.findIndex(searchData.results.resultTypes, item => item.type === searchData.selected.type); - - if (typeIndex === 0 && searchData.selected.index === 0 && offset === -1) { - searchData.selected = null; - return; - } - - let currentResults = searchData.results.resultTypes[typeIndex].results; - let newPosition = searchData.selected.index + offset; - - if (newPosition < currentResults.length && newPosition >= 0) { - searchData.selected.index = newPosition; - } else { - // possibly move to next type - let newTypeIndex = typeIndex + offset; - if (newTypeIndex >= 0 && newTypeIndex < searchData.results.resultTypes.length) { - newPosition = 0; - if (offset === -1) { - newPosition = searchData.results.resultTypes[newTypeIndex].results.length - 1; - } - searchData.selected = {type: searchData.results.resultTypes[newTypeIndex].type, index: newPosition}; - } - } - }, - triggerSearch() { searchData.noResults = false; this.searchService().set('highlightTerm', searchData.term); diff --git a/app/assets/stylesheets/common/base/menu-panel.scss b/app/assets/stylesheets/common/base/menu-panel.scss index 09dde7b8d0f..10d2de5b673 100644 --- a/app/assets/stylesheets/common/base/menu-panel.scss +++ b/app/assets/stylesheets/common/base/menu-panel.scss @@ -149,12 +149,6 @@ text-align: center; } - li.selected { - background-color: $highlight-medium; - } - li:focus { - outline: none; - } .filter { padding: 0; &:hover {background: transparent;}