Angular search update to RC0 (#121)

* initial commit

* initial commit
This commit is contained in:
David Hartman 2017-02-10 19:17:27 -05:00 committed by Vesa Juvonen
parent 7b7a04ef6a
commit 87866b253c
35 changed files with 1452 additions and 0 deletions

View File

@ -0,0 +1,25 @@
# EditorConfig helps developers define and maintain consistent
# coding styles between different editors and IDEs
# editorconfig.org
root = true
[*]
# change these settings to your own preference
indent_style = space
indent_size = 2
# we recommend you to keep these unchanged
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
[*.md]
trim_trailing_whitespace = false
[{package,bower}.json]
indent_style = space
indent_size = 2

View File

@ -0,0 +1 @@
* text=auto

32
samples/angular-search-rc/.gitignore vendored Normal file
View File

@ -0,0 +1,32 @@
# Logs
logs
*.log
npm-debug.log*
# Dependency directories
node_modules
# Build generated files
dist
lib
solution
temp
*.sppkg
# Coverage directory used by tools like istanbul
coverage
# OSX
.DS_Store
# Visual Studio files
.ntvs_analysis.dat
.vs
bin
obj
# Resx Generated Code
*.resx.ts
# Styles Generated Code
*.scss.ts

View File

@ -0,0 +1,14 @@
# Folders
.vscode
coverage
node_modules
sharepoint
src
temp
# Files
*.csproj
.git*
.yo-rc.json
gulpfile.js
tsconfig.json

View File

@ -0,0 +1,7 @@
{
"@microsoft/generator-sharepoint": {
"libraryName": "angular-search",
"libraryId": "21c361d1-704f-4cf9-8756-967fa092bc81",
"framework": "none"
}
}

View File

@ -0,0 +1,59 @@
# Search Client-Side Web Part Built with Angular v1.x
## Summary
Sample Search Web Part that illustrates how you can use Angular within the new SharePoint Framework
![Sample of the search web part](./assets/angularSearch.png)
This app uses SharePoint's Search REST API endpoint to query listitems of a specific content type and displays the results to the end user.
Ideally instead of selecting a content type for the search you would want to select a Result Source, but currently Result Sources are not
available through SharePoint's REST API.
The logic for querying the SharePoint Content Types in the properties of the webpart was in part due to Chris O'Brien and this [blog post](http://www.sharepointnutsandbolts.com/2016/09/sharepoint-framework-spfx-web-part-properties-dynamic-dropdown.html?m=0)
> Note: In order to use the ngOfficeFabric code I use the ModuleLoader to load newer source files than the currently Office Fabric UI in SharePoint Online, which will cause many of the icons not to load properly on the SharePoint Page this webpart is added to.
> Note: For the display template of the search results I'm currently using the Office Fabric UI List template. Ideally I was hoping to use the DocumentCard Component, however, that is not yet available through the ngOfficUIFabric.
> Note: The List display is not currently displaying correctly because there appears to be an issue when loading https://appsforoffice.microsoft.com/fabric/2.6.1/fabric.components.min.css which causes the dropdowns in the property pane not to work.
## Used SharePoint Framework Version
![drop](https://img.shields.io/badge/drop-rc0-green.svg)
## Applies to
* [SharePoint Framework Developer Preview](http://dev.office.com/sharepoint/docs/spfx/sharepoint-framework-overview)
* [Office 365 developer tenant](http://dev.office.com/sharepoint/docs/spfx/set-up-your-developer-tenant)
## Solution
Solution|Author(s)
--------|---------
angular-search|David Hartman ([Slalom](https://slalom.com))
## Version history
Version|Date|Comments
-------|----|--------
1.0|February 4th, 2017|Initial release
## Disclaimer
**THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.**
---
## Configuration Bliss
- clone this repo
- in the command line run:
- `npm i typings -g`
- `npm i`
- `gulp serve --nobrowser`
- Enable the following features in you site
- Publishing features on site collection
- Publishing features on site
> Note: The Content Types that I pull for the search come from the Publishing Content Type which only
> available when the Publishing Features are enabled on the site. I'm also searching by content type name
> and not by id becauase then I would get everything that inherits from that content type. I only want the
> the results for a specific content type and not everything that inherits that content type as well

Binary file not shown.

After

Width:  |  Height:  |  Size: 65 KiB

View File

@ -0,0 +1,13 @@
{
"entries": [
{
"entry": "./lib/webparts/angularSearch/AngularSearchWebPart.js",
"manifest": "./src/webparts/angularSearch/AngularSearchWebPart.manifest.json",
"outputPath": "./dist/angular-search.bundle.js"
}
],
"externals": {},
"localizedResources": {
"angularSearchStrings": "webparts/angularSearch/loc/{locale}.js"
}
}

View File

@ -0,0 +1,6 @@
{
"workingDir": "./temp/deploy/",
"account": "<!-- STORAGE ACCOUNT NAME -->",
"container": "angular-search",
"accessKey": "<!-- ACCESS KEY -->"
}

View File

@ -0,0 +1,10 @@
{
"solution": {
"name": "angular-search-client-side-solution",
"id": "21c361d1-704f-4cf9-8756-967fa092bc81",
"version": "1.0.0.0"
},
"paths": {
"zippedPackage": "solution/angular-search.sppkg"
}
}

View File

@ -0,0 +1,3 @@
{
"deployCdnPath": "temp/deploy"
}

View File

@ -0,0 +1,9 @@
{
"port": 4321,
"initialPage": "https://localhost:5432/workbench",
"https": true,
"api": {
"port": 5432,
"entryPath": "node_modules/@microsoft/sp-webpart-workbench/lib/api/"
}
}

View File

@ -0,0 +1,50 @@
{
// Display errors as warnings
"displayAsWarning": true,
// The TSLint task may have been configured with several custom lint rules
// before this config file is read (for example lint rules from the tslint-microsoft-contrib
// project). If true, this flag will deactivate any of these rules.
"removeExistingRules": true,
// When true, the TSLint task is configured with some default TSLint "rules.":
"useDefaultConfigAsBase": false,
// Since removeExistingRules=true and useDefaultConfigAsBase=false, there will be no lint rules
// which are active, other than the list of rules below.
"lintConfig": {
// Opt-in to Lint rules which help to eliminate bugs in JavaScript
"rules": {
"class-name": false,
"export-name": false,
"forin": false,
"label-position": false,
"label-undefined": false,
"member-access": true,
"no-arg": false,
"no-console": false,
"no-construct": false,
"no-duplicate-case": true,
"no-duplicate-key": false,
"no-duplicate-variable": true,
"no-eval": false,
"no-function-expression": true,
"no-internal-module": true,
"no-shadowed-variable": true,
"no-switch-case-fall-through": true,
"no-unnecessary-semicolons": true,
"no-unused-expression": true,
"no-unused-imports": true,
"no-unused-variable": true,
"no-unreachable": true,
"no-use-before-declare": true,
"no-with-statement": true,
"semicolon": true,
"trailing-comma": false,
"typedef": false,
"typedef-whitespace": false,
"use-named-parameter": true,
"valid-typeof": true,
"variable-name": false,
"whitespace": false,
"prefer-const": true
}
}
}

View File

@ -0,0 +1,3 @@
{
"cdnBasePath": "<!-- PATH TO CDN -->"
}

6
samples/angular-search-rc/gulpfile.js vendored Normal file
View File

@ -0,0 +1,6 @@
'use strict';
const gulp = require('gulp');
const build = require('@microsoft/sp-build-web');
build.initialize(gulp);

View File

@ -0,0 +1,31 @@
{
"name": "angular-search",
"version": "0.0.1",
"private": true,
"engines": {
"node": ">=0.10.0"
},
"dependencies": {
"@microsoft/sp-client-base": "~0.7.0",
"@microsoft/sp-client-preview": "~0.9.0",
"@microsoft/sp-core-library": "~0.1.2",
"@microsoft/sp-webpart-base": "~0.4.0",
"@types/angular": "^1.6.4",
"@types/webpack-env": ">=1.12.1 <1.14.0",
"angular": "^1.5.10",
"ng-office-ui-fabric": "^0.13.2"
},
"devDependencies": {
"@microsoft/sp-build-web": "~0.9.0",
"@microsoft/sp-module-interfaces": "~0.7.0",
"@microsoft/sp-webpart-workbench": "~0.8.0",
"gulp": "~3.9.1",
"@types/chai": ">=3.4.34 <3.6.0",
"@types/mocha": ">=2.2.33 <2.6.0"
},
"scripts": {
"build": "gulp bundle",
"clean": "gulp clean",
"test": "gulp test"
}
}

View File

@ -0,0 +1,5 @@
var context = require.context('.', true, /.+\.test\.js?$/);
context.keys().forEach(context);
module.exports = context;

View File

@ -0,0 +1,39 @@
@import "~/office-ui-fabric-react/dist/sass/Fabric.Common";
.row {
@include ms-Grid-row;
@include ms-bgColor-themeDark;
@include ms-fontColor-white;
box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.2), 0 25px 50px 0 rgba(0, 0, 0, 0.1);
max-width: 700px;
margin: 0 auto;
padding: 20px;
}
.column {
@include ms-Grid-col;
@include ms-u-lg10;
@include ms-u-xl8;
@include ms-u-lgPush1;
@include ms-u-xlPush2;
}
.title {
@include ms-font-xl;
@include ms-fontColor-white;
}
.subtitle {
@include ms-font-l;
@include ms-fontColor-white;
}
.description {
@include ms-font-l;
@include ms-fontColor-white;
}
.button {
text-decoration: none;
}

View File

@ -0,0 +1,21 @@
{
"$schema": "../../../node_modules/@microsoft/sp-module-interfaces/lib/manifestSchemas/jsonSchemas/clientSideComponentManifestSchema.json",
"id": "23dc01e2-9059-49ff-9f2d-ba8edd5d1ee9",
"alias": "AngularSearchWebPart",
"componentType": "WebPart",
"version": "0.0.1",
"manifestVersion": 2,
"preconfiguredEntries": [{
"groupId": "23dc01e2-9059-49ff-9f2d-ba8edd5d1ee9",
"group": { "default": "Under Development" },
"title": { "default": "AngularSearch" },
"description": { "default": "AngularSearch description" },
"officeFabricIconFontName": "Page",
"properties": {
"description": "AngularSearch",
"contentTypes": ""
}
}]
}

View File

@ -0,0 +1,158 @@
import {
Version,
Environment,
EnvironmentType
} from '@microsoft/sp-core-library';
import {
BaseClientSideWebPart,
IPropertyPaneConfiguration,
PropertyPaneTextField,
IPropertyPaneDropdownOption,
PropertyPaneDropdown,
IWebPartContext
} from '@microsoft/sp-webpart-base';
import { SPComponentLoader } from '@microsoft/sp-loader';
import { SPHttpClient } from '@microsoft/sp-http';
import { escape } from '@microsoft/sp-lodash-subset';
import styles from './AngularSearch.module.scss';
import * as strings from 'angularSearchStrings';
import { IAngularSearchWebPartProps } from './IAngularSearchWebPartProps';
import * as angular from 'angular';
import MockHttpClient from './MockHttpClient';
import './app/app.module';
import 'ng-office-ui-fabric';
export interface ISPCTypeLists {
value: ISPCType[];
}
export interface ISPCType {
Name: string;
Description: string;
Id: ISPStrVal;
}
export interface ISPStrVal {
StringValue: string;
}
export default class AngularSearchWebPart extends BaseClientSideWebPart<IAngularSearchWebPartProps> {
private $injector: angular.auto.IInjectorService;
private _CTypesInThisSite: IPropertyPaneDropdownOption[] = [];
public constructor(context: IWebPartContext) {
super();
SPComponentLoader.loadCss('https://appsforoffice.microsoft.com/fabric/2.6.1/fabric.min.css');
//SPComponentLoader.loadCss('https://appsforoffice.microsoft.com/fabric/2.6.1/fabric.components.min.css');
}
public onInit<T>(): Promise<T> {
//Determine if we are in a local environment
if (Environment.type == EnvironmentType.Local) {
this._getMockOptions().then((data) => {
this._CTypesInThisSite = data;
});
}
else {
this._getOptions().then((data) => {
this._CTypesInThisSite = data;
});
}
return Promise.resolve();
}
public render(): void {
if (this.renderedOnce === false) {
this.domElement.innerHTML = `<angularsearch web="${this.context.pageContext.web.absoluteUrl}" style='${angular.toJson(styles)}' contentType='${this.properties.contentTypes}'></angularsearch>`;
this.$injector = angular.bootstrap(this.domElement, ['angularsearchapp']);
}
this.$injector.get('$rootScope').$broadcast('configurationChanged', {
contentType: this.properties.contentTypes
});
}
private _getCTypes(url: string): Promise<ISPCTypeLists> {
return this.context.spHttpClient.get(url, SPHttpClient.configurations.v1).then((response: Response) => {
if (response.ok) {
return response.json();
}
else {
console.log("error: " + response.statusText);
return null;
}
});
}
private _getMockOptions(): Promise<IPropertyPaneDropdownOption[]> {
return this._getMockCTypes()
.then((data: ISPCTypeLists) => {
var options: Array<IPropertyPaneDropdownOption> = new Array<IPropertyPaneDropdownOption>();
var cTypes: ISPCType[] = data.value;
cTypes.forEach((cType: ISPCType) => {
console.log("Found Content Type(s)");
options.push({ key: cType.Id.StringValue, text: cType.Name });
});
return options;
});
}
private _getMockCTypes(): Promise<ISPCTypeLists> {
return MockHttpClient.get(this.context.pageContext.web.absoluteUrl)
.then((data: ISPCType[]) => {
let cTypeData: ISPCTypeLists = { value: data };
return cTypeData;
}) as Promise<ISPCTypeLists>;
}
private _getOptions(): Promise<IPropertyPaneDropdownOption[]> {
var url = this.context.pageContext.web.absoluteUrl + '/_api/web/AvailableContentTypes?$filter=Group eq \'Page Layout Content Types\'';
return this._getCTypes(url).then((response) => {
var options: Array<IPropertyPaneDropdownOption> = new Array<IPropertyPaneDropdownOption>();
var lists: ISPCType[] = response.value;
lists.forEach((list: ISPCType) => {
console.log("Found Content Type(s)");
options.push({ key: list.Name, text: list.Name });
});
return options;
});
}
protected get dataVersion(): Version {
return Version.parse('1.0');
}
protected getPropertyPaneConfiguration(): IPropertyPaneConfiguration {
return {
pages: [
{
header: {
description: strings.PropertyPaneDescription
},
groups: [
{
groupName: strings.BasicGroupName,
groupFields: [
PropertyPaneTextField('description', {
label: strings.DescriptionFieldLabel
}),
PropertyPaneDropdown('contentTypes', {
label: 'Available Content Types',
options: this._CTypesInThisSite,
})
]
}
]
}
]
};
}
}

View File

@ -0,0 +1,4 @@
export interface IAngularSearchWebPartProps {
description: string;
contentTypes: string;
}

View File

@ -0,0 +1,15 @@
import { ISPCType } from './AngularSearchWebPart'
export default class MockHttpClient {
private static _items: ISPCType[] = [
{ Name: 'Mock CType 1', Description: 'Mock CType 1', Id: { StringValue: 'Mock CType 1' } },
{ Name: 'Mock CType 2', Description: 'Mock CType 2', Id: { StringValue: 'Mock CType 2' } },
{ Name: 'Mock CType 3', Description: 'Mock CType 3', Id: { StringValue: 'Mock CType 3' } }
];
public static get(restUrl: string): Promise<ISPCType[]> {
return new Promise<ISPCType[]>((resolve) => {
resolve(MockHttpClient._items);
});
}
}

View File

@ -0,0 +1,44 @@
import { ISearchResults } from './../models/ISearchResults'
export interface IDataService {
getSearchResults(webUrl: string, contentType: string): angular.IPromise<ISearchResults>;
}
export default class DataService implements IDataService {
public static $inject: string[] = ['$q', '$http'];
constructor(private $q: angular.IQService, private $http: angular.IHttpService) { }
public getSearchResults(webUrl: string, contentType: string): angular.IPromise<ISearchResults> {
const deferred: angular.IDeferred<ISearchResults> = this.$q.defer();
this.$http({
url: `${webUrl}/_api/search/query?queryText='ContentType:"${contentType}"
Path:${webUrl}'&selectproperties='Title,Author,HitHighlightedSummary,PublishingImage,Url'`,
method: 'GET',
headers: {
'Accept': 'application/json;odata=verbose'
}
}).then((response: angular.IHttpPromiseCallbackArg<any>): void => {
if (response != null && response.data != null) {
const result: ISearchResults = response.data.d.query;
if (typeof result.PrimaryQueryResult !== 'undefined' &&
typeof result.PrimaryQueryResult.RelevantResults !== 'undefined' &&
typeof result.PrimaryQueryResult.RelevantResults.Table !== 'undefined' &&
typeof result.PrimaryQueryResult.RelevantResults.Table.Rows !== 'undefined') {
deferred.resolve(result);
}
else {
deferred.reject("problem getting search results");
}
}
else {
deferred.reject("problem getting search results");
}
}, (error: any): void => {
deferred.reject(error);
});
return deferred.promise;
}
}

View File

@ -0,0 +1,106 @@
import * as angular from 'angular';
import { IDataService } from './DataService';
import { ISearchResults, ICells, ICellValue } from './../models/ISearchResults';
interface IConfigurationChangeArgs {
contentType: string;
}
export default class HomeController {
public static $inject: string[] = ['DataService', '$rootScope', '$scope', '$attrs'];
public status: string = undefined;
public styles: any = null;
public searchNotConfigured: boolean = true;
public items: any[] = [];
public searching: boolean = false;
private _web: string = null;
private _contentType: string = undefined;
constructor(private dataService: IDataService, private $rootScope: angular.IRootScopeService, private $scope: angular.IScope, private $attrs: angular.IAttributes) {
const vm: HomeController = this;
vm.styles = angular.fromJson($attrs['style']);
vm._web = $attrs['web'];
vm._contentType = $attrs['contenttype'] === "" ? undefined : $attrs['contenttype'];
if (this._contentType !== undefined) {
this._init(this._contentType, vm.$scope);
}
else {
this._init(undefined, undefined);
}
$rootScope.$on('configurationChanged',
(event: angular.IAngularEvent, args: IConfigurationChangeArgs): void => {
vm._init(args.contentType, vm.$scope);
});
}
private _init(ctype: string, $scope: angular.IScope): void {
if (ctype !== undefined && ctype.length > 0) {
this._contentType = ctype;
this.searchNotConfigured = false;
}
else {
this.searchNotConfigured = true;
}
this.status = this.searchNotConfigured ? 'Please select a contenet type in the Web Part properties' : 'Ready';
if ($scope && this._contentType !== undefined) {
//$scope.$digest();
//get search results as long as it isn't our mock dataService
if (ctype.toLowerCase().indexOf('mock') == -1) {
this.getSearchResults();
}
}
}
public getSearchResults(): void {
//display searching message
this.searching = true;
this.dataService.getSearchResults(this._web, this._contentType)
.then((results: ISearchResults): void => {
this.items = this._setSearchResults(results.PrimaryQueryResult.RelevantResults.Table.Rows.results);
console.log(this.items);
//hide searching message
this.searching = false;
});
}
private _setSearchResults(searchResults: ICells[]): any[] {
if (searchResults.length > 0) {
const temp: any[] = [];
searchResults.forEach((result: ICells) => {
var val: Object = {};
result.Cells.results.forEach((cell: ICellValue) => {
if (cell.Key == 'HitHighlightedSummary') {
//need to replace <ddd> markup
val[cell.Key] = cell.Value.replace(/ <ddd\/>/g, '.');
}
else if (cell.Key == 'PublishingImage' && cell.Value !== null) {
//need to pull image url out of PublishingImage field
let div = document.createElement('div');
div.innerHTML = cell.Value;
let img = div.getElementsByTagName('img')[0];
val[cell.Key] = img.src;
}
else {
val[cell.Key] = cell.Value;
}
});
temp.push(val);
});
return temp;
}
else {
return [];
}
}
}

View File

@ -0,0 +1,20 @@
import * as angular from 'angular';
import DataService from './DataService';
import HomeController from './HomeController';
angular
.module('angularsearchapp', [
'officeuifabric.core',
'officeuifabric.components'
])
.component('angularsearch', {
controller: (HomeController),
controllerAs: 'vm',
bindings: {
web: '@',
style: '<',
contentType: '@'
},
template: require(`home-template.html`).toString()
})
.service('DataService', DataService);

View File

@ -0,0 +1,45 @@
<div class="ms-Grid">
<div class="">
<div class="ms-Grid-row ms-bgColor-themeDark ms-fontColor-white {{::vm.styles.row}}">
<div class="ms-Grid-col ms-u-lg10 ms-u-x-18 ms-u-xlPush2 ms-u-lgPush1">
<span class="ms-font-xl ms-fontColor-white">
Sample SharePoint Search in Angular
</span>
<uif-button type="button" ng-click="vm.getSearchResults()" ng-disabled="vm.searchNotConfigured">
<i class="ms-Icon ms-Icon--Sync" title="Refresh" aria-hidden="true"></i>
</uif-button>
</div>
</div>
<div class="ms-Grid-row" ng-show="vm.searchNotConfigured">
<div class="ms-Grid-col ms-u-sm12">
{{vm.status}}
</div>
</div>
<div class="ms-Grid-row" ng-show="vm.searching">
<div class="ms-Grid-col ms-u-smPush6 ms-u-mdPush6 ms-u-lgPush6 ms-u-xlPush6">
<uif-spinner uif-size="large">Searching...</uif-spinner>
</div>
</div>
<div class="ms-Grid-row">
<div class="ms-Grid-col ms-u-sm-12">
<div ng-show="!vm.searching">
<uif-list uif-item-select-mode="single">
<uif-list-item ng-repeat="item in vm.items" uif-item="item">
<div class="ms-Grid-row">
<div class="ms-Grid-col ms-u-sm-12">
<uif-link ng-href="{{item.Url}}" style="text-decoration: none;">
<uif-list-item-image>
<img ng-src="{{item.PublishingImage}}" style="width: 80%" />
</uif-list-item-image>
<uif-list-item-primary-text>{{item.Title}}</uif-list-item-primary-text>
<uif-list-item-secondary-text>By: {{item.Author}}</uif-list-item-secondary-text>
<uif-list-item-tertiary-text>{{item.HitHighlightedSummary}}</uif-list-item-tertiary-text>
</uif-link>
</div>
</div>
</uif-list>
</div>
</div>
</div>
</div>
</div>

View File

@ -0,0 +1,7 @@
define([], function() {
return {
"PropertyPaneDescription": "Description",
"BasicGroupName": "Group Name",
"DescriptionFieldLabel": "Description Field"
}
});

View File

@ -0,0 +1,10 @@
declare interface IAngularSearchStrings {
PropertyPaneDescription: string;
BasicGroupName: string;
DescriptionFieldLabel: string;
}
declare module 'angularSearchStrings' {
const strings: IAngularSearchStrings;
export = strings;
}

View File

@ -0,0 +1,33 @@
export interface ISearchResults {
PrimaryQueryResult: IPrimaryQueryResult;
}
export interface IPrimaryQueryResult {
RelevantResults: IRelevantResults;
}
export interface IRelevantResults {
Table: ITable;
}
export interface ITable {
Rows: IResults;
}
export interface IResults {
results: Array<ICells>;
}
export interface ICells {
Cells: IResultValues;
}
export interface IResultValues {
results: Array<ICellValue>;
}
export interface ICellValue {
Key: string;
Value: string;
ValueType: string;
}

View File

@ -0,0 +1,9 @@
/// <reference types="mocha" />
import { assert } from 'chai';
describe('AngularSearchWebPart', () => {
it('should do something', () => {
assert.ok(true);
});
});

View File

@ -0,0 +1,13 @@
{
"compilerOptions": {
"target": "es5",
"forceConsistentCasingInFileNames": true,
"module": "commonjs",
"jsx": "react",
"declaration": true,
"sourceMap": true,
"types": [
"webpack-env"
]
}
}

View File

@ -0,0 +1,5 @@
// Type definitions for Microsoft ODSP projects
// Project: ODSP
/* Global definition for UNIT_TEST builds */
declare const UNIT_TEST: boolean;

View File

@ -0,0 +1,15 @@
// Type definitions for assertion-error 1.0.0
// Project: https://github.com/chaijs/assertion-error
// Definitions by: Bart van der Schoor <https://github.com/Bartvds>
// Definitions: https://github.com/borisyankov/DefinitelyTyped
declare module 'assertion-error' {
class AssertionError implements Error {
constructor(message: string, props?: any, ssf?: Function);
name: string;
message: string;
showDiff: boolean;
stack: string;
}
export = AssertionError;
}

View File

@ -0,0 +1,631 @@
// Type definitions for Knockout v3.2.0
// Project: http://knockoutjs.com
// Definitions by: Boris Yankov <https://github.com/borisyankov/>, Igor Oleinikov <https://github.com/Igorbek/>, Clément Bourgeois <https://github.com/moonpyk/>
// Definitions: https://github.com/borisyankov/DefinitelyTyped
interface KnockoutSubscribableFunctions<T> {
[key: string]: KnockoutBindingHandler;
notifySubscribers(valueToWrite?: T, event?: string): void;
}
interface KnockoutComputedFunctions<T> {
[key: string]: KnockoutBindingHandler;
}
interface KnockoutObservableFunctions<T> {
[key: string]: KnockoutBindingHandler;
equalityComparer(a: any, b: any): boolean;
}
interface KnockoutObservableArrayFunctions<T> {
// General Array functions
indexOf(searchElement: T, fromIndex?: number): number;
slice(start: number, end?: number): T[];
splice(start: number): T[];
splice(start: number, deleteCount: number, ...items: T[]): T[];
pop(): T;
push(...items: T[]): void;
shift(): T;
unshift(...items: T[]): number;
reverse(): KnockoutObservableArray<T>;
sort(): KnockoutObservableArray<T>;
sort(compareFunction: (left: T, right: T) => number): KnockoutObservableArray<T>;
// Ko specific
[key: string]: KnockoutBindingHandler;
replace(oldItem: T, newItem: T): void;
remove(item: T): T[];
remove(removeFunction: (item: T) => boolean): T[];
removeAll(items: T[]): T[];
removeAll(): T[];
destroy(item: T): void;
destroy(destroyFunction: (item: T) => boolean): void;
destroyAll(items: T[]): void;
destroyAll(): void;
}
interface KnockoutSubscribableStatic {
fn: KnockoutSubscribableFunctions<any>;
new <T>(): KnockoutSubscribable<T>;
}
interface KnockoutSubscription {
dispose(): void;
}
interface KnockoutSubscribable<T> extends KnockoutSubscribableFunctions<T> {
subscribe(callback: (newValue: T) => void, target?: any, event?: string): KnockoutSubscription;
subscribe<TEvent>(callback: (newValue: TEvent) => void, target: any, event: string): KnockoutSubscription;
extend(requestedExtenders: { [key: string]: any; }): KnockoutSubscribable<T>;
getSubscriptionsCount(): number;
}
interface KnockoutComputedStatic {
fn: KnockoutComputedFunctions<any>;
<T>(): KnockoutComputed<T>;
<T>(func: () => T, context?: any, options?: any): KnockoutComputed<T>;
<T>(def: KnockoutComputedDefine<T>, context?: any): KnockoutComputed<T>;
}
interface KnockoutComputed<T> extends KnockoutObservable<T>, KnockoutComputedFunctions<T> {
fn: KnockoutComputedFunctions<any>;
dispose(): void;
isActive(): boolean;
getDependenciesCount(): number;
extend(requestedExtenders: { [key: string]: any; }): KnockoutComputed<T>;
}
interface KnockoutObservableArrayStatic {
fn: KnockoutObservableArrayFunctions<any>;
<T>(value?: T[]): KnockoutObservableArray<T>;
}
interface KnockoutObservableArray<T> extends KnockoutObservable<T[]>, KnockoutObservableArrayFunctions<T> {
extend(requestedExtenders: { [key: string]: any; }): KnockoutObservableArray<T>;
}
interface KnockoutObservableStatic {
fn: KnockoutObservableFunctions<any>;
<T>(value?: T): KnockoutObservable<T>;
}
interface KnockoutObservable<T> extends KnockoutSubscribable<T>, KnockoutObservableFunctions<T> {
(): T;
(value: T): void;
peek(): T;
valueHasMutated?:{(): void;};
valueWillMutate?:{(): void;};
extend(requestedExtenders: { [key: string]: any; }): KnockoutObservable<T>;
}
interface KnockoutComputedDefine<T> {
read(): T;
write? (value: T): void;
disposeWhenNodeIsRemoved?: Node;
disposeWhen? (): boolean;
owner?: any;
deferEvaluation?: boolean;
pure?: boolean;
}
interface KnockoutBindingContext {
$parent: any;
$parents: any[];
$root: any;
$data: any;
$rawData: any | KnockoutObservable<any>;
$index?: KnockoutObservable<number>;
$parentContext?: KnockoutBindingContext;
$component: any;
$componentTemplateNodes: Node[];
extend(properties: any): any;
createChildContext(dataItemOrAccessor: any, dataItemAlias?: any, extendCallback?: Function): any;
}
interface KnockoutAllBindingsAccessor {
(): any;
get(name: string): any;
has(name: string): boolean;
}
interface KnockoutBindingHandler {
after?: Array<string>;
init?: (element: any, valueAccessor: () => any, allBindingsAccessor?: KnockoutAllBindingsAccessor, viewModel?: any, bindingContext?: KnockoutBindingContext) => void | { controlsDescendantBindings: boolean; };
update?: (element: any, valueAccessor: () => any, allBindingsAccessor?: KnockoutAllBindingsAccessor, viewModel?: any, bindingContext?: KnockoutBindingContext) => void;
options?: any;
preprocess?: (value: string, name: string, addBindingCallback?: (name: string, value: string) => void) => string;
}
interface KnockoutBindingHandlers {
[bindingHandler: string]: KnockoutBindingHandler;
// Controlling text and appearance
visible: KnockoutBindingHandler;
text: KnockoutBindingHandler;
html: KnockoutBindingHandler;
css: KnockoutBindingHandler;
style: KnockoutBindingHandler;
attr: KnockoutBindingHandler;
// Control Flow
foreach: KnockoutBindingHandler;
if: KnockoutBindingHandler;
ifnot: KnockoutBindingHandler;
with: KnockoutBindingHandler;
// Working with form fields
click: KnockoutBindingHandler;
event: KnockoutBindingHandler;
submit: KnockoutBindingHandler;
enable: KnockoutBindingHandler;
disable: KnockoutBindingHandler;
value: KnockoutBindingHandler;
textInput: KnockoutBindingHandler;
hasfocus: KnockoutBindingHandler;
checked: KnockoutBindingHandler;
options: KnockoutBindingHandler;
selectedOptions: KnockoutBindingHandler;
uniqueName: KnockoutBindingHandler;
// Rendering templates
template: KnockoutBindingHandler;
// Components (new for v3.2)
component: KnockoutBindingHandler;
}
interface KnockoutMemoization {
memoize(callback: () => string): string;
unmemoize(memoId: string, callbackParams: any[]): boolean;
unmemoizeDomNodeAndDescendants(domNode: any, extraCallbackParamsArray: any[]): boolean;
parseMemoText(memoText: string): string;
}
interface KnockoutVirtualElement {}
interface KnockoutVirtualElements {
allowedBindings: { [bindingName: string]: boolean; };
emptyNode(node: KnockoutVirtualElement ): void;
firstChild(node: KnockoutVirtualElement ): KnockoutVirtualElement;
insertAfter( container: KnockoutVirtualElement, nodeToInsert: Node, insertAfter: Node ): void;
nextSibling(node: KnockoutVirtualElement): Node;
prepend(node: KnockoutVirtualElement, toInsert: Node ): void;
setDomNodeChildren(node: KnockoutVirtualElement, newChildren: { length: number;[index: number]: Node; } ): void;
childNodes(node: KnockoutVirtualElement ): Node[];
}
interface KnockoutExtenders {
throttle(target: any, timeout: number): KnockoutComputed<any>;
notify(target: any, notifyWhen: string): any;
rateLimit(target: any, timeout: number): any;
rateLimit(target: any, options: { timeout: number; method?: string; }): any;
trackArrayChanges(target: any): any;
}
//
// NOTE TO MAINTAINERS AND CONTRIBUTORS : pay attention to only include symbols that are
// publicly exported in the minified version of ko, without that you can give the false
// impression that some functions will be available in production builds.
//
interface KnockoutUtils {
//////////////////////////////////
// utils.domData.js
//////////////////////////////////
domData: {
get (node: Element, key: string): any;
set (node: Element, key: string, value: any): void;
getAll(node: Element, createIfNotFound: boolean): any;
clear(node: Element): boolean;
};
//////////////////////////////////
// utils.domNodeDisposal.js
//////////////////////////////////
domNodeDisposal: {
addDisposeCallback(node: Element, callback: Function): void;
removeDisposeCallback(node: Element, callback: Function): void;
cleanNode(node: Node): Element;
removeNode(node: Node): void;
};
addOrRemoveItem<T>(array: T[] | KnockoutObservable<T>, value: T, included: T): void;
arrayFilter<T>(array: T[], predicate: (item: T) => boolean): T[];
arrayFirst<T>(array: T[], predicate: (item: T) => boolean, predicateOwner?: any): T;
arrayForEach<T>(array: T[], action: (item: T, index: number) => void): void;
arrayGetDistinctValues<T>(array: T[]): T[];
arrayIndexOf<T>(array: T[], item: T): number;
arrayMap<T, U>(array: T[], mapping: (item: T) => U): U[];
arrayPushAll<T>(array: T[] | KnockoutObservableArray<T>, valuesToPush: T[]): T[];
arrayRemoveItem(array: any[], itemToRemove: any): void;
compareArrays<T>(a: T[], b: T[]): Array<KnockoutArrayChange<T>>;
extend(target: Object, source: Object): Object;
fieldsIncludedWithJsonPost: any[];
getFormFields(form: any, fieldName: string): any[];
objectForEach(obj: any, action: (key: any, value: any) => void): void;
parseHtmlFragment(html: string): any[];
parseJson(jsonString: string): any;
postJson(urlOrForm: any, data: any, options: any): void;
peekObservable<T>(value: KnockoutObservable<T>): T;
range(min: any, max: any): any;
registerEventHandler(element: any, eventType: any, handler: Function): void;
setHtml(node: Element, html: () => string): void;
setHtml(node: Element, html: string): void;
setTextContent(element: any, textContent: string | KnockoutObservable<string>): void;
stringifyJson(data: any, replacer?: Function, space?: string): string;
toggleDomNodeCssClass(node: any, className: string, shouldHaveClass: boolean): void;
triggerEvent(element: any, eventType: any): void;
unwrapObservable<T>(value: KnockoutObservable<T> | T): T;
// NOT PART OF THE MINIFIED API SURFACE (ONLY IN knockout-{version}.debug.js) https://github.com/SteveSanderson/knockout/issues/670
// forceRefresh(node: any): void;
// ieVersion: number;
// isIe6: boolean;
// isIe7: boolean;
// jQueryHtmlParse(html: string): any[];
// makeArray(arrayLikeObject: any): any[];
// moveCleanedNodesToContainerElement(nodes: any[]): HTMLElement;
// replaceDomNodes(nodeToReplaceOrNodeArray: any, newNodesArray: any[]): void;
// setDomNodeChildren(domNode: any, childNodes: any[]): void;
// setElementName(element: any, name: string): void;
// setOptionNodeSelectionState(optionNode: any, isSelected: boolean): void;
// simpleHtmlParse(html: string): any[];
// stringStartsWith(str: string, startsWith: string): boolean;
// stringTokenize(str: string, delimiter: string): string[];
// stringTrim(str: string): string;
// tagNameLower(element: any): string;
}
interface KnockoutArrayChange<T> {
status: string;
value: T;
index: number;
moved?: number;
}
//////////////////////////////////
// templateSources.js
//////////////////////////////////
interface KnockoutTemplateSourcesDomElement {
text(): any;
text(value: any): void;
data(key: string): any;
data(key: string, value: any): any;
}
interface KnockoutTemplateAnonymous extends KnockoutTemplateSourcesDomElement {
nodes(): any;
nodes(value: any): void;
}
interface KnockoutTemplateSources {
domElement: {
prototype: KnockoutTemplateSourcesDomElement
new (element: Element): KnockoutTemplateSourcesDomElement
};
anonymousTemplate: {
prototype: KnockoutTemplateAnonymous;
new (element: Element): KnockoutTemplateAnonymous;
};
}
//////////////////////////////////
// nativeTemplateEngine.js
//////////////////////////////////
interface KnockoutNativeTemplateEngine {
renderTemplateSource(templateSource: Object, bindingContext?: KnockoutBindingContext, options?: Object): any[];
}
//////////////////////////////////
// templateEngine.js
//////////////////////////////////
interface KnockoutTemplateEngine extends KnockoutNativeTemplateEngine {
createJavaScriptEvaluatorBlock(script: string): string;
makeTemplateSource(template: any, templateDocument?: Document): any;
renderTemplate(template: any, bindingContext: KnockoutBindingContext, options: Object, templateDocument: Document): any;
isTemplateRewritten(template: any, templateDocument: Document): boolean;
rewriteTemplate(template: any, rewriterCallback: Function, templateDocument: Document): void;
}
/////////////////////////////////
interface KnockoutStatic {
utils: KnockoutUtils;
memoization: KnockoutMemoization;
bindingHandlers: KnockoutBindingHandlers;
getBindingHandler(handler: string): KnockoutBindingHandler;
virtualElements: KnockoutVirtualElements;
extenders: KnockoutExtenders;
applyBindings(viewModelOrBindingContext?: any, rootNode?: any): void;
applyBindingsToDescendants(viewModelOrBindingContext: any, rootNode: any): void;
applyBindingAccessorsToNode(node: Node, bindings: (bindingContext: KnockoutBindingContext, node: Node) => {}, bindingContext: KnockoutBindingContext): void;
applyBindingAccessorsToNode(node: Node, bindings: {}, bindingContext: KnockoutBindingContext): void;
applyBindingAccessorsToNode(node: Node, bindings: (bindingContext: KnockoutBindingContext, node: Node) => {}, viewModel: any): void;
applyBindingAccessorsToNode(node: Node, bindings: {}, viewModel: any): void;
applyBindingsToNode(node: Node, bindings: any, viewModelOrBindingContext?: any): any;
subscribable: KnockoutSubscribableStatic;
observable: KnockoutObservableStatic;
computed: KnockoutComputedStatic;
pureComputed<T>(evaluatorFunction: () => T, context?: any): KnockoutComputed<T>;
pureComputed<T>(options: KnockoutComputedDefine<T>, context?: any): KnockoutComputed<T>;
observableArray: KnockoutObservableArrayStatic;
contextFor(node: any): any;
isSubscribable(instance: any): boolean;
toJSON(viewModel: any, replacer?: Function, space?: any): string;
toJS(viewModel: any): any;
isObservable(instance: any): boolean;
isWriteableObservable(instance: any): boolean;
isComputed(instance: any): boolean;
dataFor(node: any): any;
removeNode(node: Element): void;
cleanNode(node: Element): Element;
renderTemplate(template: Function, viewModel: any, options?: any, target?: any, renderMode?: any): any;
renderTemplate(template: string, viewModel: any, options?: any, target?: any, renderMode?: any): any;
unwrap<T>(value: KnockoutObservable<T> | T): T;
computedContext: KnockoutComputedContext;
//////////////////////////////////
// templateSources.js
//////////////////////////////////
templateSources: KnockoutTemplateSources;
//////////////////////////////////
// templateEngine.js
//////////////////////////////////
templateEngine: {
prototype: KnockoutTemplateEngine;
new (): KnockoutTemplateEngine;
};
//////////////////////////////////
// templateRewriting.js
//////////////////////////////////
templateRewriting: {
ensureTemplateIsRewritten(template: Node, templateEngine: KnockoutTemplateEngine, templateDocument: Document): any;
ensureTemplateIsRewritten(template: string, templateEngine: KnockoutTemplateEngine, templateDocument: Document): any;
memoizeBindingAttributeSyntax(htmlString: string, templateEngine: KnockoutTemplateEngine): any;
applyMemoizedBindingsToNextSibling(bindings: any, nodeName: string): string;
};
//////////////////////////////////
// nativeTemplateEngine.js
//////////////////////////////////
nativeTemplateEngine: {
prototype: KnockoutNativeTemplateEngine;
new (): KnockoutNativeTemplateEngine;
instance: KnockoutNativeTemplateEngine;
};
//////////////////////////////////
// jqueryTmplTemplateEngine.js
//////////////////////////////////
jqueryTmplTemplateEngine: {
prototype: KnockoutTemplateEngine;
renderTemplateSource(templateSource: Object, bindingContext: KnockoutBindingContext, options: Object): Node[];
createJavaScriptEvaluatorBlock(script: string): string;
addTemplate(templateName: string, templateMarkup: string): void;
};
//////////////////////////////////
// templating.js
//////////////////////////////////
setTemplateEngine(templateEngine: KnockoutNativeTemplateEngine): void;
renderTemplate(template: Function, dataOrBindingContext: KnockoutBindingContext, options: Object, targetNodeOrNodeArray: Node, renderMode: string): any;
renderTemplate(template: any, dataOrBindingContext: KnockoutBindingContext, options: Object, targetNodeOrNodeArray: Node, renderMode: string): any;
renderTemplate(template: Function, dataOrBindingContext: any, options: Object, targetNodeOrNodeArray: Node, renderMode: string): any;
renderTemplate(template: any, dataOrBindingContext: any, options: Object, targetNodeOrNodeArray: Node, renderMode: string): any;
renderTemplate(template: Function, dataOrBindingContext: KnockoutBindingContext, options: Object, targetNodeOrNodeArray: Node[], renderMode: string): any;
renderTemplate(template: any, dataOrBindingContext: KnockoutBindingContext, options: Object, targetNodeOrNodeArray: Node[], renderMode: string): any;
renderTemplate(template: Function, dataOrBindingContext: any, options: Object, targetNodeOrNodeArray: Node[], renderMode: string): any;
renderTemplate(template: any, dataOrBindingContext: any, options: Object, targetNodeOrNodeArray: Node[], renderMode: string): any;
renderTemplateForEach(template: Function, arrayOrObservableArray: any[], options: Object, targetNode: Node, parentBindingContext: KnockoutBindingContext): any;
renderTemplateForEach(template: any, arrayOrObservableArray: any[], options: Object, targetNode: Node, parentBindingContext: KnockoutBindingContext): any;
renderTemplateForEach(template: Function, arrayOrObservableArray: KnockoutObservable<any>, options: Object, targetNode: Node, parentBindingContext: KnockoutBindingContext): any;
renderTemplateForEach(template: any, arrayOrObservableArray: KnockoutObservable<any>, options: Object, targetNode: Node, parentBindingContext: KnockoutBindingContext): any;
expressionRewriting: {
bindingRewriteValidators: any;
parseObjectLiteral: { (objectLiteralString: string): any[] }
};
/////////////////////////////////
bindingProvider: {
instance: KnockoutBindingProvider;
new (): KnockoutBindingProvider;
}
/////////////////////////////////
// selectExtensions.js
/////////////////////////////////
selectExtensions: {
readValue(element: HTMLElement): any;
writeValue(element: HTMLElement, value: any): void;
};
components: KnockoutComponents;
}
interface KnockoutBindingProvider {
nodeHasBindings(node: Node): boolean;
getBindings(node: Node, bindingContext: KnockoutBindingContext): {};
getBindingAccessors?(node: Node, bindingContext: KnockoutBindingContext): { [key: string]: string; };
}
interface KnockoutComputedContext {
getDependenciesCount(): number;
isInitial: () => boolean;
isSleeping: boolean;
}
//
// refactored types into a namespace to reduce global pollution
// and used Union Types to simplify overloads (requires TypeScript 1.4)
//
declare module KnockoutComponentTypes {
interface Config {
viewModel?: ViewModelFunction | ViewModelSharedInstance | ViewModelFactoryFunction | AMDModule;
template: string | Node[]| DocumentFragment | TemplateElement | AMDModule;
synchronous?: boolean;
}
interface ComponentConfig {
viewModel?: ViewModelFunction | ViewModelSharedInstance | ViewModelFactoryFunction | AMDModule;
template: any;
createViewModel?: any;
}
interface EmptyConfig {
}
// common AMD type
interface AMDModule {
require: string;
}
// viewmodel types
interface ViewModelFunction {
(params?: any): any;
}
interface ViewModelSharedInstance {
instance: any;
}
interface ViewModelFactoryFunction {
createViewModel: (params?: any, componentInfo?: ComponentInfo) => any;
}
interface ComponentInfo {
element: Node;
templateNodes: Node[];
}
interface TemplateElement {
element: string | Node;
}
interface Loader {
getConfig? (componentName: string, callback: (result: ComponentConfig) => void): void;
loadComponent? (componentName: string, config: ComponentConfig, callback: (result: Definition) => void): void;
loadTemplate? (componentName: string, templateConfig: any, callback: (result: Node[]) => void): void;
loadViewModel? (componentName: string, viewModelConfig: any, callback: (result: any) => void): void;
suppressLoaderExceptions?: boolean;
}
interface Definition {
template: Node[];
createViewModel? (params: any, options: { element: Node; }): any;
}
}
interface KnockoutComponents {
// overloads for register method:
register(componentName: string, config: KnockoutComponentTypes.Config | KnockoutComponentTypes.EmptyConfig): void;
isRegistered(componentName: string): boolean;
unregister(componentName: string): void;
get(componentName: string, callback: (definition: KnockoutComponentTypes.Definition) => void): void;
clearCachedDefinition(componentName: string): void
defaultLoader: KnockoutComponentTypes.Loader;
loaders: KnockoutComponentTypes.Loader[];
getComponentNameForNode(node: Node): string;
}
declare var ko: KnockoutStatic;
declare module "knockout" {
export = ko;
}

View File

@ -0,0 +1,3 @@
/// <reference path="@ms/odsp.d.ts" />
/// <reference path="assertion-error/assertion-error.d.ts" />
/// <reference path="knockout/knockout.d.ts" />