/* * Lightbox window */ // import Events from './_events' const W = window class MetaWindow { state = { content: '', type: ['empty'], shown: false, loading: false, error: false, embed: false, collections: [], current: null, target: null, extraClass: null, } cleanLinks () { document.querySelectorAll('[data-toggle="lightbox"]') .forEach((el) => { el.classList.remove('loading') }) } collectGaleries (gallery) { const ui = this if (!gallery) { return } ui.state.collections[gallery] = [] document .querySelectorAll( `[data-toggle="lightbox"][data-gallery="${gallery}"]` ) .forEach((el) => { ui.state.collections[gallery].push(el) }) } toggle (el) { const ui = this ui.cleanLinks() const link = el.getAttribute('href') || el.getAttribute('data-href') const embed = el.getAttribute('data-embed') el.classList.add('loading') ui.state.current = el const title = el.getAttribute('data-title') if (title) { ui.setCaption(title) } if (embed) { ui.embed(link) } else { ui.load(link) } ui.addExtraClass(el.getAttribute('data-lightbox-class')) } init () { const ui = this console.log('MetaWindow: [links] init') document .querySelectorAll('[data-toggle="lightbox"],[data-gallery]') .forEach((el) => { const gallery = el.getAttribute('data-gallery') ui.collectGaleries(gallery) // click handler el.addEventListener('click', (e) => { e.preventDefault() console.log('MetaWindow: [link] click') const el = e.currentTarget ui.toggle(el) }) }) } constructor ( state = { shown: false, }, action ) { const ui = this ui.name = ui.constructor.name console.log(`${ui.name}: init`) ui.setState(state) switch (action) { case 'show': ui.hide() break case 'hide': ui.hide() break } W.dispatchEvent(new Event('{ui.name}.init')) } show = () => { const ui = this console.log(`${ui.name}: show`) ui.setState({ shown: true, }) W.dispatchEvent(new Event('{ui.name}.show')) } hide = () => { const ui = this console.log(`${ui.name}: hide`) ui.setState({ shown: false, }) W.dispatchEvent(new Event('{ui.name}.hide')) } next = () => { const ui = this const el = ui.state.current const gallery = el.getAttribute('data-gallery') let i = ui._currIndex() if (i < ui.state.collections[gallery].length - 1) { i++ } else { i = 0 } ui.state.collections[gallery][i].click() console.log(`${ui.name}: next`) W.dispatchEvent(new Event('{ui.name}.next')) } prev = () => { const ui = this const el = ui.state.current const gallery = el.getAttribute('data-gallery') let i = ui._currIndex() if (i > 0) { i-- } else { i = ui.state.collections[gallery].length - 1 } ui.state.collections[gallery][i].click() console.log(`${ui.name}: prev`) W.dispatchEvent(new Event('{ui.name}.prev')) } reset = () => { const ui = this ui.setState({ content: '', type: ['empty'], shown: false, loading: false, error: false, embed: false, // collections: [], // current: null, // target: null, }) } load = (link) => { const ui = this ui.reset() ui.setState({ loading: true, }) ui.show() window.fetch(link).then((resp) => { // handle success const type = resp.headers.get('content-type') console.log(resp) console.log( `${ui.name}: response content-type: ${type}` ) const json = false switch (type) { case 'image/jpeg': case 'image/png': case 'image/svg+xml': case 'image/bmp': case 'image/gif': case 'image/tiff': case 'image/webp': case 'image/jpg': case 'image/svg': // json = JSON.parse(ui._abToString(resp.data)); resp.arrayBuffer().then((buffer) => { ui.setContent( ``, `meta-${ui.name}--image` ) }) break case 'application/json': case 'application/ld+json': case 'application/json; charset=UTF-8': ui.setContent(`${json.Content}`, [ `meta-${ui.name}--text`, `meta-${ui.name}--html`, `meta-${ui.name}--json`, ]) break case 'video/mp4': ui.setContent(``, [ `meta-${ui.name}--image`, `meta-${ui.name}--video`, ]) break case 'text/html': case 'application/xhtml+xml': case 'text/plain': case 'text/html; charset=UTF-8': case 'application/xhtml+xml; charset=UTF-8': case 'text/plain; charset=UTF-8': ui.setContent(resp.data, [ `meta-${ui.name}--text`, `meta-${ui.name}--html`, `meta-${ui.name}--pajax`, ]) break default: console.warn(`${ui.name}: Unknown response content-type!`) break } W.dispatchEvent(new Event('{ui.name}.loaded')) }) .catch((error) => { console.error(error) let msg = '' if (error.response) { switch (error.response.status) { case 404: msg = 'Not Found.' break case 500: msg = 'Server issue, please try again latter.' break default: msg = 'Something went wrong.' break } } else if (error.request) { msg = 'No response received' } else { console.warn('Error', error.message) } ui.setState({ error: msg, }) W.dispatchEvent(new Event('{ui.name}.error')) }) .then(() => { ui.setState({ loading: false, }) setTimeout(() => { ui.state.current.classList.remove('loading') }, 1000) }) } _currIndex = () => { const ui = this const el = ui.state.current const gallery = el.getAttribute('data-gallery') return ui.state.collections[gallery].indexOf(el) } embed = (link) => { const ui = this console.log(`${ui.name}: embed`) ui.reset() ui.setState({ embed: link, loading: false, type: [`meta-${ui.name}--embed`, `meta-${ui.name}--video`], }) ui.show() } setCaption = (title) => { const ui = this console.log(`${ui.name}: setCaption`) ui.state.caption = title } addExtraClass = (cls) => { const ui = this if (!cls || !cls.length) { return } console.log(`${ui.name}: addExtraClass(${cls})`) ui.state.extraClass = cls } getCaption = () => { const ui = this return ui.state.caption } /* _abToString = (arrayBuffer) => { return String.fromCharCode.apply(null, new Uint8Array(arrayBuffer)); }; */ _imageEncode = (buffer) => { let binary = '' const bytes = [].slice.call(new Uint8Array(buffer)) bytes.forEach((b) => { binary += String.fromCharCode(b) }) return window.btoa(binary) } setContent = (html, type) => { const ui = this console.log(`${ui.name}: setContent`) let typeArr = type || [`meta-${ui.name}--html`, `meta-${ui.name}--text`] if (!Array.isArray(typeArr)) { typeArr = type.split(' ') } ui.setState({ content: html, type: typeArr, }) } getHtml = () => { const ui = this if (ui.state.embed) { const youtubeEmbed = require('youtube-embed') const embedLink = youtubeEmbed(ui.state.embed) ui.state.content = `` } return ui.state.content } setState (state) { const ui = this ui.state = Object.assign({}, ui.state, state) ui.render() } render () { const ui = this const name = ui.name const el = ui.state.current ui.state.target.innerHTML = '' const meta = document.createElement('div') meta.classList.add(`meta-${name}`) meta.classList.add(...ui.state.type) ui.state.target.append(meta) const metaOverlay = document.createElement('div') metaOverlay.classList.add(`meta-${name}-overlay`) if (ui.state.shown) { metaOverlay.classList.add(`meta-${name}-overlay--open`) } if (ui.state.loading) { metaOverlay.classList.add(`meta-${name}-overlay--loading`) } if (ui.state.error) { metaOverlay.classList.add(`meta-${name}-overlay--error`) } meta.append(metaOverlay) const metaContent = document.createElement('div') metaContent.classList.add('meta-content') metaOverlay.append(metaContent) const btnClose = document.createElement('button') btnClose.classList.add('meta-nav', 'meta-close', 'a') btnClose.innerHTML = '' + ' Close' btnClose.addEventListener('click', (e) => { e.preventDefault() ui.hide() }) metaContent.append(btnClose) if (el) { const gallery = el.getAttribute('data-gallery') if (gallery && ui.state.collections[gallery].length > 1) { const navs = document.createElement('nav') navs.classList.add('meta-navs') const prevBtn = document.createElement('button') prevBtn.classList.add( 'meta-nav', 'meta-nav-arrow', 'meta-nav-arrow__prev', 'a' ) prevBtn.innerHTML = '' + ' Previous' prevBtn.addEventListener('click', (e) => { e.preventDefault() ui.prev() }) navs.append(prevBtn) const nextBtn = document.createElement('button') nextBtn.classList.add( 'meta-nav', 'meta-nav-arrow', 'meta-nav-arrow__next', 'a' ) nextBtn.innerHTML = '' + ' Next' nextBtn.addEventListener('click', (e) => { e.preventDefault() ui.next() }) navs.append(nextBtn) metaContent.append(navs) } } const content = document.createElement('section') content.classList.add('meta-wrap', 'typography') if (ui.state.extraClass) { content.classList.add(ui.state.extraClass) } content.innerHTML = ui.getHtml() metaContent.append(content) if (ui.state.error) { const error = document.createElement('div') error.classList.add('meta-error') error.innerHTML = ui.state.error metaContent.append(error) } else if (ui.state.caption) { const caption = document.createElement('div') caption.classList.add('meta-caption') caption.innerHTML = ui.getCaption() metaContent.append(caption) } // update fontawesome dome if (typeof window.FontAwesome !== 'undefined') { window.FontAwesome.dom.i2svg() } return ui } } export default MetaWindow