aircox/assets/public/app.js
2021-03-05 18:19:49 +01:00

96 lines
2.8 KiB
JavaScript

import Vue from 'vue';
export const defaultConfig = {
el: '#app',
delimiters: ['[[', ']]'],
computed: {
player() { return window.aircox.player; },
},
}
export default class AppBuilder {
constructor(config={}) {
this._config = config;
this.title = null;
this.app = null;
}
get config() {
let config = this._config instanceof Function ? this._config() : this._config;
for(var k of new Set([...Object.keys(config || {}), ...Object.keys(defaultConfig)])) {
if(!config[k] && defaultConfig[k])
config[k] = defaultConfig[k]
else if(config[k] instanceof Object)
config[k] = {...defaultConfig[k], ...config[k]}
}
return config;
}
set config(value) {
this._config = value;
}
destroy() {
self.app && self.app.$destroy();
self.app = null;
}
fetch(url, {el='app', ...options}={}) {
return fetch(url, options).then(response => response.text())
.then(content => {
let doc = new DOMParser().parseFromString(content, 'text/html');
let app = doc.getElementById('app');
content = app ? app.innerHTML : content;
return this.load({sync: true, content, title: doc.title, url })
})
}
load({async=false,content=null,title=null,el='app'}={}) {
var self = this;
return new Promise((resolve, reject) => {
let func = () => {
try {
let config = self.config;
const el = document.querySelector(config.el);
if(!el)
return reject(`Error: can't get element ${config.el}`)
if(content)
el.innerHTML = content
if(title)
document.title = title;
this.app = new Vue(config);
window.scroll(0, 0);
resolve(self.app)
} catch(error) {
self.destroy();
reject(error)
}};
async ? window.addEventListener('load', func) : func();
});
}
/// Save application state into browser history
historySave(url,replace=false) {
const el = document.querySelector(this.config.el);
const state = {
content: el.innerHTML,
title: document.title,
};
if(replace)
history.replaceState(state, '', url)
else
history.pushState(state, '', url)
}
/// Load application from browser history's state
historyLoad(state) {
return this.load({ content: state.content, title: state.title });
}
}