Compare commits
38 Commits
0adc966608
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 9690401dad | |||
| 63f894f526 | |||
| 345be1aa23 | |||
| e14b0c0214 | |||
| d073a2e804 | |||
| 8f41a39a6e | |||
| df6ba88040 | |||
| 0b34b37aaf | |||
| 694e610ebb | |||
| 3503fd90ab | |||
| 0c21f7b772 | |||
| 53ed4eea07 | |||
| 605398505a | |||
| 4f728a3514 | |||
| 3e7a82edc2 | |||
| a871288c1c | |||
| 5f8e3865e3 | |||
| d25a4b548a | |||
| f031142848 | |||
| b9b39a2679 | |||
| eb891c8cef | |||
| 974501fea8 | |||
| 40b12f0c47 | |||
| 33ea2bd672 | |||
| ff4a25c1b2 | |||
| cfe33b8111 | |||
| 7d3548d597 | |||
| 9381d82ae5 | |||
| 839634a3ee | |||
| 0e6d23c1e1 | |||
| 8fc680fcb9 | |||
| 54eb584fd7 | |||
| c16f4a1b42 | |||
| 7f4e13c5e0 | |||
| f39f27efee | |||
| bd43063230 | |||
| 7d10993b66 | |||
| fd270d27da |
+16
-4
@@ -72,7 +72,17 @@ bz-select > div.options-container{
|
|||||||
transition: max-height 0.4s ease;
|
transition: max-height 0.4s ease;
|
||||||
}
|
}
|
||||||
bz-select > div.options-container.open{ pointer-events: auto; max-height: 10em;}
|
bz-select > div.options-container.open{ pointer-events: auto; max-height: 10em;}
|
||||||
bz-select option{
|
div.options-container.portaled{
|
||||||
|
pointer-events: none;
|
||||||
|
position: fixed;
|
||||||
|
z-index: 10000;
|
||||||
|
max-height: 0;
|
||||||
|
overflow: auto;
|
||||||
|
transition: max-height 0.4s ease;
|
||||||
|
}
|
||||||
|
div.options-container.portaled.open{ pointer-events: auto; max-height: 10em;}
|
||||||
|
bz-select option,
|
||||||
|
div.options-container option{
|
||||||
background-color: #DDD;
|
background-color: #DDD;
|
||||||
border: 1px solid black;
|
border: 1px solid black;
|
||||||
color: #000;
|
color: #000;
|
||||||
@@ -88,12 +98,14 @@ bz-select option{
|
|||||||
margin-top 0.3s ease,
|
margin-top 0.3s ease,
|
||||||
opacity 0.3s ease;
|
opacity 0.3s ease;
|
||||||
}
|
}
|
||||||
bz-select option.open{
|
bz-select option.open,
|
||||||
|
div.options-container option.open{
|
||||||
margin: 0;
|
margin: 0;
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
pointer-events: auto;
|
pointer-events: auto;
|
||||||
}
|
}
|
||||||
bz-select option:hover{
|
bz-select option:hover,
|
||||||
|
div.options-container option:hover{
|
||||||
background-color: #44F;
|
background-color: #44F;
|
||||||
color: #FFF;
|
color: #FFF;
|
||||||
}
|
}
|
||||||
@@ -254,7 +266,7 @@ bz-graflow .bzgf-nodes-container{ /* used to keep the nodes container pointer-ev
|
|||||||
}
|
}
|
||||||
bz-graflow .bzgf-nodes-container > * { /* allow the nodes to be moved ! */
|
bz-graflow .bzgf-nodes-container > * { /* allow the nodes to be moved ! */
|
||||||
pointer-events: auto;
|
pointer-events: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
bz-graflow .bzgf-nodes-container .bzgf-node{ position:absolute; }
|
bz-graflow .bzgf-nodes-container .bzgf-node{ position:absolute; }
|
||||||
bz-graflow .bzgf-nodes-container .bzgf-fake-node{
|
bz-graflow .bzgf-nodes-container .bzgf-fake-node{
|
||||||
|
|||||||
+109
-15
@@ -135,7 +135,7 @@ class BZselect extends Buildoz {
|
|||||||
if(!this.optionscontainer) this.optionscontainer = document.createElement('div')
|
if(!this.optionscontainer) this.optionscontainer = document.createElement('div')
|
||||||
this.optionscontainer.classList.add('options-container')
|
this.optionscontainer.classList.add('options-container')
|
||||||
this.append(this.optionscontainer)
|
this.append(this.optionscontainer)
|
||||||
this.options = this.querySelectorAll('option')
|
this.syncOptions()
|
||||||
if(this.#fillFromMarkup){ //can only do it once and only if fillOptions was not already called !!
|
if(this.#fillFromMarkup){ //can only do it once and only if fillOptions was not already called !!
|
||||||
for(const opt of this.options){
|
for(const opt of this.options){
|
||||||
this.optionscontainer.append(opt) // Will move is to the right parent
|
this.optionscontainer.append(opt) // Will move is to the right parent
|
||||||
@@ -147,6 +147,15 @@ class BZselect extends Buildoz {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
disconnectedCallback() {
|
||||||
|
if(this.open || this._closing) this.closeDropdown(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
syncOptions() {
|
||||||
|
if(this.optionscontainer) this.options = this.optionscontainer.querySelectorAll('option')
|
||||||
|
else this.options = []
|
||||||
|
}
|
||||||
|
|
||||||
// static get observedAttributes(){ // Only if you want actions on attr change
|
// static get observedAttributes(){ // Only if you want actions on attr change
|
||||||
// return([...super.observedAttributes, 'disabled'])
|
// return([...super.observedAttributes, 'disabled'])
|
||||||
// }
|
// }
|
||||||
@@ -172,19 +181,104 @@ class BZselect extends Buildoz {
|
|||||||
}
|
}
|
||||||
|
|
||||||
toggle(){
|
toggle(){
|
||||||
for(const opt of this.options){
|
if(this.open) this.closeDropdown()
|
||||||
if(this.open) {
|
else this.openDropdown()
|
||||||
opt.classList.remove('open')
|
}
|
||||||
this.optionscontainer.classList.remove('open')
|
|
||||||
} else {
|
openDropdown() {
|
||||||
document.querySelectorAll('bz-select').forEach((sel) => {
|
document.querySelectorAll('bz-select').forEach((sel) => {
|
||||||
if((sel!==this) && sel.open) sel.toggle()
|
if((sel!==this) && sel.open) sel.closeDropdown(true)
|
||||||
})
|
})
|
||||||
opt.classList.add('open')
|
this.optionscontainer.classList.add('portaled')
|
||||||
|
document.body.appendChild(this.optionscontainer)
|
||||||
|
this.positionPortal()
|
||||||
|
this.bindPortalListeners()
|
||||||
|
this.open = true
|
||||||
|
requestAnimationFrame(() => {
|
||||||
|
requestAnimationFrame(() => {
|
||||||
|
if(!this.open) return
|
||||||
this.optionscontainer.classList.add('open')
|
this.optionscontainer.classList.add('open')
|
||||||
|
for(const opt of this.options) opt.classList.add('open')
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
closeDropdown(immediate = false) {
|
||||||
|
if(!this.open) return
|
||||||
|
this.unbindPortalListeners()
|
||||||
|
for(const opt of this.options) opt.classList.remove('open')
|
||||||
|
this.optionscontainer.classList.remove('open')
|
||||||
|
if(immediate) {
|
||||||
|
this.clearCloseTransition()
|
||||||
|
this.finishCloseDropdown()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this._closing = true
|
||||||
|
this._onTransitionEnd = (evt) => {
|
||||||
|
if(evt.target !== this.optionscontainer) return
|
||||||
|
if(evt.propertyName !== 'max-height') return
|
||||||
|
this.finishCloseDropdownAfterTransition()
|
||||||
|
}
|
||||||
|
this.optionscontainer.addEventListener('transitionend', this._onTransitionEnd)
|
||||||
|
this._closeTimer = setTimeout(() => this.finishCloseDropdownAfterTransition(), 450)
|
||||||
|
}
|
||||||
|
|
||||||
|
finishCloseDropdownAfterTransition() {
|
||||||
|
if(!this._closing) return
|
||||||
|
this.clearCloseTransition()
|
||||||
|
this.finishCloseDropdown()
|
||||||
|
}
|
||||||
|
|
||||||
|
clearCloseTransition() {
|
||||||
|
this._closing = false
|
||||||
|
if(this._closeTimer) clearTimeout(this._closeTimer)
|
||||||
|
this._closeTimer = null
|
||||||
|
if(this._onTransitionEnd) {
|
||||||
|
this.optionscontainer.removeEventListener('transitionend', this._onTransitionEnd)
|
||||||
|
this._onTransitionEnd = null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
finishCloseDropdown() {
|
||||||
|
this.optionscontainer.classList.remove('portaled')
|
||||||
|
this.clearPortalStyles()
|
||||||
|
if(this.optionscontainer.parentElement !== this) this.append(this.optionscontainer)
|
||||||
|
this.open = false
|
||||||
|
}
|
||||||
|
|
||||||
|
positionPortal() {
|
||||||
|
const rect = this.button.getBoundingClientRect()
|
||||||
|
this.optionscontainer.style.top = `${rect.bottom}px`
|
||||||
|
this.optionscontainer.style.left = `${rect.left}px`
|
||||||
|
this.optionscontainer.style.width = `${rect.width}px`
|
||||||
|
}
|
||||||
|
|
||||||
|
clearPortalStyles() {
|
||||||
|
this.optionscontainer.style.top = ''
|
||||||
|
this.optionscontainer.style.left = ''
|
||||||
|
this.optionscontainer.style.width = ''
|
||||||
|
}
|
||||||
|
|
||||||
|
bindPortalListeners() {
|
||||||
|
this._repositionBound = this.positionPortal.bind(this)
|
||||||
|
window.addEventListener('scroll', this._repositionBound, true)
|
||||||
|
window.addEventListener('resize', this._repositionBound)
|
||||||
|
this._outsideClickBound = (evt) => {
|
||||||
|
if(this.open && !this.contains(evt.target) && !this.optionscontainer.contains(evt.target)) {
|
||||||
|
this.closeDropdown()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.open = !this.open
|
this._outsideClickTimer = setTimeout(() => {
|
||||||
|
document.addEventListener('click', this._outsideClickBound, true)
|
||||||
|
}, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
unbindPortalListeners() {
|
||||||
|
if(this._repositionBound) window.removeEventListener('scroll', this._repositionBound, true)
|
||||||
|
if(this._repositionBound) window.removeEventListener('resize', this._repositionBound)
|
||||||
|
if(this._outsideClickBound) document.removeEventListener('click', this._outsideClickBound, true)
|
||||||
|
if(this._outsideClickTimer) clearTimeout(this._outsideClickTimer)
|
||||||
|
this._outsideClickTimer = null
|
||||||
}
|
}
|
||||||
|
|
||||||
onClick(evt){
|
onClick(evt){
|
||||||
@@ -196,7 +290,7 @@ class BZselect extends Buildoz {
|
|||||||
onOption(value, silent=false){
|
onOption(value, silent=false){
|
||||||
if(this.getAttribute('disabled') !== null) return
|
if(this.getAttribute('disabled') !== null) return
|
||||||
this.value = value
|
this.value = value
|
||||||
if(!silent) this.toggle()
|
if(!silent && this.open) this.closeDropdown()
|
||||||
}
|
}
|
||||||
|
|
||||||
addOption(value, markup){
|
addOption(value, markup){
|
||||||
@@ -207,16 +301,16 @@ class BZselect extends Buildoz {
|
|||||||
opt.addEventListener('click',this.onClick.bind(this))
|
opt.addEventListener('click',this.onClick.bind(this))
|
||||||
if(!this.optionscontainer) this.optionscontainer = document.createElement('div')
|
if(!this.optionscontainer) this.optionscontainer = document.createElement('div')
|
||||||
this.optionscontainer.append(opt)
|
this.optionscontainer.append(opt)
|
||||||
this.options = this.querySelectorAll('option')
|
this.syncOptions()
|
||||||
this.#fillFromMarkup = false
|
this.#fillFromMarkup = false
|
||||||
}
|
}
|
||||||
|
|
||||||
fillOptions(opts, erase = true){
|
fillOptions(opts, erase = true){
|
||||||
// Caution: you cannot count on connectedCallback to have run already, because one might fill before adding to the DOM
|
// Caution: you cannot count on connectedCallback to have run already, because one might fill before adding to the DOM
|
||||||
if(erase){
|
if(erase){
|
||||||
this.options = this.querySelectorAll('option')
|
this.syncOptions()
|
||||||
this.options.forEach(node => { node.remove() })
|
this.options.forEach(node => { node.remove() })
|
||||||
this.options = this.querySelectorAll('option')
|
this.syncOptions()
|
||||||
this.onOption('', true) // unselect last
|
this.onOption('', true) // unselect last
|
||||||
}
|
}
|
||||||
for(const opt of opts) this.addOption(opt.value, opt.markup)
|
for(const opt of opts) this.addOption(opt.value, opt.markup)
|
||||||
|
|||||||
+222
-31
@@ -30,6 +30,7 @@ class BZgraflow extends Buildoz{
|
|||||||
this.stagedNodes = { }
|
this.stagedNodes = { }
|
||||||
this.stagedWires = { }
|
this.stagedWires = { }
|
||||||
this.arrowDefs = null
|
this.arrowDefs = null
|
||||||
|
this.arrowMarkerId = `arrow-${crypto.randomUUID()}`
|
||||||
this.currentOrientation = null
|
this.currentOrientation = null
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -98,6 +99,28 @@ class BZgraflow extends Buildoz{
|
|||||||
else this.initFlow()
|
else this.initFlow()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static get observedAttributes(){
|
||||||
|
return([...super.observedAttributes, 'disabled'])
|
||||||
|
}
|
||||||
|
|
||||||
|
attributeChangedCallback(name, oldValue, newValue) {
|
||||||
|
super.attributeChangedCallback(name, oldValue, newValue)
|
||||||
|
if(name == 'disabled'){
|
||||||
|
if(newValue === null) {
|
||||||
|
this.disabled = false
|
||||||
|
this.style.opacity = 1
|
||||||
|
this.style.pointerEvents = 'auto'
|
||||||
|
} else {
|
||||||
|
this.disabled = true
|
||||||
|
this.style.opacity = 0.5
|
||||||
|
this.style.pointerEvents = 'none'
|
||||||
|
}
|
||||||
|
this.querySelectorAll('.bzgf-zoom-in, .bzgf-zoom-out').forEach((btn) => {
|
||||||
|
btn.disabled = this.disabled
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
error(msg, err){
|
error(msg, err){
|
||||||
this.querySelector('.graflow-error')?.remove()
|
this.querySelector('.graflow-error')?.remove()
|
||||||
const errorEl = document.createElement('div')
|
const errorEl = document.createElement('div')
|
||||||
@@ -142,7 +165,10 @@ class BZgraflow extends Buildoz{
|
|||||||
await this.loadNodes(flowObj.nodesFile)
|
await this.loadNodes(flowObj.nodesFile)
|
||||||
this.flow = flowObj.flow
|
this.flow = flowObj.flow
|
||||||
this.refresh()
|
this.refresh()
|
||||||
this.fireEvent('flowLoaded', { url: source instanceof Blob ? null : source, blob: source instanceof Blob ? source : null })
|
this.fireEvent('flowLoaded', {
|
||||||
|
parentNodeId: null,
|
||||||
|
component: this,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
initFlow(){
|
initFlow(){
|
||||||
@@ -159,6 +185,8 @@ class BZgraflow extends Buildoz{
|
|||||||
for(const tpl of doc.querySelectorAll('template')){
|
for(const tpl of doc.querySelectorAll('template')){
|
||||||
if(tpl.id=='svg-arrows'){
|
if(tpl.id=='svg-arrows'){
|
||||||
this.arrowDefs = tpl.querySelector('defs').cloneNode(true)
|
this.arrowDefs = tpl.querySelector('defs').cloneNode(true)
|
||||||
|
const defaultArrow = this.arrowDefs.querySelector('#arrow')
|
||||||
|
if(defaultArrow) defaultArrow.id = this.arrowMarkerId
|
||||||
this.wiresContainer.appendChild(this.arrowDefs)
|
this.wiresContainer.appendChild(this.arrowDefs)
|
||||||
} else {
|
} else {
|
||||||
const rootEl = tpl.content.querySelector('.bzgf-node')
|
const rootEl = tpl.content.querySelector('.bzgf-node')
|
||||||
@@ -214,6 +242,7 @@ class BZgraflow extends Buildoz{
|
|||||||
this.enterSubflow(id)
|
this.enterSubflow(id)
|
||||||
})
|
})
|
||||||
this.stagedNodes[id].appendChild(btnEnterSubflow)
|
this.stagedNodes[id].appendChild(btnEnterSubflow)
|
||||||
|
this.stagedNodes[id].dataset.subflow = true
|
||||||
}
|
}
|
||||||
this.nodesContainer.append(this.stagedNodes[id])
|
this.nodesContainer.append(this.stagedNodes[id])
|
||||||
if(!this.flow.nodes.find(n => n.id === id)) {
|
if(!this.flow.nodes.find(n => n.id === id)) {
|
||||||
@@ -223,6 +252,7 @@ class BZgraflow extends Buildoz{
|
|||||||
}
|
}
|
||||||
|
|
||||||
enterSubflow(id){
|
enterSubflow(id){
|
||||||
|
if(this.disabled || this.hasAttribute('disabled')) return
|
||||||
const nodeEl = this.stagedNodes[id]
|
const nodeEl = this.stagedNodes[id]
|
||||||
if(!nodeEl) return
|
if(!nodeEl) return
|
||||||
|
|
||||||
@@ -246,7 +276,7 @@ class BZgraflow extends Buildoz{
|
|||||||
childEl.addNode({
|
childEl.addNode({
|
||||||
"nodeType": portLink.refNodeType,
|
"nodeType": portLink.refNodeType,
|
||||||
"id": nid,
|
"id": nid,
|
||||||
"markup": { "parentport": portLink.parentPort }
|
"markup": { ...portLink }
|
||||||
})
|
})
|
||||||
if(portLink.direction=='in') {
|
if(portLink.direction=='in') {
|
||||||
childEl.addWire({
|
childEl.addWire({
|
||||||
@@ -260,8 +290,8 @@ class BZgraflow extends Buildoz{
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Rebuild once refNodes are injected so the final refresh/autofit includes them.
|
||||||
childEl.autoPlace()
|
childEl.refresh()
|
||||||
}, { once:true })
|
}, { once:true })
|
||||||
|
|
||||||
if(flowNode.subflow.url) childEl.setAttribute('flow', flowNode.subflow.url)
|
if(flowNode.subflow.url) childEl.setAttribute('flow', flowNode.subflow.url)
|
||||||
@@ -271,7 +301,6 @@ class BZgraflow extends Buildoz{
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
childEl.setAttribute('tension', this.getBZAttribute('tension') || '60')
|
|
||||||
// Remember which node we "came from" so exitSubflow() can animate back to it.
|
// Remember which node we "came from" so exitSubflow() can animate back to it.
|
||||||
childEl.dataset.enterNodeId = id
|
childEl.dataset.enterNodeId = id
|
||||||
const btnExitSubflow = document.createElement('button')
|
const btnExitSubflow = document.createElement('button')
|
||||||
@@ -325,7 +354,10 @@ class BZgraflow extends Buildoz{
|
|||||||
childEl.style.transform = 'none' // Important for nested subflows to position correctly
|
childEl.style.transform = 'none' // Important for nested subflows to position correctly
|
||||||
childEl.style.willChange = ''
|
childEl.style.willChange = ''
|
||||||
childEl.style.overflow = 'auto'
|
childEl.style.overflow = 'auto'
|
||||||
this.fireEvent('subflowLoaded', { subflow: childEl })
|
this.fireEvent('subflowLoaded', {
|
||||||
|
parentNodeId: id,
|
||||||
|
component: childEl
|
||||||
|
})
|
||||||
}, { once:true })
|
}, { once:true })
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -400,7 +432,9 @@ class BZgraflow extends Buildoz{
|
|||||||
this.hostContainer.style.opacity = '1'
|
this.hostContainer.style.opacity = '1'
|
||||||
this.hostContainer.style.visibility = 'visible'
|
this.hostContainer.style.visibility = 'visible'
|
||||||
childEl.style.willChange = ''
|
childEl.style.willChange = ''
|
||||||
this.fireEvent('subflowExited', { subflow: childEl })
|
this.fireEvent('subflowExited', {
|
||||||
|
component: this
|
||||||
|
})
|
||||||
}, { once:true })
|
}, { once:true })
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -432,8 +466,8 @@ class BZgraflow extends Buildoz{
|
|||||||
this.stagedWires[id] = document.createElementNS('http://www.w3.org/2000/svg', 'path')
|
this.stagedWires[id] = document.createElementNS('http://www.w3.org/2000/svg', 'path')
|
||||||
this.stagedWires[id].setAttribute('d', path)
|
this.stagedWires[id].setAttribute('d', path)
|
||||||
this.stagedWires[id].setAttribute('fill', 'none')
|
this.stagedWires[id].setAttribute('fill', 'none')
|
||||||
if(this.arrowDefs && link.endArrow) this.stagedWires[id].setAttribute('marker-end','url(#arrow)')
|
if(this.arrowDefs && link.endArrow) this.stagedWires[id].setAttribute('marker-end',`url(#${this.arrowMarkerId})`)
|
||||||
if(this.arrowDefs && link.startArrow) this.stagedWires[id].setAttribute('marker-start','url(#arrow)')
|
if(this.arrowDefs && link.startArrow) this.stagedWires[id].setAttribute('marker-start',`url(#${this.arrowMarkerId})`)
|
||||||
this.stagedWires[id].classList.add('bzgf-wire')
|
this.stagedWires[id].classList.add('bzgf-wire')
|
||||||
this.stagedWires[id].dataset.id = id
|
this.stagedWires[id].dataset.id = id
|
||||||
this.stagedWires[id].link = link
|
this.stagedWires[id].link = link
|
||||||
@@ -471,15 +505,97 @@ class BZgraflow extends Buildoz{
|
|||||||
else this.currentOrientation = 'vertical'
|
else this.currentOrientation = 'vertical'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(forceAutoplace) this.autoPlace(this.currentOrientation, parseInt(this.getBZAttribute('gapx')) || 80, parseInt(this.getBZAttribute('gapy')) || 80)
|
const gapx = parseInt(this.getBZAttribute('gapx')) || 80
|
||||||
this.fireEvent('refreshed', { })
|
const gapy = parseInt(this.getBZAttribute('gapy')) || 80
|
||||||
if(this.hasAttribute('autofit')){
|
const finishRefresh = () => {
|
||||||
const autofitAttr = this.getAttribute('autofit')
|
this.fireEvent('refreshed', { })
|
||||||
const autofitPercent = (autofitAttr !== null && autofitAttr !== '' && !Number.isNaN(parseFloat(autofitAttr)))
|
if(this.hasAttribute('autofit')){
|
||||||
? parseFloat(autofitAttr)
|
const autofitAttr = this.getAttribute('autofit')
|
||||||
: undefined
|
const autofitPercent = (autofitAttr !== null && autofitAttr !== '' && !Number.isNaN(parseFloat(autofitAttr)))
|
||||||
this.autofit(autofitPercent)
|
? parseFloat(autofitAttr)
|
||||||
|
: undefined
|
||||||
|
if(this._canRunAutoPlace()) this.autofit(autofitPercent)
|
||||||
|
else this._scheduleLayoutWhenReady(() => this.autofit(autofitPercent))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
const onLayoutComplete = () => {
|
||||||
|
this.fireEvent('layoutComplete', { })
|
||||||
|
finishRefresh()
|
||||||
|
}
|
||||||
|
if(forceAutoplace) this._scheduleAutoPlaceWhenReady(this.currentOrientation, gapx, gapy, onLayoutComplete)
|
||||||
|
else onLayoutComplete()
|
||||||
|
}
|
||||||
|
|
||||||
|
disconnectedCallback(){
|
||||||
|
this._disconnectLayoutObserver()
|
||||||
|
super.disconnectedCallback?.()
|
||||||
|
}
|
||||||
|
|
||||||
|
_disconnectLayoutObserver(){
|
||||||
|
if(this._layoutObserver) {
|
||||||
|
this._layoutObserver.disconnect()
|
||||||
|
this._layoutObserver = null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_canRunAutoPlace(){
|
||||||
|
let nodesHaveLayoutSize = false
|
||||||
|
const ids = Object.keys(this.stagedNodes || {})
|
||||||
|
if(ids.length === 0) return(true)
|
||||||
|
for(const nid of ids){
|
||||||
|
if(nid.startsWith('longLinkPlaceHolder_')) continue
|
||||||
|
const el = this.stagedNodes[nid]
|
||||||
|
if(el && (el.offsetWidth > 0 || el.offsetHeight > 0)) {
|
||||||
|
nodesHaveLayoutSize=true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return((this.clientWidth > 0 && this.clientHeight > 0) && nodesHaveLayoutSize)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* autoPlace uses offsetWidth/offsetHeight; when the host is hidden (display:none / off-screen view)
|
||||||
|
* those are 0 and layout is wrong. Defer until the element is measurable.
|
||||||
|
*/
|
||||||
|
_scheduleLayoutWhenReady(callback){
|
||||||
|
this._layoutScheduleToken = (this._layoutScheduleToken || 0) + 1
|
||||||
|
const token = this._layoutScheduleToken
|
||||||
|
this._disconnectLayoutObserver()
|
||||||
|
|
||||||
|
const attempt = () => {
|
||||||
|
if(token !== this._layoutScheduleToken) return(true)
|
||||||
|
if(!this._canRunAutoPlace()) return(false)
|
||||||
|
this._disconnectLayoutObserver()
|
||||||
|
callback()
|
||||||
|
return(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
if(attempt()) return
|
||||||
|
|
||||||
|
this._layoutObserver = new ResizeObserver(() => { attempt() })
|
||||||
|
this._layoutObserver.observe(this)
|
||||||
|
|
||||||
|
let frames = 0
|
||||||
|
const rafPoll = () => {
|
||||||
|
if(token !== this._layoutScheduleToken) return
|
||||||
|
if(attempt()) return
|
||||||
|
if(++frames < 12) requestAnimationFrame(rafPoll)
|
||||||
|
}
|
||||||
|
requestAnimationFrame(rafPoll)
|
||||||
|
}
|
||||||
|
|
||||||
|
_scheduleAutoPlaceWhenReady(orientation, gapx, gapy, onLayoutComplete){
|
||||||
|
this._scheduleLayoutWhenReady(() => {
|
||||||
|
this.autoPlace(orientation, gapx, gapy, null, null, onLayoutComplete)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
_maybeFireLayoutComplete(){
|
||||||
|
if(this._layoutMovePending > 0) return
|
||||||
|
if(!this._layoutCompleteHandler) return
|
||||||
|
const fn = this._layoutCompleteHandler
|
||||||
|
this._layoutCompleteHandler = null
|
||||||
|
fn()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convert viewport (client) coordinates to this instance's SVG local coordinates.
|
// Convert viewport (client) coordinates to this instance's SVG local coordinates.
|
||||||
@@ -669,7 +785,7 @@ class BZgraflow extends Buildoz{
|
|||||||
return(path)
|
return(path)
|
||||||
}
|
}
|
||||||
|
|
||||||
autoPlace(orientation = null, gapx = null, gapy = null, tween = null, align = null){
|
autoPlace(orientation = null, gapx = null, gapy = null, tween = null, align = null, onLayoutComplete = null){
|
||||||
if(orientation == null) orientation = this.getBZAttribute('orientation') || this.currentOrientation || 'horizontal'
|
if(orientation == null) orientation = this.getBZAttribute('orientation') || this.currentOrientation || 'horizontal'
|
||||||
if(gapx == null) gapx = parseInt(this.getBZAttribute('gapx')) || 80
|
if(gapx == null) gapx = parseInt(this.getBZAttribute('gapx')) || 80
|
||||||
if(gapy == null) gapy = parseInt(this.getBZAttribute('gapy')) || 80
|
if(gapy == null) gapy = parseInt(this.getBZAttribute('gapy')) || 80
|
||||||
@@ -681,6 +797,9 @@ class BZgraflow extends Buildoz{
|
|||||||
// moveNode() checks this token each frame and will no-op if superseded.
|
// moveNode() checks this token each frame and will no-op if superseded.
|
||||||
this._autoPlaceToken = (this._autoPlaceToken || 0) + 1
|
this._autoPlaceToken = (this._autoPlaceToken || 0) + 1
|
||||||
const token = this._autoPlaceToken
|
const token = this._autoPlaceToken
|
||||||
|
this._layoutMovePending = 0
|
||||||
|
this._layoutCompleteToken = token
|
||||||
|
this._layoutCompleteHandler = (typeof onLayoutComplete === 'function') ? onLayoutComplete : null
|
||||||
|
|
||||||
// Cleanup placeholders from previous autoPlace() runs.
|
// Cleanup placeholders from previous autoPlace() runs.
|
||||||
// Each run creates new longLinkPlaceHolder_* IDs; without cleanup they accumulate in the DOM.
|
// Each run creates new longLinkPlaceHolder_* IDs; without cleanup they accumulate in the DOM.
|
||||||
@@ -804,7 +923,7 @@ class BZgraflow extends Buildoz{
|
|||||||
y = Math.max(parentsY[parents[nid][0]], y) //TODO handle multiple parents with avg
|
y = Math.max(parentsY[parents[nid][0]], y) //TODO handle multiple parents with avg
|
||||||
}
|
}
|
||||||
placedY = y
|
placedY = y
|
||||||
this.moveNode(nid, x, y, orientation, tween, null, token)
|
this.moveNode(nid, x, y, orientation, tween, token)
|
||||||
if((align == 'parent') && (nid in parents) && (parents[nid][0] in parentsY)) {
|
if((align == 'parent') && (nid in parents) && (parents[nid][0] in parentsY)) {
|
||||||
parentsY[parents[nid][0]] += gapy + nodeHeight
|
parentsY[parents[nid][0]] += gapy + nodeHeight
|
||||||
} else {
|
} else {
|
||||||
@@ -817,7 +936,7 @@ class BZgraflow extends Buildoz{
|
|||||||
}
|
}
|
||||||
placedY = y
|
placedY = y
|
||||||
this.addFakeNode(nid, x, y, wMax*0.75, fakeNodeHeight)
|
this.addFakeNode(nid, x, y, wMax*0.75, fakeNodeHeight)
|
||||||
this.moveNode(nid, x, y, orientation, tween, null, token)
|
this.moveNode(nid, x, y, orientation, tween, token)
|
||||||
// Never increment parentsY for fake nodes: they're placeholders and must not disalign real children
|
// Never increment parentsY for fake nodes: they're placeholders and must not disalign real children
|
||||||
y = Math.max(y, placedY + gapy + fakeNodeHeight)
|
y = Math.max(y, placedY + gapy + fakeNodeHeight)
|
||||||
}
|
}
|
||||||
@@ -838,7 +957,7 @@ class BZgraflow extends Buildoz{
|
|||||||
!nid.startsWith('longLinkPlaceHolder_') && nid in parents && parents[nid][0] === pid
|
!nid.startsWith('longLinkPlaceHolder_') && nid in parents && parents[nid][0] === pid
|
||||||
)
|
)
|
||||||
if(firstRealChild && nodeY[pid] !== nodeY[firstRealChild]){
|
if(firstRealChild && nodeY[pid] !== nodeY[firstRealChild]){
|
||||||
this.moveNode(pid, nodeX[pid], nodeY[firstRealChild], orientation, tween, null, token)
|
this.moveNode(pid, nodeX[pid], nodeY[firstRealChild], orientation, tween, token)
|
||||||
nodeY[pid] = nodeY[firstRealChild]
|
nodeY[pid] = nodeY[firstRealChild]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -867,17 +986,18 @@ class BZgraflow extends Buildoz{
|
|||||||
for(const nid of layer){
|
for(const nid of layer){
|
||||||
if(!nid.startsWith('longLinkPlaceHolder_')){
|
if(!nid.startsWith('longLinkPlaceHolder_')){
|
||||||
const bb = this.stagedNodes[nid].getBoundingClientRect()
|
const bb = this.stagedNodes[nid].getBoundingClientRect()
|
||||||
this.moveNode(nid, x, y, orientation, tween, null, token)
|
this.moveNode(nid, x, y, orientation, tween, token)
|
||||||
x += gapx + (this.stagedNodes[nid].offsetWidth || bb.width)
|
x += gapx + (this.stagedNodes[nid].offsetWidth || bb.width)
|
||||||
} else {
|
} else {
|
||||||
this.addFakeNode(nid, x, y, fakeNodeWidth, hMax*0.75)
|
this.addFakeNode(nid, x, y, fakeNodeWidth, hMax*0.75)
|
||||||
this.moveNode(nid, x, y, orientation, tween, null, token)
|
this.moveNode(nid, x, y, orientation, tween, token)
|
||||||
x += gapx + fakeNodeWidth
|
x += gapx + fakeNodeWidth
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
y += hMax + gapy
|
y += hMax + gapy
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
this._maybeFireLayoutComplete()
|
||||||
}
|
}
|
||||||
|
|
||||||
clearFakeNodes(){
|
clearFakeNodes(){
|
||||||
@@ -997,17 +1117,34 @@ class BZgraflow extends Buildoz{
|
|||||||
}
|
}
|
||||||
|
|
||||||
moveNode(nid, destx, desty, orientation, duration = 200, autoPlaceToken = null) {
|
moveNode(nid, destx, desty, orientation, duration = 200, autoPlaceToken = null) {
|
||||||
const t0 = performance.now()
|
|
||||||
const el0 = this.stagedNodes?.[nid]
|
const el0 = this.stagedNodes?.[nid]
|
||||||
if(!el0) return
|
if(!el0) return
|
||||||
|
let layoutTracked = false
|
||||||
|
if(autoPlaceToken != null && autoPlaceToken === this._layoutCompleteToken) {
|
||||||
|
layoutTracked = true
|
||||||
|
this._layoutMovePending++
|
||||||
|
}
|
||||||
|
const finishLayoutMove = () => {
|
||||||
|
if(!layoutTracked) return
|
||||||
|
layoutTracked = false
|
||||||
|
this._layoutMovePending = Math.max(0, this._layoutMovePending - 1)
|
||||||
|
this._maybeFireLayoutComplete()
|
||||||
|
}
|
||||||
|
const t0 = performance.now()
|
||||||
const bb = el0.getBoundingClientRect()
|
const bb = el0.getBoundingClientRect()
|
||||||
const parentbb = el0.parentElement.getBoundingClientRect()
|
const parentbb = el0.parentElement.getBoundingClientRect()
|
||||||
const x0=bb.x - parentbb.x
|
const x0=bb.x - parentbb.x
|
||||||
const y0 = bb.y - parentbb.y
|
const y0 = bb.y - parentbb.y
|
||||||
function frame(t) {
|
function frame(t) {
|
||||||
if(autoPlaceToken && autoPlaceToken !== this._autoPlaceToken) return
|
if(autoPlaceToken && autoPlaceToken !== this._autoPlaceToken) {
|
||||||
|
finishLayoutMove()
|
||||||
|
return
|
||||||
|
}
|
||||||
const el = this.stagedNodes?.[nid]
|
const el = this.stagedNodes?.[nid]
|
||||||
if(!el) return
|
if(!el) {
|
||||||
|
finishLayoutMove()
|
||||||
|
return
|
||||||
|
}
|
||||||
const p = Math.min((t - t0) / duration, 1)
|
const p = Math.min((t - t0) / duration, 1)
|
||||||
const k = p * p * (3 - 2 * p) // smoothstep
|
const k = p * p * (3 - 2 * p) // smoothstep
|
||||||
const x = x0 + (destx - x0) * k
|
const x = x0 + (destx - x0) * k
|
||||||
@@ -1025,6 +1162,7 @@ class BZgraflow extends Buildoz{
|
|||||||
flowNode.coords.y = y
|
flowNode.coords.y = y
|
||||||
}
|
}
|
||||||
this.fireEvent('nodeMoved', { nid, x, y })
|
this.fireEvent('nodeMoved', { nid, x, y })
|
||||||
|
finishLayoutMove()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
requestAnimationFrame(frame.bind(this))
|
requestAnimationFrame(frame.bind(this))
|
||||||
@@ -1194,16 +1332,69 @@ class BZgraflow extends Buildoz{
|
|||||||
return(crossLayerLinks)
|
return(crossLayerLinks)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Union bounding boxes of nodes and wires (viewport coords).
|
||||||
|
* Same measurement strategy as autofit(). Call with transform cleared for stable sizes.
|
||||||
|
*/
|
||||||
|
getContentSize(){
|
||||||
|
let left = Infinity
|
||||||
|
let top = Infinity
|
||||||
|
let right = -Infinity
|
||||||
|
let bottom = -Infinity
|
||||||
|
|
||||||
|
const includeBB = (bb) => {
|
||||||
|
if(!bb) return
|
||||||
|
left = Math.min(left, bb.left)
|
||||||
|
top = Math.min(top, bb.top)
|
||||||
|
right = Math.max(right, bb.right)
|
||||||
|
bottom = Math.max(bottom, bb.bottom)
|
||||||
|
}
|
||||||
|
|
||||||
|
this.nodesContainer?.querySelectorAll?.('.bzgf-node').forEach(nodeEl => includeBB(nodeEl.getBoundingClientRect()))
|
||||||
|
this.wiresContainer?.querySelectorAll?.('path.bzgf-wire').forEach(path => includeBB(path.getBoundingClientRect()))
|
||||||
|
|
||||||
|
const gapx = parseInt(this.getBZAttribute('gapx')) || 80
|
||||||
|
const gapy = parseInt(this.getBZAttribute('gapy')) || 80
|
||||||
|
const hasBounds = Number.isFinite(left) && Number.isFinite(right) && Number.isFinite(top) && Number.isFinite(bottom)
|
||||||
|
const rawWidth = hasBounds ? Math.max(right - left, 1) : Math.max(this.mainContainer?.clientWidth || this.offsetWidth || 1, 1)
|
||||||
|
const rawHeight = hasBounds ? Math.max(bottom - top, 1) : Math.max(this.mainContainer?.clientHeight || this.offsetHeight || 1, 1)
|
||||||
|
|
||||||
|
return({
|
||||||
|
left: hasBounds ? left : null,
|
||||||
|
top: hasBounds ? top : null,
|
||||||
|
right: hasBounds ? right : null,
|
||||||
|
bottom: hasBounds ? bottom : null,
|
||||||
|
rawWidth,
|
||||||
|
rawHeight,
|
||||||
|
width: rawWidth + (2 * gapx),
|
||||||
|
height: rawHeight + (2 * gapy),
|
||||||
|
gapx,
|
||||||
|
gapy,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
autofit(percent=100){
|
autofit(percent=100){
|
||||||
|
if(!this.parentElement) return
|
||||||
|
|
||||||
|
const prevTransformOrigin = this.style.transformOrigin
|
||||||
|
this.style.transform = 'none'
|
||||||
|
this.style.transformOrigin = 'top left'
|
||||||
|
|
||||||
|
const { left, top, width: contentW, height: contentH, gapx, gapy } = this.getContentSize()
|
||||||
const parentBB = this.parentElement.getBoundingClientRect()
|
const parentBB = this.parentElement.getBoundingClientRect()
|
||||||
// Use scroll dimensions for actual content extent (nodes can extend beyond element bounds)
|
|
||||||
const contentW = Math.max(this.scrollWidth || this.offsetWidth || 1, 1)
|
|
||||||
const contentH = Math.max(this.scrollHeight || this.offsetHeight || 1, 1)
|
|
||||||
const sx = parentBB.width / contentW
|
const sx = parentBB.width / contentW
|
||||||
const sy = parentBB.height / contentH
|
const sy = parentBB.height / contentH
|
||||||
const scale = Math.min(sx, sy)*(percent/100) // uniform scale to fit inside parent
|
const scale = Math.min(sx, sy)*(percent/100) // uniform scale to fit inside parent
|
||||||
this.style.transformOrigin = 'top left'
|
const tx = left != null ? (-left + gapx) : gapx
|
||||||
this.style.transform = `scale(${scale})`
|
const ty = top != null ? (-top + gapy) : gapy
|
||||||
|
if(!this.isSubflow) {
|
||||||
|
this.style.transformOrigin = prevTransformOrigin || 'top left'
|
||||||
|
this.style.transform = `scale(${scale}) translate(${tx}px, ${ty}px)`
|
||||||
|
} else {
|
||||||
|
this.style.transform = `scale(${scale})`
|
||||||
|
this.style.width = `calc(100% / ${scale})` // means 100% of the parent node DESPITE the scaling
|
||||||
|
this.style.height = `calc(100% / ${scale})` // means 100% of the parent node DESPITE the scaling
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Buildoz.define('graflow', BZgraflow)
|
Buildoz.define('graflow', BZgraflow)
|
||||||
|
|||||||
@@ -54,7 +54,7 @@
|
|||||||
window.addEventListener('load',()=>{
|
window.addEventListener('load',()=>{
|
||||||
let grflw1 = document.querySelector('bz-graflow.compunet')
|
let grflw1 = document.querySelector('bz-graflow.compunet')
|
||||||
grflw1.addEventListener('bz:graflow:subflowLoaded',
|
grflw1.addEventListener('bz:graflow:subflowLoaded',
|
||||||
(evt) => { grflw1 = evt.detail.subflow }
|
(evt) => { grflw1 = evt.detail.component }
|
||||||
)
|
)
|
||||||
grflw1.addEventListener('bz:graflow:subflowExited',
|
grflw1.addEventListener('bz:graflow:subflowExited',
|
||||||
(evt) => { grflw1 = evt.target }
|
(evt) => { grflw1 = evt.target }
|
||||||
|
|||||||
@@ -54,7 +54,7 @@
|
|||||||
window.addEventListener('load',()=>{
|
window.addEventListener('load',()=>{
|
||||||
let grflw3 = document.querySelector('bz-graflow.organi')
|
let grflw3 = document.querySelector('bz-graflow.organi')
|
||||||
grflw3.addEventListener('bz:graflow:subflowLoaded',
|
grflw3.addEventListener('bz:graflow:subflowLoaded',
|
||||||
(evt) => { grflw3 = evt.detail.subflow }
|
(evt) => { grflw3 = evt.detail.component }
|
||||||
)
|
)
|
||||||
grflw3.addEventListener('bz:graflow:subflowExited',
|
grflw3.addEventListener('bz:graflow:subflowExited',
|
||||||
(evt) => { grflw3 = evt.target }
|
(evt) => { grflw3 = evt.target }
|
||||||
|
|||||||
@@ -57,7 +57,7 @@
|
|||||||
grflw2.setAttribute('align', document.querySelector('select[name="align"]').value)
|
grflw2.setAttribute('align', document.querySelector('select[name="align"]').value)
|
||||||
grflw2.setAttribute('wiretype', document.querySelector('select[name="wiretype"]').value)
|
grflw2.setAttribute('wiretype', document.querySelector('select[name="wiretype"]').value)
|
||||||
grflw2.addEventListener('bz:graflow:subflowLoaded',
|
grflw2.addEventListener('bz:graflow:subflowLoaded',
|
||||||
(evt) => { grflw2 = evt.detail.subflow }
|
(evt) => { grflw2 = evt.detail.component }
|
||||||
)
|
)
|
||||||
grflw2.addEventListener('bz:graflow:subflowExited',
|
grflw2.addEventListener('bz:graflow:subflowExited',
|
||||||
(evt) => { grflw2 = evt.target }
|
(evt) => { grflw2 = evt.target }
|
||||||
|
|||||||
@@ -57,7 +57,7 @@
|
|||||||
grflw4.setAttribute('align', document.querySelector('select[name="align"]').value)
|
grflw4.setAttribute('align', document.querySelector('select[name="align"]').value)
|
||||||
grflw4.setAttribute('wiretype', document.querySelector('select[name="wiretype"]').value)
|
grflw4.setAttribute('wiretype', document.querySelector('select[name="wiretype"]').value)
|
||||||
grflw4.addEventListener('bz:graflow:subflowLoaded',
|
grflw4.addEventListener('bz:graflow:subflowLoaded',
|
||||||
(evt) => { grflw4 = evt.detail.subflow }
|
(evt) => { grflw4 = evt.detail.component }
|
||||||
)
|
)
|
||||||
grflw4.addEventListener('bz:graflow:subflowExited',
|
grflw4.addEventListener('bz:graflow:subflowExited',
|
||||||
(evt) => { grflw4 = evt.target }
|
(evt) => { grflw4 = evt.target }
|
||||||
|
|||||||
@@ -83,7 +83,7 @@
|
|||||||
|
|
||||||
let grflw4 = document.querySelector('bz-graflow.icmp')
|
let grflw4 = document.querySelector('bz-graflow.icmp')
|
||||||
grflw4.addEventListener('bz:graflow:subflowLoaded',
|
grflw4.addEventListener('bz:graflow:subflowLoaded',
|
||||||
(evt) => { grflw4 = evt.detail.subflow }
|
(evt) => { grflw4 = evt.detail.component }
|
||||||
)
|
)
|
||||||
grflw4.addEventListener('bz:graflow:subflowExited',
|
grflw4.addEventListener('bz:graflow:subflowExited',
|
||||||
(evt) => { grflw4 = evt.target }
|
(evt) => { grflw4 = evt.target }
|
||||||
@@ -110,7 +110,7 @@
|
|||||||
ro.observe(el)
|
ro.observe(el)
|
||||||
|
|
||||||
let aifmi = null; let sidx=0;
|
let aifmi = null; let sidx=0;
|
||||||
const sevanimation = () => { console.log('sevanimation')
|
const sevanimation = () => {
|
||||||
severities.forEach(severity => aifmi.removeAttribute(severity))
|
severities.forEach(severity => aifmi.removeAttribute(severity))
|
||||||
aifmi.setAttribute(severities[sidx], '')
|
aifmi.setAttribute(severities[sidx], '')
|
||||||
sidx++
|
sidx++
|
||||||
|
|||||||
@@ -54,7 +54,7 @@
|
|||||||
window.addEventListener('load',()=>{
|
window.addEventListener('load',()=>{
|
||||||
let grflw1 = document.querySelector('bz-graflow.compunet')
|
let grflw1 = document.querySelector('bz-graflow.compunet')
|
||||||
grflw1.addEventListener('bz:graflow:subflowLoaded',
|
grflw1.addEventListener('bz:graflow:subflowLoaded',
|
||||||
(evt) => { grflw1 = evt.detail.subflow }
|
(evt) => { grflw1 = evt.detail.component }
|
||||||
)
|
)
|
||||||
grflw1.addEventListener('bz:graflow:subflowExited',
|
grflw1.addEventListener('bz:graflow:subflowExited',
|
||||||
(evt) => { grflw1 = evt.target }
|
(evt) => { grflw1 = evt.target }
|
||||||
|
|||||||
@@ -57,7 +57,7 @@
|
|||||||
grflw1.setAttribute('align', document.querySelector('select[name="align"]').value)
|
grflw1.setAttribute('align', document.querySelector('select[name="align"]').value)
|
||||||
grflw1.setAttribute('wiretype', document.querySelector('select[name="wiretype"]').value)
|
grflw1.setAttribute('wiretype', document.querySelector('select[name="wiretype"]').value)
|
||||||
grflw1.addEventListener('bz:graflow:subflowLoaded',
|
grflw1.addEventListener('bz:graflow:subflowLoaded',
|
||||||
(evt) => { grflw1 = evt.detail.subflow }
|
(evt) => { grflw1 = evt.detail.component }
|
||||||
)
|
)
|
||||||
grflw1.addEventListener('bz:graflow:subflowExited',
|
grflw1.addEventListener('bz:graflow:subflowExited',
|
||||||
(evt) => { grflw1 = evt.target }
|
(evt) => { grflw1 = evt.target }
|
||||||
|
|||||||
Reference in New Issue
Block a user