2021-01-31 02:43:13 +13:00
|
|
|
<template>
|
|
|
|
|
|
|
|
<span>
|
2021-04-10 12:22:31 +12:00
|
|
|
|
|
|
|
<!-- Delele document dialog -->
|
|
|
|
<deleteDocumentCheckDialog
|
|
|
|
:dialog-trigger="deleteObjectDialogTrigger"
|
|
|
|
:document-id="toDeleteID"
|
|
|
|
:document-type="toDeleteType"
|
|
|
|
@trigger-dialog-close="deleteObjectDialogClose"
|
|
|
|
/>
|
|
|
|
|
2021-03-18 10:26:08 +13:00
|
|
|
<div
|
|
|
|
class="treeSearchWrapper"
|
|
|
|
:class="{'fullWidth': disableDocumentControlBar}"
|
|
|
|
>
|
|
|
|
<q-input
|
|
|
|
ref="treeFilter"
|
|
|
|
filled
|
|
|
|
dark
|
|
|
|
debounce="200"
|
|
|
|
v-model="treeFilter"
|
|
|
|
label="Filter document tree..."
|
|
|
|
>
|
|
|
|
<template v-slot:append>
|
|
|
|
<q-icon name="mdi-text-search" />
|
|
|
|
</template>
|
|
|
|
<template v-slot:prepend>
|
|
|
|
<q-icon v-if="treeFilter !== ''" name="clear" class="cursor-pointer text-secondary" @click="resetTreeFilter" />
|
|
|
|
</template>
|
|
|
|
</q-input>
|
|
|
|
</div>
|
|
|
|
|
|
|
|
<h6 class="projectTitle text-cultured" v-if="!noProjectName">
|
2021-03-08 11:07:40 +13:00
|
|
|
<span>
|
|
|
|
{{projectName}}
|
|
|
|
<q-tooltip
|
|
|
|
:delay="1000"
|
|
|
|
>
|
|
|
|
This is your currently opened project's name.
|
|
|
|
</q-tooltip>
|
|
|
|
</span>
|
|
|
|
</h6>
|
|
|
|
|
2021-01-31 02:43:13 +13:00
|
|
|
<q-tree
|
2021-02-09 15:21:48 +13:00
|
|
|
class="objectTree q-pa-sm"
|
2021-03-18 10:26:08 +13:00
|
|
|
:class="{'hasTextShadow': textShadow}"
|
2021-02-23 11:30:18 +13:00
|
|
|
:nodes="hierarchicalTree"
|
2021-02-21 03:13:37 +13:00
|
|
|
node-key="key"
|
2021-01-31 02:43:13 +13:00
|
|
|
no-connectors
|
|
|
|
ref="tree"
|
|
|
|
dark
|
2021-04-27 01:01:51 +12:00
|
|
|
:duration="200"
|
2021-01-31 02:43:13 +13:00
|
|
|
:filter="treeFilter"
|
|
|
|
:selected.sync="selectedTreeNode"
|
2021-02-26 14:50:46 +13:00
|
|
|
:expanded.sync="expandedTreeNodes"
|
2021-03-08 11:07:40 +13:00
|
|
|
no-nodes-label="Loading your project..."
|
|
|
|
no-results-label="Nothing matches your request"
|
2021-01-31 02:43:13 +13:00
|
|
|
>
|
|
|
|
<template v-slot:default-header="prop">
|
2021-04-06 12:15:17 +12:00
|
|
|
<div
|
|
|
|
class="row items-center col-grow documentWrapper"
|
2021-04-07 02:01:37 +12:00
|
|
|
:class="{'isMinor': prop.node.isMinor, 'isDeadTree': prop.node.isDead}"
|
2021-04-06 12:15:17 +12:00
|
|
|
:style="`background-color: ${prop.node.bgColor};`"
|
|
|
|
@click.stop.prevent="processNodeClick(prop.node)"
|
|
|
|
@click.stop.prevent.middle="processNodeLabelMiddleClick(prop.node)"
|
2021-03-08 11:07:40 +13:00
|
|
|
>
|
2021-02-23 11:30:18 +13:00
|
|
|
<div class="documentLabel"
|
2021-04-06 12:15:17 +12:00
|
|
|
:style="`color: ${prop.node.color};`"
|
2021-02-23 11:30:18 +13:00
|
|
|
>
|
2021-02-26 14:50:46 +13:00
|
|
|
<q-icon
|
2021-03-03 14:10:05 +13:00
|
|
|
:style="`color: ${determineNodeColor(prop.node)}; width: 22px !important;`"
|
2021-02-26 14:50:46 +13:00
|
|
|
:size="(prop.node.icon.includes('fas')? '16px': '21px')"
|
|
|
|
:name="prop.node.icon"
|
|
|
|
class="q-mr-sm self-center" />
|
2021-04-07 02:01:37 +12:00
|
|
|
<span v-if="prop.node.isDead" class="documentLabel__isDeadMarker">†</span>
|
2021-04-10 12:22:31 +12:00
|
|
|
<span :class="{'documentLabel__content': !hideDeadCrossThrough}">
|
2021-04-07 02:01:37 +12:00
|
|
|
{{ prop.node.label }}
|
|
|
|
</span>
|
|
|
|
|
2021-01-31 14:46:23 +13:00
|
|
|
<span
|
2021-03-19 14:54:44 +13:00
|
|
|
class="text-grey-5 text-weight-medium q-ml-xs"
|
|
|
|
v-if="(prop.node.isRoot || prop.node.isTag) && !disableDocumentCounts">
|
2021-04-26 09:01:41 +12:00
|
|
|
<span v-html="determineCategoryString(prop.node)"/>
|
2021-03-05 12:51:41 +13:00
|
|
|
<q-tooltip
|
2021-03-19 14:54:44 +13:00
|
|
|
:delay="500"
|
2021-03-05 12:51:41 +13:00
|
|
|
>
|
2021-03-19 14:54:44 +13:00
|
|
|
Document & Categories count: <span class="text-bold text-satin-sheen-gold-dark">{{prop.node.allCount}}</span>
|
|
|
|
<br>
|
2021-03-08 11:07:40 +13:00
|
|
|
Document count: <span class="text-bold text-satin-sheen-gold-dark">{{prop.node.documentCount}}</span>
|
2021-03-05 12:51:41 +13:00
|
|
|
<br>
|
2021-03-08 11:07:40 +13:00
|
|
|
Category count: <span class="text-bold text-satin-sheen-gold-dark">{{prop.node.categoryCount}}</span>
|
2021-03-05 12:51:41 +13:00
|
|
|
</q-tooltip>
|
2021-01-31 14:46:23 +13:00
|
|
|
</span>
|
2021-01-31 02:43:13 +13:00
|
|
|
<q-badge
|
2021-02-26 14:50:46 +13:00
|
|
|
class="treeBadge"
|
2021-03-03 08:59:56 +13:00
|
|
|
:class="{'noChilden': prop.node.children.length === 0}"
|
2021-04-10 12:22:31 +12:00
|
|
|
v-if="prop.node.sticker && !hideTreeOrderNumbers"
|
2021-02-26 14:50:46 +13:00
|
|
|
color="primary"
|
|
|
|
outline
|
|
|
|
floating
|
|
|
|
>
|
|
|
|
{{prop.node.sticker}}
|
|
|
|
<q-tooltip
|
|
|
|
:delay="500"
|
|
|
|
>
|
2021-01-31 02:43:13 +13:00
|
|
|
Order priority of the document
|
|
|
|
</q-tooltip>
|
|
|
|
</q-badge>
|
2021-02-23 11:30:18 +13:00
|
|
|
<div class="treeButtonGroup">
|
|
|
|
<q-btn
|
|
|
|
tabindex="-1"
|
2021-04-11 13:40:03 +12:00
|
|
|
v-if="((prop.node.children && prop.node.children.length > 0) || !hideTreeExtraIcons) && !prop.node.isRoot && !prop.node.isTag && !hideTreeIconView && !prop.node.specialLabel"
|
2021-02-23 11:30:18 +13:00
|
|
|
round
|
2021-02-26 14:50:46 +13:00
|
|
|
flat
|
2021-02-23 11:30:18 +13:00
|
|
|
dense
|
2021-02-26 14:50:46 +13:00
|
|
|
color="dark"
|
|
|
|
class="z-1 q-ml-sm treeButton treeButton--edit"
|
2021-04-11 13:40:03 +12:00
|
|
|
icon="mdi-book-open-page-variant-outline"
|
2021-03-05 12:51:41 +13:00
|
|
|
size="10px"
|
2021-02-26 14:50:46 +13:00
|
|
|
@click.stop.prevent="openExistingDocumentRoute(prop.node)"
|
|
|
|
>
|
|
|
|
<q-tooltip
|
|
|
|
:delay="300"
|
2021-02-23 11:30:18 +13:00
|
|
|
>
|
2021-04-11 13:40:03 +12:00
|
|
|
Open {{ prop.node.label }}
|
|
|
|
</q-tooltip>
|
|
|
|
</q-btn>
|
|
|
|
<q-btn
|
|
|
|
tabindex="-1"
|
|
|
|
v-if="!prop.node.isRoot && !prop.node.isTag && !hideTreeIconEdit && !prop.node.specialLabel"
|
|
|
|
round
|
|
|
|
flat
|
|
|
|
dense
|
|
|
|
color="dark"
|
|
|
|
class="z-1 q-ml-sm treeButton treeButton--edit"
|
|
|
|
icon="mdi-pencil"
|
|
|
|
size="10px"
|
|
|
|
@click.stop.prevent="openExistingDocumentRouteWithEdit(prop.node)"
|
|
|
|
>
|
|
|
|
<q-tooltip
|
|
|
|
:delay="300"
|
|
|
|
>
|
|
|
|
Edit {{ prop.node.label }}
|
2021-02-23 11:30:18 +13:00
|
|
|
</q-tooltip>
|
|
|
|
</q-btn>
|
|
|
|
<q-btn
|
|
|
|
tabindex="-1"
|
2021-04-11 13:40:03 +12:00
|
|
|
v-if="!prop.node.specialLabel && !prop.node.isRoot && !prop.node.isTag && !hideTreeIconAddUnder"
|
2021-02-23 11:30:18 +13:00
|
|
|
round
|
2021-02-26 14:50:46 +13:00
|
|
|
flat
|
2021-02-23 11:30:18 +13:00
|
|
|
dense
|
2021-02-26 14:50:46 +13:00
|
|
|
color="dark"
|
|
|
|
class="z-1 q-ml-sm treeButton treeButton--add"
|
2021-04-10 12:22:31 +12:00
|
|
|
icon="mdi-file-tree"
|
2021-03-05 12:51:41 +13:00
|
|
|
size="10px"
|
2021-02-26 14:50:46 +13:00
|
|
|
@click.stop.prevent="processNodeNewDocumentButton(prop.node)"
|
|
|
|
>
|
|
|
|
<q-tooltip
|
|
|
|
:delay="300"
|
|
|
|
>
|
|
|
|
Add a new document belonging under {{ prop.node.label }}
|
2021-02-23 11:30:18 +13:00
|
|
|
</q-tooltip>
|
|
|
|
</q-btn>
|
|
|
|
</div>
|
2021-04-10 12:22:31 +12:00
|
|
|
<q-menu
|
|
|
|
touch-position
|
|
|
|
context-menu
|
|
|
|
>
|
|
|
|
|
2021-04-16 07:03:18 +12:00
|
|
|
<q-list class="bg-gunmetal-light text-accent" v-if="!prop.node.isTag">
|
2021-04-10 12:22:31 +12:00
|
|
|
|
|
|
|
<template v-if="prop.node.isRoot || prop.node.children.length > 0">
|
|
|
|
<q-item clickable v-close-popup @click="recursivelyExpandNodeDownwards(prop.node.key)">
|
2021-04-11 13:40:03 +12:00
|
|
|
<q-item-section>Expand all under this node</q-item-section>
|
2021-04-10 12:22:31 +12:00
|
|
|
<q-item-section avatar>
|
|
|
|
<q-icon name="mdi-expand-all-outline" />
|
|
|
|
</q-item-section>
|
|
|
|
</q-item>
|
|
|
|
<q-item clickable v-close-popup @click="collapseAllNodesForce(prop.node)">
|
2021-04-11 13:40:03 +12:00
|
|
|
<q-item-section>Collapse all under this node</q-item-section>
|
2021-04-10 12:22:31 +12:00
|
|
|
<q-item-section avatar>
|
|
|
|
<q-icon name="mdi-collapse-all-outline" />
|
|
|
|
</q-item-section>
|
|
|
|
</q-item>
|
|
|
|
</template>
|
|
|
|
|
|
|
|
<template v-if="prop.node.isRoot">
|
2021-04-17 00:46:34 +12:00
|
|
|
<q-separator dark />
|
2021-04-10 12:22:31 +12:00
|
|
|
<q-item clickable v-close-popup @click="addNewObjectRoute(prop.node)">
|
|
|
|
<q-item-section>Add new document of type: {{prop.node.label}}</q-item-section>
|
|
|
|
<q-item-section avatar>
|
|
|
|
<q-icon name="mdi-plus" />
|
|
|
|
</q-item-section>
|
|
|
|
</q-item>
|
|
|
|
</template>
|
|
|
|
|
|
|
|
<template v-if="!prop.node.isRoot">
|
2021-04-17 00:46:34 +12:00
|
|
|
<q-separator dark />
|
2021-04-10 12:22:31 +12:00
|
|
|
<q-item clickable v-close-popup @click="copyName(prop.node)">
|
|
|
|
<q-item-section>Copy name</q-item-section>
|
|
|
|
<q-item-section avatar>
|
|
|
|
<q-icon name="mdi-text-recognition" />
|
|
|
|
</q-item-section>
|
|
|
|
</q-item>
|
|
|
|
<q-item clickable v-close-popup @click="copyTextColor(prop.node)">
|
|
|
|
<q-item-section>Copy text color</q-item-section>
|
|
|
|
<q-item-section avatar>
|
|
|
|
<q-icon name="mdi-eyedropper" />
|
|
|
|
</q-item-section>
|
|
|
|
</q-item>
|
|
|
|
<q-item clickable v-close-popup @click="copyBackgroundColor(prop.node)">
|
|
|
|
<q-item-section>Copy background color</q-item-section>
|
|
|
|
<q-item-section avatar>
|
|
|
|
<q-icon name="mdi-format-color-fill" />
|
|
|
|
</q-item-section>
|
|
|
|
</q-item>
|
2021-04-17 00:46:34 +12:00
|
|
|
<q-separator dark />
|
2021-04-10 12:22:31 +12:00
|
|
|
<q-item clickable v-close-popup @click="openExistingDocumentRoute(prop.node)">
|
|
|
|
<q-item-section>Open document</q-item-section>
|
2021-04-11 13:40:03 +12:00
|
|
|
<q-item-section avatar>
|
|
|
|
<q-icon name="mdi-book-open-page-variant-outline" />
|
|
|
|
</q-item-section>
|
|
|
|
</q-item>
|
|
|
|
<q-item clickable v-close-popup @click="openExistingDocumentRouteWithEdit(prop.node)">
|
|
|
|
<q-item-section>Edit document</q-item-section>
|
2021-04-10 12:22:31 +12:00
|
|
|
<q-item-section avatar>
|
|
|
|
<q-icon name="mdi-pencil" />
|
|
|
|
</q-item-section>
|
|
|
|
</q-item>
|
|
|
|
<q-item clickable v-close-popup @click="addNewUnderParent(prop.node)">
|
|
|
|
<q-item-section>Create new document with this document as parent</q-item-section>
|
|
|
|
<q-item-section avatar>
|
|
|
|
<q-icon name="mdi-file-tree" />
|
|
|
|
</q-item-section>
|
|
|
|
</q-item>
|
|
|
|
<q-item clickable v-close-popup @click="copyTargetDocument(prop.node)">
|
|
|
|
<q-item-section>Copy this document</q-item-section>
|
|
|
|
<q-item-section avatar>
|
|
|
|
<q-icon name="mdi-content-copy" />
|
|
|
|
</q-item-section>
|
|
|
|
</q-item>
|
2021-04-17 00:46:34 +12:00
|
|
|
<q-separator dark />
|
2021-04-10 12:22:31 +12:00
|
|
|
<q-item clickable v-close-popup @click="deleteTabDocument(prop.node)">
|
|
|
|
<q-item-section class="text-secondary"><b>Delete this document</b></q-item-section>
|
|
|
|
<q-item-section avatar class="text-secondary">
|
|
|
|
<q-icon name="mdi-text-box-remove-outline" />
|
|
|
|
</q-item-section>
|
|
|
|
</q-item>
|
|
|
|
</template>
|
|
|
|
|
|
|
|
</q-list>
|
|
|
|
|
|
|
|
</q-menu>
|
2021-02-23 11:30:18 +13:00
|
|
|
</div>
|
2021-01-31 02:43:13 +13:00
|
|
|
</div>
|
2021-02-23 11:30:18 +13:00
|
|
|
|
2021-01-31 02:43:13 +13:00
|
|
|
</template>
|
|
|
|
</q-tree>
|
|
|
|
|
|
|
|
<!--
|
|
|
|
<q-list>
|
|
|
|
<q-separator
|
|
|
|
color="white"
|
|
|
|
inset
|
|
|
|
class="q-mt-md"
|
|
|
|
/>
|
|
|
|
<q-item
|
|
|
|
v-ripple
|
|
|
|
clickable
|
|
|
|
class="q-mt-md"
|
|
|
|
>
|
|
|
|
<q-item-section avatar>
|
|
|
|
<q-icon :name="menuAddNewItem.icon" />
|
|
|
|
</q-item-section>
|
|
|
|
<q-item-section>
|
|
|
|
{{ menuAddNewItem.label }}
|
|
|
|
</q-item-section>
|
|
|
|
</q-item>
|
|
|
|
|
|
|
|
</q-list>
|
|
|
|
|
|
|
|
-->
|
|
|
|
</span>
|
|
|
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
<script lang="ts">
|
2021-02-23 11:30:18 +13:00
|
|
|
import { Component, Watch } from "vue-property-decorator"
|
2021-01-31 02:43:13 +13:00
|
|
|
|
|
|
|
import BaseClass from "src/BaseClass"
|
2021-02-28 06:00:57 +13:00
|
|
|
import { I_OpenedDocument, I_ShortenedDocument } from "src/interfaces/I_OpenedDocument"
|
2021-04-10 12:22:31 +12:00
|
|
|
import deleteDocumentCheckDialog from "src/components/dialogs/DeleteDocumentCheck.vue"
|
|
|
|
|
2021-03-03 14:10:05 +13:00
|
|
|
import { extend, colors } from "quasar"
|
|
|
|
import { tagListBuildFromBlueprints } from "src/scripts/utilities/tagListBuilder"
|
2021-03-08 11:07:40 +13:00
|
|
|
import { retrieveCurrentProjectName } from "src/scripts/projectManagement/projectManagent"
|
2021-04-10 12:22:31 +12:00
|
|
|
import { createNewWithParent } from "src/scripts/documentActions/createNewWithParent"
|
|
|
|
import { copyDocumentName, copyDocumentTextColor, copyDocumentBackgroundColor } from "src/scripts/documentActions/uniqueFieldCopy"
|
|
|
|
import { copyDocument } from "src/scripts/documentActions/copyDocument"
|
2021-01-31 02:43:13 +13:00
|
|
|
|
|
|
|
@Component({
|
2021-04-10 12:22:31 +12:00
|
|
|
components: { deleteDocumentCheckDialog }
|
2021-01-31 02:43:13 +13:00
|
|
|
})
|
|
|
|
export default class ObjectTree extends BaseClass {
|
2021-02-23 11:30:18 +13:00
|
|
|
/****************************************************************/
|
|
|
|
// KEYBINDS MANAGEMENT
|
|
|
|
/****************************************************************/
|
|
|
|
@Watch("SGET_getCurrentKeyBindData", { deep: true })
|
|
|
|
processKeyPush () {
|
|
|
|
// Focus left tree search
|
2021-03-18 10:26:08 +13:00
|
|
|
if (this.determineKeyBind("focusHierarchicalTree") && !this.SGET_getDialogsState) {
|
2021-02-21 01:06:21 +13:00
|
|
|
const treeFilterDOM = this.$refs.treeFilter as unknown as HTMLInputElement
|
|
|
|
treeFilterDOM.focus()
|
|
|
|
}
|
|
|
|
|
2021-02-23 11:30:18 +13:00
|
|
|
// Clear input in the left tree search
|
2021-03-18 10:26:08 +13:00
|
|
|
if (this.determineKeyBind("clearInputHierarchicalTree") && !this.SGET_getDialogsState) {
|
2021-02-21 01:06:21 +13:00
|
|
|
this.resetTreeFilter()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-02-23 11:30:18 +13:00
|
|
|
/****************************************************************/
|
|
|
|
// GENERIC FUNCTIONALITY
|
|
|
|
/****************************************************************/
|
2021-01-31 02:43:13 +13:00
|
|
|
|
2021-03-08 11:07:40 +13:00
|
|
|
projectName = ""
|
|
|
|
|
2021-01-31 02:43:13 +13:00
|
|
|
/**
|
2021-02-23 11:30:18 +13:00
|
|
|
* Load all blueprints and build the tree out of them
|
2021-01-31 02:43:13 +13:00
|
|
|
*/
|
2021-02-23 11:30:18 +13:00
|
|
|
async created () {
|
2021-03-08 11:07:40 +13:00
|
|
|
this.projectName = await retrieveCurrentProjectName()
|
|
|
|
|
2021-02-23 11:30:18 +13:00
|
|
|
// Unfuck the rendering by giving the app some time to load first
|
2021-03-04 13:27:07 +13:00
|
|
|
await this.$nextTick()
|
2021-03-18 10:26:08 +13:00
|
|
|
}
|
|
|
|
|
|
|
|
tagsAtTop = false
|
|
|
|
compactTags = false
|
|
|
|
noTags = false
|
|
|
|
noProjectName = false
|
|
|
|
invertTreeSorting = false
|
|
|
|
doNotcollaseTreeOptions = false
|
|
|
|
disableDocumentControlBar = false
|
|
|
|
textShadow = false
|
2021-03-19 14:54:44 +13:00
|
|
|
disableDocumentCounts = false
|
|
|
|
compactDocumentCount = false
|
|
|
|
invertCategoryPosition = false
|
|
|
|
doubleDashDocCount = false
|
2021-04-10 12:22:31 +12:00
|
|
|
hideDeadCrossThrough = false
|
|
|
|
hideTreeOrderNumbers = false
|
2021-04-11 13:40:03 +12:00
|
|
|
hideTreeExtraIcons = false
|
|
|
|
hideTreeIconAddUnder = false
|
|
|
|
hideTreeIconEdit = false
|
|
|
|
hideTreeIconView = false
|
2021-03-18 10:26:08 +13:00
|
|
|
|
|
|
|
@Watch("SGET_options", { immediate: true, deep: true })
|
|
|
|
onSettingsChange () {
|
|
|
|
const options = this.SGET_options
|
|
|
|
this.tagsAtTop = options.tagsAtTop
|
|
|
|
this.compactTags = options.compactTags
|
|
|
|
this.noTags = options.noTags
|
|
|
|
this.noProjectName = options.noProjectName
|
|
|
|
this.invertTreeSorting = options.invertTreeSorting
|
|
|
|
this.doNotcollaseTreeOptions = options.doNotcollaseTreeOptions
|
|
|
|
this.disableDocumentControlBar = options.disableDocumentControlBar
|
|
|
|
this.textShadow = options.textShadow
|
2021-03-19 14:54:44 +13:00
|
|
|
this.disableDocumentCounts = options.disableDocumentCounts
|
|
|
|
this.compactDocumentCount = options.compactDocumentCount
|
|
|
|
this.invertCategoryPosition = options.invertCategoryPosition
|
|
|
|
this.doubleDashDocCount = options.doubleDashDocCount
|
2021-04-10 12:22:31 +12:00
|
|
|
this.hideDeadCrossThrough = options.hideDeadCrossThrough
|
|
|
|
this.hideTreeOrderNumbers = options.hideTreeOrderNumbers
|
2021-04-11 13:40:03 +12:00
|
|
|
this.hideTreeExtraIcons = options.hideTreeExtraIcons
|
|
|
|
this.hideTreeIconAddUnder = options.hideTreeIconAddUnder
|
|
|
|
this.hideTreeIconEdit = options.hideTreeIconEdit
|
|
|
|
this.hideTreeIconView = options.hideTreeIconView
|
2021-04-26 09:01:41 +12:00
|
|
|
this.buildCurrentObjectTree()
|
2021-01-31 02:43:13 +13:00
|
|
|
}
|
|
|
|
|
2021-02-23 11:30:18 +13:00
|
|
|
/****************************************************************/
|
|
|
|
// HIERARCHICAL TREE - HELPERS AND MODELS
|
|
|
|
/****************************************************************/
|
|
|
|
|
2021-03-08 11:07:40 +13:00
|
|
|
@Watch("$route", { deep: true })
|
|
|
|
async reactToRouteChange () {
|
|
|
|
// Wait for animations
|
|
|
|
await this.sleep(200)
|
|
|
|
if (this.SGET_allOpenedDocuments.docs.length > 0) {
|
|
|
|
const currentDoc = this.findRequestedOrActiveDocument() as unknown as I_OpenedDocument
|
|
|
|
this.selectedTreeNode = currentDoc._id
|
|
|
|
}
|
|
|
|
else {
|
2021-01-31 02:43:13 +13:00
|
|
|
this.selectedTreeNode = null
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-02-23 11:30:18 +13:00
|
|
|
/**
|
|
|
|
*
|
|
|
|
*/
|
2021-01-31 02:43:13 +13:00
|
|
|
@Watch("SGET_allOpenedDocuments", { deep: true })
|
2021-04-26 09:01:41 +12:00
|
|
|
reactToDocumentListChange (val: { treeAction: boolean, docs: I_OpenedDocument[]}) {
|
2021-02-28 06:00:57 +13:00
|
|
|
if (val.treeAction) {
|
2021-04-26 09:01:41 +12:00
|
|
|
this.buildCurrentObjectTree()
|
2021-02-28 06:00:57 +13:00
|
|
|
this.buildTreeExpands(val?.docs)
|
|
|
|
this.lastDocsSnapShot = extend(true, [], val.docs)
|
|
|
|
}
|
|
|
|
else if (val.docs.length !== this.lastDocsSnapShot.length) {
|
|
|
|
this.lastDocsSnapShot = extend(true, [], val.docs)
|
|
|
|
}
|
2021-01-31 02:43:13 +13:00
|
|
|
}
|
|
|
|
|
2021-02-28 06:00:57 +13:00
|
|
|
lastDocsSnapShot:I_OpenedDocument[] = []
|
|
|
|
|
2021-04-26 09:01:41 +12:00
|
|
|
/**
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
@Watch("SGET_allDocuments", { deep: true })
|
|
|
|
reactToAllDocumentListChange (val: { docs: I_OpenedDocument[]}) {
|
|
|
|
if (!this.SGET_allDocumentsFirstRunState) {
|
|
|
|
this.buildCurrentObjectTree()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
@Watch("SGET_allDocumentsFirstRunState")
|
|
|
|
reactToFirstRunFinish (val: boolean) {
|
|
|
|
if (!val) {
|
|
|
|
this.buildCurrentObjectTree()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-02-23 11:30:18 +13:00
|
|
|
/**
|
|
|
|
* Generic wrapper for adding of new object types to the tree
|
|
|
|
*/
|
|
|
|
menuAddNewItem = {
|
|
|
|
icon: "mdi-plus",
|
|
|
|
label: "Add new object type"
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Contains all the data for the render in tree
|
|
|
|
*/
|
|
|
|
hierarchicalTree: {children: I_ShortenedDocument[], icon: string, label: string}[] = []
|
|
|
|
|
|
|
|
/**
|
|
|
|
* A resetter for the currently selected node
|
|
|
|
*/
|
2021-03-08 11:07:40 +13:00
|
|
|
selectedTreeNode = null as null | string
|
2021-02-23 11:30:18 +13:00
|
|
|
|
2021-02-26 14:50:46 +13:00
|
|
|
/**
|
|
|
|
* Holds all currently expanded notes
|
|
|
|
*/
|
2021-03-18 10:26:08 +13:00
|
|
|
expandedTreeNodes: string[] = []
|
2021-02-26 14:50:46 +13:00
|
|
|
|
2021-02-23 11:30:18 +13:00
|
|
|
/**
|
|
|
|
* Filter model for the tree
|
|
|
|
*/
|
|
|
|
treeFilter = ""
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Resets the tree filter and refocuses the search box
|
|
|
|
*/
|
|
|
|
resetTreeFilter () {
|
|
|
|
this.treeFilter = ""
|
|
|
|
const treeFilterDOM = this.$refs.treeFilter as unknown as HTMLInputElement
|
2021-03-03 14:10:05 +13:00
|
|
|
|
|
|
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-call
|
2021-02-23 11:30:18 +13:00
|
|
|
treeFilterDOM.focus()
|
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************/
|
|
|
|
// HIERARCHICAL TREE - CONTENT CONSTRUCTION
|
|
|
|
/****************************************************************/
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Sort the whole tree via alphabetical and custom numeric order
|
|
|
|
* @param input Hierartchical tree object to sort
|
|
|
|
*/
|
2021-01-31 02:43:13 +13:00
|
|
|
sortDocuments (input: I_ShortenedDocument[]) {
|
|
|
|
input
|
2021-02-23 11:30:18 +13:00
|
|
|
|
|
|
|
// Sort by name
|
2021-01-31 02:43:13 +13:00
|
|
|
.sort((a, b) => a.label.localeCompare(b.label))
|
2021-02-23 11:30:18 +13:00
|
|
|
|
|
|
|
// Sort by custom order
|
2021-01-31 02:43:13 +13:00
|
|
|
.sort((a, b) => {
|
2021-03-18 10:26:08 +13:00
|
|
|
let order1 = 0
|
|
|
|
let order2 = 0
|
|
|
|
|
|
|
|
if (!this.invertTreeSorting) {
|
|
|
|
order1 = a.extraFields.find(e => e.id === "order")?.value
|
|
|
|
order2 = b.extraFields.find(e => e.id === "order")?.value
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
order2 = a.extraFields.find(e => e.id === "order")?.value
|
|
|
|
order1 = b.extraFields.find(e => e.id === "order")?.value
|
|
|
|
}
|
2021-01-31 02:43:13 +13:00
|
|
|
|
2021-02-23 11:30:18 +13:00
|
|
|
if (order1 > order2) {
|
|
|
|
return 1
|
|
|
|
}
|
|
|
|
if (order1 < order2) {
|
|
|
|
return -1
|
|
|
|
}
|
2021-01-31 02:43:13 +13:00
|
|
|
|
|
|
|
return 0
|
|
|
|
})
|
|
|
|
|
2021-02-28 06:00:57 +13:00
|
|
|
// Put the number value on top of the list and alphabetical below them
|
|
|
|
input = [
|
|
|
|
...input.filter(e => e.extraFields.find(e => e.id === "order")?.value),
|
|
|
|
...input.filter(e => !e.extraFields.find(e => e.id === "order")?.value)
|
|
|
|
]
|
|
|
|
|
2021-01-31 02:43:13 +13:00
|
|
|
input.forEach((e, i) => {
|
2021-02-23 11:30:18 +13:00
|
|
|
// Run recursive if the node has any children
|
|
|
|
if (e.children.length > 0) {
|
|
|
|
input[i].children = this.sortDocuments(input[i].children)
|
|
|
|
}
|
2021-01-31 02:43:13 +13:00
|
|
|
})
|
|
|
|
|
|
|
|
return input
|
|
|
|
}
|
|
|
|
|
2021-02-23 11:30:18 +13:00
|
|
|
/**
|
|
|
|
* Builds proper hiearachy for flat array of documents
|
|
|
|
* @param input Non-hierarchical tree to build the hiearachy out of
|
|
|
|
*/
|
2021-01-31 02:43:13 +13:00
|
|
|
buildTreeHierarchy (input: I_ShortenedDocument[]) {
|
|
|
|
const map: number[] = []
|
|
|
|
let node
|
|
|
|
const roots = []
|
|
|
|
let i
|
|
|
|
|
|
|
|
for (i = 0; i < input.length; i += 1) {
|
2021-02-23 11:30:18 +13:00
|
|
|
// Initialize the map
|
|
|
|
map[input[i]._id] = i
|
2021-01-31 02:43:13 +13:00
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < input.length; i += 1) {
|
|
|
|
node = input[i]
|
|
|
|
if (node.parentDoc !== false) {
|
2021-02-23 11:30:18 +13:00
|
|
|
// If there are any dangling branches check that map[node.parentDoc] exists
|
2021-01-31 02:43:13 +13:00
|
|
|
if (input[map[node.parentDoc]]) {
|
|
|
|
input[map[node.parentDoc]].children.push(node)
|
2021-02-23 11:30:18 +13:00
|
|
|
}
|
|
|
|
else {
|
2021-01-31 02:43:13 +13:00
|
|
|
roots.push(node)
|
|
|
|
}
|
2021-02-23 11:30:18 +13:00
|
|
|
}
|
|
|
|
else {
|
2021-01-31 02:43:13 +13:00
|
|
|
roots.push(node)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
const sortedRoots = this.sortDocuments(roots)
|
|
|
|
|
|
|
|
return sortedRoots
|
|
|
|
}
|
|
|
|
|
2021-02-23 11:30:18 +13:00
|
|
|
/**
|
|
|
|
* Builds a brand new sparkling hearchy tree out of available data
|
|
|
|
*/
|
2021-04-26 09:01:41 +12:00
|
|
|
buildCurrentObjectTree () {
|
2021-04-27 01:01:51 +12:00
|
|
|
this.hierarchicalTree = []
|
|
|
|
|
2021-01-31 02:43:13 +13:00
|
|
|
const allBlueprings = this.SGET_allBlueprints
|
2021-03-18 10:26:08 +13:00
|
|
|
let treeObject: any[] = []
|
2021-04-27 01:01:51 +12:00
|
|
|
|
2021-03-03 14:10:05 +13:00
|
|
|
let allTreeDocuments: I_ShortenedDocument[] = []
|
2021-01-31 02:43:13 +13:00
|
|
|
|
2021-02-23 11:30:18 +13:00
|
|
|
// Process all documents, build hieararchy out of the and sort them via name and custom order
|
2021-01-31 02:43:13 +13:00
|
|
|
for (const blueprint of allBlueprings) {
|
2021-04-26 09:01:41 +12:00
|
|
|
const allDocuments = this.SGET_allDocumentsByType(blueprint._id)
|
|
|
|
let allDocumentsRows: I_ShortenedDocument[] = []
|
|
|
|
|
|
|
|
if (allDocuments && allDocuments.docs) {
|
|
|
|
allDocumentsRows = allDocuments.docs
|
|
|
|
.map((doc) => {
|
|
|
|
const parentDocID = doc.extraFields.find(e => e.id === "parentDoc")?.value.value as unknown as {_id: string}
|
|
|
|
const color = doc.extraFields.find(e => e.id === "documentColor")?.value as unknown as string
|
|
|
|
const bgColor = doc.extraFields.find(e => e.id === "documentBackgroundColor")?.value as unknown as string
|
|
|
|
|
|
|
|
const isCategory = doc.extraFields.find(e => e.id === "categorySwitch")?.value as unknown as boolean
|
|
|
|
const isMinor = doc.extraFields.find(e => e.id === "minorSwitch")?.value as unknown as boolean
|
|
|
|
const isDead = doc.extraFields.find(e => e.id === "deadSwitch")?.value as unknown as boolean
|
|
|
|
|
|
|
|
return {
|
|
|
|
label: doc.extraFields.find(e => e.id === "name")?.value,
|
|
|
|
icon: (isCategory) ? "fas fa-folder-open" : doc.icon,
|
|
|
|
isCategory: !!(isCategory),
|
|
|
|
isMinor: isMinor,
|
|
|
|
isDead: isDead,
|
|
|
|
sticker: doc.extraFields.find(e => e.id === "order")?.value,
|
|
|
|
parentDoc: (parentDocID) ? parentDocID._id : false,
|
|
|
|
handler: this.openExistingDocumentRoute,
|
|
|
|
expandable: true,
|
|
|
|
color: color,
|
|
|
|
bgColor: bgColor,
|
|
|
|
type: doc.type,
|
|
|
|
children: [],
|
|
|
|
hasEdits: false,
|
|
|
|
isNew: false,
|
|
|
|
url: doc.url,
|
|
|
|
extraFields: (doc?.extraFields) || [],
|
|
|
|
_id: doc._id,
|
|
|
|
key: doc._id
|
|
|
|
} as I_ShortenedDocument
|
|
|
|
})
|
|
|
|
}
|
2021-03-05 12:51:41 +13:00
|
|
|
const documentCount = allDocumentsRows.filter(e => !e.isCategory).length
|
|
|
|
const categoryCount = allDocumentsRows.filter(e => e.isCategory).length
|
|
|
|
const allCount = allDocumentsRows.length
|
|
|
|
|
2021-04-06 01:28:33 +12:00
|
|
|
// @ts-ignore
|
|
|
|
allTreeDocuments = [...allTreeDocuments, ...extend(true, [], allDocumentsRows)]
|
2021-01-31 14:46:23 +13:00
|
|
|
|
2021-01-31 02:43:13 +13:00
|
|
|
const hierarchicalTreeContent = this.buildTreeHierarchy(allDocumentsRows)
|
|
|
|
|
|
|
|
const treeRow = {
|
|
|
|
label: blueprint.namePlural,
|
|
|
|
icon: blueprint.icon,
|
2021-01-31 14:46:23 +13:00
|
|
|
order: blueprint.order,
|
2021-01-31 02:43:13 +13:00
|
|
|
_id: blueprint._id,
|
2021-02-21 03:13:37 +13:00
|
|
|
key: blueprint._id,
|
2021-02-23 11:30:18 +13:00
|
|
|
handler: this.addNewObjectRoute,
|
2021-01-31 02:43:13 +13:00
|
|
|
specialLabel: blueprint.nameSingular.toLowerCase(),
|
2021-01-31 14:46:23 +13:00
|
|
|
isRoot: true,
|
2021-03-05 12:51:41 +13:00
|
|
|
allCount: allCount,
|
2021-01-31 14:46:23 +13:00
|
|
|
documentCount: documentCount,
|
2021-03-05 12:51:41 +13:00
|
|
|
categoryCount: categoryCount,
|
2021-01-31 02:43:13 +13:00
|
|
|
children: [
|
|
|
|
...hierarchicalTreeContent,
|
|
|
|
{
|
|
|
|
label: `Add new ${blueprint.nameSingular.toLowerCase()}`,
|
|
|
|
icon: "mdi-plus",
|
2021-02-23 11:30:18 +13:00
|
|
|
handler: this.addNewObjectRoute,
|
|
|
|
children: false,
|
|
|
|
key: `${blueprint._id}_add`,
|
|
|
|
_id: blueprint._id,
|
|
|
|
specialLabel: blueprint.nameSingular.toLowerCase()
|
|
|
|
|
2021-01-31 02:43:13 +13:00
|
|
|
}
|
|
|
|
]
|
|
|
|
}
|
|
|
|
|
|
|
|
treeObject.push(treeRow)
|
|
|
|
}
|
|
|
|
|
2021-02-23 11:30:18 +13:00
|
|
|
// Sort the top level of the blueprints
|
2021-01-31 14:46:23 +13:00
|
|
|
treeObject.sort((a, b) => {
|
|
|
|
if (a.order < b.order) {
|
|
|
|
return 1
|
|
|
|
}
|
|
|
|
|
|
|
|
if (a.order > b.order) {
|
|
|
|
return -1
|
|
|
|
}
|
|
|
|
return 0
|
|
|
|
})
|
|
|
|
|
2021-03-18 10:26:08 +13:00
|
|
|
if (!this.noTags) {
|
2021-04-26 09:01:41 +12:00
|
|
|
const tagList = tagListBuildFromBlueprints(this.SGET_allDocuments.docs)
|
2021-03-03 14:10:05 +13:00
|
|
|
|
2021-03-18 10:26:08 +13:00
|
|
|
let allTags = 0
|
|
|
|
let allTagsCategories = 0
|
|
|
|
let allTagsDocuments = 0
|
|
|
|
|
|
|
|
let tagNodeList = tagList.map((tag: string) => {
|
|
|
|
const tagDocs = allTreeDocuments
|
|
|
|
.filter(doc => {
|
|
|
|
const docTags = doc.extraFields.find(e => e.id === "tags")?.value as unknown as string[]
|
|
|
|
return (docTags && docTags.includes(tag))
|
|
|
|
})
|
|
|
|
.map((doc:I_ShortenedDocument) => {
|
2021-03-03 14:10:05 +13:00
|
|
|
// @ts-ignore
|
2021-03-18 10:26:08 +13:00
|
|
|
doc.key = `${tag}${doc._id}`
|
|
|
|
// @ts-ignore
|
|
|
|
// doc.isTag = true
|
|
|
|
return doc
|
|
|
|
})
|
|
|
|
.sort((a, b) => a.label.localeCompare(b.label))
|
|
|
|
|
|
|
|
const documentCount = tagDocs.filter(e => !e.isCategory).length
|
|
|
|
const categoryCount = tagDocs.filter(e => e.isCategory).length
|
|
|
|
const allCount = tagDocs.length
|
|
|
|
|
|
|
|
allTags += allCount
|
|
|
|
allTagsCategories += categoryCount
|
|
|
|
allTagsDocuments += documentCount
|
|
|
|
|
|
|
|
return {
|
|
|
|
label: `${tag}`,
|
|
|
|
icon: "mdi-tag",
|
|
|
|
_id: `tag-${tag}`,
|
|
|
|
key: `tag-${tag}`,
|
|
|
|
allCount: allCount,
|
|
|
|
documentCount: documentCount,
|
|
|
|
categoryCount: categoryCount,
|
|
|
|
isRoot: true,
|
|
|
|
isTag: true,
|
2021-04-06 02:46:58 +12:00
|
|
|
children: this.sortDocuments(tagDocs)
|
2021-03-18 10:26:08 +13:00
|
|
|
}
|
|
|
|
})
|
2021-03-03 14:10:05 +13:00
|
|
|
|
2021-03-18 10:26:08 +13:00
|
|
|
if (this.compactTags && tagNodeList.length > 0) {
|
|
|
|
tagNodeList = [
|
|
|
|
{
|
|
|
|
label: "Tags",
|
|
|
|
icon: "mdi-tag",
|
|
|
|
_id: "tagsList",
|
|
|
|
key: "tagList",
|
|
|
|
isRoot: true,
|
|
|
|
allCount: allTags,
|
|
|
|
documentCount: allTagsDocuments,
|
|
|
|
categoryCount: allTagsCategories,
|
|
|
|
isTag: true,
|
|
|
|
// @ts-ignore
|
|
|
|
children: tagNodeList.map(e => {
|
|
|
|
e.isRoot = false
|
|
|
|
return e
|
|
|
|
})
|
|
|
|
}
|
|
|
|
]
|
|
|
|
}
|
2021-03-05 12:51:41 +13:00
|
|
|
|
2021-03-18 10:26:08 +13:00
|
|
|
if (this.tagsAtTop) {
|
|
|
|
treeObject = [...tagNodeList, ...treeObject]
|
2021-03-03 14:10:05 +13:00
|
|
|
}
|
2021-03-18 10:26:08 +13:00
|
|
|
else {
|
|
|
|
treeObject = [...treeObject, ...tagNodeList]
|
|
|
|
}
|
|
|
|
}
|
2021-03-03 14:10:05 +13:00
|
|
|
|
2021-02-23 11:30:18 +13:00
|
|
|
// Assign the finished object to the render model
|
2021-04-27 01:01:51 +12:00
|
|
|
// treeObject.forEach(cat => this.recursivelyFreezeChildren(cat.children))
|
2021-04-26 09:01:41 +12:00
|
|
|
// @ts-ignore
|
2021-04-27 01:01:51 +12:00
|
|
|
this.hierarchicalTree = treeObject
|
2021-04-26 09:01:41 +12:00
|
|
|
}
|
|
|
|
|
|
|
|
recursivelyFreezeChildren (children: {children: []}) {
|
|
|
|
Object.freeze(children)
|
|
|
|
if (children.children) {
|
|
|
|
// @ts-ignore
|
|
|
|
this.recursivelyFreezeChildren(children.children)
|
|
|
|
}
|
2021-01-31 02:43:13 +13:00
|
|
|
}
|
|
|
|
|
2021-02-23 11:30:18 +13:00
|
|
|
processNodeNewDocumentButton (node: {
|
|
|
|
key: string
|
|
|
|
_id: string
|
|
|
|
children: []
|
|
|
|
type: string
|
|
|
|
isRoot: boolean
|
|
|
|
specialLabel: string|boolean
|
|
|
|
}) {
|
|
|
|
// If this is top level blueprint
|
|
|
|
if (node.isRoot) {
|
|
|
|
// @ts-ignore
|
|
|
|
this.addNewObjectRoute(node)
|
|
|
|
}
|
|
|
|
// If this is a custom document
|
|
|
|
else {
|
|
|
|
const routeObject = {
|
|
|
|
_id: node.type,
|
|
|
|
parent: node._id
|
|
|
|
}
|
|
|
|
// @ts-ignore
|
|
|
|
this.addNewObjectRoute(routeObject)
|
|
|
|
}
|
|
|
|
}
|
2021-01-31 02:43:13 +13:00
|
|
|
|
2021-02-28 06:00:57 +13:00
|
|
|
buildTreeExpands (newDocs: I_OpenedDocument[]) {
|
|
|
|
const expandIDs: string[] = []
|
|
|
|
|
2021-04-06 01:28:33 +12:00
|
|
|
let newDocsSnapshot: I_OpenedDocument[] = extend(true, [], newDocs)
|
2021-03-18 10:26:08 +13:00
|
|
|
|
2021-02-28 06:00:57 +13:00
|
|
|
// Check for parent changes
|
2021-03-18 10:26:08 +13:00
|
|
|
newDocsSnapshot.forEach((s, index) => {
|
2021-02-28 06:00:57 +13:00
|
|
|
const oldParentDoc = this.lastDocsSnapShot.find(doc => doc._id === s._id)
|
|
|
|
// Fizzle if the parent doesn't exist in the old version
|
|
|
|
if (!oldParentDoc) {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
const oldParentDocField = this.retrieveFieldValue(oldParentDoc, "parentDoc")
|
|
|
|
// @ts-ignore
|
|
|
|
const oldParentDocID = (oldParentDocField?.value) ? oldParentDocField.value.value : ""
|
|
|
|
|
|
|
|
const newParentDocField = this.retrieveFieldValue(s, "parentDoc")
|
|
|
|
|
|
|
|
// @ts-ignore
|
|
|
|
const newParentDocID = (newParentDocField?.value) ? newParentDocField.value.value : ""
|
|
|
|
if ((newParentDocID !== oldParentDocID) || (newParentDocID && oldParentDoc.isNew)) {
|
|
|
|
expandIDs.push(newParentDocID)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
|
|
|
|
// Process top level documents
|
2021-03-18 10:26:08 +13:00
|
|
|
newDocsSnapshot.forEach(s => {
|
2021-02-28 06:00:57 +13:00
|
|
|
const newParentDocField = this.retrieveFieldValue(s, "parentDoc")
|
2021-03-18 10:26:08 +13:00
|
|
|
const oldParentDoc = this.lastDocsSnapShot.find(doc => doc._id === s._id)
|
|
|
|
// @ts-ignore
|
|
|
|
const oldParentDocField = this.retrieveFieldValue(oldParentDoc, "parentDoc")
|
|
|
|
|
|
|
|
// @ts-ignore
|
|
|
|
const oldParentDocID = (oldParentDocField?.value) ? oldParentDocField.value.value : false
|
2021-02-28 06:00:57 +13:00
|
|
|
|
|
|
|
// @ts-ignore
|
|
|
|
const newParentDocID = (newParentDocField?.value) ? newParentDocField.value.value : false
|
|
|
|
|
2021-03-18 10:26:08 +13:00
|
|
|
if (!newParentDocID && oldParentDocID !== newParentDocID) {
|
2021-02-28 06:00:57 +13:00
|
|
|
expandIDs.push(s.type)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
|
2021-04-06 01:28:33 +12:00
|
|
|
// @ts-ignore
|
|
|
|
newDocsSnapshot = null
|
|
|
|
|
2021-03-03 08:59:56 +13:00
|
|
|
expandIDs.forEach(s => {
|
2021-04-10 12:22:31 +12:00
|
|
|
this.recursivelyExpandNodeUpwards(s)
|
2021-02-28 06:00:57 +13:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2021-04-10 12:22:31 +12:00
|
|
|
recursivelyExpandNodeUpwards (nodeID: string) {
|
2021-02-28 06:00:57 +13:00
|
|
|
const treeDOM = this.$refs.tree as unknown as {
|
|
|
|
setExpanded: (key:string, state: boolean)=> void
|
|
|
|
getNodeByKey: (key:string)=> void
|
|
|
|
}
|
|
|
|
|
|
|
|
// @ts-ignore
|
|
|
|
this.expandedTreeNodes = [...new Set([
|
|
|
|
...this.expandedTreeNodes,
|
|
|
|
nodeID
|
|
|
|
])]
|
|
|
|
|
|
|
|
const currentTreeNode = (treeDOM.getNodeByKey(nodeID)) as unknown as {parentDoc: string, type: string}
|
|
|
|
|
|
|
|
// Dig into the upper hierarchy
|
|
|
|
if (currentTreeNode?.parentDoc) {
|
2021-04-10 12:22:31 +12:00
|
|
|
this.recursivelyExpandNodeUpwards(currentTreeNode.parentDoc)
|
|
|
|
}
|
|
|
|
// If we are at the top of the tree, expand the top category
|
|
|
|
else if (currentTreeNode?.type) {
|
|
|
|
// @ts-ignore
|
|
|
|
this.expandedTreeNodes = [...new Set([
|
|
|
|
...this.expandedTreeNodes,
|
|
|
|
currentTreeNode.type
|
|
|
|
])]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
recursivelyExpandNodeDownwards (nodeID: string) {
|
|
|
|
const treeDOM = this.$refs.tree as unknown as {
|
|
|
|
setExpanded: (key:string, state: boolean)=> void
|
|
|
|
getNodeByKey: (key:string)=> void
|
|
|
|
}
|
|
|
|
|
|
|
|
// @ts-ignore
|
|
|
|
this.expandedTreeNodes = [...new Set([
|
|
|
|
...this.expandedTreeNodes,
|
|
|
|
nodeID
|
|
|
|
])]
|
|
|
|
|
|
|
|
const currentTreeNode = (treeDOM.getNodeByKey(nodeID)) as unknown as {children: any[], type: string}
|
|
|
|
|
|
|
|
// Dig into the upper hierarchy
|
|
|
|
if (currentTreeNode?.children && currentTreeNode?.children.length > 0) {
|
|
|
|
for (const child of currentTreeNode.children) {
|
|
|
|
this.recursivelyExpandNodeDownwards(child.key)
|
|
|
|
}
|
2021-02-28 06:00:57 +13:00
|
|
|
}
|
|
|
|
// If we are at the top of the tree, expand the top category
|
|
|
|
else if (currentTreeNode?.type) {
|
|
|
|
// @ts-ignore
|
|
|
|
this.expandedTreeNodes = [...new Set([
|
|
|
|
...this.expandedTreeNodes,
|
|
|
|
currentTreeNode.type
|
|
|
|
])]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-02-23 11:30:18 +13:00
|
|
|
processNodeLabelMiddleClick (node: {
|
|
|
|
key: string
|
|
|
|
_id: string
|
|
|
|
children: []
|
|
|
|
type: string
|
|
|
|
isRoot: boolean
|
2021-03-03 14:10:05 +13:00
|
|
|
isTag: boolean
|
2021-02-23 11:30:18 +13:00
|
|
|
specialLabel: string|boolean
|
|
|
|
}) {
|
2021-03-03 14:10:05 +13:00
|
|
|
if (node.isRoot && node.isTag) {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2021-02-23 11:30:18 +13:00
|
|
|
if (!node.specialLabel && !node.isRoot) {
|
|
|
|
// @ts-ignore
|
|
|
|
this.openExistingDocumentRoute(node)
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
this.addNewObjectRoute(node)
|
|
|
|
}
|
2021-01-31 02:43:13 +13:00
|
|
|
}
|
|
|
|
|
2021-02-23 11:30:18 +13:00
|
|
|
processNodeClick (node: {
|
|
|
|
key: string
|
|
|
|
children: []
|
|
|
|
specialLabel: string|boolean
|
|
|
|
}) {
|
|
|
|
// If this is a category or has children
|
|
|
|
if (node.children.length > 0) {
|
|
|
|
this.expandeCollapseNode(node)
|
|
|
|
}
|
|
|
|
// If this lacks a "special label" - AKA anything that isn't the "Add new XY" node
|
|
|
|
else if (!node.specialLabel) {
|
|
|
|
// @ts-ignore
|
|
|
|
this.openExistingDocumentRoute(node)
|
|
|
|
}
|
|
|
|
// If this lacks a "special label" - AKA if this is the "Add new XY" node
|
|
|
|
else {
|
|
|
|
// @ts-ignore
|
|
|
|
this.addNewObjectRoute(node)
|
|
|
|
}
|
|
|
|
}
|
2021-01-31 02:43:13 +13:00
|
|
|
|
2021-03-18 10:26:08 +13:00
|
|
|
expandeCollapseNode (node: {key: string, children: []}) {
|
2021-02-23 11:30:18 +13:00
|
|
|
const treeDOM = this.$refs.tree as unknown as {
|
|
|
|
setExpanded: (key:string, state: boolean)=> void,
|
|
|
|
isExpanded: (key:string)=> boolean
|
|
|
|
}
|
2021-01-31 02:43:13 +13:00
|
|
|
|
2021-02-23 11:30:18 +13:00
|
|
|
const isExpanded = treeDOM.isExpanded(node.key)
|
2021-03-18 10:26:08 +13:00
|
|
|
|
|
|
|
if (isExpanded) {
|
|
|
|
this.collapseAllNodes(node)
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
treeDOM.setExpanded(node.key, true)
|
|
|
|
}
|
2021-01-31 02:43:13 +13:00
|
|
|
}
|
2021-03-03 14:10:05 +13:00
|
|
|
|
|
|
|
determineNodeColor (node: {color: string, isTag: boolean, isRoot: boolean}) {
|
|
|
|
// @ts-ignore
|
2021-03-18 10:26:08 +13:00
|
|
|
return (node?.isTag) ? colors.getBrand("primary") : node.color
|
|
|
|
}
|
|
|
|
|
|
|
|
collapseAllNodes (node: {key: string, children: []}) {
|
|
|
|
if (node.children && !this.doNotcollaseTreeOptions) {
|
|
|
|
for (const child of node.children) {
|
|
|
|
if (this.expandedTreeNodes.includes(node.key)) {
|
|
|
|
this.collapseAllNodes(child)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (this.expandedTreeNodes.includes(node.key)) {
|
|
|
|
this.expandedTreeNodes = this.expandedTreeNodes.filter(n => n !== node.key)
|
|
|
|
}
|
2021-03-03 14:10:05 +13:00
|
|
|
}
|
2021-03-19 14:54:44 +13:00
|
|
|
|
2021-04-10 12:22:31 +12:00
|
|
|
collapseAllNodesForce (node: {key: string, children: []}) {
|
|
|
|
if (node.children) {
|
|
|
|
for (const child of node.children) {
|
|
|
|
if (this.expandedTreeNodes.includes(node.key)) {
|
|
|
|
this.collapseAllNodesForce(child)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (this.expandedTreeNodes.includes(node.key)) {
|
|
|
|
this.expandedTreeNodes = this.expandedTreeNodes.filter(n => n !== node.key)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-04-26 09:01:41 +12:00
|
|
|
determineCategoryString (node: {
|
2021-03-19 14:54:44 +13:00
|
|
|
documentCount: string
|
|
|
|
categoryCount: string
|
|
|
|
}) {
|
|
|
|
let extraDivider = ""
|
|
|
|
if (this.doubleDashDocCount) {
|
|
|
|
extraDivider = "|"
|
|
|
|
}
|
|
|
|
|
|
|
|
if (this.compactDocumentCount) {
|
|
|
|
return `(<span class="docCount">${node.documentCount}</span>)`
|
|
|
|
}
|
|
|
|
if (this.invertCategoryPosition) {
|
|
|
|
return `(<span class="catCount">${node.categoryCount}</span> |${extraDivider} <span class="docCount">${node.documentCount}</span>)`
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
return `(<span class="docCount">${node.documentCount}</span> |${extraDivider} <span class="catCount">${node.categoryCount}</span>)`
|
|
|
|
}
|
|
|
|
}
|
2021-04-10 12:22:31 +12:00
|
|
|
|
|
|
|
/****************************************************************/
|
|
|
|
// Document field copying
|
|
|
|
/****************************************************************/
|
|
|
|
|
|
|
|
copyName (currentDoc: I_OpenedDocument) {
|
|
|
|
copyDocumentName(currentDoc)
|
|
|
|
}
|
|
|
|
|
|
|
|
copyTextColor (currentDoc: I_OpenedDocument) {
|
|
|
|
copyDocumentTextColor(currentDoc)
|
|
|
|
}
|
|
|
|
|
|
|
|
copyBackgroundColor (currentDoc: I_OpenedDocument) {
|
|
|
|
copyDocumentBackgroundColor(currentDoc)
|
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************/
|
|
|
|
// Document copy
|
|
|
|
/****************************************************************/
|
|
|
|
|
|
|
|
documentPass = null as unknown as I_OpenedDocument
|
|
|
|
|
|
|
|
copyTargetDocument (currentDoc: I_OpenedDocument) {
|
|
|
|
this.documentPass = extend(true, {}, currentDoc)
|
|
|
|
|
|
|
|
const newDocument = copyDocument(this.documentPass, this.generateUID())
|
|
|
|
|
|
|
|
const dataPass = {
|
|
|
|
doc: newDocument,
|
|
|
|
treeAction: false
|
|
|
|
}
|
|
|
|
|
|
|
|
// @ts-ignore
|
|
|
|
this.SSET_addOpenedDocument(dataPass)
|
|
|
|
this.$router.push({
|
|
|
|
path: newDocument.url
|
|
|
|
}).catch((e: {name: string}) => {
|
|
|
|
const errorName : string = e.name
|
|
|
|
if (errorName === "NavigationDuplicated") {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
console.log(e)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************/
|
|
|
|
// Add new document under parent
|
|
|
|
/****************************************************************/
|
|
|
|
addNewUnderParent (currentDoc: I_OpenedDocument) {
|
|
|
|
createNewWithParent(currentDoc, this)
|
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************/
|
|
|
|
// Delete dialog
|
|
|
|
/****************************************************************/
|
|
|
|
|
|
|
|
deleteObjectDialogTrigger: string | false = false
|
|
|
|
deleteObjectDialogClose () {
|
|
|
|
this.deleteObjectDialogTrigger = false
|
|
|
|
}
|
|
|
|
|
|
|
|
deleteObjectAssignUID () {
|
|
|
|
this.deleteObjectDialogTrigger = this.generateUID()
|
|
|
|
}
|
|
|
|
|
|
|
|
toDeleteID = ""
|
|
|
|
toDeleteType = ""
|
|
|
|
|
|
|
|
deleteTabDocument (targetDocument: I_OpenedDocument) {
|
|
|
|
this.toDeleteID = targetDocument._id
|
|
|
|
this.toDeleteType = targetDocument.type
|
|
|
|
this.deleteObjectAssignUID()
|
|
|
|
}
|
2021-01-31 02:43:13 +13:00
|
|
|
}
|
|
|
|
</script>
|
2021-02-09 15:21:48 +13:00
|
|
|
|
|
|
|
<style lang="scss">
|
2021-03-05 12:51:41 +13:00
|
|
|
|
2021-03-08 11:07:40 +13:00
|
|
|
.projectTitle {
|
|
|
|
margin: 0 0 -5px 0;
|
2021-03-18 10:26:08 +13:00
|
|
|
padding: 10px 10px 0;
|
2021-03-08 11:07:40 +13:00
|
|
|
}
|
|
|
|
|
2021-02-09 15:21:48 +13:00
|
|
|
.objectTree {
|
2021-03-18 10:26:08 +13:00
|
|
|
&.hasTextShadow {
|
|
|
|
.documentLabel {
|
|
|
|
font-weight: 500;
|
|
|
|
$shadowColorOutline: #000;
|
|
|
|
$shadowColorSurround: #000;
|
|
|
|
|
|
|
|
filter: drop-shadow(0 0 4px #000);
|
|
|
|
text-shadow:
|
|
|
|
-2px -2px 0 $shadowColorSurround,
|
|
|
|
2px -2px 0 $shadowColorSurround,
|
|
|
|
-2px 2px 0 $shadowColorSurround,
|
|
|
|
2px 2px 0 $shadowColorSurround,
|
|
|
|
-1px -1px 0 $shadowColorOutline,
|
|
|
|
1px -1px 0 $shadowColorOutline,
|
|
|
|
-1px 1px 0 $shadowColorOutline,
|
|
|
|
1px 1px 0 $shadowColorOutline;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-03-19 14:54:44 +13:00
|
|
|
.catCount {
|
|
|
|
color: var(--q-color-accent);
|
|
|
|
}
|
|
|
|
|
|
|
|
.docCount {
|
|
|
|
color: var(--q-color-primary);
|
|
|
|
}
|
|
|
|
|
2021-03-08 11:07:40 +13:00
|
|
|
> .q-tree__node {
|
|
|
|
padding-left: 0 !important;
|
|
|
|
}
|
|
|
|
|
|
|
|
.q-tree__children {
|
|
|
|
padding-left: 5px;
|
|
|
|
}
|
2021-03-05 12:51:41 +13:00
|
|
|
|
2021-02-09 15:21:48 +13:00
|
|
|
.q-tree__arrow {
|
2021-02-23 11:30:18 +13:00
|
|
|
margin-right: 0;
|
2021-02-26 14:50:46 +13:00
|
|
|
padding: 4px 4px 4px 0;
|
2021-03-08 11:07:40 +13:00
|
|
|
position: absolute;
|
|
|
|
pointer-events: none;
|
2021-02-23 11:30:18 +13:00
|
|
|
}
|
|
|
|
|
2021-03-05 12:51:41 +13:00
|
|
|
.q-tree__node {
|
|
|
|
padding: 0 0 0 22px;
|
|
|
|
}
|
|
|
|
|
2021-02-23 11:30:18 +13:00
|
|
|
.q-tree__node-header {
|
|
|
|
padding: 0;
|
2021-03-08 11:07:40 +13:00
|
|
|
|
|
|
|
&:focus {
|
|
|
|
> .q-focus-helper {
|
|
|
|
opacity: 0 !important;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
&:hover {
|
|
|
|
> .q-focus-helper {
|
|
|
|
opacity: 0.15 !important;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
&.q-tree__node--selected {
|
|
|
|
> .q-focus-helper {
|
|
|
|
opacity: 0.22 !important;
|
|
|
|
}
|
|
|
|
}
|
2021-02-09 15:21:48 +13:00
|
|
|
}
|
|
|
|
|
2021-04-06 12:15:17 +12:00
|
|
|
.documentWrapper {
|
|
|
|
border-radius: 3px;
|
|
|
|
|
|
|
|
&.isMinor {
|
|
|
|
filter: grayscale(100) brightness(0.7);
|
|
|
|
}
|
2021-04-07 02:01:37 +12:00
|
|
|
|
|
|
|
&.isDeadTree {
|
|
|
|
.documentLabel__content {
|
|
|
|
text-decoration: line-through;
|
|
|
|
text-decoration-color: #fff;
|
|
|
|
}
|
|
|
|
|
|
|
|
.documentLabel__isDeadMarker {
|
|
|
|
margin-right: 5px;
|
|
|
|
font-weight: 600;
|
|
|
|
}
|
|
|
|
}
|
2021-04-06 12:15:17 +12:00
|
|
|
}
|
|
|
|
|
2021-02-09 15:21:48 +13:00
|
|
|
.documentLabel {
|
2021-02-23 11:30:18 +13:00
|
|
|
width: 100%;
|
|
|
|
display: flex;
|
|
|
|
justify-content: space-between;
|
2021-03-08 11:07:40 +13:00
|
|
|
padding: 4px 4px 4px 25px;
|
|
|
|
align-items: center;
|
2021-02-23 11:30:18 +13:00
|
|
|
}
|
|
|
|
|
|
|
|
.treeButtonGroup {
|
|
|
|
flex-grow: 0;
|
|
|
|
flex-shrink: 0;
|
|
|
|
display: flex;
|
|
|
|
height: fit-content;
|
|
|
|
margin-left: auto;
|
|
|
|
align-self: center;
|
2021-02-09 15:21:48 +13:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-02-26 14:50:46 +13:00
|
|
|
.treeBadge {
|
|
|
|
left: inherit;
|
|
|
|
right: calc(100% + 3px);
|
|
|
|
padding: 3px 2px;
|
|
|
|
border: none;
|
|
|
|
background: rgba($primary, 0.15);
|
|
|
|
top: 50%;
|
|
|
|
transform: translateY(-50%);
|
|
|
|
min-width: 24px;
|
|
|
|
justify-content: center;
|
2021-03-03 08:59:56 +13:00
|
|
|
|
|
|
|
&.noChilden {
|
2021-03-08 11:07:40 +13:00
|
|
|
right: calc(100% + 3px);
|
2021-03-03 08:59:56 +13:00
|
|
|
}
|
2021-02-26 14:50:46 +13:00
|
|
|
}
|
2021-02-23 11:30:18 +13:00
|
|
|
|
2021-03-05 12:51:41 +13:00
|
|
|
.treeSearchWrapper {
|
2021-03-18 10:26:08 +13:00
|
|
|
top: -55px;
|
|
|
|
left: 0;
|
|
|
|
position: fixed;
|
2021-03-05 12:51:41 +13:00
|
|
|
width: 375px;
|
|
|
|
z-index: 555;
|
|
|
|
background-color: $dark;
|
|
|
|
|
2021-03-18 10:26:08 +13:00
|
|
|
&.fullWidth {
|
|
|
|
width: 100%;
|
|
|
|
}
|
|
|
|
|
2021-03-05 12:51:41 +13:00
|
|
|
> div {
|
|
|
|
width: 100%;
|
|
|
|
}
|
|
|
|
|
|
|
|
label {
|
|
|
|
background-color: $dark;
|
|
|
|
|
|
|
|
&.q-field--focused {
|
|
|
|
width: 100vw;
|
|
|
|
max-width: inherit;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-02-26 14:50:46 +13:00
|
|
|
.treeButton {
|
2021-02-23 11:30:18 +13:00
|
|
|
&--add {
|
|
|
|
.q-icon {
|
|
|
|
font-size: 20px;
|
2021-02-26 14:50:46 +13:00
|
|
|
color: $primary;
|
2021-02-23 11:30:18 +13:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
&--edit {
|
|
|
|
.q-icon {
|
|
|
|
font-size: 14px;
|
2021-02-26 14:50:46 +13:00
|
|
|
color: #fff;
|
2021-02-23 11:30:18 +13:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2021-03-18 10:26:08 +13:00
|
|
|
|
|
|
|
body.body--dark {
|
|
|
|
.objectTree {
|
|
|
|
.documentLabel {
|
|
|
|
color: #dcdcdc;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
.projectTitle {
|
|
|
|
color: #dcdcdc;
|
|
|
|
}
|
|
|
|
}
|
2021-02-09 15:21:48 +13:00
|
|
|
</style>
|