Work on special pages
This commit is contained in:
parent
d9adfd3a91
commit
da7999fb24
7 changed files with 185 additions and 95 deletions
2
node.go
2
node.go
|
|
@ -54,6 +54,7 @@ type Node struct {
|
||||||
DeletedSeq sql.NullInt64 `db:"deleted_seq"`
|
DeletedSeq sql.NullInt64 `db:"deleted_seq"`
|
||||||
Content string
|
Content string
|
||||||
ContentEncrypted string `db:"content_encrypted" json:"-"`
|
ContentEncrypted string `db:"content_encrypted" json:"-"`
|
||||||
|
Special bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func NodeTree(userID, offset int, synced uint64) (nodes []TreeNode, maxSeq uint64, moreRowsExist bool, err error) { // {{{
|
func NodeTree(userID, offset int, synced uint64) (nodes []TreeNode, maxSeq uint64, moreRowsExist bool, err error) { // {{{
|
||||||
|
|
@ -135,6 +136,7 @@ func Nodes(userID, offset int, synced uint64, clientUUID string) (nodes []Node,
|
||||||
FROM
|
FROM
|
||||||
public.node
|
public.node
|
||||||
WHERE
|
WHERE
|
||||||
|
NOT special AND
|
||||||
user_id = $1 AND
|
user_id = $1 AND
|
||||||
client != $5::uuid AND
|
client != $5::uuid AND
|
||||||
(
|
(
|
||||||
|
|
|
||||||
|
|
@ -186,6 +186,11 @@ button {
|
||||||
img {
|
img {
|
||||||
width: auto;
|
width: auto;
|
||||||
height: 18px;
|
height: 18px;
|
||||||
|
|
||||||
|
&.deleted {
|
||||||
|
height: 24px;
|
||||||
|
transform: translateX(3px) translateY(3px);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -24,12 +24,12 @@
|
||||||
inkscape:deskcolor="#d1d1d1"
|
inkscape:deskcolor="#d1d1d1"
|
||||||
inkscape:document-units="px"
|
inkscape:document-units="px"
|
||||||
inkscape:zoom="31.614857"
|
inkscape:zoom="31.614857"
|
||||||
inkscape:cx="5.0609117"
|
inkscape:cx="5.0450964"
|
||||||
inkscape:cy="9.5524708"
|
inkscape:cy="9.5682862"
|
||||||
inkscape:window-width="2190"
|
inkscape:window-width="2190"
|
||||||
inkscape:window-height="1401"
|
inkscape:window-height="1401"
|
||||||
inkscape:window-x="1463"
|
inkscape:window-x="1463"
|
||||||
inkscape:window-y="0"
|
inkscape:window-y="18"
|
||||||
inkscape:window-maximized="1"
|
inkscape:window-maximized="1"
|
||||||
inkscape:current-layer="layer1"
|
inkscape:current-layer="layer1"
|
||||||
showgrid="false" /><defs
|
showgrid="false" /><defs
|
||||||
|
|
|
||||||
|
Before Width: | Height: | Size: 2.4 KiB After Width: | Height: | Size: 2.4 KiB |
68
static/images/leaf_deleted.svg
Normal file
68
static/images/leaf_deleted.svg
Normal file
|
|
@ -0,0 +1,68 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
width="24.000015"
|
||||||
|
height="23.999998"
|
||||||
|
viewBox="0 0 6.350004 6.3499995"
|
||||||
|
version="1.1"
|
||||||
|
id="svg1"
|
||||||
|
sodipodi:docname="leaf_deleted.svg"
|
||||||
|
inkscape:version="1.4.4 (dcaf3e7d9e, 2026-05-05)"
|
||||||
|
xml:space="preserve"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"><sodipodi:namedview
|
||||||
|
id="namedview1"
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
bordercolor="#000000"
|
||||||
|
borderopacity="0.25"
|
||||||
|
inkscape:showpageshadow="2"
|
||||||
|
inkscape:pageopacity="0.0"
|
||||||
|
inkscape:pagecheckerboard="0"
|
||||||
|
inkscape:deskcolor="#d1d1d1"
|
||||||
|
inkscape:document-units="px"
|
||||||
|
inkscape:zoom="22.627417"
|
||||||
|
inkscape:cx="3.292466"
|
||||||
|
inkscape:cy="15.62264"
|
||||||
|
inkscape:window-width="2190"
|
||||||
|
inkscape:window-height="1401"
|
||||||
|
inkscape:window-x="1463"
|
||||||
|
inkscape:window-y="18"
|
||||||
|
inkscape:window-maximized="1"
|
||||||
|
inkscape:current-layer="layer1"
|
||||||
|
showgrid="false" /><defs
|
||||||
|
id="defs1" /><g
|
||||||
|
inkscape:label="Layer 1"
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
id="layer1"
|
||||||
|
transform="translate(-107.95,-148.16667)"><title
|
||||||
|
id="title1">folder-open</title><title
|
||||||
|
id="title1-1">folder-open-outline</title><title
|
||||||
|
id="title1-5">notebook-outline</title><title
|
||||||
|
id="title1-8">text-box-outline</title><path
|
||||||
|
style="fill:#ffffff;stroke-width:0.264583"
|
||||||
|
d="m 108.3015,148.56838 h 3.95851 v 3.96688 h -3.95851 z"
|
||||||
|
id="path3"
|
||||||
|
sodipodi:nodetypes="ccccc" /><path
|
||||||
|
d="m 108.47917,148.16667 c -0.29369,0 -0.52917,0.23548 -0.52917,0.52917 V 152.4 c 0,0.29369 0.23548,0.52917 0.52917,0.52917 h 3.70416 c 0.29369,0 0.52917,-0.23548 0.52917,-0.52917 v -3.70416 c 0,-0.29369 -0.23548,-0.52917 -0.52917,-0.52917 h -3.70416 m 0,0.52917 h 3.70416 V 152.4 h -3.70416 v -3.70416"
|
||||||
|
id="path1"
|
||||||
|
style="fill:#ababab;fill-opacity:1;stroke-width:0.264583"
|
||||||
|
sodipodi:nodetypes="cssssssscccccc" /><path
|
||||||
|
d="m 109.00833,149.225 v 0.52917 h 2.64584 V 149.225 h -2.64584 m 0,1.05834 v 0.52916 h 2.64584 v -0.52916 h -2.64584 m 0,1.05833 v 0.52917 h 1.85209 v -0.52917 z"
|
||||||
|
id="path2"
|
||||||
|
style="fill:#c7c7c7;fill-opacity:1;stroke-width:0.264583"
|
||||||
|
sodipodi:nodetypes="ccccccccccccccc" /><title
|
||||||
|
id="title1-9">delete-circle</title><g
|
||||||
|
id="g1"
|
||||||
|
transform="matrix(1.6249303,0,0,1.6249427,-68.307567,-93.38766)"><rect
|
||||||
|
style="fill:#ffffff;stroke:none;stroke-width:0.79375"
|
||||||
|
id="rect1"
|
||||||
|
width="1.5817325"
|
||||||
|
height="1.8579081"
|
||||||
|
x="110.28522"
|
||||||
|
y="150.33034" /><path
|
||||||
|
d="m 111.0761,149.95667 c 0.72034,0 1.30261,0.58227 1.30261,1.30262 0,0.72035 -0.58227,1.3026 -1.30261,1.3026 -0.72035,0 -1.30263,-0.58225 -1.30263,-1.3026 0,-0.72035 0.58227,-1.30262 1.30263,-1.30262 m 0.6513,0.65131 h -0.32566 l -0.13026,-0.13026 h -0.39078 l -0.13027,0.13026 h -0.32565 v 0.26052 h 1.30262 v -0.26052 m -1.0421,1.43288 h 0.78157 a 0.13026143,0.13026143 0 0 0 0.13026,-0.13026 v -0.91184 h -1.04209 v 0.91184 a 0.13026143,0.13026143 0 0 0 0.13026,0.13026 z"
|
||||||
|
id="path1-1"
|
||||||
|
style="fill:#aa0000;stroke-width:0.130261" /></g></g></svg>
|
||||||
|
After Width: | Height: | Size: 3.3 KiB |
|
|
@ -1,6 +1,8 @@
|
||||||
import { Node } from 'node'
|
import { Node } from 'node'
|
||||||
|
|
||||||
export const ROOT_NODE = '00000000-0000-0000-0000-000000000000'
|
export const ROOT_NODE = '00000000-0000-0000-0000-000000000000'
|
||||||
|
export const ORPHANED_NODE = '00000000-0000-0000-0000-000000000001'
|
||||||
|
export const DELETED_NODE = '00000000-0000-0000-0000-000000000002'
|
||||||
|
|
||||||
export class NodeStore {
|
export class NodeStore {
|
||||||
constructor() {//{{{
|
constructor() {//{{{
|
||||||
|
|
@ -76,8 +78,7 @@ export class NodeStore {
|
||||||
this.sendQueue = new SimpleNodeStore(this.db, 'send_queue')
|
this.sendQueue = new SimpleNodeStore(this.db, 'send_queue')
|
||||||
this.nodesHistory = new NodeHistoryStore(this.db, 'nodes_history')
|
this.nodesHistory = new NodeHistoryStore(this.db, 'nodes_history')
|
||||||
this.files = new SimpleNodeStore(this.db, 'files')
|
this.files = new SimpleNodeStore(this.db, 'files')
|
||||||
this.initializeRootNode()
|
resolve()
|
||||||
.then(() => resolve())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
req.onerror = (event) => {
|
req.onerror = (event) => {
|
||||||
|
|
@ -85,37 +86,6 @@ export class NodeStore {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}//}}}
|
}//}}}
|
||||||
initializeRootNode() {//{{{
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
// The root node is a magical node which displays as the first node if none is specified.
|
|
||||||
// If not already existing, it will be created.
|
|
||||||
const trx = this.db.transaction('nodes', 'readwrite')
|
|
||||||
const nodes = trx.objectStore('nodes')
|
|
||||||
const getRequest = nodes.get(ROOT_NODE)
|
|
||||||
getRequest.onsuccess = (event) => {
|
|
||||||
// Root node exists - nice!
|
|
||||||
if (event.target.result !== undefined) {
|
|
||||||
resolve(event.target.result)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
const putRequest = nodes.put({
|
|
||||||
UUID: ROOT_NODE,
|
|
||||||
Name: 'Notes2',
|
|
||||||
Content: 'Hello, World!',
|
|
||||||
Updated: new Date().toISOString(),
|
|
||||||
ParentUUID: '',
|
|
||||||
})
|
|
||||||
putRequest.onsuccess = (event) => {
|
|
||||||
resolve(event.target.result)
|
|
||||||
}
|
|
||||||
putRequest.onerror = (event) => {
|
|
||||||
reject(event.target.error)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
getRequest.onerror = (event) => reject(event.target.error)
|
|
||||||
})
|
|
||||||
}//}}}
|
|
||||||
purgeCache() {//{{{
|
purgeCache() {//{{{
|
||||||
this.nodes = {}
|
this.nodes = {}
|
||||||
}//}}}
|
}//}}}
|
||||||
|
|
@ -272,74 +242,92 @@ export class NodeStore {
|
||||||
}//}}}
|
}//}}}
|
||||||
get(uuid, suppliedNodestore) {//{{{
|
get(uuid, suppliedNodestore) {//{{{
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
|
switch (uuid) {
|
||||||
|
case ROOT_NODE:
|
||||||
|
const rootNode = new Node({ UUID: ROOT_NODE, Name: 'Start', Special: true }, -1)
|
||||||
|
this.nodes[ROOT_NODE] = rootNode
|
||||||
|
resolve(rootNode)
|
||||||
|
return
|
||||||
|
case DELETED_NODE:
|
||||||
|
const deletedNode = new Node({ UUID: DELETED_NODE, Name: 'Deleted nodes', Special: true }, -1)
|
||||||
|
this.nodes[DELETED_NODE] = deletedNode
|
||||||
|
resolve(deletedNode)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// A nodestore can be provided in order to
|
// A nodestore can be provided in order to
|
||||||
// avoid creating new transactions.
|
// avoid creating new transactions.
|
||||||
let trx
|
let trx
|
||||||
let nodeStore = suppliedNodestore
|
let nodeStore = suppliedNodestore
|
||||||
|
|
||||||
if (nodeStore === undefined) {
|
if (nodeStore === undefined) {
|
||||||
trx = this.db.transaction('nodes', 'readonly')
|
trx = this.db.transaction('nodes', 'readonly')
|
||||||
nodeStore = trx.objectStore('nodes')
|
nodeStore = trx.objectStore('nodes')
|
||||||
|
}
|
||||||
|
|
||||||
|
const getRequest = nodeStore.get(uuid)
|
||||||
|
|
||||||
|
getRequest.onsuccess = (event) => {
|
||||||
|
// Node not found in IndexedDB.
|
||||||
|
if (event.target.result === undefined) {
|
||||||
|
reject("No such node")
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
const node = this.node(uuid, event.target.result, -1)
|
||||||
|
resolve(node)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}//}}}
|
||||||
|
getNodeAncestry(node, accumulated) {//{{{
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
if (accumulated === undefined)
|
||||||
|
accumulated = []
|
||||||
|
|
||||||
const getRequest = nodeStore.get(uuid)
|
const nodeParentIndex = this.db
|
||||||
|
.transaction('nodes', 'readonly')
|
||||||
|
.objectStore('nodes')
|
||||||
|
|
||||||
getRequest.onsuccess = (event) => {
|
if (node.UUID === ROOT_NODE || node.ParentUUID === ROOT_NODE) {
|
||||||
// Node not found in IndexedDB.
|
resolve(accumulated)
|
||||||
if (event.target.result === undefined) {
|
return
|
||||||
reject("No such node")
|
}
|
||||||
return
|
|
||||||
}
|
|
||||||
const node = this.node(uuid, event.target.result, -1)
|
|
||||||
resolve(node)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}//}}}
|
|
||||||
getNodeAncestry(node, accumulated) {//{{{
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
if (accumulated === undefined)
|
|
||||||
accumulated = []
|
|
||||||
|
|
||||||
const nodeParentIndex = this.db
|
if (node.UUID === DELETED_NODE || node.ParentUUID === DELETED_NODE) {
|
||||||
.transaction('nodes', 'readonly')
|
resolve(accumulated)
|
||||||
.objectStore('nodes')
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if (node.UUID === ROOT_NODE || node.ParentUUID === ROOT_NODE) {
|
const getRequest = nodeParentIndex.get(node.ParentUUID)
|
||||||
resolve(accumulated)
|
getRequest.onsuccess = (event) => {
|
||||||
|
// Node not found in IndexedDB.
|
||||||
|
// Not expected to happen.
|
||||||
|
const parentNodeData = event.target.result
|
||||||
|
if (parentNodeData === undefined) {
|
||||||
|
reject("No such node")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
const getRequest = nodeParentIndex.get(node.ParentUUID)
|
const parentNode = this.node(parentNodeData.UUID, parentNodeData, -1)
|
||||||
getRequest.onsuccess = (event) => {
|
this.getNodeAncestry(parentNode, accumulated.concat(parentNode))
|
||||||
// Node not found in IndexedDB.
|
.then(accumulated => resolve(accumulated))
|
||||||
// Not expected to happen.
|
}
|
||||||
const parentNodeData = event.target.result
|
})
|
||||||
if (parentNodeData === undefined) {
|
|
||||||
reject("No such node")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
const parentNode = this.node(parentNodeData.UUID, parentNodeData, -1)
|
}//}}}
|
||||||
this.getNodeAncestry(parentNode, accumulated.concat(parentNode))
|
newTransaction(objectStore, mode) {// {{{
|
||||||
.then(accumulated => resolve(accumulated))
|
return this.db.transaction(objectStore, mode)
|
||||||
}
|
}// }}}
|
||||||
})
|
|
||||||
|
|
||||||
}//}}}
|
nodeCount() {//{{{
|
||||||
newTransaction(objectStore, mode) {// {{{
|
return new Promise((resolve, reject) => {
|
||||||
return this.db.transaction(objectStore, mode)
|
const t = this.db.transaction('nodes', 'readwrite')
|
||||||
}// }}}
|
const nodeStore = t.objectStore('nodes')
|
||||||
|
const countReq = nodeStore.count()
|
||||||
nodeCount() {//{{{
|
countReq.onsuccess = event => {
|
||||||
return new Promise((resolve, reject) => {
|
resolve(event.target.result)
|
||||||
const t = this.db.transaction('nodes', 'readwrite')
|
}
|
||||||
const nodeStore = t.objectStore('nodes')
|
})
|
||||||
const countReq = nodeStore.count()
|
}//}}}
|
||||||
countReq.onsuccess = event => {
|
|
||||||
resolve(event.target.result)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}//}}}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class SimpleNodeStore {
|
class SimpleNodeStore {
|
||||||
|
|
|
||||||
|
|
@ -46,7 +46,10 @@ export class N2PageNodeUI extends CustomHTMLElement {
|
||||||
|
|
||||||
_mbus.subscribe('NODE_UI_OPEN', event => {
|
_mbus.subscribe('NODE_UI_OPEN', event => {
|
||||||
this.node = event.detail.data
|
this.node = event.detail.data
|
||||||
this.showMarkdown(true)
|
|
||||||
|
|
||||||
|
if (!this.node.isSpecial())
|
||||||
|
this.showMarkdown(true)
|
||||||
this.render()
|
this.render()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
@ -437,6 +440,9 @@ export class Node {
|
||||||
isFirstSibling() {//{{{
|
isFirstSibling() {//{{{
|
||||||
return this._sibling_before === null
|
return this._sibling_before === null
|
||||||
}//}}}
|
}//}}}
|
||||||
|
isSpecial() {// {{{
|
||||||
|
return this.data.Special
|
||||||
|
}// }}}
|
||||||
content() {//{{{
|
content() {//{{{
|
||||||
/* TODO - implement crypto
|
/* TODO - implement crypto
|
||||||
if (this.CryptoKeyID != 0 && !this._decrypted)
|
if (this.CryptoKeyID != 0 && !this._decrypted)
|
||||||
|
|
@ -506,16 +512,15 @@ export class Node {
|
||||||
}
|
}
|
||||||
|
|
||||||
class N2Menu extends CustomHTMLElement {
|
class N2Menu extends CustomHTMLElement {
|
||||||
static {
|
static {// {{{
|
||||||
this.tmpl = document.createElement('template')
|
this.tmpl = document.createElement('template')
|
||||||
this.tmpl.innerHTML = `
|
this.tmpl.innerHTML = `
|
||||||
<div id="node-menu" popover>Popover content</div>
|
<div id="node-menu" popover>Popover content</div>
|
||||||
`
|
`
|
||||||
}
|
}// }}}
|
||||||
|
constructor() {// {{{
|
||||||
constructor() {
|
|
||||||
super()
|
super()
|
||||||
}
|
}// }}}
|
||||||
}
|
}
|
||||||
customElements.define('n2-menu', N2Menu)
|
customElements.define('n2-menu', N2Menu)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
import { ROOT_NODE } from 'node_store'
|
import { ROOT_NODE, ORPHANED_NODE , DELETED_NODE} from 'node_store'
|
||||||
|
import { Node } from 'node'
|
||||||
import { CustomHTMLElement } from './lib/custom_html_element.mjs'
|
import { CustomHTMLElement } from './lib/custom_html_element.mjs'
|
||||||
import { Color, Solver } from './lib/css_colorize.mjs'
|
import { Color, Solver } from './lib/css_colorize.mjs'
|
||||||
|
|
||||||
|
|
@ -156,8 +157,15 @@ export class N2Sidebar extends CustomHTMLElement {
|
||||||
this.expandedNodes[ROOT_NODE] = true
|
this.expandedNodes[ROOT_NODE] = true
|
||||||
const startnode = await nodeStore.get(ROOT_NODE)
|
const startnode = await nodeStore.get(ROOT_NODE)
|
||||||
const starttreenode = new N2TreeNode(this, startnode, null)
|
const starttreenode = new N2TreeNode(this, startnode, null)
|
||||||
|
|
||||||
|
const deletednode = await nodeStore.get(DELETED_NODE)
|
||||||
|
const deletedtreenode = new SpecialNodeDeleted(this, deletednode, null)
|
||||||
|
|
||||||
this.treeNodeComponents[startnode.UUID] = starttreenode
|
this.treeNodeComponents[startnode.UUID] = starttreenode
|
||||||
|
this.treeNodeComponents[deletednode.UUID] = deletedtreenode
|
||||||
|
|
||||||
this.elTreenodes.appendChild(await starttreenode.render())
|
this.elTreenodes.appendChild(await starttreenode.render())
|
||||||
|
this.elTreenodes.appendChild(await deletedtreenode.render())
|
||||||
|
|
||||||
// Notify the application that the initial tree is rendered (with children)
|
// Notify the application that the initial tree is rendered (with children)
|
||||||
// and that initial node selection can take place. App will check URL to
|
// and that initial node selection can take place. App will check URL to
|
||||||
|
|
@ -668,6 +676,12 @@ export class N2TreeNode extends CustomHTMLElement {
|
||||||
// The expand icon <img> is only changed to not get a flickering when re-rendering.
|
// The expand icon <img> is only changed to not get a flickering when re-rendering.
|
||||||
if (this.node.UUID === ROOT_NODE)
|
if (this.node.UUID === ROOT_NODE)
|
||||||
this.setImgSrc(this.elExpand, `/images/${window._VERSION}/icon_home.svg`)
|
this.setImgSrc(this.elExpand, `/images/${window._VERSION}/icon_home.svg`)
|
||||||
|
|
||||||
|
else if (this.node.UUID === '00000000-0000-0000-0000-000000000002') {
|
||||||
|
this.setImgSrc(this.elExpand, `/images/${window._VERSION}/leaf_deleted.svg`)
|
||||||
|
this.elExpand.classList.add('deleted')
|
||||||
|
}
|
||||||
|
|
||||||
else if (!this.node.hasChildren())
|
else if (!this.node.hasChildren())
|
||||||
this.setImgSrc(this.elExpand, `/images/${window._VERSION}/leaf.svg`)
|
this.setImgSrc(this.elExpand, `/images/${window._VERSION}/leaf.svg`)
|
||||||
else if (this.sidebar.getNodeExpanded(this.node.UUID))
|
else if (this.sidebar.getNodeExpanded(this.node.UUID))
|
||||||
|
|
@ -703,7 +717,15 @@ export class N2TreeNode extends CustomHTMLElement {
|
||||||
}// }}}
|
}// }}}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class SpecialNodeDeleted extends N2TreeNode {
|
||||||
|
constructor(sidebar, node, parent) {//{{{
|
||||||
|
super(sidebar, node, parent)
|
||||||
|
this.removeAttribute('draggable')
|
||||||
|
}//}}}
|
||||||
|
}
|
||||||
|
|
||||||
customElements.define('n2-sidebar', N2Sidebar)
|
customElements.define('n2-sidebar', N2Sidebar)
|
||||||
customElements.define('n2-treenode', N2TreeNode)
|
customElements.define('n2-treenode', N2TreeNode)
|
||||||
|
customElements.define('n2-specialnodedeleted', SpecialNodeDeleted)
|
||||||
|
|
||||||
// vim: foldmethod=marker
|
// vim: foldmethod=marker
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue