Merge branch 'master' of gitea.iwm-tuebingen.de:IWMBrowser/iwmlib

This commit is contained in:
2019-07-19 08:39:08 +02:00
125 changed files with 11184 additions and 8154 deletions
+482 -380
View File
File diff suppressed because it is too large Load Diff
+50 -37
View File
@@ -4,17 +4,15 @@
let _HighlightEnabled = true
let _CircleIds = 0
/** Helper method to round values with one digit precision */
function round(value) {
return Math.round(parseFloat(value) * 10) / 10
}
/**
* A namespace with static functions to expand and shrink highlighted image regions.
* Assumes an SVG image with the following structure:
*
*
* <svg viewbox="0 0 100 100">
* <!-- The defs section must be defined and cannot be generated in JavaScript -->
* <defs>
@@ -23,15 +21,14 @@ function round(value) {
* <circle onclick="Highlight.animateZoom(event)" cx="47" cy="18" r="8" stroke-width="0.5" />
* <circle onclick="Highlight.animateZoom(event)" cx="60" cy="67" r="8" stroke-width="0.5" />
* </svg>
*
*
* The SVG root element should use a viewbox with 0 0 100 100 to ensure that the positions and size of the
* circles can be represnted in percent.
*
*
* @class Highlight
* @extends {Object}
*/
export default class Highlight extends Object {
static disableAnimations() {
_HighlightEnabled = false
let expanded = document.querySelectorAll('.expanded')
@@ -64,7 +61,10 @@ export default class Highlight extends Object {
if (circle.classList.length == 0) {
circle.removeAttribute('class')
}
if (circle.hasAttribute('id') && circle.getAttribute('id').startsWith('@@')) {
if (
circle.hasAttribute('id') &&
circle.getAttribute('id').startsWith('@@')
) {
circle.removeAttribute('id')
}
circle.removeAttribute('data-svg-origin')
@@ -79,9 +79,11 @@ export default class Highlight extends Object {
}
}
static expand(obj, { scale = 2, duration = 3, stroke = 2, onComplete = null } = {}) {
if (obj == null)
return
static expand(
obj,
{ scale = 2, duration = 3, stroke = 2, onComplete = null } = {}
) {
if (obj == null) return
//console.log("expand")
obj.classList.add('zooming')
TweenLite.to(obj, duration, {
@@ -102,8 +104,7 @@ export default class Highlight extends Object {
static shrink(obj, { duration = 0.5, stroke = 2 } = {}) {
//console.log("shrink")
if (obj == null)
return
if (obj == null) return
obj.classList.add('zooming')
TweenLite.to(obj, duration, {
scale: 1,
@@ -141,7 +142,6 @@ export default class Highlight extends Object {
let circleGroup = circle.parentNode
let image = svgRoot.querySelector('image')
let stroke = parseFloat(circleGroup.getAttribute('stroke-width') || 6)
let defs = svgRoot.querySelector('defs')
@@ -160,15 +160,16 @@ export default class Highlight extends Object {
this.shrink(maskImage, { stroke })
return
}
//console.log("animate called while zooming out -> expand")
}
else if (circle.classList.contains('zooming')) {
//console.log("animate called while zooming out -> expand")
} else if (circle.classList.contains('zooming')) {
//console.log("animate called while zooming in -> shrink")
this.shrink(circle, { stroke })
this.shrink(maskImage, { stroke })
return
}
let circles = Array.from(circleGroup.children).filter(e => e.tagName == 'circle')
let circles = Array.from(circleGroup.children).filter(
e => e.tagName == 'circle'
)
for (let c of circles) {
//console.log("shrinking all circles")
this.shrink(c, { stroke })
@@ -188,11 +189,10 @@ export default class Highlight extends Object {
return false
}
static openHighlight(target, {
animation = 0.5,
scale = 2,
onExpanded = null
} = {}) {
static openHighlight(
target,
{ animation = 0.5, scale = 2, onExpanded = null } = {}
) {
if (Highlight._isExpanded(target)) {
console.log('Target is already expanded!')
return
@@ -206,7 +206,10 @@ export default class Highlight extends Object {
let image = parent.querySelector(imageId)
if (image) {
this._bringToFront(image)
} else console.error('Could not find corresponding image element.')
} else
console.error(
'Could not find corresponding image element.'
)
} else console.log('Element was no parent:', target)
}
this._bringToFront(target)
@@ -215,10 +218,15 @@ export default class Highlight extends Object {
let image = svgRoot.querySelector('image')
// eslint-disable-next-line no-unused-vars
let [mask, maskImage] = Highlight._getSVGMask(target, { svgRoot, image })
let [mask, maskImage] = Highlight._getSVGMask(target, {
svgRoot,
image
})
let center = Highlight._calculateCenterRelativeTo(target, image)
TweenLite.set(maskImage, { transformOrigin: `${center.x}% ${center.y}%` })
TweenLite.set(maskImage, {
transformOrigin: `${center.x}% ${center.y}%`
})
TweenLite.set(target, { transformOrigin: '50% 50%' })
TweenLite.to([target, maskImage], animation, {
@@ -233,8 +241,7 @@ export default class Highlight extends Object {
static toggleHighlight(node) {
if (Highlight._isExpanded(node)) {
Highlight.closeHighlight(node)
}
else {
} else {
Highlight.openHighlight(node)
}
}
@@ -244,7 +251,12 @@ export default class Highlight extends Object {
if (target && parent) {
parent.removeChild(target)
parent.appendChild(target)
} else console.error('Could not bring to front. Either no target or no parent.', target, parent)
} else
console.error(
'Could not bring to front. Either no target or no parent.',
target,
parent
)
}
static _getSVGMask(circle, { svgRoot = null, image = null } = {}) {
@@ -258,13 +270,15 @@ export default class Highlight extends Object {
let maskImage = svgRoot.getElementById(maskImageId)
if (!mask || !maskImage)
[mask, maskImage] = Highlight._createSVGMask(circle, { svgRoot, image, id })
[mask, maskImage] = Highlight._createSVGMask(circle, {
svgRoot,
image,
id
})
return [mask, maskImage]
}
/**
* Creates an SVG mask for a provided svgElement.
*
@@ -277,8 +291,10 @@ export default class Highlight extends Object {
* @returns
* @memberof Highlight
*/
static _createSVGMask(element, { svgRoot = null, image = null, id = null } = {}) {
static _createSVGMask(
element,
{ svgRoot = null, image = null, id = null } = {}
) {
// We can fetch these values here, but it's more efficient to
// simply pass them in, as it's likely they were already retrieved beforehand.
if (svgRoot == null) svgRoot = element.closest('svg')
@@ -316,7 +332,6 @@ export default class Highlight extends Object {
let height = bbox.height
if (maskImage == null) {
maskImage = document.createElementNS(svg, 'image')
maskImage.style.pointerEvents = 'none'
maskImage.setAttribute('id', maskImageId)
@@ -369,8 +384,7 @@ export default class Highlight extends Object {
}
static animate(event) {
if (!_HighlightEnabled)
return
if (!_HighlightEnabled) return
event.stopPropagation()
Highlight.animateCircle(event.target)
@@ -394,4 +408,3 @@ export default class Highlight extends Object {
}
Highlight.expandedClass = 'expanded'
+160 -132
View File
@@ -1,13 +1,12 @@
export var CardPlugin = CardPlugin || {}
export class CardPluginBase {
apply(context) {
if (this.verify(context)) {
this.append(context)
console.log("Plugin " + this.name + " was verified successfully.")
console.log('Plugin ' + this.name + ' was verified successfully.')
return true
} else console.error("Could not verify module " + this.name + ".")
} else console.error('Could not verify module ' + this.name + '.')
return false
}
@@ -32,19 +31,20 @@ export class CardPluginBase {
missing.push(selector)
}
}
const valid = (missing.length == 0)
if (!valid) console.error("Elements were missing: ", missing.join(", "))
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!")
console.error(
'Call of abstract method CardPlugin.prototype.append(context). Plugins need to overwrite the append method!'
)
}
_getVerificationFunctions(context) {
@@ -56,7 +56,7 @@ export class CardPluginBase {
_verifyContext(context) {
if (!(context instanceof HTMLElement)) {
console.error("Context is not of type HTML Element.", context)
console.error('Context is not of type HTML Element.', context)
return false
} else return true
}
@@ -71,13 +71,18 @@ export class CardPluginBase {
}
})
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!")
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__
@@ -91,9 +96,6 @@ export class CardPluginBase {
}
}
CardPlugin.LightBox = class LightBox extends CardPluginBase {
constructor(className, style = {}) {
super()
@@ -102,27 +104,30 @@ CardPlugin.LightBox = class LightBox extends CardPluginBase {
}
append(context) {
let wrapper = document.createElement("div")
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",
})
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.
@@ -131,12 +136,15 @@ CardPlugin.LightBox = class LightBox extends CardPluginBase {
* @extends {CardPlugin}
*/
CardPlugin.EnlargeableThumbnail = class EnlargeableThumbnail extends CardPluginBase {
constructor(wrapperSelector, overlaySelector = null, {
zoomAnimationDuration = 0.4,
fadeAnimationDuration = 0.4,
interactionType = "tap"
} = {}) {
constructor(
wrapperSelector,
overlaySelector = null,
{
zoomAnimationDuration = 0.4,
fadeAnimationDuration = 0.4,
interactionType = 'tap'
} = {}
) {
super()
this.wrapperSelector = wrapperSelector
this.overlaySelector = overlaySelector
@@ -147,15 +155,18 @@ CardPlugin.EnlargeableThumbnail = class EnlargeableThumbnail extends CardPluginB
}
get require() {
return [
CardPlugin.LightBox
]
return [CardPlugin.LightBox]
}
_getVerificationFunctions(context) {
let arr = super._getVerificationFunctions(context)
let funcs = [
this._verifyElementsExist.bind(this, context, this.wrapperSelector, this.overlaySelector)
this._verifyElementsExist.bind(
this,
context,
this.wrapperSelector,
this.overlaySelector
)
]
return arr.concat(funcs)
}
@@ -165,7 +176,6 @@ CardPlugin.EnlargeableThumbnail = class EnlargeableThumbnail extends CardPluginB
this.setupEnlargeableThumbnail(context, source)
}
/**
* Get the preview image.
*
@@ -177,26 +187,25 @@ CardPlugin.EnlargeableThumbnail = class EnlargeableThumbnail extends CardPluginB
* @memberof EnlargeableThumbnail
*/
_retrieveSource(context) {
let img = context.querySelector(this.wrapperSelector + " img")
let src = img.getAttribute("src")
let parts = src.split("/")
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"
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"
let icon = document.createElement('div')
icon.className = 'button corner-button bottom-right icon zoom'
wrapper.appendChild(icon)
Object.assign(wrapper.style, {
cursor: "pointer"
cursor: 'pointer'
})
InteractionMapper.on(this.interactionType, wrapper, () => {
@@ -209,28 +218,28 @@ CardPlugin.EnlargeableThumbnail = class EnlargeableThumbnail extends CardPluginB
}
openThumbnailDetail(context, src) {
let overlay = context.querySelector(".img-overlay")
overlay.innerHTML = ""
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")
let image = imageWrapper.querySelector('img')
Object.assign(imageWrapper.style, {
maxWidth: "none",
maxHeight: "none"
maxWidth: 'none',
maxHeight: 'none'
})
Object.assign(image.style, {
width: "100%",
height: "100%",
objectFit: "cover"
width: '100%',
height: '100%',
objectFit: 'cover'
})
this._replaceIcon(imageWrapper)
image.onload = () => {
let header = context.querySelector("header")
let header = context.querySelector('header')
let headerStlye = window.getComputedStyle(header)
/**
@@ -242,20 +251,20 @@ CardPlugin.EnlargeableThumbnail = class EnlargeableThumbnail extends CardPluginB
/**
* 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 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" }
const _width = { name: 'width', axis: 'x' }
const _height = { name: 'height', axis: 'y' }
if (image.naturalHeight > image.naturalWidth) {
majorSide = _height
minorSide = _width
@@ -268,14 +277,17 @@ CardPlugin.EnlargeableThumbnail = class EnlargeableThumbnail extends CardPluginB
return string.charAt(0).toUpperCase() + string.slice(1)
}
function getImageSize(side) {
return image["natural" + capitalize(side.name)]
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
let size =
majorImageSize > max[majorSide.name]
? max[majorSide.name]
: majorImageSize
if (size * ratio > maxMinorSize) {
size = maxMinorSize / ratio
@@ -286,8 +298,10 @@ CardPlugin.EnlargeableThumbnail = class EnlargeableThumbnail extends CardPluginB
height: 0
}
let position = Points.fromPageToNode(context, Points.fromNodeToPage(source, { x: 0, y: 0 }))
let position = Points.fromPageToNode(
context,
Points.fromNodeToPage(source, { x: 0, y: 0 })
)
let targetOffset = {
x: 0,
@@ -297,8 +311,14 @@ CardPlugin.EnlargeableThumbnail = class EnlargeableThumbnail extends CardPluginB
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
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)
@@ -307,14 +327,13 @@ CardPlugin.EnlargeableThumbnail = class EnlargeableThumbnail extends CardPluginB
top: 0,
x: position.x,
y: position.y,
position: "absolute",
position: 'absolute',
width: parseInt(sourceStyle.width),
height: parseInt(sourceStyle.height)
})
TweenMax.set(overlay, {
display: "flex",
display: 'flex',
autoAlpha: 0
})
@@ -322,7 +341,7 @@ CardPlugin.EnlargeableThumbnail = class EnlargeableThumbnail extends CardPluginB
x: targetOffset.x,
y: targetOffset.y,
width: targetDimensions.width,
height: targetDimensions.height,
height: targetDimensions.height
})
TweenMax.to(overlay, this.fadeAnimationTime, {
autoAlpha: 1
@@ -333,35 +352,40 @@ CardPlugin.EnlargeableThumbnail = class EnlargeableThumbnail extends CardPluginB
}
_replaceIcon(clone) {
let zoomIcon = clone.querySelector(".icon.zoom")
zoomIcon.classList.remove("zoom")
zoomIcon.classList.add("close")
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)
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)
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 overlay = context.querySelector('.img-overlay')
let timeline = new TimelineLite()
timeline.to(overlay, this.fadeAnimationDuration, {
autoAlpha: 0
}).set(overlay, {
display: "none"
})
timeline
.to(overlay, this.fadeAnimationDuration, {
autoAlpha: 0
})
.set(overlay, {
display: 'none'
})
}
}
CardPlugin.Ui = class UiPlugin extends CardPluginBase {
@@ -373,56 +397,52 @@ CardPlugin.Ui = class UiPlugin extends CardPluginBase {
_getVerificationFunctions(context) {
let arr = super._getVerificationFunctions(context)
let func = [
this._doesParentExist.bind(this, context, this.parent)
]
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)
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")
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") {
constructor(parentSelector, className, interactionType = 'tap') {
super()
this.className = className
this.parentSelector = parentSelector
this.interactionType = interactionType
}
get require() {
return [
CardPlugin.Ui
]
return [CardPlugin.Ui]
}
append(context) {
let container = context.querySelector(this.parentSelector)
this.button = document.createElement("div")
this.button.className = "icon button " + this.className
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
let subcard = context.querySelector('.mainview > .subcard')
let target = subcard ? subcard : context
this.speak(target)
})
}
@@ -433,8 +453,7 @@ CardPlugin.Speech = class SpeechPlugin extends CardPluginBase {
}
_activateButton() {
if (this.button)
this.button.classList.add("active")
if (this.button) this.button.classList.add('active')
}
_deactivate() {
@@ -442,36 +461,32 @@ CardPlugin.Speech = class SpeechPlugin extends CardPluginBase {
}
_deactivateButton() {
if (this.button)
this.button.classList.remove("active")
if (this.button) this.button.classList.remove('active')
}
_isSameNode(node) {
//console.log(this.currentText, node.innerText)
return (this.currentText == node.innerText)
return this.currentText == node.innerText
}
speak(node) {
console.log(this._isSameNode(node))
if (!window.speechSynthesis.speaking) {
console.log("Noone talking!")
console.log('Noone talking!')
this._start(node)
} else if (this._isSameNode(node)) {
console.log("Requested same!")
console.log('Requested same!')
this._stop()
} else {
console.log("Requested Different!")
console.log('Requested Different!')
this._stop()
this._start(node)
}
}
_disableActive() {
console.log("disableActive:", this.active)
console.log('disableActive:', this.active)
if (this.active) {
this.active._deactivate()
}
@@ -483,28 +498,40 @@ CardPlugin.Speech = class SpeechPlugin extends CardPluginBase {
let voices = window.speechSynthesis.getVoices()
console.log(voices)
let voice = voices.filter((val) => {
let voice = voices.filter(val => {
//console.log(val)
return val.name == "Microsoft Hedda Desktop - German"
return val.name == 'Microsoft Hedda Desktop - German'
})[0]
//console.log(voice)
utterance.voice = voice
console.log("TALK: ", utterance)
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)
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() {
@@ -517,7 +544,9 @@ CardPlugin.Speech = class SpeechPlugin extends CardPluginBase {
return this.constructor.active
}
set active(val) { this.constructor.active = val }
set active(val) {
this.constructor.active = val
}
get currentText() {
return this.constructor.text
@@ -526,5 +555,4 @@ CardPlugin.Speech = class SpeechPlugin extends CardPluginBase {
set currentText(val) {
this.constructor.text = val
}
}
+31 -39
View File
@@ -6,8 +6,6 @@ import Card from './card.js'
* @class ScatterCard
*/
export default class ScatterCard extends Card {
/**
* TODO: Find a more suitable name.
* Adjusts the HTML to work in the new context.
@@ -19,32 +17,27 @@ export default class ScatterCard extends Card {
* @param {*} [opts={}]
* @memberof Card
*/
static setup(context, htmlString, {
basePath = "./",
modules = []
} = {}) {
context.classList.add("info-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")
let html = parser.parseFromString(htmlString, 'text/html')
/**
* Conflicts with the FindTarget method of the Abstract scatter.
*/
this._replaceAttributes(html, "onclick", this._replaceCallback)
this._replaceAttributes(html, 'onclick', this._replaceCallback)
let content = html.querySelector(".mainview")
let content = html.querySelector('.mainview')
context.appendChild(content)
super.setup(context, modules)
return context
}
/**
* Appends a close listener to the scatter element.
*
@@ -59,7 +52,6 @@ export default class ScatterCard extends Card {
}
}
/**
* Creates a scatter for the card and applies the card to it,
*
@@ -71,11 +63,12 @@ export default class ScatterCard extends Card {
* @returns
* @memberof Card
*/
static createCardScatter(html, scatterContainer, {
basePath = "./",
modules = []
} = {}) {
let element = document.createElement("div")
static createCardScatter(
html,
scatterContainer,
{ basePath = './', modules = [] } = {}
) {
let element = document.createElement('div')
scatterContainer.element.appendChild(element)
new DOMScatter(element, scatterContainer, {
@@ -90,8 +83,6 @@ export default class ScatterCard extends Card {
return element
}
/**
*Utility function to create a fully functional card scatter.
*
@@ -103,24 +94,27 @@ export default class ScatterCard extends Card {
* @returns
* @memberof CardScatter
*/
static loadAndCreateScatterCard(scatterContainer, item, {
basePath = "../",
modules = [],
onClose = null
} = {}) {
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)
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)
console.log('Received', html)
let element = this.createCardScatter(
html,
scatterContainer,
{
basePath,
modules
}
)
if (onClose) this.addOnCloseListener(element, onClose)
resolve(element)
})
.catch(e => reject(e))
@@ -134,14 +128,12 @@ export default class ScatterCard extends Card {
static _getLanguage(context) {
return context.language
}
}
ScatterCard.selectedLanguage = 0
ScatterCard.languages = ["Deutsch", "English"]
ScatterCard.languages = ['Deutsch', 'English']
ScatterCard.languageTags = {
Deutsch: "de",
English: "en"
Deutsch: 'de',
English: 'en'
}
ScatterCard.scatterContainer = null
+3 -6
View File
@@ -7,7 +7,6 @@
* @class Theme
*/
export default class Theme {
/**
* Loads a config file and parses it to JSON.
*
@@ -18,17 +17,15 @@ export default class Theme {
*/
static loadConfig(path = null) {
return new Promise((resolve, reject) => {
path = (path) ? path : './config.json'
path = path ? path : './config.json'
let xhttp = new XMLHttpRequest()
xhttp.onreadystatechange = function () {
xhttp.onreadystatechange = function() {
if (this.readyState == 4) {
if (this.status == 200 || Theme._isLocal()) {
try {
const json = JSON.parse(this.responseText)
resolve(json)
} catch (e) {
reject(e)
}
@@ -41,6 +38,6 @@ export default class Theme {
}
static _isLocal() {
return (window.location.protocol == 'file:')
return window.location.protocol == 'file:'
}
}
+53 -43
View File
@@ -5,8 +5,10 @@ import Events from '../events.js'
import { Points } from '../utils.js'
export default class CardWrapper extends Object {
constructor(domNode, { triggerSVGClicks = true, allowClickDistance = 44 } = {}) {
constructor(
domNode,
{ triggerSVGClicks = true, allowClickDistance = 44 } = {}
) {
super()
this.domNode = domNode
this.triggerSVGClicks = triggerSVGClicks
@@ -16,42 +18,43 @@ export default class CardWrapper extends Object {
}
handleClicks() {
this.domNode.addEventListener('click', event => {
if (event.isTrusted) {
Events.stop(event)
if (this.triggerSVGClicks && this.isSVGNode(event.target)) {
this.tap(event, "triggerSVGClicks")
this.domNode.addEventListener(
'click',
event => {
if (event.isTrusted) {
Events.stop(event)
if (this.triggerSVGClicks && this.isSVGNode(event.target)) {
this.tap(event, 'triggerSVGClicks')
}
}
}
}, true)
},
true
)
}
handleClicksAsTaps() {
this.domNode.addEventListener('click', event => {
if (event.isTrusted) {
Events.stop(event)
}
this.tap(event)
}, true)
this.domNode.addEventListener(
'click',
event => {
if (event.isTrusted) {
Events.stop(event)
}
this.tap(event)
},
true
)
}
isClickable(node) {
if (node == null)
return false
if (node.tagName == 'A' && node.hasAttribute("href"))
return true
if (node.hasAttribute("onclick"))
return true
if (node == null) return false
if (node.tagName == 'A' && node.hasAttribute('href')) return true
if (node.hasAttribute('onclick')) return true
return false
}
hasClickHandler(node) {
if (node == null)
return false
if (this.tapNodes.has(node))
return true
if (node == null) return false
if (this.tapNodes.has(node)) return true
for (let [selector, handler] of this.tapHandler.entries()) {
for (let obj of this.domNode.querySelectorAll(selector)) {
if (node == obj) {
@@ -68,15 +71,13 @@ export default class CardWrapper extends Object {
* See https://stackoverflow.com/questions/11455515/how-to-check-whether-dynamically-attached-event-listener-exists-or-not
* Therefore we can only detect the following standard cases:
* I. All clickable objects like activeNodes
* II. Objects that have been attached a click handler by the scatter itself via
* II. Objects that have been attached a click handler by the scatter itself via
*/
activeNodes() {
let result = []
for (let node of this.domNode.querySelectorAll("*")) {
if (this.isClickable(node))
result.push(node)
if (this.hasClickHandler(node))
result.push(node)
for (let node of this.domNode.querySelectorAll('*')) {
if (this.isClickable(node)) result.push(node)
if (this.hasClickHandler(node)) result.push(node)
}
return result
}
@@ -84,14 +85,26 @@ export default class CardWrapper extends Object {
nearestActive(event) {
let element = this.domNode
let activeNodes = this.activeNodes()
let globalClick = (event.center) ? event.center : { x: event.x, y: event.y }
let globalClick = event.center
? event.center
: { x: event.x, y: event.y }
let localClick = Points.fromPageToNode(element, globalClick)
let clickRects = activeNodes.map(link => {
let rect = link.getBoundingClientRect()
let topLeft = Points.fromPageToNode(element, rect)
let center = Points.fromPageToNode(element, { x: rect.x + rect.width / 2, y: rect.y + rect.height / 2 })
return { x: topLeft.x, y: topLeft.y, width: rect.width, height: rect.height, center, link }
let center = Points.fromPageToNode(element, {
x: rect.x + rect.width / 2,
y: rect.y + rect.height / 2
})
return {
x: topLeft.x,
y: topLeft.y,
width: rect.width,
height: rect.height,
center,
link
}
})
let distances = []
@@ -147,12 +160,12 @@ export default class CardWrapper extends Object {
return false
}
tap(event, calledBy='unknown') {
tap(event, calledBy = 'unknown') {
if (event.isTrusted) {
let node = this.nearestActive(event)
this.nodeTapped(node, event)
/* let node = document.elementFromPoint(event.clientX, event.clientY)
/* let node = document.elementFromPoint(event.clientX, event.clientY)
if (!this.nodeTapped(node, event)) {
node = this.nearestActive(event)
this.nodeTapped(node, event)
@@ -161,13 +174,10 @@ export default class CardWrapper extends Object {
}
onTap(objOrSelector, handler) {
if (typeof (objOrSelector) == 'string') {
if (typeof objOrSelector == 'string') {
this.tapHandler.set(objOrSelector, handler)
}
else {
} else {
this.tapNodes.set(objOrSelector, handler)
}
}
}