// Do not initialize the search on browsers that lack web worker support if ('Worker'inwindow) { this.searchService.initWorker('app/search/search-worker.js'); this.searchService.loadIndex(); }
exportinterfaceDocumentContents { /** The unique identifier for this document */ id: string; /** The HTML to display in the doc viewer */ contents: string; } //========================================== currentDocument: DocumentContents;
ngOnInit(){ ... this.locationService.currentPath.subscribe(path => { if (path === this.currentPath) { // scroll only if on same page (most likely a change to the hash) this.autoScroll(); } else { // don't scroll; leave that to `onDocRendered` this.currentPath = path;
// Start progress bar if doc not rendered within brief time clearTimeout(this.isFetchingTimeout); this.isFetchingTimeout = setTimeout(() =>this.isFetching = true, 200); } }); ... } autoScroll() { this.scrollService.scroll(); }
監控瀏覽的狀態,細部的功能檢視會在看 navigationService 時研究
1 2 3 4 5 6 7 8
/** * A map of current nodes by view. * This is needed because some urls map to nodes in more than one view. * If a view does not contain a node that matches the current url then the value will be undefined. */ exportinterfaceCurrentNodes { [view: string]: CurrentNode; }
// Preserve current sidenav open state by default let openSideNav = this.sidenav.opened; // const sideNavView = 'SideNav'; const isSideNavDoc = !!currentNodes[sideNavView];
if (this.isSideNavDoc !== isSideNavDoc) { // View type changed. Is it now a sidenav view (e.g, guide or tutorial)? // Open if changed to a sidenav doc; close if changed to a marketing doc. openSideNav = this.isSideNavDoc = isSideNavDoc; } // May be open or closed when wide; always closed when narrow this.sideNavToggle(this.isSideBySide ? openSideNav : false); }); // Compute the version picker list from the current version and the versions in the navigation map combineLatest( this.navigationService.versionInfo.map(versionInfo => ({ title: versionInfo.raw, url: null })), this.navigationService.navigationViews.map(views => views['docVersions']), (currentVersion, otherVersions) => [currentVersion, ...otherVersions]) .subscribe(versions => { this.docVersions = versions; this.currentDocVersion = this.docVersions[0]; });
// Hide the search results if we clicked outside both the "search box" and the "search results" if (!this.searchElements.some(element => element.nativeElement.contains(eventTarget))) { this.hideSearchResults(); }
// Show developer source view if the footer is clicked while holding the meta and alt keys if (eventTarget.tagName === 'FOOTER' && metaKey && altKey) { this.dtOn = !this.dtOn; returnfalse; }
// Deal with anchor clicks; climb DOM tree until anchor found (or null) let target = eventTarget; while (target && !(target instanceofHTMLAnchorElement)) { target = target.parentElement; } if (target instanceofHTMLAnchorElement) { returnthis.locationService.handleAnchorClick(target, button, ctrlKey, metaKey); }
// Allow the click to pass through returntrue; }
監聽頁面上所有的 click事件
如果在 search box 外的地方點擊,會把搜尋結果的區塊隱藏起來。
win+alt+click on footer (1)的地方,會切換顯示/隱藏頁面內容的原始碼(2)
處理連結錨點
onDocRendered
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
onDocRendered() { // Stop fetching timeout (which, when render is fast, means progress bar never shown) clearTimeout(this.isFetchingTimeout);
// Put page in a clean visual state this.scrollService.scrollToTop();
// Scroll 500ms after the doc-viewer has finished rendering the new doc // The delay is to allow time for async layout to complete setTimeout(() => { this.autoScroll(); this.isStarting = false; this.isFetching = false; }, 500); }
// Dynamically change height of table of contents container @HostListener('window:scroll') onScroll() { if (!this.tocMaxHeightOffset) { // Must wait until now for md-toolbar to be measurable. const el = this.hostElement.nativeElementasElement; this.tocMaxHeightOffset = el.querySelector('footer').clientHeight + el.querySelector('md-toolbar.app-toolbar').clientHeight + 44; // margin }
// Restrain scrolling inside an element, when the cursor is over it restrainScrolling(evt: WheelEvent) { const elem = evt.currentTargetasElement; const scrollTop = elem.scrollTop;
if (evt.deltaY < 0) { // Trying to scroll up: Prevent scrolling if already at the top. if (scrollTop < 1) { evt.preventDefault(); } } else { // Trying to scroll down: Prevent scrolling if already at the bottom. const maxScrollTop = elem.scrollHeight - elem.clientHeight; if (maxScrollTop - scrollTop < 1) { evt.preventDefault(); } } }