From 5c96c2d4ee9ed401d3f0d8da321826dd779fd63d Mon Sep 17 00:00:00 2001 From: Karl Bishop Date: Mon, 11 Apr 2016 06:55:58 -0400 Subject: [PATCH] fix(select): using string.match not regexp.test (fixes #57, fixes #54, fixes #56) * Using string.match not regexp.test * Added stripTags to filtering values * Fixed line breaking on city array * Backed out child filter change * fixed highlights and slect value display * fixed lint errors * Added RichDemo example --- components/select/select-pipes.ts | 23 +++++- components/select/select.ts | 20 +++-- demo/components/select-section.ts | 8 +- demo/components/select/rich-demo.html | 21 ++++++ demo/components/select/rich-demo.ts | 104 ++++++++++++++++++++++++++ demo/components/select/single-demo.ts | 15 ++-- 6 files changed, 175 insertions(+), 16 deletions(-) create mode 100644 demo/components/select/rich-demo.html create mode 100644 demo/components/select/rich-demo.ts diff --git a/components/select/select-pipes.ts b/components/select/select-pipes.ts index 03df053a..4ffb6eda 100644 --- a/components/select/select-pipes.ts +++ b/components/select/select-pipes.ts @@ -11,12 +11,29 @@ export class HightlightPipe { let query = args[0]; - return query ? - value.replace(new RegExp(this.escapeRegexp(query), 'gi'), '$&') : - value; + if ( query ) { + let tagRE = new RegExp('<[^<>]*>', 'ig'); + // get ist of tags + let tagList = value.match( tagRE ); + // Replace tags with token + let tmpValue = value.replace( tagRE, '$!$'); + // Replace search words + value = tmpValue.replace(new RegExp(this.escapeRegexp(query), 'gi'), '$&'); + // Reinsert HTML + for (let i = 0; value.indexOf('$!$') > -1; i++) { + value = value.replace('$!$', tagList[i]); + } + } + return value; } private escapeRegexp(queryToEscape:string) { return queryToEscape.replace(/([.?*+^$[\]\\(){}|-])/g, '\\$1'); } } + +export function stripTags(input:string) { + let tags = /<\/?([a-z][a-z0-9]*)\b[^>]*>/gi, + commentsAndPhpTags = /|<\?(?:php)?[\s\S]*?\?>/gi; + return input.replace(commentsAndPhpTags, '').replace(tags, ''); +} diff --git a/components/select/select.ts b/components/select/select.ts index d8cbba08..055b9209 100644 --- a/components/select/select.ts +++ b/components/select/select.ts @@ -12,7 +12,10 @@ import { NgStyle } from 'angular2/common'; import {SelectItem} from './select-item'; -import {HightlightPipe} from './select-pipes'; +import { + HightlightPipe, + stripTags +} from './select-pipes'; import {IOptionsBehavior} from './select-interfaces'; let optionsTemplate = ` @@ -68,7 +71,8 @@ let optionsTemplate = ` style="outline: 0;"> {{placeholder}} {{active[0].text}} + [ngClass]="{'ui-select-allow-clear': allowClear && active.length > 0}" + [innerHTML]="active[0].text"> { let el = this.element.nativeElement.querySelector('div.ui-select-container > input'); - el.focus(); - el.value = value; + if (el) { + el.focus(); + el.value = value; + } }, 0); } @@ -417,6 +423,7 @@ export class Select { if (this.multiple === true) { this.focusToInput(''); } else { + this.focusToInput( stripTags(value.text) ); this.element.nativeElement.querySelector('.ui-select-container').focus(); } } @@ -518,7 +525,7 @@ export class GenericBehavior extends Behavior implements IOptionsBehavior { public filter(query:RegExp) { let options = this.actor.itemObjects - .filter(option => query.test(option.text) && + .filter(option => stripTags(option.text).match(query) && (this.actor.multiple === false || (this.actor.multiple === true && this.actor.active.indexOf(option) < 0))); @@ -529,6 +536,7 @@ export class GenericBehavior extends Behavior implements IOptionsBehavior { super.ensureHighlightVisible(); } } + } export class ChildrenBehavior extends Behavior implements IOptionsBehavior { @@ -618,3 +626,5 @@ export class ChildrenBehavior extends Behavior implements IOptionsBehavior { } } } + + diff --git a/demo/components/select-section.ts b/demo/components/select-section.ts index 188aee25..6f432b14 100644 --- a/demo/components/select-section.ts +++ b/demo/components/select-section.ts @@ -6,6 +6,7 @@ import {TAB_DIRECTIVES} from 'ng2-bootstrap/ng2-bootstrap'; import {SingleDemo} from './select/single-demo'; import {MultipleDemo} from './select/multiple-demo'; import {ChildrenDemo} from './select/children-demo'; +import {RichDemo} from './select/rich-demo'; let name = 'Select'; // webpack html imports @@ -26,6 +27,11 @@ let tabDesc:Array = [ heading: 'Children', ts: require('!!prismjs?lang=typescript!./select/children-demo.ts'), html: require('!!prismjs?lang=markup!./select/children-demo.html') + }, + { + heading: 'Rich', + ts: require('!!prismjs?lang=typescript!./select/rich-demo.ts'), + html: require('!!prismjs?lang=markup!./select/rich-demo.html') } ]; @@ -80,7 +86,7 @@ tabDesc.forEach(desc => { `, - directives: [SingleDemo, MultipleDemo, ChildrenDemo, TAB_DIRECTIVES, CORE_DIRECTIVES] + directives: [SingleDemo, MultipleDemo, ChildrenDemo, RichDemo, TAB_DIRECTIVES, CORE_DIRECTIVES] }) export class SelectSection { public currentHeading:string = 'Single'; diff --git a/demo/components/select/rich-demo.html b/demo/components/select/rich-demo.html new file mode 100644 index 00000000..927711e1 --- /dev/null +++ b/demo/components/select/rich-demo.html @@ -0,0 +1,21 @@ +
+

Select a color

+ + +

+
{{value.text}}
+
+ +
+
diff --git a/demo/components/select/rich-demo.ts b/demo/components/select/rich-demo.ts new file mode 100644 index 00000000..677cac04 --- /dev/null +++ b/demo/components/select/rich-demo.ts @@ -0,0 +1,104 @@ +import { + Component, + OnInit, + ViewEncapsulation +} from 'angular2/core'; +import {CORE_DIRECTIVES, FORM_DIRECTIVES, NgClass} from 'angular2/common'; +import {ButtonCheckbox} from 'ng2-bootstrap/ng2-bootstrap'; + +import {SELECT_DIRECTIVES} from '../../../ng2-select'; + +const COLORS = [ + { 'name': 'Blue 10', 'hex': '#C0E6FF' }, + { 'name': 'Blue 20', 'hex': '#7CC7FF' }, + { 'name': 'Blue 30', 'hex': '#5AAAFA' }, + { 'name': 'Blue 40', 'hex': '#5596E6' }, + { 'name': 'Blue 50', 'hex': '#4178BE' }, + { 'name': 'Blue 60', 'hex': '#325C80' }, + { 'name': 'Blue 70', 'hex': '#264A60' }, + { 'name': 'Blue 80', 'hex': '#1D3649' }, + { 'name': 'Blue 90', 'hex': '#152935' }, + { 'name': 'Blue 100', 'hex': '#010205' }, + { 'name': 'Green 10', 'hex': '#C8F08F' }, + { 'name': 'Green 20', 'hex': '#B4E051' }, + { 'name': 'Green 30', 'hex': '#8CD211' }, + { 'name': 'Green 40', 'hex': '#5AA700' }, + { 'name': 'Green 50', 'hex': '#4B8400' }, + { 'name': 'Green 60', 'hex': '#2D660A' }, + { 'name': 'Green 70', 'hex': '#144D14' }, + { 'name': 'Green 80', 'hex': '#0A3C02' }, + { 'name': 'Green 90', 'hex': '#0C2808' }, + { 'name': 'Green 100', 'hex': '#010200' }, + { 'name': 'Red 10', 'hex': '#FFD2DD' }, + { 'name': 'Red 20', 'hex': '#FFA5B4' }, + { 'name': 'Red 30', 'hex': '#FF7D87' }, + { 'name': 'Red 40', 'hex': '#FF5050' }, + { 'name': 'Red 50', 'hex': '#E71D32' }, + { 'name': 'Red 60', 'hex': '#AD1625' }, + { 'name': 'Red 70', 'hex': '#8C101C' }, + { 'name': 'Red 80', 'hex': '#6E0A1E' }, + { 'name': 'Red 90', 'hex': '#4C0A17' }, + { 'name': 'Red 100', 'hex': '#040001' }, + { 'name': 'Yellow 10', 'hex': '#FDE876' }, + { 'name': 'Yellow 20', 'hex': '#FDD600' }, + { 'name': 'Yellow 30', 'hex': '#EFC100' }, + { 'name': 'Yellow 40', 'hex': '#BE9B00' }, + { 'name': 'Yellow 50', 'hex': '#8C7300' }, + { 'name': 'Yellow 60', 'hex': '#735F00' }, + { 'name': 'Yellow 70', 'hex': '#574A00' }, + { 'name': 'Yellow 80', 'hex': '#3C3200' }, + { 'name': 'Yellow 90', 'hex': '#281E00' }, + { 'name': 'Yellow 100', 'hex': '#020100' } +]; + +// webpack html imports +let template = require('./rich-demo.html'); + +@Component({ + selector: 'rich-demo', + template: template, + styles: [`colorbox,.colorbox { display:inline-block; height:14px; width:14px;margin-right:4px; border:1px solid #000;}`], + directives: [SELECT_DIRECTIVES, NgClass, CORE_DIRECTIVES, FORM_DIRECTIVES, ButtonCheckbox], + encapsulation: ViewEncapsulation.None // Enable dynamic HTML styles +}) +export class RichDemo implements OnInit { + private value:any = {}; + private _disabledV:string = '0'; + private disabled:boolean = false; + private items:Array = []; + + ngOnInit() { + COLORS.forEach( c => { + this.items.push( { + id : c.hex, + text: `${c.name} (${c.hex})` + }); + }); + } + + private get disabledV():string { + return this._disabledV; + } + + private set disabledV(value:string) { + this._disabledV = value; + this.disabled = this._disabledV === '1'; + } + + private selected(value:any) { + console.log('Selected value is: ', value); + } + + private removed(value:any) { + console.log('Removed value is: ', value); + } + + private typed(value:any) { + console.log('New search input: ', value); + } + + private refreshValue(value:any) { + this.value = value; + } +} + diff --git a/demo/components/select/single-demo.ts b/demo/components/select/single-demo.ts index 1ff20ac2..3da0ad80 100644 --- a/demo/components/select/single-demo.ts +++ b/demo/components/select/single-demo.ts @@ -18,13 +18,14 @@ export class SingleDemo { private disabled:boolean = false; private items:Array = ['Amsterdam', 'Antwerp', 'Athens', 'Barcelona', 'Berlin', 'Birmingham', 'Bradford', 'Bremen', 'Brussels', 'Bucharest', - 'Budapest', 'Cologne', 'Copenhagen', 'Dortmund', 'Dresden', 'Dublin', 'Düsseldorf', - 'Essen', 'Frankfurt', 'Genoa', 'Glasgow', 'Gothenburg', 'Hamburg', 'Hannover', - 'Helsinki', 'Leeds', 'Leipzig', 'Lisbon', 'Łódź', 'London', 'Kraków', 'Madrid', - 'Málaga', 'Manchester', 'Marseille', 'Milan', 'Munich', 'Naples', 'Palermo', - 'Paris', 'Poznań', 'Prague', 'Riga', 'Rome', 'Rotterdam', 'Seville', 'Sheffield', - 'Sofia', 'Stockholm', 'Stuttgart', 'The Hague', 'Turin', 'Valencia', 'Vienna', - 'Vilnius', 'Warsaw', 'Wrocław', 'Zagreb', 'Zaragoza']; + 'Budapest', 'Cologne', 'Copenhagen', 'Dortmund', 'Dresden', 'Dublin', + 'Düsseldorf', 'Essen', 'Frankfurt', 'Genoa', 'Glasgow', 'Gothenburg', + 'Hamburg', 'Hannover', 'Helsinki', 'Kraków', 'Leeds', 'Leipzig', 'Lisbon', + 'London', 'Madrid', 'Manchester', 'Marseille', 'Milan', 'Munich', 'Málaga', + 'Naples', 'Palermo', 'Paris', 'Poznań', 'Prague', 'Riga', 'Rome', + 'Rotterdam', 'Seville', 'Sheffield', 'Sofia', 'Stockholm', 'Stuttgart', + 'The Hague', 'Turin', 'Valencia', 'Vienna', 'Vilnius', 'Warsaw', 'Wrocław', + 'Zagreb', 'Zaragoza', 'Łódź']; private get disabledV():string { return this._disabledV;