芝麻web文件管理V1.00
编辑当前文件:/home/qrafawbu/kwesioben.com/paymoney/vendor/livewire/livewire/js/component/SyncBrowserHistory.js
import store from '@/Store' import Message from '@/Message'; export default function () { let initializedPath = false let componentIdsThatAreWritingToHistoryState = new Set LivewireStateManager.clearState() store.registerHook('component.initialized', component => { if (! component.effects.path) return // We are using setTimeout() to make sure all the components on the page have // loaded before we store anything in the history state (because the position // of a component on a page matters for generating its state signature). setTimeout(() => { let url = onlyChangeThePathAndQueryString(initializedPath ? undefined : component.effects.path) // Generate faux response. let response = { serverMemo: component.serverMemo, effects: component.effects, } normalizeResponse(response, component) LivewireStateManager.replaceState(url, response, component) componentIdsThatAreWritingToHistoryState.add(component.id) initializedPath = true }) }) store.registerHook('message.processed', (message, component) => { // Preventing a circular dependancy. if (message.replaying) return let { response } = message let effects = response.effects || {} normalizeResponse(response, component) if ('path' in effects && effects.path !== window.location.href) { let url = onlyChangeThePathAndQueryString(effects.path) LivewireStateManager.pushState(url, response, component) componentIdsThatAreWritingToHistoryState.add(component.id) } else { // If the current component has changed it's state, but hasn't written // anything new to the URL, we still need to update it's data in the // history state so that when a back button is hit, it is caught // up to the most recent known data state. if (componentIdsThatAreWritingToHistoryState.has(component.id)) { LivewireStateManager.replaceState(window.location.href, response, component) } } }) window.addEventListener('popstate', event => { if (LivewireStateManager.missingState(event)) return LivewireStateManager.replayResponses(event, (response, component) => { let message = new Message(component, []) message.storeResponse(response) message.replaying = true component.handleResponse(message) }) }) function normalizeResponse(response, component) { // Add ALL properties as "dirty" so that when the back button is pressed, // they ALL are forced to refresh on the page (even if the HTML didn't change). response.effects.dirty = Object.keys(response.serverMemo.data) // Sometimes Livewire doesn't return html from the server to save on bandwidth. // So we need to set the HTML no matter what. response.effects.html = component.lastFreshHtml } function onlyChangeThePathAndQueryString(url) { if (! url) return let destination = new URL(url) let afterOrigin = destination.href.replace(destination.origin, '').replace(/\?$/, '') return window.location.origin + afterOrigin + window.location.hash } store.registerHook('element.updating', (from, to, component) => { // It looks like the element we are about to update is the root // element of the component. Let's store this knowledge to // reference after update in the "element.updated" hook. if (from.getAttribute('wire:id') === component.id) { component.lastKnownDomId = component.id } }) store.registerHook('element.updated', (node, component) => { // If the element that was just updated was the root DOM element. if (component.lastKnownDomId) { // Let's check and see if the wire:id was the thing that changed. if (node.getAttribute('wire:id') !== component.lastKnownDomId) { // If so, we need to change this ID globally everwhere it's referenced. store.changeComponentId(component, node.getAttribute('wire:id')) } // Either way, we'll unset this for the next update. delete component.lastKnownDomId } // We have to update the component ID because we are replaying responses // from similar components but with completely different IDs. If didn't // update the component ID, the checksums would fail. }) } let LivewireStateManager = { replaceState(url, response, component) { this.updateState('replaceState', url, response, component) }, pushState(url, response, component) { this.updateState('pushState', url, response, component) }, updateState(method, url, response, component) { let state = this.currentState() state.storeResponse(response, component) let stateArray = state.toStateArray() // Copy over existing history state if it's an object, so we don't overwrite it. let fullstateObject = Object.assign(history.state || {}, { livewire: stateArray }) let capitalize = subject => subject.charAt(0).toUpperCase() + subject.slice(1) store.callHook('before'+capitalize(method), fullstateObject, url, component) try { if (decodeURI(url) != 'undefined') { url = decodeURI(url).replaceAll(' ', '+').replaceAll('\\', '%5C') } history[method](fullstateObject, '', url) } catch (error) { // Firefox has a 160kb limit to history state entries. // If that limit is reached, we'll instead put it in // sessionStorage and store a reference to it. if (error.name === 'NS_ERROR_ILLEGAL_VALUE') { let key = this.storeInSession(stateArray) fullstateObject.livewire = key history[method](fullstateObject, '', url) } } }, replayResponses(event, callback) { if (! event.state.livewire) return let state = typeof event.state.livewire === 'string' ? new LivewireState(this.getFromSession(event.state.livewire)) : new LivewireState(event.state.livewire) state.replayResponses(callback) }, currentState() { if (! history.state) return new LivewireState if (! history.state.livewire) return new LivewireState let state = typeof history.state.livewire === 'string' ? new LivewireState(this.getFromSession(history.state.livewire)) : new LivewireState(history.state.livewire) return state }, missingState(event) { return ! (event.state && event.state.livewire) }, clearState() { // This is to prevent exponentially increasing the size of our state on page refresh. if (window.history.state) window.history.state.livewire = (new LivewireState).toStateArray(); }, storeInSession(value) { let key = 'livewire:'+(new Date).getTime() let stringifiedValue = JSON.stringify(value) this.tryToStoreInSession(key, stringifiedValue) return key }, tryToStoreInSession(key, value) { // sessionStorage has a max storage limit (usally 5MB). // If we meet that limit, we'll start removing entries // (oldest first), until there's enough space to store // the new one. try { sessionStorage.setItem(key, value) } catch (error) { // 22 is Chrome, 1-14 is other browsers. if (! [22, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14].includes(error.code)) return let oldestTimestamp = Object.keys(sessionStorage) .map(key => Number(key.replace('livewire:', ''))) .sort() .shift() if (! oldestTimestamp) return sessionStorage.removeItem('livewire:'+oldestTimestamp) this.tryToStoreInSession(key, value) } }, getFromSession(key) { let item = sessionStorage.getItem(key) if (! item) return return JSON.parse(item) }, } class LivewireState { constructor(stateArray = []) { this.items = stateArray } toStateArray() { return this.items } pushItemInProperOrder(signature, response, component) { let targetItem = { signature, response } // First, we'll check if this signature already has an entry, if so, replace it. let existingIndex = this.items.findIndex(item => item.signature === signature) if (existingIndex !== -1) return this.items[existingIndex] = targetItem // If it doesn't already exist, we'll add it, but we MUST first see if any of its // parents components have entries, and insert it immediately before them. // This way, when we replay responses, we will always start with the most // inward components and go outwards. let closestParentId = store.getClosestParentId(component.id, this.componentIdsWithStoredResponses()) if (! closestParentId) return this.items.unshift(targetItem) let closestParentIndex = this.items.findIndex(item => { let { originalComponentId } = this.parseSignature(item.signature) if (originalComponentId === closestParentId) return true }) this.items.splice(closestParentIndex, 0, targetItem); } storeResponse(response, component) { let signature = this.getComponentNameBasedSignature(component) this.pushItemInProperOrder(signature, response, component) } replayResponses(callback) { this.items.forEach(({ signature, response }) => { let component = this.findComponentBySignature(signature) if (! component) return callback(response, component) }) } // We can't just store component reponses by their id because // ids change on every refresh, so history state won't have // a component to apply it's changes to. Instead we must // generate a unique id based on the components name // and it's relative position amongst others with // the same name that are loaded on the page. getComponentNameBasedSignature(component) { let componentName = component.fingerprint.name let sameNamedComponents = store.getComponentsByName(componentName) let componentIndex = sameNamedComponents.indexOf(component) return `${component.id}:${componentName}:${componentIndex}` } findComponentBySignature(signature) { let { componentName, componentIndex } = this.parseSignature(signature) let sameNamedComponents = store.getComponentsByName(componentName) // If we found the component in the proper place, return it, // otherwise return the first one. return sameNamedComponents[componentIndex] || sameNamedComponents[0] || console.warn(`Livewire: couldn't find component on page: ${componentName}`) } parseSignature(signature) { let [originalComponentId, componentName, componentIndex] = signature.split(':') return { originalComponentId, componentName, componentIndex } } componentIdsWithStoredResponses() { return this.items.map(({ signature }) => { let { originalComponentId } = this.parseSignature(signature) return originalComponentId }) } }