tapspace
Version:
A zoomable user interface lib for web apps
126 lines (111 loc) • 3.23 kB
JavaScript
module.exports = function (id, content, isPlaceholder) {
// @TreeLoader:open(id, content[, isPlaceholder])
//
// Open a space, given that there are neighbors.
//
// Parameters:
// id
// a string
// content
// a Component
// isPlaceholder
// optional boolean, default false.
// .. Set true to prevent loading propagation continuing to neighbors.
//
if (!this.loading[id]) {
// Not loading anymore
return
}
if (!isPlaceholder) {
// Now loaded.
delete this.loading[id]
}
// TODO auto convert text content to Item
// Space may already exist.
const space = this.spaces[id]
if (space) {
// Reuse basis, replace content.
// TODO what if this happens a lot accidentally due to recursion?
const oldSpace = space
const oldBasis = oldSpace.getBasis().changeBasis(this.viewport)
oldSpace.remove()
this.spaces[id] = content
this.viewport.addChild(content)
content.setBasis(oldBasis)
this.emit('replaced', {
id: id,
old: oldSpace,
new: content
})
// Propagate opening to neighbors if there is demand.
if (!isPlaceholder && this.demand[id] > 1) {
setTimeout(() => {
if (this.spaces[id] && this.demand[id] > 1) {
this.openNeighbors(id, this.demand[id] - 1)
}
}, 0)
}
return
}
// Try find basis for the space.
let basis = null
// Try via parent first.
const parentId = this.backtracker(id, space)
if (parentId && this.spaces[parentId]) {
// Has existing parent.
const parentSpace = this.spaces[parentId]
// Position about the parent.
basis = this.mapper(parentId, parentSpace, id)
}
if (!basis) {
// No parent for reference.
// Try via children.
const childIds = this.tracker(id, space)
// Try to find existing child.
const childId = childIds.find((cid) => {
return this.spaces[cid]
})
if (childId) {
// Child space available.
const childSpace = this.spaces[childId]
// Position about the child
const insertionBasis = this.mapper(id, content, childId)
if (insertionBasis) {
// Insertion basis is the position of the child w.r.t. the parent.
// However, the parent does not yet exist.
const childBasis = childSpace.getBasis()
// Therefore compute where would the parent basis be.
basis = insertionBasis.getMatchedOuter(childBasis)
}
}
}
if (!basis) {
// Possibly a manually added basis via init.
if (this.bases[id]) {
// Consume so it does not stay haunting.
basis = this.bases[id]
delete this.bases[id]
}
}
if (!basis) {
// Cannot find basis.
return
}
// Basis found. Add the content.
this.spaces[id] = content
this.viewport.addChild(content)
content.setBasis(basis)
// Signal that the node is now open and available.
this.emit('opened', {
id: id,
space: content
})
// The node is finished. Propagate opening if there is demand.
if (!isPlaceholder && this.demand[id] > 1) {
setTimeout(() => {
if (this.spaces[id] && this.demand[id] > 1) {
this.openNeighbors(id, this.demand[id] - 1)
}
}, 0)
}
}