From 8b848f58cd925e89abd1340e4fe83639703d7eb0 Mon Sep 17 00:00:00 2001 From: Ed Carroll Date: Wed, 22 Mar 2017 10:31:18 +0000 Subject: [PATCH 01/25] Disabled automatic positioning --- .gitignore | 1 - components/search/search.ts | 5 ----- package.json | 2 +- 3 files changed, 1 insertion(+), 7 deletions(-) diff --git a/.gitignore b/.gitignore index b4ced5e11..4dcd9f6b3 100644 --- a/.gitignore +++ b/.gitignore @@ -5,7 +5,6 @@ /tmp ## ngc logs - *.ngfactory.ts *.ngsummary.json diff --git a/components/search/search.ts b/components/search/search.ts index 4221eb105..d161fa6ef 100644 --- a/components/search/search.ts +++ b/components/search/search.ts @@ -39,7 +39,6 @@ import {PositioningService, PositioningPlacement} from '../util/positioning.serv export class SuiSearch implements AfterViewInit { public dropdownService:DropdownService; public searchService:SearchService; - public position:PositioningService; @ViewChild(SuiDropdownMenu) private _menu:SuiDropdownMenu; @@ -131,10 +130,6 @@ export class SuiSearch implements AfterViewInit { public ngAfterViewInit() { this._menu.service = this.dropdownService; - - // Initialse the positioning service to correctly display the results. - // This adds support for repositioning the results above the search when there isn't enough space below. - this.position = new PositioningService(this._element, this._menu.element, PositioningPlacement.BottomLeft); } // Selects an item. diff --git a/package.json b/package.json index cb279a898..fcb7fd6b9 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,7 @@ "main": "ng2-semantic-ui.dist.js", "module": "index.js", "typings": "index.d.ts", - "version": "0.5.0", + "version": "0.5.1", "description": "Angular 2 Semantic UI Components", "repository": { "type": "git", From ded6b8e0684086470f087131ecb51be083bb10ff Mon Sep 17 00:00:00 2001 From: Ed Carroll Date: Wed, 22 Mar 2017 10:32:25 +0000 Subject: [PATCH 02/25] Fixed rollup warning --- rollup.config.js | 1 - 1 file changed, 1 deletion(-) diff --git a/rollup.config.js b/rollup.config.js index db66e20d8..8a7f72031 100644 --- a/rollup.config.js +++ b/rollup.config.js @@ -1,4 +1,3 @@ -import rollup from 'rollup' import nodeResolve from 'rollup-plugin-node-resolve' import commonjs from 'rollup-plugin-commonjs'; import uglify from 'rollup-plugin-uglify' From b7cd0b99229ad9cb52f39db505e5639bc5a5e868 Mon Sep 17 00:00:00 2001 From: Ed Carroll Date: Wed, 22 Mar 2017 10:46:37 +0000 Subject: [PATCH 03/25] Fixed search not being able to programmatically deselect option --- components/search/search.ts | 6 ++---- package.json | 2 +- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/components/search/search.ts b/components/search/search.ts index d161fa6ef..24ee0321c 100644 --- a/components/search/search.ts +++ b/components/search/search.ts @@ -155,10 +155,8 @@ export class SuiSearch implements AfterViewInit { // Sets a specific item to be selected, updating the query automatically. public writeValue(item:T) { - if (item) { - this.selectedItem = item; - this.searchService.updateQuery(this.readValue(item) as string, () => {}); - } + this.selectedItem = item; + this.searchService.updateQuery(item ? this.readValue(item) as string : ""); } } diff --git a/package.json b/package.json index fcb7fd6b9..6f36f8c94 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,7 @@ "main": "ng2-semantic-ui.dist.js", "module": "index.js", "typings": "index.d.ts", - "version": "0.5.1", + "version": "0.5.2", "description": "Angular 2 Semantic UI Components", "repository": { "type": "git", From e4a8d89ceb74e0e0342860c2e0fbb8e96261faad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Damjan=20Cilens=CC=8Cek?= Date: Wed, 22 Mar 2017 15:05:24 +0100 Subject: [PATCH 04/25] Use e.target instead of IE's e.srcElement --- components/dropdown/dropdown-menu.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/dropdown/dropdown-menu.ts b/components/dropdown/dropdown-menu.ts index d49457b49..2c05270ef 100644 --- a/components/dropdown/dropdown-menu.ts +++ b/components/dropdown/dropdown-menu.ts @@ -137,7 +137,7 @@ export class SuiDropdownMenu extends SuiTransition implements AfterContentInit { e.stopPropagation(); if (this._service.autoCloseMode == DropdownAutoCloseType.ItemClick) { - if (e.srcElement.classList.contains("item")) { + if ((e.target as Element).classList.contains("item")) { // Once an item is selected, we can close the entire dropdown. this._service.setOpenState(false, true); } From 958168b28709c2e85db634d1cfec696a3567e240 Mon Sep 17 00:00:00 2001 From: Ed Carroll Date: Wed, 22 Mar 2017 14:14:21 +0000 Subject: [PATCH 05/25] Closes #27 --- components/dropdown/dropdown-menu.ts | 5 ++++- package.json | 3 ++- rollup.config.js | 5 ++++- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/components/dropdown/dropdown-menu.ts b/components/dropdown/dropdown-menu.ts index d49457b49..793432034 100644 --- a/components/dropdown/dropdown-menu.ts +++ b/components/dropdown/dropdown-menu.ts @@ -3,6 +3,8 @@ import {SuiTransition, Transition} from '../transition/transition'; import {DropdownService, DropdownAutoCloseType} from './dropdown.service'; import {TransitionController} from '../transition/transition-controller'; import {KeyCode} from '../util/util'; +// Polyfill for IE +import "element-closest"; @Directive({ // We must attach to every '.item' as Angular doesn't support > selectors. @@ -137,7 +139,8 @@ export class SuiDropdownMenu extends SuiTransition implements AfterContentInit { e.stopPropagation(); if (this._service.autoCloseMode == DropdownAutoCloseType.ItemClick) { - if (e.srcElement.classList.contains("item")) { + const target = e.target as Element; + if (this.element.nativeElement.contains(target.closest(".item")) && !/input|textarea/i.test(target.tagName)) { // Once an item is selected, we can close the entire dropdown. this._service.setOpenState(false, true); } diff --git a/package.json b/package.json index 6f36f8c94..bb073c25d 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,7 @@ "main": "ng2-semantic-ui.dist.js", "module": "index.js", "typings": "index.d.ts", - "version": "0.5.2", + "version": "0.5.3", "description": "Angular 2 Semantic UI Components", "repository": { "type": "git", @@ -38,6 +38,7 @@ "@angular/http": ">=2.4.1", "@angular/platform-browser": ">=2.4.1", "core-js": ">=2.4.1", + "element-closest": "^2.0.2", "popper.js": "^1.0.6", "reflect-metadata": "^0.1.3", "rxjs": "^5.0.1", diff --git a/rollup.config.js b/rollup.config.js index 8a7f72031..00de760b5 100644 --- a/rollup.config.js +++ b/rollup.config.js @@ -26,7 +26,10 @@ export default { plugins: [ nodeResolve({ jsnext: true, module: true }), commonjs({ - include: 'node_modules/rxjs/**', + include: [ + 'node_modules/rxjs/**', + 'node_modules/element-closest/**' + ] }), uglify() ] From 529fa98df0caff6933847b754b54581186e603b2 Mon Sep 17 00:00:00 2001 From: Ed Carroll Date: Wed, 22 Mar 2017 14:17:58 +0000 Subject: [PATCH 06/25] Stopped tabindex being applied to nested dropdowns --- components/dropdown/dropdown.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/dropdown/dropdown.ts b/components/dropdown/dropdown.ts index 776c1e87d..52fb8fb1f 100644 --- a/components/dropdown/dropdown.ts +++ b/components/dropdown/dropdown.ts @@ -56,7 +56,7 @@ export class SuiDropdown implements AfterContentInit { @HostBinding('attr.tabindex') public get tabIndex() { - return this.isDisabled ? -1 : 0; + return this.isDisabled || (this.service && this.service.isNested) ? -1 : 0; } @Input() From dccbe6eb1a47bb30bbce1cde72a26a5758e4782c Mon Sep 17 00:00:00 2001 From: Ed Carroll Date: Wed, 22 Mar 2017 14:36:59 +0000 Subject: [PATCH 07/25] Fixed tabindex still appearing as -1 --- components/dropdown/dropdown.ts | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/components/dropdown/dropdown.ts b/components/dropdown/dropdown.ts index 52fb8fb1f..7802e6625 100644 --- a/components/dropdown/dropdown.ts +++ b/components/dropdown/dropdown.ts @@ -56,7 +56,7 @@ export class SuiDropdown implements AfterContentInit { @HostBinding('attr.tabindex') public get tabIndex() { - return this.isDisabled || (this.service && this.service.isNested) ? -1 : 0; + return (this.isDisabled || this.service.isNested) ? null : 0; } @Input() diff --git a/package.json b/package.json index bb073c25d..38d78fe95 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,7 @@ "main": "ng2-semantic-ui.dist.js", "module": "index.js", "typings": "index.d.ts", - "version": "0.5.3", + "version": "0.5.1", "description": "Angular 2 Semantic UI Components", "repository": { "type": "git", From a7f9bc206fa4a86828a66defa10f5cb942faad75 Mon Sep 17 00:00:00 2001 From: Ed Carroll Date: Wed, 22 Mar 2017 14:40:07 +0000 Subject: [PATCH 08/25] Bumped version to 0.5.5 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 38d78fe95..ddc3c8697 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,7 @@ "main": "ng2-semantic-ui.dist.js", "module": "index.js", "typings": "index.d.ts", - "version": "0.5.1", + "version": "0.5.5", "description": "Angular 2 Semantic UI Components", "repository": { "type": "git", From 1005f17ebbe9cabff092009e96418eec1d5987cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Damjan=20Cilens=CC=8Cek?= Date: Sun, 26 Mar 2017 13:23:52 +0200 Subject: [PATCH 09/25] Detect lookup function in options input --- components/select/select-base.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/components/select/select-base.ts b/components/select/select-base.ts index e5489c2fa..43bfaa8bb 100644 --- a/components/select/select-base.ts +++ b/components/select/select-base.ts @@ -70,6 +70,10 @@ export abstract class SuiSelectBase implements AfterContentInit { } public set options(options:T[]) { + if (typeof (options) == "function") { + this.searchService.optionsLookup = options; + return; + } this.searchService.options = options; this.optionsUpdateHook(); } From f90c83f5643cc4f3f7324e367bb78fb264f37821 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Damjan=20Cilens=CC=8Cek?= Date: Sun, 26 Mar 2017 13:24:50 +0200 Subject: [PATCH 10/25] Initial lookup call when opening a dropdown --- components/select/select-base.ts | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/components/select/select-base.ts b/components/select/select-base.ts index 43bfaa8bb..f71a02da2 100644 --- a/components/select/select-base.ts +++ b/components/select/select-base.ts @@ -72,6 +72,12 @@ export abstract class SuiSelectBase implements AfterContentInit { public set options(options:T[]) { if (typeof (options) == "function") { this.searchService.optionsLookup = options; + let subscription = this.dropdownService.isOpenChange.subscribe((value:boolean) => { + if (value) { + subscription.unsubscribe(); + this.updateQuery(this.query); + } + }); return; } this.searchService.options = options; @@ -90,6 +96,10 @@ export abstract class SuiSelectBase implements AfterContentInit { } public set query(query:string) { + this.updateQuery(query); + } + + protected updateQuery(query:string) { this.queryUpdateHook(); // Update the query then open the dropdown, as after keyboard input it should always be open. this.searchService.updateQuery(query, () => From 38dff6119795c0e9f572474cbaf31d491f598f75 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Damjan=20Cilens=CC=8Cek?= Date: Sun, 26 Mar 2017 13:26:24 +0200 Subject: [PATCH 11/25] Search lookup example in demo app --- demo/src/app/pages/select/select.page.html | 7 +++++++ demo/src/app/pages/select/select.page.ts | 16 +++++++++++++++- 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/demo/src/app/pages/select/select.page.html b/demo/src/app/pages/select/select.page.html index 45488b712..c33396980 100644 --- a/demo/src/app/pages/select/select.page.html +++ b/demo/src/app/pages/select/select.page.html @@ -27,6 +27,13 @@

