From 5da711e98df57530339d5d98edf482b41791ade5 Mon Sep 17 00:00:00 2001 From: Juan Ferrer Toribio Date: Sun, 22 Jan 2017 23:21:02 +0100 Subject: [PATCH] Combo v7 --- @salix/core/src/autocomplete/index.js | 148 ++++++++++++++++---------- 1 file changed, 92 insertions(+), 56 deletions(-) diff --git a/@salix/core/src/autocomplete/index.js b/@salix/core/src/autocomplete/index.js index 007d0f1cc..844897b3b 100644 --- a/@salix/core/src/autocomplete/index.js +++ b/@salix/core/src/autocomplete/index.js @@ -52,22 +52,27 @@ function controller($http, $element, $attrs, $scope, $parse, $document, popoverP this.timeoutId = null; this.lastSearch = null; this.lastRequest = null; + this.currentRequest = null; this.moreData = false; this.activeOption = -1; this.maxRows = 10; - this.filterDelay = 350; + this.requestDelay = 350; this.requestItem(); }, loadData: function(textFilter) { - let lastSearch = this.lastSearch; - if(lastSearch === textFilter) return; + textFilter = textFilter ? textFilter : ''; + + if(this.lastSearch === textFilter) { + this.popoverDataReady(); + return; + } + this.lastSearch = textFilter; let lastRequest = this.lastRequest; - let requestWillSame = ( - this.data && textFilter && lastRequest && !this.moreData - && textFilter.substr(0, lastRequest.length) == lastRequest - ); + let requestWillSame = lastRequest !== null + && !this.moreData + && textFilter.substr(0, lastRequest.length) === lastRequest; if(requestWillSame) this.localFilter(textFilter); @@ -80,36 +85,12 @@ function controller($http, $element, $attrs, $scope, $parse, $document, popoverP fields[this.showField] = true; return fields; }, - requestItem: function() { - if(!this.model) return; - - let where = {}; - where[this.valueField] = this.model; - - let filter = { - fields: this.getRequestFields(), - where: where, - }; - - let json = JSON.stringify(filter); - - $http.get(`${this.url}?filter=${json}`).then( - json => this.onItemRequest(json.data), - json => this.onItemRequest(null) - ); - }, - onItemRequest: function(data) { - if(data && data.length > 0) - this.showItem(data[0]); - else - this.showItem(null); - }, requestData: function(textFilter, append) { let where = {}; - if(textFilter) where[this.showField] = {ilike: textFilter}; - let skip = 0; + if(textFilter) + where[this.showField] = {ilike: textFilter}; if(append && this.data) skip = this.data.length; @@ -121,15 +102,20 @@ function controller($http, $element, $attrs, $scope, $parse, $document, popoverP limit: this.maxRows }; - this.lastRequest = textFilter; + this.lastRequest = textFilter ? textFilter : ''; let json = JSON.stringify(filter); - $http.get(`${this.url}?filter=${json}`).then( + if(this.currentRequest) + this.currentRequest.resolve(); + + this.currentRequest = $http.get(`${this.url}?filter=${json}`); + this.currentRequest.then( json => this.onRequest(json.data, append), json => this.onRequest([]) ); }, onRequest: function(data, append) { + this.currentRequest = null; this.moreData = data.length >= this.maxRows; if(!append || !this.data) @@ -148,39 +134,46 @@ function controller($http, $element, $attrs, $scope, $parse, $document, popoverP }, setPopoverData: function(data) { this.popoverData = data; - + this.popoverDataReady(); + }, + popoverDataReady: function() { if(this.hasFocus) this.showPopover(); }, showPopover: function() { if(!this.data) return; - //FIXME - this.hidePopover(); - - let popover = $document[0].createElement('ul'); - popover.addEventListener('click', - (e) => this.onPopoverClick(e)); - popover.addEventListener('mousedown', - (e) => this.onPopoverMousedown(e)); - popover.className = 'vn-autocomplete'; + let fragment = $document[0].createDocumentFragment(); let data = this.popoverData; for(let i = 0; i < data.length; i++) { let li = $document[0].createElement('li'); li.appendChild($document[0].createTextNode(data[i][this.showField])); - popover.appendChild(li); + fragment.appendChild(li); } if(this.moreData) { let li = $document[0].createElement('li'); li.appendChild($document[0].createTextNode('Load more')); li.className = 'load-more'; - popover.appendChild(li); + fragment.appendChild(li); } - popoverProvider.show(popover, this.input); - this.popover = popover; + if (!this.popover) { + let popover = $document[0].createElement('ul'); + popover.addEventListener('click', + (e) => this.onPopoverClick(e)); + popover.addEventListener('mousedown', + (e) => this.onPopoverMousedown(e)); + popover.className = 'vn-autocomplete'; + popover.appendChild(fragment); + popoverProvider.show(popover, this.input); + this.popover = popover; + } + else { + this.popover.innerHTML = ''; + this.popover.appendChild(fragment); + } }, hidePopover: function() { if(!this.popover) return; @@ -224,6 +217,7 @@ function controller($http, $element, $attrs, $scope, $parse, $document, popoverP }, onBlur: function() { this.hasFocus = false; + this.restoreShowValue(); this.hidePopover(); }, onKeydown: function(event) { @@ -232,7 +226,8 @@ function controller($http, $element, $attrs, $scope, $parse, $document, popoverP this.selectPopoverOption(this.activeOption); break; case 27: // Escape - this.hidePopover(); + this.restoreShowValue(); + this.input.select(); break; case 38: // Arrow up this.activateOption(this.activeOption-1); @@ -249,7 +244,7 @@ function controller($http, $element, $attrs, $scope, $parse, $document, popoverP onKeyup: function(event) { if(!this.isKeycodePrintable(event.keyCode)) return; if(this.timeoutId) clearTimeout(this.timeoutId); - this.timeoutId = setTimeout(() => this.onTimeout(), this.filterDelay); + this.timeoutId = setTimeout(() => this.onTimeout(), this.requestDelay); }, onTimeout: function() { this.loadData(this.input.value); @@ -264,22 +259,63 @@ function controller($http, $element, $attrs, $scope, $parse, $document, popoverP || (keyCode > 185 && keyCode < 193) // ;=,-./` || (keyCode > 218 && keyCode < 223); // [\]' }, + restoreShowValue: function() { + this.putItem(this.item); + }, + requestItem: function() { + if(!this.model) return; + + let where = {}; + where[this.valueField] = this.model; + + let filter = { + fields: this.getRequestFields(), + where: where, + }; + + let json = JSON.stringify(filter); + + $http.get(`${this.url}?filter=${json}`).then( + json => this.onItemRequest(json.data), + json => this.onItemRequest(null) + ); + }, + onItemRequest: function(data) { + if(data && data.length > 0) + this.showItem(data[0]); + else + this.showItem(null); + }, activateOption: function(index) { + if(!this.popover) this.showPopover(); - let childs = this.popover.childNodes; + let popover = this.popover; + let childs = popover.childNodes; + let len = this.popoverData.length; if(this.activeOption >= 0) childs[this.activeOption].className = ''; - if(index >= childs.length) + if(index >= len) index = 0; else if(index < 0) - index = childs.length - 1; + index = len - 1; - if (index >= 0) - childs[index].className = 'active'; + if (index >= 0) { + let opt = childs[index]; + let top = popover.scrollTop; + let height = popover.clientHeight; + + if(opt.offsetTop + opt.offsetHeight > top + height) + top = opt.offsetTop + opt.offsetHeight - height; + else if(opt.offsetTop < top) + top = opt.offsetTop; + + opt.className = 'active'; + popover.scrollTop = top; + } this.activeOption = index; },