157 lines
4.6 KiB
JavaScript
157 lines
4.6 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)
|
|
window.addEventListener('resize', () => {
|
|
this._resize()
|
|
}, false)
|
|
|
|
this.mute = function() {
|
|
shadow.querySelectorAll('video').forEach(video => {
|
|
video.muted = true
|
|
})
|
|
}
|
|
}
|
|
|
|
|
|
static get observedAttributes() { return ['muted']; }
|
|
|
|
connectedCallback() {
|
|
this._loadAnnotations()
|
|
this._updateStyle()
|
|
}
|
|
disconnectedCallback() {
|
|
//console.log('scroll disconnected')
|
|
}
|
|
adoptedCallback() {
|
|
//console.log('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')
|
|
config.video = document.querySelector('video')
|
|
loadAnnotations(config).then(config => {
|
|
config.loaded = true
|
|
if (config.mode == "single") {
|
|
renderSingleMode(config)
|
|
} else {
|
|
config.annotations.forEach(annotation => {
|
|
annotation.src = `${streamPrefix}/${annotation.id.split('/')[0]}/480p.webm`
|
|
renderAnnotation(window.config, config.video, config.root, annotation)
|
|
})
|
|
}
|
|
})
|
|
}
|
|
|
|
_resize() {
|
|
var video = this.shadowRoot.querySelector('video')
|
|
if (video && video._frame) {
|
|
var rect = video._frame.getBoundingClientRect(),
|
|
root_rect = video._root.getBoundingClientRect(),
|
|
top = rect.top - root_rect.top;
|
|
video.style.top = top + 'px'
|
|
}
|
|
}
|
|
}
|
|
|
|
class PandoraItem extends HTMLElement {
|
|
constructor() {
|
|
super()
|
|
}
|
|
}
|
|
class PandoraEdit extends HTMLElement {
|
|
constructor() {
|
|
super()
|
|
}
|
|
}
|
|
|
|
customElements.define("pandora-scroll", PandoraScroll);
|
|
customElements.define("pandora-item", PandoraItem);
|
|
customElements.define("pandora-edit", PandoraEdit);
|
|
|
|
|
|
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('&', '&').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
|
|
}
|