Search Selection

+ +
+

Search Selection Lookup

+

A select can allow a user to search through a list of choices from API

+
+ +

Multiple Selection

diff --git a/demo/src/app/pages/select/select.page.ts b/demo/src/app/pages/select/select.page.ts index 2b149ed32..3b6d2dea6 100644 --- a/demo/src/app/pages/select/select.page.ts +++ b/demo/src/app/pages/select/select.page.ts @@ -231,6 +231,20 @@ export class SelectExampleSearch { public options:Array = [{ name: "Example" }, { name: "Test" }, { name: "What" }, { name: "No" }, { name: "Benefit" }, { name: "Oranges" }, { name: "Artemis" }, { name: "Another" }]; } +@Component({ + selector: 'select-example-search-lookup', + template: new SelectPage().exampleSearchTemplate +}) +export class SelectExampleLookupSearch { + private _options:Array = [{ name: "Example" }, { name: "Test" }, { name: "What" }, { name: "No" }, { name: "Benefit" }, { name: "Oranges" }, { name: "Artemis" }, { name: "Another" }]; + public options = (query:string) => { + var regex:RegExp = new RegExp(query, 'i'); + return new Promise((resolve, reject) => { + resolve(this._options.filter((item) => item.name.match(regex))); + }); + }; +} + @Component({ selector: 'select-example-multiple', template: new SelectPage().exampleMultipleTemplate @@ -258,4 +272,4 @@ export class SelectExampleTemplateSearch { public selectedOption = this.options[5]; } -export const SelectPageComponents:Array = [SelectPage, SelectExampleStandard, SelectExampleOptions, SelectExampleSearch, SelectExampleMultiple, SelectExampleMultipleSearch, SelectExampleTemplateSearch]; +export const SelectPageComponents:Array = [SelectPage, SelectExampleStandard, SelectExampleOptions, SelectExampleSearch, SelectExampleLookupSearch, SelectExampleMultiple, SelectExampleMultipleSearch, SelectExampleTemplateSearch]; From 0729ad2a9dc8c8a39a853fc10b0e01b1d1c077fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Damjan=20Cilens=CC=8Cek?= Date: Sun, 26 Mar 2017 15:56:22 +0200 Subject: [PATCH 12/25] Selected option lookup for search select --- components/search/search.service.ts | 20 ++++++++++++--- components/search/search.ts | 2 +- components/select/select-base.ts | 7 +++++- components/select/select.ts | 18 +++++++++++--- demo/src/app/pages/select/select.page.ts | 31 ++++++++++++++++++------ 5 files changed, 61 insertions(+), 17 deletions(-) diff --git a/components/search/search.service.ts b/components/search/search.service.ts index 3342efb46..4a7ce0ebd 100644 --- a/components/search/search.service.ts +++ b/components/search/search.service.ts @@ -1,7 +1,7 @@ import {readValue} from '../util/util'; // Define useful types to avoid any. -export type LookupFn = (query:string) => Promise +export type LookupFn = (query:any, initial?:boolean) => Promise type CachedArray = { [query:string]:T[] }; // T extends JavascriptObject so we can do a recursive search on the object. @@ -9,7 +9,9 @@ export class SearchService { // Stores the available options. private _options:T[]; // Converts a query string into an array of options. Must be a function returning a promise. - private _optionsLookup:LookupFn; + private _optionsLookup:LookupFn; + // Lookup for option or options based on their valueField + private _selectedLookup:LookupFn; // Field that options are searched & displayed on. private _optionsField:string; @@ -29,13 +31,23 @@ export class SearchService { return this._optionsLookup; } - public set optionsLookup(lookupFn:LookupFn) { - this._optionsLookup = lookupFn; + public set optionsLookup(lookupFn:LookupFn) { + this._optionsLookup = (query) => lookupFn(query); + if (lookupFn.length == 2) { + this._selectedLookup = (query) => lookupFn(query, true); + } + else { + this._selectedLookup = null; + } // As before, cannot use local & remote options simultaneously. this._options = []; this.reset(); } + public get selectedLookup() { + return this._selectedLookup; + } + public get optionsField() { return this._optionsField } diff --git a/components/search/search.ts b/components/search/search.ts index 24ee0321c..0a2e853fa 100644 --- a/components/search/search.ts +++ b/components/search/search.ts @@ -76,7 +76,7 @@ export class SuiSearch implements AfterViewInit { // Sets local or remote options by determining whether a function is passed. @Input() - public set options(options:T[] | LookupFn) { + public set options(options:T[] | LookupFn) { if (typeof(options) == "function") { this.searchService.optionsLookup = options; return; diff --git a/components/select/select-base.ts b/components/select/select-base.ts index f71a02da2..74b16a7a5 100644 --- a/components/select/select-base.ts +++ b/components/select/select-base.ts @@ -96,11 +96,11 @@ export abstract class SuiSelectBase implements AfterContentInit { } public set query(query:string) { + this.queryUpdateHook(); this.updateQuery(query); } protected updateQuery(query:string) { - this.queryUpdateHook(); // Update the query then open the dropdown, as after keyboard input it should always be open. this.searchService.updateQuery(query, () => this.dropdownService.setOpenState(true)); @@ -188,6 +188,11 @@ export abstract class SuiSelectBase implements AfterContentInit { throw new Error("Not implemented"); } + protected findOption(options:T[], value:U) { + // Tries to find an option in options array + return options.find(o => value == this.valueGetter(o)); + } + @HostListener("click", ['$event']) public onClick(e:MouseEvent) { e.stopPropagation(); diff --git a/components/select/select.ts b/components/select/select.ts index 42a662077..cbda384f8 100644 --- a/components/select/select.ts +++ b/components/select/select.ts @@ -43,7 +43,7 @@ export class SuiSelect extends SuiSelectBase { protected optionsUpdateHook() { if (this._writtenOption && this.options.length > 0) { // If there was an value written by ngModel before the options had been loaded, this runs to fix it. - this.selectedOption = this.options.find(o => this._writtenOption == this.valueGetter(o)); + this.selectedOption = this.findOption(this.options, this._writtenOption); if (this.selectedOption) { this._writtenOption = null; this.drawSelectedOption(); @@ -87,11 +87,21 @@ export class SuiSelect extends SuiSelectBase { if (value != null) { if (this.options.length > 0) { // If the options have already been loaded, we can immediately match the ngModel value to an option. - this.selectedOption = this.options.find(o => value == this.valueGetter(o)); + this.selectedOption = this.findOption(this.options, value); } if (!this.selectedOption) { - // Otherwise, cache the written value for when options are set. - this._writtenOption = value; + if (this.searchService.selectedLookup) { + // If there's a selected lookup function, query it + this.searchService.selectedLookup(value) + .then((results) => { + this.selectedOption = this.findOption(results, value) + this.drawSelectedOption(); + }); + } + else { + // Otherwise, cache the written value for when options are set. + this._writtenOption = value; + } } } diff --git a/demo/src/app/pages/select/select.page.ts b/demo/src/app/pages/select/select.page.ts index 3b6d2dea6..f6b906a2f 100644 --- a/demo/src/app/pages/select/select.page.ts +++ b/demo/src/app/pages/select/select.page.ts @@ -158,6 +158,15 @@ export class SelectPage {

Currently selected: {{ selectedOption | json }}

+`; + public exampleSearchLookupTemplate:string = ` +

You can also use the keyboard to navigate.

+ + + +
+

Currently selected: {{ selectedOption | json }}

+
`; public exampleMultipleTemplate:string = ` @@ -233,16 +242,24 @@ export class SelectExampleSearch { @Component({ selector: 'select-example-search-lookup', - template: new SelectPage().exampleSearchTemplate + template: new SelectPage().exampleSearchLookupTemplate }) export class SelectExampleLookupSearch { - private _options:Array = [{ name: "Example" }, { name: "Test" }, { name: "What" }, { name: "No" }, { name: "Benefit" }, { name: "Oranges" }, { name: "Artemis" }, { name: "Another" }]; - public options = (query:string) => { - var regex:RegExp = new RegExp(query, 'i'); - return new Promise((resolve, reject) => { - resolve(this._options.filter((item) => item.name.match(regex))); - }); + private _options:Array = [{ id: 1, name: "Example" }, { id: 2, name: "Test" }, { id: 3, name: "What" }, { id: 4, name: "No" }, { id: 5, name: "Benefit" }, { id: 6, name: "Oranges" }, { id: 7, name: "Artemis" }, { id: 8, name: "Another" }]; + public options = (query:string, initial:boolean = false) => { + if (initial) { + return new Promise((resolve, reject) => { + resolve(this._options.filter((item) => item.id == query)); + }); + } + else { + var regex:RegExp = new RegExp(query, 'i'); + return new Promise((resolve, reject) => { + resolve(this._options.filter((item) => item.name.match(regex))); + }); + } }; + public selectedOption = this._options[0]['id']; } @Component({ From 5f48eab101a35c0e770591cbe957cd220a124c38 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Damjan=20Cilens=CC=8Cek?= Date: Sun, 26 Mar 2017 23:07:23 +0200 Subject: [PATCH 13/25] Initial lookup moved to select's writeWalue --- components/search/search.service.ts | 20 ++++---------------- components/select/select.ts | 7 ++++--- demo/src/app/pages/select/select.page.ts | 4 ++-- 3 files changed, 10 insertions(+), 21 deletions(-) diff --git a/components/search/search.service.ts b/components/search/search.service.ts index 4a7ce0ebd..bb6ab0d5c 100644 --- a/components/search/search.service.ts +++ b/components/search/search.service.ts @@ -1,7 +1,7 @@ import {readValue} from '../util/util'; // Define useful types to avoid any. -export type LookupFn = (query:any, initial?:boolean) => Promise +export type LookupFn = (query:string, initial?:U) => Promise type CachedArray = { [query:string]:T[] }; // T extends JavascriptObject so we can do a recursive search on the object. @@ -9,9 +9,7 @@ export class SearchService { // Stores the available options. private _options:T[]; // Converts a query string into an array of options. Must be a function returning a promise. - private _optionsLookup:LookupFn; - // Lookup for option or options based on their valueField - private _selectedLookup:LookupFn; + private _optionsLookup:LookupFn; // Field that options are searched & displayed on. private _optionsField:string; @@ -31,23 +29,13 @@ export class SearchService { return this._optionsLookup; } - public set optionsLookup(lookupFn:LookupFn) { - this._optionsLookup = (query) => lookupFn(query); - if (lookupFn.length == 2) { - this._selectedLookup = (query) => lookupFn(query, true); - } - else { - this._selectedLookup = null; - } + public set optionsLookup(lookupFn:LookupFn) { + this._optionsLookup = lookupFn; // As before, cannot use local & remote options simultaneously. this._options = []; this.reset(); } - public get selectedLookup() { - return this._selectedLookup; - } - public get optionsField() { return this._optionsField } diff --git a/components/select/select.ts b/components/select/select.ts index cbda384f8..a16dc9315 100644 --- a/components/select/select.ts +++ b/components/select/select.ts @@ -90,10 +90,11 @@ export class SuiSelect extends SuiSelectBase { this.selectedOption = this.findOption(this.options, value); } if (!this.selectedOption) { - if (this.searchService.selectedLookup) { + let optionsLookup = this.searchService.optionsLookup; + if (optionsLookup && optionsLookup.length == 2) { // If there's a selected lookup function, query it - this.searchService.selectedLookup(value) - .then((results) => { + optionsLookup(this.searchService.query, value) + .then(results => { this.selectedOption = this.findOption(results, value) this.drawSelectedOption(); }); diff --git a/demo/src/app/pages/select/select.page.ts b/demo/src/app/pages/select/select.page.ts index f6b906a2f..94c502d91 100644 --- a/demo/src/app/pages/select/select.page.ts +++ b/demo/src/app/pages/select/select.page.ts @@ -246,10 +246,10 @@ export class SelectExampleSearch { }) export class SelectExampleLookupSearch { private _options:Array = [{ id: 1, name: "Example" }, { id: 2, name: "Test" }, { id: 3, name: "What" }, { id: 4, name: "No" }, { id: 5, name: "Benefit" }, { id: 6, name: "Oranges" }, { id: 7, name: "Artemis" }, { id: 8, name: "Another" }]; - public options = (query:string, initial:boolean = false) => { + public options = (query:string, initial:any = false) => { if (initial) { return new Promise((resolve, reject) => { - resolve(this._options.filter((item) => item.id == query)); + resolve(this._options.filter((item) => item.id == initial)); }); } else { From 6eff0eccf706c2147bee05e3179eaec95b736169 Mon Sep 17 00:00:00 2001 From: Ed Carroll Date: Mon, 27 Mar 2017 00:46:07 +0100 Subject: [PATCH 14/25] Minor cleanups --- components/search/search.service.ts | 17 ++++++++++------- components/search/search.ts | 8 ++++---- components/select/select-base.ts | 18 +++++++----------- components/select/select.ts | 12 ++++++------ package.json | 10 +++++----- 5 files changed, 32 insertions(+), 33 deletions(-) diff --git a/components/search/search.service.ts b/components/search/search.service.ts index bb6ab0d5c..60ac35fd2 100644 --- a/components/search/search.service.ts +++ b/components/search/search.service.ts @@ -5,11 +5,11 @@ export type LookupFn = (query:string, initial?:U) => Promise type CachedArray = { [query:string]:T[] }; // T extends JavascriptObject so we can do a recursive search on the object. -export class SearchService { +export class SearchService { // Stores the available options. private _options:T[]; // Converts a query string into an array of options. Must be a function returning a promise. - private _optionsLookup:LookupFn; + private _optionsLookup:LookupFn; // Field that options are searched & displayed on. private _optionsField:string; @@ -29,13 +29,19 @@ export class SearchService { return this._optionsLookup; } - public set optionsLookup(lookupFn:LookupFn) { + public set optionsLookup(lookupFn:LookupFn) { this._optionsLookup = lookupFn; // As before, cannot use local & remote options simultaneously. this._options = []; this.reset(); } + public get selectedLookup() { + if (this.optionsLookup && this.optionsLookup.length == 2) { + return this.optionsLookup; + } + } + public get optionsField() { return this._optionsField } @@ -170,12 +176,9 @@ export class SearchService { // Resets the search back to a pristine state. private reset() { - this._query = ""; this._results = []; - if (this.allowEmptyQuery) { - this._results = this._options; - } this._resultsCache = {}; this._isSearching = false; + this.updateQuery(""); } } \ No newline at end of file diff --git a/components/search/search.ts b/components/search/search.ts index 0a2e853fa..b9082808a 100644 --- a/components/search/search.ts +++ b/components/search/search.ts @@ -38,7 +38,7 @@ import {PositioningService, PositioningPlacement} from '../util/positioning.serv }) export class SuiSearch implements AfterViewInit { public dropdownService:DropdownService; - public searchService:SearchService; + public searchService:SearchService; @ViewChild(SuiDropdownMenu) private _menu:SuiDropdownMenu; @@ -76,8 +76,8 @@ export class SuiSearch implements AfterViewInit { // Sets local or remote options by determining whether a function is passed. @Input() - public set options(options:T[] | LookupFn) { - if (typeof(options) == "function") { + public set options(options:T[] | LookupFn) { + if (typeof options == "function") { this.searchService.optionsLookup = options; return; } @@ -117,7 +117,7 @@ export class SuiSearch implements AfterViewInit { constructor(private _element:ElementRef) { this.dropdownService = new DropdownService(); - this.searchService = new SearchService(); + this.searchService = new SearchService(); this._searchClasses = true; this.hasIcon = true; diff --git a/components/select/select-base.ts b/components/select/select-base.ts index 74b16a7a5..3828666f3 100644 --- a/components/select/select-base.ts +++ b/components/select/select-base.ts @@ -10,7 +10,7 @@ import {Subscription} from 'rxjs'; // We use generic type T to specify the type of the options we are working with, and U to specify the type of the property of the option used as the value. export abstract class SuiSelectBase implements AfterContentInit { public dropdownService:DropdownService; - public searchService:SearchService; + public searchService:SearchService; @ViewChild(SuiDropdownMenu) protected _menu:SuiDropdownMenu; @@ -70,17 +70,13 @@ export abstract class SuiSelectBase implements AfterContentInit { } public set options(options:T[]) { - if (typeof (options) == "function") { + if (typeof options == "function") { this.searchService.optionsLookup = options; - let subscription = this.dropdownService.isOpenChange.subscribe((value:boolean) => { - if (value) { - subscription.unsubscribe(); - this.updateQuery(this.query); - } - }); - return; } - this.searchService.options = options; + else { + this.searchService.options = options; + } + this.optionsUpdateHook(); } @@ -140,7 +136,7 @@ export abstract class SuiSelectBase implements AfterContentInit { constructor(private _element:ElementRef, private _renderer:Renderer) { this.dropdownService = new DropdownService(); // We do want an empty query to return all results. - this.searchService = new SearchService(true); + this.searchService = new SearchService(true); this.isSearchable = false; this.noResultsMessage = "No results"; diff --git a/components/select/select.ts b/components/select/select.ts index a16dc9315..7e0e48481 100644 --- a/components/select/select.ts +++ b/components/select/select.ts @@ -90,14 +90,14 @@ export class SuiSelect extends SuiSelectBase { this.selectedOption = this.findOption(this.options, value); } if (!this.selectedOption) { - let optionsLookup = this.searchService.optionsLookup; - if (optionsLookup && optionsLookup.length == 2) { - // If there's a selected lookup function, query it - optionsLookup(this.searchService.query, value) - .then(results => { - this.selectedOption = this.findOption(results, value) + if (this.searchService.selectedLookup) { + // If the search service has a selected lookup function, make use of that to load the initial value. + this.searchService.selectedLookup(undefined, value) + .then(r => { + this.selectedOption = this.findOption(r, value); this.drawSelectedOption(); }); + return; } else { // Otherwise, cache the written value for when options are set. diff --git a/package.json b/package.json index ddc3c8697..b70e31013 100644 --- a/package.json +++ b/package.json @@ -46,11 +46,11 @@ "zone.js": "^0.7.0" }, "devDependencies": { - "@angular/cli": "1.0.0-rc.2", - "@angular/compiler": "^2.4.1", - "@angular/compiler-cli": "^2.4.1", - "@angular/platform-browser-dynamic": "^2.4.0", - "@angular/router": "^3.4.0", + "@angular/cli": "1.0.0", + "@angular/compiler": ">=2.4.1", + "@angular/compiler-cli": ">=2.4.1", + "@angular/platform-browser-dynamic": ">=2.4.0", + "@angular/router": ">=3.4.0", "@types/prismjs": "~1.4.18", "@types/protractor": "~4.0.0", "@types/requirejs": "~2.1.28", From 65d527e6275474432fd98ee9c11330714c25381c Mon Sep 17 00:00:00 2001 From: Ed Carroll Date: Mon, 27 Mar 2017 22:11:57 +0100 Subject: [PATCH 15/25] Updated to Angular 4 Should close #49 --- ng2-semantic-ui.ts | 1 - package.json | 30 ++++++++++++++---------------- tsconfig.json | 4 ++-- 3 files changed, 16 insertions(+), 19 deletions(-) delete mode 100644 ng2-semantic-ui.ts diff --git a/ng2-semantic-ui.ts b/ng2-semantic-ui.ts deleted file mode 100644 index e2161b405..000000000 --- a/ng2-semantic-ui.ts +++ /dev/null @@ -1 +0,0 @@ -export * from "./components"; \ No newline at end of file diff --git a/package.json b/package.json index ddc3c8697..061075580 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,7 @@ "main": "ng2-semantic-ui.dist.js", "module": "index.js", "typings": "index.d.ts", - "version": "0.5.5", + "version": "0.6.0", "description": "Angular 2 Semantic UI Components", "repository": { "type": "git", @@ -32,25 +32,23 @@ "build": "npm run compile && npm run package" }, "dependencies": { - "@angular/common": ">=2.4.1", - "@angular/core": ">=2.4.1", - "@angular/forms": ">=2.4.1", - "@angular/http": ">=2.4.1", - "@angular/platform-browser": ">=2.4.1", - "core-js": ">=2.4.1", + "@angular/common": "^4.0.0", + "@angular/core": "^4.0.0", + "@angular/forms": "^4.0.0", + "@angular/http": "^4.0.0", + "@angular/platform-browser": "^4.0.0", + "core-js": "^2.4.1", "element-closest": "^2.0.2", "popper.js": "^1.0.6", - "reflect-metadata": "^0.1.3", "rxjs": "^5.0.1", - "ts-helpers": "^1.1.1", - "zone.js": "^0.7.0" + "zone.js": "^0.8.4" }, "devDependencies": { - "@angular/cli": "1.0.0-rc.2", - "@angular/compiler": "^2.4.1", - "@angular/compiler-cli": "^2.4.1", - "@angular/platform-browser-dynamic": "^2.4.0", - "@angular/router": "^3.4.0", + "@angular/cli": "^1.0.0", + "@angular/compiler": "^4.0.0", + "@angular/compiler-cli": "^4.0.0", + "@angular/platform-browser-dynamic": "^4.0.0", + "@angular/router": "^4.0.0", "@types/prismjs": "~1.4.18", "@types/protractor": "~4.0.0", "@types/requirejs": "~2.1.28", @@ -69,6 +67,6 @@ "rollup-plugin-uglify": "~1.0.1", "ts-node": "~2.0.0", "tslint": "~4.3.1", - "typescript": "~2.0.5" + "typescript": "^2.1.6" } } diff --git a/tsconfig.json b/tsconfig.json index 1cfb92a6b..7015717b8 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -26,10 +26,10 @@ ] }, "files": [ - "index.ts", - "ng2-semantic-ui.ts" + "index.ts" ], "angularCompilerOptions": { + "annotateForClosureCompiler": true, "strictMetadataEmit": true } } From 545957bb15fc8e931ea29aaa15db7c15ed68f803 Mon Sep 17 00:00:00 2001 From: Ed Carroll Date: Tue, 28 Mar 2017 00:19:01 +0100 Subject: [PATCH 16/25] Updated github buttons on demo --- README.md | 2 +- .../components/page-title/page-title.component.html | 13 ++++++++++++- .../pages/getting-started/getting-started.page.html | 2 +- 3 files changed, 14 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 8deb26e58..8a3079ff2 100644 --- a/README.md +++ b/README.md @@ -44,7 +44,7 @@ Now you're good to go! ## Dependencies -* [Angular 2](https://angular.io) (>=2.0.0) +* [Angular 2](https://angular.io) (^4.0.0) * [Semantic UI CSS](http://semantic-ui.com/) (jQuery is **not** required) ## Components diff --git a/demo/src/app/components/page-title/page-title.component.html b/demo/src/app/components/page-title/page-title.component.html index f6d95bbe3..375180e7e 100644 --- a/demo/src/app/components/page-title/page-title.component.html +++ b/demo/src/app/components/page-title/page-title.component.html @@ -2,7 +2,18 @@

- +
+ + +

diff --git a/demo/src/app/pages/getting-started/getting-started.page.html b/demo/src/app/pages/getting-started/getting-started.page.html index fbe15fa20..b4fee3e92 100644 --- a/demo/src/app/pages/getting-started/getting-started.page.html +++ b/demo/src/app/pages/getting-started/getting-started.page.html @@ -29,7 +29,7 @@

Installation

Now you're good to go!

Dependencies

-
Angular 2 (>=2.0.0)
+
Angular 2 (^4.0.0)
Semantic UI CSS (jQuery is not required)
From a4c7f2237f1c0dfab25a59fa3ef8b4a36f21f9ef Mon Sep 17 00:00:00 2001 From: Ed Carroll Date: Tue, 28 Mar 2017 03:00:10 +0100 Subject: [PATCH 17/25] Made docs responsive --- angular-cli.json | 5 +- components/dropdown/dropdown-menu.ts | 6 +- demo/src/app/app.component.css | 76 +++++++++++++++++++ demo/src/app/app.component.html | 53 +++++-------- demo/src/app/app.component.ts | 21 ++++- .../app/components/demo-components.module.ts | 9 +++ .../github-buttons.component.html | 28 +++++++ .../github-buttons.component.ts | 10 +++ .../page-content/page-content.component.css | 23 ++++-- .../page-content/page-content.component.ts | 1 - .../page-title/page-title.component.css | 42 +++++----- .../page-title/page-title.component.html | 27 ++----- .../components/sidebar/sidebar.component.css | 9 +++ .../components/sidebar/sidebar.component.html | 31 ++++++++ .../components/sidebar/sidebar.component.ts | 29 +++++++ demo/src/{styles.css => css/code.css} | 37 --------- demo/src/css/styles.css | 3 + 17 files changed, 287 insertions(+), 123 deletions(-) create mode 100644 demo/src/app/app.component.css create mode 100644 demo/src/app/components/github-buttons/github-buttons.component.html create mode 100644 demo/src/app/components/github-buttons/github-buttons.component.ts create mode 100644 demo/src/app/components/sidebar/sidebar.component.css create mode 100644 demo/src/app/components/sidebar/sidebar.component.html create mode 100644 demo/src/app/components/sidebar/sidebar.component.ts rename demo/src/{styles.css => css/code.css} (85%) create mode 100644 demo/src/css/styles.css diff --git a/angular-cli.json b/angular-cli.json index 4c985940a..32ad12b03 100644 --- a/angular-cli.json +++ b/angular-cli.json @@ -16,7 +16,10 @@ "tsconfig": "tsconfig.json", "prefix": "demo", "mobile": false, - "styles": ["styles.css"], + "styles": [ + "css/styles.css", + "css/code.css" + ], "scripts": [], "environmentSource": "environments/environment.ts", "environments": { diff --git a/components/dropdown/dropdown-menu.ts b/components/dropdown/dropdown-menu.ts index 793432034..5ef7f5d55 100644 --- a/components/dropdown/dropdown-menu.ts +++ b/components/dropdown/dropdown-menu.ts @@ -6,6 +6,10 @@ import {KeyCode} from '../util/util'; // Polyfill for IE import "element-closest"; +interface AugmentedElement extends Element { + closest(selector:string):AugmentedElement; +} + @Directive({ // We must attach to every '.item' as Angular doesn't support > selectors. selector: '.item' @@ -139,7 +143,7 @@ export class SuiDropdownMenu extends SuiTransition implements AfterContentInit { e.stopPropagation(); if (this._service.autoCloseMode == DropdownAutoCloseType.ItemClick) { - const target = e.target as Element; + const target = e.target as AugmentedElement; if (this.element.nativeElement.contains(target.closest(".item")) && !/input|textarea/i.test(target.tagName)) { // Once an item is selected, we can close the entire dropdown. this._service.setOpenState(false, true); diff --git a/demo/src/app/app.component.css b/demo/src/app/app.component.css new file mode 100644 index 000000000..d9cd46a54 --- /dev/null +++ b/demo/src/app/app.component.css @@ -0,0 +1,76 @@ +:host { + position: fixed; + top: 0; + left: 0; + bottom: 0; + right: 0; +} + +.pusher { + height: 100%; +} + +.pusher > .full.height { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-flex-direction: row; + -ms-flex-direction: row; + flex-direction: row; + + height: 100%; + overflow-y: auto; + overflow-x: hidden; +} + +.pusher > .full.height { + background-color: #FFFFFF; +} + +.full.height > .toc { + position: relative; + z-index: 1; + background-color: #1b1c1d; + width: 250px; + -webkit-box-flex: 0; + -webkit-flex: 0 0 auto; + -ms-flex: 0 0 auto; + flex: 0 0 auto; +} + +.full.height > .toc .ui.menu { + position: fixed; + top: 0; + bottom: 0; + border-radius: 0; + border-width: 0 1px 0 0; + box-shadow: none; + margin: 0; + width: inherit; + overflow: hidden; + will-change: transform; +} + +.article { + -webkit-box-flex: 1; + -webkit-flex: 1 1 auto; + -ms-flex: 1 1 auto; + flex: 1 1 auto; + min-width: 0px; +} + +.article > .ui.top.attached.menu { + display: none; + border-radius: 0; +} + +@media only screen and (max-width: 1200px) { + .article > .ui.top.attached.menu { + display: flex; + } + + .toc { + display: none; + } +} \ No newline at end of file diff --git a/demo/src/app/app.component.html b/demo/src/app/app.component.html index 5a9c8cd3b..1a70c0a8e 100644 --- a/demo/src/app/app.component.html +++ b/demo/src/app/app.component.html @@ -1,38 +1,23 @@ -