Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ env:
- CI_MODE=browserstack_required
- CI_MODE=saucelabs_optional
- CI_MODE=browserstack_optional
- CI_MODE=docs_test

matrix:
fast_finish: true
Expand Down
44 changes: 44 additions & 0 deletions docs/src/app/app.component.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/*
Copyright 2016 Google Inc. All Rights Reserved.
Use of this source code is governed by an MIT-style license that
can be found in the LICENSE file at http://angular.io/license
*/

import {Component, OnInit, NgZone } from '@angular/core';
import {FormControl, ReactiveFormsModule} from '@angular/forms';
import {Observable} from 'rxjs/Observable';
import 'rxjs/add/operator/do';
import 'rxjs/add/operator/switchMap';
import {QueryResults, SearchWorkerClient} from './search-worker-client';


@Component({
selector: 'my-app',
template: `
<h1>Angular Docs Search</h1>
<div class="search-bar"><input [formControl]="searchInput"></div>
<div class="search-results">
<div *ngIf="!(indexReady | async)">Waiting...</div>
<ul>
<li *ngFor="let result of (searchResult$ | async)">
<a href="{{result.path}}">{{ result.title }} ({{result.type}})</a>
</li>
</ul>
</div>
`
})
export class AppComponent implements OnInit {
searchResult$: Observable<QueryResults>;
indexReady: Promise<boolean>;
searchInput: FormControl;

constructor(private zone: NgZone) {}

ngOnInit() {
const searchWorker = new SearchWorkerClient('app/search-worker.js', this.zone);
this.indexReady = searchWorker.ready;
this.searchInput = new FormControl();
this.searchResult$ = this.searchInput.valueChanges
.switchMap((searchText: string) => searchWorker.search(searchText));
}
}
21 changes: 21 additions & 0 deletions docs/src/app/main.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/*
Copyright 2016 Google Inc. All Rights Reserved.
Use of this source code is governed by an MIT-style license that
can be found in the LICENSE file at http://angular.io/license
*/
import {platformBrowserDynamic} from '@angular/platform-browser-dynamic';
import {NgModule} from '@angular/core';
import {BrowserModule} from '@angular/platform-browser';
import {ReactiveFormsModule} from '@angular/forms';
import {AppComponent} from 'app/app.component';

@NgModule({
imports: [ BrowserModule, ReactiveFormsModule ],
declarations: [ AppComponent ],
bootstrap: [ AppComponent ]
})
class AppModule {

}

platformBrowserDynamic().bootstrapModule(AppModule);
97 changes: 97 additions & 0 deletions docs/src/app/search-worker-client.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
/*
Copyright 2016 Google Inc. All Rights Reserved.
Use of this source code is governed by an MIT-style license that
can be found in the LICENSE file at http://angular.io/license
*/

import {NgZone} from '@angular/core';
import {Observable} from 'rxjs/Observable';
import {Subscriber} from 'rxjs/Subscriber';
import 'rxjs/add/observable/fromPromise';
import 'rxjs/add/observable/of';
import 'rxjs/add/operator/switchMap';


export interface QueryResults {}

export interface ResultsReadyMessage {
type: 'query-results';
id: number;
query: string;
results: QueryResults;
}

export class SearchWorkerClient {
ready: Promise<boolean>;
worker: Worker;
private _queryId = 0;

constructor(url: string, private zone: NgZone) {
this.worker = new Worker(url);
this.ready = this._waitForIndex(this.worker);
}

search(query: string) {
return Observable.fromPromise(this.ready)
.switchMap(() => this._createQuery(query));
}

private _waitForIndex(worker: Worker) {
return new Promise((resolve, reject) => {

worker.onmessage = (e) => {
if(e.data.type === 'index-ready') {
resolve(true);
cleanup();
}
};

worker.onerror = (e) => {
reject(e);
cleanup();
};
});

function cleanup() {
worker.onmessage = null;
worker.onerror = null;
}
}

private _createQuery(query: string) {
return new Observable<QueryResults>((subscriber: Subscriber<QueryResults>) => {

// get a new identifier for this query that we can match to results
const id = this._queryId++;

const handleMessage = (message: MessageEvent) => {
const {type, id: queryId, results} = message.data as ResultsReadyMessage;
if (type === 'query-results' && id === queryId) {
this.zone.run(() => {
subscriber.next(results);
subscriber.complete();
});
}
};

const handleError = (error: ErrorEvent) => {
this.zone.run(() => {
subscriber.error(error);
});
};

// Wire up the event listeners for this query
this.worker.addEventListener('message', handleMessage);
this.worker.addEventListener('error', handleError);

// Post the query to the web worker
this.worker.postMessage({query, id});

// At completion/error unwire the event listeners
return () => {
this.worker.removeEventListener('message', handleMessage);
this.worker.removeEventListener('error', handleError);
};
});
}
}
63 changes: 63 additions & 0 deletions docs/src/app/search-worker.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
'use strict';

/* eslint-env worker */
/* global importScripts, lunr */

importScripts('https://unpkg.com/lunr@0.7.2');

var index = createIndex();
var pages = {};

makeRequest('search-data.json', loadIndex);

self.onmessage = handleMessage;

// Create the lunr index - the docs should be an array of objects, each object containing
// the path and search terms for a page
function createIndex() {
return lunr(/** @this */function() {
this.ref('path');
this.field('titleWords', {boost: 50});
this.field('members', {boost: 40});
this.field('keywords', {boost: 20});
});
}


// Use XHR to make a request to the server
function makeRequest(url, callback) {
var searchDataRequest = new XMLHttpRequest();
searchDataRequest.onload = function() {
callback(JSON.parse(this.responseText));
};
searchDataRequest.open('GET', url);
searchDataRequest.send();
}


// Create the search index from the searchInfo which contains the information about each page to be indexed
function loadIndex(searchInfo) {
// Store the pages data to be used in mapping query results back to pages
// Add search terms from each page to the search index
searchInfo.forEach(function(page) {
index.add(page);
pages[page.path] = page;
});
self.postMessage({type: 'index-ready'});
}


// The worker receives a message everytime the web app wants to query the index
function handleMessage(message) {
var id = message.data.id;
var query = message.data.query;
var results = queryIndex(query);
self.postMessage({type: 'query-results', id: id, query: query, results: results});
}


