From f9b36574405f155f81c3a89d85d0438b531939b6 Mon Sep 17 00:00:00 2001 From: Dani Herrero Date: Wed, 13 Sep 2017 14:59:58 +0200 Subject: [PATCH 1/7] refactoring 30% --- .../src/autocomplete-v2/autocomplete.html | 16 +++ .../core/src/autocomplete-v2/autocomplete.js | 136 ++++++++++++++++++ client/core/src/autocomplete-v2/style.scss | 37 +++++ client/core/src/components.js | 2 +- 4 files changed, 190 insertions(+), 1 deletion(-) create mode 100644 client/core/src/autocomplete-v2/autocomplete.html create mode 100644 client/core/src/autocomplete-v2/autocomplete.js create mode 100644 client/core/src/autocomplete-v2/style.scss diff --git a/client/core/src/autocomplete-v2/autocomplete.html b/client/core/src/autocomplete-v2/autocomplete.html new file mode 100644 index 000000000..f322a37ce --- /dev/null +++ b/client/core/src/autocomplete-v2/autocomplete.html @@ -0,0 +1,16 @@ + + + + + + + + \ No newline at end of file diff --git a/client/core/src/autocomplete-v2/autocomplete.js b/client/core/src/autocomplete-v2/autocomplete.js new file mode 100644 index 000000000..9f86e433d --- /dev/null +++ b/client/core/src/autocomplete-v2/autocomplete.js @@ -0,0 +1,136 @@ +import {module} from '../module'; +import './style.scss'; + +class Autocomplete { + constructor($element, $scope, $http, $timeout) { + this.$element = $element; + this.$scope = $scope; + this.$http = $http; + this.$timeout = $timeout; + + this._showDropDown = false; + this.finding = false; + this.findMore = false; + this._value = null; + this._field = null; + this.maxRow = 10; + this.showField = this.showField || 'name'; + this.items = this.data || null; + } + + get showDropDown() { + return this._showDropDown; + } + set showDropDown(value) { + this._showDropDown = value; + } + + get displayValue() { + return this._value; + } + + set displayValue(value) { + this._value = (value === undefined || value === '') ? null : value; + if (value === null) { + this.field = null; + } + } + + get field() { + return this._field; + } + set field(value) { + this._field = value; + if (value && value.hasOwnProperty(this.showField)) + this.displayValue = value[this.showField]; + } + + findItems(search) { + if (!this.url) + return this.items ? this.items : []; + + if (search && !this.finding) { + let filter = {where: {name: {regexp: search}}}; + let json = JSON.stringify(filter); + this.finding = true; + this.$http.get(`${this.url}?filter=${json}`).then( + json => { + this.items = json.data; + this.finding = false; + }, + () => { + this.finding = false; + } + ); + } else if (!search && !this.finding) { + this.items = []; + this.getItems(); + } + } + getItems() { + let filter = {}; + + if (this.maxRow) { + if (this.items) { + filter.skip = this.items.length; + } + filter.limit = this.maxRow; + filter.order = 'name ASC'; + } + + let json = JSON.stringify(filter); + + this.$http.get(`${this.url}?filter=${json}`).then( + json => { + if (json.data.length) + json.data.forEach( + el => { + this.items.push(el); + } + ); + else + this.maxRow = false; + } + ); + } + $onInit() { + if (!this.items && this.url) { + this.items = []; + this.getItems(); + } + + this.findMore = this.url && this.maxRow; + + this.$element.bind('mouseover', e => { + this.$timeout(() => { + this.showDropDown = true; + }); + }); + + this.$element.bind('mouseout', () => { + this.$timeout(() => { + this.showDropDown = false; + }); + }); + } + +} + +Autocomplete.$inject = ['$element', '$scope', '$http', '$timeout']; + +module.component('vnAutocomplete', { + template: require('./autocomplete.html'), + controller: Autocomplete, + bindings: { + url: '@?', + showField: '@?', + valueField: '@?', + selectFields: '@?', + initialData: ' Date: Thu, 14 Sep 2017 13:40:55 +0200 Subject: [PATCH 2/7] autocomplete recatoring 80% --- .../src/autocomplete-v2/autocomplete.html | 27 +++-- .../core/src/autocomplete-v2/autocomplete.js | 24 +++++ client/core/src/autocomplete-v2/style.scss | 3 + client/core/src/drop-down/drop-down.html | 9 +- client/core/src/drop-down/drop-down.js | 98 ++++++++++++++++--- client/core/src/drop-down/style.scss | 2 +- client/core/src/icon-menu/icon-menu.html | 2 + client/core/src/icon-menu/icon-menu.js | 15 +++ 8 files changed, 141 insertions(+), 39 deletions(-) diff --git a/client/core/src/autocomplete-v2/autocomplete.html b/client/core/src/autocomplete-v2/autocomplete.html index f322a37ce..7daac5342 100644 --- a/client/core/src/autocomplete-v2/autocomplete.html +++ b/client/core/src/autocomplete-v2/autocomplete.html @@ -1,16 +1,13 @@ - - - - - - - + + + \ No newline at end of file diff --git a/client/core/src/autocomplete-v2/autocomplete.js b/client/core/src/autocomplete-v2/autocomplete.js index 9f86e433d..ecd72d6c2 100644 --- a/client/core/src/autocomplete-v2/autocomplete.js +++ b/client/core/src/autocomplete-v2/autocomplete.js @@ -16,6 +16,8 @@ class Autocomplete { this.maxRow = 10; this.showField = this.showField || 'name'; this.items = this.data || null; + + this.input = $element[0].querySelector('input'); } get showDropDown() { @@ -50,6 +52,7 @@ class Autocomplete { return this.items ? this.items : []; if (search && !this.finding) { + this.maxRow = false; let filter = {where: {name: {regexp: search}}}; let json = JSON.stringify(filter); this.finding = true; @@ -63,6 +66,7 @@ class Autocomplete { } ); } else if (!search && !this.finding) { + this.maxRow = 10; this.items = []; this.getItems(); } @@ -112,6 +116,26 @@ class Autocomplete { this.showDropDown = false; }); }); + this.$element.bind('focusin', e => { + this.$timeout(() => { + this.showDropDown = true; + }); + }); + this.$element.bind('focusout', e => { + this.$timeout(() => { + this.showDropDown = false; + }); + }); + + let rectangle = this.$element[0].getBoundingClientRect(); + this.width = Math.round(rectangle.width) - 15; + } + + $onDestroy() { + this.$element.unbind('mouseover'); + this.$element.unbind('mouseout'); + this.$element.unbind('focusin'); + this.$element.unbind('focusout'); } } diff --git a/client/core/src/autocomplete-v2/style.scss b/client/core/src/autocomplete-v2/style.scss index 5c4dd1a4b..3ea0428c6 100644 --- a/client/core/src/autocomplete-v2/style.scss +++ b/client/core/src/autocomplete-v2/style.scss @@ -34,4 +34,7 @@ vn-autocomplete { .material-icons { font-size: 18px; } + vn-drop-down{ + margin-top: 50px; + } } \ No newline at end of file diff --git a/client/core/src/drop-down/drop-down.html b/client/core/src/drop-down/drop-down.html index dad08a84f..87adbed17 100644 --- a/client/core/src/drop-down/drop-down.html +++ b/client/core/src/drop-down/drop-down.html @@ -1,18 +1,13 @@ -
- -
-
- -
+
diff --git a/client/core/src/drop-down/drop-down.js b/client/core/src/drop-down/drop-down.js index ece781507..7fce991b7 100644 --- a/client/core/src/drop-down/drop-down.js +++ b/client/core/src/drop-down/drop-down.js @@ -2,12 +2,41 @@ import {module} from '../module'; import './style.scss'; export default class DropDown { - constructor($element, $filter) { + constructor($element, $filter, $timeout) { this.$element = $element; this.$filter = $filter; - this.search = ''; - this.itemsFiltered = []; + this.$timeout = $timeout; + this.parent = this.parent || $element[0].parentNode; + this._search = null; + this.itemsFiltered = []; + this._activeOption = -1; + } + + get search() { + return this._search; + } + set search(value) { + let val = (value === undefined && value === '') ? null : value; + this._search = val; + + if (this.filterAction) + this.onFilterRest(); + else + this.filterItems(); + } + get activeOption() { + return this._activeOption; + } + set activeOption(value) { + if (value < 0) { + value = 0; + } else if (value >= this.items.length) { + value = this.items.length - 1; + } + this.$timeout(() => { + this._activeOption = value; + }); } filterItems() { @@ -15,32 +44,66 @@ export default class DropDown { } onFilterRest() { - this.showLoadMore = false; - if (this.filterAction) { - this.filterAction({search: this.search}); - } + this.filterAction({search: this.search}); } $onChanges(changesObj) { if (changesObj.show && changesObj.top && changesObj.top.currentValue) { this.$element.css('top', changesObj.top.currentValue + 'px'); } + if (changesObj.show && changesObj.itemWidth && changesObj.itemWidth.currentValue) { + this.$element.css('width', changesObj.itemWidth.currentValue + 'px'); + } if (changesObj.items) { this.filterItems(); } } clearSearch() { - this.search = ''; - this.showLoadMore = this.loadMore != null; - if (this.filterAction) { - this.filterAction({search: this.search}); - } else { - this.filterItems(); + this.search = null; + } + + selectOption() { + if (this.activeOption >= 0 && this.items[this.activeOption]) { + this.selected = this.items[this.activeOption]; + this.clearSearch(); } } + + onKeydown(event) { + if (this.show) { + switch (event.keyCode) { + case 13: // Enter + this.$timeout(() => { + this.selectOption(); + }); + event.preventDefault(); + break; + case 27: // Escape + this.clearSearch(); + break; + case 38: // Arrow up + this.activeOption--; + break; + case 40: // Arrow down + this.activeOption++; + break; + default: + return; + } + } + } + + $onInit() { + if (this.parent) + this.parent.addEventListener('keydown', e => this.onKeydown(e)); + } + $onDestroy() { + if (this.parent) + this.parent.removeEventListener('keydown', e => this.onKeydown(e)); + } } -DropDown.$inject = ['$element', '$filter']; +DropDown.$inject = ['$element', '$filter', '$timeout']; module.component('vnDropDown', { template: require('./drop-down.html'), @@ -50,9 +113,12 @@ module.component('vnDropDown', { show: '<', filter: '@?', selected: '=', + search: '=?', loadMore: '&?', filterAction: '&?', - showLoadMore: '
@@ -17,6 +18,7 @@ load-more="$ctrl.getItems()" show-load-more="$ctrl.maxRow" filter-action="$ctrl.findItems(search)" + parent="$ctrl.element" >
\ No newline at end of file diff --git a/client/core/src/icon-menu/icon-menu.js b/client/core/src/icon-menu/icon-menu.js index a81d3f512..4ac9d2302 100644 --- a/client/core/src/icon-menu/icon-menu.js +++ b/client/core/src/icon-menu/icon-menu.js @@ -9,6 +9,7 @@ export default class IconMenu { this._showDropDown = false; this.finding = false; this.findMore = false; + this.element = $element[0]; } get showDropDown() { return this._showDropDown; @@ -34,6 +35,7 @@ export default class IconMenu { } ); } else if (!search && !this.finding) { + this.maxRow = 10; this.items = []; this.getItems(); } @@ -83,10 +85,23 @@ export default class IconMenu { this.showDropDown = false; }); }); + this.$element.bind('focusin', e => { + this.$timeout(() => { + this.showDropDown = true; + }); + }); + this.$element.bind('focusout', e => { + this.$timeout(() => { + this.showDropDown = false; + }); + }); } + $onDestroy() { this.$element.unbind('mouseover'); this.$element.unbind('mouseout'); + this.$element.unbind('focusin'); + this.$element.unbind('focusout'); } } IconMenu.$inject = ['$element', '$http', '$timeout']; From d81d36217a5c7fcaf238d2664885a3f252fd3a0d Mon Sep 17 00:00:00 2001 From: Dani Herrero Date: Wed, 20 Sep 2017 11:50:53 +0200 Subject: [PATCH 3/7] transclude funcionando --- client/client/src/basic-data/basic-data.html | 6 +- .../client/src/fiscal-data/fiscal-data.html | 4 +- .../src/autocomplete-v2/autocomplete.html | 2 +- .../core/src/autocomplete-v2/autocomplete.js | 117 +++++++++++++++--- client/core/src/autocomplete-v2/style.scss | 2 +- client/core/src/drop-down/drop-down.html | 13 +- client/core/src/drop-down/drop-down.js | 23 +++- 7 files changed, 139 insertions(+), 28 deletions(-) diff --git a/client/client/src/basic-data/basic-data.html b/client/client/src/basic-data/basic-data.html index 072aa036a..02f71c792 100644 --- a/client/client/src/basic-data/basic-data.html +++ b/client/client/src/basic-data/basic-data.html @@ -22,7 +22,7 @@ - {{::i.name}} {{::i.surname}} + {{::$parent.$parent.item.name}} {{::$parent.$parent.item.surname}} diff --git a/client/client/src/fiscal-data/fiscal-data.html b/client/client/src/fiscal-data/fiscal-data.html index 3fbf66d90..a9aa7f7b0 100644 --- a/client/client/src/fiscal-data/fiscal-data.html +++ b/client/client/src/fiscal-data/fiscal-data.html @@ -20,7 +20,7 @@ + >{{$parent.item.name}}
\ No newline at end of file diff --git a/client/core/src/autocomplete-v2/autocomplete.js b/client/core/src/autocomplete-v2/autocomplete.js index ecd72d6c2..8454418b7 100644 --- a/client/core/src/autocomplete-v2/autocomplete.js +++ b/client/core/src/autocomplete-v2/autocomplete.js @@ -1,8 +1,10 @@ import {module} from '../module'; +import Component from '../lib/component'; import './style.scss'; -class Autocomplete { +class Autocomplete extends Component { constructor($element, $scope, $http, $timeout) { + super($element); this.$element = $element; this.$scope = $scope; this.$http = $http; @@ -13,17 +15,21 @@ class Autocomplete { this.findMore = false; this._value = null; this._field = null; + this._preLoad = false; this.maxRow = 10; this.showField = this.showField || 'name'; - this.items = this.data || null; - - this.input = $element[0].querySelector('input'); + this.valueField = this.valueField || 'id'; + this.items = this.data || []; } get showDropDown() { return this._showDropDown; } set showDropDown(value) { + if (value && this.url && !this._preLoad) { + this._preLoad = true; + this.getItems(); + } this._showDropDown = value; } @@ -42,9 +48,82 @@ class Autocomplete { return this._field; } set field(value) { - this._field = value; + this.finding = true; + if (value && value.hasOwnProperty(this.valueField)) + this._field = value[this.valueField]; + else + this.setValue(value); + if (value && value.hasOwnProperty(this.showField)) this.displayValue = value[this.showField]; + + this.finding = false; + } + + set initialData(value) { + if (value) { + this.field = value; + } + } + + setValue(value) { + if (value) { + let data = this.items; + + if (data && data.length) + for (let i = 0; i < data.length; i++) + if (data[i][this.valueField] === value) { + this.showItem(data[i]); + return; + } + + this.requestItem(value); + } else { + this._field = null; + this.displayValue = ''; + } + } + + requestItem(value) { + if (!value) return; + + let where = {}; + where[this.valueField] = value; + + let filter = { + fields: this.getRequestFields(), + where: where + }; + + let json = JSON.stringify(filter); + + this.$http.get(`${this.url}?filter=${json}`).then( + json => this.onItemRequest(json.data), + json => this.onItemRequest(null) + ); + } + onItemRequest(data) { + if (data && data.length > 0) + this.showItem(data[0]); + else + this.showItem(null); + } + + showItem(item) { + this.displayValue = item ? item[this.showField] : ''; + this.field = item; + } + + getRequestFields() { + let fields = {}; + fields[this.valueField] = true; + fields[this.showField] = true; + + if (this._selectFields) + for (let field of this._selectFields) + fields[field] = true; + + return fields; } findItems(search) { @@ -98,37 +177,39 @@ class Autocomplete { ); } $onInit() { - if (!this.items && this.url) { - this.items = []; - this.getItems(); - } - this.findMore = this.url && this.maxRow; + this.mouseFocus = false; + this.focused = false; this.$element.bind('mouseover', e => { this.$timeout(() => { - this.showDropDown = true; + this.mouseFocus = true; + this.showDropDown = this.focused; }); }); this.$element.bind('mouseout', () => { this.$timeout(() => { - this.showDropDown = false; + this.mouseFocus = false; + this.showDropDown = this.focused; }); }); this.$element.bind('focusin', e => { this.$timeout(() => { + this.focused = true; this.showDropDown = true; }); }); this.$element.bind('focusout', e => { this.$timeout(() => { - this.showDropDown = false; + this.focused = false; + this.showDropDown = this.mouseFocus; }); - }); + }); let rectangle = this.$element[0].getBoundingClientRect(); - this.width = Math.round(rectangle.width) - 15; + this.width = Math.round(rectangle.width) - 10; + } $onDestroy() { @@ -155,6 +236,10 @@ module.component('vnAutocomplete', { data: ' + @@ -7,8 +7,15 @@ \ No newline at end of file diff --git a/client/core/src/drop-down/drop-down.js b/client/core/src/drop-down/drop-down.js index 7fce991b7..b171394c3 100644 --- a/client/core/src/drop-down/drop-down.js +++ b/client/core/src/drop-down/drop-down.js @@ -32,7 +32,7 @@ export default class DropDown { if (value < 0) { value = 0; } else if (value >= this.items.length) { - value = this.items.length - 1; + value = this.showLoadMore ? this.items.length : this.items.length - 1; } this.$timeout(() => { this._activeOption = value; @@ -64,9 +64,12 @@ export default class DropDown { } selectOption() { - if (this.activeOption >= 0 && this.items[this.activeOption]) { + if (this.activeOption >= 0 && this.activeOption < this.items.length && this.items[this.activeOption]) { this.selected = this.items[this.activeOption]; + this.show = false; this.clearSearch(); + } else if (this.showLoadMore && this.activeOption === this.items.length) { + this.loadMore(); } } @@ -84,15 +87,28 @@ export default class DropDown { break; case 38: // Arrow up this.activeOption--; + this.$timeout(() => { + this.setScrollPosition(); + }, 100); break; case 40: // Arrow down this.activeOption++; + this.$timeout(() => { + this.setScrollPosition(); + }, 100); break; default: return; } } } + setScrollPosition() { + let dropdown = this.$element[0].querySelector('ul.dropdown'); + let child = dropdown ? dropdown.childNodes[this.activeOption] : null; + if (child && typeof child.scrollIntoView === 'function') { + child.scrollIntoView(); + } + } $onInit() { if (this.parent) @@ -120,5 +136,8 @@ module.component('vnDropDown', { top: ' Date: Wed, 20 Sep 2017 13:52:53 +0200 Subject: [PATCH 4/7] autocomplete con seleccion multiple --- client/client/src/basic-data/basic-data.html | 2 +- .../src/autocomplete-v2/autocomplete.html | 3 +- .../core/src/autocomplete-v2/autocomplete.js | 69 +++++++++++++++++-- client/core/src/autocomplete-v2/style.scss | 3 + client/core/src/drop-down/drop-down.html | 11 +-- client/core/src/drop-down/drop-down.js | 13 +++- client/core/src/drop-down/style.scss | 5 ++ 7 files changed, 91 insertions(+), 15 deletions(-) diff --git a/client/client/src/basic-data/basic-data.html b/client/client/src/basic-data/basic-data.html index 02f71c792..092e7d946 100644 --- a/client/client/src/basic-data/basic-data.html +++ b/client/client/src/basic-data/basic-data.html @@ -30,7 +30,7 @@ select-fields="surname" label="Salesperson"> - {{::$parent.$parent.item.name}} {{::$parent.$parent.item.surname}} + {{$parent.$parent.item.name}} {{$parent.$parent.item.surname}} {{$parent.item.name}}
\ No newline at end of file diff --git a/client/core/src/autocomplete-v2/autocomplete.js b/client/core/src/autocomplete-v2/autocomplete.js index 8454418b7..d5e2d7e71 100644 --- a/client/core/src/autocomplete-v2/autocomplete.js +++ b/client/core/src/autocomplete-v2/autocomplete.js @@ -20,6 +20,8 @@ class Autocomplete extends Component { this.showField = this.showField || 'name'; this.valueField = this.valueField || 'id'; this.items = this.data || []; + this.displayValueMultiCheck = []; + this._multiField = []; } get showDropDown() { @@ -38,26 +40,50 @@ class Autocomplete extends Component { } set displayValue(value) { - this._value = (value === undefined || value === '') ? null : value; + let val = (value === undefined || value === '') ? null : value; + if (this.multiple && val) { + let index = this.displayValueMultiCheck.indexOf(val); + if (index === -1) + this.displayValueMultiCheck.push(val); + else + this.displayValueMultiCheck.splice(index, 1); + + this._value = this.displayValueMultiCheck.join(', '); + } else { + this._value = val; + } + if (value === null) { this.field = null; + if (this.multiple && this.items.length) { + this.displayValueMultiCheck = []; + this.items.map(item => { + item.checked = false; + return item; + }); + } } } get field() { - return this._field; + return this.multiple ? this._multiField : this._field; } set field(value) { this.finding = true; - if (value && value.hasOwnProperty(this.valueField)) + if (value && value.hasOwnProperty(this.valueField)) { this._field = value[this.valueField]; - else + this.setMultiField(value[this.valueField]); + } else { this.setValue(value); + } if (value && value.hasOwnProperty(this.showField)) this.displayValue = value[this.showField]; this.finding = false; + + if (this.onChange) + this.onChange({item: this._field}); } set initialData(value) { @@ -66,6 +92,22 @@ class Autocomplete extends Component { } } + setMultiField(val) { + if (val && typeof val === 'object' && val[this.valueField]) { + val = val[this.valueField]; + } + if (val === null) { + this._multiField = []; + } else { + let index = this._multiField.indexOf(val); + if (index === -1) { + this._multiField.push(val); + } else { + this._multiField.splice(index, 1); + } + } + } + setValue(value) { if (value) { let data = this.items; @@ -80,6 +122,7 @@ class Autocomplete extends Component { this.requestItem(value); } else { this._field = null; + this.setMultiField(null); this.displayValue = ''; } } @@ -112,6 +155,7 @@ class Autocomplete extends Component { showItem(item) { this.displayValue = item ? item[this.showField] : ''; this.field = item; + this.setMultiField(item); } getRequestFields() { @@ -137,7 +181,15 @@ class Autocomplete extends Component { this.finding = true; this.$http.get(`${this.url}?filter=${json}`).then( json => { - this.items = json.data; + this.items = []; + json.data.forEach( + el => { + if (this.multiple) { + el.checked = this.field.indexOf(el[this.valueField]) !== -1; + } + this.items.push(el); + } + ); this.finding = false; }, () => { @@ -168,6 +220,9 @@ class Autocomplete extends Component { if (json.data.length) json.data.forEach( el => { + if (this.multiple) { + el.checked = this.field.indexOf(el[this.valueField]) !== -1; + } this.items.push(el); } ); @@ -209,7 +264,6 @@ class Autocomplete extends Component { let rectangle = this.$element[0].getBoundingClientRect(); this.width = Math.round(rectangle.width) - 10; - } $onDestroy() { @@ -237,7 +291,8 @@ module.component('vnAutocomplete', { itemAs: '@?', field: '=', label: '@', - itemTemplate: '@?' + itemTemplate: '@?', + multiple: '@?' }, transclude: { tplItem: '?tplItem' diff --git a/client/core/src/autocomplete-v2/style.scss b/client/core/src/autocomplete-v2/style.scss index 2b8220ede..1472dbcf3 100644 --- a/client/core/src/autocomplete-v2/style.scss +++ b/client/core/src/autocomplete-v2/style.scss @@ -37,4 +37,7 @@ vn-autocomplete { vn-drop-down{ margin-top: 47px; } + vn-drop-down .dropdown-body .filter vn-icon { + margin-left: -26px; + } } \ No newline at end of file diff --git a/client/core/src/drop-down/drop-down.html b/client/core/src/drop-down/drop-down.html index 1b862cfba..c65feac28 100644 --- a/client/core/src/drop-down/drop-down.html +++ b/client/core/src/drop-down/drop-down.html @@ -1,4 +1,4 @@ - + @@ -7,13 +7,14 @@ diff --git a/client/core/src/drop-down/drop-down.js b/client/core/src/drop-down/drop-down.js index b171394c3..d8de9c014 100644 --- a/client/core/src/drop-down/drop-down.js +++ b/client/core/src/drop-down/drop-down.js @@ -110,6 +110,16 @@ export default class DropDown { } } + selectItem(item) { + this.selected = item; + if (this.multiple) { + item.checked = !item.checked; + this.show = true; + } else { + this.show = false; + } + } + $onInit() { if (this.parent) this.parent.addEventListener('keydown', e => this.onKeydown(e)); @@ -135,7 +145,8 @@ module.component('vnDropDown', { showLoadMore: '=?', top: ' Date: Wed, 20 Sep 2017 13:56:47 +0200 Subject: [PATCH 5/7] quitado autocomplete anterior --- .../core/src/autocomplete/autocomplete.html | 20 - client/core/src/autocomplete/autocomplete.js | 435 ------------------ .../src/autocomplete/autocomplete.spec.js | 24 - client/core/src/autocomplete/style.scss | 37 -- 4 files changed, 516 deletions(-) delete mode 100644 client/core/src/autocomplete/autocomplete.html delete mode 100644 client/core/src/autocomplete/autocomplete.js delete mode 100644 client/core/src/autocomplete/autocomplete.spec.js delete mode 100644 client/core/src/autocomplete/style.scss diff --git a/client/core/src/autocomplete/autocomplete.html b/client/core/src/autocomplete/autocomplete.html deleted file mode 100644 index b08702f52..000000000 --- a/client/core/src/autocomplete/autocomplete.html +++ /dev/null @@ -1,20 +0,0 @@ -
- - - -
diff --git a/client/core/src/autocomplete/autocomplete.js b/client/core/src/autocomplete/autocomplete.js deleted file mode 100644 index d4d17a54c..000000000 --- a/client/core/src/autocomplete/autocomplete.js +++ /dev/null @@ -1,435 +0,0 @@ -import {module} from '../module'; -import Component from '../lib/component'; -import './style.scss'; - -/** - * Combobox like component with search and partial data loading features. - */ -export default class Autocomplete extends Component { - constructor($element, $scope, $http, vnPopover, $transclude, $timeout) { - super($element); - this.input = $element[0].querySelector('input'); - this.item = null; - this.$timeout = $timeout; - // this.data = null; - this.popover = null; - this.popoverId = null; - this.displayData = null; - this.timeoutId = null; - this.lastSearch = null; - this.lastRequest = null; - this.currentRequest = null; - this.moreData = false; - this.activeOption = -1; - this.locked = false; - this.$http = $http; - this.$scope = $scope; - this.vnPopover = vnPopover; - this.$transclude = $transclude; - this.scopes = null; - - Object.assign(this, { - maxRows: 10, - requestDelay: 350, - showField: 'name', - valueField: 'id', - itemAs: 'i' - }); - - componentHandler.upgradeElement($element[0].firstChild); - } - set field(value) { - this.locked = true; - this.setValue(value); - this.locked = false; - } - get field() { - return this.value; - } - set initialData(value) { - if (value) { - if (!this.data) - this.data = []; - this.data.push(value); - } - } - set selectFields(value) { - this._selectFields = []; - - if (!value) - return; - - let res = value.split(','); - for (let i of res) - this._selectFields.push(i.trim()); - } - mdlUpdate() { - let mdlField = this.element.firstChild.MaterialTextfield; - if (mdlField) - mdlField.updateClasses_(); - } - loadData(textFilter) { - textFilter = textFilter ? textFilter : ''; - - if (this.lastSearch === textFilter) { - this.showPopoverIfFocus(); - return; - } - - this.lastSearch = textFilter; - - let lastRequest = this.lastRequest; - let requestWillSame = lastRequest !== null - && !this.moreData - && textFilter.substr(0, lastRequest.length) === lastRequest; - - if (requestWillSame || !this.url) - this.localFilter(textFilter); - else if (this.url) - this.requestData(textFilter, false); - else - this.setDisplayData(this.data); - } - getRequestFields() { - let fields = {}; - fields[this.valueField] = true; - fields[this.showField] = true; - - if (this._selectFields) - for (let field of this._selectFields) - fields[field] = true; - - return fields; - } - requestData(textFilter, append) { - let where = {}; - let skip = 0; - - if (textFilter) - where[this.showField] = {regexp: textFilter}; - 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 ? textFilter : ''; - let json = JSON.stringify(filter); - - if (this.currentRequest) - this.currentRequest.resolve(); - - this.currentRequest = this.$http.get(`${this.url}?filter=${json}`); - this.currentRequest.then( - json => this.onRequest(json.data, append), - json => this.onRequest([]) - ); - } - onRequest(data, append) { - this.currentRequest = null; - this.moreData = data.length >= this.maxRows; - - if (!append || !this.data) - this.data = data; - else - this.data = this.data.concat(data); - - this.setDisplayData(this.data); - } - localFilter(textFilter) { - let regex = new RegExp(textFilter, 'i'); - let data = this.data.filter(item => { - return regex.test(item[this.showField]); - }); - this.setDisplayData(data); - } - setDisplayData(data) { - this.displayData = data; - this.showPopoverIfFocus(); - } - showPopoverIfFocus() { - if (this.hasFocus) - this.showPopover(); - } - destroyScopes() { - if (this.scopes) - for (let scope of this.scopes) - scope.$destroy(); - } - showPopover() { - let data = this.displayData; - - if (!data) - return; - - let fragment = this.document.createDocumentFragment(); - this.destroyScopes(); - this.scopes = []; - - let hasTemplate = this.$transclude.isSlotFilled('tplItem'); - - for (let i = 0; i < data.length; i++) { - let li = this.document.createElement('li'); - fragment.appendChild(li); - - if (hasTemplate) { - this.$transclude((clone, scope) => { - scope[this.itemAs] = data[i]; - li.appendChild(clone[0]); - this.scopes[i] = scope; - }, null, 'tplItem'); - } else { - let text = this.document.createTextNode(data[i][this.showField]); - li.appendChild(text); - } - } - - if (this.moreData) { - let li = this.document.createElement('li'); - li.appendChild(this.document.createTextNode('Load more')); - li.className = 'load-more'; - fragment.appendChild(li); - } - - if (this.popover) { - this.popover.innerHTML = ''; - this.popover.appendChild(fragment); - } else { - let popover = this.document.createElement('ul'); - popover.addEventListener('click', - e => this.onPopoverClick(e)); - popover.addEventListener('mousedown', - e => this.onPopoverMousedown(e)); - popover.className = 'vn-autocomplete'; - popover.appendChild(fragment); - this.popoverId = this.vnPopover.show(popover, this.input); - this.popover = popover; - } - } - hidePopover() { - if (!this.popover) return; - this.activeOption = -1; - this.vnPopover.hide(this.popoverId); - this.destroyScopes(); - this.popover = null; - } - selectPopoverOption(index) { - if (!this.popover || index === -1) return; - if (index < this.displayData.length) { - this.selectOptionByDataIndex(this.displayData, index); - this.hidePopover(); - } else - this.requestData(this.lastRequest, true); - } - onPopoverClick(event) { - let target = event.target; - let childs = this.popover.childNodes; - - if (target === this.popover) - return; - - while (target.parentNode !== this.popover) - target = target.parentNode; - - for (let i = 0; i < childs.length; i++) - if (childs[i] === target) { - this.selectPopoverOption(i); - break; - } - } - onPopoverMousedown(event) { - // Prevents input from loosing focus - event.preventDefault(); - } - onClear() { - this.setValue(null); - this.$timeout( - () => { - this.mdlUpdate(); - } - ); - } - onClick(event) { - if (!this.popover) - this.showPopover(); - } - onFocus() { - this.hasFocus = true; - this.input.select(); - - this.loadData(); - } - onBlur() { - this.hasFocus = false; - this.restoreShowValue(); - this.hidePopover(); - } - onKeydown(event) { - switch (event.keyCode) { - case 13: // Enter - this.selectPopoverOption(this.activeOption); - break; - case 27: // Escape - this.restoreShowValue(); - this.input.select(); - break; - case 38: // Arrow up - this.activateOption(this.activeOption - 1); - break; - case 40: // Arrow down - this.activateOption(this.activeOption + 1); - break; - default: - return; - } - - event.preventDefault(); - } - onKeyup(event) { - if (!this.isKeycodePrintable(event.keyCode)) return; - if (this.timeoutId) clearTimeout(this.timeoutId); - this.timeoutId = setTimeout(() => this.onTimeout(), this.requestDelay); - } - onTimeout() { - this.loadData(this.input.value); - this.timeoutId = null; - } - isKeycodePrintable(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); // [\]' - } - restoreShowValue() { - this.putItem(this.item); - } - requestItem() { - if (!this.value) return; - - let where = {}; - where[this.valueField] = this.value; - - let filter = { - fields: this.getRequestFields(), - where: where - }; - - let json = JSON.stringify(filter); - - this.$http.get(`${this.url}?filter=${json}`).then( - json => this.onItemRequest(json.data), - json => this.onItemRequest(null) - ); - } - onItemRequest(data) { - if (data && data.length > 0) - this.showItem(data[0]); - else - this.showItem(null); - } - activateOption(index) { - if (!this.popover) - this.showPopover(); - - let popover = this.popover; - let childs = popover.childNodes; - let len = this.displayData.length; - - if (this.activeOption >= 0) - childs[this.activeOption].className = ''; - - if (index >= len) - index = 0; - else if (index < 0) - index = len - 1; - - 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; - } - setValue(value) { - this.value = value; - - 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; - } - - this.requestItem(); - } else - this.putItem(null); - } - selectOptionByIndex(index) { - this.selectOptionByDataIndex(this.data, index); - } - selectOptionByDataIndex(data, index) { - if (data && index >= 0 && index < data.length) - this.putItem(data[index]); - else - this.putItem(null); - } - putItem(item) { - this.showItem(item); - let value = item ? item[this.valueField] : undefined; - - if (!this.locked) - this.value = value; - - if (this.onChange) - this.onChange({item: item}); - } - showItem(item) { - this.input.value = item ? item[this.showField] : ''; - this.item = item; - this.mdlUpdate(); - } - $onDestroy() { - this.destroyScopes(); - } -} -Autocomplete.$inject = ['$element', '$scope', '$http', 'vnPopover', '$transclude', '$timeout']; - -module.component('vnAutocomplete', { - template: require('./autocomplete.html'), - bindings: { - url: '@?', - showField: '@?', - valueField: '@?', - selectFields: '@?', - initialData: ' { - describe('Component mdlUpdate', () => { - let $componentController; - let $state; - - beforeEach(() => { - angular.mock.module('client'); - }); - - beforeEach(angular.mock.inject((_$componentController_, _$state_) => { - $componentController = _$componentController_; - $state = _$state_; - $state.params.id = '1234'; - })); - - it('should define and set address property', () => { - let controller = $componentController('vnAddressCreate', {$state: $state}); - expect(controller.address.clientFk).toBe(1234); - expect(controller.address.enabled).toBe(true); - }); - }); -}); diff --git a/client/core/src/autocomplete/style.scss b/client/core/src/autocomplete/style.scss deleted file mode 100644 index 5c4dd1a4b..000000000 --- a/client/core/src/autocomplete/style.scss +++ /dev/null @@ -1,37 +0,0 @@ -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; - } - } -} -vn-autocomplete { - .mdl-chip__action { - position: absolute; - top: 0px; - right: -6px; - margin: 22px 0px; - background-color: white; - } - .material-icons { - font-size: 18px; - } -} \ No newline at end of file From 4b1e88cc1c8a1d11f49daa96fef42e5957071b0c Mon Sep 17 00:00:00 2001 From: Dani Herrero Date: Wed, 20 Sep 2017 14:23:53 +0200 Subject: [PATCH 6/7] removed autocomplete folder --- .../src/autocomplete/autocomplete.spec.js | 25 ------------------- 1 file changed, 25 deletions(-) delete mode 100644 client/core/src/autocomplete/autocomplete.spec.js diff --git a/client/core/src/autocomplete/autocomplete.spec.js b/client/core/src/autocomplete/autocomplete.spec.js deleted file mode 100644 index 5d76a26d0..000000000 --- a/client/core/src/autocomplete/autocomplete.spec.js +++ /dev/null @@ -1,25 +0,0 @@ -import './autocomplete.js'; - -describe('Core', () => { - describe('Component mdlUpdate', () => { - let $componentController; - let $state; - - beforeEach(() => { - angular.mock.module('client'); - }); - - beforeEach(angular.mock.inject((_$componentController_, _$state_) => { - $componentController = _$componentController_; - $state = _$state_; - $state.params.id = '1234'; - })); - - it('should define and set address property', () => { - let controller = $componentController('vnAddressCreate', {$state: $state}); - - expect(controller.address.clientFk).toBe(1234); - expect(controller.address.enabled).toBe(true); - }); - }); -}); From f6399596cea4e8bb1807053932bbfd16f3214d98 Mon Sep 17 00:00:00 2001 From: Dani Herrero Date: Wed, 20 Sep 2017 14:25:43 +0200 Subject: [PATCH 7/7] autocomplete-v2 renamed --- .../src/{autocomplete-v2 => autocomplete}/autocomplete.html | 0 .../core/src/{autocomplete-v2 => autocomplete}/autocomplete.js | 0 client/core/src/{autocomplete-v2 => autocomplete}/style.scss | 0 client/core/src/components.js | 2 +- 4 files changed, 1 insertion(+), 1 deletion(-) rename client/core/src/{autocomplete-v2 => autocomplete}/autocomplete.html (100%) rename client/core/src/{autocomplete-v2 => autocomplete}/autocomplete.js (100%) rename client/core/src/{autocomplete-v2 => autocomplete}/style.scss (100%) diff --git a/client/core/src/autocomplete-v2/autocomplete.html b/client/core/src/autocomplete/autocomplete.html similarity index 100% rename from client/core/src/autocomplete-v2/autocomplete.html rename to client/core/src/autocomplete/autocomplete.html diff --git a/client/core/src/autocomplete-v2/autocomplete.js b/client/core/src/autocomplete/autocomplete.js similarity index 100% rename from client/core/src/autocomplete-v2/autocomplete.js rename to client/core/src/autocomplete/autocomplete.js diff --git a/client/core/src/autocomplete-v2/style.scss b/client/core/src/autocomplete/style.scss similarity index 100% rename from client/core/src/autocomplete-v2/style.scss rename to client/core/src/autocomplete/style.scss diff --git a/client/core/src/components.js b/client/core/src/components.js index fc1634e41..04e5d7287 100644 --- a/client/core/src/components.js +++ b/client/core/src/components.js @@ -5,7 +5,7 @@ import './textfield/textfield'; import './watcher/watcher'; import './paging/paging'; import './icon/icon'; -import './autocomplete-v2/autocomplete'; +import './autocomplete/autocomplete'; import './popover/popover'; import './dialog/dialog';