diff --git a/README.md b/README.md
index 0ae05ce..9bb78d5 100644
--- a/README.md
+++ b/README.md
@@ -93,9 +93,9 @@ Webdriver for NodeJS is used for the integration tests. This project has been mo
The following is a list of test statistics for the project for date
| Date | Commit | Number of Tests | Code Coverage |
-| --- | --- | --- | --- |
-| 2022-01-15 | [8ac447f](https://github.com/stamp-web/stamp-web-aurelia/commit/8ac447f580f29d1f0f8dd23e284c6f25448cf1d7) | 83 | 12% |
-
+| --- | --- | --- |---------------|
+| 2022-01-15 | [8ac447f](https://github.com/stamp-web/stamp-web-aurelia/commit/8ac447f580f29d1f0f8dd23e284c6f25448cf1d7) | 83 | 12.05% |
+| 2022-01-15 | [081fe3f](https://github.com/stamp-web/stamp-web-aurelia/commit/081fe3f31d5962c10777f4017e2c7a5dbe26e12e) | 86 | 12.20% |
## Optimizing for Browsers
diff --git a/index.html b/index.html
index c85ee63..ee98b94 100644
--- a/index.html
+++ b/index.html
@@ -16,7 +16,7 @@
${'editor.defects'|t}
-
@@ -48,7 +48,7 @@
${'editor.deceptions'|t}
diff --git a/src/resources/elements/ownerships/ownership-notes.scss b/src/resources/elements/ownerships/ownership-notes.scss
index 8c0c2cc..545e53a 100644
--- a/src/resources/elements/ownerships/ownership-notes.scss
+++ b/src/resources/elements/ownerships/ownership-notes.scss
@@ -1,6 +1,8 @@
@import "../../../theme/_semantic.scss";
ownership-notes {
+ z-index: 10;
+
.sw-icon-info {
color: $theme-link-color;
}
diff --git a/src/resources/elements/select-picker/select-picker.js b/src/resources/elements/select-picker/select-picker.js
index 8421b2c..7b2a62e 100644
--- a/src/resources/elements/select-picker/select-picker.js
+++ b/src/resources/elements/select-picker/select-picker.js
@@ -24,7 +24,7 @@ import select2 from 'select2'; //eslint-disable-line no-unused-vars
@customElement('select-picker')
export class Select2Picker {
- @bindable({defaultBindingMode : bindingMode.twoWay}) value;
+ @bindable({defaultBindingMode: bindingMode.twoWay}) value;
@bindable valueType = 'Number';
@bindable valueProperty = 'id';
@bindable labelProperty = 'name';
@@ -51,37 +51,37 @@ export class Select2Picker {
let options = {
placeholder: caption,
- allowClear: true
- };
+ allowClear: true
+ };
- if( typeof this.config.filterSearch !== 'undefined' && this.config.filterSearch === false ) {
+ if (typeof this.config.filterSearch !== 'undefined' && this.config.filterSearch === false) {
options.minimumResultsForSearch = Infinity;
}
- if( this.config.valueProperty ) {
+ if (this.config.valueProperty) {
this.valueProperty = this.config.valueProperty;
}
- if( this.config.labelProperty ) {
+ if (this.config.labelProperty) {
this.labelProperty = this.config.labelProperty;
}
- if( this.config.valueType ) {
+ if (this.config.valueType) {
this.valueType = this.config.valueType;
}
- if( typeof this.config.allowClear !== 'undefined') {
+ if (typeof this.config.allowClear !== 'undefined') {
options.allowClear = this.config.allowClear;
}
- if( typeof this.config.noSearch !== 'undefined') {
+ if (typeof this.config.noSearch !== 'undefined') {
options.minimumResultsForSearch = Infinity;
}
- if( this.config.id ) {
+ if (this.config.id) {
this.id = this.config.id;
} else {
- this.id = 'select-' + parseInt(Math.random() * 16384, 10);
+ this.id = `select-${parseInt(Math.random() * 16384, 10)}`;
}
- if( this.config.multiple === true || this.multiple === 'true' ) {
+ if (_.get(this, 'config.multiple') === true || _.get(this, 'multiple') === 'true') {
options.multiple = true;
this.multiple = true;
}
@@ -96,7 +96,7 @@ export class Select2Picker {
this.select2 = $select.select2(options);
let tabIndex = this.config.tabIndex;
- if( typeof tabIndex === 'undefined' ) {
+ if (typeof tabIndex === 'undefined') {
tabIndex = -1;
}
@@ -109,9 +109,9 @@ export class Select2Picker {
unbind() {
let select = this.element.firstElementChild;
- if( select ) {
+ if (select) {
const $select = $(select);
- if( $select.data('select2')) { // depending on the destory state need to check whether it still thinks it is a select2
+ if ($select.data('select2')) { // depending on the destroyed state need to check whether it still thinks it is a select2
$select.select2('destroy');
}
}
@@ -122,28 +122,29 @@ export class Select2Picker {
* @param e selection event.
*/
onSelect(e) {
- if( e.params && e.params.data ) {
- let data = e.params.data.id;
- if( this.multiple === true ) {
- let val = data;
- data = (this.value) ? _.clone(this.value) : this._getClearedValue();
- data.push(val);
- this.value = _.uniq(data); // prevent duplicates
- } else if ( this.valueType === 'Number') {
- this.value = data ? Number.parseInt(data) : this._getClearedValue();
+ if (e.params && e.params.data) {
+ let data = _.get(e, 'params.data.id');
+ let originValue = this.value;
+ if (this.multiple === true) {
+ originValue.push(data);
+ this.value = this._getClearedValue();
+ } else if (this.valueType === 'Number') {
+ originValue = data ? Number.parseInt(data) : this._getClearedValue();
} else {
- this.value = data;
+ originValue = data;
}
- let changeEvent = EventHelper.changeEvent(data);
- this.element.dispatchEvent(changeEvent);
+ _.defer(() => { // need to tickle the array
+ this.value = originValue;
+ this.element.dispatchEvent(EventHelper.changeEvent(this.value));
+ });
}
}
_getClearedValue() {
let value = '';
- if( this.multiple === true ) {
+ if (this.multiple === true) {
value = [];
- } else if ( this.valueType === 'Number') {
+ } else if (this.valueType === 'Number') {
value = -1;
}
return value;
@@ -157,15 +158,27 @@ export class Select2Picker {
return item[this.labelProperty];
}
- onUnselect(e) {
+ onUnselect() {
_.defer(() => {
$(this.select2).off('select2:opening');
});
}
onUnselecting(e) {
- this.value = this._getClearedValue();
- this.element.dispatchEvent(EventHelper.changeEvent(this.value));
+ let removalValue = _.get(e, 'params.args.data');
+ let origValue = this.value;
+ if (removalValue) {
+ if (this.multiple) {
+ this.value = this._getClearedValue();
+ _.pull(origValue, _.get(removalValue, 'id'));
+ } else {
+ origValue = this._getClearedValue();
+ }
+ }
+ _.defer(() => {
+ this.value = origValue;
+ this.element.dispatchEvent(EventHelper.changeEvent(origValue));
+ });
$(this.select2).on('select2:opening', e => {
e.preventDefault();
@@ -198,11 +211,11 @@ export class Select2Picker {
* Handle the conversion of the type from the modeled value to the String equivalence of the value used by select2
*/
_convertToInternal(val) {
- if( typeof val === 'undefined' || _.isNil(val)) {
+ if (typeof val === 'undefined' || _.isNil(val)) {
return undefined;
}
let retValue = val;
- switch(this.valueType) {
+ switch (this.valueType) {
case 'Number':
retValue = val.toString();
break;
@@ -215,9 +228,9 @@ export class Select2Picker {
*/
attached() {
_.debounce(() => {
- if( this.items && this.items.length > 0 ) { // cached items are loaded
- this.valueChanged(this.value);
- }
+ if (this.items && this.items.length > 0) { // cached items are loaded
+ this.valueChanged(this.value);
+ }
}, 125)();
}
@@ -229,7 +242,7 @@ export class Select2Picker {
* @param oldValue
*/
itemsChanged(newValue, oldValue) { //eslint-disable-line no-unused-vars
- if( newValue && newValue.length > 0 ) {
+ if (newValue && newValue.length > 0) {
_.defer(() => {
this.valueChanged(this.value);
});
diff --git a/src/resources/elements/select-picker/select-picker.scss b/src/resources/elements/select-picker/select-picker.scss
index d4b59a5..362bf30 100644
--- a/src/resources/elements/select-picker/select-picker.scss
+++ b/src/resources/elements/select-picker/select-picker.scss
@@ -79,7 +79,7 @@ select-picker {
.select2-selection__clear {
color: $theme-clear-color;
margin-left: $theme-margin-thinner;
- margin-right: 0;
+ margin-right: $theme-margin-thinner;
margin-top: 0;
transform: scale(1.5) translateY(0.5rem);
}
diff --git a/test/unit/resources/elements/select-picker/select-picker.spec.js b/test/unit/resources/elements/select-picker/select-picker.spec.js
new file mode 100644
index 0000000..d83959f
--- /dev/null
+++ b/test/unit/resources/elements/select-picker/select-picker.spec.js
@@ -0,0 +1,152 @@
+/**
+ Copyright 2022 Jason Drake
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ */
+import {Select2Picker} from 'resources/elements/select-picker/select-picker';
+import {createSpyObj} from 'jest-createspyobj';
+import _ from 'lodash';
+
+describe('SelectPicker test suite', () => {
+
+ describe('onSelect', () => {
+ let selectPicker;
+
+ beforeEach(() => {
+ let elm = {
+ dispatchEvent: jest.fn()
+ }
+ selectPicker = new Select2Picker(elm);
+ });
+
+ it('single selected for String', () => {
+ let evt = {};
+ _.defer = jest.fn().mockImplementation(f => f());
+ _.set(evt, 'params.data.id', '32');
+ selectPicker.value = '16';
+ selectPicker.valueType = 'String';
+ selectPicker.onSelect(evt);
+ expect(selectPicker.value).toBe('32');
+ _.delay(() => {
+ expect(selectPicker.value).toBe('32');
+ expect(selectPicker.element.dispatchEvent).toHaveBeenCalled();
+ }, 125);
+ });
+
+ it('single selected for Number', () => {
+ let evt = {};
+ _.defer = jest.fn().mockImplementation(f => f());
+ _.set(evt, 'params.data.id', 32);
+ selectPicker.value = 16;
+ selectPicker.onSelect(evt);
+ expect(selectPicker.value).toBe(32);
+ _.delay(() => {
+ expect(selectPicker.value).toBe(32);
+ expect(selectPicker.element.dispatchEvent).toHaveBeenCalled();
+ }, 125);
+ });
+
+ it('multiple selected from empty', () => {
+ let evt = {};
+ _.set(evt, 'params.data.id', '32');
+ selectPicker.value = []
+ selectPicker.multiple = true;
+ selectPicker.onSelect(evt);
+ expect(selectPicker.value.length).toBe(0);
+ _.delay(() => {
+ expect(selectPicker.value.length).toBe(1);
+ expect(selectPicker.element.dispatchEvent).toHaveBeenCalled();
+ }, 125);
+ });
+
+ it('multiple selected with existing', () => {
+ let evt = {};
+ _.set(evt, 'params.data.id', '32');
+ selectPicker.value = ['4']
+ selectPicker.multiple = true;
+ selectPicker.onSelect(evt);
+ expect(selectPicker.value.length).toBe(0);
+ _.delay(() => {
+ expect(selectPicker.value.length).toBe(2);
+ expect(selectPicker.element.dispatchEvent).toHaveBeenCalled();
+ }, 125);
+ });
+ });
+
+ describe('onUnselecting', () => {
+ let selectPicker;
+
+ beforeEach(() => {
+ let elm = {
+ dispatchEvent: jest.fn()
+ }
+ selectPicker = new Select2Picker(elm);
+ });
+
+ it('single removed', () => {
+ let evt = {};
+ _.defer = jest.fn().mockImplementation(f => f());
+ _.set(evt, 'params.args.data', '32');
+ selectPicker.value = '32';
+ selectPicker.valueType = 'String';
+ selectPicker.onUnselecting(evt);
+ expect(selectPicker.value).toBe('');
+ _.delay(() => {
+ expect(selectPicker.value).toBe('');
+ expect(selectPicker.element.dispatchEvent).toHaveBeenCalled();
+ }, 125);
+ });
+
+ it('single removed as numeric', () => {
+ let evt = {};
+ _.set(evt, 'params.args.data', 64);
+ selectPicker.value = 64;
+ selectPicker.valueType = 'Number';
+ selectPicker.onUnselecting(evt);
+ expect(selectPicker.value).toBe(64);
+ _.delay(() => {
+ expect(selectPicker.value).toBe(-1);
+ expect(selectPicker.element.dispatchEvent).toHaveBeenCalled();
+ }, 125);
+ });
+
+ it('multiple removed one from list', () => {
+ let evt = {};
+ _.set(evt, 'params.args.data', '32');
+ selectPicker.multiple = true;
+ selectPicker.value = ['2', '32', '64'];
+ selectPicker.onUnselecting(evt);
+ expect(selectPicker.value.length).toBe(0);
+ _.delay(() => {
+ expect(selectPicker.value.length).toBe(2);
+ expect(selectPicker.element.dispatchEvent).toHaveBeenCalled();
+ }, 125);
+ });
+
+ it('multiple removed last from list', () => {
+ let evt = {};
+ _.set(evt, 'params.args.data', '32');
+ selectPicker.multiple = true;
+ selectPicker.value = ['32'];
+ selectPicker.onUnselecting(evt);
+ expect(selectPicker.value.length).toBe(0);
+ _.delay(() => {
+ expect(selectPicker.value.length).toBe(0);
+ expect(selectPicker.element.dispatchEvent).toHaveBeenCalled();
+ }, 125);
+
+ });
+ });
+
+
+});