njpma/app/static/js/pandora-scroll.js

136 lines
3.7 KiB
JavaScript

class PandoraScroll extends HTMLElement {
constructor() {
super()
if (this.attributes.src && this.attributes.src.value) {
const attributes = parseIframeURL(this.attributes.src.value)
Object.keys(attributes).forEach(key => {
if (key[0] != '_') {
this.setAttribute(key, attributes[key])
}
})
}
const shadow = this.attachShadow({mode: 'open'})
const link = document.createElement('link')
link.rel = 'stylesheet'
link.href = document.head.querySelector('link[rel="stylesheet"]').href
const style = document.createElement('style')
const body = document.createElement('div')
body.classList.add('pandora-scroll')
shadow.appendChild(link)
shadow.appendChild(style)
shadow.appendChild(body)
this.mute = function() {
shadow.querySelectorAll('video').forEach(video => {
video.muted = true
})
}
}
static get observedAttributes() { return ['muted']; }
connectedCallback() {
console.log('scroll connected')
this._loadAnnotations()
this._updateStyle()
}
disconnectedCallback() {
console.log('scroll disconnected')
}
adoptedCallback() {
console.log('Custom square element moved to new page.');
}
attributeChangedCallback(name, oldValue, newValue) {
console.log('value changed', name, oldValue, newValue);
this._updateStyle()
}
_updateStyle() {
const shadow = this.shadowRoot;
const childNodes = shadow.childNodes;
for (const node of childNodes) {
if (node.nodeName === 'STYLE') {
node.textContent = `
.pandora-scroll {
position: relative;
display: block;
}
`
}
}
}
_config() {
var config = {}
for (var i=0; i<this.attributes.length; i++) {
var a = this.attributes[i]
config[a.name] = a.value
if (a.name == 'layers') {
config[a.name] = a.value.split(' ')
} else if (['in', 'out'].indexOf(a.name) > -1) {
config[a.name] = parseTime(a.value)
} else {
config[a.name] = a.value
}
}
return config
}
_loadAnnotations() {
var config = this._config()
config.root = this.shadowRoot.querySelector('.pandora-scroll')
console.log(config)
loadAnnotations(config)
}
}
customElements.define("pandora-scroll", PandoraScroll);
function parseTime(value) {
return value.split(":").map(p => parseFloat(p)).reduce((c, p) => { return c*60 + p}, 0)
}
function isInside(config, annotation) {
if (!config['in'] && !config['out']) {
return true
}
if (annotation['in'] < config['out'] && annotation['out'] > config['in']) {
return true
}
return false
}
function parseIframeURL(value) {
var config = {}
value = value.replace('/player/', '/')
value = value.replace('/editor/', '/')
var data = value.split('#embed?')
function decodeValue(value) {
return decodeURIComponent(value)
.replace(/_/g, ' ').replace(/\t/g, '_')
.replace(/\x0E/g, '<').replace(/\x0F/g, '>');
}
var args = data[1].replace('&amp;', '&').split('&').map(kv => {
kv = kv.split('=')
console.log(kv, decodeValue(kv[1]))
return [kv[0], JSON.parse(decodeValue(kv[1]))]
}).reduce((k, v) => {
k[v[0]] = v[1]
return k
}, {})
var parts = data[0].split('/')
config.item = parts[3]
var ts = parts[4].split(',')
config['in'] = ts[0]
config['out'] = ts[1]
config._args = args
if (args.showLayers) {
config.layers = args.showLayers.join(' ')
}
if (args.showTimeline) {
config.timeline = "slitscan"
}
return config
}