forked from rc/aircox
		
	radiocampus: style update
This commit is contained in:
		
							
								
								
									
										179
									
								
								radiocampus/assets/src/pageLoad.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										179
									
								
								radiocampus/assets/src/pageLoad.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,179 @@
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Load page without leaving current one (hot-reload).
 | 
			
		||||
 */
 | 
			
		||||
export default class PageLoad {
 | 
			
		||||
    constructor(el, {loadingClass="loading", append=false}={}) {
 | 
			
		||||
        this.el = el
 | 
			
		||||
        this.append = append
 | 
			
		||||
        this.loadingClass = loadingClass
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    get target() {
 | 
			
		||||
        if(!this._target)
 | 
			
		||||
            this._target = document.querySelector(this.el)
 | 
			
		||||
        return this._target
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    reset() {
 | 
			
		||||
        this._target = null
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Enable hot reload: catch page change in order to fetch them and
 | 
			
		||||
     * load page without actually leaving current one.
 | 
			
		||||
     */
 | 
			
		||||
    enable(target=null) {
 | 
			
		||||
        if(this._pageChanged)
 | 
			
		||||
            throw "Already enabled, please disable me"
 | 
			
		||||
 | 
			
		||||
        if(!target)
 | 
			
		||||
            target = this.target || document.body
 | 
			
		||||
        this.historySave(document.location, true)
 | 
			
		||||
 | 
			
		||||
        this._pageChanged = event => this.pageChanged(event)
 | 
			
		||||
        this._statePopped = event => this.statePopped(event)
 | 
			
		||||
 | 
			
		||||
        target.addEventListener('click', this._pageChanged, true)
 | 
			
		||||
        target.addEventListener('submit', this._pageChanged, true)
 | 
			
		||||
        window.addEventListener('popstate', this._statePopped, true)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Disable hot reload, remove listeners.
 | 
			
		||||
     */
 | 
			
		||||
    disable() {
 | 
			
		||||
        this.target.removeEventListener('click', this._pageChanged, true)
 | 
			
		||||
        this.target.removeEventListener('submit', this._pageChanged, true)
 | 
			
		||||
        window.removeEventListener('popstate', this._statePopped, true)
 | 
			
		||||
 | 
			
		||||
        this._pageChanged = null
 | 
			
		||||
        this._statePopped = null
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
    * Fetch url, return promise, similar to standard Fetch API.
 | 
			
		||||
    * Default implementation just forward argument to it.
 | 
			
		||||
    */
 | 
			
		||||
    fetch(url, options) {
 | 
			
		||||
        return fetch(url, options)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Fetch app from remote and mount application.
 | 
			
		||||
     */
 | 
			
		||||
    load(url, {mount=true,  scroll=[0,0], ...options}={}) {
 | 
			
		||||
        if(this.loadingClass)
 | 
			
		||||
            this.target.classList.add(this.loadingClass)
 | 
			
		||||
 | 
			
		||||
        if(this.onLoad)
 | 
			
		||||
            this.onLoad({url, el: this.el, options})
 | 
			
		||||
        if(scroll)
 | 
			
		||||
            window.scroll(...scroll)
 | 
			
		||||
        return this.fetch(url, options).then(response => response.text())
 | 
			
		||||
            .then(content => {
 | 
			
		||||
                if(this.loadingClass)
 | 
			
		||||
                    this.target.classList.remove(this.loadingClass)
 | 
			
		||||
 | 
			
		||||
                var doc = new DOMParser().parseFromString(content, 'text/html')
 | 
			
		||||
                var dom = doc.querySelectorAll(this.el)
 | 
			
		||||
                var result = {url,
 | 
			
		||||
                              content: dom || [document.createTextNode(content)],
 | 
			
		||||
                              title: doc.title,
 | 
			
		||||
                              append: this.append}
 | 
			
		||||
                mount && this.mount(result)
 | 
			
		||||
                return result
 | 
			
		||||
            })
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
    * Mount the page on provided target element
 | 
			
		||||
    */
 | 
			
		||||
    mount({content, title=null, ...options}={}) {
 | 
			
		||||
        if(this.onPreMount)
 | 
			
		||||
            this.onPreMount({target: this.target, content, items, title})
 | 
			
		||||
        var items = null;
 | 
			
		||||
        if(content)
 | 
			
		||||
            items = this.mountContent(content, options)
 | 
			
		||||
        if(title)
 | 
			
		||||
            document.title = title
 | 
			
		||||
        if(this.onMount)
 | 
			
		||||
            this.onMount({target: this.target, content, items, title})
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
    * Mount page content
 | 
			
		||||
    */
 | 
			
		||||
    mountContent(content, {append=false}={}) {
 | 
			
		||||
        if(typeof content == "string") {
 | 
			
		||||
            this.target.innerHTML = append ? this.target.innerHTML + content
 | 
			
		||||
                                           : content;
 | 
			
		||||
            // TODO
 | 
			
		||||
            return []
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if(!append)
 | 
			
		||||
            this.target.innerHTML = ""
 | 
			
		||||
 | 
			
		||||
        var fragment = document.createDocumentFragment()
 | 
			
		||||
        var items = []
 | 
			
		||||
        for(var node of content)
 | 
			
		||||
            while(node.firstChild) {
 | 
			
		||||
                items.push(node.firstChild)
 | 
			
		||||
                fragment.appendChild(node.firstChild)
 | 
			
		||||
            }
 | 
			
		||||
        this.target.append(fragment)
 | 
			
		||||
        return items
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Save application state into browser history
 | 
			
		||||
    historySave(url,replace=false) {
 | 
			
		||||
        const state = { content: this.target.innerHTML,
 | 
			
		||||
                        title: document.title, }
 | 
			
		||||
        if(replace)
 | 
			
		||||
            history.replaceState(state, '', url)
 | 
			
		||||
        else
 | 
			
		||||
            history.pushState(state, '', url)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    dispatchPageLoaded(url) {
 | 
			
		||||
        var evt = new CustomEvent("pageLoaded", {detail: url})
 | 
			
		||||
        document.dispatchEvent(evt)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // --- events
 | 
			
		||||
    pageChanged(event) {
 | 
			
		||||
        let submit = event.type == 'submit';
 | 
			
		||||
        let target = submit || event.target.tagName == 'A'
 | 
			
		||||
                        ? event.target : event.target.closest('a');
 | 
			
		||||
        if(!target || target.hasAttribute('target') || (target.dataset && target.dataset.forceReload))
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        let url = submit ? target.getAttribute('action') || ''
 | 
			
		||||
                         : target.getAttribute('href');
 | 
			
		||||
        let domain = window.location.protocol + '//' + window.location.hostname
 | 
			
		||||
        let stay = (url === '' || url.startsWith('/') || url.startsWith('?') ||
 | 
			
		||||
                    url.startsWith(domain)) && url.indexOf('wp-admin') == -1
 | 
			
		||||
        if(url===null || !stay) {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        let options = {};
 | 
			
		||||
        if(submit) {
 | 
			
		||||
            let formData = new FormData(event.target);
 | 
			
		||||
            if(target.method == 'get')
 | 
			
		||||
                url += '?' + (new URLSearchParams(formData)).toString();
 | 
			
		||||
            else
 | 
			
		||||
                options = {...options, method: target.method, body: formData}
 | 
			
		||||
        }
 | 
			
		||||
        this.load(url, options).then(() => this.dispatchPageLoaded(url)).then(() => this.historySave(url))
 | 
			
		||||
        event.preventDefault();
 | 
			
		||||
        event.stopPropagation();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    statePopped(event) {
 | 
			
		||||
        const state = event.state
 | 
			
		||||
        if(state && state.content)
 | 
			
		||||
            this.mount({ content: state.content, title: state.title });
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user