From 3e1641796569e8da24bba08d436bcbad5aa01ba7 Mon Sep 17 00:00:00 2001 From: Juan Ferrer Toribio Date: Thu, 19 Jan 2017 14:45:50 +0100 Subject: [PATCH 01/12] Combo v3 --- @salix/core/src/autocomplete/index.js | 202 +++++++++++------- @salix/core/src/autocomplete/index.mdl.html | 4 +- @salix/core/src/autocomplete/style.css | 6 +- @salix/core/src/popover/index.js | 1 + @salix/crud/src/client/basic-data/index.js | 6 +- @salix/crud/src/client/fiscal-data/index.html | 30 ++- @salix/crud/src/client/fiscal-data/index.js | 12 -- 7 files changed, 152 insertions(+), 109 deletions(-) diff --git a/@salix/core/src/autocomplete/index.js b/@salix/core/src/autocomplete/index.js index cb153da0e..5d0ccf7e2 100644 --- a/@salix/core/src/autocomplete/index.js +++ b/@salix/core/src/autocomplete/index.js @@ -1,82 +1,154 @@ import {module} from '../module'; export {factory as mdlFactory} from './index.mdl'; -import * as resolveFactory from '../resolveDefaultComponents'; -import * as normalizerFactory from '../inputAttrsNormalizer'; require('./style.css'); -directive.$inject = [resolveFactory.NAME, normalizerFactory.NAME]; -export function directive(resolve, normalizer) { - return { - restrict: 'E', - transclude: true, - scope: { - url: '@', - showField: '@', - valueField: '@', - model: '<' - }, - template: function(element, attrs) { - normalizer.normalize(attrs); - return resolve.getTemplate('autocomplete', attrs); - }, - link: function(scope, element, attrs) { - scope.$watch(attrs.model, () => { - let mdlField = element[0].firstChild.MaterialTextfield; - if (mdlField) - mdlField.updateClasses_(); - }); - componentHandler.upgradeElement(element[0].firstChild); - }, - controller: controller - }; +export const component = { + restrict: 'E', + transclude: true, + bindings: { + url: '@', + showField: '@', + valueField: '@', + model: '<' + }, + template: template, + controller: controller +}; +module.component('vnAutocomplete', component); + +template.$inject = ['$element', '$attrs', 'vnInputAttrsNormalizer', 'vnResolveDefaultComponent']; +function template($element, $attrs, normalizer, resolve) { + normalizer.normalize($attrs); + return resolve.getTemplate('autocomplete', $attrs); } -module.directive('vnAutocomplete', directive); controller.$inject = ['$http', '$element', '$attrs', '$scope', '$parse', '$document', 'vnPopover']; -export function controller($http, $element, $attrs, $scope, $parse, $document, popover) { +function controller($http, $element, $attrs, $scope, $parse, $document, popover) { let dropdown = null; let input = $element.find('input'); let data = []; let locked = false; - - $http.get($scope.url).then( - json => { - data = json.data; - setTimeout(function() { - $scope.setValue($scope.model); - }); - }, - json => {data = [];} - ); + let timeoutId = null; $scope.$watch($attrs.model, (newValue) => { if(!locked) { locked = true; - $scope.setValue(newValue); + this.setValue(newValue); locked = false; } - }); - $scope.setValue = function(value) { + let mdlField = $element[0].firstChild.MaterialTextfield; + if (mdlField) + mdlField.updateClasses_(); + }); + componentHandler.upgradeElement($element[0].firstChild); + + this.loadData = function(where, callback) { + if(!where) where = {}; + let fields = {}; + fields[this.valueField] = true; + fields[this.showField] = true; + + let filter = { + fields: fields, + where: where, + order: `${this.showField} ASC`, + limit: 5 + }; + + let json = JSON.stringify(filter); + + $http.get(`${this.url}?filter=${json}`).then( + json => { + data = json.data; + if (callback) callback(); + }, + json => { + data = []; + } + ); + }; + + this.onClick = function() { + input[0].select(); + this.showDropdown(); + }; + + this.showDropdown = function() { + //FIXME + popover.hide(); + + dropdown = $document[0].createElement('ul'); + dropdown.addEventListener('click', + (e) => this.onOptionClick(e)); + dropdown.className = 'vn-dropdown'; + + for(let i = 0; i < data.length; i++) { + let li = $document[0].createElement('li'); + li.tabIndex = 0; + li.appendChild($document[0].createTextNode(data[i][this.showField])); + dropdown.appendChild(li); + } + + popover.show(dropdown, input); + } + + this.onOptionClick = function(event) { + popover.hide(); + + let childs = dropdown.childNodes; + for(let i = 0; i < childs.length; i++) + if(childs[i] === event.target) { + this.selectOptionByIndex(i); + break; + } + } + + this.onTimeout = function() { + let value = input.val(); + let filter = {}; + filter[this.showField] = {ilike: value}; + this.loadData(filter, () => this.showDropdown()); + clearTimeout(timeoutId); + timeoutId = null; + } + + this.onKeyup = function(event) { + if(timeoutId) clearTimeout(timeoutId); + console.log(event.keyCode); + + switch(event.keyCode) { + case 13: // Enter + this.selectOptionByIndex(0); + return; + case 40: // Arrow down + dropdown.firstChild.focus(); + return; + } + + timeoutId = setTimeout(() => this.onTimeout(), 300); + }; + + this.setValue = function(value) { let index = -1; if(value && data) for(let i = 0; i < data.length; i++) - if(data[i][$scope.valueField] == value) { - $scope.selectOptionByIndex(i); + if(data[i][this.valueField] == value) { + this.selectOptionByIndex(i); return; } - $scope.selectOptionByIndex(-1); + this.selectOptionByIndex(-1); } - $scope.selectOptionByIndex = function(index) { + this.selectOptionByIndex = function(index) { let value; - if(index >= 0) { + if(index >= 0 && index < data.length) { let item = data[index]; - input.val(item[$scope.showField]); - value = item[$scope.valueField]; + input.val(item[this.showField]); + value = item[this.valueField]; } else { input.val(''); @@ -92,33 +164,7 @@ export function controller($http, $element, $attrs, $scope, $parse, $document, p } } - function onOptionClick(event) { - popover.hide(); - - let childs = dropdown.childNodes; - for(let i = 0; i < childs.length; i++) - if(childs[i] === event.target) { - $scope.selectOptionByIndex(i); - break; - } - } - - $scope.onClick = () => { - dropdown = $document[0].createElement('ul'); - dropdown.addEventListener('click', onOptionClick); - dropdown.className = 'vn-dropdown'; - - for(let i = 0; i < data.length; i++) { - let item = $document[0].createElement('li'); - item.className = 'vn-dropdown-item'; - item.appendChild($document[0].createTextNode(data[i][$scope.showField])); - dropdown.appendChild(item); - } - - popover.show(dropdown, input); - }; - - $scope.onKeypress = () => { - console.log(input.val()); - }; + this.loadData(null, () => { + setTimeout(() => this.setValue(this.model)); + }); } diff --git a/@salix/core/src/autocomplete/index.mdl.html b/@salix/core/src/autocomplete/index.mdl.html index 04ef50d81..6b72b2e9a 100644 --- a/@salix/core/src/autocomplete/index.mdl.html +++ b/@salix/core/src/autocomplete/index.mdl.html @@ -1,4 +1,4 @@ -
- +
+
diff --git a/@salix/core/src/autocomplete/style.css b/@salix/core/src/autocomplete/style.css index 39811f1a1..32d0fef27 100644 --- a/@salix/core/src/autocomplete/style.css +++ b/@salix/core/src/autocomplete/style.css @@ -4,15 +4,15 @@ margin: 0; padding: 0; } -.vn-dropdown-item { +.vn-dropdown > li { display: block; padding: .8em; margin: 0; } -.vn-dropdown-item:hover { +.vn-dropdown > li:hover { background-color: rgba(1,1,1,.1); cursor: pointer; } -.vn-dropdown-item:active { +.vn-dropdown > li:active { background-color: rgba(1,1,1,.2); } \ No newline at end of file diff --git a/@salix/core/src/popover/index.js b/@salix/core/src/popover/index.js index d2ef01b6f..e8f28cc69 100644 --- a/@salix/core/src/popover/index.js +++ b/@salix/core/src/popover/index.js @@ -77,6 +77,7 @@ function provider($document, $compile) { this.show(childElement, parent); }, hide: function() { + if(!this.popover) return; $document.off('mousedown', this.docMouseDownHandler); $document[0].body.removeChild (this.popover); this.popover = null; diff --git a/@salix/crud/src/client/basic-data/index.js b/@salix/crud/src/client/basic-data/index.js index 9d8da6f5d..33ae58e41 100644 --- a/@salix/crud/src/client/basic-data/index.js +++ b/@salix/crud/src/client/basic-data/index.js @@ -21,11 +21,7 @@ export const COMPONENT = { this.$onDestroy = function() { deregister(); }; -/* - $http.get('/client/api/SalesPeople').then( - json => {this.sales = json.data;} - ); -*/ + function callback(transition) { if (!equalsObject(self.client, self.clientOld)) { self.state = transition.to().name; diff --git a/@salix/crud/src/client/fiscal-data/index.html b/@salix/crud/src/client/fiscal-data/index.html index 8a4d59651..d4de95dbd 100644 --- a/@salix/crud/src/client/fiscal-data/index.html +++ b/@salix/crud/src/client/fiscal-data/index.html @@ -13,12 +13,20 @@ - - - - - - + + + + @@ -27,9 +35,13 @@ Información de facturación - - - + + diff --git a/@salix/crud/src/client/fiscal-data/index.js b/@salix/crud/src/client/fiscal-data/index.js index 401c22d97..c589a4cba 100644 --- a/@salix/crud/src/client/fiscal-data/index.js +++ b/@salix/crud/src/client/fiscal-data/index.js @@ -12,18 +12,6 @@ export const COMPONENT = { var self = this; var deregister = $transitions.onStart({ }, callback); - $http.get('/client/api/Countries').then( - json => this.countries = json.data - ); - - $http.get('/client/api/Provinces').then( - json => this.provinces = json.data - ); - - $http.get('/client/api/PaymentMethods').then( - json => this.payments = json.data - ); - this.submit = function() { if (!equalsObject(this.client, this.clientOld)) { this.client.modify = "FiscalData"; From c4afb057aa9b6f677416d94e5a324e83e3fcbe28 Mon Sep 17 00:00:00 2001 From: Juan Ferrer Toribio Date: Thu, 19 Jan 2017 14:47:51 +0100 Subject: [PATCH 02/12] Errores solucionados --- @salix/core/src/autocomplete/index.js | 1 - 1 file changed, 1 deletion(-) diff --git a/@salix/core/src/autocomplete/index.js b/@salix/core/src/autocomplete/index.js index 5d0ccf7e2..ab6240996 100644 --- a/@salix/core/src/autocomplete/index.js +++ b/@salix/core/src/autocomplete/index.js @@ -115,7 +115,6 @@ function controller($http, $element, $attrs, $scope, $parse, $document, popover) this.onKeyup = function(event) { if(timeoutId) clearTimeout(timeoutId); - console.log(event.keyCode); switch(event.keyCode) { case 13: // Enter From 8061d58ad886a659deb16e351b35352912631327 Mon Sep 17 00:00:00 2001 From: Juan Ferrer Toribio Date: Thu, 19 Jan 2017 18:11:30 +0100 Subject: [PATCH 03/12] Combo v3 --- @salix/core/src/autocomplete/index.js | 263 ++++++++++++-------- @salix/core/src/autocomplete/index.mdl.html | 14 +- @salix/core/src/autocomplete/style.css | 6 +- 3 files changed, 168 insertions(+), 115 deletions(-) diff --git a/@salix/core/src/autocomplete/index.js b/@salix/core/src/autocomplete/index.js index ab6240996..b5c9f7f27 100644 --- a/@salix/core/src/autocomplete/index.js +++ b/@salix/core/src/autocomplete/index.js @@ -29,6 +29,7 @@ function controller($http, $element, $attrs, $scope, $parse, $document, popover) let data = []; let locked = false; let timeoutId = null; + let activeOption = -1; $scope.$watch($attrs.model, (newValue) => { if(!locked) { @@ -43,125 +44,167 @@ function controller($http, $element, $attrs, $scope, $parse, $document, popover) }); componentHandler.upgradeElement($element[0].firstChild); - this.loadData = function(where, callback) { - if(!where) where = {}; - let fields = {}; - fields[this.valueField] = true; - fields[this.showField] = true; + Object.assign(this, { + loadData: function(where, callback) { + if(!where) where = {}; + let fields = {}; + fields[this.valueField] = true; + fields[this.showField] = true; - let filter = { - fields: fields, - where: where, - order: `${this.showField} ASC`, - limit: 5 - }; + let filter = { + fields: fields, + where: where, + order: `${this.showField} ASC`, + limit: 5 + }; - let json = JSON.stringify(filter); + let json = JSON.stringify(filter); - $http.get(`${this.url}?filter=${json}`).then( - json => { - data = json.data; - if (callback) callback(); - }, - json => { - data = []; + $http.get(`${this.url}?filter=${json}`).then( + json => { + data = json.data; + if (callback) callback(); + }, + json => { + data = []; + } + ); + }, + showPopover: function() { + //FIXME + this.hidePopover(); + + dropdown = $document[0].createElement('ul'); + dropdown.addEventListener('click', + (e) => this.onPopoverClick(e)); + dropdown.addEventListener('mousedown', + (e) => this.onPopoverMousedown(e)); + dropdown.className = 'vn-dropdown'; + + for(let i = 0; i < data.length; i++) { + let li = $document[0].createElement('li'); + li.appendChild($document[0].createTextNode(data[i][this.showField])); + dropdown.appendChild(li); } - ); - }; - this.onClick = function() { - input[0].select(); - this.showDropdown(); - }; + popover.show(dropdown, input); + }, + hidePopover: function() { + activeOption = -1; + popover.hide(); + dropdown = null; + }, + onPopoverClick: function(event) { + let childs = dropdown.childNodes; + for(let i = 0; i < childs.length; i++) + if(childs[i] === event.target) { + this.selectOptionByIndex(i); + break; + } - this.showDropdown = function() { - //FIXME - popover.hide(); - - dropdown = $document[0].createElement('ul'); - dropdown.addEventListener('click', - (e) => this.onOptionClick(e)); - dropdown.className = 'vn-dropdown'; - - for(let i = 0; i < data.length; i++) { - let li = $document[0].createElement('li'); - li.tabIndex = 0; - li.appendChild($document[0].createTextNode(data[i][this.showField])); - dropdown.appendChild(li); - } - - popover.show(dropdown, input); - } - - this.onOptionClick = function(event) { - popover.hide(); - - let childs = dropdown.childNodes; - for(let i = 0; i < childs.length; i++) - if(childs[i] === event.target) { - this.selectOptionByIndex(i); - break; - } - } - - this.onTimeout = function() { - let value = input.val(); - let filter = {}; - filter[this.showField] = {ilike: value}; - this.loadData(filter, () => this.showDropdown()); - clearTimeout(timeoutId); - timeoutId = null; - } - - this.onKeyup = function(event) { - if(timeoutId) clearTimeout(timeoutId); - - switch(event.keyCode) { - case 13: // Enter - this.selectOptionByIndex(0); + this.hidePopover(); + }, + onPopoverMousedown: function(event) { + // Prevents input from loosing focus + event.preventDefault(); + }, + onFocus: function() { + input[0].select(); + this.showPopover(); + }, + onBlur: function() { + this.hidePopover(); + }, + onKeypress: function(event) { + if(dropdown) + switch(event.keyCode) { + case 13: // Enter + this.selectOptionByIndex(activeOption); + return; + case 38: // Arrow up + this.activateOption(activeOption-1); + return; + case 40: // Arrow down + this.activateOption(activeOption+1); + return; + } + }, + onClick: function(event) { + if(!dropdown) + this.showPopover(); + }, + onKeyup: function(event) { + if(!this.isKeycodePrintable(event.keyCode)) return; - case 40: // Arrow down - dropdown.firstChild.focus(); + + if(timeoutId) clearTimeout(timeoutId); + timeoutId = setTimeout(() => this.onTimeout(), 300); + }, + onTimeout: function() { + let value = input.val(); + let filter = {}; + filter[this.showField] = {ilike: value}; + this.loadData(filter, () => this.showPopover()); + timeoutId = null; + }, + isKeycodePrintable: function(keycode) { + return keycode == 32 // Spacebar + || (keycode > 47 && keycode < 58) // Numbers + || (keycode > 64 && keycode < 91) // Letters + || (keycode > 95 && keycode < 112) // Numpad + || (keycode > 185 && keycode < 193) // ;=,-./` + || (keycode > 218 && keycode < 223); // [\]' + }, + activateOption: function(index) { + let childs = dropdown.childNodes; + + if(activeOption >= 0) + childs[activeOption].className = ''; + + if(index >= childs.length) + index = 0; + else if (index < 0) + index = childs.length - 1; + + if (index >= 0) + childs[index].className = 'active'; + + activeOption = index; + }, + setValue: function(value) { + let index = -1; + + if(value && data) + for(let i = 0; i < data.length; i++) + if(data[i][this.valueField] == value) { + this.selectOptionByIndex(i); return; + } + + this.selectOptionByIndex(-1); + }, + selectOptionByIndex: function(index) { + let value; + + if(index >= 0 && index < data.length) { + let item = data[index]; + input.val(item[this.showField]); + value = item[this.valueField]; + } + else { + input.val(''); + value = undefined; + } + + if(!locked) { + $scope.$apply(function () { + locked = true; + $parse($attrs.model).assign($scope, value); + locked = false; + }); + } } - - timeoutId = setTimeout(() => this.onTimeout(), 300); - }; - - this.setValue = function(value) { - let index = -1; - - if(value && data) - for(let i = 0; i < data.length; i++) - if(data[i][this.valueField] == value) { - this.selectOptionByIndex(i); - return; - } - - this.selectOptionByIndex(-1); - } - - this.selectOptionByIndex = function(index) { - let value; - - if(index >= 0 && index < data.length) { - let item = data[index]; - input.val(item[this.showField]); - value = item[this.valueField]; - } - else { - input.val(''); - value = undefined; - } - - if(!locked) { - $scope.$apply(function () { - locked = true; - $parse($attrs.model).assign($scope, value); - locked = false; - }); - } - } + }); this.loadData(null, () => { setTimeout(() => this.setValue(this.model)); diff --git a/@salix/core/src/autocomplete/index.mdl.html b/@salix/core/src/autocomplete/index.mdl.html index 6b72b2e9a..160659871 100644 --- a/@salix/core/src/autocomplete/index.mdl.html +++ b/@salix/core/src/autocomplete/index.mdl.html @@ -1,4 +1,14 @@ -
- +
+
diff --git a/@salix/core/src/autocomplete/style.css b/@salix/core/src/autocomplete/style.css index 32d0fef27..2b4e841f3 100644 --- a/@salix/core/src/autocomplete/style.css +++ b/@salix/core/src/autocomplete/style.css @@ -9,10 +9,10 @@ padding: .8em; margin: 0; } +.vn-dropdown > li.active { + background-color: rgba(1,1,1,.1); +} .vn-dropdown > li:hover { background-color: rgba(1,1,1,.1); cursor: pointer; -} -.vn-dropdown > li:active { - background-color: rgba(1,1,1,.2); } \ No newline at end of file From 768b27ae9e8f6e94e051bea2e36a320f1e33576d Mon Sep 17 00:00:00 2001 From: Juan Ferrer Toribio Date: Thu, 19 Jan 2017 18:48:33 +0100 Subject: [PATCH 04/12] Combo v5 --- .../app/src/components/searchbar/searchbar.js | 2 +- @salix/core/src/autocomplete/index.js | 62 ++++++++++--------- @salix/core/src/autocomplete/style.css | 8 +-- @salix/core/src/popover/index.js | 2 +- 4 files changed, 40 insertions(+), 34 deletions(-) diff --git a/@salix/app/src/components/searchbar/searchbar.js b/@salix/app/src/components/searchbar/searchbar.js index ff5987a55..9a013a5e7 100644 --- a/@salix/app/src/components/searchbar/searchbar.js +++ b/@salix/app/src/components/searchbar/searchbar.js @@ -19,7 +19,7 @@ function controller($element, $scope, $document, $compile, popover) { this.onClick = function(event) { var child = $document[0].createElement(this.popover); $compile(child)($scope); - popover.show(child, $element); + popover.show(child, $element[0]); // XXX: ¿Existe una forma más adecuada de acceder al controlador de un componente? var childCtrl = angular.element(child).isolateScope().$ctrl; diff --git a/@salix/core/src/autocomplete/index.js b/@salix/core/src/autocomplete/index.js index b5c9f7f27..7a727598d 100644 --- a/@salix/core/src/autocomplete/index.js +++ b/@salix/core/src/autocomplete/index.js @@ -23,9 +23,9 @@ function template($element, $attrs, normalizer, resolve) { } controller.$inject = ['$http', '$element', '$attrs', '$scope', '$parse', '$document', 'vnPopover']; -function controller($http, $element, $attrs, $scope, $parse, $document, popover) { - let dropdown = null; - let input = $element.find('input'); +function controller($http, $element, $attrs, $scope, $parse, $document, popoverProvider) { + let input = $element.find('input')[0]; + let popover = null; let data = []; let locked = false; let timeoutId = null; @@ -55,7 +55,7 @@ function controller($http, $element, $attrs, $scope, $parse, $document, popover) fields: fields, where: where, order: `${this.showField} ASC`, - limit: 5 + limit: 10 }; let json = JSON.stringify(filter); @@ -74,28 +74,29 @@ function controller($http, $element, $attrs, $scope, $parse, $document, popover) //FIXME this.hidePopover(); - dropdown = $document[0].createElement('ul'); - dropdown.addEventListener('click', + popover = $document[0].createElement('ul'); + popover.addEventListener('click', (e) => this.onPopoverClick(e)); - dropdown.addEventListener('mousedown', + popover.addEventListener('mousedown', (e) => this.onPopoverMousedown(e)); - dropdown.className = 'vn-dropdown'; + popover.className = 'vn-autocomplete-popover'; for(let i = 0; i < data.length; i++) { let li = $document[0].createElement('li'); li.appendChild($document[0].createTextNode(data[i][this.showField])); - dropdown.appendChild(li); + popover.appendChild(li); } - popover.show(dropdown, input); + popoverProvider.show(popover, input); }, hidePopover: function() { + if(!popover) return; activeOption = -1; - popover.hide(); - dropdown = null; + popoverProvider.hide(); + popover = null; }, onPopoverClick: function(event) { - let childs = dropdown.childNodes; + let childs = popover.childNodes; for(let i = 0; i < childs.length; i++) if(childs[i] === event.target) { this.selectOptionByIndex(i); @@ -109,17 +110,19 @@ function controller($http, $element, $attrs, $scope, $parse, $document, popover) event.preventDefault(); }, onFocus: function() { - input[0].select(); + input.select(); this.showPopover(); }, onBlur: function() { this.hidePopover(); }, onKeypress: function(event) { - if(dropdown) switch(event.keyCode) { case 13: // Enter - this.selectOptionByIndex(activeOption); + if(popover && activeOption != -1) { + this.selectOptionByIndex(activeOption); + this.hidePopover(); + } return; case 38: // Arrow up this.activateOption(activeOption-1); @@ -130,7 +133,7 @@ function controller($http, $element, $attrs, $scope, $parse, $document, popover) } }, onClick: function(event) { - if(!dropdown) + if(!popover) this.showPopover(); }, onKeyup: function(event) { @@ -141,7 +144,7 @@ function controller($http, $element, $attrs, $scope, $parse, $document, popover) timeoutId = setTimeout(() => this.onTimeout(), 300); }, onTimeout: function() { - let value = input.val(); + let value = input.value; let filter = {}; filter[this.showField] = {ilike: value}; this.loadData(filter, () => this.showPopover()); @@ -156,7 +159,10 @@ function controller($http, $element, $attrs, $scope, $parse, $document, popover) || (keycode > 218 && keycode < 223); // [\]' }, activateOption: function(index) { - let childs = dropdown.childNodes; + if(!popover) + this.showPopover(); + + let childs = popover.childNodes; if(activeOption >= 0) childs[activeOption].className = ''; @@ -188,25 +194,25 @@ function controller($http, $element, $attrs, $scope, $parse, $document, popover) if(index >= 0 && index < data.length) { let item = data[index]; - input.val(item[this.showField]); + input.value = item[this.showField]; value = item[this.valueField]; } else { - input.val(''); + input.value = ''; value = undefined; } if(!locked) { - $scope.$apply(function () { - locked = true; - $parse($attrs.model).assign($scope, value); - locked = false; + setTimeout (() => { + $scope.$apply(function () { + locked = true; + $parse($attrs.model).assign($scope, value); + locked = false; + }); }); } } }); - this.loadData(null, () => { - setTimeout(() => this.setValue(this.model)); - }); + this.loadData(null, () => this.setValue(this.model)); } diff --git a/@salix/core/src/autocomplete/style.css b/@salix/core/src/autocomplete/style.css index 2b4e841f3..1b4377fc9 100644 --- a/@salix/core/src/autocomplete/style.css +++ b/@salix/core/src/autocomplete/style.css @@ -1,18 +1,18 @@ -.vn-dropdown { +.vn-autocomplete-popover { list-style-type: none; padding: 1em; margin: 0; padding: 0; } -.vn-dropdown > li { +.vn-autocomplete-popover > li { display: block; padding: .8em; margin: 0; } -.vn-dropdown > li.active { +.vn-autocomplete-popover > li.active { background-color: rgba(1,1,1,.1); } -.vn-dropdown > li:hover { +.vn-autocomplete-popover > li:hover { background-color: rgba(1,1,1,.1); cursor: pointer; } \ No newline at end of file diff --git a/@salix/core/src/popover/index.js b/@salix/core/src/popover/index.js index e8f28cc69..629d74835 100644 --- a/@salix/core/src/popover/index.js +++ b/@salix/core/src/popover/index.js @@ -47,7 +47,7 @@ function provider($document, $compile) { } if(parent) { - let parentNode = parent[0]; + let parentNode = parent; let rect = parentNode.getBoundingClientRect(); let left = rect.left; let top = rect.top + spacing + parentNode.offsetHeight; From 183406812319b178289603f4edf81c6d3bca19fd Mon Sep 17 00:00:00 2001 From: Juan Ferrer Toribio Date: Thu, 19 Jan 2017 19:03:06 +0100 Subject: [PATCH 05/12] =?UTF-8?q?Datos=20a=C3=B1adidos=20a=20db.json?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- db.json | 67 +++++++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 61 insertions(+), 6 deletions(-) diff --git a/db.json b/db.json index 529d5023b..df67e9611 100644 --- a/db.json +++ b/db.json @@ -4,10 +4,10 @@ "AccessToken": 2, "Client": 16, "PaymentMethod": 4, - "SalesPerson": 4, + "SalesPerson": 11, "Address": 58, - "Country": 3, - "Province": 3, + "Country": 10, + "Province": 44, "Agency": 4, "Account": 20, "ClientObservation": 1265 @@ -32,7 +32,14 @@ "SalesPerson": { "1": "{\"id\":1,\"name\":\"Jesus Brocal\"}", "2": "{\"name\":\"Juan Carlos Lorenzo\",\"id\":2}", - "3": "{\"name\":\"Carlos Zambrano\",\"id\":3}" + "3": "{\"name\":\"Carlos Zambrano\",\"id\":3}", + "4": "{\"name\":\"Juan Ferrer\",\"id\":4}", + "5": "{\"name\":\"Javi Gallego\",\"id\":5}", + "6": "{\"name\":\"Vicente Falco\",\"id\":6}", + "7": "{\"name\":\"Nelo Sanchez\",\"id\":7}", + "8": "{\"name\":\"Francisco Natek\",\"id\":8}", + "9": "{\"name\":\"Silverio Rodriguez\",\"id\":9}", + "10": "{\"name\":\"Manoli\",\"id\":10}" }, "Address": { "57": "{\"street\":\"Avda Espioca\",\"consignee\":\"Vicente\",\"city\":\"Silla\",\"postcode\":\"46900\",\"phone\":\"963242100\",\"province\":\"1\",\"agency\":\"3\",\"id\":57,\"enabled\":true,\"default\":true}", @@ -41,11 +48,59 @@ }, "Country": { "1": "{\"id\":1,\"name\":\"Spain\"}", - "2": "{\"id\":2,\"name\":\"France\"}" + "2": "{\"id\":2,\"name\":\"France\"}", + "3": "{\"name\":\"Italy\",\"id\":3}", + "4": "{\"name\":\"Germany\",\"id\":4}", + "5": "{\"name\":\"Portugal\",\"id\":5}", + "6": "{\"name\":\"Netherlands\",\"id\":6}", + "7": "{\"name\":\"Colombia\",\"id\":7}", + "8": "{\"name\":\"Mexico\",\"id\":8}", + "9": "{\"name\":\"USA\",\"id\":9}" }, "Province": { "1": "{\"id\":1,\"name\":\"Valencia\"}", - "2": "{\"id\":2,\"name\":\"Madrid\"}" + "2": "{\"id\":2,\"name\":\"Madrid\"}", + "3": "{\"id\":3,\"name\":\"Alicante\"}", + "4": "{\"id\":4,\"name\":\"Castellon\"}", + "5": "{\"id\":5,\"name\":\"Murcia\"}", + "6": "{\"id\":6,\"name\":\"Albacete\"}", + "7": "{\"id\":7,\"name\":\"Barcelona\"}", + "8": "{\"id\":8,\"name\":\"Tarragona\"}", + "9": "{\"id\":9,\"name\":\"Gerona\"}", + "10": "{\"id\":10,\"name\":\"Granada\"}", + "11": "{\"id\":11,\"name\":\"Guadalajara\"}", + "12": "{\"id\":12,\"name\":\"Cuenca\"}", + "13": "{\"id\":13,\"name\":\"Asturias\"}", + "14": "{\"id\":14,\"name\":\"Almería\"}", + "15": "{\"id\":15,\"name\":\"Ávila\"}", + "16": "{\"id\":16,\"name\":\"Vadajoz\"}", + "17": "{\"id\":17,\"name\":\"Burgos\"}", + "18": "{\"id\":18,\"name\":\"Málaga\"}", + "19": "{\"id\":19,\"name\":\"Navarra\"}", + "20": "{\"id\":20,\"name\":\"Ceuta\"}", + "21": "{\"id\":21,\"name\":\"Melilla\"}", + "22": "{\"id\":22,\"name\":\"Melilla\"}", + "23": "{\"id\":23,\"name\":\"Zaragoza\"}", + "24": "{\"id\":24,\"name\":\"Zamora\"}", + "25": "{\"id\":25,\"name\":\"Vizcaya\"}", + "26": "{\"id\":26,\"name\":\"Valladolid\"}", + "27": "{\"id\":27,\"name\":\"Toledo\"}", + "28": "{\"id\":28,\"name\":\"Teruel\"}", + "29": "{\"id\":29,\"name\":\"Santa Cruz de Tenerife\"}", + "30": "{\"id\":30,\"name\":\"Soria\"}", + "31": "{\"id\":31,\"name\":\"Sevilla\"}", + "32": "{\"id\":32,\"name\":\"Segovia\"}", + "33": "{\"id\":33,\"name\":\"Salamanca\"}", + "34": "{\"id\":34,\"name\":\"La Rioja\"}", + "35": "{\"id\":35,\"name\":\"Pontevedra\"}", + "36": "{\"id\":36,\"name\":\"Las Palmas\"}", + "37": "{\"id\":37,\"name\":\"Palencia\"}", + "38": "{\"id\":38,\"name\":\"Orense\"}", + "39": "{\"id\":39,\"name\":\"Lugo\"}", + "40": "{\"id\":40,\"name\":\"Lérida\"}", + "41": "{\"id\":41,\"name\":\"León\"}", + "42": "{\"id\":42,\"name\":\"Jaén\"}", + "43": "{\"id\":43,\"name\":\"Baleares\"}" }, "Agency": { "1": "{\"name\":\"Zeleris\",\"id\":1}", From a74925d3804158b4b9d06a04e71dbaf4accf734b Mon Sep 17 00:00:00 2001 From: Juan Ferrer Toribio Date: Thu, 19 Jan 2017 19:15:07 +0100 Subject: [PATCH 06/12] Bug combo solucionado --- @salix/core/src/autocomplete/index.js | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/@salix/core/src/autocomplete/index.js b/@salix/core/src/autocomplete/index.js index 7a727598d..a53d1d27e 100644 --- a/@salix/core/src/autocomplete/index.js +++ b/@salix/core/src/autocomplete/index.js @@ -150,13 +150,14 @@ function controller($http, $element, $attrs, $scope, $parse, $document, popoverP this.loadData(filter, () => this.showPopover()); timeoutId = null; }, - isKeycodePrintable: function(keycode) { - return keycode == 32 // Spacebar - || (keycode > 47 && keycode < 58) // Numbers - || (keycode > 64 && keycode < 91) // Letters - || (keycode > 95 && keycode < 112) // Numpad - || (keycode > 185 && keycode < 193) // ;=,-./` - || (keycode > 218 && keycode < 223); // [\]' + isKeycodePrintable: function(keyCode) { + return keyCode == 32 // Spacebar + || keyCode == 8 // Backspace + || (keyCode > 47 && keyCode < 58) // Numbers + || (keyCode > 64 && keyCode < 91) // Letters + || (keyCode > 95 && keyCode < 112) // Numpad + || (keyCode > 185 && keyCode < 193) // ;=,-./` + || (keyCode > 218 && keyCode < 223); // [\]' }, activateOption: function(index) { if(!popover) From eb4f6f91c10b6b57b11cc36dcf9bc3b1c96e6f55 Mon Sep 17 00:00:00 2001 From: jgallego Date: Fri, 20 Jan 2017 09:22:47 +0100 Subject: [PATCH 07/12] vnDialogConfirm css --- @salix/app/src/app.js | 18 +++++++-------- @salix/core/src/mdl-override.css | 13 +++++++++++ .../src/client/addresses-data-edit/index.js | 2 +- @salix/crud/src/client/confirm/index.html | 23 +++++++++++-------- @salix/crud/src/client/confirm/index.js | 2 ++ @salix/crud/src/client/confirm/style.css | 5 ++++ @salix/crud/src/client/new-note/index.js | 7 +++--- 7 files changed, 46 insertions(+), 24 deletions(-) create mode 100644 @salix/crud/src/client/confirm/style.css diff --git a/@salix/app/src/app.js b/@salix/app/src/app.js index 81835fd89..4683d2169 100644 --- a/@salix/app/src/app.js +++ b/@salix/app/src/app.js @@ -6,14 +6,14 @@ import * as run from './run'; import * as configNgTranslate from './translate'; import * as components from './components'; -import title from './styles/title.css' -import padding from './styles/layout.css' -import margin from './styles/margin.scss' -import layout from './styles/padding.scss' -import background from './styles/background.scss' -import border from './styles/border.scss' -import fontStyle from './styles/font-style.scss' -import misc from './styles/misc.scss' -import display from './styles/display.css' +import title from './styles/title.css'; +import padding from './styles/layout.css'; +import margin from './styles/margin.scss'; +import layout from './styles/padding.scss'; +import background from './styles/background.scss'; +import border from './styles/border.scss'; +import fontStyle from './styles/font-style.scss'; +import misc from './styles/misc.scss'; +import display from './styles/display.css'; bootstrap(); diff --git a/@salix/core/src/mdl-override.css b/@salix/core/src/mdl-override.css index f2ea87bfd..c556fa556 100644 --- a/@salix/core/src/mdl-override.css +++ b/@salix/core/src/mdl-override.css @@ -9,6 +9,8 @@ /* TODO: No utilizar !important */ .mdl-button { font-weight: bolder; + color: #ffa410; + } .mdl-button--colored { color: white !important; @@ -26,3 +28,14 @@ color: white !important; background-color: #ff9400 !important; } + +.mdl-dialog__actions--full-width>*{ + text-align: center; +} + +.mdl-dialog{ + width: 400px; + font-family: raleway-regular; + line-height:60px; + text-align: center; +} \ No newline at end of file diff --git a/@salix/crud/src/client/addresses-data-edit/index.js b/@salix/crud/src/client/addresses-data-edit/index.js index 0e7d785a8..268389dc1 100644 --- a/@salix/crud/src/client/addresses-data-edit/index.js +++ b/@salix/crud/src/client/addresses-data-edit/index.js @@ -13,7 +13,7 @@ export const COMPONENT = { this.copyAddress(); } ); - + $http.get('/client/api/Agencies').then( json => { this.agencies = json.data; diff --git a/@salix/crud/src/client/confirm/index.html b/@salix/crud/src/client/confirm/index.html index 5547c7527..82a6b0f26 100644 --- a/@salix/crud/src/client/confirm/index.html +++ b/@salix/crud/src/client/confirm/index.html @@ -1,11 +1,14 @@ - -
-

- ¿Desea salir sin guardar los cambios? -

-
-
- - -
+ + +
+ ¿Seguro que quieres salir sin guardar? +
+
+ Los cambios que no hayas guardado se perderán +
+
+ + + +
\ No newline at end of file diff --git a/@salix/crud/src/client/confirm/index.js b/@salix/crud/src/client/confirm/index.js index f9c3400bb..877de9b7b 100644 --- a/@salix/crud/src/client/confirm/index.js +++ b/@salix/crud/src/client/confirm/index.js @@ -1,6 +1,8 @@ import template from './index.html'; import {module} from '../../module'; +require('./style.css'); + export const NAME = 'vnDialogConfirm'; export const COMPONENT = { template: template, diff --git a/@salix/crud/src/client/confirm/style.css b/@salix/crud/src/client/confirm/style.css new file mode 100644 index 000000000..97fc32283 --- /dev/null +++ b/@salix/crud/src/client/confirm/style.css @@ -0,0 +1,5 @@ + +.dialog-title{ + color:#424242; + font-family: raleway-bold; +} diff --git a/@salix/crud/src/client/new-note/index.js b/@salix/crud/src/client/new-note/index.js index f1bd48dfa..d9bc9de0e 100644 --- a/@salix/crud/src/client/new-note/index.js +++ b/@salix/crud/src/client/new-note/index.js @@ -6,14 +6,13 @@ export const COMPONENT = { template: template, controllerAs: 'newNote', controller: function($http, $state, copyObject, equalsObject, $transitions, $element) { - this.client = $state.params.id; this.note = {text: null}; var self = this; - + var deregister = $transitions.onStart({ }, callback); copyNote(); - + this.submit = function() { if (this.note) { let observation = this.createNote(); @@ -21,7 +20,7 @@ export const COMPONENT = { json => { this.note = json.data; copyNote(); - $state.go('clientCard.notes'); + $state.go('clientCard.notes'); } ); } From c298205e2fd8d06d8aafe1b479e9f0c06c4ad7ba Mon Sep 17 00:00:00 2001 From: jgallego Date: Fri, 20 Jan 2017 09:34:55 +0100 Subject: [PATCH 08/12] alineacion del activo del descriptor --- @salix/crud/src/client/descriptor/descriptor.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/@salix/crud/src/client/descriptor/descriptor.html b/@salix/crud/src/client/descriptor/descriptor.html index c6a198de2..05a869d34 100644 --- a/@salix/crud/src/client/descriptor/descriptor.html +++ b/@salix/crud/src/client/descriptor/descriptor.html @@ -8,8 +8,8 @@
{{descriptor.client.id}}
{{descriptor.client.name}}
{{descriptor.client.phone}}
+ - - + From 470ff7a6aad95e6dfc6c42a0bc133fa79e376329 Mon Sep 17 00:00:00 2001 From: jgallego Date: Fri, 20 Jan 2017 12:43:38 +0100 Subject: [PATCH 09/12] algun consignatario de prueba --- db.json | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/db.json b/db.json index df67e9611..923d9c442 100644 --- a/db.json +++ b/db.json @@ -2,15 +2,15 @@ "ids": { "User": 2, "AccessToken": 2, - "Client": 16, + "Client": 17, "PaymentMethod": 4, "SalesPerson": 11, - "Address": 58, + "Address": 61, "Country": 10, "Province": 44, "Agency": 4, - "Account": 20, - "ClientObservation": 1265 + "Account": 21, + "ClientObservation": 1268 }, "models": { "User": { @@ -22,7 +22,8 @@ "Client": { "12": "{\"name\":\"Verdnatura\",\"id\":12,\"fi\":\"B97367486\",\"salesPerson\":\"1\",\"telefono\":\"963242100\",\"socialName\":\"Verdnatura Levante SL\",\"active\":true,\"user\":\"verdnatura\",\"fax\":\"963242100\",\"phone\":\"963242101d\",\"email\":\"informatica@verdnatura.es\",\"surcharge\":true,\"cyc\":2345,\"credit\":1000,\"iban\":\"456\",\"street\":\"Avenida Espioca, 100\",\"city\":\"Silla\",\"postcode\":\"46013\",\"mobile\":\"654654654\",\"dueDay\":10,\"gestdoc\":23452343,\"province\":\"2\",\"country\":\"1\",\"modify\":\"BasicData\",\"navigate\":true,\"payMethod\":\"1\"}", "14": "{\"name\":\"Cliente 1\",\"id\":14,\"street\":\"Aaaaaaaaaa\",\"fi\":\"1234567890A\",\"socialName\":\"Cliente 1\",\"fax\":\"963242100\",\"dischargeDate\":\"01/01/2017\",\"telefono\":\"963242100\",\"salesPerson\":\"2\",\"email\":\"informatica@verdnatura.es\",\"city\":\"asdf\",\"postcode\":\"asdf\",\"phone\":\"asdf\",\"mobile\":\"asdf\",\"credit\":2345,\"cyc\":123,\"iban\":\"asdf\",\"dueDay\":345,\"gestdoc\":2435,\"surcharge\":true,\"navigate\":true}", - "15": "{\"name\":\"afsdf\",\"fi\":\"12341234rasf\",\"socialName\":\"asdfasd\",\"dueDay\":5,\"id\":15,\"payMethod\":\"2\",\"salesPerson\":\"1\",\"modify\":\"BasicData\",\"iban\":\"sdfgsdfgsdfg\"}" + "15": "{\"name\":\"afsdf\",\"fi\":\"12341234rasf\",\"socialName\":\"asdfasd\",\"dueDay\":5,\"id\":15,\"payMethod\":\"2\",\"salesPerson\":\"1\",\"modify\":\"BasicData\",\"iban\":\"sdfgsdfgsdfg\"}", + "16": "{\"name\":\"floristeria laasdfas\",\"fi\":\"2345234523d\",\"socialName\":\"23452345assdfgsdfgt\",\"active\":true,\"dueDay\":5,\"id\":16,\"modify\":\"FiscalData\",\"email\":\"asdfopi jso@aosijf.com\",\"phone\":\"654654654\",\"mobile\":\"654456456\",\"fax\":\"456456456\",\"street\":\"asdfasdf\"}" }, "PaymentMethod": { "1": "{\"name\":\"Tarjeta\",\"id\":1}", @@ -43,6 +44,9 @@ }, "Address": { "57": "{\"street\":\"Avda Espioca\",\"consignee\":\"Vicente\",\"city\":\"Silla\",\"postcode\":\"46900\",\"phone\":\"963242100\",\"province\":\"1\",\"agency\":\"3\",\"id\":57,\"enabled\":true,\"default\":true}", + "58": "{\"street\":\"asdfasdfsdf\",\"consignee\":\"oiaspjdfopasidjfopsj\",\"city\":\"asdfasd\",\"postcode\":\"46460\",\"enabled\":true,\"phone\":\"23423342\",\"mobile\":\"234423\",\"default\":false,\"province\":\"19\",\"agency\":\"1\",\"client\":\"16\",\"id\":58}", + "59": "{\"street\":\"asdfasdf\",\"consignee\":\"asdfasdfasdf\",\"city\":\"sdfasdf\",\"postcode\":\"asdfa\",\"enabled\":true,\"phone\":\"a\",\"province\":\"14\",\"agency\":\"3\",\"client\":\"16\",\"id\":59,\"default\":false}", + "60": "{\"street\":\"asdfasdf\",\"consignee\":\"aasdfasdf\",\"city\":\"asdf\",\"postcode\":\"asdf\",\"enabled\":false,\"default\":false,\"province\":\"3\",\"client\":\"16\",\"id\":60}", "63": "{\"street\":\"Avd. Espioca nº 100\",\"consignee\":\"Verndatura Silla\",\"city\":\"Silla\",\"postcode\":\"46460\",\"phone\":\"66666666\",\"mobile\":\"989898888\",\"id\":63,\"province\":\"2\",\"agency\":\"3\",\"default\":false,\"enabled\":false}", "64": "{\"street\":\"Aaa\",\"consignee\":\"aaa\",\"city\":\"121212\",\"postcode\":\"11111\",\"phone\":\"963242100\",\"mobile\":\"11231241423\",\"id\":64,\"default\":false,\"province\":\"1\",\"agency\":\"2\",\"enabled\":false}" }, @@ -110,7 +114,8 @@ "Account": { "1": "{\"id\":1,\"password\":\"joselito\",\"name\":\"asdf\"}", "14": "{\"id\":14,\"active\":true,\"name\":\"f\"}", - "15": "{\"id\":15,\"name\":\"asdf\"}" + "15": "{\"id\":15,\"name\":\"asdf\"}", + "16": "{\"id\":16,\"name\":\"joselito\",\"active\":true}" }, "ClientObservation": { "1258": "{\"text\":\"Nota de prueba 1\",\"creationDate\":\"2017-01-17T15:24:23.320Z\",\"client\":12,\"salesPerson\":\"user\",\"id\":1258}", @@ -119,7 +124,10 @@ "1261": "{\"text\":\"Nota 2\",\"creationDate\":\"2017-01-17T15:35:06.313Z\",\"client\":14,\"salesPerson\":\"user\",\"id\":1261}", "1262": "{\"text\":\"Nota 3\",\"creationDate\":\"2017-01-17T15:35:10.602Z\",\"client\":14,\"salesPerson\":\"user\",\"id\":1262}", "1263": "{\"text\":\"Nota 4\",\"creationDate\":\"2017-01-17T15:35:44.768Z\",\"client\":14,\"salesPerson\":\"user\",\"id\":1263}", - "1264": "{\"text\":\"Nota 5\",\"creationDate\":\"2017-01-17T15:35:50.064Z\",\"client\":14,\"salesPerson\":\"user\",\"id\":1264}" + "1264": "{\"text\":\"Nota 5\",\"creationDate\":\"2017-01-17T15:35:50.064Z\",\"client\":14,\"salesPerson\":\"user\",\"id\":1264}", + "1265": "{\"text\":\"primera nota\",\"creationDate\":\"2017-01-20T10:23:28.000Z\",\"client\":\"16\",\"salesPerson\":\"user\",\"modify\":\"ClientObservation\",\"id\":1265}", + "1266": "{\"text\":\"segunda nota\",\"creationDate\":\"2017-01-20T10:23:37.000Z\",\"client\":\"16\",\"salesPerson\":\"user\",\"modify\":\"ClientObservation\",\"id\":1266}", + "1267": "{\"text\":\"tercera nota\",\"creationDate\":\"2017-01-20T10:23:53.000Z\",\"client\":\"16\",\"salesPerson\":\"user\",\"modify\":\"ClientObservation\",\"id\":1267}" } } } \ No newline at end of file From 0d4e769906fd43af92adef63b8d3308a8aea2bb1 Mon Sep 17 00:00:00 2001 From: Juan Ferrer Toribio Date: Fri, 20 Jan 2017 12:43:58 +0100 Subject: [PATCH 10/12] Combo v6 --- @salix/core/src/autocomplete/index.js | 168 +++++++++++++------- @salix/core/src/autocomplete/index.mdl.html | 2 +- 2 files changed, 115 insertions(+), 55 deletions(-) diff --git a/@salix/core/src/autocomplete/index.js b/@salix/core/src/autocomplete/index.js index a53d1d27e..4fc9168ac 100644 --- a/@salix/core/src/autocomplete/index.js +++ b/@salix/core/src/autocomplete/index.js @@ -24,12 +24,7 @@ function template($element, $attrs, normalizer, resolve) { controller.$inject = ['$http', '$element', '$attrs', '$scope', '$parse', '$document', 'vnPopover']; function controller($http, $element, $attrs, $scope, $parse, $document, popoverProvider) { - let input = $element.find('input')[0]; - let popover = null; - let data = []; let locked = false; - let timeoutId = null; - let activeOption = -1; $scope.$watch($attrs.model, (newValue) => { if(!locked) { @@ -45,8 +40,43 @@ function controller($http, $element, $attrs, $scope, $parse, $document, popoverP componentHandler.upgradeElement($element[0].firstChild); Object.assign(this, { - loadData: function(where, callback) { - if(!where) where = {}; + init: function() { + this.input = $element.find('input')[0]; + this.popover = null; + this.data = null; + this.showData = null; + this.timeoutId = null; + this.activeOption = -1; + this.lastSearch = null; + this.lastRequest = null; + this.maxRows = 10; + this.filterDelay = 350; + this.loadData(); + }, + loadData: function(value) { + // Optimiza la petición + + let lastSearch = this.lastSearch; + if(lastSearch === value) return; + this.lastSearch = value; + + let lastRequest = this.lastRequest; + let requestWillSame = ( + this.data && value && lastRequest + && this.data.length < this.maxRows + && value.substr(0, lastRequest.length) == lastRequest + ); + + if(requestWillSame) { + this.localFilter(value); + return; + } + + // Genera el filtro + + let where = {}; + if(value) where[this.showField] = {ilike: value}; + let fields = {}; fields[this.valueField] = true; fields[this.showField] = true; @@ -55,48 +85,68 @@ function controller($http, $element, $attrs, $scope, $parse, $document, popoverP fields: fields, where: where, order: `${this.showField} ASC`, - limit: 10 + limit: this.maxRows }; + // Envia la petición + + this.lastRequest = value; let json = JSON.stringify(filter); $http.get(`${this.url}?filter=${json}`).then( - json => { - data = json.data; - if (callback) callback(); - }, - json => { - data = []; - } + json => this.setData(json.data), + json => this.setData([]) ); }, + setData: function(data) { + this.data = data; + this.setShowData(this.data); + }, + localFilter: function(value) { + let regex = new RegExp(value, 'i'); + let data = this.data.filter((item) => { + return regex.test(item[this.showField]); + }); + this.setShowData(data); + }, + setShowData: function(data) { + this.showData = data; + + if(this.hasFocus) + this.showPopover(); + else + this.setValue(this.model); + }, showPopover: function() { //FIXME this.hidePopover(); - popover = $document[0].createElement('ul'); + 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'; + let data = this.showData; + 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); } - popoverProvider.show(popover, input); + popoverProvider.show(popover, this.input); + this.popover = popover; }, hidePopover: function() { - if(!popover) return; - activeOption = -1; + if(!this.popover) return; + this.activeOption = -1; popoverProvider.hide(); - popover = null; + this.popover = null; }, onPopoverClick: function(event) { - let childs = popover.childNodes; + let childs = this.popover.childNodes; for(let i = 0; i < childs.length; i++) if(childs[i] === event.target) { this.selectOptionByIndex(i); @@ -110,45 +160,48 @@ function controller($http, $element, $attrs, $scope, $parse, $document, popoverP event.preventDefault(); }, onFocus: function() { - input.select(); + this.hasFocus = true; + this.input.select(); this.showPopover(); }, onBlur: function() { + this.hasFocus = false; this.hidePopover(); }, - onKeypress: function(event) { + onKeydown: function(event) { switch(event.keyCode) { case 13: // Enter - if(popover && activeOption != -1) { - this.selectOptionByIndex(activeOption); + if(this.popover && this.activeOption != -1) { + this.putValue(this.showData[this.activeOption]); this.hidePopover(); } - return; + break; + case 27: // Escape + this.hidePopover(); + break; case 38: // Arrow up - this.activateOption(activeOption-1); - return; + this.activateOption(this.activeOption-1); + break; case 40: // Arrow down - this.activateOption(activeOption+1); + this.activateOption(this.activeOption+1); + break; + default: return; } + + event.preventDefault(); }, onClick: function(event) { - if(!popover) - this.showPopover(); + if(!this.popover) this.showPopover(); }, onKeyup: function(event) { - if(!this.isKeycodePrintable(event.keyCode)) - return; - - if(timeoutId) clearTimeout(timeoutId); - timeoutId = setTimeout(() => this.onTimeout(), 300); + if(!this.isKeycodePrintable(event.keyCode)) return; + if(this.timeoutId) clearTimeout(this.timeoutId); + this.timeoutId = setTimeout(() => this.onTimeout(), this.filterDelay); }, onTimeout: function() { - let value = input.value; - let filter = {}; - filter[this.showField] = {ilike: value}; - this.loadData(filter, () => this.showPopover()); - timeoutId = null; + this.loadData(this.input.value); + this.timeoutId = null; }, isKeycodePrintable: function(keyCode) { return keyCode == 32 // Spacebar @@ -160,13 +213,13 @@ function controller($http, $element, $attrs, $scope, $parse, $document, popoverP || (keyCode > 218 && keyCode < 223); // [\]' }, activateOption: function(index) { - if(!popover) + if(!this.popover) this.showPopover(); - let childs = popover.childNodes; + let childs = this.popover.childNodes; - if(activeOption >= 0) - childs[activeOption].className = ''; + if(this.activeOption >= 0) + childs[this.activeOption].className = ''; if(index >= childs.length) index = 0; @@ -176,30 +229,37 @@ function controller($http, $element, $attrs, $scope, $parse, $document, popoverP if (index >= 0) childs[index].className = 'active'; - activeOption = index; + this.activeOption = index; }, setValue: function(value) { - let index = -1; + let data = this.data; if(value && data) for(let i = 0; i < data.length; i++) if(data[i][this.valueField] == value) { - this.selectOptionByIndex(i); + this.putValue(data[i]); return; } - this.selectOptionByIndex(-1); + this.putValue(null); }, selectOptionByIndex: function(index) { + let data = this.data; + + if(data && index >= 0 && index < data.length) + this.putValue(data[index]); + else + this.putValue(null); + }, + putValue: function(item) { let value; - if(index >= 0 && index < data.length) { - let item = data[index]; - input.value = item[this.showField]; + if(item) { + this.input.value = item[this.showField]; value = item[this.valueField]; } else { - input.value = ''; + this.input.value = ''; value = undefined; } @@ -215,5 +275,5 @@ function controller($http, $element, $attrs, $scope, $parse, $document, popoverP } }); - this.loadData(null, () => this.setValue(this.model)); + this.init(); } diff --git a/@salix/core/src/autocomplete/index.mdl.html b/@salix/core/src/autocomplete/index.mdl.html index 160659871..bef534feb 100644 --- a/@salix/core/src/autocomplete/index.mdl.html +++ b/@salix/core/src/autocomplete/index.mdl.html @@ -5,7 +5,7 @@ rule="*[rule]*" *[enabled]* *[focus]* - ng-keypress="$ctrl.onKeypress($event)" + ng-keydown="$ctrl.onKeydown($event)" ng-click="$ctrl.onClick($event)" ng-keyup="$ctrl.onKeyup($event)" ng-focus="$ctrl.onFocus($event)" From 757ec02d4ee9de685a22367ce9bf1c8ddff6a493 Mon Sep 17 00:00:00 2001 From: Juan Ferrer Toribio Date: Fri, 20 Jan 2017 15:51:17 +0100 Subject: [PATCH 11/12] Combo v6: Cargar mas, Peticiones optimizadas, Errores --- @salix/core/src/autocomplete/index.js | 218 +++++++++++++++--------- @salix/core/src/autocomplete/style.css | 18 -- @salix/core/src/autocomplete/style.scss | 25 +++ 3 files changed, 161 insertions(+), 100 deletions(-) delete mode 100644 @salix/core/src/autocomplete/style.css create mode 100644 @salix/core/src/autocomplete/style.scss diff --git a/@salix/core/src/autocomplete/index.js b/@salix/core/src/autocomplete/index.js index 4fc9168ac..007d0f1cc 100644 --- a/@salix/core/src/autocomplete/index.js +++ b/@salix/core/src/autocomplete/index.js @@ -1,6 +1,6 @@ import {module} from '../module'; export {factory as mdlFactory} from './index.mdl'; -require('./style.css'); +require('./style.scss'); export const component = { restrict: 'E', @@ -32,92 +32,128 @@ function controller($http, $element, $attrs, $scope, $parse, $document, popoverP this.setValue(newValue); locked = false; } + }); + componentHandler.upgradeElement($element[0].firstChild); + + function mdlUpdate() { let mdlField = $element[0].firstChild.MaterialTextfield; if (mdlField) mdlField.updateClasses_(); - }); - componentHandler.upgradeElement($element[0].firstChild); + } Object.assign(this, { init: function() { this.input = $element.find('input')[0]; - this.popover = null; + this.item = null; this.data = null; - this.showData = null; + this.popover = null; + this.popoverData = null; this.timeoutId = null; - this.activeOption = -1; this.lastSearch = null; this.lastRequest = null; + this.moreData = false; + this.activeOption = -1; this.maxRows = 10; this.filterDelay = 350; - this.loadData(); + this.requestItem(); }, - loadData: function(value) { - // Optimiza la petición - + loadData: function(textFilter) { let lastSearch = this.lastSearch; - if(lastSearch === value) return; - this.lastSearch = value; + if(lastSearch === textFilter) return; + this.lastSearch = textFilter; let lastRequest = this.lastRequest; let requestWillSame = ( - this.data && value && lastRequest - && this.data.length < this.maxRows - && value.substr(0, lastRequest.length) == lastRequest + this.data && textFilter && lastRequest && !this.moreData + && textFilter.substr(0, lastRequest.length) == lastRequest ); - if(requestWillSame) { - this.localFilter(value); - return; - } - - // Genera el filtro - - let where = {}; - if(value) where[this.showField] = {ilike: value}; - + if(requestWillSame) + this.localFilter(textFilter); + else + this.requestData(textFilter, false); + }, + getRequestFields: function() { let fields = {}; fields[this.valueField] = true; fields[this.showField] = true; + return fields; + }, + requestItem: function() { + if(!this.model) return; + + let where = {}; + where[this.valueField] = this.model; let filter = { - fields: fields, + fields: this.getRequestFields(), where: where, - order: `${this.showField} ASC`, - limit: this.maxRows }; - // Envia la petición - - this.lastRequest = value; let json = JSON.stringify(filter); $http.get(`${this.url}?filter=${json}`).then( - json => this.setData(json.data), - json => this.setData([]) + json => this.onItemRequest(json.data), + json => this.onItemRequest(null) ); }, - setData: function(data) { - this.data = data; - this.setShowData(this.data); + onItemRequest: function(data) { + if(data && data.length > 0) + this.showItem(data[0]); + else + this.showItem(null); }, - localFilter: function(value) { - let regex = new RegExp(value, 'i'); + requestData: function(textFilter, append) { + let where = {}; + if(textFilter) where[this.showField] = {ilike: textFilter}; + + let skip = 0; + + if(append && this.data) + skip = this.data.length; + + let filter = { + fields: this.getRequestFields(), + where: where, + order: `${this.showField} ASC`, + skip: skip, + limit: this.maxRows + }; + + this.lastRequest = textFilter; + let json = JSON.stringify(filter); + + $http.get(`${this.url}?filter=${json}`).then( + json => this.onRequest(json.data, append), + json => this.onRequest([]) + ); + }, + onRequest: function(data, append) { + this.moreData = data.length >= this.maxRows; + + if(!append || !this.data) + this.data = data; + else + this.data = this.data.concat(data); + + this.setPopoverData(this.data); + }, + localFilter: function(textFilter) { + let regex = new RegExp(textFilter, 'i'); let data = this.data.filter((item) => { return regex.test(item[this.showField]); }); - this.setShowData(data); + this.setPopoverData(data); }, - setShowData: function(data) { - this.showData = data; + setPopoverData: function(data) { + this.popoverData = data; if(this.hasFocus) this.showPopover(); - else - this.setValue(this.model); }, showPopover: function() { + if(!this.data) return; //FIXME this.hidePopover(); @@ -126,15 +162,22 @@ function controller($http, $element, $attrs, $scope, $parse, $document, popoverP (e) => this.onPopoverClick(e)); popover.addEventListener('mousedown', (e) => this.onPopoverMousedown(e)); - popover.className = 'vn-autocomplete-popover'; + popover.className = 'vn-autocomplete'; - let data = this.showData; + 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); } + + if(this.moreData) { + let li = $document[0].createElement('li'); + li.appendChild($document[0].createTextNode('Load more')); + li.className = 'load-more'; + popover.appendChild(li); + } popoverProvider.show(popover, this.input); this.popover = popover; @@ -145,24 +188,39 @@ function controller($http, $element, $attrs, $scope, $parse, $document, popoverP popoverProvider.hide(); this.popover = null; }, + selectPopoverOption: function(index) { + if(!this.popover || index == -1) return; + if(index < this.popoverData.length) { + this.selectOptionByDataIndex(this.popoverData, index); + this.hidePopover(); + } + else + this.requestData(this.lastRequest, true); + }, onPopoverClick: function(event) { let childs = this.popover.childNodes; for(let i = 0; i < childs.length; i++) if(childs[i] === event.target) { - this.selectOptionByIndex(i); + this.selectPopoverOption(i); break; } - - this.hidePopover(); }, onPopoverMousedown: function(event) { // Prevents input from loosing focus event.preventDefault(); }, + onClick: function(event) { + if(!this.popover) + this.showPopover(); + }, onFocus: function() { this.hasFocus = true; this.input.select(); - this.showPopover(); + + if(this.data) + this.showPopover(); + else + this.loadData(); }, onBlur: function() { this.hasFocus = false; @@ -171,10 +229,7 @@ function controller($http, $element, $attrs, $scope, $parse, $document, popoverP onKeydown: function(event) { switch(event.keyCode) { case 13: // Enter - if(this.popover && this.activeOption != -1) { - this.putValue(this.showData[this.activeOption]); - this.hidePopover(); - } + this.selectPopoverOption(this.activeOption); break; case 27: // Escape this.hidePopover(); @@ -191,9 +246,6 @@ function controller($http, $element, $attrs, $scope, $parse, $document, popoverP event.preventDefault(); }, - onClick: function(event) { - if(!this.popover) this.showPopover(); - }, onKeyup: function(event) { if(!this.isKeycodePrintable(event.keyCode)) return; if(this.timeoutId) clearTimeout(this.timeoutId); @@ -223,7 +275,7 @@ function controller($http, $element, $attrs, $scope, $parse, $document, popoverP if(index >= childs.length) index = 0; - else if (index < 0) + else if(index < 0) index = childs.length - 1; if (index >= 0) @@ -232,36 +284,33 @@ function controller($http, $element, $attrs, $scope, $parse, $document, popoverP this.activeOption = index; }, setValue: function(value) { - let data = this.data; + if(value) { + let data = this.data; + + if(data) + for(let i = 0; i < data.length; i++) + if(data[i][this.valueField] == value) { + this.putItem(data[i]); + return; + } - if(value && data) - for(let i = 0; i < data.length; i++) - if(data[i][this.valueField] == value) { - this.putValue(data[i]); - return; + this.requestItem(); } - - this.putValue(null); + else + this.putItem(null); }, selectOptionByIndex: function(index) { - let data = this.data; - - if(data && index >= 0 && index < data.length) - this.putValue(data[index]); - else - this.putValue(null); + this.selectOptionByDataIndex(this.data, index); }, - putValue: function(item) { - let value; - - if(item) { - this.input.value = item[this.showField]; - value = item[this.valueField]; - } - else { - this.input.value = ''; - value = undefined; - } + selectOptionByDataIndex: function(data, index) { + if(data && index >= 0 && index < data.length) + this.putItem(data[index]); + else + this.putItem(null); + }, + putItem: function(item) { + this.showItem(item); + let value = item ? item[this.valueField] : undefined; if(!locked) { setTimeout (() => { @@ -272,6 +321,11 @@ function controller($http, $element, $attrs, $scope, $parse, $document, popoverP }); }); } + }, + showItem: function(item) { + this.input.value = item ? item[this.showField] : ''; + this.item = item; + mdlUpdate(); } }); diff --git a/@salix/core/src/autocomplete/style.css b/@salix/core/src/autocomplete/style.css deleted file mode 100644 index 1b4377fc9..000000000 --- a/@salix/core/src/autocomplete/style.css +++ /dev/null @@ -1,18 +0,0 @@ -.vn-autocomplete-popover { - list-style-type: none; - padding: 1em; - margin: 0; - padding: 0; -} -.vn-autocomplete-popover > li { - display: block; - padding: .8em; - margin: 0; -} -.vn-autocomplete-popover > li.active { - background-color: rgba(1,1,1,.1); -} -.vn-autocomplete-popover > li:hover { - background-color: rgba(1,1,1,.1); - cursor: pointer; -} \ No newline at end of file diff --git a/@salix/core/src/autocomplete/style.scss b/@salix/core/src/autocomplete/style.scss new file mode 100644 index 000000000..1ddff61ec --- /dev/null +++ b/@salix/core/src/autocomplete/style.scss @@ -0,0 +1,25 @@ +ul.vn-autocomplete { + list-style-type: none; + padding: 1em; + margin: 0; + padding: 0; + overflow: auto; + max-height: 300px; + + li { + display: block; + padding: .8em; + margin: 0; + cursor: pointer; + + &.active, + &:hover { + background-color: rgba(1,1,1,.1); + } + &.load-more { + color: #ffa410; + font-weight: bold; + padding: .4em .8em; + } + } +} \ No newline at end of file From 5da711e98df57530339d5d98edf482b41791ade5 Mon Sep 17 00:00:00 2001 From: Juan Ferrer Toribio Date: Sun, 22 Jan 2017 23:21:02 +0100 Subject: [PATCH 12/12] 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; },