@w11k/ngx-present
Version:
Angular based Presentation Tool
1,920 lines (1,909 loc) • 118 kB
JavaScript
import { CommonModule } from '@angular/common';
import { InjectionToken, Injectable, Injector, ɵɵdefineInjectable, ɵɵinject, INJECTOR, Directive, ElementRef, Optional, Input, Pipe, Component, ViewContainerRef, ComponentFactoryResolver, ViewChild, HostListener, ViewEncapsulation, TemplateRef, NgModule, isDevMode } from '@angular/core';
import { MatButtonModule } from '@angular/material/button';
import { MatCardModule } from '@angular/material/card';
import { MatDialog, MatDialogModule } from '@angular/material/dialog';
import { MatIconModule } from '@angular/material/icon';
import { MatListModule } from '@angular/material/list';
import { MatSidenav, MatSidenavModule } from '@angular/material/sidenav';
import { MatSlideToggleModule } from '@angular/material/slide-toggle';
import { MatToolbarModule } from '@angular/material/toolbar';
import { Router, RouterLinkWithHref, ActivatedRoute, RouterModule } from '@angular/router';
import { TyduxModule } from '@w11k/tydux-angular';
import { Title } from '@angular/platform-browser';
import { Commands, Facade } from '@w11k/tydux';
import { Observable, Subject, combineLatest, ReplaySubject, fromEvent, of, BehaviorSubject } from 'rxjs';
import { OnDestroyMixin, untilComponentDestroyed } from '@w11k/ngx-componentdestroyed';
import { skipNil, skipPropertyNil } from '@w11k/rx-ninja';
import { filter, takeUntil, take, map, withLatestFrom, delay, first, switchMap } from 'rxjs/operators';
/**
* @fileoverview added by tsickle
* Generated from: lib/core/utils.ts
* @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
/**
* @template T
* @param {?} list
* @return {?}
*/
function maxDepth(list) {
if (list.length === 0) {
return 0;
}
/**
* @param {?} value
* @param {?} currentDepth
* @return {?}
*/
function recursive(value, currentDepth) {
return value.reduce((/**
* @param {?} depth
* @param {?} val
* @return {?}
*/
(depth, val) => {
if (Array.isArray(val)) {
/** @type {?} */
const newDepth = recursive(val, currentDepth + 1);
return max(newDepth, depth);
}
return depth;
}), currentDepth + 1);
}
return recursive(list, 0);
}
/**
* @param {?} a
* @param {?} b
* @param {...?} c
* @return {?}
*/
function min(a, b, ...c) {
/** @type {?} */
const values = [a, b, ...c];
return values.reduce((/**
* @param {?} x
* @param {?} y
* @return {?}
*/
(x, y) => x > y ? y : x));
}
/**
* @param {?} a
* @param {?} b
* @param {...?} c
* @return {?}
*/
function max(a, b, ...c) {
/** @type {?} */
const values = [a, b, ...c];
return values.reduce((/**
* @param {?} x
* @param {?} y
* @return {?}
*/
(x, y) => x > y ? x : y));
}
/**
* @template T
* @param {?} value
* @param {?=} result
* @return {?}
*/
function flattenDeep(value, result = []) {
for (const element of value) {
if (Array.isArray(element)) {
flattenDeep(element, result);
}
else {
result.push(element);
}
}
return result;
}
/**
* @template T, U
* @param {?} level0
* @param {?} mapper
* @return {?}
*/
function mapDeep(level0, mapper) {
return level0.map((/**
* @param {?} level1
* @return {?}
*/
level1 => {
if (Array.isArray(level1)) {
return mapDeep(level1, mapper);
}
else {
return mapper(level1);
}
}));
}
/**
* @template T
* @param {?} list
* @param {?} predicate
* @return {?}
*/
function filterDeep(list, predicate) {
/** @type {?} */
const filtered = [];
list.forEach((/**
* @param {?} entry
* @return {?}
*/
entry => {
if (Array.isArray(entry)) {
/** @type {?} */
const nestedFiltered = filterDeep(entry, predicate);
if (nestedFiltered.length > 0) {
filtered.push(nestedFiltered);
}
}
else if (predicate(entry)) {
filtered.push(entry);
}
}));
return filtered;
}
/**
* @template S1, S2
* @param {?} s1
* @param {...?} sources
* @return {?}
*/
function mergeDeep(s1, ...sources) {
/** @type {?} */
const target = {};
/** @type {?} */
const s1AndSources = [s1, ...sources];
for (const source of s1AndSources) {
if (source === undefined) {
continue;
}
/** @type {?} */
const keys = Object.keys(source);
for (const key of keys) {
/** @type {?} */
const sourceVal = source[key];
/** @type {?} */
const targetVal = target[key];
/** @type {?} */
const targetIsObj = typeof targetVal === 'object' && Array.isArray(targetVal) === false;
/** @type {?} */
const sourceIsObj = typeof sourceVal === 'object' && Array.isArray(sourceVal) === false;
if (targetIsObj && sourceIsObj) {
/** @type {?} */
const merged = mergeDeep(targetVal, sourceVal);
target[key] = merged;
}
else if (source.hasOwnProperty(key)) {
target[key] = sourceVal;
}
}
}
return target;
}
/**
* @template T
* @param {?} list
* @return {?}
*/
function flattenDelayedWithAnimationFrame(list) {
/** @type {?} */
const flatList = flattenDeep(list);
/** @type {?} */
const observable = new Observable((/**
* @param {?} subscriber
* @return {?}
*/
(subscriber) => {
/** @type {?} */
const k = 5;
/** @type {?} */
let i = k;
/** @type {?} */
const next = (/**
* @return {?}
*/
() => {
subscriber.next(flatList.slice(0, i));
i = i + k;
if (i > flatList.length) {
cancelAnimationFrame(frame);
subscriber.complete();
}
else {
frame = requestAnimationFrame(next);
}
});
/** @type {?} */
let frame = requestAnimationFrame(next);
}));
return observable;
}
/**
* @template T
* @param {?} list
* @param {?} depth
* @return {?}
*/
function limitDepth(list, depth) {
if (depth === undefined || depth < 0) {
return list;
}
return recursive(list, depth);
/**
* @param {?} value
* @param {?} depth_
* @return {?}
*/
function recursive(value, depth_) {
if (depth_ === 0) {
return [];
}
return value
.map((/**
* @param {?} x
* @return {?}
*/
x => {
if (Array.isArray(x)) {
return recursive(x, depth_ - 1);
}
return x;
}))
.filter((/**
* @param {?} x
* @return {?}
*/
x => (Array.isArray(x) && x.length === 0) === false));
}
}
/**
* @fileoverview added by tsickle
* Generated from: lib/core/presentation.types.ts
* @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
class Slide {
/**
* @param {?} component
* @param {?} coordinates
* @param {?} index
*/
constructor(component, coordinates, index) {
this.component = component;
this.coordinates = coordinates;
this.index = index;
}
}
if (false) {
/** @type {?} */
Slide.prototype.component;
/** @type {?} */
Slide.prototype.coordinates;
/** @type {?} */
Slide.prototype.index;
}
/** @type {?} */
const ngxPresentDefaultConfig = {
sidebar: {
tableOfContent: {
enabled: true,
showCoordinates: (/** @type {?} */ (undefined)),
separator: (/** @type {?} */ (undefined)),
depth: (/** @type {?} */ (undefined))
}
},
tableOfContent: {
showCoordinates: false,
separator: ')',
depth: (/** @type {?} */ (undefined)),
},
coordinates: {
separator: '.'
},
title: {
separator: ' / '
},
navigation: {
overview: {
component: (/** @type {?} */ (undefined))
}
},
presenter: {
preview1: {
move: 1,
coordinatesToKeep: (/** @type {?} */ (undefined))
},
preview2: {
move: 2,
coordinatesToKeep: (/** @type {?} */ (undefined))
}
},
code: {
theme: (/** @type {?} */ ('dark'))
}
};
class PresentationState {
constructor() {
this.config = ngxPresentDefaultConfig;
this.slides = [];
this.sideBar = {
open: false,
expert: false,
settings: false
};
/** @type {?} */
const id = Math.random().toString(36).substr(2, 9);
/** @type {?} */
const chunks = id.match(/.{1,3}/g);
if (!chunks) {
throw new Error(`ID generation failed. Couldn't generate chunks from random string`);
}
this.id = chunks.join('-');
}
}
if (false) {
/** @type {?} */
PresentationState.prototype.id;
/** @type {?} */
PresentationState.prototype.config;
/** @type {?} */
PresentationState.prototype.slides;
/** @type {?} */
PresentationState.prototype.sideBar;
}
class PresentationCommands extends Commands {
constructor() {
super();
}
/**
* @param {?} slides
* @return {?}
*/
setSlides(slides) {
this.state.slides = slides;
}
/**
* @param {?} config
* @return {?}
*/
mergeConfig(config) {
this.state.config = mergeDeep(this.state.config, config);
}
/**
* @return {?}
*/
toggleSideBar() {
this.state.sideBar = Object.assign(Object.assign({}, this.state.sideBar), { open: !this.state.sideBar.open });
}
/**
* @return {?}
*/
closeSideBar() {
this.state.sideBar = Object.assign(Object.assign({}, this.state.sideBar), { open: false });
}
/**
* @return {?}
*/
openSideBar() {
this.state.sideBar = Object.assign(Object.assign({}, this.state.sideBar), { open: true });
}
/**
* @return {?}
*/
enableSideBarExpertMode() {
this.state.sideBar = Object.assign(Object.assign({}, this.state.sideBar), { expert: true, settings: true });
}
/**
* @param {?} id
* @return {?}
*/
setId(id) {
this.state.id = id;
}
/**
* @param {?} theme
* @return {?}
*/
setCodeTheme(theme) {
this.state.config = Object.assign(Object.assign({}, this.state.config), { code: Object.assign(Object.assign({}, this.state.config.code), { theme: theme }) });
}
}
/**
* @fileoverview added by tsickle
* Generated from: lib/core/presentation.functions.ts
* @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
/**
* @param {?} component
* @param {?} coordinates
* @param {?} index
* @return {?}
*/
function componentToSlide(component, coordinates, index) {
return new Slide(component, coordinates, index);
}
/**
* @param {?} components
* @param {?} coordinates
* @param {?} counter
* @return {?}
*/
function componentsToSlidesRecursive(components, coordinates, counter) {
if (Array.isArray(components)) {
return components.map((/**
* @param {?} x
* @param {?} i
* @return {?}
*/
(x, i) => {
/** @type {?} */
const newCoordinates = coordinates.slice();
newCoordinates.push(i + 1);
return componentsToSlidesRecursive(x, newCoordinates, counter);
}));
}
counter.index++;
return componentToSlide(components, coordinates, counter.index);
}
/**
* @param {?} slideComponents
* @return {?}
*/
function componentsToSlideTree(slideComponents) {
/** @type {?} */
const counter = {
index: -1
};
return slideComponents.map((/**
* @param {?} x
* @param {?} i
* @return {?}
*/
(x, i) => componentsToSlidesRecursive(x, [i + 1], counter)));
}
/**
* @fileoverview added by tsickle
* Generated from: lib/core/presentation.service.ts
* @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
/** @type {?} */
const NGX_PRESENT_CONFIG = new InjectionToken('NgxPresentConfig');
/** @type {?} */
const SLIDES = new InjectionToken('SLIDES');
class PresentationService extends Facade {
/**
* @param {?} injector
*/
constructor(injector) {
super('Presentation', new PresentationState(), new PresentationCommands());
// make mutate public
this.dispatch = this.commands;
/** @type {?} */
const slideComponents = injector.get(SLIDES);
/** @type {?} */
const config = injector.get(NGX_PRESENT_CONFIG);
/** @type {?} */
const slides = componentsToSlideTree(slideComponents);
this.commands.setSlides(slides);
this.commands.mergeConfig(config);
}
/**
* @param {?} event
* @return {?}
*/
toggleSideBar(event) {
if (event.altKey) {
this.commands.enableSideBarExpertMode();
}
this.commands.toggleSideBar();
}
}
PresentationService.decorators = [
{ type: Injectable, args: [{
providedIn: 'root'
},] }
];
/** @nocollapse */
PresentationService.ctorParameters = () => [
{ type: Injector }
];
/** @nocollapse */ PresentationService.ɵprov = ɵɵdefineInjectable({ factory: function PresentationService_Factory() { return new PresentationService(ɵɵinject(INJECTOR)); }, token: PresentationService, providedIn: "root" });
if (false) {
/** @type {?} */
PresentationService.prototype.dispatch;
}
/**
* @fileoverview added by tsickle
* Generated from: lib/core/title.service.ts
* @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
class AdvancedTitleService {
/**
* @param {?} title
* @param {?} presentation
*/
constructor(title, presentation) {
this.title = title;
this.presentation = presentation;
this.original = title.getTitle();
}
/**
* @param {?} newTitle
* @return {?}
*/
setTitle(newTitle) {
/** @type {?} */
const oldTitle = this.title.getTitle();
this.title.setTitle(newTitle);
this.lastReturnedUnset = ((/**
* @return {?}
*/
() => {
/** @type {?} */
const unset = (/**
* @return {?}
*/
() => {
if (this.lastReturnedUnset === unset) {
this.title.setTitle(oldTitle);
}
});
return unset;
}))();
return this.lastReturnedUnset;
}
/**
* @param {?} prefix
* @param {?=} separator
* @return {?}
*/
prefixTitle(prefix, separator = this.presentation.state.config.title.separator) {
return this.setTitle(prefix + separator + this.original);
}
}
AdvancedTitleService.decorators = [
{ type: Injectable, args: [{
providedIn: 'root'
},] }
];
/** @nocollapse */
AdvancedTitleService.ctorParameters = () => [
{ type: Title },
{ type: PresentationService }
];
/** @nocollapse */ AdvancedTitleService.ɵprov = ɵɵdefineInjectable({ factory: function AdvancedTitleService_Factory() { return new AdvancedTitleService(ɵɵinject(Title), ɵɵinject(PresentationService)); }, token: AdvancedTitleService, providedIn: "root" });
if (false) {
/**
* @type {?}
* @private
*/
AdvancedTitleService.prototype.lastReturnedUnset;
/**
* @type {?}
* @private
*/
AdvancedTitleService.prototype.original;
/**
* @type {?}
* @private
*/
AdvancedTitleService.prototype.title;
/**
* @type {?}
* @private
*/
AdvancedTitleService.prototype.presentation;
}
/**
* @fileoverview added by tsickle
* Generated from: lib/core/page-title.directive.ts
* @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
class PageTitleDirective {
/**
* @param {?} title
* @param {?} element
*/
constructor(title, element) {
this.title = title;
this.element = element;
}
/**
* @return {?}
*/
ngAfterViewInit() {
/** @type {?} */
const pageTitle = this.element.nativeElement.innerText;
this.unsetTitle = this.title.prefixTitle(pageTitle);
this.element.nativeElement.hidden = true;
}
/**
* @return {?}
*/
ngOnDestroy() {
if (this.unsetTitle) {
this.unsetTitle();
}
}
}
PageTitleDirective.decorators = [
{ type: Directive, args: [{
selector: '[ngxPresentPageTitle]'
},] }
];
/** @nocollapse */
PageTitleDirective.ctorParameters = () => [
{ type: AdvancedTitleService },
{ type: ElementRef }
];
if (false) {
/** @type {?} */
PageTitleDirective.prototype.unsetTitle;
/**
* @type {?}
* @private
*/
PageTitleDirective.prototype.title;
/**
* @type {?}
* @private
*/
PageTitleDirective.prototype.element;
}
/**
* @fileoverview added by tsickle
* Generated from: lib/core/event.service.ts
* @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
/**
* @param {?} event
* @return {?}
*/
function nonNavigationEvent(event) {
return noModifierPressed(event) && isNotEditable(event);
}
/**
* @param {?} event
* @return {?}
*/
function isNotEditable(event) {
/** @type {?} */
const srcElement = event.srcElement;
if (srcElement instanceof HTMLElement) {
/** @type {?} */
const tagName = srcElement.tagName;
if (tagName === 'INPUT' || tagName === 'TEXTAREA' || srcElement.isContentEditable) {
return false;
}
}
return true;
}
/**
* @param {?} event
* @return {?}
*/
function noModifierPressed(event) {
if (event.altKey || event.ctrlKey || event.shiftKey || event.metaKey) {
return false;
}
return true;
}
/**
* @abstract
*/
class KeyboardEventProcessor {
}
if (false) {
/**
* @abstract
* @param {?} events$
* @return {?}
*/
KeyboardEventProcessor.prototype.init = function (events$) { };
}
class ToggleSideNav {
/**
* @param {?} service
*/
constructor(service) {
this.service = service;
}
/**
* @param {?} events$
* @return {?}
*/
init(events$) {
events$
.pipe(filter(isNotEditable), filter((/**
* @param {?} event
* @return {?}
*/
event => !(event.ctrlKey || event.metaKey || event.shiftKey))),
// letter m
filter((/**
* @param {?} event
* @return {?}
*/
event => event.keyCode === 77)))
.subscribe((/**
* @param {?} event
* @return {?}
*/
event => {
event.preventDefault();
this.service.toggleSideBar(event);
}));
}
}
ToggleSideNav.decorators = [
{ type: Injectable }
];
/** @nocollapse */
ToggleSideNav.ctorParameters = () => [
{ type: PresentationService }
];
if (false) {
/**
* @type {?}
* @private
*/
ToggleSideNav.prototype.service;
}
/** @type {?} */
const KEYBOARD_EVENT_PROCESSOR_TOKEN = new InjectionToken('KEYBOARD_EVENT_PROCESSORS');
class EventService {
/**
* @param {?} injector
*/
constructor(injector) {
this.keyboardEvents$ = new Subject();
/** @type {?} */
const keyboardEventProcessors = injector.get(KEYBOARD_EVENT_PROCESSOR_TOKEN);
for (const processor of keyboardEventProcessors) {
processor.init(this.keyboardEvents$);
}
}
/**
* @param {?} event
* @return {?}
*/
processKeyboardEvent(event) {
// console.debug('EventService: emit keyboard event');
this.keyboardEvents$.next(event);
}
}
EventService.decorators = [
{ type: Injectable, args: [{
providedIn: 'root'
},] }
];
/** @nocollapse */
EventService.ctorParameters = () => [
{ type: Injector }
];
/** @nocollapse */ EventService.ɵprov = ɵɵdefineInjectable({ factory: function EventService_Factory() { return new EventService(ɵɵinject(INJECTOR)); }, token: EventService, providedIn: "root" });
if (false) {
/**
* @type {?}
* @private
*/
EventService.prototype.keyboardEvents$;
}
/**
* @fileoverview added by tsickle
* Generated from: lib/theming/table-of-content.ts
* @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
/** @type {?} */
const tableOfContentMetadataKey = Symbol('TableOfContentEntry');
/**
* @record
*/
function DecoratorMetadata() { }
if (false) {
/** @type {?} */
DecoratorMetadata.prototype.linkName;
}
// Decorator
/**
* @param {?} config
* @return {?}
*/
function TableOfContentEntry(config) {
return (/**
* @param {?} constructor
* @return {?}
*/
function (constructor) {
// TODO: get rid of cast to any, include proper Reflect typings
((/** @type {?} */ (Reflect))).defineMetadata(tableOfContentMetadataKey, config, constructor);
});
}
/**
* @param {?} slide
* @return {?}
*/
function tableOfContentMetadata(slide) {
/** @type {?} */
const decoratorMetadata = ((/** @type {?} */ (Reflect))).getMetadata(tableOfContentMetadataKey, slide.component);
return decoratorMetadata;
}
/**
* @param {?} slides
* @return {?}
*/
function tableOfContentSlides(slides) {
return slides.filter((/**
* @param {?} slide
* @return {?}
*/
slide => tableOfContentMetadata(slide) !== undefined));
}
/**
* @fileoverview added by tsickle
* Generated from: lib/slide-by-slide/slide-by-slide.functions.ts
* @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
/**
* @param {?} slides
* @param {?} currentSlide
* @param {?} move
* @param {?} coordinatesToKeep
* @param {?} coordinatesMaxDepth
* @return {?}
*/
function calculateCoordinates(slides, currentSlide, move, coordinatesToKeep, coordinatesMaxDepth) {
if (move === 0) {
return currentSlide;
}
if (coordinatesToKeep === undefined) {
return slides[currentSlide.index + move];
}
/** @type {?} */
const currentCoordinates = currentSlide.coordinates;
/** @type {?} */
const coordinatesToKeepAbs = coordinatesToKeepAbsolute(currentCoordinates, coordinatesToKeep);
/** @type {?} */
const newCoordinates = currentCoordinates.slice(0, coordinatesToKeepAbs);
if (move > 0 && coordinatesToKeepAbs < currentCoordinates.length) {
newCoordinates.push(currentCoordinates[coordinatesToKeepAbs] + move);
}
else if (move > 0) {
newCoordinates.push(move);
}
else if (move < 0 && currentCoordinates[coordinatesToKeepAbs + 1] !== undefined && currentCoordinates[coordinatesToKeepAbs + 1] > 1) {
newCoordinates.push(currentCoordinates[coordinatesToKeepAbs] + move + 1);
}
else if (move < 0 && coordinatesToKeepAbs < currentCoordinates.length) {
newCoordinates.push(max(1, currentCoordinates[coordinatesToKeepAbs] + move));
}
else if (move < 0) {
newCoordinates.push(1);
}
if (move < 0) {
while (newCoordinates.length <= coordinatesMaxDepth) {
newCoordinates.push(1);
}
}
/** @type {?} */
let arrayToSearchIn;
if (move >= 0) {
arrayToSearchIn = slides.slice(currentSlide.index + 1);
}
else {
arrayToSearchIn = slides.slice(0, currentSlide.index).reverse();
}
/** @type {?} */
const nextSlide = arrayToSearchIn.find((/**
* @param {?} slide
* @return {?}
*/
slide => {
/** @type {?} */
const compared = compareCoordinates(slide.coordinates, newCoordinates);
if (move < 0) {
return compared <= 0;
}
else {
return compared >= 0;
}
}));
return nextSlide;
}
/**
* @param {?} coordinates
* @param {?} coordinatesToKeepRelative
* @return {?}
*/
function coordinatesToKeepAbsolute(coordinates, coordinatesToKeepRelative) {
if (coordinatesToKeepRelative >= 0) {
return min(coordinatesToKeepRelative, coordinates.length);
}
return max(coordinates.length + coordinatesToKeepRelative, 0);
}
/** @type {?} */
const routerParamsCoordinatePrefix = 'coordinate-';
/**
* @param {?} routeParams
* @return {?}
*/
function routeParamsToCoordinate(routeParams) {
/** @type {?} */
const keys = Object.keys(routeParams);
/** @type {?} */
const coordinates = keys
.filter((/**
* @param {?} key
* @return {?}
*/
key => key.startsWith(routerParamsCoordinatePrefix)))
.map((/**
* @param {?} key
* @return {?}
*/
key => {
/** @type {?} */
const keyNumber = parseInt(key.substr(routerParamsCoordinatePrefix.length), 10);
return { key, keyNumber };
}))
.sort((/**
* @param {?} a
* @param {?} b
* @return {?}
*/
(a, b) => compareNumber(a.keyNumber, b.keyNumber)))
.map((/**
* @param {?} key
* @return {?}
*/
key => parseInt(routeParams[key.key], 10)));
return coordinates;
}
/**
* @param {?} a
* @param {?} b
* @return {?}
*/
function compareNumber(a, b) {
if (a !== undefined && b === undefined) {
return 1;
}
if (a === undefined && b !== undefined) {
return -1;
}
if (a === undefined && b === undefined) {
return 0;
}
if (a !== undefined && b !== undefined && a > b) {
return 1;
}
if (a !== undefined && b !== undefined && a < b) {
return -1;
}
return 0;
}
/**
* @param {?} c1
* @param {?} c2
* @return {?}
*/
function equalCoordinates(c1, c2) {
return compareCoordinates(c1, c2) === 0;
}
/**
* @param {?} c1
* @param {?} c2
* @return {?}
*/
function compareCoordinates(c1, c2) {
if (c1 === c2) {
return 0;
}
if (c1 === null || c1 === undefined) {
return -1;
}
if (c2 === null || c2 === undefined) {
return 1;
}
/** @type {?} */
const maxLength = max(c1.length, c2.length);
for (let i = 0; i < maxLength; i++) {
/** @type {?} */
const c1i = c1[i];
/** @type {?} */
const c2i = c2[i];
/** @type {?} */
const iResult = compareNumber(c1i, c2i);
if (iResult !== 0) {
return iResult;
}
}
return 0;
}
/**
* @param {?} slides
* @param {?} coordinates
* @return {?}
*/
function isValidCoordinate(slides, coordinates) {
if (coordinates.length === 0) {
return false;
}
/** @type {?} */
let current = slides;
for (const coordinate of coordinates) {
/** @type {?} */
const tooLow = coordinate < 1;
/** @type {?} */
const tooHigh = Array.isArray(current) && coordinate - 1 >= current.length;
if (tooLow || tooHigh) {
return false;
}
/** @type {?} */
const next = current[coordinate - 1];
if (Array.isArray(next)) {
current = next;
}
else {
current = [];
}
}
return true;
}
/**
* @param {?} coordinates
* @param {?} separator
* @param {?=} length
* @return {?}
*/
function coordinatesToString(coordinates, separator, length) {
return coordinates.slice(0, length).join(separator);
}
/**
* @param {?} slides
* @return {?}
*/
function coordinateToSlideMap(slides) {
/** @type {?} */
const map = {};
for (const slide of slides) {
/** @type {?} */
const index = coordinatesToString(slide.coordinates, '.');
map[index] = slide;
}
return map;
}
/**
* @fileoverview added by tsickle
* Generated from: lib/slide-by-slide/slide-by-slide.service.ts
* @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
class SlideBySlideState {
constructor() {
this.coordinatesMaxDepth = 0;
this.slides = [];
this.slideMap = {};
}
}
if (false) {
/** @type {?} */
SlideBySlideState.prototype.coordinatesMaxDepth;
/** @type {?} */
SlideBySlideState.prototype.slides;
/** @type {?} */
SlideBySlideState.prototype.slideMap;
/** @type {?} */
SlideBySlideState.prototype.currentSlide;
/** @type {?} */
SlideBySlideState.prototype.currentMode;
}
class SlideBySlideMutator extends Commands {
constructor() {
super();
}
/**
* @param {?} slide
* @return {?}
*/
setCurrentSlide(slide) {
this.state.currentSlide = slide;
}
/**
* @param {?} mode
* @return {?}
*/
setCurrentMode(mode) {
this.state.currentMode = mode;
}
/**
* @param {?} slides
* @return {?}
*/
setSlides(slides) {
this.state.coordinatesMaxDepth = maxDepth(slides);
this.state.slides = flattenDeep(slides);
this.state.slideMap = coordinateToSlideMap(this.state.slides);
}
}
class SlideBySlideService extends Facade {
/**
* @param {?} injector
* @param {?} presentation
* @param {?} router
*/
constructor(injector, presentation, router) {
super('SlideBySlide', new SlideBySlideState(), new SlideBySlideMutator());
this.presentation = presentation;
this.router = router;
this.onDestroy$ = new Subject();
this.presentation.select((/**
* @param {?} state
* @return {?}
*/
state => state.slides))
.pipe(takeUntil(this.onDestroy$))
.subscribe((/**
* @param {?} slides
* @return {?}
*/
slides => this.commands.setSlides(slides)));
}
/**
* @param {?} coordinatesToKeep
* @param {?=} mode
* @return {?}
*/
navigateToNext(coordinatesToKeep, mode) {
this.nextSlide(coordinatesToKeep)
.pipe(take(1))
.subscribe((/**
* @param {?} slide
* @return {?}
*/
slide => this.navigateAbsolute(slide, mode)));
}
/**
* @param {?} coordinatesToKeep
* @param {?=} mode
* @return {?}
*/
navigateToPrevious(coordinatesToKeep, mode) {
this.previousSlide(coordinatesToKeep)
.pipe(take(1))
.subscribe((/**
* @param {?} slide
* @return {?}
*/
slide => this.navigateAbsolute(slide, mode)));
}
/**
* @param {?} coordinatesToKeep
* @param {?=} prefix
* @return {?}
*/
previousSlide(coordinatesToKeep, prefix) {
return this.navigateRelative(-1, coordinatesToKeep);
}
/**
* @param {?} coordinatesToKeep
* @return {?}
*/
nextSlide(coordinatesToKeep) {
return this.navigateRelative(1, coordinatesToKeep);
}
/**
* @param {?=} mode
* @return {?}
*/
navigateToNextToc(mode) {
this.nextToc('forward')
.pipe(take(1))
.subscribe((/**
* @param {?} slide
* @return {?}
*/
slide => this.navigateAbsolute(slide, mode)));
}
/**
* @param {?=} mode
* @return {?}
*/
navigateToPreviousToc(mode) {
this.nextToc('backward')
.pipe(take(1))
.subscribe((/**
* @param {?} slide
* @return {?}
*/
slide => this.navigateAbsolute(slide, mode)));
}
/**
* @param {?} direction
* @return {?}
*/
nextToc(direction) {
/** @type {?} */
const currentSlide$ = this.select((/**
* @param {?} state
* @return {?}
*/
state => state.currentSlide))
.pipe(skipNil());
/** @type {?} */
const tocSlides$ = this.select((/**
* @param {?} state
* @return {?}
*/
state => state.slides))
.pipe(skipNil(), filter((/**
* @param {?} x
* @return {?}
*/
x => x.length !== 0)), map(tableOfContentSlides));
return combineLatest(currentSlide$, tocSlides$)
.pipe(map((/**
* @param {?} __0
* @return {?}
*/
([currentSlide, tocSlides]) => {
if (direction === 'forward') {
return tocSlides.find((/**
* @param {?} tocSlide
* @return {?}
*/
tocSlide => {
return compareCoordinates(tocSlide.coordinates, currentSlide.coordinates) === 1;
}));
}
else {
return tocSlides.slice().reverse().find((/**
* @param {?} tocSlide
* @return {?}
*/
tocSlide => {
return compareCoordinates(tocSlide.coordinates, currentSlide.coordinates) === -1;
}));
}
})));
}
/**
* @param {?} move
* @param {?} coordinatesToKeep
* @return {?}
*/
navigateRelative(move, coordinatesToKeep) {
/** @type {?} */
const currentSlide$ = this.select((/**
* @param {?} state
* @return {?}
*/
state => state.currentSlide))
.pipe(skipNil());
/** @type {?} */
const slides$ = this.select((/**
* @param {?} state
* @return {?}
*/
state => state.slides))
.pipe(skipNil(), filter((/**
* @param {?} x
* @return {?}
*/
x => x.length !== 0)));
/** @type {?} */
const depth$ = this.select((/**
* @param {?} state
* @return {?}
*/
state => state.coordinatesMaxDepth))
.pipe(skipNil());
return combineLatest(slides$, currentSlide$, depth$)
.pipe(map((/**
* @param {?} __0
* @return {?}
*/
([slides, current, depth]) => calculateCoordinates(slides, current, move, coordinatesToKeep, depth))));
}
/**
* @param {?} target
* @param {?=} mode
* @return {?}
*/
navigateAbsolute(target, mode) {
/** @type {?} */
let slide;
if (target instanceof Slide) {
slide = target;
}
else {
slide = this.state.slides.find((/**
* @param {?} x
* @return {?}
*/
x => equalCoordinates(target, x.coordinates)));
}
if (slide === undefined) {
return;
}
/** @type {?} */
let modeWithFallback;
if (mode !== undefined) {
modeWithFallback = mode;
}
else if (this.state.currentMode !== undefined) {
modeWithFallback = this.state.currentMode;
}
else {
modeWithFallback = 'slide';
}
/** @type {?} */
const link = [`/${modeWithFallback}`, ...slide.coordinates];
return this.router.navigate(link, { queryParamsHandling: 'merge' });
}
/**
* @param {?=} prefix
* @return {?}
*/
navigateToFirst(prefix) {
this.firstSlide()
.pipe(take(1), takeUntil(this.onDestroy$))
.subscribe((/**
* @param {?} slide
* @return {?}
*/
slide => this.navigateAbsolute(slide, prefix)));
}
/**
* @return {?}
*/
firstSlide() {
return this.select((/**
* @param {?} state
* @return {?}
*/
state => state.slides))
.pipe(skipNil(), filter((/**
* @param {?} slides
* @return {?}
*/
slides => slides.length > 0)), map((/**
* @param {?} slides
* @return {?}
*/
slides => slides[0])));
}
/**
* @param {?} coordinates
* @return {?}
*/
isValidCoordinate(coordinates) {
return this.presentation.select((/**
* @param {?} state
* @return {?}
*/
state => state.slides))
.pipe(skipNil(), filter((/**
* @param {?} slides
* @return {?}
*/
slides => slides.length > 0)), map((/**
* @param {?} slides
* @return {?}
*/
slides => isValidCoordinate(slides, coordinates))));
}
/**
* @private
* @param {?} coordinates
* @return {?}
*/
coordinatesToSlide(coordinates) {
return this.state.slideMap[coordinates.join('.')];
}
/**
* @param {?} route
* @return {?}
*/
setCurrentModeAndSlide(route) {
/** @type {?} */
const coordinates = routeParamsToCoordinate(route.params);
/** @type {?} */
const mode = (/** @type {?} */ (route.url[0].path));
/** @type {?} */
const slide = this.coordinatesToSlide(coordinates);
this.commands.setCurrentSlide(slide);
this.commands.setCurrentMode(mode);
}
/**
* @return {?}
*/
ngOnDestroy() {
this.onDestroy$.next();
}
}
SlideBySlideService.decorators = [
{ type: Injectable, args: [{
providedIn: 'root'
},] }
];
/** @nocollapse */
SlideBySlideService.ctorParameters = () => [
{ type: Injector },
{ type: PresentationService },
{ type: Router }
];
/** @nocollapse */ SlideBySlideService.ɵprov = ɵɵdefineInjectable({ factory: function SlideBySlideService_Factory() { return new SlideBySlideService(ɵɵinject(INJECTOR), ɵɵinject(PresentationService), ɵɵinject(Router)); }, token: SlideBySlideService, providedIn: "root" });
if (false) {
/**
* @type {?}
* @private
*/
SlideBySlideService.prototype.onDestroy$;
/**
* @type {?}
* @private
*/
SlideBySlideService.prototype.presentation;
/**
* @type {?}
* @private
*/
SlideBySlideService.prototype.router;
}
class NavigateSectionForward {
/**
* @param {?} service
*/
constructor(service) {
this.service = service;
}
/**
* @param {?} events$
* @return {?}
*/
init(events$) {
events$
.pipe(filter(isNotEditable),
// arrow down + alt || arrow right + alt
filter((/**
* @param {?} event
* @return {?}
*/
event => {
if (event.keyCode === 40 && event.altKey) {
return true;
}
else if (event.keyCode === 39 && event.altKey) {
return true;
}
return false;
})))
.subscribe((/**
* @return {?}
*/
() => {
this.service.navigateToNextToc();
}));
}
}
NavigateSectionForward.decorators = [
{ type: Injectable }
];
/** @nocollapse */
NavigateSectionForward.ctorParameters = () => [
{ type: SlideBySlideService }
];
if (false) {
/**
* @type {?}
* @private
*/
NavigateSectionForward.prototype.service;
}
class NavigateSlideForward {
/**
* @param {?} service
*/
constructor(service) {
this.service = service;
}
/**
* @param {?} events$
* @return {?}
*/
init(events$) {
events$
.pipe(filter(nonNavigationEvent),
// arrow down, arrow right, or page down
filter((/**
* @param {?} event
* @return {?}
*/
event => event.keyCode === 40 || event.keyCode === 39 || event.keyCode === 34)))
.subscribe((/**
* @return {?}
*/
() => {
this.service.navigateToNext(-1);
}));
}
}
NavigateSlideForward.decorators = [
{ type: Injectable }
];
/** @nocollapse */
NavigateSlideForward.ctorParameters = () => [
{ type: SlideBySlideService }
];
if (false) {
/**
* @type {?}
* @private
*/
NavigateSlideForward.prototype.service;
}
class NavigateSectionBackward {
/**
* @param {?} service
*/
constructor(service) {
this.service = service;
}
/**
* @param {?} events$
* @return {?}
*/
init(events$) {
events$
.pipe(filter(isNotEditable),
// arrow up + alt || arrow left + alt
filter((/**
* @param {?} event
* @return {?}
*/
event => {
if (event.keyCode === 38 && event.altKey) {
return true;
}
else if (event.keyCode === 37 && event.altKey) {
return true;
}
return false;
})))
.subscribe((/**
* @return {?}
*/
() => {
this.service.navigateToPreviousToc();
}));
}
}
NavigateSectionBackward.decorators = [
{ type: Injectable }
];
/** @nocollapse */
NavigateSectionBackward.ctorParameters = () => [
{ type: SlideBySlideService }
];
if (false) {
/**
* @type {?}
* @private
*/
NavigateSectionBackward.prototype.service;
}
class NavigateSlideBackward {
/**
* @param {?} service
*/
constructor(service) {
this.service = service;
}
/**
* @param {?} events$
* @return {?}
*/
init(events$) {
events$
.pipe(filter(nonNavigationEvent),
// arrow up, arrow left or page up
filter((/**
* @param {?} event
* @return {?}
*/
event => event.keyCode === 38 || event.keyCode === 37 || event.keyCode === 33)))
.subscribe((/**
* @return {?}
*/
() => {
this.service.navigateToPrevious(-1);
}));
}
}
NavigateSlideBackward.decorators = [
{ type: Injectable }
];
/** @nocollapse */
NavigateSlideBackward.ctorParameters = () => [
{ type: SlideBySlideService }
];
if (false) {
/**
* @type {?}
* @private
*/
NavigateSlideBackward.prototype.service;
}
class NavigateToFirstSlide {
/**
* @param {?} service
*/
constructor(service) {
this.service = service;
}
/**
* @param {?} events$
* @return {?}
*/
init(events$) {
events$
.pipe(filter(nonNavigationEvent),
// pos 1
filter((/**
* @param {?} event
* @return {?}
*/
event => event.keyCode === 36)))
.subscribe((/**
* @return {?}
*/
() => {
this.service.navigateToFirst();
}));
}
}
NavigateToFirstSlide.decorators = [
{ type: Injectable }
];
/** @nocollapse */
NavigateToFirstSlide.ctorParameters = () => [
{ type: SlideBySlideService }
];
if (false) {
/**
* @type {?}
* @private
*/
NavigateToFirstSlide.prototype.service;
}
class NavigateToOverview {
/**
* @param {?} service
* @param {?} presentation
*/
constructor(service, presentation) {
this.service = service;
this.presentation = presentation;
}
/**
* @param {?} events$
* @return {?}
*/
init(events$) {
/** @type {?} */
const config$ = this.presentation.select((/**
* @param {?} state
* @return {?}
*/
state => state.config.navigation.overview))
.pipe(skipPropertyNil('component'));
/** @type {?} */
const slide$ = this.service.select()
.pipe(withLatestFrom(config$), map((/**
* @param {?} __0
* @return {?}
*/
([state, config]) => state.slides.find((/**
* @param {?} slide
* @return {?}
*/
slide => slide.component === config.component)))));
events$
.pipe(filter(nonNavigationEvent),
// pos 1
filter((/**
* @param {?} event
* @return {?}
*/
event => {
// o
return event.keyCode === 79;
})), withLatestFrom(slide$))
.subscribe((/**
* @param {?} __0
* @return {?}
*/
([event, slide]) => {
this.service.navigateAbsolute(slide);
}));
}
}
NavigateToOverview.decorators = [
{ type: Injectable }
];
/** @nocollapse */
NavigateToOverview.ctorParameters = () => [
{ type: SlideBySlideService },
{ type: PresentationService }
];
if (false) {
/**
* @type {?}
* @private
*/
NavigateToOverview.prototype.service;
/**
* @type {?}
* @private
*/
NavigateToOverview.prototype.presentation;
}
class TogglePresenter {
/**
* @param {?} service
* @param {?} router
*/
constructor(service, router) {
this.service = service;
this.router = router;
}
/**
* @param {?} events$
* @return {?}
*/
init(events$) {
/** @type {?} */
const slide$ = this.service.select();
events$
.pipe(filter(isNotEditable),
// letter p
filter((/**
* @param {?} event
* @return {?}
*/
event => event.keyCode === 80 && event.altKey)), withLatestFrom(slide$))
.subscribe((/**
* @param {?} __0
* @return {?}
*/
([event, state]) => {
/** @type {?} */
let mode;
if (state.currentMode === 'presenter') {
mode = 'slide';
}
else {
mode = 'presenter';
}
/** @type {?} */
let coordinates = [];
if (state.currentSlide !== undefined) {
coordinates = state.currentSlide.coordinates;
}
/** @type {?} */
const link = [mode, ...coordinates];
this.router.navigate(link, { queryParamsHandling: 'merge' });
}));
}
}
TogglePresenter.decorators = [
{ type: Injectable }
];
/** @nocollapse */
TogglePresenter.ctorParameters = () => [
{ type: SlideBySlideService },
{ type: Router }
];
if (false) {
/**
* @type {?}
* @private
*/
TogglePresenter.prototype.service;
/**
* @type {?}
* @private
*/
TogglePresenter.prototype.router;
}
/**
* @fileoverview added by tsickle
* Generated from: lib/core/slide-link.directive.ts
* @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
/**
* @param {?} event
* @return {?}
*/
function isMouseEvent(event) {
return event instanceof MouseEvent;
}
/**
* Use in conjunction with routerLink on an anchor tag for real links.
* Use on any tag for click event handling.
*/
class SlideLinkDirective extends OnDestroyMixin {
/**
* @param {?} service
* @param {?} router
* @param {?} element
* @param {?} routerLinkDirective
*/
constructor(service, router, element, routerLinkDirective) {
super();
this.service = service;
this.router = router;
this.element = element;
this.routerLinkDirective = routerLinkDirective;
this.slide$ = new ReplaySubject(1);
if (routerLinkDirective) {
this.slide$
.pipe(untilComponentDestroyed(this))
.subscribe((/**
* @param {?} slide
* @return {?}
*/
slide => {
/** @type {?} */
let link;
if (slide) {
/** @type {?} */
const mode = `/${this.service.state.currentMode}`;
link = ([mode, ...slide.coordinates]);
}
else {
link = [];
}
this.routerLinkDirective.routerLink = link;
// update href on link
this.routerLinkDirective.ngOnChanges({});
}));
}
fromEvent(element.nativeElement, 'click')
.pipe(filter(isMouseEvent), filter((/**
* @param {?} event
* @return {?}
*/
event => event.altKey)), withLatestFrom(this.slide$), untilComponentDestroyed(this))
.subscribe((/**
* @param {?} __0
* @return {?}
*/
([event, slide]) => {
event.preventDefault();
/** @type {?} */
const link = (['/presenter', ...slide.coordinates]);
this.router.navigate(link, { queryParamsHandling: 'merge' });
}));
}
/**
* @param {?} component
* @return {?}
*/
set ngxPresentSlideLink(component) {
this.service.select(((/**
* @param {?} state
* @return {?}
*/
state => state.slides)))
.pipe(skipNil(), untilComponentDestroyed(this))
.pipe(map((/**
* @param {?} slides
* @return {?}
*/
slide