diff --git a/client/src/views/fields/assigned-user.js b/client/src/views/fields/assigned-user.js index ba2804fe0f..87ffa1382f 100644 --- a/client/src/views/fields/assigned-user.js +++ b/client/src/views/fields/assigned-user.js @@ -51,14 +51,12 @@ class AssignedUserFieldView extends UserWithAvatarFieldView { } getEmptyAutocompleteResult() { - return { - list: [ - { - id: this.getUser().id, - name: this.getUser().get('name'), - } - ] - }; + return [ + { + id: this.getUser().id, + name: this.getUser().get('name'), + }, + ]; } } diff --git a/client/src/views/fields/link-multiple.js b/client/src/views/fields/link-multiple.js index 292bb62cba..9f344064c5 100644 --- a/client/src/views/fields/link-multiple.js +++ b/client/src/views/fields/link-multiple.js @@ -30,6 +30,7 @@ import BaseFieldView from 'views/fields/base'; import RecordModal from 'helpers/record-modal'; +import Autocomplete from 'ui/autocomplete'; /** * A link-multiple field (for has-many relations). @@ -518,69 +519,16 @@ class LinkMultipleFieldView extends BaseFieldView { if (this.isEditMode() || this.isSearchMode()) { this.$element = this.$el.find('input.main-element'); - const $element = this.$element; - if (!this.autocompleteDisabled) { - // Does not work well with autocompleteOnEmpty. - /*this.$element.on('blur', () => { - setTimeout(() => this.$element.autocomplete('clear'), 300); - });*/ - - const minChar = this.autocompleteOnEmpty ? 0 : 1; - - this.$element.autocomplete({ - lookup: (q, callback) => { - Promise.resolve(this.getAutocompleteUrl(q)) - .then(url => { - Espo.Ajax - .getRequest(url, {q: q}) - .then(response => { - callback(this._transformAutocompleteResult(response)); - }); - }); - }, - minChars: minChar, - paramName: 'q', - noCache: true, + const autocomplete = new Autocomplete(this.$element.get(0), { + minChars: this.autocompleteOnEmpty ? 0 : 1, + focusOnSelect: true, + handleFocusMode: 3, autoSelectFirst: true, - triggerSelectOnValidInput: false, - beforeRender: $c => { - if (this.$element.hasClass('input-sm')) { - $c.addClass('small'); - } - - // Prevent an issue that suggestions are shown and not hidden - // when clicking outside the window and then focusing back on the document. - if (this.$element.get(0) !== document.activeElement) { - setTimeout(() => this.$element.autocomplete('hide'), 30); - } - }, - formatResult: suggestion => { - // noinspection JSUnresolvedReference - return this.getHelper().escapeString(suggestion.name); - }, - transformResult: response => { - response = JSON.parse(response); - - const list = []; - - response.list.forEach((item) => { - list.push({ - id: item.id, - name: item.name || item.id, - data: item.id, - value: item.name || item.id, - }); - }); - - return { - suggestions: list - }; - }, - onSelect: s => { + forceHide: true, + onSelect: item => { this.getModelFactory().create(this.foreignScope, model => { - // noinspection JSUnresolvedReference - model.set(s.attributes); + model.set(item.attributes); this.select([model]) @@ -588,23 +536,20 @@ class LinkMultipleFieldView extends BaseFieldView { this.$element.focus(); }); }, + lookupFunction: query => { + return Espo.Ajax.getRequest(this.getAutocompleteUrl(query), {q: query}) + .then(/** {list: Record[]} */response => { + return response.list.map(item => ({ + value: item.name, + attributes: item, + })); + }); + }, }); - this.$element.attr('autocomplete', 'espo-' + this.name); - - this.once('render', () => { - $element.autocomplete('dispose'); - }); - - this.once('remove', () => { - $element.autocomplete('dispose'); - }); + this.once('render remove', () => autocomplete.dispose()); } - $element.on('change', () => { - $element.val(''); - }); - this.renderLinks(); if (this.isEditMode()) { @@ -1123,25 +1068,6 @@ class LinkMultipleFieldView extends BaseFieldView { }); } - /** - * @private - */ - _transformAutocompleteResult(response) { - const list = []; - - response.list.forEach(item => { - list.push({ - id: item.id, - name: item.name || item.id, - data: item.id, - value: item.name || item.id, - attributes: item, - }); - }); - - return {suggestions: list}; - } - actionCreateLink() { const viewName = this.getMetadata().get(['clientDefs', this.foreignScope, 'modalViews', 'edit']) || 'views/modals/edit'; diff --git a/client/src/views/fields/link-parent.js b/client/src/views/fields/link-parent.js index a6078e7e56..0313fcadf0 100644 --- a/client/src/views/fields/link-parent.js +++ b/client/src/views/fields/link-parent.js @@ -31,6 +31,7 @@ import BaseFieldView from 'views/fields/base'; import RecordModal from 'helpers/record-modal'; import Select from 'ui/select'; +import Autocomplete from 'ui/autocomplete'; /** * A link-parent field (belongs-to-parent relation). @@ -498,82 +499,40 @@ class LinkParentFieldView extends BaseFieldView { e.currentTarget.value = this.model.get(this.nameName) || ''; } }, 100); - - if (!this.autocompleteDisabled) { - setTimeout(() => this.$elementName.autocomplete('clear'), 300); - } }); if (!this.autocompleteDisabled) { - this.$elementName.autocomplete({ - serviceUrl: (q) => { - return this.getAutocompleteUrl(q); - }, - minChars: this.autocompleteOnEmpty ? 0 : 1, - paramName: 'q', - triggerSelectOnValidInput: false, + const autocomplete = new Autocomplete(this.$elementName.get(0), { + name: this.name, + focusOnSelect: true, + handleFocusMode: 2, autoSelectFirst: true, - noCache: true, - beforeRender: ($c) => { - if (this.$elementName.hasClass('input-sm')) { - $c.addClass('small'); - } - }, - formatResult: (/** Record */suggestion) => { - return this.getHelper().escapeString(suggestion.name); - }, - transformResult: (response) => { - response = JSON.parse(response); - const list = []; - - response.list.forEach(item => { - list.push({ - id: item.id, - name: item.name || item.id, - data: item.id, - value: item.name || item.id, - attributes: item, - }); - }); - - return {suggestions: list}; - }, - onSelect: (/** Record */s) => { - this.getModelFactory().create(this.foreignScope, (model) => { - model.set(s.attributes); + forceHide: true, + minChars: this.autocompleteOnEmpty ? 0 : 1, + onSelect: item => { + this.getModelFactory().create(this.foreignScope, model => { + model.set(item.attributes); this.select(model); this.$elementName.focus(); }); }, + lookupFunction: query => { + return Promise.resolve(this.getAutocompleteUrl(query)) + .then(url => Espo.Ajax.getRequest(url, {q: query})) + .then(/** {list: Record[]} */response => { + return response.list.map(item => ({ + value: item.name, + attributes: item, + })); + }); + }, }); - this.$elementName.off('focus.autocomplete'); - - this.$elementName.on('focus', () => { - if (this.$elementName.val()) { - this.$elementName.get(0).select(); - - return; - } - - this.$elementName.autocomplete('onFocus'); - }); - - this.$elementName.attr('autocomplete', 'espo-' + this.name); + this.once('render remove', () => autocomplete.dispose()); Select.init(this.$elementType, {}); } - - const $elementName = this.$elementName; - - this.once('render', () => { - $elementName.autocomplete('dispose'); - }); - - this.once('remove', () => { - $elementName.autocomplete('dispose'); - }); } if (this.isSearchMode()) { diff --git a/client/src/views/fields/link.js b/client/src/views/fields/link.js index 1095c3ac0b..d8d78a603d 100644 --- a/client/src/views/fields/link.js +++ b/client/src/views/fields/link.js @@ -30,6 +30,7 @@ import BaseFieldView from 'views/fields/base'; import RecordModal from 'helpers/record-modal'; +import Autocomplete from 'ui/autocomplete'; /** * A link field (belongs-to relation). @@ -604,10 +605,6 @@ class LinkFieldView extends BaseFieldView { e.currentTarget.value = this.model.get(this.nameName); } }, 100); - - if (!this.autocompleteDisabled) { - setTimeout(() => this.$elementName.autocomplete('clear'), 300); - } }); const $elementName = this.$elementName; @@ -623,111 +620,54 @@ class LinkFieldView extends BaseFieldView { }); } - this.$elementName.autocomplete({ - beforeRender: $c => { - if (this.$elementName.hasClass('input-sm')) { - $c.addClass('small'); - } - - // Prevent an issue that suggestions are shown and not hidden - // when clicking outside the window and then focusing back on the document. - if (this.$elementName.get(0) !== document.activeElement) { - setTimeout(() => this.$elementName.autocomplete('hide'), 30); - } - }, - lookup: (q, callback) => { - if (!this.autocompleteOnEmpty && q.length === 0) { - isEmptyQueryResult = true; - - const emptyResult = this.getEmptyAutocompleteResult(); - - if (emptyResult) { - callback(this._transformAutocompleteResult(emptyResult)); - } - - return; - } - - isEmptyQueryResult = false; - - Promise.resolve(this.getAutocompleteUrl(q)) - .then(url => { - Espo.Ajax - .getRequest(url, {q: q}) - .then(response => { - callback(this._transformAutocompleteResult(response)); - }); - }); - }, - minChars: 0, - triggerSelectOnValidInput: false, + const autocomplete = new Autocomplete(this.$elementName.get(0), { + name: this.name, + handleFocusMode: 2, autoSelectFirst: true, - noCache: true, - formatResult: suggestion => { - // noinspection JSUnresolvedReference - return this.getHelper().escapeString(suggestion.name); - }, - onSelect: s => { - this.getModelFactory().create(this.foreignScope, (model) => { - // noinspection JSUnresolvedReference - model.set(s.attributes); - + forceHide: true, + onSelect: item => { + this.getModelFactory().create(this.foreignScope, model => { + model.set(item.attributes); this.select(model); this.$elementName.focus(); }); }, + lookupFunction: query => { + if (!this.autocompleteOnEmpty && query.length === 0) { + isEmptyQueryResult = true; + + const emptyResult = this.getEmptyAutocompleteResult(); + + if (emptyResult) { + return Promise.resolve(this._transformAutocompleteResult({list: emptyResult})); + } + + return Promise.resolve([]); + } + + isEmptyQueryResult = false; + + return Promise.resolve(this.getAutocompleteUrl(query)) + .then(url => Espo.Ajax.getRequest(url, {q: query})) + .then(response => this._transformAutocompleteResult(response)); + }, }); - this.$elementName.off('focus.autocomplete'); - - this.$elementName.on('focus', () => { - if (this.$elementName.val()) { - this.$elementName.get(0).select(); - - return; - } - - this.$elementName.autocomplete('onFocus'); - }); - - this.$elementName.attr('autocomplete', 'espo-' + this.name); - - this.once('render', () => { - $elementName.autocomplete('dispose'); - }); - - this.once('remove', () => { - $elementName.autocomplete('dispose'); - }); + this.once('render remove', () => autocomplete.dispose()); if (this.isSearchMode()) { const $elementOneOf = this.$el.find('input.element-one-of'); - // noinspection JSCheckFunctionSignatures - $elementOneOf.autocomplete({ - beforeRender: $c => { - if (this.$elementName.hasClass('input-sm')) { - $c.addClass('small'); - } - }, - serviceUrl: () => { - return this.getAutocompleteUrl(); - }, + const autocomplete = new Autocomplete($elementOneOf.get(0), { minChars: 1, - paramName: 'q', - noCache: true, - formatResult: suggestion => { - // noinspection JSUnresolvedReference - return this.getHelper().escapeString(suggestion.name); - }, - transformResult: response => { - return this._transformAutocompleteResult(JSON.parse(response)); - }, - onSelect: s => { + focusOnSelect: true, + handleFocusMode: 3, + autoSelectFirst: true, + forceHide: true, + onSelect: item => { this.getModelFactory().create(this.foreignScope, model => { - // noinspection JSUnresolvedReference - model.set(s.attributes); + model.set(item.attributes); this.selectOneOf([model]); @@ -735,17 +675,18 @@ class LinkFieldView extends BaseFieldView { setTimeout(() => $elementOneOf.focus(), 50); }); }, + lookupFunction: query => { + return Espo.Ajax.getRequest(this.getAutocompleteUrl(query), {q: query}) + .then(/** {list: Record[]} */response => { + return response.list.map(item => ({ + value: item.name, + attributes: item, + })); + }); + }, }); - $elementOneOf.attr('autocomplete', 'espo-' + this.name); - - this.once('render', () => { - $elementOneOf.autocomplete('dispose'); - }); - - this.once('remove', () => { - $elementOneOf.autocomplete('dispose'); - }); + this.once('render remove', () => autocomplete.dispose()); this.$el.find('select.search-type').on('change', () => { this.trigger('change'); @@ -789,7 +730,7 @@ class LinkFieldView extends BaseFieldView { }); }); - return {suggestions: list}; + return list; } /** @inheritDoc */ @@ -1286,6 +1227,9 @@ class LinkFieldView extends BaseFieldView { }); } + /** + * @return {Record[]|undefined} + */ getEmptyAutocompleteResult() { return undefined; } diff --git a/client/src/views/fields/varchar.js b/client/src/views/fields/varchar.js index e4fdad7441..a1bee992a1 100644 --- a/client/src/views/fields/varchar.js +++ b/client/src/views/fields/varchar.js @@ -204,9 +204,6 @@ class VarcharFieldView extends BaseFieldView { responseParsed.list.forEach(item => { list.push({ - //id: item.id, - //name: item.name || item.id, - //data: item.id, value: item.name || item.id, attributes: item, });