UNPKG

dbm

Version:

254 lines (196 loc) 5.72 kB
import Dbm from "../index.js"; export default class SiteNavigation extends Dbm.core.BaseObject { _construct() { super._construct(); this.item.setValue("url", null); this.item.setValue("active", false); this.item.setValue("travelPaths", []); this.item.setValue("navigationLocks", []); this.item.setValue("allowedPaths", [ new RegExp(".*") ]); this.item.setValue("ignoredPaths", [ new RegExp("/assets/.*$"), new RegExp("/api/.*$"), ]); this._callback_beforeUnloadBound = this._callback_beforeUnload.bind(this); this._callback_clickBound = this._callback_click.bind(this); this._callback_popStateBound = this._callback_popState.bind(this); } start() { this._performStart(); this.item.active = true; return this; } _performStart() { window.addEventListener("beforeunload", this._callback_beforeUnloadBound, true); window.addEventListener("click", this._callback_clickBound, false); window.addEventListener("popstate", this._callback_popStateBound, false); } stop() { this._performStop(); this.item.active = false; return this; } _performStop() { window.removeEventListener("beforeunload", this._callback_beforeUnloadBound, true); window.removeEventListener("click", this._callback_clickBound, false); window.removeEventListener("popstate", this._callback_popStateBound, false); } _callback_beforeUnload(aEvent) { //METODO let isLocked = this.hasNavigationLock(); if(isLocked) { aEvent.preventDefault(); aEvent.returnValue = ""; return true; } return false; } _shouldHandle(aLink) { let shouldHandle = false; { let currentArray = this.item.allowedPaths; let currentArrayLength = currentArray.length; for(let i = 0; i < currentArrayLength; i++) { let currentIgnoredPattern = currentArray[i]; if(currentIgnoredPattern.test(aLink)) { shouldHandle = true; break; } } } if(!shouldHandle) { return false; } { let currentArray = this.item.ignoredPaths; let currentArrayLength = currentArray.length; for(let i = 0; i < currentArrayLength; i++) { let currentIgnoredPattern = currentArray[i]; if(currentIgnoredPattern.test(aLink)) { return false; } } } return true; } _hasSpecialKey(aEvent) { return aEvent.altKey || aEvent.ctrlKey || aEvent.metaKey || aEvent.shiftKey; } _callback_click(aEvent) { if(aEvent.defaultPrevented) { return true; } let shouldSkip = false; if(this._hasSpecialKey(aEvent)) { shouldSkip = true; } let link = null; let currentNode = aEvent.target; let debugCounter = 0; while(currentNode) { if(debugCounter++ > 10000) { console.error("Loop has run for too long"); break; } if(currentNode.localName === "a") { let hrefAttribute = currentNode.getAttribute("href"); if(hrefAttribute) { link = hrefAttribute.toString(); let hardNavigation = currentNode.getAttribute("data-not-spa-link"); if(hardNavigation) { shouldSkip = true; } let target = currentNode.getAttribute("target"); if(target === "_blank") { shouldSkip = true; } break; } } currentNode = currentNode.parentNode; } if(!link) { return true; } let trackingController = Dbm.getInstance().repository.getItem("trackingController").controller; if(trackingController) { if(link.indexOf("mailto:") === 0) { trackingController.trackEvent("link / email", {}); } else if(link.indexOf("tel:") === 0) { trackingController.trackEvent("link / phone", {}); } } if(shouldSkip) { return true; } if(link.indexOf("#") === 0) { return true; } let originalUrl = new URL(document.location.href); let finalUrl = new URL(link, document.location.href); if(originalUrl.hostname !== finalUrl.hostname) { return true; } if(!this._shouldHandle(finalUrl.href)) { return true; } aEvent.preventDefault(); this._internalNavigation(finalUrl.href); return false; } _addUrlToPath(aUrl) { let paths = [].concat(this.item.travelPaths); paths.push(aUrl); this.item.travelPaths = paths; } _internalNavigation(aUrl) { let locks = this.getLockedNavigationLocks(); if(locks.length > 0) { if(!confirm("Leave without saving changes?")) { return; } } history.pushState({}, "", aUrl); this.item.url = aUrl; this._addUrlToPath(aUrl); } _callback_popState(aEvent) { //console.log("_callback_popState"); let url = document.location.href; this.item.url = url; let paths = [].concat(this.item.travelPaths); paths.pop(); this.item.travelPaths = paths; } navigate(aUrl) { let originalUrl = new URL(document.location.href); let finalUrl = new URL(aUrl, document.location.href); if(this.item.active && originalUrl.hostname === finalUrl.hostname && this._shouldHandle(finalUrl.href)) { this._internalNavigation(finalUrl.href); } else { document.location.href = aUrl; } } updateQueryString(aUrl) { history.replaceState({}, "", aUrl); } setUrlFromLocation() { let url = document.location.href; this.item.url = url; this._addUrlToPath(url); return this; } getLockedNavigationLocks() { let locks = this.item.navigationLocks; let lockedLocks = locks; //METODO: filter by locked locks return lockedLocks; } hasNavigationLock() { let locks = this.getLockedNavigationLocks(); return (locks.length > 0); } }