Skip to content

Commit

Permalink
feat(core): add custom entry to Select Editor/Filter collections (#592)
Browse files Browse the repository at this point in the history
* feat(core): add custom entry to Select Editor/Filter collections
- add 2 new methods (`addCustomFirstEntry`, `addCustomLastEntry`) to optionally add entry on both end of the collection
  • Loading branch information
ghiscoding committed Oct 1, 2020
1 parent f847e43 commit 43e483e
Show file tree
Hide file tree
Showing 5 changed files with 173 additions and 50 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,7 @@ describe('SelectEditor', () => {
expect(editorElm[0].value).toEqual('male');
});

it('should create the multi-select filter with a blank entry at the beginning of the collection when "addBlankEntry" is set in the "collectionOptions" property', () => {
it('should create the multi-select editor with a blank entry at the beginning of the collection when "addBlankEntry" is set in the "collectionOptions" property', () => {
mockColumn.internalColumnEditor.collection = [{ value: 'male', label: 'male' }, { value: 'female', label: 'female' }];
mockColumn.internalColumnEditor.collectionOptions = { addBlankEntry: true };

Expand All @@ -217,6 +217,39 @@ describe('SelectEditor', () => {
editorOkElm.click();

expect(editorListElm.length).toBe(3);
expect(editorListElm[0].value).toBe('');
expect(editorListElm[1].textContent).toBe('');
});

it('should create the multi-select editor with a custom entry at the beginning of the collection when "addCustomFirstEntry" is provided in the "collectionOptions" property', () => {
mockColumn.internalColumnEditor.collection = [{ value: 'male', label: 'male' }, { value: 'female', label: 'female' }];
mockColumn.internalColumnEditor.collectionOptions = { addCustomFirstEntry: { value: null, label: '' } };

editor = new SelectEditor(editorArguments, true);
const editorBtnElm = divContainer.querySelector<HTMLButtonElement>('.ms-parent.ms-filter.editor-gender button.ms-choice');
const editorListElm = divContainer.querySelectorAll<HTMLInputElement>(`[name=editor-gender].ms-drop ul>li input[type=checkbox]`);
const editorOkElm = divContainer.querySelector<HTMLButtonElement>(`[name=editor-gender].ms-drop .ms-ok-button`);
editorBtnElm.click();
editorOkElm.click();

expect(editorListElm.length).toBe(3);
expect(editorListElm[0].value).toBe('');
expect(editorListElm[1].textContent).toBe('');
});

it('should create the multi-select editor with a custom entry at the end of the collection when "addCustomFirstEntry" is provided in the "collectionOptions" property', () => {
mockColumn.internalColumnEditor.collection = [{ value: 'male', label: 'male' }, { value: 'female', label: 'female' }];
mockColumn.internalColumnEditor.collectionOptions = { addCustomLastEntry: { value: null, label: '' } };

editor = new SelectEditor(editorArguments, true);
const editorBtnElm = divContainer.querySelector<HTMLButtonElement>('.ms-parent.ms-filter.editor-gender button.ms-choice');
const editorListElm = divContainer.querySelectorAll<HTMLInputElement>(`[name=editor-gender].ms-drop ul>li input[type=checkbox]`);
const editorOkElm = divContainer.querySelector<HTMLButtonElement>(`[name=editor-gender].ms-drop .ms-ok-button`);
editorBtnElm.click();
editorOkElm.click();

expect(editorListElm.length).toBe(3);
expect(editorListElm[2].value).toBe('');
expect(editorListElm[1].textContent).toBe('');
});

Expand Down Expand Up @@ -457,7 +490,7 @@ describe('SelectEditor', () => {
});

describe('initialize with collection', () => {
it('should create the multi-select filter with a default search term when passed as a filter argument even with collection an array of strings', () => {
it('should create the multi-select editor with a default search term when passed as a filter argument even with collection an array of strings', () => {
mockColumn.internalColumnEditor.collection = ['male', 'female'];

editor = new SelectEditor(editorArguments, true);
Expand All @@ -474,7 +507,7 @@ describe('SelectEditor', () => {
});

describe('collectionSortBy setting', () => {
it('should create the multi-select filter and sort the string collection when "collectionSortBy" is set', () => {
it('should create the multi-select editor and sort the string collection when "collectionSortBy" is set', () => {
mockColumn.internalColumnEditor = {
collection: ['other', 'male', 'female'],
collectionSortBy: {
Expand All @@ -494,7 +527,7 @@ describe('SelectEditor', () => {
expect(editorListElm[2].value).toBe('female');
});

it('should create the multi-select filter and sort the value/label pair collection when "collectionSortBy" is set', () => {
it('should create the multi-select editor and sort the value/label pair collection when "collectionSortBy" is set', () => {
mockColumn.internalColumnEditor = {
collection: [{ value: 'other', description: 'other' }, { value: 'male', description: 'male' }, { value: 'female', description: 'female' }],
collectionSortBy: {
Expand All @@ -521,7 +554,7 @@ describe('SelectEditor', () => {
});

describe('collectionFilterBy setting', () => {
it('should create the multi-select filter and filter the string collection when "collectionFilterBy" is set', () => {
it('should create the multi-select editor and filter the string collection when "collectionFilterBy" is set', () => {
mockColumn.internalColumnEditor = {
collection: ['other', 'male', 'female'],
collectionFilterBy: {
Expand All @@ -539,7 +572,7 @@ describe('SelectEditor', () => {
expect(editorListElm[0].value).toBe('other');
});

it('should create the multi-select filter and filter the value/label pair collection when "collectionFilterBy" is set', () => {
it('should create the multi-select editor and filter the value/label pair collection when "collectionFilterBy" is set', () => {
mockColumn.internalColumnEditor = {
collection: [{ value: 'other', description: 'other' }, { value: 'male', description: 'male' }, { value: 'female', description: 'female' }],
collectionFilterBy: [
Expand All @@ -561,7 +594,7 @@ describe('SelectEditor', () => {
expect(editorListElm[0].value).toBe('female');
});

it('should create the multi-select filter and filter the value/label pair collection when "collectionFilterBy" is set and "filterResultAfterEachPass" is set to "merge"', () => {
it('should create the multi-select editor and filter the value/label pair collection when "collectionFilterBy" is set and "filterResultAfterEachPass" is set to "merge"', () => {
mockColumn.internalColumnEditor = {
collection: [{ value: 'other', description: 'other' }, { value: 'male', description: 'male' }, { value: 'female', description: 'female' }],
collectionFilterBy: [
Expand Down Expand Up @@ -615,7 +648,7 @@ describe('SelectEditor', () => {
});

describe('enableRenderHtml property', () => {
it('should create the multi-select filter with a default search term and have the HTML rendered when "enableRenderHtml" is set', () => {
it('should create the multi-select editor with a default search term and have the HTML rendered when "enableRenderHtml" is set', () => {
mockColumn.internalColumnEditor = {
enableRenderHtml: true,
collection: [{ value: true, label: 'True', labelPrefix: `<i class="fa fa-check"></i> ` }, { value: false, label: 'False' }],
Expand All @@ -635,7 +668,7 @@ describe('SelectEditor', () => {
expect(editorListElm[0].innerHTML).toBe('<i class="fa fa-check"></i> True');
});

it('should create the multi-select filter with a default search term and have the HTML rendered and sanitized when "enableRenderHtml" is set and has <script> tag', () => {
it('should create the multi-select editor with a default search term and have the HTML rendered and sanitized when "enableRenderHtml" is set and has <script> tag', () => {
mockColumn.internalColumnEditor = {
enableRenderHtml: true,
collection: [{ isEffort: true, label: 'True', labelPrefix: `<script>alert('test')></script><i class="fa fa-check"></i> ` }, { isEffort: false, label: 'False' }],
Expand Down
27 changes: 24 additions & 3 deletions src/app/modules/angular-slickgrid/editors/selectEditor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -519,10 +519,24 @@ export class SelectEditor implements Editor {
}

// user can optionally add a blank entry at the beginning of the collection
if (this.collectionOptions && this.collectionOptions.addBlankEntry && Array.isArray(collection) && collection.length > 0 && collection[0][this.labelName] !== '') {
// make sure however that it wasn't added more than once
if (this.collectionOptions && this.collectionOptions.addBlankEntry && Array.isArray(collection) && collection.length > 0 && collection[0][this.valueName] !== '') {
collection.unshift(this.createBlankEntry());
}

// user can optionally add his own custom entry at the beginning of the collection
if (this.collectionOptions && this.collectionOptions.addCustomFirstEntry && Array.isArray(collection) && collection.length > 0 && collection[0][this.valueName] !== this.collectionOptions.addCustomFirstEntry[this.valueName]) {
collection.unshift(this.collectionOptions && this.collectionOptions.addCustomFirstEntry);
}

// user can optionally add his own custom entry at the end of the collection
if (this.collectionOptions && this.collectionOptions.addCustomLastEntry && Array.isArray(collection) && collection.length > 0) {
const lastCollectionIndex = collection.length - 1;
if (collection[lastCollectionIndex][this.valueName] !== this.collectionOptions.addCustomLastEntry[this.valueName]) {
collection.push(this.collectionOptions && this.collectionOptions.addCustomLastEntry);
}
}

let newCollection = collection || [];

// user might want to filter and/or sort certain items of the collection
Expand Down Expand Up @@ -560,7 +574,9 @@ export class SelectEditor implements Editor {
let prefixText = option[this.labelPrefixName] || '';
let suffixText = option[this.labelSuffixName] || '';
let optionLabel = option[this.optionLabel] || '';
optionLabel = optionLabel.toString().replace(/\"/g, '\''); // replace double quotes by single quotes to avoid interfering with regular html
if (optionLabel && optionLabel.toString) {
optionLabel = optionLabel.toString().replace(/\"/g, '\''); // replace double quotes by single quotes to avoid interfering with regular html
}

// also translate prefix/suffix if enableTranslateLabel is true and text is a string
prefixText = (this.enableTranslateLabel && prefixText && typeof prefixText === 'string') ? this._translate.instant(prefixText || ' ') : prefixText;
Expand All @@ -580,7 +596,12 @@ export class SelectEditor implements Editor {
optionText = htmlEncode(sanitizedText);
}

options += `<option value="${option[this.valueName]}" label="${optionLabel}">${optionText}</option>`;
// html text of each select option
let optionValue = option[this.valueName];
if (optionValue === undefined || optionValue === null) {
optionValue = '';
}
options += `<option value="${optionValue}" label="${optionLabel}">${optionText}</option>`;
});
}

Expand Down

0 comments on commit 43e483e

Please sign in to comment.