// Query the index and return the processed results
function queryIndex(query) {
// Only return the array of paths to pages
return index.search(query).map(function(hit) { return pages[hit.ref]; });
}
30 changes: 30 additions & 0 deletions docs/src/app/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
{
"compilerOptions": {
"baseUrl": ".",
"declaration": true,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"module": "commonjs",
"moduleResolution": "node",
"outDir": "../dist/tools/",
"noImplicitAny": true,
"noFallthroughCasesInSwitch": true,
"paths": {
},
"rootDir": ".",
"sourceMap": true,
"inlineSources": true,
"lib": ["es6", "dom"],
"target": "es5",
"skipLibCheck": true,
"typeRoots": [
"../../../node_modules"
]
},
"exclude": [
"node_modules",
"typings-test",
"public_api_guard",
"docs"
]
}
28 changes: 28 additions & 0 deletions docs/src/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<!DOCTYPE html>
<html>
<head>
<title>Hello Angular</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<style>
body {color:#369;font-family: Arial,Helvetica,sans-serif;}
</style>

<!-- Polyfills for older browsers -->
<script src="https://unpkg.com/core-js/client/shim.min.js"></script>

<script src="https://unpkg.com/zone.js@0.7.2?main=browser"></script>
<script src="https://unpkg.com/reflect-metadata@0.1.8"></script>
<script src="https://unpkg.com/systemjs@0.19.39/dist/system.src.js"></script>

<script src="systemjs.config.web.js"></script>
<script>
System.import('app').catch(function(err){ console.error(err); });
</script>
</head>

<body>
<my-app>Loading AppComponent content here ...</my-app>
</body>

</html>
64 changes: 64 additions & 0 deletions docs/src/systemjs.config.web.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
/*
Copyright 2016 Google Inc. All Rights Reserved.
Use of this source code is governed by an MIT-style license that
can be found in the LICENSE file at http://angular.io/license
*/

System.config({
// DEMO ONLY! REAL CODE SHOULD NOT TRANSPILE IN THE BROWSER
transpiler: 'ts',
typescriptOptions: {
// Copy of compiler options in standard tsconfig.json
"target": "es5",
"module": "commonjs",
"moduleResolution": "node",
"sourceMap": true,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"noImplicitAny": true,
"suppressImplicitAnyIndexErrors": true
},
meta: {
'typescript': {
"exports": "ts"
}
},
paths: {
// paths serve as alias
'npm:': 'https://unpkg.com/'
},
// map tells the System loader where to look for things
map: {
// our app is within the app folder
app: 'app',

// angular bundles
'@angular/core': 'npm:@angular/core/bundles/core.umd.js',
'@angular/common': 'npm:@angular/common/bundles/common.umd.js',
'@angular/compiler': 'npm:@angular/compiler/bundles/compiler.umd.js',
'@angular/platform-browser': 'npm:@angular/platform-browser/bundles/platform-browser.umd.js',
'@angular/platform-browser-dynamic': 'npm:@angular/platform-browser-dynamic/bundles/platform-browser-dynamic.umd.js',
'@angular/http': 'npm:@angular/http/bundles/http.umd.js',
'@angular/router': 'npm:@angular/router/bundles/router.umd.js',
'@angular/forms': 'npm:@angular/forms/bundles/forms.umd.js',
'@angular/upgrade': 'npm:@angular/upgrade/bundles/upgrade.umd.js',
'@angular/upgrade/static': 'npm:@angular/upgrade/bundles/upgrade-static.umd.js',

// other libraries
'rxjs': 'npm:rxjs',
'angular-in-memory-web-api': 'npm:angular-in-memory-web-api/bundles/in-memory-web-api.umd.js',
'ts': 'npm:plugin-typescript@4.0.10/lib/plugin.js',
'typescript': 'npm:typescript@2.0.3/lib/typescript.js',

},
// packages tells the System loader how to load when no filename and/or no extension
packages: {
app: {
main: './main.ts',
defaultExtension: 'ts'
},
rxjs: {
defaultExtension: 'js'
}
}
});
15 changes: 15 additions & 0 deletions docs/templates/api-list-audit.template.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
[{% for module, items in doc.data %}
{% for item in items %}
{
"title": "{$ item.title $}",
"path": "{$ item.exportDoc.path $}",
"docType": "{$ item.docType $}",
"stability": "{$ item.stability $}",
"secure": "{$ item.security $}",
"howToUse": "{$ item.howToUse | replace('"','\\"') $}",
"whatItDoes": {% if item.whatItDoes %}"Exists"{% else %}"Not Done"{% endif %},
"barrel" : "{$ module | replace("/index", "") $}"
}{% if not loop.last %},{% endif %}
{% endfor %}
{% endfor %}
]
14 changes: 14 additions & 0 deletions docs/templates/api-list-data.template.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
{%- for module, items in doc.data %}
"{$ module | replace("/index", "") $}" : [{% for item in items %}
{
"title": "{$ item.title $}",
"path": "{$ item.exportDoc.path $}",
"docType": "{$ item.docType $}",
"stability": "{$ item.stability $}",
"secure": "{$ item.security $}",
"barrel" : "{$ module | replace("/index", "") $}"
}{% if not loop.last %},{% endif %}
{% endfor %}]{% if not loop.last %},{% endif %}
{% endfor -%}
}
Loading