Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
317 changes: 175 additions & 142 deletions resources/js/partials.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,165 +2,198 @@ import {findClosestLivewireComponent, isComponentRootEl, isntElement} from "./ut

document.addEventListener('livewire:init', () => {
Livewire.interceptMessage(({message, onSuccess}) => {
onSuccess(({payload}) => {
queueMicrotask(() => {
onSuccess(({payload, onMorph}) => {
const applyPartials = () => {
if (payload.effects?.html) {
return
}

const partialFragments = payload.effects?.partialFragments ?? {}

for (const [name, html] of Object.entries(partialFragments)) {

let els = Array.from(
message.component.el.querySelectorAll(
`[wire\\:partial="${name}"]`,
),
).filter(
(el) =>
findClosestLivewireComponent(el).id ===
message.component.id,
)

if (!els.length) {
continue
}

let el = els[0]

const getIgnoreKey = (node) => {
return node.getAttribute('wire:partial.ignore') ||
node.getAttribute('wire:key') ||
node.id
}

const applyMarkers = (node) => {
if (node.hasAttribute('wire:partial.ignore')) {
let key = getIgnoreKey(node)
if (key && !node.previousSibling?.nodeValue?.includes(`START:PARTIAL-IGNORE:${key}`)) {
node.before(document.createComment(`START:PARTIAL-IGNORE:${key}`))
node.after(document.createComment(`END:PARTIAL-IGNORE:${key}`))
}
}
node.querySelectorAll('[wire\\:partial\\.ignore]').forEach(child => {
let key = getIgnoreKey(child)
if (key && !child.previousSibling?.nodeValue?.includes(`START:PARTIAL-IGNORE:${key}`)) {
child.before(document.createComment(`START:PARTIAL-IGNORE:${key}`))
child.after(document.createComment(`END:PARTIAL-IGNORE:${key}`))
}
})
try {
morphPartial(message, name, html)
} catch (error) {
console.error(`[powergrid-partials] Failed to morph "${name}"`, error)
}
}
}

const capturedContent = new Map()

const captureContent = (node) => {
if (node.hasAttribute('wire:partial.ignore')) {
let key = getIgnoreKey(node)
if (key) {
capturedContent.set(key, node.innerHTML)
}
}
node.querySelectorAll('[wire\\:partial\\.ignore]').forEach(child => {
let key = getIgnoreKey(child)
if (key) {
capturedContent.set(key, child.innerHTML)
}
})
}
if (typeof onMorph === 'function') {
onMorph(applyPartials)
} else {
queueMicrotask(applyPartials)
}
})
})
})

captureContent(el)
applyMarkers(el)
function wrapperTagName(el) {
const parent = el.parentElement
const tag = parent ? parent.tagName.toLowerCase() : 'div'
const customElement = window.customElements?.get(tag)

return customElement?.name || tag
}

function morphPartial(message, name, html) {
let els = Array.from(
message.component.el.querySelectorAll(
`[wire\\:partial="${name}"]`,
),
).filter(
(el) =>
findClosestLivewireComponent(el).id ===
message.component.id,
)

if (!els.length) {
return
}

let el = els[0]

const getIgnoreKey = (node) => {
return node.getAttribute('wire:partial.ignore') ||
node.getAttribute('wire:key') ||
node.id
}

const applyMarkers = (node) => {
if (node.hasAttribute('wire:partial.ignore')) {
let key = getIgnoreKey(node)
if (key && !node.previousSibling?.nodeValue?.includes(`START:PARTIAL-IGNORE:${key}`)) {
node.before(document.createComment(`START:PARTIAL-IGNORE:${key}`))
node.after(document.createComment(`END:PARTIAL-IGNORE:${key}`))
}
}
node.querySelectorAll('[wire\\:partial\\.ignore]').forEach(child => {
let key = getIgnoreKey(child)
if (key && !child.previousSibling?.nodeValue?.includes(`START:PARTIAL-IGNORE:${key}`)) {
child.before(document.createComment(`START:PARTIAL-IGNORE:${key}`))
child.after(document.createComment(`END:PARTIAL-IGNORE:${key}`))
}
})
}

const capturedContent = new Map()

const captureContent = (node) => {
if (node.hasAttribute('wire:partial.ignore')) {
let key = getIgnoreKey(node)
if (key) {
capturedContent.set(key, node.innerHTML)
}
}
node.querySelectorAll('[wire\\:partial\\.ignore]').forEach(child => {
let key = getIgnoreKey(child)
if (key) {
capturedContent.set(key, child.innerHTML)
}
})
}

let wrapperTag = el.parentElement
? el.parentElement.tagName.toLowerCase()
: 'div'
captureContent(el)
applyMarkers(el)

let wrapper = document.createElement(wrapperTag)
let wrapper = document.createElement(wrapperTagName(el))

wrapper.innerHTML = html
wrapper.__livewire = message.component
wrapper.innerHTML = html
wrapper.__livewire = message.component

let to = wrapper.firstElementChild
let to = wrapper.firstElementChild

to.__livewire = message.component
if (!to) {
return
}

applyMarkers(to)
to.__livewire = message.component

to.querySelectorAll('[wire\\:partial\\.ignore]').forEach(node => {
let key = getIgnoreKey(node)
if (key && node.innerHTML.includes(`<!--PARTIAL:IGNORE:${key}-->`)) {
node.innerHTML = capturedContent.get(key)
}
})
applyMarkers(to)

if (to.hasAttribute('wire:partial.ignore')) {
let key = getIgnoreKey(to)
if (key && to.innerHTML.includes(`<!--PARTIAL:IGNORE:${key}-->`)) {
to.innerHTML = capturedContent.get(key)
}
}
to.querySelectorAll('[wire\\:partial\\.ignore]').forEach(node => {
let key = getIgnoreKey(node)
if (key && node.innerHTML.includes(`<!--PARTIAL:IGNORE:${key}-->`)) {
node.innerHTML = capturedContent.get(key)
}
})

window.Alpine.morph(el, to, {
updating: (el, toEl, childrenOnly, skip) => {
if (isntElement(el)) {
return
}

if (el.__livewire_replace === true) {
el.innerHTML = toEl.innerHTML
}

if (el.__livewire_replace_self === true) {
el.outerHTML = toEl.outerHTML

return skip()
}

if (el.hasAttribute('wire:partial.ignore')) {
return skip()
}

if (el.__livewire_ignore === true) {
return skip()
}

if (el.__livewire_ignore_self === true) {
childrenOnly()
}

if (
isComponentRootEl(el) &&
el.getAttribute('wire:id') !==
message.component.id
) {
return skip()
}

if (isComponentRootEl(el)) {
toEl.__livewire = message.component
}
},

key: (el) => {
if (isntElement(el)) {
return
}

if (el.hasAttribute(`wire:key`)) {
return el.getAttribute(`wire:key`)
}

if (el.hasAttribute(`wire:id`)) {
return el.getAttribute(`wire:id`)
}

return el.id
},

lookahead: false,
})
}
})
})
if (to.hasAttribute('wire:partial.ignore')) {
let key = getIgnoreKey(to)
if (key && to.innerHTML.includes(`<!--PARTIAL:IGNORE:${key}-->`)) {
to.innerHTML = capturedContent.get(key)
}
}

Livewire.trigger?.('morph', {el, toEl: to, component: message.component})

window.Alpine.morph(el, to, {
updating: (el, toEl, childrenOnly, skip) => {
if (isntElement(el)) {
return
}

if (el.__livewire_replace === true) {
el.innerHTML = toEl.innerHTML
}

if (el.__livewire_replace_self === true) {
el.outerHTML = toEl.outerHTML

return skip()
}

if (el.hasAttribute('wire:partial.ignore')) {
return skip()
}

if (el.__livewire_ignore === true || el.hasAttribute('wire:ignore')) {
return skip()
}

if (el.__livewire_ignore_self === true || el.hasAttribute('wire:ignore.self')) {
childrenOnly()
}

if (
isComponentRootEl(el) &&
el.getAttribute('wire:id') !==
message.component.id
) {
return skip()
}

if (isComponentRootEl(el)) {
toEl.__livewire = message.component
}
},

added: (addedEl) => {
if (isntElement(addedEl)) {
return
}

Livewire.trigger?.('morph.added', {el: addedEl})
},

key: (el) => {
if (isntElement(el)) {
return
}

if (el.hasAttribute(`wire:key`)) {
return el.getAttribute(`wire:key`)
}

if (el.hasAttribute(`wire:id`)) {
return el.getAttribute(`wire:id`)
}

return el.id
},

lookahead: false,
})
})

Livewire.trigger?.('morphed', {el, component: message.component})
}
Loading