mirror of https://github.com/Requarks/wiki.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
374 lines
9.5 KiB
374 lines
9.5 KiB
<template lang="pug">
|
|
div
|
|
.pa-3.d-flex(:class='$vuetify.theme.dark ? `grey darken-5` : `blue darken-3`')
|
|
v-btn.ml-2(
|
|
depressed
|
|
:color='$vuetify.theme.dark ? `grey darken-4` : `blue darken-2`'
|
|
style='min-width:0;'
|
|
@click='goHome'
|
|
:aria-label='$t(`common:header.home`)'
|
|
)
|
|
v-icon(size='20') mdi-home
|
|
v-btn.ml-3(
|
|
depressed
|
|
:color='$vuetify.theme.dark ? `grey darken-4` : `blue darken-2`'
|
|
style='min-width:0;'
|
|
@click='goStudentProfile'
|
|
:aria-label='$t(`common:header.home`)'
|
|
)
|
|
v-icon(size='20') mdi-account-box
|
|
v-btn.ml-2(
|
|
depressed
|
|
:color='$vuetify.theme.dark ? `grey darken-4` : `blue darken-2`'
|
|
style='flex: 1 1 100%;'
|
|
@click='goPlan'
|
|
:aria-label='$t(`common:header.home`)'
|
|
)
|
|
v-icon(size='20') mdi-book-education
|
|
v-divider
|
|
|
|
//-> Tree Navigation
|
|
v-treeview(
|
|
activatable
|
|
dense
|
|
open-on-click
|
|
:color='"white"'
|
|
:active='treeDefaultActive'
|
|
:open='treeDefaultOpen'
|
|
:items='treeItems'
|
|
:load-children='fetchTreeChild'
|
|
@update:active='activeTreeItem'
|
|
)
|
|
template(v-slot:prepend="{ item, open }")
|
|
v-icon(v-if="open") mdi-folder-open
|
|
v-icon(v-else) mdi-{{ item.icon }}
|
|
template(v-slot:label="{ item }")
|
|
div(class='tree-item')
|
|
a(v-if="!item.children" :href="'/'+item.locale+'/'+item.path")
|
|
span {{item.name}}
|
|
span(v-else) {{item.name}}
|
|
</template>
|
|
|
|
<script>
|
|
import _ from 'lodash'
|
|
import gql from 'graphql-tag'
|
|
import { get } from 'vuex-pathify'
|
|
|
|
/* global siteLangs */
|
|
|
|
export default {
|
|
props: {
|
|
color: {
|
|
type: String,
|
|
default: 'primary'
|
|
},
|
|
dark: {
|
|
type: Boolean,
|
|
default: true
|
|
},
|
|
items: {
|
|
type: Array,
|
|
default: () => []
|
|
},
|
|
navMode: {
|
|
type: String,
|
|
default: 'MIXED'
|
|
}
|
|
},
|
|
data() {
|
|
return {
|
|
currentItems: [],
|
|
currentParent: {
|
|
id: 0,
|
|
title: '/ (root)'
|
|
},
|
|
parents: [],
|
|
loadedCache: [],
|
|
treeItems: [],
|
|
treeDefaultOpen: [],
|
|
treeDefaultActive: []
|
|
}
|
|
},
|
|
computed: {
|
|
path: get('page/path'),
|
|
locale: get('page/locale')
|
|
},
|
|
methods: {
|
|
async fetchBrowseItems (item) {
|
|
this.$store.commit(`loadingStart`, 'browse-load')
|
|
if (!item) {
|
|
item = this.currentParent
|
|
}
|
|
|
|
if (this.loadedCache.indexOf(item.id) < 0) {
|
|
this.currentItems = []
|
|
}
|
|
|
|
if (item.id === 0) {
|
|
this.parents = []
|
|
} else {
|
|
const flushRightIndex = _.findIndex(this.parents, ['id', item.id])
|
|
if (flushRightIndex >= 0) {
|
|
this.parents = _.take(this.parents, flushRightIndex)
|
|
}
|
|
if (this.parents.length < 1) {
|
|
this.parents.push(this.currentParent)
|
|
}
|
|
this.parents.push(item)
|
|
}
|
|
|
|
this.currentParent = item
|
|
|
|
const resp = await this.$apollo.query({
|
|
query: gql`
|
|
query ($parent: Int, $locale: String!) {
|
|
pages {
|
|
tree(parent: $parent, mode: ALL, locale: $locale) {
|
|
id
|
|
path
|
|
title
|
|
isFolder
|
|
pageId
|
|
parent
|
|
locale
|
|
}
|
|
}
|
|
}
|
|
`,
|
|
fetchPolicy: 'cache-first',
|
|
variables: {
|
|
parent: item.id,
|
|
locale: this.locale
|
|
}
|
|
})
|
|
this.loadedCache = _.union(this.loadedCache, [item.id])
|
|
this.currentItems = _.get(resp, 'data.pages.tree', [])
|
|
this.$store.commit(`loadingStop`, 'browse-load')
|
|
},
|
|
async loadFromCurrentPath() {
|
|
this.$store.commit(`loadingStart`, 'browse-load')
|
|
const resp = await this.$apollo.query({
|
|
query: gql`
|
|
query ($path: String, $locale: String!) {
|
|
pages {
|
|
tree(path: $path, mode: ALL, locale: $locale, includeAncestors: true) {
|
|
id
|
|
path
|
|
title
|
|
isFolder
|
|
pageId
|
|
parent
|
|
locale
|
|
}
|
|
}
|
|
}
|
|
`,
|
|
fetchPolicy: 'cache-first',
|
|
variables: {
|
|
path: this.path,
|
|
locale: this.locale
|
|
}
|
|
})
|
|
const items = _.get(resp, 'data.pages.tree', [])
|
|
const curPage = _.find(items, ['pageId', this.$store.get('page/id')])
|
|
if (!curPage) {
|
|
console.warn('Could not find current page in page tree listing!')
|
|
return
|
|
}
|
|
|
|
let curParentId = curPage.parent
|
|
let invertedAncestors = []
|
|
while (curParentId) {
|
|
const curParent = _.find(items, ['id', curParentId])
|
|
if (!curParent) {
|
|
break
|
|
}
|
|
invertedAncestors.push(curParent)
|
|
curParentId = curParent.parent
|
|
}
|
|
|
|
this.parents = [this.currentParent, ...invertedAncestors.reverse()]
|
|
this.currentParent = _.last(this.parents)
|
|
|
|
this.loadedCache = [curPage.parent]
|
|
this.currentItems = _.filter(items, ['parent', curPage.parent])
|
|
this.$store.commit(`loadingStop`, 'browse-load')
|
|
if (curPage.isFolder) {
|
|
await this.fetchBrowseItems(curPage)
|
|
}
|
|
},
|
|
goHome (event) {
|
|
const url = siteLangs.length > 0 ? `/${this.locale}/home` : '/'
|
|
|
|
if (event.ctrlKey || event.metaKey) {
|
|
// Если зажат Ctrl или Cmd (на Mac), открываем в новом окне
|
|
window.open(url, '_blank')
|
|
} else {
|
|
// Иначе открываем в текущем окне
|
|
window.location.assign(url)
|
|
}
|
|
},
|
|
goStudentProfile (event) {
|
|
const url = '/Users/profile'
|
|
|
|
if (event.ctrlKey || event.metaKey) {
|
|
window.open(url, '_blank')
|
|
} else {
|
|
window.location.assign(url)
|
|
}
|
|
},
|
|
goPlan (event) {
|
|
const url = '/plan'
|
|
|
|
if (event.ctrlKey || event.metaKey) {
|
|
window.open(url, '_blank')
|
|
} else {
|
|
window.location.assign(url)
|
|
}
|
|
},
|
|
pageItem2TreeItem(item, level) {
|
|
if (item.isFolder) {
|
|
return { id: item.id, icon: item.icon, level: level, pageId: item.pageId, path: item.path, locale: item.locale, name: item.title, children: [] }
|
|
} else {
|
|
return { id: item.id, icon: item.icon, level: level, path: item.path, locale: item.locale, name: item.title }
|
|
}
|
|
},
|
|
activeTreeItem([id]) {
|
|
const find = (items) => {
|
|
for (const item of items) {
|
|
if (item.id === id) {
|
|
return item
|
|
}
|
|
if (item.children && item.children.length) {
|
|
const v = find(item.children)
|
|
if (v) {
|
|
return v
|
|
}
|
|
}
|
|
}
|
|
}
|
|
const item = find(this.treeItems)
|
|
if (item) {
|
|
if (!this.treeDefaultActive.includes(item.id)) {
|
|
location.href = `/${item.locale}/${item.path}`
|
|
} else {
|
|
setTimeout(() => {
|
|
const el = document.querySelector('.v-treeview-node--active')
|
|
el.scrollIntoViewIfNeeded()
|
|
})
|
|
}
|
|
}
|
|
},
|
|
async fetchTreeChild(parent) {
|
|
const items = await this.fetchPages(parent.id)
|
|
parent.children = []
|
|
if (parent.pageId) {
|
|
parent.children.push({
|
|
id: parent.pageId,
|
|
level: parent.level + 1,
|
|
icon: parent.icon,
|
|
path: parent.path,
|
|
locale: parent.locale,
|
|
name: parent.name
|
|
})
|
|
}
|
|
parent.children.push(
|
|
...items.map(item => this.pageItem2TreeItem(item, parent.level + 1))
|
|
)
|
|
this.checkTreeDefaultOpen(parent.children)
|
|
},
|
|
async fetchTreeRoot() {
|
|
const children = await this.fetchPages(0)
|
|
this.treeItems = children.map(item => this.pageItem2TreeItem(item, 0))
|
|
this.checkTreeDefaultOpen(this.treeItems, 0)
|
|
},
|
|
checkTreeDefaultOpen(items) {
|
|
const autoOpenBlacklist = 'Users'
|
|
|
|
const item = items.find(item => {
|
|
if (item.path.startsWith(autoOpenBlacklist)) {
|
|
return false
|
|
}
|
|
|
|
return item.children && this.path.startsWith(item.path)
|
|
})
|
|
if (item) {
|
|
setTimeout(() => {
|
|
this.treeDefaultOpen.push(item.id)
|
|
})
|
|
}
|
|
const active = items.find(item => item.path === this.path)
|
|
if (active) {
|
|
this.treeDefaultActive.push(active.id)
|
|
}
|
|
},
|
|
async fetchPages(id) {
|
|
const resp = await this.$apollo.query({
|
|
query: gql`
|
|
query($parent: Int, $locale: String!) {
|
|
pages {
|
|
tree(parent: $parent, mode: ALL, locale: $locale) {
|
|
id
|
|
path
|
|
title
|
|
icon
|
|
isFolder
|
|
pageId
|
|
parent
|
|
locale
|
|
}
|
|
}
|
|
}
|
|
`,
|
|
fetchPolicy: 'cache-first',
|
|
variables: {
|
|
parent: id,
|
|
locale: this.locale
|
|
}
|
|
})
|
|
|
|
return _.get(resp, 'data.pages.tree', [])
|
|
}
|
|
},
|
|
mounted () {
|
|
this.currentParent.title = `/ ${this.$t('common:sidebar.root')}`
|
|
|
|
this.fetchTreeRoot()
|
|
}
|
|
}
|
|
</script>
|
|
|
|
<style lang="scss">
|
|
.v-treeview{
|
|
.tree-item {
|
|
font-weight: 500;
|
|
line-height: 1rem;
|
|
font-size: 0.9rem;
|
|
}
|
|
a {
|
|
text-decoration: none;
|
|
}
|
|
&.theme--dark{
|
|
a {
|
|
color: white;
|
|
}
|
|
}
|
|
}
|
|
|
|
.v-treeview-node {
|
|
min-height: 32px;
|
|
|
|
.v-treeview-node__root {
|
|
min-height: 32px;
|
|
padding: 1px 0;
|
|
}
|
|
|
|
.v-treeview-node__content {
|
|
margin: 1px 0;
|
|
}
|
|
|
|
.v-treeview-node__children {
|
|
margin-left: 16px;
|
|
}
|
|
}
|
|
</style>
|