From 8896b08ecb3bbc9857009227729aa3a316dbf0e1 Mon Sep 17 00:00:00 2001 From: Aliaxei Terentiev Date: Fri, 11 Nov 2016 17:11:56 -0800 Subject: [PATCH] Logic implemented --- .../termSetRequester/common/SPEntities.ts | 30 - .../data-helpers/DataHelperBase.ts | 15 - .../data-helpers/DataHelperMock.ts | 38 - .../data-helpers/DataHelperSP.ts | 83 --- samples/knockout-metadata/typings/SP/SP.d.ts | 29 - .../.editorconfig | 0 .../.gitattributes | 0 .../.gitignore | 0 .../.npmignore | 0 .../.vscode/settings.json | 2 + .../.vscode/tasks.json | 0 .../.yo-rc.json | 0 .../README.md | 0 .../config/config.json | 2 +- .../config/deploy-azure-storage.json | 0 .../config/package-solution.json | 0 .../config/prepare-deploy.json | 0 .../config/serve.json | 0 .../config/tslint.json | 0 .../config/write-manifests.json | 0 .../gulpfile.js | 0 .../knockout-metadata.njsproj | 0 .../package.json | 1 + .../src/tests.js | 0 .../ITermSetRequesterWebPartProps.ts | 0 .../TermSetRequester.module.scss | 0 .../TermSetRequesterWebPart.manifest.json | 0 .../TermSetRequesterWebPart.ts | 17 +- .../termSetRequester/common/SPEntities.ts | 99 +++ .../controls/TaxonomyControl.ts | 47 ++ .../controls/TaxonomyControlModel.ts | 66 ++ .../controls/TaxonomyControlView.ts | 60 ++ .../controls/TaxonomyControlViewModel.ts | 313 +++++++++ .../data-helpers/DataHelperBase.ts | 32 + .../data-helpers/DataHelperMock.ts | 185 +++++ .../data-helpers/DataHelperSP.ts | 663 ++++++++++++++++++ .../data-helpers/DataHelpersFactory.ts | 0 .../webparts/termSetRequester/loc/en-us.js | 0 .../termSetRequester/loc/mystrings.d.ts | 0 .../tests/TermSetRequester.test.ts | 0 .../tsconfig.json | 0 .../typings/@ms/odsp-webpack.d.ts | 0 .../typings/@ms/odsp.d.ts | 0 samples/knockout-taxonomy/typings/SP/SP.d.ts | 207 ++++++ .../assertion-error/assertion-error.d.ts | 0 .../typings/chai/chai.d.ts | 0 .../typings/combokeys/combokeys.d.ts | 0 .../es6-collections/es6-collections.d.ts | 0 .../typings/es6-promise/es6-promise.d.ts | 0 .../typings/knockout/knockout.d.ts | 0 .../typings/lodash/lodash.d.ts | 0 .../typings/mocha/mocha.d.ts | 0 .../typings/node/node.d.ts | 0 .../react/react-addons-shallow-compare.d.ts | 0 .../react/react-addons-test-utils.d.ts | 0 .../typings/react/react-addons-update.d.ts | 0 .../typings/react/react-dom.d.ts | 0 .../typings/react/react.d.ts | 0 .../typings/systemjs/systemjs.d.ts | 0 .../typings/tsd.d.ts | 1 + .../typings/whatwg-fetch/whatwg-fetch.d.ts | 0 61 files changed, 1684 insertions(+), 206 deletions(-) delete mode 100644 samples/knockout-metadata/src/webparts/termSetRequester/common/SPEntities.ts delete mode 100644 samples/knockout-metadata/src/webparts/termSetRequester/data-helpers/DataHelperBase.ts delete mode 100644 samples/knockout-metadata/src/webparts/termSetRequester/data-helpers/DataHelperMock.ts delete mode 100644 samples/knockout-metadata/src/webparts/termSetRequester/data-helpers/DataHelperSP.ts delete mode 100644 samples/knockout-metadata/typings/SP/SP.d.ts rename samples/{knockout-metadata => knockout-taxonomy}/.editorconfig (100%) rename samples/{knockout-metadata => knockout-taxonomy}/.gitattributes (100%) rename samples/{knockout-metadata => knockout-taxonomy}/.gitignore (100%) rename samples/{knockout-metadata => knockout-taxonomy}/.npmignore (100%) rename samples/{knockout-metadata => knockout-taxonomy}/.vscode/settings.json (91%) rename samples/{knockout-metadata => knockout-taxonomy}/.vscode/tasks.json (100%) rename samples/{knockout-metadata => knockout-taxonomy}/.yo-rc.json (100%) rename samples/{knockout-metadata => knockout-taxonomy}/README.md (100%) rename samples/{knockout-metadata => knockout-taxonomy}/config/config.json (98%) rename samples/{knockout-metadata => knockout-taxonomy}/config/deploy-azure-storage.json (100%) rename samples/{knockout-metadata => knockout-taxonomy}/config/package-solution.json (100%) rename samples/{knockout-metadata => knockout-taxonomy}/config/prepare-deploy.json (100%) rename samples/{knockout-metadata => knockout-taxonomy}/config/serve.json (100%) rename samples/{knockout-metadata => knockout-taxonomy}/config/tslint.json (100%) rename samples/{knockout-metadata => knockout-taxonomy}/config/write-manifests.json (100%) rename samples/{knockout-metadata => knockout-taxonomy}/gulpfile.js (100%) rename samples/{knockout-metadata => knockout-taxonomy}/knockout-metadata.njsproj (100%) rename samples/{knockout-metadata => knockout-taxonomy}/package.json (92%) rename samples/{knockout-metadata => knockout-taxonomy}/src/tests.js (100%) rename samples/{knockout-metadata => knockout-taxonomy}/src/webparts/termSetRequester/ITermSetRequesterWebPartProps.ts (100%) rename samples/{knockout-metadata => knockout-taxonomy}/src/webparts/termSetRequester/TermSetRequester.module.scss (100%) rename samples/{knockout-metadata => knockout-taxonomy}/src/webparts/termSetRequester/TermSetRequesterWebPart.manifest.json (100%) rename samples/{knockout-metadata => knockout-taxonomy}/src/webparts/termSetRequester/TermSetRequesterWebPart.ts (63%) create mode 100644 samples/knockout-taxonomy/src/webparts/termSetRequester/common/SPEntities.ts create mode 100644 samples/knockout-taxonomy/src/webparts/termSetRequester/controls/TaxonomyControl.ts create mode 100644 samples/knockout-taxonomy/src/webparts/termSetRequester/controls/TaxonomyControlModel.ts create mode 100644 samples/knockout-taxonomy/src/webparts/termSetRequester/controls/TaxonomyControlView.ts create mode 100644 samples/knockout-taxonomy/src/webparts/termSetRequester/controls/TaxonomyControlViewModel.ts create mode 100644 samples/knockout-taxonomy/src/webparts/termSetRequester/data-helpers/DataHelperBase.ts create mode 100644 samples/knockout-taxonomy/src/webparts/termSetRequester/data-helpers/DataHelperMock.ts create mode 100644 samples/knockout-taxonomy/src/webparts/termSetRequester/data-helpers/DataHelperSP.ts rename samples/{knockout-metadata => knockout-taxonomy}/src/webparts/termSetRequester/data-helpers/DataHelpersFactory.ts (100%) rename samples/{knockout-metadata => knockout-taxonomy}/src/webparts/termSetRequester/loc/en-us.js (100%) rename samples/{knockout-metadata => knockout-taxonomy}/src/webparts/termSetRequester/loc/mystrings.d.ts (100%) rename samples/{knockout-metadata => knockout-taxonomy}/src/webparts/termSetRequester/tests/TermSetRequester.test.ts (100%) rename samples/{knockout-metadata => knockout-taxonomy}/tsconfig.json (100%) rename samples/{knockout-metadata => knockout-taxonomy}/typings/@ms/odsp-webpack.d.ts (100%) rename samples/{knockout-metadata => knockout-taxonomy}/typings/@ms/odsp.d.ts (100%) create mode 100644 samples/knockout-taxonomy/typings/SP/SP.d.ts rename samples/{knockout-metadata => knockout-taxonomy}/typings/assertion-error/assertion-error.d.ts (100%) rename samples/{knockout-metadata => knockout-taxonomy}/typings/chai/chai.d.ts (100%) rename samples/{knockout-metadata => knockout-taxonomy}/typings/combokeys/combokeys.d.ts (100%) rename samples/{knockout-metadata => knockout-taxonomy}/typings/es6-collections/es6-collections.d.ts (100%) rename samples/{knockout-metadata => knockout-taxonomy}/typings/es6-promise/es6-promise.d.ts (100%) rename samples/{knockout-metadata => knockout-taxonomy}/typings/knockout/knockout.d.ts (100%) rename samples/{knockout-metadata => knockout-taxonomy}/typings/lodash/lodash.d.ts (100%) rename samples/{knockout-metadata => knockout-taxonomy}/typings/mocha/mocha.d.ts (100%) rename samples/{knockout-metadata => knockout-taxonomy}/typings/node/node.d.ts (100%) rename samples/{knockout-metadata => knockout-taxonomy}/typings/react/react-addons-shallow-compare.d.ts (100%) rename samples/{knockout-metadata => knockout-taxonomy}/typings/react/react-addons-test-utils.d.ts (100%) rename samples/{knockout-metadata => knockout-taxonomy}/typings/react/react-addons-update.d.ts (100%) rename samples/{knockout-metadata => knockout-taxonomy}/typings/react/react-dom.d.ts (100%) rename samples/{knockout-metadata => knockout-taxonomy}/typings/react/react.d.ts (100%) rename samples/{knockout-metadata => knockout-taxonomy}/typings/systemjs/systemjs.d.ts (100%) rename samples/{knockout-metadata => knockout-taxonomy}/typings/tsd.d.ts (96%) rename samples/{knockout-metadata => knockout-taxonomy}/typings/whatwg-fetch/whatwg-fetch.d.ts (100%) diff --git a/samples/knockout-metadata/src/webparts/termSetRequester/common/SPEntities.ts b/samples/knockout-metadata/src/webparts/termSetRequester/common/SPEntities.ts deleted file mode 100644 index 5749bc886..000000000 --- a/samples/knockout-metadata/src/webparts/termSetRequester/common/SPEntities.ts +++ /dev/null @@ -1,30 +0,0 @@ -/** - * Represents SharePoint View object - */ -export interface ISPView { - Title: string; - Id: string; - ListId: string; -} - -/** - * Represents SharePoint List object - */ -export interface ISPList { - Title: string; - Id: string; -} - -/** - * Represents SharePoint REST service response for /_api/web/lists service call - */ -export interface ISPLists { - value: ISPList[]; -} - -/** - * Represents SharePoint REST service response for /_api/web/lists('id')/views service call - */ -export interface ISPViews { - value: ISPView[]; -} \ No newline at end of file diff --git a/samples/knockout-metadata/src/webparts/termSetRequester/data-helpers/DataHelperBase.ts b/samples/knockout-metadata/src/webparts/termSetRequester/data-helpers/DataHelperBase.ts deleted file mode 100644 index 70d40be59..000000000 --- a/samples/knockout-metadata/src/webparts/termSetRequester/data-helpers/DataHelperBase.ts +++ /dev/null @@ -1,15 +0,0 @@ -import * as SP from '../typings/SP'; - -/** - * Data Helpers interface - */ -export interface IDataHelper { - /** - * API to get lists from the source - */ - getLists(): Promise; - /** - * API to get views from the source - */ - getViews(listId: string): Promise; -} \ No newline at end of file diff --git a/samples/knockout-metadata/src/webparts/termSetRequester/data-helpers/DataHelperMock.ts b/samples/knockout-metadata/src/webparts/termSetRequester/data-helpers/DataHelperMock.ts deleted file mode 100644 index f48674875..000000000 --- a/samples/knockout-metadata/src/webparts/termSetRequester/data-helpers/DataHelperMock.ts +++ /dev/null @@ -1,38 +0,0 @@ -import { ISPList, ISPView } from '../common/SPEntities'; -import { IDataHelper } from './DataHelperBase'; - -/** - * MOCK data helper. Gets data from hardcoded values - */ -export class DataHelperMock implements IDataHelper { - /** - * hardcoded collection of lists - */ - private static _lists: ISPList[] = [{ Title: 'Test 1', Id: '1' }, { Title: 'Test 2', Id: '2' }, { Title: 'Test 3', Id: '3' }]; - /** - * hardcoded collection of views - */ - private static _views: ISPView[] = [{ Title: 'All Items', Id: '1', ListId: '1' }, { Title: 'Demo', Id: '2', ListId: '1' }, { Title: 'All Items', Id: '1', ListId: '2' }, { Title: 'All Items', Id: '1', ListId: '3' }]; - - /** - * API to get lists from the source - */ - public getLists(): Promise { - return new Promise((resolve) => { - resolve(DataHelperMock._lists); // returning all the lists - }); - } - - /** - * API to get views from the source - */ - public getViews(listId: string): Promise { - return new Promise((resolve) => { - // filtering views based on list id - const result: ISPView[] = DataHelperMock._views.filter((value, index, array) => { - return value.ListId === listId; - }); - resolve(result); - }); - } -} \ No newline at end of file diff --git a/samples/knockout-metadata/src/webparts/termSetRequester/data-helpers/DataHelperSP.ts b/samples/knockout-metadata/src/webparts/termSetRequester/data-helpers/DataHelperSP.ts deleted file mode 100644 index dcc3e6373..000000000 --- a/samples/knockout-metadata/src/webparts/termSetRequester/data-helpers/DataHelperSP.ts +++ /dev/null @@ -1,83 +0,0 @@ -import { - IWebPartContext -} from '@microsoft/sp-webpart-base'; -import { ISPList, ISPView, ISPLists, ISPViews } from '../common/SPEntities'; -import { IDataHelper } from './DataHelperBase'; - -/** - * List with views interface - */ -interface ISPListWithViews extends ISPList { - /** - * List Views - */ - Views: ISPView[]; -} - -/** - * SharePoint Data Helper class. - * Gets information from current web - */ -export class DataHelperSP implements IDataHelper { - /** - * Web part context - */ - public context: IWebPartContext; - - /** - * Loaded lists - */ - private _lists: ISPListWithViews[]; - - /** - * ctor - */ - public constructor(_context: IWebPartContext) { - this.context = _context; - } - - /** - * API to get lists from the source - */ - public getLists(): Promise { - return this.context.httpClient.get(this.context.pageContext.web.absoluteUrl + `/_api/web/lists?$filter=Hidden eq false`) // sending the request to SharePoint REST API - .then((response: Response) => { // httpClient.get method returns a response object where json method creates a Promise of getting result - return response.json(); - }).then((response: ISPLists) => { // response is an ISPLists object - return response.value; - }); - } - - /** - * API to get views from the source - */ - public getViews(listId: string): Promise { - if (listId && listId == '-1' || listId == '0') - return new Promise((resolve) => { - resolve(new Array()); - }); - - // - // trying to get views from cache - // - const lists: ISPListWithViews[] = this._lists && this._lists.length && this._lists.filter((value, index, array) => { return value.Id === listId; }); - - if (lists && lists.length) { - return new Promise((resolve) => { - resolve(lists[0].Views); - }); - } - else { - return this.context.httpClient.get(this.context.pageContext.web.absoluteUrl + '/_api/web/lists(\'' + listId + '\')/views') // requesting views from SharePoint REST API - .then((response: Response) => { // httpClient.get method returns a response object where json method creates a Promise of getting result - return response.json(); - }).then((response: ISPViews) => { // response is an ISPViews object - var views = response.value; - if (!this._lists || !this._lists.length) - this._lists = new Array(); - this._lists.push({ Id: listId, Title: '', Views: views }); - return views; - }); - } - } -} \ No newline at end of file diff --git a/samples/knockout-metadata/typings/SP/SP.d.ts b/samples/knockout-metadata/typings/SP/SP.d.ts deleted file mode 100644 index 7295f0ec3..000000000 --- a/samples/knockout-metadata/typings/SP/SP.d.ts +++ /dev/null @@ -1,29 +0,0 @@ -declare namespace SP { - export class ClientContext { - static get_current(): ClientContext; - load(obj: any, ...rest: string[]): void; - executeQueryAsyncCallback(success: (result: any) => void, error: (error: any) => void); - } - - namespace Taxonomy { - export class TaxonomySession { - static getTaxonomySession(spContext: ClientRect): TaxonomySession; - get_termStores(): ITermStoreCollection; - } - - export interface ITermStore { - get_groups(): ITermGroupCollection; - } - - export interface ITermStoreCollection { - get_item(index: number): ITermStore; - } - - export interface ITermGroup { - } - - export interface ITermGroupCollection { - get_item(index: number): ITermGroup; - } - } -} \ No newline at end of file diff --git a/samples/knockout-metadata/.editorconfig b/samples/knockout-taxonomy/.editorconfig similarity index 100% rename from samples/knockout-metadata/.editorconfig rename to samples/knockout-taxonomy/.editorconfig diff --git a/samples/knockout-metadata/.gitattributes b/samples/knockout-taxonomy/.gitattributes similarity index 100% rename from samples/knockout-metadata/.gitattributes rename to samples/knockout-taxonomy/.gitattributes diff --git a/samples/knockout-metadata/.gitignore b/samples/knockout-taxonomy/.gitignore similarity index 100% rename from samples/knockout-metadata/.gitignore rename to samples/knockout-taxonomy/.gitignore diff --git a/samples/knockout-metadata/.npmignore b/samples/knockout-taxonomy/.npmignore similarity index 100% rename from samples/knockout-metadata/.npmignore rename to samples/knockout-taxonomy/.npmignore diff --git a/samples/knockout-metadata/.vscode/settings.json b/samples/knockout-taxonomy/.vscode/settings.json similarity index 91% rename from samples/knockout-metadata/.vscode/settings.json rename to samples/knockout-taxonomy/.vscode/settings.json index ab46aaa4f..72890dfce 100644 --- a/samples/knockout-metadata/.vscode/settings.json +++ b/samples/knockout-taxonomy/.vscode/settings.json @@ -18,4 +18,6 @@ "lib": true, "temp": true } +, +"typescript.tsdk": "./node_modules/typescript/lib" } diff --git a/samples/knockout-metadata/.vscode/tasks.json b/samples/knockout-taxonomy/.vscode/tasks.json similarity index 100% rename from samples/knockout-metadata/.vscode/tasks.json rename to samples/knockout-taxonomy/.vscode/tasks.json diff --git a/samples/knockout-metadata/.yo-rc.json b/samples/knockout-taxonomy/.yo-rc.json similarity index 100% rename from samples/knockout-metadata/.yo-rc.json rename to samples/knockout-taxonomy/.yo-rc.json diff --git a/samples/knockout-metadata/README.md b/samples/knockout-taxonomy/README.md similarity index 100% rename from samples/knockout-metadata/README.md rename to samples/knockout-taxonomy/README.md diff --git a/samples/knockout-metadata/config/config.json b/samples/knockout-taxonomy/config/config.json similarity index 98% rename from samples/knockout-metadata/config/config.json rename to samples/knockout-taxonomy/config/config.json index e0c174980..b6a048198 100644 --- a/samples/knockout-metadata/config/config.json +++ b/samples/knockout-taxonomy/config/config.json @@ -15,7 +15,7 @@ "react": "node_modules/react/dist/react.min.js", "react-dom": "node_modules/react-dom/dist/react-dom.min.js", "react-dom/server": "node_modules/react-dom/dist/react-dom-server.min.js", - "knockout": "node_modules/knockout/build/output/knockout-latest.js" + "knockout": "node_modules/knockout/build/output/knockout-latest.debug.js" }, "localizedResources": { "termSetRequesterStrings": "webparts/termSetRequester/loc/{locale}.js" diff --git a/samples/knockout-metadata/config/deploy-azure-storage.json b/samples/knockout-taxonomy/config/deploy-azure-storage.json similarity index 100% rename from samples/knockout-metadata/config/deploy-azure-storage.json rename to samples/knockout-taxonomy/config/deploy-azure-storage.json diff --git a/samples/knockout-metadata/config/package-solution.json b/samples/knockout-taxonomy/config/package-solution.json similarity index 100% rename from samples/knockout-metadata/config/package-solution.json rename to samples/knockout-taxonomy/config/package-solution.json diff --git a/samples/knockout-metadata/config/prepare-deploy.json b/samples/knockout-taxonomy/config/prepare-deploy.json similarity index 100% rename from samples/knockout-metadata/config/prepare-deploy.json rename to samples/knockout-taxonomy/config/prepare-deploy.json diff --git a/samples/knockout-metadata/config/serve.json b/samples/knockout-taxonomy/config/serve.json similarity index 100% rename from samples/knockout-metadata/config/serve.json rename to samples/knockout-taxonomy/config/serve.json diff --git a/samples/knockout-metadata/config/tslint.json b/samples/knockout-taxonomy/config/tslint.json similarity index 100% rename from samples/knockout-metadata/config/tslint.json rename to samples/knockout-taxonomy/config/tslint.json diff --git a/samples/knockout-metadata/config/write-manifests.json b/samples/knockout-taxonomy/config/write-manifests.json similarity index 100% rename from samples/knockout-metadata/config/write-manifests.json rename to samples/knockout-taxonomy/config/write-manifests.json diff --git a/samples/knockout-metadata/gulpfile.js b/samples/knockout-taxonomy/gulpfile.js similarity index 100% rename from samples/knockout-metadata/gulpfile.js rename to samples/knockout-taxonomy/gulpfile.js diff --git a/samples/knockout-metadata/knockout-metadata.njsproj b/samples/knockout-taxonomy/knockout-metadata.njsproj similarity index 100% rename from samples/knockout-metadata/knockout-metadata.njsproj rename to samples/knockout-taxonomy/knockout-metadata.njsproj diff --git a/samples/knockout-metadata/package.json b/samples/knockout-taxonomy/package.json similarity index 92% rename from samples/knockout-metadata/package.json rename to samples/knockout-taxonomy/package.json index de8a0e3bd..cfcce120d 100644 --- a/samples/knockout-metadata/package.json +++ b/samples/knockout-taxonomy/package.json @@ -12,6 +12,7 @@ "devDependencies": { "@microsoft/sp-build-web": "~0.7.0", "@microsoft/sp-module-interfaces": "~0.4.0", + "@microsoft/sp-webpart-base": "^0.1.0", "@microsoft/sp-webpart-workbench": "~0.5.0", "gulp": "~3.9.1", "knockout": "^3.4.1" diff --git a/samples/knockout-metadata/src/tests.js b/samples/knockout-taxonomy/src/tests.js similarity index 100% rename from samples/knockout-metadata/src/tests.js rename to samples/knockout-taxonomy/src/tests.js diff --git a/samples/knockout-metadata/src/webparts/termSetRequester/ITermSetRequesterWebPartProps.ts b/samples/knockout-taxonomy/src/webparts/termSetRequester/ITermSetRequesterWebPartProps.ts similarity index 100% rename from samples/knockout-metadata/src/webparts/termSetRequester/ITermSetRequesterWebPartProps.ts rename to samples/knockout-taxonomy/src/webparts/termSetRequester/ITermSetRequesterWebPartProps.ts diff --git a/samples/knockout-metadata/src/webparts/termSetRequester/TermSetRequester.module.scss b/samples/knockout-taxonomy/src/webparts/termSetRequester/TermSetRequester.module.scss similarity index 100% rename from samples/knockout-metadata/src/webparts/termSetRequester/TermSetRequester.module.scss rename to samples/knockout-taxonomy/src/webparts/termSetRequester/TermSetRequester.module.scss diff --git a/samples/knockout-metadata/src/webparts/termSetRequester/TermSetRequesterWebPart.manifest.json b/samples/knockout-taxonomy/src/webparts/termSetRequester/TermSetRequesterWebPart.manifest.json similarity index 100% rename from samples/knockout-metadata/src/webparts/termSetRequester/TermSetRequesterWebPart.manifest.json rename to samples/knockout-taxonomy/src/webparts/termSetRequester/TermSetRequesterWebPart.manifest.json diff --git a/samples/knockout-metadata/src/webparts/termSetRequester/TermSetRequesterWebPart.ts b/samples/knockout-taxonomy/src/webparts/termSetRequester/TermSetRequesterWebPart.ts similarity index 63% rename from samples/knockout-metadata/src/webparts/termSetRequester/TermSetRequesterWebPart.ts rename to samples/knockout-taxonomy/src/webparts/termSetRequester/TermSetRequesterWebPart.ts index 9931f06cf..e83323d39 100644 --- a/samples/knockout-metadata/src/webparts/termSetRequester/TermSetRequesterWebPart.ts +++ b/samples/knockout-taxonomy/src/webparts/termSetRequester/TermSetRequesterWebPart.ts @@ -9,6 +9,8 @@ import styles from './TermSetRequester.module.scss'; import * as strings from 'termSetRequesterStrings'; import { ITermSetRequesterWebPartProps } from './ITermSetRequesterWebPartProps'; +import { TaxonomyControl } from './controls/TaxonomyControl'; + export default class TermSetRequesterWebPart extends BaseClientSideWebPart { public constructor(context: IWebPartContext) { @@ -19,18 +21,13 @@ export default class TermSetRequesterWebPart extends BaseClientSideWebPart
-
-
- Welcome to SharePoint! -

Customize SharePoint experiences using Web Parts.

-

${this.properties.description}

- - Learn more - -
-
+
`; + + const container: HTMLDivElement = this.domElement.querySelector('.' + styles.container) as HTMLDivElement; + var termStoreCtrl = new TaxonomyControl(this.context); + termStoreCtrl.render(container); } protected get propertyPaneSettings(): IPropertyPaneSettings { diff --git a/samples/knockout-taxonomy/src/webparts/termSetRequester/common/SPEntities.ts b/samples/knockout-taxonomy/src/webparts/termSetRequester/common/SPEntities.ts new file mode 100644 index 000000000..ad5d2155a --- /dev/null +++ b/samples/knockout-taxonomy/src/webparts/termSetRequester/common/SPEntities.ts @@ -0,0 +1,99 @@ +/** + * Base interface for Taxonomy objects + */ +export interface ITermBase { + /** + * Unique identifier + */ + id: string; + /** + * Name + */ + name: string; +} + +/** + * Term Store interface + */ +export interface ITermStore extends ITermBase { +} + +/** + * Term Group interface + */ +export interface ITermGroup extends ITermBase { + /** + * Term Group's description + */ + description: string; + /** + * Term Store ID. + * It is added to be able to store hierarchy structure (and it helps to decrease amount of Ajax requests to SharePoint) + */ + termStoreId: string; +} + +/** + * Term Set Interface + */ +export interface ITermSet extends ITermBase { + /** + * Description + */ + description?: string; + /** + * Term Group ID + * It is added to be able to store hierarchy structure (and it helps to decrease amount of Ajax requests to SharePoint) + */ + termGroupId?: string; + /** + * Term Store ID. + * It is added to be able to store hierarchy structure (and it helps to decrease amount of Ajax requests to SharePoint) + */ + termStoreId?: string; +} + +/** + * Term interface` + */ +export interface ITerm extends ITermBase { + /** + * Description + */ + description: string; + /** + * Flag if the current term is a root term in a term set + */ + isRoot: boolean; + /** + * Term labels + */ + labels: ILabel[]; + /** + * Number of child terms + */ + termsCount: number; + /** + * Term Set ID + * It is added to be able to store hierarchy structure (and it helps to decrease amount of Ajax requests to SharePoint) + */ + termSetId: string; +} + +/** + * Term Label interface + */ +export interface ILabel { + /** + * Flag if the label is default for current language + */ + isDefaultForLanguage: boolean; + /** + * Label's value + */ + value: string; + /** + * Current Language + */ + language: string; +} \ No newline at end of file diff --git a/samples/knockout-taxonomy/src/webparts/termSetRequester/controls/TaxonomyControl.ts b/samples/knockout-taxonomy/src/webparts/termSetRequester/controls/TaxonomyControl.ts new file mode 100644 index 000000000..d33021928 --- /dev/null +++ b/samples/knockout-taxonomy/src/webparts/termSetRequester/controls/TaxonomyControl.ts @@ -0,0 +1,47 @@ +import * as ko from 'knockout'; +import { + IWebPartContext +} from '@microsoft/sp-webpart-base'; + +import { TaxonomyControlView } from './TaxonomyControlView'; +import { TaxonomyControlViewModel } from './TaxonomyControlViewModel'; + +/** + * Class that represents a control to render Taxonomy hierarchy + */ +export class TaxonomyControl { + /** + * View + */ + private view: TaxonomyControlView; + /** + * ViewModel + */ + private viewModel: TaxonomyControlViewModel; + + /** + * ctor + * @param context: web part context + */ + constructor(context: IWebPartContext) { + this.view = new TaxonomyControlView(); + this.viewModel = new TaxonomyControlViewModel(context); + } + + /** + * Renders the control + */ + public render(element: HTMLElement): Promise { + return new Promise((resolve) => { + // renders html first + this.view.render(element).then(() => { + // inits view model + this.viewModel.init().then(() => { + // applies bindings + ko.applyBindings(this.viewModel, element); + resolve(); + }); + }); + }); + } +} \ No newline at end of file diff --git a/samples/knockout-taxonomy/src/webparts/termSetRequester/controls/TaxonomyControlModel.ts b/samples/knockout-taxonomy/src/webparts/termSetRequester/controls/TaxonomyControlModel.ts new file mode 100644 index 000000000..f7d1db9c5 --- /dev/null +++ b/samples/knockout-taxonomy/src/webparts/termSetRequester/controls/TaxonomyControlModel.ts @@ -0,0 +1,66 @@ +import { + ITermStore, + ITermSet, + ITermGroup, + ITerm +} from '../common/SPEntities'; + +import { + IWebPartContext +} from '@microsoft/sp-webpart-base'; + +import { IDataHelper } from '../data-helpers/DataHelperBase'; +import { DataHelpersFactory } from '../data-helpers/DataHelpersFactory'; + +/** + * Taxonomy Control Model + */ +export class TaxonomyControlModel { + /** + * data helper + */ + private _dataHelper: IDataHelper; + + /** + * ctor + * @param context: web part context + */ + constructor(context: IWebPartContext) { + this._dataHelper = DataHelpersFactory.createDataHelper(context); + } + + /** + * API to get Term Stores + */ + public getTermStores(): Promise { + return this._dataHelper.getTermStores(); + } + + /** + * API to get Term Groups by Term Store + */ + public getTermGroups(termStore: ITermStore): Promise { + return this._dataHelper.getTermGroups(termStore.id); + } + + /** + * API to get Term Sets by Term Group + */ + public getTermSets(termGroup: ITermGroup): Promise { + return this._dataHelper.getTermSets(termGroup); + } + + /** + * API to get Terms by Term Set + */ + public getTerms(termSet: ITermSet): Promise { + return this._dataHelper.getTerms(termSet); + } + + /** + * API to get Terms by Term + */ + public getChildTerms(term: ITerm): Promise { + return this._dataHelper.getChildTerms(term); + } +} \ No newline at end of file diff --git a/samples/knockout-taxonomy/src/webparts/termSetRequester/controls/TaxonomyControlView.ts b/samples/knockout-taxonomy/src/webparts/termSetRequester/controls/TaxonomyControlView.ts new file mode 100644 index 000000000..207705f72 --- /dev/null +++ b/samples/knockout-taxonomy/src/webparts/termSetRequester/controls/TaxonomyControlView.ts @@ -0,0 +1,60 @@ +export class TaxonomyControlView { + private _template: string = ` +
+
    + + +
+
+ + + + + + + + + `; + + /** + * Renders markup + */ + public render(element: HTMLElement): Promise { + return new Promise((resolve) => { + element.innerHTML = this._template; + resolve(); + }); + } +} \ No newline at end of file diff --git a/samples/knockout-taxonomy/src/webparts/termSetRequester/controls/TaxonomyControlViewModel.ts b/samples/knockout-taxonomy/src/webparts/termSetRequester/controls/TaxonomyControlViewModel.ts new file mode 100644 index 000000000..7d7fe2ca5 --- /dev/null +++ b/samples/knockout-taxonomy/src/webparts/termSetRequester/controls/TaxonomyControlViewModel.ts @@ -0,0 +1,313 @@ +import * as ko from 'knockout'; +import { TaxonomyControlModel } from './TaxonomyControlModel'; +import { + IWebPartContext +} from '@microsoft/sp-webpart-base'; +import { + ITermBase, + ITermStore, + ITermSet, + ITermGroup, + ITerm, + ILabel +} from '../common/SPEntities'; + +/** + * Taxonomy Control ViewModel class + */ +export class TaxonomyControlViewModel { + /** + * Collection of term store view models + */ + protected termStores: KnockoutObservableArray; + /** + * Model + */ + private model: TaxonomyControlModel; + + /** + * ctor + * @param context: web part context + */ + constructor(context: IWebPartContext) { + this.model = new TaxonomyControlModel(context); + this.termStores = ko.observableArray(); + } + + /** + * Inits the view model object + */ + public init(): Promise { + return new Promise((resolve) => { + // loading top level items of the hierarchy + this.model.getTermStores().then((termStores) => { + const termStoreViewModels: TermStoreViewModel[] = []; + termStores.forEach((value) => { + termStoreViewModels.push(new TermStoreViewModel(this.model, value)); + }); + + this.termStores(termStoreViewModels); + resolve(); + }); + }); + } +} + +/** + * Base viewmodel for all Taxonomy objects + */ +export class TermBaseViewModel { + /** + * Object's id + */ + protected id: string; + /** + * Name + */ + protected name: string; + /** + * Flag if the the item is expanded + */ + protected isExpanded: KnockoutObservable; + /** + * Model + */ + protected model: TaxonomyControlModel; + + /** + * ctor + * @param model: taxonomy control model + * @param entity: entity that is underline current view model + */ + constructor(model: TaxonomyControlModel, entity: ITermBase) { + this.model = model; + this.isExpanded = ko.observable(false); + this.id = entity.id; + this.name = entity.name; + } +} + +/** + * Term store viewmodel + */ +export class TermStoreViewModel extends TermBaseViewModel { + /** + * Term store entity + */ + private entity: ITermStore; + /** + * collection of viewmodels for term store groups + */ + protected termGroups: KnockoutObservableArray; + + /** + * ctor + * @param model: taxonomy control model + * @param entity: entity that is underline current view model + */ + constructor(model: TaxonomyControlModel, entity: ITermStore) { + super(model, entity); + this.entity = entity; + this.termGroups = ko.observableArray(); + } + + /** + * Expand\collapse click handler + */ + protected actionClick(ev: MouseEvent): void { + this.isExpanded(!this.isExpanded()); + + const isExpanded = this.isExpanded(); + + if (isExpanded) { + const unwrappedGroups = ko.utils.unwrapObservable(this.termGroups); + + if (!unwrappedGroups || !unwrappedGroups.length) { + this.model.getTermGroups(this.entity).then((termGroups) => { + const termGroupViewModels: TermGroupViewModel[] = []; + termGroups.forEach((value) => { + termGroupViewModels.push(new TermGroupViewModel(this.model, value)); + }); + + this.termGroups(termGroupViewModels); + }); + } + } + } +} + + +/** + * Term Group ViewModel + */ +export class TermGroupViewModel extends TermBaseViewModel { + /** + * Term Group entity + */ + private entity: ITermGroup; + /** + * Description + */ + protected description: string; + /** + * collection of viewmodels for nested term sets + */ + protected termSets: KnockoutObservableArray; + + /** + * ctor + * @param model: taxonomy control model + * @param entity: entity that is underline current view model + */ + constructor(model: TaxonomyControlModel, entity: ITermGroup) { + super(model, entity); + + this.entity = entity; + this.description = entity.description; + this.termSets = ko.observableArray(); + } + + /** + * Expand\collapse click handler + */ + protected actionClick(ev: MouseEvent): void { + this.isExpanded(!this.isExpanded()); + + const isExpanded = this.isExpanded(); + + if (isExpanded) { + const unwrappedSets = ko.utils.unwrapObservable(this.termSets); + + if (!unwrappedSets || !unwrappedSets.length) { + this.model.getTermSets(this.entity).then((termSets) => { + const termSetViewModels: TermSetViewModel[] = []; + termSets.forEach((value) => { + termSetViewModels.push(new TermSetViewModel(this.model, value)); + }); + + this.termSets(termSetViewModels); + }); + } + } + } +} + +/** + * Term Set View Model + */ +export class TermSetViewModel extends TermBaseViewModel { + /** + * Term Set entity + */ + private entity: ITermSet; + /** + * Description + */ + protected description: string; + /** + * collection of viewmodels for nested terms + */ + protected terms: KnockoutObservableArray; + + /** + * ctor + * @param model: taxonomy control model + * @param entity: entity that is underline current view model + */ + constructor(model: TaxonomyControlModel, entity: ITermSet) { + super(model, entity); + + this.entity = entity; + this.description = entity.description; + this.terms = ko.observableArray(); + } + + /** + * Expand\collapse click handler + */ + protected actionClick(ev: MouseEvent): void { + this.isExpanded(!this.isExpanded()); + + const isExpanded = this.isExpanded(); + + if (isExpanded) { + const unwrappedTerms = ko.utils.unwrapObservable(this.terms); + + if (!unwrappedTerms || !unwrappedTerms.length) { + this.model.getTerms(this.entity).then((terms) => { + const termViewModels: TermViewModel[] = []; + terms.forEach((value) => { + termViewModels.push(new TermViewModel(this.model, value)); + }); + + this.terms(termViewModels); + }); + } + } + } +} + +/** + * Term ViewModel + */ +export class TermViewModel extends TermBaseViewModel { + /** + * Term emtity + */ + private entity: ITerm; + /** + * Description + */ + protected description: string; + /** + * collection of viewmodels for nested terms + */ + protected terms: KnockoutObservableArray; + /** + * Flag if current term has child terms + */ + protected hasChildTerms: boolean; + /** + * Term's labels + */ + protected labels: ILabel[]; + + /** + * ctor + * @param model: taxonomy control model + * @param entity: entity that is underline current view model + */ + constructor(model: TaxonomyControlModel, entity: ITerm) { + super(model, entity); + + this.entity = entity; + this.description = entity.description; + this.terms = ko.observableArray(); + this.hasChildTerms = entity.termsCount > 0; + this.labels = entity.labels; + } + + /** + * Expand\collapse click handler + */ + protected actionClick(ev: MouseEvent): void { + this.isExpanded(!this.isExpanded()); + + const isExpanded = this.isExpanded(); + + if (isExpanded) { + const unwrappedTerms = ko.utils.unwrapObservable(this.terms); + + if (!unwrappedTerms || !unwrappedTerms.length) { + this.model.getChildTerms(this.entity).then((terms) => { + const termViewModels: TermViewModel[] = []; + terms.forEach((value) => { + termViewModels.push(new TermViewModel(this.model, value)); + }); + + this.terms(termViewModels); + }); + } + } + } +} \ No newline at end of file diff --git a/samples/knockout-taxonomy/src/webparts/termSetRequester/data-helpers/DataHelperBase.ts b/samples/knockout-taxonomy/src/webparts/termSetRequester/data-helpers/DataHelperBase.ts new file mode 100644 index 000000000..66e057e62 --- /dev/null +++ b/samples/knockout-taxonomy/src/webparts/termSetRequester/data-helpers/DataHelperBase.ts @@ -0,0 +1,32 @@ +import { + ITermStore, + ITermSet, + ITermGroup, + ITerm +} from '../common/SPEntities'; + +/** + * Data Helpers interface + */ +export interface IDataHelper { + /** + * API to get Term Stores + */ + getTermStores(): Promise; + /** + * API to get Term Groups by Term Store + */ + getTermGroups(termStoreId: string): Promise; + /** + * API to get Term Sets by Term Group + */ + getTermSets(termGroup: ITermGroup): Promise; + /** + * API to get Terms by Term Set + */ + getTerms(termSet: ITermSet): Promise; + /** + * API to get Terms by Term + */ + getChildTerms(term: ITerm): Promise; +} \ No newline at end of file diff --git a/samples/knockout-taxonomy/src/webparts/termSetRequester/data-helpers/DataHelperMock.ts b/samples/knockout-taxonomy/src/webparts/termSetRequester/data-helpers/DataHelperMock.ts new file mode 100644 index 000000000..f5a350f9a --- /dev/null +++ b/samples/knockout-taxonomy/src/webparts/termSetRequester/data-helpers/DataHelperMock.ts @@ -0,0 +1,185 @@ +import { + ITermStore, + ITermSet, + ITermGroup, + ITerm +} from '../common/SPEntities'; +import { + IDataHelper +} from './DataHelperBase'; + +/** + * Interface for Term store with groups + */ +interface ITermStoreWithGroups extends ITermStore { + /** + * nested groups + */ + groups?: ITermGroupWithTermSets[]; +} + +/** + * Interface for term group with term sets + */ +interface ITermGroupWithTermSets extends ITermGroup { + /** + * nested term sets + */ + termSets?: ITermSetWithTerms[]; +} + +/** + * Interface for term set with terms + */ +interface ITermSetWithTerms extends ITermSet { + /** + * nested terms + */ + terms?: ITermWithTerms[]; +} + +/** + * Interface for term with nested terms + */ +interface ITermWithTerms extends ITerm { + /** + * nested terms + */ + terms?: ITermWithTerms[]; +} + +/** + * MOCK data helper. Gets data from hardcoded values + */ +export class DataHelperMock implements IDataHelper { + private static _termStores: ITermStoreWithGroups[] = [{ + name: 'Term Store 1', + id: 'E920D42D-1540-4E39-B3F6-3795FBEF7F21', + groups: [{ + id: '6789F532-CCDE-44C4-AE45-2EC5FC509274', + termStoreId: 'E920D42D-1540-4E39-B3F6-3795FBEF7F21', + name: 'Group 1 from Term Store 1', + description: 'This is the first group of the first term store', + termSets: [{ + name: 'TSet 1 Gr 1 TStore 1', + id: 'B12D3D77-7DEA-435E-B1AF-3175DC9851DF', + termGroupId: '6789F532-CCDE-44C4-AE45-2EC5FC509274', + termStoreId: 'E920D42D-1540-4E39-B3F6-3795FBEF7F21', + description: 'Term Set 1 from Group 1 from Term Store 1', + terms: [{ + id: '1494A0ED-0866-4082-92A8-1C83D5B117C4', + termSetId: 'B12D3D77-7DEA-435E-B1AF-3175DC9851DF', + name: 'T 1 TSet 1 Gr 1 TStore 1', + description: 'Term 1 from Term Set 1 from Group 1 from Term Store 1', + labels: [{ + isDefaultForLanguage: true, + value: 'Term Label', + language: 'en-US' + }], + terms: [{ + id: '1494A0ED-0866-4082-92A8-1C83D5B117C4', + termSetId: 'B12D3D77-7DEA-435E-B1AF-3175DC9851DF', + name: 'T 1.1 TSet 1 Gr 1 TStore 1', + description: 'Term 1 from Term Set 1 from Group 1 from Term Store 1', + labels: [{ + isDefaultForLanguage: true, + value: 'Term Label', + language: 'en-US' + }], + termsCount: 0, + isRoot: false + }], + termsCount: 1, + isRoot: true + }] + }, { + id: '6783B7F9-41CA-4405-A85C-5C74B98AC81C', + termGroupId: '6789F532-CCDE-44C4-AE45-2EC5FC509274', + termStoreId: 'E920D42D-1540-4E39-B3F6-3795FBEF7F21', + name: 'TSet 2 Gr 1 TStore 1', + description: 'Term Set 2 from Group 1 from Term Store 1', + terms: [] + }] + }, { + id: '9FC4934A-EFA2-4460-A5DB-1611B8B478FE', + termStoreId: 'E920D42D-1540-4E39-B3F6-3795FBEF7F21', + name: 'Group 2 from Term Store 1', + description: 'This is the second group of the first term store', + termSets: [{ + id: '6AC24DB3-CF84-47D0-83E6-C118DD7C1D44', + termGroupId: '9FC4934A-EFA2-4460-A5DB-1611B8B478FE', + termStoreId: 'E920D42D-1540-4E39-B3F6-3795FBEF7F21', + name: 'TSet 1 Gr 2 TStore 1', + description: 'Term Set 1 from Group 2 from Term Store 1', + terms: [] + }] + }] + }, { + name: 'Term Store 2', + id: 'BBB5D5CF-F39E-45D4-A71A-F74681133D03', + groups: [{ + id: '96BD2791-BD83-4E1F-930C-0F2EBE943DFA', + termStoreId: 'BBB5D5CF-F39E-45D4-A71A-F74681133D03', + name: 'Group 1 from Term Store 2', + description: 'This is the first group of the second term store', + termSets: [{ + id: 'DDF892AB-00D2-4F13-B70C-378BE3A95A1D', + termGroupId: '96BD2791-BD83-4E1F-930C-0F2EBE943DFA', + termStoreId: 'BBB5D5CF-F39E-45D4-A71A-F74681133D03', + name: 'TSet 1 Gr 1 TStore 2', + description: 'Term Set 1 from Group 1 from Term Store 2', + terms: [] + }] + }] + }]; + + /** + * API to get Term Stores + */ + public getTermStores(): Promise { + return new Promise((resolve) => { + resolve(DataHelperMock._termStores); + }); + } + /** + * API to get Term Groups by Term Store + */ + public getTermGroups(termStoreId: string): Promise { + return new Promise((resolve) => { + for (let i = 0, len = DataHelperMock._termStores.length; i < len; i++) { + const termStore = DataHelperMock._termStores[i]; + if (termStore.id === termStoreId) { + resolve(termStore.groups); + return; + } + } + }); + } + /** + * API to get Term Sets by Term Group + */ + public getTermSets(termGroup: ITermGroup): Promise { + return new Promise((resolve) => { + const termGroupWithTermSets: ITermGroupWithTermSets = termGroup as ITermGroupWithTermSets; + resolve(termGroupWithTermSets.termSets); + }); + } + /** + * API to get Terms by Term Set + */ + public getTerms(termSet: ITermSet): Promise { + return new Promise((resolve) => { + const termSetWithTerms: ITermSetWithTerms = termSet as ITermSetWithTerms; + resolve(termSetWithTerms.terms); + }); + } + /** + * API to get Terms by Term + */ + public getChildTerms(term: ITerm): Promise { + return new Promise((resolve) => { + const termWithTerms: ITermWithTerms = term as ITermWithTerms; + resolve(termWithTerms.terms); + }); + } +} \ No newline at end of file diff --git a/samples/knockout-taxonomy/src/webparts/termSetRequester/data-helpers/DataHelperSP.ts b/samples/knockout-taxonomy/src/webparts/termSetRequester/data-helpers/DataHelperSP.ts new file mode 100644 index 000000000..52d0d8eb7 --- /dev/null +++ b/samples/knockout-taxonomy/src/webparts/termSetRequester/data-helpers/DataHelperSP.ts @@ -0,0 +1,663 @@ +/// +import { + IWebPartContext +} from '@microsoft/sp-webpart-base'; +import { + ITermStore, + ITermSet, + ITermGroup, + ITerm +} from '../common/SPEntities'; +import { + IDataHelper +} from './DataHelperBase'; + +/** + * Interface for terms with path property and nested terns + */ +interface ITermWithTerms extends ITerm { + /** + * Term's path + */ + path: string[]; + /** + * child terms + */ + terms?: ITerms; +} + +/** + * Interface that represents a map wit key term ID and value ITermWithTerms object + */ +interface ITerms { + [name: string]: ITermWithTerms; +} + +/** + * Interface that represents a map with key term set ID and value ITerms object + */ +interface ITermSetTerms { + [name: string]: ITerms; +} + +/** + * SharePoint Data Helper class. + * Gets information from current web + */ +export class DataHelperSP implements IDataHelper { + /** + * cached term stores. This property can be changed to static to be able to use the same cache in different web parts + */ + private _loadedTermStores: SP.Taxonomy.ITermStoreCollection; + /** + * cached terms' hierarchy. This property can be changed to static to be able to use the same cache in different web parts + */ + private _loadedTermsHierarchy: ITermSetTerms = {}; + /** + * cached terms' flat list. This property can be changed to static to be able to use the same cache in different web parts + */ + private _loadedTermsFlat: ITerms[] = []; + + /** + * Web part context + */ + public context: IWebPartContext; + + /** + * ctor + * @param context: web part context + */ + public constructor(_context: IWebPartContext) { + this.context = _context; + } + + /** + * API to get Term Stores + */ + public getTermStores(): Promise { + return new Promise((resolve) => { + // term stores have been already loaded + if (this._loadedTermStores) { + // converting SP.Taxonomy.ITermStore object to ITermStore objects + const termStoreEntities: ITermStore[] = this.getTermStoreEntities(this._loadedTermStores); + resolve(termStoreEntities); + return; + } + + // + // need to load term stores + // + + this.loadScripts().then(() => { // loading scripts first + const taxonomySession = this.taxonomySession; + let termStores = taxonomySession.get_termStores(); + this.clientContext.load(termStores); + this.clientContext.executeQueryAsync(() => { + // converting SP.Taxonomy.ITermStore object to ITermStore objects + const termStoreEntities: ITermStore[] = this.getTermStoreEntities(termStores); + // caching loaded term stores + this._loadedTermStores = termStores; + resolve(termStoreEntities); + }, () => { + resolve([]); + }); + + }); + }); + } + + /** + * API to get Term Groups by Term Store + */ + public getTermGroups(termStoreId: string): Promise { + return new Promise((resolve) => { + this.getTermStoreById(termStoreId).then((termStore) => { // getting the term store + if (!termStore) { + resolve([]); + return; + } + + let groups = termStore.get_groups(); + // + // if Groups property is not loaded get_count will throw an error that will be handled to retrieve groups + // + try { + + if (!groups.get_count()) { // this will throw error if groups were not loaded + resolve([]); + return; + } + + // converting SP.Taxonomy.ITermGroup object to ITermGroup objects + resolve(this.getTermGroupEntities(groups, termStore.get_id().toString())); + } + catch (ex) { // retrieving groups + this.clientContext.load(groups); + this.clientContext.executeQueryAsync(() => { + // converting SP.Taxonomy.ITermGroup object to ITermGroup objects + resolve(this.getTermGroupEntities(groups, termStore.get_id().toString())); + }, () => { + resolve([]); + }); + } + finally { + } + }); + }); + } + /** + * API to get Term Sets by Term Group + */ + public getTermSets(termGroup: ITermGroup): Promise { + return new Promise((resolve) => { + this.getTermStoreById(termGroup.termStoreId).then((termStore) => { // getting term store by id + if (!termStore) { + resolve([]); + return; + } + + this.getTermGroupById(termStore, termGroup.id).then((group) => { // getting term group by id + if (!group) { + resolve([]); + return; + } + let termSets = group.get_termSets(); + // + // if termSets property is not loaded get_count will throw an error that will be handled to retrieve term sets + // + try { + if (!termSets.get_count()) { // this will throw error if term sets were not loaded + resolve([]); + return; + } + + //converting SP.Taxonomy.ITermSet object to ITermSet object + resolve(this.getTermSetEntities(termSets, termGroup.id, termGroup.termStoreId)); + } + catch (ex) { // retrieving term sets + this.clientContext.load(termSets); + this.clientContext.executeQueryAsync(() => { + //converting SP.Taxonomy.ITermSet object to ITermSet object + resolve(this.getTermSetEntities(termSets, termGroup.id, termGroup.termStoreId)); + }, () => { + resolve([]); + }); + } + finally { + } + }); + }); + }); + } + /** + * API to get Terms by Term Set + */ + public getTerms(termSet: ITermSet): Promise { + return new Promise((resolve) => { + // checking if terms were previously loaded + if (this._loadedTermsHierarchy[termSet.id]) { + const termSetTerms = this._loadedTermsHierarchy[termSet.id]; + // converting ITerms object to collection of ITerm objects + resolve(this.getTermEntities(termSetTerms)); + return; + } + + // + // need to load terms + // + this.getTermStoreById(termSet.termStoreId).then((termStore) => { // getting store by id + if (!termStore) { + resolve([]); + return; + } + + this.getTermGroupById(termStore, termSet.termGroupId).then((group) => { // getting group by id + if (!group) { + resolve([]); + return; + } + + this.getTermSetById(termStore, group, termSet.id).then((set) => { // getting term set by id + if (!set) { + resolve([]); + return; + } + + let allTerms: SP.Taxonomy.ITermCollection; + // + // if terms property is not loaded get_count will throw an error that will be handled to retrieve terms + // + try { + allTerms = set.getAllTerms(); + + if (!allTerms.get_count()) { // this will throw error if terms were not loaded + resolve([]); + return; + } + + // caching terms + this._loadedTermsHierarchy[termSet.id] = this.buildTermsHierarchy(allTerms, termSet.id); + // converting ITerms object to collection of ITerm objects + resolve(this.getTermEntities(this._loadedTermsHierarchy[termSet.id])); + } + catch (ex) { // retrieving terms + this.clientContext.load(allTerms, 'Include(Id, Name, Description, IsRoot, TermsCount, PathOfTerm, Labels)'); + this.clientContext.executeQueryAsync(() => { + // caching terms + this._loadedTermsHierarchy[termSet.id] = this.buildTermsHierarchy(allTerms, termSet.id); + // converting ITerms object to collection of ITerm objects + resolve(this.getTermEntities(this._loadedTermsHierarchy[termSet.id])); + }, () => { + resolve([]); + }); + } + finally { } + + }); + }); + }); + }); + } + /** + * API to get Terms by Term + */ + public getChildTerms(term: ITerm): Promise { + return new Promise((resolve) => { + if (!this._loadedTermsFlat.length) { + // + // We can add logic to retrieve term from term Store + // But I'll skip it for this example + // + resolve([]); + return; + } + + let terms: ITerms; + // iterating through flat list of terms to find needed one + for (let i = 0, len = this._loadedTermsFlat.length; i < len; i++) { + const currTerm = this._loadedTermsFlat[i][term.id]; + if (currTerm) { + terms = currTerm.terms; + break; + } + } + + if (!terms) { + resolve([]); + return; + } + + // converting ITerms object to collection of ITerm objects + resolve(this.getTermEntities(terms)); + + }); + } + + /** + * Loads scripts that are needed to work with taxonomy + */ + private loadScripts(): Promise { + return new Promise((resolve) => { + // + // constructing path to Layouts folder + // + let layoutsUrl: string = this.context.pageContext.site.absoluteUrl; + if (layoutsUrl.lastIndexOf('/') === layoutsUrl.length - 1) + layoutsUrl = layoutsUrl.slice(0, -1); + layoutsUrl += '/_layouts/15/'; + + this.loadScript(layoutsUrl + 'init.js', 'Sod').then(() => { // loading init.js + return this.loadScript(layoutsUrl + 'sp.runtime.js', 'sp_runtime_initialize'); // loading sp.runtime.js + }).then(() => { + return this.loadScript(layoutsUrl + 'sp.js', 'sp_initialize'); // loading sp.js + }).then(() => { + return this.loadScript(layoutsUrl + 'sp.taxonomy.js', 'SP.Taxonomy'); // loading sp.taxonomy.js + }).then(() => { + resolve(); + }); + }); + } + + /** + * Loads script + * @param url: script src + * @param globalObjectName: name of global object to check if it is loaded to the page + */ + private loadScript(url: string, globalObjectName: string): Promise { + return new Promise((resolve) => { + let isLoaded = true; + if (globalObjectName.indexOf('.') !== -1) { + const props = globalObjectName.split('.'); + let currObj: any = window; + + for (let i = 0, len = props.length; i < len; i++) { + if (!currObj[props[i]]) { + isLoaded = false; + break; + } + + currObj = currObj[props[i]]; + } + } + else { + isLoaded = !!window[globalObjectName]; + } + // checking if the script was previously added to the page + if (isLoaded || document.head.querySelector('script[src="' + url + '"]')) { + resolve(); + return; + } + + // loading the script + const script = document.createElement('script'); + script.type = 'text/javascript'; + script.src = url; + script.onload = () => { + resolve(); + }; + document.head.appendChild(script); + }); + } + + /** + * Taxonomy session getter + */ + private get taxonomySession(): SP.Taxonomy.TaxonomySession { + return SP.Taxonomy.TaxonomySession.getTaxonomySession(this.clientContext); + } + + /** + * Client Context getter + */ + private get clientContext(): SP.ClientContext { + return SP.ClientContext.get_current(); + } + + /** + * Converts SP.Taxonomy.ITermStore objects to ITermStore objects + * @param termStores: SP.Taxonomy.ITermStoreCollection object + */ + private getTermStoreEntities(termStores: SP.Taxonomy.ITermStoreCollection): ITermStore[] { + if (!termStores) + return []; + + const termStoreEntities: ITermStore[] = []; + for (let i = 0, len = termStores.get_count(); i < len; i++) { + const termStore = termStores.get_item(i); + termStoreEntities.push({ + id: termStore.get_id().toString(), + name: termStore.get_name() + }); + } + + return termStoreEntities; + } + + /** + * Converts SP.Taxonomy.ITermGroup objects to ITermGroup objects + * @param termGroups: SP.Taxonomy.ITermGroupCollection object + * @param termStoreId: the identifier of parent term store + */ + private getTermGroupEntities(termGroups: SP.Taxonomy.ITermGroupCollection, termStoreId: string): ITermGroup[] { + if (!termGroups) + return []; + const termGroupEntities: ITermGroup[] = []; + for (let i = 0, len = termGroups.get_count(); i < len; i++) { + const termGroup = termGroups.get_item(i); + termGroupEntities.push({ + id: termGroup.get_id().toString(), + termStoreId: termStoreId, + name: termGroup.get_name(), + description: termGroup.get_description() + }); + } + + return termGroupEntities; + } + + /** + * Converts SP.Taxonomy.ITermSet objects to ITermSet objects + * @param termSets: SP.Taxonomy.ITermSetCollection object + * @param termGroupId: the identifier of parent term group + * @param termStoreId: the identifier of parent term store + */ + private getTermSetEntities(termSets: SP.Taxonomy.ITermSetCollection, termGroupId: string, termStoreId: string): ITermSet[] { + if (!termSets) + return []; + const termSetEntities: ITermSet[] = []; + + for (let i = 0, len = termSets.get_count(); i < len; i++) { + const termSet = termSets.get_item(i); + termSetEntities.push({ + id: termSet.get_id().toString(), + name: termSet.get_name(), + description: termSet.get_description(), + termGroupId: termGroupId, + termStoreId: termStoreId + }); + } + + return termSetEntities; + } + + /** + * Retrieves term store by its id + * @param termStoreId: the identifier of the store to retrieve + */ + private getTermStoreById(termStoreId: string): Promise { + return new Promise((resolve) => { + if (!this._loadedTermStores) { // term stores were not loaded, need to load them + this.getTermStores().then(() => { + return this.getTermStoreById(termStoreId); + }); + } + else { // term stores are loaded + let termStore = null; + + if (this._loadedTermStores) { + for (let i = 0, len = this._loadedTermStores.get_count(); i < len; i++) { + if (this._loadedTermStores.get_item(i).get_id().toString() === termStoreId) { + termStore = this._loadedTermStores.get_item(i); + break; + } + } + } + + resolve(termStore); + } + }); + } + + /** + * Retrieves term group by its id and parent term store + * @param termStore: parent term store + * @param termGroupId: the identifier of the group to retrieve + */ + private getTermGroupById(termStore: SP.Taxonomy.ITermStore, termGroupId: string): Promise { + return new Promise((resolve) => { + if (!termStore || !termGroupId) { + resolve(null); + return; + } + + let result: SP.Taxonomy.ITermGroup; + // + // if Groups property is not loaded get_count will throw an error that will be handled to retrieve groups + // + try { + const groups: SP.Taxonomy.ITermGroupCollection = termStore.get_groups(); + const groupsCount: number = groups.get_count(); + const groupIdUpper = termGroupId.toUpperCase(); + + for (let i = 0; i < groupsCount; i++) { + const currGroup: SP.Taxonomy.ITermGroup = groups.get_item(i); + if (currGroup.get_id().toString().toUpperCase() === groupIdUpper) { + result = currGroup; + break; + } + } + + if (!result) { // throwing an exception to try to load the group from server again + throw new Error(); + } + + resolve(result); + } + catch (ex) { // retrieving the groups from server + result = termStore.getGroup(termGroupId); + this.clientContext.load(result); + this.clientContext.executeQueryAsync(() => { + resolve(result); + }, () => { + resolve(null); + }); + } + finally { } + }); + } + + /** + * Retrieves term set by its id, parent group and parent store + * @param termStore: parent term store + * @param termGroup: parent term group + * @param termSetId: the identifier of the term set to retrieve + */ + private getTermSetById(termStore: SP.Taxonomy.ITermStore, termGroup: SP.Taxonomy.ITermGroup, termSetId: string): Promise { + return new Promise((resolve) => { + if (!termGroup || !termSetId) { + resolve(null); + return; + } + + let result: SP.Taxonomy.ITermSet; + // + // if termSets property is not loaded get_count will throw an error that will be handled to retrieve term sets + // + try { + const termSets: SP.Taxonomy.ITermSetCollection = termGroup.get_termSets(); + const setsCount: number = termSets.get_count(); + const setIdUpper = termSetId.toUpperCase(); + + for (let i = 0; i < setsCount; i++) { + const currSet: SP.Taxonomy.ITermSet = termSets.get_item(i); + if (currSet.get_id().toString().toUpperCase() === setIdUpper) { + result = currSet; + break; + } + } + + if (!result) { // throwing an exception to try to load the term set from server again + throw new Error(); + } + + resolve(result); + } + catch (ex) { + result = termStore.getTermSet(termSetId); + this.clientContext.load(result); + this.clientContext.executeQueryAsync(() => { + resolve(result); + }, () => { + resolve(null); + }); + } + finally { } + }); + } + + /** + * Builds terms' hierarchy and also caches flat list of terms + * @param terms: SP.Taxonomy.ITermCollection object + * @param termSetId: the indetifier of parent term set + */ + private buildTermsHierarchy(terms: SP.Taxonomy.ITermCollection, termSetId: string): ITerms { + if (!terms) + return {}; + const tree: ITerms = {}; + const flat: ITerms = {}; + + // + // Iterating through terms to collect flat list and create ITermWithTerms instances + // + for (let i = 0, len = terms.get_count(); i < len; i++) { + const term = terms.get_item(i); + // creating instance + const termEntity: ITermWithTerms = { + id: term.get_id().toString(), + name: term.get_name(), + description: term.get_description(), + labels: [], + termsCount: term.get_termsCount(), + isRoot: term.get_isRoot(), + path: term.get_pathOfTerm().split(';'), + termSetId: termSetId + }; + + // + // settings labels + // + const labels = term.get_labels(); + for (let lblIdx = 0, lblLen = labels.get_count(); lblIdx < lblLen; lblIdx++) { + const lbl = labels.get_item(lblIdx); + termEntity.labels.push({ + isDefaultForLanguage: lbl.get_isDefaultForLanguage(), + value: lbl.get_value(), + language: lbl.get_language() + }); + } + + // if term is root we need to add it to the tree + if (termEntity.isRoot) { + tree[termEntity.id] = termEntity; + } + + // adding term entity to flat list + flat[termEntity.id] = termEntity; + } + + const keys = Object.keys(flat); + // + // iterating through flat list of terms to build the tree structure + // + for (let keyIdx = 0, keysLength = keys.length; keyIdx < keysLength; keyIdx++) { + const key = keys[keyIdx]; + const currentTerm = flat[key]; + + // skipping root items + if (currentTerm.isRoot) continue; + + // getting parent term name + const termParentName = currentTerm.path[currentTerm.path.length - 2]; + + // + // second iteration to get parent term in flat list + // + for (let keySecondIndex = 0; keySecondIndex < keysLength; keySecondIndex++) { + const secondTerm = flat[keys[keySecondIndex]]; + if (secondTerm.name === termParentName) { + if (!secondTerm.terms) + secondTerm.terms = {}; + secondTerm.terms[currentTerm.id] = currentTerm; + } + } + } + + this._loadedTermsFlat.push(flat); + + return tree; + } + + /** + * Converts ITerms object to collection of ITerm objects + * @param terms: ITerms object + */ + private getTermEntities(terms: ITerms): ITerm[] { + const termsKeys = Object.keys(terms); + const termEntities: ITerm[] = []; + for (let keyIdx = 0, keysLength = termsKeys.length; keyIdx < keysLength; keyIdx++) { + termEntities.push(terms[termsKeys[keyIdx]]); + } + + return termEntities; + } +} \ No newline at end of file diff --git a/samples/knockout-metadata/src/webparts/termSetRequester/data-helpers/DataHelpersFactory.ts b/samples/knockout-taxonomy/src/webparts/termSetRequester/data-helpers/DataHelpersFactory.ts similarity index 100% rename from samples/knockout-metadata/src/webparts/termSetRequester/data-helpers/DataHelpersFactory.ts rename to samples/knockout-taxonomy/src/webparts/termSetRequester/data-helpers/DataHelpersFactory.ts diff --git a/samples/knockout-metadata/src/webparts/termSetRequester/loc/en-us.js b/samples/knockout-taxonomy/src/webparts/termSetRequester/loc/en-us.js similarity index 100% rename from samples/knockout-metadata/src/webparts/termSetRequester/loc/en-us.js rename to samples/knockout-taxonomy/src/webparts/termSetRequester/loc/en-us.js diff --git a/samples/knockout-metadata/src/webparts/termSetRequester/loc/mystrings.d.ts b/samples/knockout-taxonomy/src/webparts/termSetRequester/loc/mystrings.d.ts similarity index 100% rename from samples/knockout-metadata/src/webparts/termSetRequester/loc/mystrings.d.ts rename to samples/knockout-taxonomy/src/webparts/termSetRequester/loc/mystrings.d.ts diff --git a/samples/knockout-metadata/src/webparts/termSetRequester/tests/TermSetRequester.test.ts b/samples/knockout-taxonomy/src/webparts/termSetRequester/tests/TermSetRequester.test.ts similarity index 100% rename from samples/knockout-metadata/src/webparts/termSetRequester/tests/TermSetRequester.test.ts rename to samples/knockout-taxonomy/src/webparts/termSetRequester/tests/TermSetRequester.test.ts diff --git a/samples/knockout-metadata/tsconfig.json b/samples/knockout-taxonomy/tsconfig.json similarity index 100% rename from samples/knockout-metadata/tsconfig.json rename to samples/knockout-taxonomy/tsconfig.json diff --git a/samples/knockout-metadata/typings/@ms/odsp-webpack.d.ts b/samples/knockout-taxonomy/typings/@ms/odsp-webpack.d.ts similarity index 100% rename from samples/knockout-metadata/typings/@ms/odsp-webpack.d.ts rename to samples/knockout-taxonomy/typings/@ms/odsp-webpack.d.ts diff --git a/samples/knockout-metadata/typings/@ms/odsp.d.ts b/samples/knockout-taxonomy/typings/@ms/odsp.d.ts similarity index 100% rename from samples/knockout-metadata/typings/@ms/odsp.d.ts rename to samples/knockout-taxonomy/typings/@ms/odsp.d.ts diff --git a/samples/knockout-taxonomy/typings/SP/SP.d.ts b/samples/knockout-taxonomy/typings/SP/SP.d.ts new file mode 100644 index 000000000..045c27118 --- /dev/null +++ b/samples/knockout-taxonomy/typings/SP/SP.d.ts @@ -0,0 +1,207 @@ +/** + * SP namespace + */ +declare namespace SP { + /** + * Client Context class + */ + export class ClientContext { + /** + * API to get current context + */ + static get_current(): ClientContext; + /** + * API to load client objects + */ + load(obj: any, ...rest: string[]): void; + /** + * API to execute query + */ + executeQueryAsync(success?: (result: any) => void, error?: (error: any) => void); + } + + /** + * Base collection interface + */ + export interface ICollectionBase { + /** + * API to get count of items in the collection + */ + get_count(): number; + } + + /** + * Taxonomy namespace + */ + namespace Taxonomy { + /** + * Taxonomy Session class + */ + export class TaxonomySession { + /** + * API to get current Taxonomy Session + * @param spContext: current Client Context + */ + static getTaxonomySession(spContext: ClientContext): TaxonomySession; + + /** + * API to get term stores + */ + get_termStores(): ITermStoreCollection; + } + + /** + * Base interface of taxonomy objects + */ + export interface ITermBase { + /** + * API to get ID + */ + get_id(): any; + /** + * API to get name + */ + get_name(): string; + } + + /** + * Term Store interface + */ + export interface ITermStore extends ITermBase { + /** + * API to get all groups in the term store + */ + get_groups(): ITermGroupCollection; + /** + * API to get group by its id + */ + getGroup(id: string): ITermGroup; + /** + * API to get term set by its id + */ + getTermSet(id: string): ITermSet; + } + + /** + * Term Stores Collection interface + */ + export interface ITermStoreCollection extends ICollectionBase { + /** + * Gets item by index + */ + get_item(index: number): ITermStore; + } + + /** + * Term Group interface + */ + export interface ITermGroup extends ITermBase { + /** + * API to get description + */ + get_description(): string; + /** + * API to get term sets from the group + */ + get_termSets(): ITermSetCollection; + } + + /** + * Term Groups Collection inteface + */ + export interface ITermGroupCollection extends ICollectionBase { + /** + * Gets item by index + */ + get_item(index: number): ITermGroup; + } + + /** + * Term Set Interface + */ + export interface ITermSet extends ITermBase { + /** + * API to get description + */ + get_description(): string; + /** + * API to get flat list of all terms in the Term set + */ + getAllTerms(): ITermCollection; + } + + /** + * Term Sets collection interface + */ + export interface ITermSetCollection extends ICollectionBase { + /** + * Gets item by index + */ + get_item(index: number): ITermSet; + } + + /** + * Term interface + */ + export interface ITerm extends ITermBase { + /** + * API to get description + */ + get_description(): string; + /** + * API to get labels + */ + get_labels(): ILabelCollection; + /** + * API to get flag if current term is root term + */ + get_isRoot(): boolean; + /** + * API to get child terms count + */ + get_termsCount(): number; + /** + * API to get path of the term in defauld lcid + */ + get_pathOfTerm(): string; + } + + /** + * Terms Collection interface + */ + export interface ITermCollection extends ICollectionBase { + /** + * Gets item by index + */ + get_item(index: number): ITerm; + } + + /** + * Labels collection interface + */ + export interface ILabelCollection extends ICollectionBase { + /** + * Gets item by index + */ + get_item(index: number): ILabel; + } + + /** + * Label interface + */ + export interface ILabel { + /** + * API to get flag if current label is default for the language + */ + get_isDefaultForLanguage(): boolean; + /** + * API to get language + */ + get_language(): string; + /** + * API to get label's value + */ + get_value(): string; + } + } +} \ No newline at end of file diff --git a/samples/knockout-metadata/typings/assertion-error/assertion-error.d.ts b/samples/knockout-taxonomy/typings/assertion-error/assertion-error.d.ts similarity index 100% rename from samples/knockout-metadata/typings/assertion-error/assertion-error.d.ts rename to samples/knockout-taxonomy/typings/assertion-error/assertion-error.d.ts diff --git a/samples/knockout-metadata/typings/chai/chai.d.ts b/samples/knockout-taxonomy/typings/chai/chai.d.ts similarity index 100% rename from samples/knockout-metadata/typings/chai/chai.d.ts rename to samples/knockout-taxonomy/typings/chai/chai.d.ts diff --git a/samples/knockout-metadata/typings/combokeys/combokeys.d.ts b/samples/knockout-taxonomy/typings/combokeys/combokeys.d.ts similarity index 100% rename from samples/knockout-metadata/typings/combokeys/combokeys.d.ts rename to samples/knockout-taxonomy/typings/combokeys/combokeys.d.ts diff --git a/samples/knockout-metadata/typings/es6-collections/es6-collections.d.ts b/samples/knockout-taxonomy/typings/es6-collections/es6-collections.d.ts similarity index 100% rename from samples/knockout-metadata/typings/es6-collections/es6-collections.d.ts rename to samples/knockout-taxonomy/typings/es6-collections/es6-collections.d.ts diff --git a/samples/knockout-metadata/typings/es6-promise/es6-promise.d.ts b/samples/knockout-taxonomy/typings/es6-promise/es6-promise.d.ts similarity index 100% rename from samples/knockout-metadata/typings/es6-promise/es6-promise.d.ts rename to samples/knockout-taxonomy/typings/es6-promise/es6-promise.d.ts diff --git a/samples/knockout-metadata/typings/knockout/knockout.d.ts b/samples/knockout-taxonomy/typings/knockout/knockout.d.ts similarity index 100% rename from samples/knockout-metadata/typings/knockout/knockout.d.ts rename to samples/knockout-taxonomy/typings/knockout/knockout.d.ts diff --git a/samples/knockout-metadata/typings/lodash/lodash.d.ts b/samples/knockout-taxonomy/typings/lodash/lodash.d.ts similarity index 100% rename from samples/knockout-metadata/typings/lodash/lodash.d.ts rename to samples/knockout-taxonomy/typings/lodash/lodash.d.ts diff --git a/samples/knockout-metadata/typings/mocha/mocha.d.ts b/samples/knockout-taxonomy/typings/mocha/mocha.d.ts similarity index 100% rename from samples/knockout-metadata/typings/mocha/mocha.d.ts rename to samples/knockout-taxonomy/typings/mocha/mocha.d.ts diff --git a/samples/knockout-metadata/typings/node/node.d.ts b/samples/knockout-taxonomy/typings/node/node.d.ts similarity index 100% rename from samples/knockout-metadata/typings/node/node.d.ts rename to samples/knockout-taxonomy/typings/node/node.d.ts diff --git a/samples/knockout-metadata/typings/react/react-addons-shallow-compare.d.ts b/samples/knockout-taxonomy/typings/react/react-addons-shallow-compare.d.ts similarity index 100% rename from samples/knockout-metadata/typings/react/react-addons-shallow-compare.d.ts rename to samples/knockout-taxonomy/typings/react/react-addons-shallow-compare.d.ts diff --git a/samples/knockout-metadata/typings/react/react-addons-test-utils.d.ts b/samples/knockout-taxonomy/typings/react/react-addons-test-utils.d.ts similarity index 100% rename from samples/knockout-metadata/typings/react/react-addons-test-utils.d.ts rename to samples/knockout-taxonomy/typings/react/react-addons-test-utils.d.ts diff --git a/samples/knockout-metadata/typings/react/react-addons-update.d.ts b/samples/knockout-taxonomy/typings/react/react-addons-update.d.ts similarity index 100% rename from samples/knockout-metadata/typings/react/react-addons-update.d.ts rename to samples/knockout-taxonomy/typings/react/react-addons-update.d.ts diff --git a/samples/knockout-metadata/typings/react/react-dom.d.ts b/samples/knockout-taxonomy/typings/react/react-dom.d.ts similarity index 100% rename from samples/knockout-metadata/typings/react/react-dom.d.ts rename to samples/knockout-taxonomy/typings/react/react-dom.d.ts diff --git a/samples/knockout-metadata/typings/react/react.d.ts b/samples/knockout-taxonomy/typings/react/react.d.ts similarity index 100% rename from samples/knockout-metadata/typings/react/react.d.ts rename to samples/knockout-taxonomy/typings/react/react.d.ts diff --git a/samples/knockout-metadata/typings/systemjs/systemjs.d.ts b/samples/knockout-taxonomy/typings/systemjs/systemjs.d.ts similarity index 100% rename from samples/knockout-metadata/typings/systemjs/systemjs.d.ts rename to samples/knockout-taxonomy/typings/systemjs/systemjs.d.ts diff --git a/samples/knockout-metadata/typings/tsd.d.ts b/samples/knockout-taxonomy/typings/tsd.d.ts similarity index 96% rename from samples/knockout-metadata/typings/tsd.d.ts rename to samples/knockout-taxonomy/typings/tsd.d.ts index ba4a4b6d7..98b7ccb15 100644 --- a/samples/knockout-metadata/typings/tsd.d.ts +++ b/samples/knockout-taxonomy/typings/tsd.d.ts @@ -16,3 +16,4 @@ /// /// /// +///