Fixed closing issue with cards.

This commit is contained in:
2019-08-14 17:46:12 +02:00
parent 30c7113713
commit 28a7a0b6a2
6 changed files with 375 additions and 262 deletions
+161 -148
View File
@@ -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')
}
}