From 28a7a0b6a2657c9fa2a988e6086439d4e7c14379 Mon Sep 17 00:00:00 2001 From: Severin Opel Date: Wed, 14 Aug 2019 17:46:12 +0200 Subject: [PATCH] Fixed closing issue with cards. --- dist/iwmlib.js | 43 ++++-- dist/iwmlib.pixi.js | 19 ++- lib/card/card.js | 206 ++++++++++++++++++-------- lib/card/plugin.js | 309 ++++++++++++++++++++------------------- lib/card/scatter.js | 58 +++----- lib/card/test/index.html | 2 + 6 files changed, 375 insertions(+), 262 deletions(-) diff --git a/dist/iwmlib.js b/dist/iwmlib.js index d1ebd35..a76f664 100644 --- a/dist/iwmlib.js +++ b/dist/iwmlib.js @@ -2772,7 +2772,9 @@ for (let j = 0; j < elements.length; j++) { // if(elements[j].tagName == "svg") return false; - let hammer = new Hammer(elements[j], opts); + const target = elements[j]; + + let hammer = new Hammer(target, opts); if (window.propagating !== 'undefined') { hammer = propagating(hammer); @@ -2793,16 +2795,23 @@ hammer.get('tap').set(opts); } + console.log('APPLY HAMMER ON', type); + + target.addEventListener("click", ()=>{ + console.log("Hello"); + }); + hammer.on(type, event => { + console.log('FIRED'); cb(event); }); - if (Hammer.__hammers.has(elements[j])) { - const elementHammers = Hammer.__hammers.get(elements[j]); + if (Hammer.__hammers.has(target)) { + const elementHammers = Hammer.__hammers.get(target); elementHammers.push(hammer); - Hammer.__hammers.set(elements[j], elementHammers); + Hammer.__hammers.set(target, elementHammers); } else { - Hammer.__hammers.set(elements[j], [hammer]); + Hammer.__hammers.set(target, [hammer]); } } } else { @@ -7709,8 +7718,9 @@ * @memberof Card */ static _replaceAttributes(context, html, attribute, replaceFunc) { - let clickables = html.querySelectorAll(`[${attribute}]`); - clickables.forEach(element => { + let attributeCarrier = html.querySelectorAll(`[${attribute}]`); + attributeCarrier.forEach(element => { + console.log(element); let attributeVal = element.getAttribute(attribute); element.removeAttribute(attribute); replaceFunc.call(this, context, element, attributeVal); @@ -7759,10 +7769,13 @@ // These are 'hardcoded' inside the convert.js. if (element.tagName == 'circle') return false + console.log("Replace" , context, element, attributeVal); + this.registerEvent(context, interactionType, element, event => { /** * Replaces the strings from the listener with the cooresponding variables. */ + console.log("EVENT"); let args = []; argsStrings.forEach(arg => { arg = arg.trim(); @@ -7811,13 +7824,6 @@ /<\s*(a|video|img|image|circle)\s(.*?)(xlink:href|href|src)\s*=\s*["'](\..*?)["']\s*(.*?)>/g, function(data) { let path = that._getRelativePath(arguments[4]); - - console.log('REPLACE ', arguments[1]); - if (arguments[1] == 'a') { - console.error('NOT REPLACING LINKS'); - return '' - } - const tag = `<${arguments[1]} ${arguments[2]} ${arguments[3]}="${path}" ${arguments[5]}>`; /* if (that.debug) */ console.log('Adjusted: ', tag); return tag @@ -9152,7 +9158,7 @@ * @memberof Card */ static openIndexCard(event, src) { - //console.log("openIndexCard", src) + console.log("openIndexCard", src); /* * Called by the expandIndexCard(...) */ @@ -9324,6 +9330,7 @@ let parser = new DOMParser(); let html = parser.parseFromString(htmlString, 'text/html'); if (!editable) { + console.log("REPLACE ONCLICK"); this._replaceAttributes(context, html, 'onclick', this._replaceCallback); } let zoomableWrappers = html.querySelectorAll('.svg-wrapper'); @@ -9562,7 +9569,10 @@ * @memberof Card */ static registerEvent(context, types, element, callback) { - InteractionMapper.on(types, element, callback); + console.log("REGISTER INTERACTION EVENT",context, types, element, callback); + InteractionMapper.on(types, element, ()=>{ + console.log("HELLO"); + }); if (context._registeredEvents == null) context._registeredEvents = []; if (context._registeredEvents.indexOf(element) == -1) context._registeredEvents.push(element); } @@ -10202,6 +10212,7 @@ context.classList.add('info-card'); this.relativePath = basePath; + console.log(htmlString); htmlString = this._adjustRelativeLinks(htmlString); let parser = new DOMParser(); diff --git a/dist/iwmlib.pixi.js b/dist/iwmlib.pixi.js index 2461bab..816d9d7 100644 --- a/dist/iwmlib.pixi.js +++ b/dist/iwmlib.pixi.js @@ -6396,7 +6396,9 @@ for (let j = 0; j < elements.length; j++) { // if(elements[j].tagName == "svg") return false; - let hammer = new Hammer(elements[j], opts); + const target = elements[j]; + + let hammer = new Hammer(target, opts); if (window.propagating !== 'undefined') { hammer = propagating(hammer); @@ -6417,16 +6419,23 @@ hammer.get('tap').set(opts); } + console.log('APPLY HAMMER ON', type); + + target.addEventListener("click", ()=>{ + console.log("Hello"); + }); + hammer.on(type, event => { + console.log('FIRED'); cb(event); }); - if (Hammer.__hammers.has(elements[j])) { - const elementHammers = Hammer.__hammers.get(elements[j]); + if (Hammer.__hammers.has(target)) { + const elementHammers = Hammer.__hammers.get(target); elementHammers.push(hammer); - Hammer.__hammers.set(elements[j], elementHammers); + Hammer.__hammers.set(target, elementHammers); } else { - Hammer.__hammers.set(elements[j], [hammer]); + Hammer.__hammers.set(target, [hammer]); } } } else { diff --git a/lib/card/card.js b/lib/card/card.js index 800cb1b..366710e 100644 --- a/lib/card/card.js +++ b/lib/card/card.js @@ -1,5 +1,6 @@ +'use strict' -'use strict'; +import Highlight from './highlight.js' /** To avoid problems with relative URL paths, we use inline data URI to load svg icons. */ const closeIconDataURI = `data:image/svg+xml;utf8, @@ -33,10 +34,17 @@ const enableNearestNeighborTaps = false export default class Card { static setup(context, modules = []) { console.log('Setup Card...', modules) - context.modules = [] + /** + * This is required for the callback functions to work properly. + */ + window.Card = Card + + context.modules = [] context.module = {} + context.onClose = null + context.classList.add('info-card') context.setAttribute('data-id', Card.id++) @@ -51,16 +59,57 @@ export default class Card { static remove(context) { for (let module of Object.values(context.module)) { - module.remove() + const moduleHasRemoveFunction = typeof module.remove === 'function' + if (moduleHasRemoveFunction) module.remove() } } - static eventClose(event) { + static close(event) { let context = this.getContext(event.target) - if (context) { - this.constructor.close(context) - } else console.error('Could not find context!', event.target) + if (context.onClose != null) { + context.onClose() + } else { + this.remove(context) + } + + // console.error("Remove") + // let context = this.getContext(event.target) + + // if (context) { + // this.remove(context) + // } else console.error('Could not find context!', event.target) + } + + /** + * Adds an on close method to the provided context. + * This will overwrite the default closing behaviour. + * Removing the + * + * @static + * @param {DOMElement} context - Context on which the onClose will be set. + * @param {Function} callback - Callback function of the onClose. + * @memberof Card + */ + static setOnClose(context, callback) { + if (context.onClose != null) console.error('OnClose was already set. It was overwritten by the new method.') + context.onClose = callback + } + + /** + * Unsets the onClose. + * + * Note: This may be used in conjunction with the setOnClose method. + * Using the setOnClose method to adjust behaviour before closing the card. + * Then unsetting the onClose to close the Card appropriately by calling the + * Card.Close again. + * + * @static + * @param {DOMElement} context - Context on which the remove will be executed. + * @memberof Card + */ + static removeOnClose(context) { + context.onClose = null } /** @@ -70,12 +119,12 @@ export default class Card { * @param {*} event * @memberof Card */ - static close(context) { - console.log('CLOSE CARD!!!') - this.unregisterAllEvents(context) - if (context.onClose) { - context.onClose(event) - } else context.parentNode.removeChild(context) + static remove(context) { + if (context.parentNode != null) { + context.parentNode.removeChild(context) + } else { + console.error('Tried removing card but it was already removed.') + } } /** @@ -88,8 +137,8 @@ export default class Card { * @memberof Card */ static _replaceAttributes(context, html, attribute, replaceFunc) { - let clickables = html.querySelectorAll(`[${attribute}]`) - clickables.forEach(element => { + let attributeCarrier = html.querySelectorAll(`[${attribute}]`) + attributeCarrier.forEach(element => { let attributeVal = element.getAttribute(attribute) element.removeAttribute(attribute) replaceFunc.call(this, context, element, attributeVal) @@ -124,11 +173,23 @@ export default class Card { let argsStrings = trimmedArgs.split(',').filter(entry => { return entry.trim() != '' }) - + /** + * As we determine a function by a string we must traverse from the window object to + * get the associated javascript function. + */ let callStack = window + let last = 'window' do { - callStack = callStack[callParts.shift().trim()] + let func = callParts.shift().trim() + if (callStack[func] == null) { + callStack = null + console.error( + `Could not access callback function: ${attributeVal}. Member ${func} of ${last} could not be found.` + ) + break + } else callStack = callStack[func] } while (callParts.length > 0) + let targetFunc = callStack let that = this @@ -161,8 +222,9 @@ export default class Card { } }) event.stopPropagation() - if (callStack) callStack.call(that, ...args) - else { + if (targetFunc) { + targetFunc.call(that, ...args) + } else { console.error('Could not call callback function ' + attributeVal, ...args) } }) @@ -190,13 +252,6 @@ export default class Card { /<\s*(a|video|img|image|circle)\s(.*?)(xlink:href|href|src)\s*=\s*["'](\..*?)["']\s*(.*?)>/g, function(data) { let path = that._getRelativePath(arguments[4]) - - console.log('REPLACE ', arguments[1]) - if (arguments[1] == 'a') { - console.error('NOT REPLACING LINKS') - return '' - } - const tag = `<${arguments[1]} ${arguments[2]} ${arguments[3]}="${path}" ${arguments[5]}>` /* if (that.debug) */ console.log('Adjusted: ', tag) return tag @@ -751,7 +806,7 @@ export default class Card { let point = svgPoint.matrixTransform(matrix) let closestDiv = node.closest('div') - console.log('closestDiv', closestDiv, point) + // console.log('closestDiv', closestDiv, point) let global = Points.fromNodeToPage(closestDiv, point) let local = Points.fromPageToNode(context, global) @@ -763,7 +818,7 @@ export default class Card { // we could load the data while the circle is animating. // but for simplicity it's just done here for now. // TODO: Adjust to load while animating (Problem: Unload when cancelled). - console.log('loadHighlightPopup', src, position, local) + // console.log('loadHighlightPopup', src, position, local) this._loadPopupContent(context, src) .then(content => { this._openPopup(context, src, local, content, { @@ -1214,7 +1269,7 @@ export default class Card { * * @param {*} card - The card to expand * @param {string} html - The original HTML of the card - * @param {*} tagName - The tagname of the element that is used as exanded element + * @param {*} tagName - The tagname of the element that is used as expanded element * @param {*} src - The src of the expanded element * @param {*} callback - A callback that is called when the expanded element is closed */ @@ -1257,7 +1312,6 @@ export default class Card { let scaleY = globalPreviewRect.height / globalIndexCardRect.height let padding = parseInt(this.css(indexbox, 'padding')) - let maxWidth = this.css(card, 'max-width') TweenLite.set(clone, { css: { @@ -1295,7 +1349,6 @@ export default class Card { if (this.dynamicHeight) { let targetHeight = subcardContent.offsetHeight - console.log(targetHeight) subcardContent.classList.add('dynamic-height') /** * Scale the content from 100% to it's target size. @@ -1309,7 +1362,7 @@ export default class Card { } //jquery hyphenate below - if (this.constructor._jQueryIsPresent()) { + if (this._isJQueryPresent()) { $('.column') .not('.overview') .children('p') @@ -1389,7 +1442,7 @@ export default class Card { if (enableNearestNeighborTaps) { //look for nearby popups on tap InteractionMapper.on('tap', indexbox, () => { - console.log('Tap handler called', editable) + // console.log('Tap handler called', editable) if (!editable) { this.findNearbyPopups(event, card) } @@ -1407,24 +1460,55 @@ export default class Card { if (isDirty) { mainController.saveNode(html.innerHTML, url => { callback(url) - this._closeIndexCard(context, card,{ + this._closeIndexCard(context, card, clone, articleClone, { eventElements, src }) }) } else { - this._closeIndexCard(context, card) + this._closeIndexCard(context, card, clone, articleClone) } } else { - this._closeIndexCard(context, card) + this._closeIndexCard(context, card, clone, articleClone) } }) } - static _closeIndexCard(context, card, { - eventElements = [], - src = null - } = []) { + /** + * Closes the index card again. + * + * @static + * @param {DOMElement} context - The Card element. + * @param {DOMElement} subcard - The original subcard element visible on the main card. + * @param {DOMElement} clonedSubcard - The cloned subcard that's going to be expanded. + * @param {DOMElement} clonedArticle - The article part of the ClonedSubcard. + * @param {Object} [{ eventElements = [], src = null }=[]] + * @memberof Card + */ + static _closeIndexCard( + context, + subcard, + clonedSubcard, + clonedArticle, + + { eventElements = [], src = null } = [] + ) { + let indexbox = context.querySelector('.mainview') + let padding = parseInt(this.css(indexbox, 'padding')) + + let globalPreviewRect = Card._getGlobalRect(subcard) + let globalIndexCardRect = Card._getGlobalRect(indexbox) + + let scale = { + x: globalPreviewRect.width / globalIndexCardRect.width, + y: globalPreviewRect.height / globalIndexCardRect.height + } + + let titlebar = clonedSubcard.querySelector('.titlebar') + + let desiredBorderBottomWidth = parseInt(window.getComputedStyle(titlebar).borderBottomWidth) + let localOrigin = Points.fromPageToNode(indexbox, Rect.getPosition(globalPreviewRect)) + //logging if (src) { let strparts = src.split('/') @@ -1442,15 +1526,14 @@ export default class Card { this._subcardChanged(context, true) this._enableCardCloseButton(context) - let previewTitlebar = card.querySelector('.titlebar') + let previewTitlebar = subcard.querySelector('.titlebar') let titlebarStyle = window.getComputedStyle(previewTitlebar) - let titlebar = clone.querySelector('.titlebar') TweenLite.to(titlebar, this.animation.articleTransition, { height: parseInt(titlebarStyle.height) }) - TweenLite.to(articleClone, this.animation.articleTransition / 2, { + TweenLite.to(clonedArticle, this.animation.articleTransition / 2, { autoAlpha: 0 }) @@ -1465,24 +1548,25 @@ export default class Card { }) } - TweenLite.set(card, { autoAlpha: 1, css: { maxWidth } }) - TweenLite.to(clone, this.animation.articleTransition, { + let maxWidth = this.css(subcard, 'max-width') + TweenLite.set(subcard, { autoAlpha: 1, css: { maxWidth } }) + TweenLite.to(clonedSubcard, this.animation.articleTransition, { x: localOrigin.x - padding, y: localOrigin.y - padding, - scaleX, - scaleY, - ease: ExpoScaleEase.config(1, scaleX), - rotation: angle, + scaleX: scale.x, + scaleY: scale.y, + ease: ExpoScaleEase.config(1, scale.x), + // rotation: angle, onComplete: () => { // article.remove() - TweenLite.to(clone, this.animation.fade, { + TweenLite.to(clonedSubcard, this.animation.fade, { //delay: 0.2, autoAlpha: 0, onComplete: () => { - if (editable) { + if (Card.isEditable()) { mainController.popController() } - clone.remove() + clonedSubcard.remove() } }) }, @@ -1508,7 +1592,7 @@ export default class Card { * Tests if jQuery is properly included in the project. * Otherwise specific features may not work correctly (e.g. hyphenation) */ - _jQueryIsPresent() { + static _isJQueryPresent() { let jQueryInitialized = typeof $ != 'undefined' if (!jQueryInitialized) console.error('No jQuery is provided. Specific features may fail.') return jQueryInitialized @@ -1542,7 +1626,7 @@ export default class Card { * @memberof Card */ static openIndexCard(event, src) { - //console.log("openIndexCard", src) + console.log('openIndexCard', src) /* * Called by the expandIndexCard(...) */ @@ -1593,9 +1677,7 @@ export default class Card { } static _enableCardCloseButton(context) { - //console.log("ENABLE") let btn = this._selectCardCloseButton(context) - //console.log(btn) btn.classList.remove('disabled') } @@ -1706,11 +1788,9 @@ export default class Card { * @memberof Card */ static postProcessResponseText(context, htmlString) { - console.error('RUN POSTPROCESS') let editable = this.isEditable() htmlString = this._adjustRelativeLinks(htmlString) - //console.log(htmlString) let parser = new DOMParser() let html = parser.parseFromString(htmlString, 'text/html') if (!editable) { @@ -1835,7 +1915,7 @@ export default class Card { this._setPopupSource(popup, source) context.popup = popup - if (this.constructor._jQueryIsPresent()) { + if (this._isJQueryPresent()) { //jquery hyphenate below console.log('hyphenated popup:', $('span').hyphenate('de')) } @@ -1908,6 +1988,14 @@ export default class Card { context.subcard = null } + static _subcardChanged(context, closed = false) { + for (let [key, module] of Object.entries(context.module)) { + if (module.subcardChanged) { + module.subcardChanged(closed) + } + } + } + static incrementZIndex(context) { if (!context.zIndex) context.zIndex = 0 context.zIndex++ diff --git a/lib/card/plugin.js b/lib/card/plugin.js index 18e1fac..1cb7957 100644 --- a/lib/card/plugin.js +++ b/lib/card/plugin.js @@ -2,6 +2,7 @@ export var CardPlugin = CardPlugin || {} export class CardPluginBase { apply(context) { + this.context = context if (this.verify(context)) { this.append(context) console.log('Plugin ' + this.name + ' was verified successfully.') @@ -91,6 +92,14 @@ export class CardPluginBase { } return requirements } + + /** + * Called when the card is removed. + * Can be used to cleanup the plugin. + * + * @memberof CardPluginBase + */ + remove() {} } CardPlugin.LightBox = class LightBox extends CardPluginBase { @@ -392,130 +401,135 @@ CardPlugin.Speech = class SpeechPlugin extends CardPluginBase { this.parentSelector = parentSelector this.interactionType = interactionType - + // We directly overwriting the function with a version that has a binded + // reference to itself. Doing so provides an easy and reliable way to remove + // the event listener using this function. - SO + this._domWasChanged = this._domWasChanged.bind(this) - /* + /* Speech doesn't stop when page is navigated. Therefore we do it manually here. */ - window.addEventListener('beforeunload', () => { - window.speechSynthesis.cancel() - }) + window.addEventListener('beforeunload', () => { + window.speechSynthesis.cancel() + }) - // Binding the function beforehand ensures, that the end function is always the same. - this._end = this._end.bind(this) + // Binding the function beforehand ensures, that the end function is always the same. + this._end = this._end.bind(this) - this._setupUtterance() - this.utterance.addEventListener('end', event => { - this._end() - }) -} - -get require() { - return [CardPlugin.Ui] -} - -subcardChanged(closed) { - if (this.cardActive) { - this._updateText(closed) + this._setupUtterance() + this.utterance.addEventListener('end', event => { + this._end() + }) } -} -get cardActive() { - return this.activeUtterance == this.utterance -} + get require() { + return [CardPlugin.Ui] + } -_updateText(ignoreSubcard = false) { - let node = this.context - let subcard = this.context.querySelector('.mainview > .subcard') + subcardChanged(closed) { + if (this.cardActive) { + this._updateText(closed) + } + } - if (ignoreSubcard) { + get cardActive() { + return this.activeUtterance == this.utterance + } + + _updateText(ignoreSubcard = false) { + let node = this.context + let subcard = node.querySelector('.mainview > .subcard') + + if (ignoreSubcard) { + if (subcard != null) { + let clone = node.cloneNode(true) + let clonedSubcard = clone.querySelector('.mainview > .subcard') + clonedSubcard.parentNode.removeChild(clonedSubcard) + node = clone + } + } else { + if (subcard) { + let clone = subcard.cloneNode(true) + clone.querySelectorAll('figure').forEach(figure => { + figure.parentNode.removeChild(figure) + }) + + node = clone + } + } + + let id = this.context.getAttribute('data-id') + let src = this.context.getAttribute('data-source') + let subcardSource = null if (subcard != null) { - let clone = node.cloneNode(true) - let clonedSubcard = clone.querySelector('.mainview > .subcard') - clonedSubcard.parentNode.removeChild(clonedSubcard) - node = clone + subcardSource = subcard.getAttribute('data-source') } - } else { - if (subcard) { - let clone = subcard.cloneNode(true) - clone.querySelectorAll('figure').forEach(figure => { - figure.parentNode.removeChild(figure) - }) - node = clone + if (!window.speechSynthesis.speaking) { + this._start(node) + Logging.log(`Started speech on card: id:${id} - source: ${src} - subcard: ${subcardSource}`) + } else if (this.cardActive && this._sameText(node)) { + Logging.log(`Stopped speech on card: id:${id} - source: ${src} - subcard: ${subcardSource}`) + this._stop() + } else { + Logging.log(`Updated Text on card: id:${id} - source: ${src} - subcard: ${subcardSource}`) + this._stop() + .then(() => { + this._start(node) + }) + .catch(console.error) } } - let id = this.context.getAttribute('data-id') - let src = this.context.getAttribute('data-source') - let subcardSource = null - if (subcard != null) { - subcardSource = subcard.getAttribute('data-source') + _sameText(node) { + return this.utterance.text == this._cleanupText(node) } - if (!window.speechSynthesis.speaking) { - this._start(node) - Logging.log(`Started speech on card: id:${id} - source: ${src} - subcard: ${subcardSource}`) - } else if (this.cardActive && this._sameText(node)) { - Logging.log(`Stopped speech on card: id:${id} - source: ${src} - subcard: ${subcardSource}`) - this._stop() - } else { - Logging.log(`Updated Text on card: id:${id} - source: ${src} - subcard: ${subcardSource}`) - this._stop() - .then(() => { - this._start(node) - }) - .catch(console.error) + _setupUtterance() { + this.utterance = new SpeechSynthesisUtterance() + this.utterance.lang = 'de-DE' } -} -_sameText(node) { - return this.utterance.text == this._cleanupText(node) -} + get require() { + return [CardPlugin.Ui] + } -_setupUtterance() { - this.utterance = new SpeechSynthesisUtterance() - this.utterance.lang = 'de-DE' -} + remove() { + this.button = null + this.context.removeEventListener('DOMNodeRemoved', this._domWasChanged) + super.remove() + } -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) -remove() { - this.button = null - super.remove() -} + InteractionMapper.on(this.interactionType, this.button, () => { + this.speak() + }) -append(context) { - let container = context.querySelector(this.parentSelector) - this.button = document.createElement('div') - this.button.className = 'icon button ' + this.className - container.appendChild(this.button) + context.addEventListener('DOMNodeRemoved', this._domWasChanged) + } - InteractionMapper.on(this.interactionType, this.button, () => { - this.speak() - }) - - this.context.addEventListener('DOMNodeRemoved', event => { - if ( + _domWasChanged(event) { + if (this.context == null) this._stop() + else if ( this.context['lastSpeechNode'] == window.speechSynthesis['speechPluginNode'] && event.target == this.context ) { this._stop() } - }) + } - ScatterCard -} + _isSameNode(node) { + return this.currentText == node.textContent + } -_isSameNode(node) { - return this.currentText == node.textContent -} - -speak() { - /** + speak() { + /** * This is a little bit ugly, but imho the most elegant of all dirty solutions. * 5ht * Within the plugins we have no knowledge of other cards and such. But must differentiate the @@ -529,63 +543,62 @@ speak() { * SO -17.07.19 */ - let activeNode = window.speechSynthesis['speechPluginNode'] - this._updateText() -} + let activeNode = window.speechSynthesis['speechPluginNode'] + this._updateText() + } -async _stop() { - return new Promise(resolve => { - if (this.activeUtterance) { - this.activeUtterance.addEventListener('end', resolve, { - once: true - }) - } + async _stop() { + return new Promise(resolve => { + if (this.activeUtterance) { + this.activeUtterance.addEventListener('end', resolve, { + once: true + }) + } + window.speechSynthesis.cancel() + }) + } + + get activeUtterance() { + return window.speechSynthesis['speechPluginUtterance'] + } + + _end() { + window.speechSynthesis['speechPluginNode'] = null + window.speechSynthesis['speechPluginUtterance'] = null + this._deactivateButton() + this.context.classList.remove('speech-plugin-is-reading') + } + + _start(node) { window.speechSynthesis.cancel() - }) + + window.speechSynthesis['speechPluginUtterance'] = this.utterance + window.speechSynthesis['speechPluginNode'] = node + this.context['lastSpeechNode'] = node + + let cleanText = this._cleanupText(node) + this.utterance.text = cleanText + window.speechSynthesis.speak(this.utterance) + this._activateButton() + + this.context.classList.add('speech-plugin-is-reading') + } + + _cleanupText(node) { + let text = node.textContent + text = this._removeShy(text) + return text + } + + _removeShy(text) { + return text.replace(/\u00AD/g, '') + } + + _activateButton() { + if (this.button) this.button.classList.add('active') + } + _deactivateButton() { + if (this.button) this.button.classList.remove('active') + } } - -get activeUtterance() { - return window.speechSynthesis['speechPluginUtterance'] -} - -_end() { - window.speechSynthesis['speechPluginNode'] = null - window.speechSynthesis['speechPluginUtterance'] = null - this._deactivateButton() - this.context.classList.remove('speech-plugin-is-reading') -} - -_start(node) { - window.speechSynthesis.cancel() - - window.speechSynthesis['speechPluginUtterance'] = this.utterance - window.speechSynthesis['speechPluginNode'] = node - this.context['lastSpeechNode'] = node - - let cleanText = this._cleanupText(node) - this.utterance.text = cleanText - window.speechSynthesis.speak(this.utterance) - this._activateButton() - - this.context.classList.add('speech-plugin-is-reading') -} - -_cleanupText(node) { - let text = node.textContent - text = this._removeShy(text) - return text -} - -_removeShy(text) { - return text.replace(/\u00AD/g, '') -} - -_activateButton() { - if (this.button) this.button.classList.add('active') -} -_deactivateButton() { - if (this.button) this.button.classList.remove('active') -} - -} \ No newline at end of file diff --git a/lib/card/scatter.js b/lib/card/scatter.js index 8a60b16..c978055 100644 --- a/lib/card/scatter.js +++ b/lib/card/scatter.js @@ -18,6 +18,17 @@ export default class ScatterCard extends Card { * @memberof ScatterCard */ static setup(context, htmlString, { basePath = './', modules = [] } = {}) { + if (typeof context.scatter == 'undefined') { + console.error( + "You need to wrap the context inside a DOMScatter before executing the ScatterCard's setup function." + ) + } + + /** + * This is required for the callback functions to work properly + */ + window.ScatterCard = ScatterCard + context.classList.add('info-card') this.relativePath = basePath @@ -38,29 +49,6 @@ export default class ScatterCard extends Card { 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 - } - } - /** - * Removes the close listener from a card element. - * - * @static - * @param {HTMLElement} element - Context of the Card. - * @memberof ScatterCard - */ - static removeOnCloseListener(element) { - element.onClose = null - } /** * Creates a scatter for the card and applies the card to it, * @@ -95,15 +83,19 @@ export default class ScatterCard extends Card { * of the scatter. */ static close(context) { - - Card.close(context) - - if (context['scatter']) { - console.error('CLOSED CARD') - context.scatter.close() - } else { + if (typeof context.scatter != 'undefined') context.scatter.close() + else { console.error('Expected a scatter element to close!', this) } + + // Card.close(context) + + // if (context['scatter']) { + // console.error('CLOSED CARD') + // context.scatter.close() + // } else { + // console.error('Expected a scatter element to close!', this) + // } } /** @@ -116,14 +108,13 @@ export default class ScatterCard extends Card { static remove(context) { if (context['scatter']) { context.scatter = null - console.error('REMOVED CARD') } else { console.error('Expected a scatter element to remove!', this) } Card.remove(context) } - + /** *Utility function to create a fully functional card scatter. * @@ -135,7 +126,7 @@ export default class ScatterCard extends Card { * @returns * @memberof CardScatter */ - static loadAndCreateScatterCard(scatterContainer, item, { basePath = '../', modules = [], onClose = null } = {}) { + static loadAndCreateScatterCard(scatterContainer, item, { basePath = '../', modules = [] } = {}) { console.log(basePath) return new Promise((resolve, reject) => { let url = basePath + '/' + item + '/index.html' @@ -147,7 +138,6 @@ export default class ScatterCard extends Card { basePath, modules }) - if (onClose) this.addOnCloseListener(element, onClose) resolve(element) }) .catch(e => reject(e)) diff --git a/lib/card/test/index.html b/lib/card/test/index.html index 475c9f1..0133bad 100644 --- a/lib/card/test/index.html +++ b/lib/card/test/index.html @@ -64,6 +64,8 @@ }) }) + createCard() + function createCard() { const path = './example/01/index.html'