Added files to make classes better accessible.
This commit is contained in:
		
							parent
							
								
									78108c4090
								
							
						
					
					
						commit
						17bbe1a90e
					
				
							
								
								
									
										1274
									
								
								dist/iwmlib.js
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1274
									
								
								dist/iwmlib.js
									
									
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@ -19,9 +19,11 @@ import { ITapDelegate, ResizeEvent, DOMScatterContainer, AbstractScatter, DOMSca
 | 
				
			|||||||
import { Cycle, Colors, Elements, Angle, Dates, Points, Polygon, Rect, Sets, Strings, isEmpty, getId, lerp, debounce, randomInt, randomFloat, LowPassFilter } from './utils.js'
 | 
					import { Cycle, Colors, Elements, Angle, Dates, Points, Polygon, Rect, Sets, Strings, isEmpty, getId, lerp, debounce, randomInt, randomFloat, LowPassFilter } from './utils.js'
 | 
				
			||||||
import UITest from './uitest.js'
 | 
					import UITest from './uitest.js'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import Card from './card/card.js'
 | 
				
			||||||
import CardWrapper from './card/wrapper.js'
 | 
					import CardWrapper from './card/wrapper.js'
 | 
				
			||||||
import Highlight from './card/highlight.js'
 | 
					import Highlight from './card/highlight.js'
 | 
				
			||||||
import {Card, ScatterCard} from './card/card.js'
 | 
					import ScatterCard from './card/card.js'
 | 
				
			||||||
 | 
					import { CardPlugin, CardPluginBase } from './card/plugin.js'
 | 
				
			||||||
import Theme from './card/theme.js'
 | 
					import Theme from './card/theme.js'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Needed to ensure that rollup.js includes class definitions and the classes
 | 
					/* Needed to ensure that rollup.js includes class definitions and the classes
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										679
									
								
								lib/card/card.js
									
									
									
									
									
								
							
							
						
						
									
										679
									
								
								lib/card/card.js
									
									
									
									
									
								
							@ -29,7 +29,7 @@ const enableNearestNeighborTaps = false
 | 
				
			|||||||
 *
 | 
					 *
 | 
				
			||||||
 * The class is used as a namespace and should never called with new.
 | 
					 * The class is used as a namespace and should never called with new.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
export class Card {
 | 
					export default class Card {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    static setup(context, modules = []) {
 | 
					    static setup(context, modules = []) {
 | 
				
			||||||
        console.log("Setup Card...", modules)
 | 
					        console.log("Setup Card...", modules)
 | 
				
			||||||
@ -1883,680 +1883,3 @@ Card.animation = {
 | 
				
			|||||||
    zoomable: 0.5
 | 
					    zoomable: 0.5
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					 | 
				
			||||||
 * Extends the card with scatter functionality.
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * @class ScatterCard
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
export class ScatterCard extends Card {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /**
 | 
					 | 
				
			||||||
     * TODO: Find a more suitable name.
 | 
					 | 
				
			||||||
     * Adjusts the HTML to work in the new context.
 | 
					 | 
				
			||||||
     *
 | 
					 | 
				
			||||||
     * @static
 | 
					 | 
				
			||||||
     * @param {*} domElement
 | 
					 | 
				
			||||||
     * @param {*} htmlString
 | 
					 | 
				
			||||||
     * @param {*} basePath
 | 
					 | 
				
			||||||
     * @param {*} [opts={}]
 | 
					 | 
				
			||||||
     * @memberof Card
 | 
					 | 
				
			||||||
     */
 | 
					 | 
				
			||||||
    static setup(context, htmlString, {
 | 
					 | 
				
			||||||
        basePath = "./",
 | 
					 | 
				
			||||||
        modules = []
 | 
					 | 
				
			||||||
    } = {}) {
 | 
					 | 
				
			||||||
        context.classList.add("info-card")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        this.relativePath = basePath
 | 
					 | 
				
			||||||
        htmlString = this._adjustRelativeLinks(htmlString)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        let parser = new DOMParser()
 | 
					 | 
				
			||||||
        let html = parser.parseFromString(htmlString, "text/html")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        /**
 | 
					 | 
				
			||||||
         * Conflicts with the FindTarget method of the Abstract scatter.
 | 
					 | 
				
			||||||
         */
 | 
					 | 
				
			||||||
        this._replaceAttributes(html, "onclick", this._replaceCallback)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        let content = html.querySelector(".mainview")
 | 
					 | 
				
			||||||
        context.appendChild(content)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        super.setup(context, modules)
 | 
					 | 
				
			||||||
        return context
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /**
 | 
					 | 
				
			||||||
     * Appends a close listener to the scatter element.
 | 
					 | 
				
			||||||
     *
 | 
					 | 
				
			||||||
     * @static
 | 
					 | 
				
			||||||
     * @param {*} element
 | 
					 | 
				
			||||||
     * @param {*} callback
 | 
					 | 
				
			||||||
     * @memberof Card
 | 
					 | 
				
			||||||
     */
 | 
					 | 
				
			||||||
    static addOnCloseListener(element, callback) {
 | 
					 | 
				
			||||||
        if (callback) {
 | 
					 | 
				
			||||||
            element.onClose = callback
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /**
 | 
					 | 
				
			||||||
     * Creates a scatter for the card and applies the card to it,
 | 
					 | 
				
			||||||
     *
 | 
					 | 
				
			||||||
     * @static
 | 
					 | 
				
			||||||
     * @param {*} html
 | 
					 | 
				
			||||||
     * @param {*} scatterContainer
 | 
					 | 
				
			||||||
     * @param {string} [basePath=""]
 | 
					 | 
				
			||||||
     * @param {*} [opts={}]
 | 
					 | 
				
			||||||
     * @returns
 | 
					 | 
				
			||||||
     * @memberof Card
 | 
					 | 
				
			||||||
     */
 | 
					 | 
				
			||||||
    static createCardScatter(html, scatterContainer, {
 | 
					 | 
				
			||||||
        basePath = "./",
 | 
					 | 
				
			||||||
        modules = []
 | 
					 | 
				
			||||||
    } = {}) {
 | 
					 | 
				
			||||||
        let element = document.createElement("div")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        scatterContainer.element.appendChild(element)
 | 
					 | 
				
			||||||
        new DOMScatter(element, scatterContainer, {
 | 
					 | 
				
			||||||
            width: 1400,
 | 
					 | 
				
			||||||
            height: 1200
 | 
					 | 
				
			||||||
        })
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        this.setup(element, html, {
 | 
					 | 
				
			||||||
            basePath,
 | 
					 | 
				
			||||||
            modules
 | 
					 | 
				
			||||||
        })
 | 
					 | 
				
			||||||
        return element
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /**
 | 
					 | 
				
			||||||
     *Utility function to create a fully functional card scatter.
 | 
					 | 
				
			||||||
     *
 | 
					 | 
				
			||||||
     * @static
 | 
					 | 
				
			||||||
     * @param {*} scatterContainer
 | 
					 | 
				
			||||||
     * @param {*} path
 | 
					 | 
				
			||||||
     * @param {string} [basePath="."]
 | 
					 | 
				
			||||||
     * @param {*} opts
 | 
					 | 
				
			||||||
     * @returns
 | 
					 | 
				
			||||||
     * @memberof CardScatter
 | 
					 | 
				
			||||||
     */
 | 
					 | 
				
			||||||
    static loadAndCreateScatterCard(scatterContainer, item, {
 | 
					 | 
				
			||||||
        basePath = "../",
 | 
					 | 
				
			||||||
        modules = [],
 | 
					 | 
				
			||||||
        onClose = null
 | 
					 | 
				
			||||||
    } = {}) {
 | 
					 | 
				
			||||||
        console.log(basePath)
 | 
					 | 
				
			||||||
        return new Promise((resolve, reject) => {
 | 
					 | 
				
			||||||
            let url = basePath + "/" + item + "/index.html"
 | 
					 | 
				
			||||||
            console.log("Loading", url)
 | 
					 | 
				
			||||||
            this.loadHTML(url)
 | 
					 | 
				
			||||||
                .then(html => {
 | 
					 | 
				
			||||||
                    console.log("Received", html)
 | 
					 | 
				
			||||||
                    let element = this.createCardScatter(html, scatterContainer, {
 | 
					 | 
				
			||||||
                        basePath,
 | 
					 | 
				
			||||||
                        modules
 | 
					 | 
				
			||||||
                    })
 | 
					 | 
				
			||||||
                    if (onClose)
 | 
					 | 
				
			||||||
                        this.addOnCloseListener(element, onClose)
 | 
					 | 
				
			||||||
                    resolve(element)
 | 
					 | 
				
			||||||
                })
 | 
					 | 
				
			||||||
                .catch(e => reject(e))
 | 
					 | 
				
			||||||
        })
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    static _setLanguage(context, language) {
 | 
					 | 
				
			||||||
        context.language = language
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    static _getLanguage(context) {
 | 
					 | 
				
			||||||
        return context.language
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
window.ScatterCard = ScatterCard
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
ScatterCard.selectedLanguage = 0
 | 
					 | 
				
			||||||
ScatterCard.languages = ["Deutsch", "English"]
 | 
					 | 
				
			||||||
ScatterCard.languageTags = {
 | 
					 | 
				
			||||||
    Deutsch: "de",
 | 
					 | 
				
			||||||
    English: "en"
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
ScatterCard.scatterContainer = null
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
var CardPlugin = CardPlugin || {}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class CardPluginBase {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    apply(context) {
 | 
					 | 
				
			||||||
        if (this.verify(context)) {
 | 
					 | 
				
			||||||
            this.append(context)
 | 
					 | 
				
			||||||
            console.log("Plugin " + this.name + " was verified successfully.")
 | 
					 | 
				
			||||||
            return true
 | 
					 | 
				
			||||||
        } else console.error("Could not verify module " + this.name + ".")
 | 
					 | 
				
			||||||
        return false
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    get name() {
 | 
					 | 
				
			||||||
        return this.constructor.name
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    verify(context) {
 | 
					 | 
				
			||||||
        let funcs = this._getVerificationFunctions(context)
 | 
					 | 
				
			||||||
        for (let func of funcs) {
 | 
					 | 
				
			||||||
            if (!func()) return false
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        return true
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    _verifyElementsExist(context, ...selectors) {
 | 
					 | 
				
			||||||
        let missing = []
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        for (let selector of selectors) {
 | 
					 | 
				
			||||||
            let requiredElement = context.querySelector(selector)
 | 
					 | 
				
			||||||
            if (requiredElement == null) {
 | 
					 | 
				
			||||||
                missing.push(selector)
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        const valid = (missing.length == 0)
 | 
					 | 
				
			||||||
        if (!valid) console.error("Elements were missing: ", missing.join(", "))
 | 
					 | 
				
			||||||
        return valid
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /**
 | 
					 | 
				
			||||||
     *  Appends the Plugin to the context.
 | 
					 | 
				
			||||||
     *
 | 
					 | 
				
			||||||
     * @memberof CardPlugin
 | 
					 | 
				
			||||||
     */
 | 
					 | 
				
			||||||
    append(context) {
 | 
					 | 
				
			||||||
        console.error("Call of abstract method CardPlugin.prototype.append(context). Plugins need to overwrite the append method!")
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    _getVerificationFunctions(context) {
 | 
					 | 
				
			||||||
        return [
 | 
					 | 
				
			||||||
            this._verifyContext.bind(this, context),
 | 
					 | 
				
			||||||
            this._verifyRequirements.bind(this, context)
 | 
					 | 
				
			||||||
        ]
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    _verifyContext(context) {
 | 
					 | 
				
			||||||
        if (!(context instanceof HTMLElement)) {
 | 
					 | 
				
			||||||
            console.error("Context is not of type HTML Element.", context)
 | 
					 | 
				
			||||||
            return false
 | 
					 | 
				
			||||||
        } else return true
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    _verifyRequirements(context) {
 | 
					 | 
				
			||||||
        let requirements = this._collectAllRequirements()
 | 
					 | 
				
			||||||
        let missing = []
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        requirements.forEach(module => {
 | 
					 | 
				
			||||||
            if (context.modules.indexOf(module.name) == -1) {
 | 
					 | 
				
			||||||
                missing.push(module.name)
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        })
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        const valid = (missing.length == 0)
 | 
					 | 
				
			||||||
        if (!valid) console.error("Could not apply module '" + this.name + "'. Following modules are required but were missing: " + missing.join(","))
 | 
					 | 
				
			||||||
        else console.log("All requirements were met! Well done!")
 | 
					 | 
				
			||||||
        return valid
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    _collectAllRequirements() {
 | 
					 | 
				
			||||||
        let requirements = []
 | 
					 | 
				
			||||||
        let klass = this.__proto__
 | 
					 | 
				
			||||||
        while (klass) {
 | 
					 | 
				
			||||||
            if (klass.require != null) {
 | 
					 | 
				
			||||||
                requirements = requirements.concat(klass.require)
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            klass = klass.__proto__
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        return requirements
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
CardPlugin.LightBox = class LightBox extends CardPluginBase {
 | 
					 | 
				
			||||||
    constructor(className, style = {}) {
 | 
					 | 
				
			||||||
        super()
 | 
					 | 
				
			||||||
        this.className = className
 | 
					 | 
				
			||||||
        this.style = style
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    append(context) {
 | 
					 | 
				
			||||||
        let wrapper = document.createElement("div")
 | 
					 | 
				
			||||||
        wrapper.className = this.className
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        Object.assign(wrapper.style, {
 | 
					 | 
				
			||||||
            zIndex: 1000,
 | 
					 | 
				
			||||||
            // backgroundColor: "black",
 | 
					 | 
				
			||||||
            top: 0,
 | 
					 | 
				
			||||||
            left: 0,
 | 
					 | 
				
			||||||
            width: "100%",
 | 
					 | 
				
			||||||
            height: "100%"
 | 
					 | 
				
			||||||
        }, this.style, {
 | 
					 | 
				
			||||||
                display: "none",
 | 
					 | 
				
			||||||
                position: "absolute",
 | 
					 | 
				
			||||||
            })
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        context.appendChild(wrapper)
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/**
 | 
					 | 
				
			||||||
 * The Enlargeable Overlay module allows the user to click on the thumbnail image,
 | 
					 | 
				
			||||||
 * and the images gets enlarged inside the card.
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * @class EnlargeableThumbnail
 | 
					 | 
				
			||||||
 * @extends {CardPlugin}
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
CardPlugin.EnlargeableThumbnail = class EnlargeableThumbnail extends CardPluginBase {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    constructor(wrapperSelector, overlaySelector = null, {
 | 
					 | 
				
			||||||
        zoomAnimationDuration = 0.4,
 | 
					 | 
				
			||||||
        fadeAnimationDuration = 0.4,
 | 
					 | 
				
			||||||
        interactionType = "tap"
 | 
					 | 
				
			||||||
    } = {}) {
 | 
					 | 
				
			||||||
        super()
 | 
					 | 
				
			||||||
        this.wrapperSelector = wrapperSelector
 | 
					 | 
				
			||||||
        this.overlaySelector = overlaySelector
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        this.zoomAnimationDuration = zoomAnimationDuration
 | 
					 | 
				
			||||||
        this.fadeAnimationDuration = fadeAnimationDuration
 | 
					 | 
				
			||||||
        this.interactionType = interactionType
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    get require() {
 | 
					 | 
				
			||||||
        return [
 | 
					 | 
				
			||||||
            CardPlugin.LightBox
 | 
					 | 
				
			||||||
        ]
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    _getVerificationFunctions(context) {
 | 
					 | 
				
			||||||
        let arr = super._getVerificationFunctions(context)
 | 
					 | 
				
			||||||
        let funcs = [
 | 
					 | 
				
			||||||
            this._verifyElementsExist.bind(this, context, this.wrapperSelector, this.overlaySelector)
 | 
					 | 
				
			||||||
        ]
 | 
					 | 
				
			||||||
        return arr.concat(funcs)
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    append(context) {
 | 
					 | 
				
			||||||
        let source = this._retrieveSource(context)
 | 
					 | 
				
			||||||
        this.setupEnlargeableThumbnail(context, source)
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /**
 | 
					 | 
				
			||||||
     * Get the preview image.
 | 
					 | 
				
			||||||
     * 
 | 
					 | 
				
			||||||
     * It depends on the fact, that the thumbnail image is in the same directory
 | 
					 | 
				
			||||||
     * 
 | 
					 | 
				
			||||||
     *
 | 
					 | 
				
			||||||
     * @param {*} context
 | 
					 | 
				
			||||||
     * @returns
 | 
					 | 
				
			||||||
     * @memberof EnlargeableThumbnail
 | 
					 | 
				
			||||||
     */
 | 
					 | 
				
			||||||
    _retrieveSource(context) {
 | 
					 | 
				
			||||||
        let img = context.querySelector(this.wrapperSelector + " img")
 | 
					 | 
				
			||||||
        let src = img.getAttribute("src")
 | 
					 | 
				
			||||||
        let parts = src.split("/")
 | 
					 | 
				
			||||||
        parts.pop()
 | 
					 | 
				
			||||||
        parts.push(parts[parts.length - 1])
 | 
					 | 
				
			||||||
        let imagePath = parts.join("/") + ".jpg"
 | 
					 | 
				
			||||||
        return imagePath
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    setupEnlargeableThumbnail(context, src) {
 | 
					 | 
				
			||||||
        let wrapper = context.querySelector(this.wrapperSelector)
 | 
					 | 
				
			||||||
        let overlay = context.querySelector(this.overlaySelector)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        let icon = document.createElement("div")
 | 
					 | 
				
			||||||
        icon.className = "button corner-button bottom-right icon zoom"
 | 
					 | 
				
			||||||
        wrapper.appendChild(icon)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        Object.assign(wrapper.style, {
 | 
					 | 
				
			||||||
            cursor: "pointer"
 | 
					 | 
				
			||||||
        })
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        InteractionMapper.on(this.interactionType, wrapper, () => {
 | 
					 | 
				
			||||||
            this.openThumbnailDetail(context, src)
 | 
					 | 
				
			||||||
        })
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        InteractionMapper.on(this.interactionType, overlay, () => {
 | 
					 | 
				
			||||||
            this.closeThumnailDetail(context)
 | 
					 | 
				
			||||||
        })
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    openThumbnailDetail(context, src) {
 | 
					 | 
				
			||||||
        let overlay = context.querySelector(".img-overlay")
 | 
					 | 
				
			||||||
        overlay.innerHTML = ""
 | 
					 | 
				
			||||||
        let source = context.querySelector(this.wrapperSelector)
 | 
					 | 
				
			||||||
        let sourceStyle = window.getComputedStyle(source)
 | 
					 | 
				
			||||||
        let imageWrapper = source.cloneNode(true)
 | 
					 | 
				
			||||||
        let image = imageWrapper.querySelector("img")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        Object.assign(imageWrapper.style, {
 | 
					 | 
				
			||||||
            maxWidth: "none",
 | 
					 | 
				
			||||||
            maxHeight: "none"
 | 
					 | 
				
			||||||
        })
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        Object.assign(image.style, {
 | 
					 | 
				
			||||||
            width: "100%",
 | 
					 | 
				
			||||||
            height: "100%",
 | 
					 | 
				
			||||||
            objectFit: "cover"
 | 
					 | 
				
			||||||
        })
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        this._replaceIcon(imageWrapper)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        image.onload = () => {
 | 
					 | 
				
			||||||
            let header = context.querySelector("header")
 | 
					 | 
				
			||||||
            let headerStlye = window.getComputedStyle(header)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            /**
 | 
					 | 
				
			||||||
             * First the maxFillRatio is considered.
 | 
					 | 
				
			||||||
             * It describes how much the image is allowed to exceed the context element.
 | 
					 | 
				
			||||||
             */
 | 
					 | 
				
			||||||
            const maxFillRatio = 1.5
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            /**
 | 
					 | 
				
			||||||
             * The minor side should not exceed the height of the context window. 
 | 
					 | 
				
			||||||
             */
 | 
					 | 
				
			||||||
            const maxMinorSize = context.offsetHeight - 2 * parseInt(headerStlye.paddingTop) - 2 * parseInt(headerStlye.marginTop)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            const max = {
 | 
					 | 
				
			||||||
                width: context.offsetWidth * maxFillRatio,
 | 
					 | 
				
			||||||
                height: context.offsetHeight * maxFillRatio
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            let majorSide
 | 
					 | 
				
			||||||
            let minorSide
 | 
					 | 
				
			||||||
            const _width = { name: "width", axis: "x" }
 | 
					 | 
				
			||||||
            const _height = { name: "height", axis: "y" }
 | 
					 | 
				
			||||||
            if (image.naturalHeight > image.naturalWidth) {
 | 
					 | 
				
			||||||
                majorSide = _height
 | 
					 | 
				
			||||||
                minorSide = _width
 | 
					 | 
				
			||||||
            } else {
 | 
					 | 
				
			||||||
                majorSide = _width
 | 
					 | 
				
			||||||
                minorSide = _height
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            function capitalize(string) {
 | 
					 | 
				
			||||||
                return string.charAt(0).toUpperCase() + string.slice(1)
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            function getImageSize(side) {
 | 
					 | 
				
			||||||
                return image["natural" + capitalize(side.name)]
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            const majorImageSize = getImageSize(majorSide)
 | 
					 | 
				
			||||||
            // const minorImageSize = getImageSize(minorSide)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            let ratio = getImageSize(minorSide) / getImageSize(majorSide)
 | 
					 | 
				
			||||||
            let size = (majorImageSize > max[majorSide.name]) ? max[majorSide.name] : majorImageSize
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            if (size * ratio > maxMinorSize) {
 | 
					 | 
				
			||||||
                size = maxMinorSize / ratio
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            let targetDimensions = {
 | 
					 | 
				
			||||||
                width: 0,
 | 
					 | 
				
			||||||
                height: 0
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            let position = Points.fromPageToNode(context, Points.fromNodeToPage(source, { x: 0, y: 0 }))
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            let targetOffset = {
 | 
					 | 
				
			||||||
                x: 0,
 | 
					 | 
				
			||||||
                y: 0
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            targetDimensions[majorSide.name] = size
 | 
					 | 
				
			||||||
            targetDimensions[minorSide.name] = size * ratio
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            targetOffset[majorSide.axis] = (context["offset" + capitalize(majorSide.name)] - targetDimensions[majorSide.name]) / 2
 | 
					 | 
				
			||||||
            targetOffset[minorSide.axis] = (context["offset" + capitalize(minorSide.name)] - targetDimensions[minorSide.name]) / 2
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            overlay.appendChild(imageWrapper)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            TweenMax.set(imageWrapper, {
 | 
					 | 
				
			||||||
                left: 0,
 | 
					 | 
				
			||||||
                top: 0,
 | 
					 | 
				
			||||||
                x: position.x,
 | 
					 | 
				
			||||||
                y: position.y,
 | 
					 | 
				
			||||||
                position: "absolute",
 | 
					 | 
				
			||||||
                width: parseInt(sourceStyle.width),
 | 
					 | 
				
			||||||
                height: parseInt(sourceStyle.height)
 | 
					 | 
				
			||||||
            })
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            TweenMax.set(overlay, {
 | 
					 | 
				
			||||||
                display: "flex",
 | 
					 | 
				
			||||||
                autoAlpha: 0
 | 
					 | 
				
			||||||
            })
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            TweenMax.to(imageWrapper, this.zoomAnimationDuration, {
 | 
					 | 
				
			||||||
                x: targetOffset.x,
 | 
					 | 
				
			||||||
                y: targetOffset.y,
 | 
					 | 
				
			||||||
                width: targetDimensions.width,
 | 
					 | 
				
			||||||
                height: targetDimensions.height,
 | 
					 | 
				
			||||||
            })
 | 
					 | 
				
			||||||
            TweenMax.to(overlay, this.fadeAnimationTime, {
 | 
					 | 
				
			||||||
                autoAlpha: 1
 | 
					 | 
				
			||||||
            })
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        image.src = src
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    _replaceIcon(clone) {
 | 
					 | 
				
			||||||
        let zoomIcon = clone.querySelector(".icon.zoom")
 | 
					 | 
				
			||||||
        zoomIcon.classList.remove("zoom")
 | 
					 | 
				
			||||||
        zoomIcon.classList.add("close")
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    getBorderHeight(style) {
 | 
					 | 
				
			||||||
        const borderWidth = parseInt(style.borderTopWidth) + parseInt(style.borderBottomWidth)
 | 
					 | 
				
			||||||
        const padding = parseInt(style.paddingTop) + parseInt(style.paddingBottom)
 | 
					 | 
				
			||||||
        return parseInt(style.width) + borderWidth + padding
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    getBorderWidth(style) {
 | 
					 | 
				
			||||||
        const borderWidth = parseInt(style.borderLeftWidth) + parseInt(style.borderRightWidth)
 | 
					 | 
				
			||||||
        const padding = parseInt(style.paddingLeft) + parseInt(style.paddingRight)
 | 
					 | 
				
			||||||
        return parseInt(style.width) + borderWidth + padding
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    closeThumnailDetail(context) {
 | 
					 | 
				
			||||||
        let overlay = context.querySelector(".img-overlay")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        let timeline = new TimelineLite()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        timeline.to(overlay, this.fadeAnimationDuration, {
 | 
					 | 
				
			||||||
            autoAlpha: 0
 | 
					 | 
				
			||||||
        }).set(overlay, {
 | 
					 | 
				
			||||||
            display: "none"
 | 
					 | 
				
			||||||
        })
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
CardPlugin.Ui = class UiPlugin extends CardPluginBase {
 | 
					 | 
				
			||||||
    constructor(className, parent = null) {
 | 
					 | 
				
			||||||
        super()
 | 
					 | 
				
			||||||
        this.parent = parent
 | 
					 | 
				
			||||||
        this.className = className
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    _getVerificationFunctions(context) {
 | 
					 | 
				
			||||||
        let arr = super._getVerificationFunctions(context)
 | 
					 | 
				
			||||||
        let func = [
 | 
					 | 
				
			||||||
            this._doesParentExist.bind(this, context, this.parent)
 | 
					 | 
				
			||||||
        ]
 | 
					 | 
				
			||||||
        return arr.concat(func)
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    _doesParentExist(context, parent) {
 | 
					 | 
				
			||||||
        if (parent == null) return true
 | 
					 | 
				
			||||||
        let valid = (context.querySelector(parent) != null)
 | 
					 | 
				
			||||||
        if (!valid) console.error("Could not find parent on context.", context, parent)
 | 
					 | 
				
			||||||
        return valid
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    append(context) {
 | 
					 | 
				
			||||||
        parent = (this.parent == null) ? context : context.querySelector(this.parent).appendChild(container)
 | 
					 | 
				
			||||||
        let container = document.createElement("div")
 | 
					 | 
				
			||||||
        container.className = this.className
 | 
					 | 
				
			||||||
        parent.appendChild(container)
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
CardPlugin.Speech = class SpeechPlugin extends CardPluginBase {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    constructor(parentSelector, className, interactionType = "tap") {
 | 
					 | 
				
			||||||
        super()
 | 
					 | 
				
			||||||
        this.className = className
 | 
					 | 
				
			||||||
        this.parentSelector = parentSelector
 | 
					 | 
				
			||||||
        this.interactionType = interactionType
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    get require() {
 | 
					 | 
				
			||||||
        return [
 | 
					 | 
				
			||||||
            CardPlugin.Ui
 | 
					 | 
				
			||||||
        ]
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    append(context) {
 | 
					 | 
				
			||||||
        let container = context.querySelector(this.parentSelector)
 | 
					 | 
				
			||||||
        this.button = document.createElement("div")
 | 
					 | 
				
			||||||
        this.button.className = "icon button " + this.className
 | 
					 | 
				
			||||||
        container.appendChild(this.button)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        InteractionMapper.on(this.interactionType, this.button, () => {
 | 
					 | 
				
			||||||
            let subcard = context.querySelector(".mainview > .subcard")
 | 
					 | 
				
			||||||
            let target = (subcard) ? subcard : context
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            this.speak(target)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        })
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    _activate() {
 | 
					 | 
				
			||||||
        this._disableActive()
 | 
					 | 
				
			||||||
        this.active = this
 | 
					 | 
				
			||||||
        this._activateButton()
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    _activateButton() {
 | 
					 | 
				
			||||||
        if (this.button)
 | 
					 | 
				
			||||||
            this.button.classList.add("active")
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    _deactivate() {
 | 
					 | 
				
			||||||
        this._deactivateButton()
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    _deactivateButton() {
 | 
					 | 
				
			||||||
        if (this.button)
 | 
					 | 
				
			||||||
            this.button.classList.remove("active")
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    _isSameNode(node) {
 | 
					 | 
				
			||||||
        //console.log(this.currentText, node.innerText)
 | 
					 | 
				
			||||||
        return (this.currentText == node.innerText)
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    speak(node) {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        console.log(this._isSameNode(node))
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if (!window.speechSynthesis.speaking) {
 | 
					 | 
				
			||||||
            console.log("Noone talking!")
 | 
					 | 
				
			||||||
            this._start(node)
 | 
					 | 
				
			||||||
        } else if (this._isSameNode(node)) {
 | 
					 | 
				
			||||||
            console.log("Requested same!")
 | 
					 | 
				
			||||||
            this._stop()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        } else {
 | 
					 | 
				
			||||||
            console.log("Requested Different!")
 | 
					 | 
				
			||||||
            this._stop()
 | 
					 | 
				
			||||||
            this._start(node)
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    _disableActive() {
 | 
					 | 
				
			||||||
        console.log("disableActive:", this.active)
 | 
					 | 
				
			||||||
        if (this.active) {
 | 
					 | 
				
			||||||
            this.active._deactivate()
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    _start(node) {
 | 
					 | 
				
			||||||
        this.currentText = node.innerText
 | 
					 | 
				
			||||||
        let utterance = new SpeechSynthesisUtterance(node.innerText)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        let voices = window.speechSynthesis.getVoices()
 | 
					 | 
				
			||||||
        console.log(voices)
 | 
					 | 
				
			||||||
        let voice = voices.filter((val) => {
 | 
					 | 
				
			||||||
            //console.log(val)
 | 
					 | 
				
			||||||
            return val.name == "Microsoft Hedda Desktop - German"
 | 
					 | 
				
			||||||
        })[0]
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        //console.log(voice)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        utterance.voice = voice
 | 
					 | 
				
			||||||
        console.log("TALK: ", utterance)
 | 
					 | 
				
			||||||
        window.speechSynthesis.speak(utterance)
 | 
					 | 
				
			||||||
        this._activate()
 | 
					 | 
				
			||||||
        window.speechSynthesis.resume()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        utterance.onboundary = () => { console.log("onboundary", node.innerText); if (this.currentText.substring(0, 5) != node.innerText.substring(0, 5)) { console.log("text for speech synth changed!", this.currentText, node.innerText); this._stop() } }
 | 
					 | 
				
			||||||
        utterance.onend = () => console.log("onend", node.innerText)
 | 
					 | 
				
			||||||
        utterance.onerror = () => console.log("onerror", node.innerText)
 | 
					 | 
				
			||||||
        utterance.onmark = () => console.log("onmark", node.innerText)
 | 
					 | 
				
			||||||
        utterance.onpause = () => console.log("onpause", node.innerText)
 | 
					 | 
				
			||||||
        utterance.onresume = () => console.log("onresume", node.innerText)
 | 
					 | 
				
			||||||
        utterance.onstart = () => console.log("onstart", node.innerText)
 | 
					 | 
				
			||||||
        utterance.onerror = () => console.log("onerror", node.innerText)
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    _stop() {
 | 
					 | 
				
			||||||
        window.speechSynthesis.cancel()
 | 
					 | 
				
			||||||
        this.currentText = null
 | 
					 | 
				
			||||||
        this._deactivate()
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    get active() {
 | 
					 | 
				
			||||||
        return this.constructor.active
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    set active(val) { this.constructor.active = val }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    get currentText() {
 | 
					 | 
				
			||||||
        return this.constructor.text
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    set currentText(val) {
 | 
					 | 
				
			||||||
        this.constructor.text = val
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
}		
 | 
					 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										530
									
								
								lib/card/plugin.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										530
									
								
								lib/card/plugin.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,530 @@
 | 
				
			|||||||
 | 
					export var CardPlugin = CardPlugin || {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export class CardPluginBase {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    apply(context) {
 | 
				
			||||||
 | 
					        if (this.verify(context)) {
 | 
				
			||||||
 | 
					            this.append(context)
 | 
				
			||||||
 | 
					            console.log("Plugin " + this.name + " was verified successfully.")
 | 
				
			||||||
 | 
					            return true
 | 
				
			||||||
 | 
					        } else console.error("Could not verify module " + this.name + ".")
 | 
				
			||||||
 | 
					        return false
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    get name() {
 | 
				
			||||||
 | 
					        return this.constructor.name
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    verify(context) {
 | 
				
			||||||
 | 
					        let funcs = this._getVerificationFunctions(context)
 | 
				
			||||||
 | 
					        for (let func of funcs) {
 | 
				
			||||||
 | 
					            if (!func()) return false
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return true
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    _verifyElementsExist(context, ...selectors) {
 | 
				
			||||||
 | 
					        let missing = []
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        for (let selector of selectors) {
 | 
				
			||||||
 | 
					            let requiredElement = context.querySelector(selector)
 | 
				
			||||||
 | 
					            if (requiredElement == null) {
 | 
				
			||||||
 | 
					                missing.push(selector)
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        const valid = (missing.length == 0)
 | 
				
			||||||
 | 
					        if (!valid) console.error("Elements were missing: ", missing.join(", "))
 | 
				
			||||||
 | 
					        return valid
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     *  Appends the Plugin to the context.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @memberof CardPlugin
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    append(context) {
 | 
				
			||||||
 | 
					        console.error("Call of abstract method CardPlugin.prototype.append(context). Plugins need to overwrite the append method!")
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    _getVerificationFunctions(context) {
 | 
				
			||||||
 | 
					        return [
 | 
				
			||||||
 | 
					            this._verifyContext.bind(this, context),
 | 
				
			||||||
 | 
					            this._verifyRequirements.bind(this, context)
 | 
				
			||||||
 | 
					        ]
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    _verifyContext(context) {
 | 
				
			||||||
 | 
					        if (!(context instanceof HTMLElement)) {
 | 
				
			||||||
 | 
					            console.error("Context is not of type HTML Element.", context)
 | 
				
			||||||
 | 
					            return false
 | 
				
			||||||
 | 
					        } else return true
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    _verifyRequirements(context) {
 | 
				
			||||||
 | 
					        let requirements = this._collectAllRequirements()
 | 
				
			||||||
 | 
					        let missing = []
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        requirements.forEach(module => {
 | 
				
			||||||
 | 
					            if (context.modules.indexOf(module.name) == -1) {
 | 
				
			||||||
 | 
					                missing.push(module.name)
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        const valid = (missing.length == 0)
 | 
				
			||||||
 | 
					        if (!valid) console.error("Could not apply module '" + this.name + "'. Following modules are required but were missing: " + missing.join(","))
 | 
				
			||||||
 | 
					        else console.log("All requirements were met! Well done!")
 | 
				
			||||||
 | 
					        return valid
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    _collectAllRequirements() {
 | 
				
			||||||
 | 
					        let requirements = []
 | 
				
			||||||
 | 
					        let klass = this.__proto__
 | 
				
			||||||
 | 
					        while (klass) {
 | 
				
			||||||
 | 
					            if (klass.require != null) {
 | 
				
			||||||
 | 
					                requirements = requirements.concat(klass.require)
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            klass = klass.__proto__
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return requirements
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					CardPlugin.LightBox = class LightBox extends CardPluginBase {
 | 
				
			||||||
 | 
					    constructor(className, style = {}) {
 | 
				
			||||||
 | 
					        super()
 | 
				
			||||||
 | 
					        this.className = className
 | 
				
			||||||
 | 
					        this.style = style
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    append(context) {
 | 
				
			||||||
 | 
					        let wrapper = document.createElement("div")
 | 
				
			||||||
 | 
					        wrapper.className = this.className
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Object.assign(wrapper.style, {
 | 
				
			||||||
 | 
					            zIndex: 1000,
 | 
				
			||||||
 | 
					            // backgroundColor: "black",
 | 
				
			||||||
 | 
					            top: 0,
 | 
				
			||||||
 | 
					            left: 0,
 | 
				
			||||||
 | 
					            width: "100%",
 | 
				
			||||||
 | 
					            height: "100%"
 | 
				
			||||||
 | 
					        }, this.style, {
 | 
				
			||||||
 | 
					                display: "none",
 | 
				
			||||||
 | 
					                position: "absolute",
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        context.appendChild(wrapper)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * The Enlargeable Overlay module allows the user to click on the thumbnail image,
 | 
				
			||||||
 | 
					 * and the images gets enlarged inside the card.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @class EnlargeableThumbnail
 | 
				
			||||||
 | 
					 * @extends {CardPlugin}
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					CardPlugin.EnlargeableThumbnail = class EnlargeableThumbnail extends CardPluginBase {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    constructor(wrapperSelector, overlaySelector = null, {
 | 
				
			||||||
 | 
					        zoomAnimationDuration = 0.4,
 | 
				
			||||||
 | 
					        fadeAnimationDuration = 0.4,
 | 
				
			||||||
 | 
					        interactionType = "tap"
 | 
				
			||||||
 | 
					    } = {}) {
 | 
				
			||||||
 | 
					        super()
 | 
				
			||||||
 | 
					        this.wrapperSelector = wrapperSelector
 | 
				
			||||||
 | 
					        this.overlaySelector = overlaySelector
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        this.zoomAnimationDuration = zoomAnimationDuration
 | 
				
			||||||
 | 
					        this.fadeAnimationDuration = fadeAnimationDuration
 | 
				
			||||||
 | 
					        this.interactionType = interactionType
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    get require() {
 | 
				
			||||||
 | 
					        return [
 | 
				
			||||||
 | 
					            CardPlugin.LightBox
 | 
				
			||||||
 | 
					        ]
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    _getVerificationFunctions(context) {
 | 
				
			||||||
 | 
					        let arr = super._getVerificationFunctions(context)
 | 
				
			||||||
 | 
					        let funcs = [
 | 
				
			||||||
 | 
					            this._verifyElementsExist.bind(this, context, this.wrapperSelector, this.overlaySelector)
 | 
				
			||||||
 | 
					        ]
 | 
				
			||||||
 | 
					        return arr.concat(funcs)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    append(context) {
 | 
				
			||||||
 | 
					        let source = this._retrieveSource(context)
 | 
				
			||||||
 | 
					        this.setupEnlargeableThumbnail(context, source)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Get the preview image.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * It depends on the fact, that the thumbnail image is in the same directory
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param {*} context
 | 
				
			||||||
 | 
					     * @returns
 | 
				
			||||||
 | 
					     * @memberof EnlargeableThumbnail
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    _retrieveSource(context) {
 | 
				
			||||||
 | 
					        let img = context.querySelector(this.wrapperSelector + " img")
 | 
				
			||||||
 | 
					        let src = img.getAttribute("src")
 | 
				
			||||||
 | 
					        let parts = src.split("/")
 | 
				
			||||||
 | 
					        parts.pop()
 | 
				
			||||||
 | 
					        parts.push(parts[parts.length - 1])
 | 
				
			||||||
 | 
					        let imagePath = parts.join("/") + ".jpg"
 | 
				
			||||||
 | 
					        return imagePath
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    setupEnlargeableThumbnail(context, src) {
 | 
				
			||||||
 | 
					        let wrapper = context.querySelector(this.wrapperSelector)
 | 
				
			||||||
 | 
					        let overlay = context.querySelector(this.overlaySelector)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let icon = document.createElement("div")
 | 
				
			||||||
 | 
					        icon.className = "button corner-button bottom-right icon zoom"
 | 
				
			||||||
 | 
					        wrapper.appendChild(icon)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Object.assign(wrapper.style, {
 | 
				
			||||||
 | 
					            cursor: "pointer"
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        InteractionMapper.on(this.interactionType, wrapper, () => {
 | 
				
			||||||
 | 
					            this.openThumbnailDetail(context, src)
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        InteractionMapper.on(this.interactionType, overlay, () => {
 | 
				
			||||||
 | 
					            this.closeThumnailDetail(context)
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    openThumbnailDetail(context, src) {
 | 
				
			||||||
 | 
					        let overlay = context.querySelector(".img-overlay")
 | 
				
			||||||
 | 
					        overlay.innerHTML = ""
 | 
				
			||||||
 | 
					        let source = context.querySelector(this.wrapperSelector)
 | 
				
			||||||
 | 
					        let sourceStyle = window.getComputedStyle(source)
 | 
				
			||||||
 | 
					        let imageWrapper = source.cloneNode(true)
 | 
				
			||||||
 | 
					        let image = imageWrapper.querySelector("img")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Object.assign(imageWrapper.style, {
 | 
				
			||||||
 | 
					            maxWidth: "none",
 | 
				
			||||||
 | 
					            maxHeight: "none"
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Object.assign(image.style, {
 | 
				
			||||||
 | 
					            width: "100%",
 | 
				
			||||||
 | 
					            height: "100%",
 | 
				
			||||||
 | 
					            objectFit: "cover"
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        this._replaceIcon(imageWrapper)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        image.onload = () => {
 | 
				
			||||||
 | 
					            let header = context.querySelector("header")
 | 
				
			||||||
 | 
					            let headerStlye = window.getComputedStyle(header)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            /**
 | 
				
			||||||
 | 
					             * First the maxFillRatio is considered.
 | 
				
			||||||
 | 
					             * It describes how much the image is allowed to exceed the context element.
 | 
				
			||||||
 | 
					             */
 | 
				
			||||||
 | 
					            const maxFillRatio = 1.5
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            /**
 | 
				
			||||||
 | 
					             * The minor side should not exceed the height of the context window.
 | 
				
			||||||
 | 
					             */
 | 
				
			||||||
 | 
					            const maxMinorSize = context.offsetHeight - 2 * parseInt(headerStlye.paddingTop) - 2 * parseInt(headerStlye.marginTop)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            const max = {
 | 
				
			||||||
 | 
					                width: context.offsetWidth * maxFillRatio,
 | 
				
			||||||
 | 
					                height: context.offsetHeight * maxFillRatio
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            let majorSide
 | 
				
			||||||
 | 
					            let minorSide
 | 
				
			||||||
 | 
					            const _width = { name: "width", axis: "x" }
 | 
				
			||||||
 | 
					            const _height = { name: "height", axis: "y" }
 | 
				
			||||||
 | 
					            if (image.naturalHeight > image.naturalWidth) {
 | 
				
			||||||
 | 
					                majorSide = _height
 | 
				
			||||||
 | 
					                minorSide = _width
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                majorSide = _width
 | 
				
			||||||
 | 
					                minorSide = _height
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            function capitalize(string) {
 | 
				
			||||||
 | 
					                return string.charAt(0).toUpperCase() + string.slice(1)
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            function getImageSize(side) {
 | 
				
			||||||
 | 
					                return image["natural" + capitalize(side.name)]
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            const majorImageSize = getImageSize(majorSide)
 | 
				
			||||||
 | 
					            // const minorImageSize = getImageSize(minorSide)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            let ratio = getImageSize(minorSide) / getImageSize(majorSide)
 | 
				
			||||||
 | 
					            let size = (majorImageSize > max[majorSide.name]) ? max[majorSide.name] : majorImageSize
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (size * ratio > maxMinorSize) {
 | 
				
			||||||
 | 
					                size = maxMinorSize / ratio
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            let targetDimensions = {
 | 
				
			||||||
 | 
					                width: 0,
 | 
				
			||||||
 | 
					                height: 0
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            let position = Points.fromPageToNode(context, Points.fromNodeToPage(source, { x: 0, y: 0 }))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            let targetOffset = {
 | 
				
			||||||
 | 
					                x: 0,
 | 
				
			||||||
 | 
					                y: 0
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            targetDimensions[majorSide.name] = size
 | 
				
			||||||
 | 
					            targetDimensions[minorSide.name] = size * ratio
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            targetOffset[majorSide.axis] = (context["offset" + capitalize(majorSide.name)] - targetDimensions[majorSide.name]) / 2
 | 
				
			||||||
 | 
					            targetOffset[minorSide.axis] = (context["offset" + capitalize(minorSide.name)] - targetDimensions[minorSide.name]) / 2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            overlay.appendChild(imageWrapper)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            TweenMax.set(imageWrapper, {
 | 
				
			||||||
 | 
					                left: 0,
 | 
				
			||||||
 | 
					                top: 0,
 | 
				
			||||||
 | 
					                x: position.x,
 | 
				
			||||||
 | 
					                y: position.y,
 | 
				
			||||||
 | 
					                position: "absolute",
 | 
				
			||||||
 | 
					                width: parseInt(sourceStyle.width),
 | 
				
			||||||
 | 
					                height: parseInt(sourceStyle.height)
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            TweenMax.set(overlay, {
 | 
				
			||||||
 | 
					                display: "flex",
 | 
				
			||||||
 | 
					                autoAlpha: 0
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            TweenMax.to(imageWrapper, this.zoomAnimationDuration, {
 | 
				
			||||||
 | 
					                x: targetOffset.x,
 | 
				
			||||||
 | 
					                y: targetOffset.y,
 | 
				
			||||||
 | 
					                width: targetDimensions.width,
 | 
				
			||||||
 | 
					                height: targetDimensions.height,
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					            TweenMax.to(overlay, this.fadeAnimationTime, {
 | 
				
			||||||
 | 
					                autoAlpha: 1
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        image.src = src
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    _replaceIcon(clone) {
 | 
				
			||||||
 | 
					        let zoomIcon = clone.querySelector(".icon.zoom")
 | 
				
			||||||
 | 
					        zoomIcon.classList.remove("zoom")
 | 
				
			||||||
 | 
					        zoomIcon.classList.add("close")
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    getBorderHeight(style) {
 | 
				
			||||||
 | 
					        const borderWidth = parseInt(style.borderTopWidth) + parseInt(style.borderBottomWidth)
 | 
				
			||||||
 | 
					        const padding = parseInt(style.paddingTop) + parseInt(style.paddingBottom)
 | 
				
			||||||
 | 
					        return parseInt(style.width) + borderWidth + padding
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    getBorderWidth(style) {
 | 
				
			||||||
 | 
					        const borderWidth = parseInt(style.borderLeftWidth) + parseInt(style.borderRightWidth)
 | 
				
			||||||
 | 
					        const padding = parseInt(style.paddingLeft) + parseInt(style.paddingRight)
 | 
				
			||||||
 | 
					        return parseInt(style.width) + borderWidth + padding
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    closeThumnailDetail(context) {
 | 
				
			||||||
 | 
					        let overlay = context.querySelector(".img-overlay")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let timeline = new TimelineLite()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        timeline.to(overlay, this.fadeAnimationDuration, {
 | 
				
			||||||
 | 
					            autoAlpha: 0
 | 
				
			||||||
 | 
					        }).set(overlay, {
 | 
				
			||||||
 | 
					            display: "none"
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					CardPlugin.Ui = class UiPlugin extends CardPluginBase {
 | 
				
			||||||
 | 
					    constructor(className, parent = null) {
 | 
				
			||||||
 | 
					        super()
 | 
				
			||||||
 | 
					        this.parent = parent
 | 
				
			||||||
 | 
					        this.className = className
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    _getVerificationFunctions(context) {
 | 
				
			||||||
 | 
					        let arr = super._getVerificationFunctions(context)
 | 
				
			||||||
 | 
					        let func = [
 | 
				
			||||||
 | 
					            this._doesParentExist.bind(this, context, this.parent)
 | 
				
			||||||
 | 
					        ]
 | 
				
			||||||
 | 
					        return arr.concat(func)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    _doesParentExist(context, parent) {
 | 
				
			||||||
 | 
					        if (parent == null) return true
 | 
				
			||||||
 | 
					        let valid = (context.querySelector(parent) != null)
 | 
				
			||||||
 | 
					        if (!valid) console.error("Could not find parent on context.", context, parent)
 | 
				
			||||||
 | 
					        return valid
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    append(context) {
 | 
				
			||||||
 | 
					        parent = (this.parent == null) ? context : context.querySelector(this.parent).appendChild(container)
 | 
				
			||||||
 | 
					        let container = document.createElement("div")
 | 
				
			||||||
 | 
					        container.className = this.className
 | 
				
			||||||
 | 
					        parent.appendChild(container)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					CardPlugin.Speech = class SpeechPlugin extends CardPluginBase {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    constructor(parentSelector, className, interactionType = "tap") {
 | 
				
			||||||
 | 
					        super()
 | 
				
			||||||
 | 
					        this.className = className
 | 
				
			||||||
 | 
					        this.parentSelector = parentSelector
 | 
				
			||||||
 | 
					        this.interactionType = interactionType
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    get require() {
 | 
				
			||||||
 | 
					        return [
 | 
				
			||||||
 | 
					            CardPlugin.Ui
 | 
				
			||||||
 | 
					        ]
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    append(context) {
 | 
				
			||||||
 | 
					        let container = context.querySelector(this.parentSelector)
 | 
				
			||||||
 | 
					        this.button = document.createElement("div")
 | 
				
			||||||
 | 
					        this.button.className = "icon button " + this.className
 | 
				
			||||||
 | 
					        container.appendChild(this.button)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        InteractionMapper.on(this.interactionType, this.button, () => {
 | 
				
			||||||
 | 
					            let subcard = context.querySelector(".mainview > .subcard")
 | 
				
			||||||
 | 
					            let target = (subcard) ? subcard : context
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            this.speak(target)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    _activate() {
 | 
				
			||||||
 | 
					        this._disableActive()
 | 
				
			||||||
 | 
					        this.active = this
 | 
				
			||||||
 | 
					        this._activateButton()
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    _activateButton() {
 | 
				
			||||||
 | 
					        if (this.button)
 | 
				
			||||||
 | 
					            this.button.classList.add("active")
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    _deactivate() {
 | 
				
			||||||
 | 
					        this._deactivateButton()
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    _deactivateButton() {
 | 
				
			||||||
 | 
					        if (this.button)
 | 
				
			||||||
 | 
					            this.button.classList.remove("active")
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    _isSameNode(node) {
 | 
				
			||||||
 | 
					        //console.log(this.currentText, node.innerText)
 | 
				
			||||||
 | 
					        return (this.currentText == node.innerText)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    speak(node) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        console.log(this._isSameNode(node))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (!window.speechSynthesis.speaking) {
 | 
				
			||||||
 | 
					            console.log("Noone talking!")
 | 
				
			||||||
 | 
					            this._start(node)
 | 
				
			||||||
 | 
					        } else if (this._isSameNode(node)) {
 | 
				
			||||||
 | 
					            console.log("Requested same!")
 | 
				
			||||||
 | 
					            this._stop()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            console.log("Requested Different!")
 | 
				
			||||||
 | 
					            this._stop()
 | 
				
			||||||
 | 
					            this._start(node)
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    _disableActive() {
 | 
				
			||||||
 | 
					        console.log("disableActive:", this.active)
 | 
				
			||||||
 | 
					        if (this.active) {
 | 
				
			||||||
 | 
					            this.active._deactivate()
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    _start(node) {
 | 
				
			||||||
 | 
					        this.currentText = node.innerText
 | 
				
			||||||
 | 
					        let utterance = new SpeechSynthesisUtterance(node.innerText)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let voices = window.speechSynthesis.getVoices()
 | 
				
			||||||
 | 
					        console.log(voices)
 | 
				
			||||||
 | 
					        let voice = voices.filter((val) => {
 | 
				
			||||||
 | 
					            //console.log(val)
 | 
				
			||||||
 | 
					            return val.name == "Microsoft Hedda Desktop - German"
 | 
				
			||||||
 | 
					        })[0]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        //console.log(voice)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        utterance.voice = voice
 | 
				
			||||||
 | 
					        console.log("TALK: ", utterance)
 | 
				
			||||||
 | 
					        window.speechSynthesis.speak(utterance)
 | 
				
			||||||
 | 
					        this._activate()
 | 
				
			||||||
 | 
					        window.speechSynthesis.resume()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        utterance.onboundary = () => { console.log("onboundary", node.innerText); if (this.currentText.substring(0, 5) != node.innerText.substring(0, 5)) { console.log("text for speech synth changed!", this.currentText, node.innerText); this._stop() } }
 | 
				
			||||||
 | 
					        utterance.onend = () => console.log("onend", node.innerText)
 | 
				
			||||||
 | 
					        utterance.onerror = () => console.log("onerror", node.innerText)
 | 
				
			||||||
 | 
					        utterance.onmark = () => console.log("onmark", node.innerText)
 | 
				
			||||||
 | 
					        utterance.onpause = () => console.log("onpause", node.innerText)
 | 
				
			||||||
 | 
					        utterance.onresume = () => console.log("onresume", node.innerText)
 | 
				
			||||||
 | 
					        utterance.onstart = () => console.log("onstart", node.innerText)
 | 
				
			||||||
 | 
					        utterance.onerror = () => console.log("onerror", node.innerText)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    _stop() {
 | 
				
			||||||
 | 
					        window.speechSynthesis.cancel()
 | 
				
			||||||
 | 
					        this.currentText = null
 | 
				
			||||||
 | 
					        this._deactivate()
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    get active() {
 | 
				
			||||||
 | 
					        return this.constructor.active
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    set active(val) { this.constructor.active = val }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    get currentText() {
 | 
				
			||||||
 | 
					        return this.constructor.text
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    set currentText(val) {
 | 
				
			||||||
 | 
					        this.constructor.text = val
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										145
									
								
								lib/card/scatter.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										145
									
								
								lib/card/scatter.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,145 @@
 | 
				
			|||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Extends the card with scatter functionality.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @class ScatterCard
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					export default class ScatterCard extends Card {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * TODO: Find a more suitable name.
 | 
				
			||||||
 | 
					     * Adjusts the HTML to work in the new context.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @static
 | 
				
			||||||
 | 
					     * @param {*} domElement
 | 
				
			||||||
 | 
					     * @param {*} htmlString
 | 
				
			||||||
 | 
					     * @param {*} basePath
 | 
				
			||||||
 | 
					     * @param {*} [opts={}]
 | 
				
			||||||
 | 
					     * @memberof Card
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    static setup(context, htmlString, {
 | 
				
			||||||
 | 
					        basePath = "./",
 | 
				
			||||||
 | 
					        modules = []
 | 
				
			||||||
 | 
					    } = {}) {
 | 
				
			||||||
 | 
					        context.classList.add("info-card")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        this.relativePath = basePath
 | 
				
			||||||
 | 
					        htmlString = this._adjustRelativeLinks(htmlString)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let parser = new DOMParser()
 | 
				
			||||||
 | 
					        let html = parser.parseFromString(htmlString, "text/html")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        /**
 | 
				
			||||||
 | 
					         * Conflicts with the FindTarget method of the Abstract scatter.
 | 
				
			||||||
 | 
					         */
 | 
				
			||||||
 | 
					        this._replaceAttributes(html, "onclick", this._replaceCallback)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let content = html.querySelector(".mainview")
 | 
				
			||||||
 | 
					        context.appendChild(content)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        super.setup(context, modules)
 | 
				
			||||||
 | 
					        return context
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Appends a close listener to the scatter element.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @static
 | 
				
			||||||
 | 
					     * @param {*} element
 | 
				
			||||||
 | 
					     * @param {*} callback
 | 
				
			||||||
 | 
					     * @memberof Card
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    static addOnCloseListener(element, callback) {
 | 
				
			||||||
 | 
					        if (callback) {
 | 
				
			||||||
 | 
					            element.onClose = callback
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Creates a scatter for the card and applies the card to it,
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @static
 | 
				
			||||||
 | 
					     * @param {*} html
 | 
				
			||||||
 | 
					     * @param {*} scatterContainer
 | 
				
			||||||
 | 
					     * @param {string} [basePath=""]
 | 
				
			||||||
 | 
					     * @param {*} [opts={}]
 | 
				
			||||||
 | 
					     * @returns
 | 
				
			||||||
 | 
					     * @memberof Card
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    static createCardScatter(html, scatterContainer, {
 | 
				
			||||||
 | 
					        basePath = "./",
 | 
				
			||||||
 | 
					        modules = []
 | 
				
			||||||
 | 
					    } = {}) {
 | 
				
			||||||
 | 
					        let element = document.createElement("div")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        scatterContainer.element.appendChild(element)
 | 
				
			||||||
 | 
					        new DOMScatter(element, scatterContainer, {
 | 
				
			||||||
 | 
					            width: 1400,
 | 
				
			||||||
 | 
					            height: 1200
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        this.setup(element, html, {
 | 
				
			||||||
 | 
					            basePath,
 | 
				
			||||||
 | 
					            modules
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
 | 
					        return element
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     *Utility function to create a fully functional card scatter.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @static
 | 
				
			||||||
 | 
					     * @param {*} scatterContainer
 | 
				
			||||||
 | 
					     * @param {*} path
 | 
				
			||||||
 | 
					     * @param {string} [basePath="."]
 | 
				
			||||||
 | 
					     * @param {*} opts
 | 
				
			||||||
 | 
					     * @returns
 | 
				
			||||||
 | 
					     * @memberof CardScatter
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    static loadAndCreateScatterCard(scatterContainer, item, {
 | 
				
			||||||
 | 
					        basePath = "../",
 | 
				
			||||||
 | 
					        modules = [],
 | 
				
			||||||
 | 
					        onClose = null
 | 
				
			||||||
 | 
					    } = {}) {
 | 
				
			||||||
 | 
					        console.log(basePath)
 | 
				
			||||||
 | 
					        return new Promise((resolve, reject) => {
 | 
				
			||||||
 | 
					            let url = basePath + "/" + item + "/index.html"
 | 
				
			||||||
 | 
					            console.log("Loading", url)
 | 
				
			||||||
 | 
					            this.loadHTML(url)
 | 
				
			||||||
 | 
					                .then(html => {
 | 
				
			||||||
 | 
					                    console.log("Received", html)
 | 
				
			||||||
 | 
					                    let element = this.createCardScatter(html, scatterContainer, {
 | 
				
			||||||
 | 
					                        basePath,
 | 
				
			||||||
 | 
					                        modules
 | 
				
			||||||
 | 
					                    })
 | 
				
			||||||
 | 
					                    if (onClose)
 | 
				
			||||||
 | 
					                        this.addOnCloseListener(element, onClose)
 | 
				
			||||||
 | 
					                    resolve(element)
 | 
				
			||||||
 | 
					                })
 | 
				
			||||||
 | 
					                .catch(e => reject(e))
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    static _setLanguage(context, language) {
 | 
				
			||||||
 | 
					        context.language = language
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    static _getLanguage(context) {
 | 
				
			||||||
 | 
					        return context.language
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ScatterCard.selectedLanguage = 0
 | 
				
			||||||
 | 
					ScatterCard.languages = ["Deutsch", "English"]
 | 
				
			||||||
 | 
					ScatterCard.languageTags = {
 | 
				
			||||||
 | 
					    Deutsch: "de",
 | 
				
			||||||
 | 
					    English: "en"
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					ScatterCard.scatterContainer = null
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user