mirror of
https://gitee.com/goploy/goploy.git
synced 2024-12-04 04:59:58 +08:00
U optimize right menu
This commit is contained in:
parent
a6fbf9501c
commit
1ca710618c
1
web+/src/icons/svg/switch.svg
Normal file
1
web+/src/icons/svg/switch.svg
Normal file
@ -0,0 +1 @@
|
||||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1621241667520" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="5368" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M929.623323 598.014206h-236.799289a94.463717 94.463717 0 0 0-94.463717 94.463717v237.311288a93.951718 93.951718 0 0 0 27.647917 66.5598A92.671722 92.671722 0 0 0 691.288038 1023.996928h237.311288A94.719716 94.719716 0 0 0 1024.08704 929.533211v-237.055288a94.975715 94.975715 0 0 0-27.647917-66.8158 93.43972 93.43972 0 0 0-66.8158-27.647917zM921.687347 698.109906a3.32799 3.32799 0 0 1 2.559993 0v221.183336s0 1.791995-3.071991 3.32799h-219.391342a3.32799 3.32799 0 0 1-3.32799-3.32799V701.437896a3.839988 3.839988 0 0 1 0-2.303993 3.071991 3.071991 0 0 1 2.303993 0zM94.297829 425.982722h237.055289A94.463717 94.463717 0 0 0 425.816835 332.799002V94.463717A94.975715 94.975715 0 0 0 331.353118 0H94.553829A94.719716 94.719716 0 0 0 0.090112 94.463717V332.799002a93.951718 93.951718 0 0 0 94.207717 94.207717z m5.887983-102.399693V102.399693A2.559992 2.559992 0 0 1 102.489805 102.399693a2.815992 2.815992 0 0 1 2.303993 0h218.623344a2.559992 2.559992 0 0 1 2.303993 0v223.743329a4.095988 4.095988 0 0 1-2.303993 0H102.489805a3.071991 3.071991 0 0 1-2.303993-3.58399zM586.328353 34.815896a53.759839 53.759839 0 0 0 5.631983 106.49568h2.559993A459.006623 459.006623 0 0 1 921.687347 389.630831a46.335861 46.335861 0 0 0 18.943943 19.96794 47.871856 47.871856 0 0 0 27.903917 9.727971H972.887194a51.199846 51.199846 0 0 0 35.327894-14.591956 49.407852 49.407852 0 0 0 15.871952-35.583893V166.143502a51.199846 51.199846 0 0 0-51.199846-51.199847h-4.095988a51.199846 51.199846 0 0 0-51.199847 51.199847v37.119888a556.79833 556.79833 0 0 0-298.239105-164.095508M439.384794 893.43732a459.006623 459.006623 0 0 1-338.430985-243.199271 51.199846 51.199846 0 0 0-46.59186-32.511902H51.289958a51.199846 51.199846 0 0 0-48.127855 35.583893 33.023901 33.023901 0 0 0-3.071991 9.727971 20.479939 20.479939 0 0 0 0 3.839988v204.799386a51.199846 51.199846 0 0 0 51.199846 51.199846h4.095988a51.199846 51.199846 0 0 0 51.199847-51.199846v-37.631887a558.334325 558.334325 0 0 0 312.319063 162.815511 61.695815 61.695815 0 0 0 19.199942 3.32799h3.839988a51.199846 51.199846 0 0 0 37.119889-15.359953 51.199846 51.199846 0 0 0 13.055961-37.631888 54.015838 54.015838 0 0 0-15.615953-38.143885 51.199846 51.199846 0 0 0-22.271933-13.567959M10.330081 668.413995z" p-id="5369"></path></svg>
|
After Width: | Height: | Size: 2.6 KiB |
140
web+/src/layout/components/RightMenu/TheDatetransform.vue
Normal file
140
web+/src/layout/components/RightMenu/TheDatetransform.vue
Normal file
@ -0,0 +1,140 @@
|
||||
<template>
|
||||
<el-row v-show="transformType === 'time'">
|
||||
<el-button
|
||||
style="margin-left: 80px"
|
||||
type="primary"
|
||||
@click="timestamp('now')"
|
||||
>
|
||||
{{ $t('now') }}
|
||||
</el-button>
|
||||
<el-button type="primary" @click="timestamp('today')">
|
||||
{{ $t('today') }}
|
||||
</el-button>
|
||||
<el-button type="primary" @click="timestamp('m1d')">
|
||||
{{ $t('m1d') }}
|
||||
</el-button>
|
||||
<el-button type="primary" @click="timestamp('p1d')">
|
||||
{{ $t('p1d') }}
|
||||
</el-button>
|
||||
<el-row style="margin-top: 10px" type="flex" align="middle">
|
||||
<span style="width: 70px; font-size: 14px; margin-right: 10px">
|
||||
Timestamp
|
||||
</span>
|
||||
<el-input
|
||||
v-model="timeExchange.timestamp"
|
||||
style="width: 200px"
|
||||
:placeholder="timeExchange.placeholder"
|
||||
clearable
|
||||
@keyup.enter="timestampToDate"
|
||||
/>
|
||||
<el-button type="primary" @click="timestampToDate">>></el-button>
|
||||
<el-input v-model="timeExchange.date" style="width: 200px" />
|
||||
</el-row>
|
||||
<el-row style="margin-top: 10px" type="flex" align="middle">
|
||||
<span style="width: 70px; font-size: 14px; margin-right: 10px">
|
||||
Date
|
||||
</span>
|
||||
<el-input
|
||||
v-model="dateExchange.date"
|
||||
style="width: 200px"
|
||||
:placeholder="dateExchange.placeholder"
|
||||
clearable
|
||||
@keyup.enter="dateToTimestamp"
|
||||
/>
|
||||
<el-button type="primary" @click="dateToTimestamp">>></el-button>
|
||||
<el-input v-model="dateExchange.timestamp" style="width: 200px" />
|
||||
</el-row>
|
||||
</el-row>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { parseTime } from '@/utils'
|
||||
import { onUnmounted, defineComponent, watch, ref, reactive } from 'vue'
|
||||
|
||||
export default defineComponent({
|
||||
props: {
|
||||
modelValue: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
},
|
||||
emits: ['update:modelValue'],
|
||||
setup(props) {
|
||||
let transformType = ref(props.modelValue)
|
||||
watch(
|
||||
() => props.modelValue,
|
||||
(val: typeof props['modelValue']) => {
|
||||
transformType.value = val
|
||||
}
|
||||
)
|
||||
|
||||
const timeExchange = reactive({
|
||||
date: parseTime(new Date().getTime()),
|
||||
timestamp: '',
|
||||
timer: setInterval(() => {
|
||||
timeExchange.placeholder = String(Math.round(Date.now() / 1000))
|
||||
}, 1000),
|
||||
placeholder: String(Math.round(Date.now() / 1000)),
|
||||
})
|
||||
const dateExchange = reactive({
|
||||
date: '',
|
||||
timestamp: Math.round(Date.now() / 1000),
|
||||
timer: setInterval(() => {
|
||||
dateExchange.placeholder = parseTime(new Date().getTime())
|
||||
}, 1000),
|
||||
placeholder: parseTime(new Date().getTime()),
|
||||
})
|
||||
const timestamp = (value: string) => {
|
||||
let ts = 0
|
||||
switch (value) {
|
||||
case 'now':
|
||||
ts = Math.round(Date.now() / 1000)
|
||||
break
|
||||
case 'today':
|
||||
ts = Math.round(
|
||||
new Date(new Date().setHours(0, 0, 0, 0)).getTime() / 1000
|
||||
)
|
||||
break
|
||||
case 'm1d':
|
||||
ts =
|
||||
timeExchange.timestamp !== ''
|
||||
? parseInt(timeExchange.timestamp) - 86400
|
||||
: Math.round(Date.now() / 1000) - 86400
|
||||
break
|
||||
case 'p1d':
|
||||
ts =
|
||||
timeExchange.timestamp !== ''
|
||||
? parseInt(timeExchange.timestamp) + 86400
|
||||
: Math.round(Date.now() / 1000) + 86400
|
||||
break
|
||||
default:
|
||||
ts = Math.round(Date.now() / 1000)
|
||||
}
|
||||
timeExchange.timestamp = String(ts)
|
||||
timeExchange.date = parseTime(ts)
|
||||
}
|
||||
|
||||
const timestampToDate = () => {
|
||||
timeExchange.date = parseTime(Number(timeExchange.timestamp))
|
||||
}
|
||||
|
||||
const dateToTimestamp = () => {
|
||||
dateExchange.timestamp = new Date(dateExchange.date).getTime() / 1000
|
||||
}
|
||||
|
||||
onUnmounted(() => {
|
||||
clearTimeout(timeExchange.timer)
|
||||
clearTimeout(dateExchange.timer)
|
||||
})
|
||||
|
||||
return {
|
||||
transformType,
|
||||
timeExchange,
|
||||
dateExchange,
|
||||
timestamp,
|
||||
timestampToDate,
|
||||
dateToTimestamp,
|
||||
}
|
||||
},
|
||||
})
|
||||
</script>
|
139
web+/src/layout/components/RightMenu/TheJSONPretty.vue
Normal file
139
web+/src/layout/components/RightMenu/TheJSONPretty.vue
Normal file
@ -0,0 +1,139 @@
|
||||
<template>
|
||||
<el-row v-show="transformType === 'json'" style="width: 100%">
|
||||
<el-row
|
||||
class="json-helper"
|
||||
type="flex"
|
||||
justify="space-between"
|
||||
align="middle"
|
||||
>
|
||||
<el-row>
|
||||
<el-button type="text" size="medium" @click="switchJSONView">
|
||||
<svg-icon icon-class="switch" />
|
||||
</el-button>
|
||||
<el-button type="text" size="medium" @click="expandAll">
|
||||
{{ $t('JSONPage.expandAll') }}
|
||||
</el-button>
|
||||
<el-button type="text" size="medium" @click="collapseAll">
|
||||
{{ $t('JSONPage.collapseAll') }}
|
||||
</el-button>
|
||||
<el-button type="text" size="medium" @click="unmarkAll">
|
||||
{{ $t('JSONPage.unmarkAll') }}
|
||||
</el-button>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-tooltip class="item" effect="dark" placement="bottom-end">
|
||||
<el-button type="text" icon="el-icon-question" />
|
||||
<template #content>
|
||||
<span v-html="$t('JSONPage.tips')"></span>
|
||||
</template>
|
||||
</el-tooltip>
|
||||
</el-row>
|
||||
</el-row>
|
||||
<el-input
|
||||
v-show="json.view === 'raw'"
|
||||
ref="jsonStringInput"
|
||||
v-model="json.input"
|
||||
style="width: 100%"
|
||||
:autosize="{ minRows: 25, maxRows: 25 }"
|
||||
type="textarea"
|
||||
class="json-string-input"
|
||||
placeholder="JSON string"
|
||||
contenteditable="true"
|
||||
@input="handleInput"
|
||||
@paste="onPaste"
|
||||
/>
|
||||
<div
|
||||
v-show="json.view === 'pretty'"
|
||||
ref="jsonPrettyString"
|
||||
class="json-pretty-string"
|
||||
/>
|
||||
</el-row>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import './jsonTree.css'
|
||||
import { jsonTree } from './jsonTree'
|
||||
import { defineComponent, watch, ref, reactive } from 'vue'
|
||||
|
||||
export default defineComponent({
|
||||
props: {
|
||||
modelValue: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
},
|
||||
emits: ['update:modelValue'],
|
||||
setup(props) {
|
||||
let transformType = ref(props.modelValue)
|
||||
watch(
|
||||
() => props.modelValue,
|
||||
(val: typeof props['modelValue']) => {
|
||||
transformType.value = val
|
||||
}
|
||||
)
|
||||
|
||||
const json = reactive({
|
||||
view: 'raw',
|
||||
input: '',
|
||||
tree: {},
|
||||
})
|
||||
const jsonPrettyString = ref()
|
||||
const handleInput = () => {
|
||||
const text = json.input
|
||||
jsonPrettyString.value.innerText = ''
|
||||
try {
|
||||
const data = JSON.parse(text)
|
||||
json.tree = jsonTree.create(data, jsonPrettyString.value)
|
||||
json.tree.expand()
|
||||
} catch (error) {
|
||||
jsonPrettyString.value.innerText = error.message
|
||||
}
|
||||
}
|
||||
const onPaste = (e: ClipboardEvent) => {
|
||||
json.view = 'pretty'
|
||||
const clip = e.clipboardData ? e.clipboardData.getData('Text') : ''
|
||||
json.input = clip
|
||||
handleInput()
|
||||
return true
|
||||
}
|
||||
|
||||
const switchJSONView = () => {
|
||||
if (json.view === 'raw') {
|
||||
json.view = 'pretty'
|
||||
} else {
|
||||
json.view = 'raw'
|
||||
}
|
||||
}
|
||||
const expandAll = () => {
|
||||
json.tree && json.tree.expand()
|
||||
}
|
||||
|
||||
const collapseAll = () => {
|
||||
json.tree && json.tree.collapse()
|
||||
}
|
||||
|
||||
const unmarkAll = () => {
|
||||
json.tree && json.tree.unmarkAll()
|
||||
}
|
||||
|
||||
return {
|
||||
jsonPrettyString,
|
||||
transformType,
|
||||
json,
|
||||
handleInput,
|
||||
onPaste,
|
||||
switchJSONView,
|
||||
expandAll,
|
||||
collapseAll,
|
||||
unmarkAll,
|
||||
}
|
||||
},
|
||||
})
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.json-helper {
|
||||
padding: 0 10px;
|
||||
height: 35px;
|
||||
width: 100%;
|
||||
}
|
||||
</style>
|
@ -1,68 +0,0 @@
|
||||
import { reactive, onUnmounted } from 'vue'
|
||||
import { parseTime } from '@/utils'
|
||||
|
||||
export default function useDateTransform() {
|
||||
const timeExchange = reactive({
|
||||
date: parseTime(new Date().getTime()),
|
||||
timestamp: '',
|
||||
timer: setInterval(() => {
|
||||
timeExchange.placeholder = String(Math.round(Date.now() / 1000))
|
||||
}, 1000),
|
||||
placeholder: String(Math.round(Date.now() / 1000)),
|
||||
})
|
||||
const dateExchange = reactive({
|
||||
date: '',
|
||||
timestamp: Math.round(Date.now() / 1000),
|
||||
timer: setInterval(() => {
|
||||
dateExchange.placeholder = parseTime(new Date().getTime())
|
||||
}, 1000),
|
||||
placeholder: parseTime(new Date().getTime()),
|
||||
})
|
||||
const timestamp = (value: string) => {
|
||||
let ts = 0
|
||||
switch (value) {
|
||||
case 'now':
|
||||
ts = Math.round(Date.now() / 1000)
|
||||
break
|
||||
case 'today':
|
||||
ts = Math.round(
|
||||
new Date(new Date().setHours(0, 0, 0, 0)).getTime() / 1000
|
||||
)
|
||||
break
|
||||
case 'm1d':
|
||||
ts =
|
||||
timeExchange.timestamp !== ''
|
||||
? parseInt(timeExchange.timestamp) - 86400
|
||||
: Math.round(Date.now() / 1000) - 86400
|
||||
break
|
||||
case 'p1d':
|
||||
ts =
|
||||
timeExchange.timestamp !== ''
|
||||
? parseInt(timeExchange.timestamp) + 86400
|
||||
: Math.round(Date.now() / 1000) + 86400
|
||||
break
|
||||
default:
|
||||
ts = Math.round(Date.now() / 1000)
|
||||
}
|
||||
timeExchange.timestamp = String(ts)
|
||||
timeExchange.date = parseTime(ts)
|
||||
}
|
||||
|
||||
const timestampToDate = () => {
|
||||
timeExchange.date = parseTime(Number(timeExchange.timestamp))
|
||||
}
|
||||
const dateToTimestamp = () => {
|
||||
dateExchange.timestamp = new Date(dateExchange.date).getTime() / 1000
|
||||
}
|
||||
onUnmounted(() => {
|
||||
clearTimeout(timeExchange.timer)
|
||||
clearTimeout(dateExchange.timer)
|
||||
})
|
||||
return {
|
||||
timeExchange,
|
||||
dateExchange,
|
||||
timestamp,
|
||||
timestampToDate,
|
||||
dateToTimestamp,
|
||||
}
|
||||
}
|
1
web+/src/layout/components/RightMenu/icons.svg
Normal file
1
web+/src/layout/components/RightMenu/icons.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="11" height="22"><defs><linearGradient id="a"><stop offset="0"/><stop offset="1" stop-opacity="0"/></linearGradient><radialGradient xlink:href="#a" cx="9.739" cy="9.716" fx="9.739" fy="9.716" r="3.709" gradientUnits="userSpaceOnUse"/></defs><g stroke="#000" fill="none"><g transform="translate(-129.5 -333.862) translate(0 .188)"><rect transform="matrix(.962 0 0 .971 4.943 11.548)" ry="2" rx="2" y="332.362" x="130" height="10.337" width="10.432" opacity=".5"/><g><path d="M132 339.175h6" opacity=".5"/><path d="M135 336.175v6" opacity=".5"/></g></g><g transform="translate(-129.5 -333.862)"><rect width="10.432" height="10.337" x="130" y="332.362" rx="2" ry="2" transform="matrix(.962 0 0 .971 4.943 22.736)" opacity=".5"/><path d="M132 350.362h6" opacity=".5"/></g></g></svg>
|
After Width: | Height: | Size: 867 B |
@ -9,6 +9,13 @@
|
||||
>
|
||||
Date Transform
|
||||
</el-button>
|
||||
<el-button
|
||||
type="text"
|
||||
size="medium"
|
||||
@click="showTransformDialog('json')"
|
||||
>
|
||||
JSON Pretty
|
||||
</el-button>
|
||||
<el-button
|
||||
type="text"
|
||||
size="medium"
|
||||
@ -81,52 +88,8 @@
|
||||
:close-on-click-modal="false"
|
||||
>
|
||||
<el-row class="transform-content">
|
||||
<el-row v-show="transformType === 'time'">
|
||||
<el-button
|
||||
style="margin-left: 80px"
|
||||
type="primary"
|
||||
@click="timestamp('now')"
|
||||
>
|
||||
{{ $t('now') }}
|
||||
</el-button>
|
||||
<el-button type="primary" @click="timestamp('today')">
|
||||
{{ $t('today') }}
|
||||
</el-button>
|
||||
<el-button type="primary" @click="timestamp('m1d')">
|
||||
{{ $t('m1d') }}
|
||||
</el-button>
|
||||
<el-button type="primary" @click="timestamp('p1d')">
|
||||
{{ $t('p1d') }}
|
||||
</el-button>
|
||||
<el-row style="margin-top: 10px" type="flex" align="middle">
|
||||
<span style="width: 70px; font-size: 14px; margin-right: 10px">
|
||||
Timestamp
|
||||
</span>
|
||||
<el-input
|
||||
v-model="timeExchange.timestamp"
|
||||
style="width: 200px"
|
||||
:placeholder="timeExchange.placeholder"
|
||||
clearable
|
||||
@keyup.enter="timestampToDate"
|
||||
/>
|
||||
<el-button type="primary" @click="timestampToDate">>></el-button>
|
||||
<el-input v-model="timeExchange.date" style="width: 200px" />
|
||||
</el-row>
|
||||
<el-row style="margin-top: 10px" type="flex" align="middle">
|
||||
<span style="width: 70px; font-size: 14px; margin-right: 10px">
|
||||
Date
|
||||
</span>
|
||||
<el-input
|
||||
v-model="dateExchange.date"
|
||||
style="width: 200px"
|
||||
:placeholder="dateExchange.placeholder"
|
||||
clearable
|
||||
@keyup.enter="dateToTimestamp"
|
||||
/>
|
||||
<el-button type="primary" @click="dateToTimestamp">>></el-button>
|
||||
<el-input v-model="dateExchange.timestamp" style="width: 200px" />
|
||||
</el-row>
|
||||
</el-row>
|
||||
<TheDatetransform v-model="transformType" />
|
||||
<TheJSONPretty v-model="transformType" />
|
||||
<el-row v-show="transformType === 'password'">
|
||||
<el-checkbox-group v-model="password.checkbox">
|
||||
<el-checkbox :label="1">A-Z</el-checkbox>
|
||||
@ -302,25 +265,21 @@ import VueQrcode from '@chenfengyuan/vue-qrcode'
|
||||
import cronstrue from 'cronstrue/i18n'
|
||||
import { humanSize } from '@/utils'
|
||||
import { md5 as hashByMD5 } from '@/utils/md5'
|
||||
|
||||
import { defineComponent } from 'vue'
|
||||
import useDateTransform from './composables/useDateTransform'
|
||||
import TheDatetransform from './TheDatetransform.vue'
|
||||
import TheJSONPretty from './TheJSONPretty.vue'
|
||||
import useRandomPWD from './composables/useRandomPWD'
|
||||
import useUnicode from './composables/useUnicode'
|
||||
import useRGBTransform from './composables/useRGBTransform'
|
||||
|
||||
export default defineComponent({
|
||||
components: {
|
||||
TheDatetransform,
|
||||
TheJSONPretty,
|
||||
VueQrcode,
|
||||
},
|
||||
setup() {
|
||||
const {
|
||||
timeExchange,
|
||||
dateExchange,
|
||||
timestamp,
|
||||
timestampToDate,
|
||||
dateToTimestamp,
|
||||
} = useDateTransform()
|
||||
|
||||
const { password, createPassword } = useRandomPWD()
|
||||
|
||||
const { unicode, unicodeUnescapeStr } = useUnicode()
|
||||
@ -328,11 +287,6 @@ export default defineComponent({
|
||||
const { cHexExchange, rgbExchange, hexToRGB, rgbToHex } = useRGBTransform()
|
||||
|
||||
return {
|
||||
timeExchange,
|
||||
dateExchange,
|
||||
timestamp,
|
||||
timestampToDate,
|
||||
dateToTimestamp,
|
||||
password,
|
||||
createPassword,
|
||||
unicode,
|
||||
@ -357,6 +311,10 @@ export default defineComponent({
|
||||
md5: {
|
||||
text: '',
|
||||
},
|
||||
json: {
|
||||
view: 'raw',
|
||||
input: '',
|
||||
},
|
||||
cron: {
|
||||
expression: '',
|
||||
chinese: '',
|
||||
@ -368,6 +326,7 @@ export default defineComponent({
|
||||
},
|
||||
methods: {
|
||||
hashByMD5,
|
||||
|
||||
showTransformDialog(type) {
|
||||
this.transformVisible = true
|
||||
this.transformType = type
|
||||
|
112
web+/src/layout/components/RightMenu/jsonTree.css
Normal file
112
web+/src/layout/components/RightMenu/jsonTree.css
Normal file
@ -0,0 +1,112 @@
|
||||
/*
|
||||
* JSON Tree Viewer
|
||||
* http://github.com/summerstyle/jsonTreeViewer
|
||||
*
|
||||
* Copyright 2017 Vera Lobacheva (http://iamvera.com)
|
||||
* Released under the MIT license (LICENSE.txt)
|
||||
*/
|
||||
|
||||
/* Background for the tree. May use for <body> element */
|
||||
.jsontree_bg {
|
||||
background: #FFF;
|
||||
}
|
||||
|
||||
/* Styles for the container of the tree (e.g. fonts, margins etc.) */
|
||||
.jsontree_tree {
|
||||
padding-left: 0px;
|
||||
margin-left: 30px;
|
||||
font-family: 'PT Mono', monospace;
|
||||
font-size: 14px;
|
||||
list-style-type: none;
|
||||
}
|
||||
|
||||
.jsontree_node {
|
||||
list-style-type: none;
|
||||
}
|
||||
|
||||
/* Styles for a list of child nodes */
|
||||
.jsontree_child-nodes {
|
||||
display: none;
|
||||
margin-bottom: 5px;
|
||||
line-height: 2;
|
||||
}
|
||||
.jsontree_node_expanded > .jsontree_value-wrapper > .jsontree_value > .jsontree_child-nodes {
|
||||
display: block;
|
||||
}
|
||||
|
||||
/* Styles for labels */
|
||||
.jsontree_label-wrapper {
|
||||
float: left;
|
||||
margin-right: 8px;
|
||||
}
|
||||
.jsontree_label {
|
||||
font-weight: normal;
|
||||
vertical-align: top;
|
||||
color: #000;
|
||||
position: relative;
|
||||
padding: 1px;
|
||||
border-radius: 4px;
|
||||
cursor: default;
|
||||
}
|
||||
.jsontree_node_marked > .jsontree_label-wrapper > .jsontree_label {
|
||||
background: #fff2aa;
|
||||
}
|
||||
|
||||
/* Styles for values */
|
||||
.jsontree_value-wrapper {
|
||||
display: inline-block;
|
||||
overflow-wrap: anywhere;
|
||||
}
|
||||
.jsontree_node_complex > .jsontree_value-wrapper {
|
||||
overflow: inherit;
|
||||
}
|
||||
.jsontree_value {
|
||||
vertical-align: top;
|
||||
display: inline;
|
||||
}
|
||||
.jsontree_value_null {
|
||||
color: #777;
|
||||
font-weight: bold;
|
||||
}
|
||||
.jsontree_value_string {
|
||||
color: #025900;
|
||||
font-weight: bold;
|
||||
}
|
||||
.jsontree_value_number {
|
||||
color: #000E59;
|
||||
font-weight: bold;
|
||||
}
|
||||
.jsontree_value_boolean {
|
||||
color: #600100;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
/* Styles for active elements */
|
||||
.jsontree_expand-button {
|
||||
position: absolute;
|
||||
top: 3px;
|
||||
left: -15px;
|
||||
display: block;
|
||||
width: 11px;
|
||||
height: 11px;
|
||||
background-image: url('icons.svg');
|
||||
}
|
||||
.jsontree_node_expanded > .jsontree_label-wrapper > .jsontree_label > .jsontree_expand-button {
|
||||
background-position: 0 -11px;
|
||||
}
|
||||
.jsontree_show-more {
|
||||
cursor: pointer;
|
||||
}
|
||||
.jsontree_node_expanded > .jsontree_value-wrapper > .jsontree_value > .jsontree_show-more {
|
||||
display: none;
|
||||
}
|
||||
.jsontree_node_empty > .jsontree_label-wrapper > .jsontree_label > .jsontree_expand-button,
|
||||
.jsontree_node_empty > .jsontree_value-wrapper > .jsontree_value > .jsontree_show-more {
|
||||
display: none !important;
|
||||
}
|
||||
.jsontree_node_complex > .jsontree_label-wrapper > .jsontree_label {
|
||||
cursor: pointer;
|
||||
}
|
||||
.jsontree_node_empty > .jsontree_label-wrapper > .jsontree_label {
|
||||
cursor: default !important;
|
||||
}
|
796
web+/src/layout/components/RightMenu/jsonTree.js
Normal file
796
web+/src/layout/components/RightMenu/jsonTree.js
Normal file
@ -0,0 +1,796 @@
|
||||
/**
|
||||
* JSON Tree library (a part of jsonTreeViewer)
|
||||
* http://github.com/summerstyle/jsonTreeViewer
|
||||
*
|
||||
* Copyright 2017 Vera Lobacheva (http://iamvera.com)
|
||||
* Released under the MIT license (LICENSE.txt)
|
||||
*/
|
||||
export var jsonTree = (function() {
|
||||
/* ---------- Utilities ---------- */
|
||||
var utils = {
|
||||
|
||||
/*
|
||||
* Returns js-"class" of value
|
||||
*
|
||||
* @param val {any type} - value
|
||||
* @returns {string} - for example, "[object Function]"
|
||||
*/
|
||||
getClass: function(val) {
|
||||
return Object.prototype.toString.call(val)
|
||||
},
|
||||
|
||||
/**
|
||||
* Checks for a type of value (for valid JSON data types).
|
||||
* In other cases - throws an exception
|
||||
*
|
||||
* @param val {any type} - the value for new node
|
||||
* @returns {string} ("object" | "array" | "null" | "boolean" | "number" | "string")
|
||||
*/
|
||||
getType: function(val) {
|
||||
if (val === null) {
|
||||
return 'null'
|
||||
}
|
||||
|
||||
switch (typeof val) {
|
||||
case 'number':
|
||||
return 'number'
|
||||
|
||||
case 'string':
|
||||
return 'string'
|
||||
|
||||
case 'boolean':
|
||||
return 'boolean'
|
||||
}
|
||||
|
||||
switch (utils.getClass(val)) {
|
||||
case '[object Array]':
|
||||
return 'array'
|
||||
|
||||
case '[object Object]':
|
||||
return 'object'
|
||||
}
|
||||
|
||||
throw new Error('Bad type: ' + utils.getClass(val))
|
||||
},
|
||||
|
||||
/**
|
||||
* Applies for each item of list some function
|
||||
* and checks for last element of the list
|
||||
*
|
||||
* @param obj {Object | Array} - a list or a dict with child nodes
|
||||
* @param func {Function} - the function for each item
|
||||
*/
|
||||
forEachNode: function(obj, func) {
|
||||
var type = utils.getType(obj)
|
||||
var isLast
|
||||
|
||||
switch (type) {
|
||||
case 'array':
|
||||
isLast = obj.length - 1
|
||||
|
||||
obj.forEach(function(item, i) {
|
||||
func(i, item, i === isLast)
|
||||
})
|
||||
|
||||
break
|
||||
|
||||
case 'object':
|
||||
var keys = Object.keys(obj).sort()
|
||||
|
||||
isLast = keys.length - 1
|
||||
|
||||
keys.forEach(function(item, i) {
|
||||
func(item, obj[item], i === isLast)
|
||||
})
|
||||
|
||||
break
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Implements the kind of an inheritance by
|
||||
* using parent prototype and
|
||||
* creating intermediate constructor
|
||||
*
|
||||
* @param Child {Function} - a child constructor
|
||||
* @param Parent {Function} - a parent constructor
|
||||
*/
|
||||
inherits: (function() {
|
||||
var F = function() {}
|
||||
|
||||
return function(Child, Parent) {
|
||||
F.prototype = Parent.prototype
|
||||
Child.prototype = new F()
|
||||
Child.prototype.constructor = Child
|
||||
}
|
||||
})(),
|
||||
|
||||
/*
|
||||
* Checks for a valid type of root node*
|
||||
*
|
||||
* @param {any type} jsonObj - a value for root node
|
||||
* @returns {boolean} - true for an object or an array, false otherwise
|
||||
*/
|
||||
isValidRoot: function(jsonObj) {
|
||||
switch (utils.getType(jsonObj)) {
|
||||
case 'object':
|
||||
case 'array':
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Extends some object
|
||||
*/
|
||||
extend: function(targetObj, sourceObj) {
|
||||
for (var prop in sourceObj) {
|
||||
if (sourceObj.hasOwnProperty(prop)) {
|
||||
targetObj[prop] = sourceObj[prop]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ---------- Node constructors ---------- */
|
||||
|
||||
/**
|
||||
* The factory for creating nodes of defined type.
|
||||
*
|
||||
* ~~~ Node ~~~ is a structure element of an onject or an array
|
||||
* with own label (a key of an object or an index of an array)
|
||||
* and value of any json data type. The root object or array
|
||||
* is a node without label.
|
||||
* {...
|
||||
* [+] "label": value,
|
||||
* ...}
|
||||
*
|
||||
* Markup:
|
||||
* <li class="jsontree_node [jsontree_node_expanded]">
|
||||
* <span class="jsontree_label-wrapper">
|
||||
* <span class="jsontree_label">
|
||||
* <span class="jsontree_expand-button" />
|
||||
* "label"
|
||||
* </span>
|
||||
* :
|
||||
* </span>
|
||||
* <(div|span) class="jsontree_value jsontree_value_(object|array|boolean|null|number|string)">
|
||||
* ...
|
||||
* </(div|span)>
|
||||
* </li>
|
||||
*
|
||||
* @param label {string} - key name
|
||||
* @param val {Object | Array | string | number | boolean | null} - a value of node
|
||||
* @param isLast {boolean} - true if node is last in list of siblings
|
||||
*
|
||||
* @return {Node}
|
||||
*/
|
||||
function Node(label, val, isLast) {
|
||||
var nodeType = utils.getType(val)
|
||||
|
||||
if (nodeType in Node.CONSTRUCTORS) {
|
||||
return new Node.CONSTRUCTORS[nodeType](label, val, isLast)
|
||||
} else {
|
||||
throw new Error('Bad type: ' + utils.getClass(val))
|
||||
}
|
||||
}
|
||||
|
||||
Node.CONSTRUCTORS = {
|
||||
'boolean': NodeBoolean,
|
||||
'number': NodeNumber,
|
||||
'string': NodeString,
|
||||
'null': NodeNull,
|
||||
'object': NodeObject,
|
||||
'array': NodeArray
|
||||
}
|
||||
|
||||
/*
|
||||
* The constructor for simple types (string, number, boolean, null)
|
||||
* {...
|
||||
* [+] "label": value,
|
||||
* ...}
|
||||
* value = string || number || boolean || null
|
||||
*
|
||||
* Markup:
|
||||
* <li class="jsontree_node">
|
||||
* <span class="jsontree_label-wrapper">
|
||||
* <span class="jsontree_label">"age"</span>
|
||||
* :
|
||||
* </span>
|
||||
* <span class="jsontree_value jsontree_value_(number|boolean|string|null)">25</span>
|
||||
* ,
|
||||
* </li>
|
||||
*
|
||||
* @abstract
|
||||
* @param label {string} - key name
|
||||
* @param val {string | number | boolean | null} - a value of simple types
|
||||
* @param isLast {boolean} - true if node is last in list of parent childNodes
|
||||
*/
|
||||
function _NodeSimple(label, val, isLast) {
|
||||
if (this.constructor === _NodeSimple) {
|
||||
throw new Error('This is abstract class')
|
||||
}
|
||||
|
||||
var self = this
|
||||
var el = document.createElement('li')
|
||||
var labelEl
|
||||
var template = function(label, val) {
|
||||
var str = ''
|
||||
str += '<span class="jsontree_label-wrapper">'
|
||||
str += '<span class="jsontree_label">"' + label + '"</span> : '
|
||||
str += '</span>'
|
||||
str += '<span class="jsontree_value-wrapper">'
|
||||
str += '<span class="jsontree_value jsontree_value_' + self.type + '">' + val + '</span>'
|
||||
str += (!isLast ? ',' : '')
|
||||
str += '</span>'
|
||||
return str
|
||||
}
|
||||
|
||||
self.label = label
|
||||
self.isComplex = false
|
||||
|
||||
el.classList.add('jsontree_node')
|
||||
el.innerHTML = template(label, val)
|
||||
|
||||
self.el = el
|
||||
|
||||
labelEl = el.querySelector('.jsontree_label')
|
||||
|
||||
labelEl.addEventListener('click', function(e) {
|
||||
if (e.altKey) {
|
||||
self.toggleMarked()
|
||||
return
|
||||
}
|
||||
|
||||
if (e.shiftKey) {
|
||||
document.getSelection().removeAllRanges()
|
||||
alert(self.getJSONPath())
|
||||
return
|
||||
}
|
||||
}, false)
|
||||
}
|
||||
|
||||
_NodeSimple.prototype = {
|
||||
constructor: _NodeSimple,
|
||||
|
||||
/**
|
||||
* Mark node
|
||||
*/
|
||||
mark: function() {
|
||||
this.el.classList.add('jsontree_node_marked')
|
||||
},
|
||||
|
||||
/**
|
||||
* Unmark node
|
||||
*/
|
||||
unmark: function() {
|
||||
this.el.classList.remove('jsontree_node_marked')
|
||||
},
|
||||
|
||||
/**
|
||||
* Mark or unmark node
|
||||
*/
|
||||
toggleMarked: function() {
|
||||
this.el.classList.toggle('jsontree_node_marked')
|
||||
},
|
||||
|
||||
/**
|
||||
* Expands parent node of this node
|
||||
*
|
||||
* @param isRecursive {boolean} - if true, expands all parent nodes
|
||||
* (from node to root)
|
||||
*/
|
||||
expandParent: function(isRecursive) {
|
||||
if (!this.parent) {
|
||||
return
|
||||
}
|
||||
|
||||
this.parent.expand()
|
||||
this.parent.expandParent(isRecursive)
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns JSON-path of this
|
||||
*
|
||||
* @param isInDotNotation {boolean} - kind of notation for returned json-path
|
||||
* (by default, in bracket notation)
|
||||
* @returns {string}
|
||||
*/
|
||||
getJSONPath: function(isInDotNotation) {
|
||||
if (this.isRoot) {
|
||||
return '$'
|
||||
}
|
||||
|
||||
var currentPath
|
||||
|
||||
if (this.parent.type === 'array') {
|
||||
currentPath = '[' + this.label + ']'
|
||||
} else {
|
||||
currentPath = isInDotNotation ? '.' + this.label : "['" + this.label + "']"
|
||||
}
|
||||
|
||||
return this.parent.getJSONPath(isInDotNotation) + currentPath
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* The constructor for boolean values
|
||||
* {...
|
||||
* [+] "label": boolean,
|
||||
* ...}
|
||||
* boolean = true || false
|
||||
*
|
||||
* @constructor
|
||||
* @param label {string} - key name
|
||||
* @param val {boolean} - value of boolean type, true or false
|
||||
* @param isLast {boolean} - true if node is last in list of parent childNodes
|
||||
*/
|
||||
function NodeBoolean(label, val, isLast) {
|
||||
this.type = 'boolean'
|
||||
|
||||
_NodeSimple.call(this, label, val, isLast)
|
||||
}
|
||||
utils.inherits(NodeBoolean, _NodeSimple)
|
||||
|
||||
/*
|
||||
* The constructor for number values
|
||||
* {...
|
||||
* [+] "label": number,
|
||||
* ...}
|
||||
* number = 123
|
||||
*
|
||||
* @constructor
|
||||
* @param label {string} - key name
|
||||
* @param val {number} - value of number type, for example 123
|
||||
* @param isLast {boolean} - true if node is last in list of parent childNodes
|
||||
*/
|
||||
function NodeNumber(label, val, isLast) {
|
||||
this.type = 'number'
|
||||
|
||||
_NodeSimple.call(this, label, val, isLast)
|
||||
}
|
||||
utils.inherits(NodeNumber, _NodeSimple)
|
||||
|
||||
/*
|
||||
* The constructor for string values
|
||||
* {...
|
||||
* [+] "label": string,
|
||||
* ...}
|
||||
* string = "abc"
|
||||
*
|
||||
* @constructor
|
||||
* @param label {string} - key name
|
||||
* @param val {string} - value of string type, for example "abc"
|
||||
* @param isLast {boolean} - true if node is last in list of parent childNodes
|
||||
*/
|
||||
function NodeString(label, val, isLast) {
|
||||
this.type = 'string'
|
||||
|
||||
_NodeSimple.call(this, label, '"' + val + '"', isLast)
|
||||
}
|
||||
utils.inherits(NodeString, _NodeSimple)
|
||||
|
||||
/*
|
||||
* The constructor for null values
|
||||
* {...
|
||||
* [+] "label": null,
|
||||
* ...}
|
||||
*
|
||||
* @constructor
|
||||
* @param label {string} - key name
|
||||
* @param val {null} - value (only null)
|
||||
* @param isLast {boolean} - true if node is last in list of parent childNodes
|
||||
*/
|
||||
function NodeNull(label, val, isLast) {
|
||||
this.type = 'null'
|
||||
|
||||
_NodeSimple.call(this, label, val, isLast)
|
||||
}
|
||||
utils.inherits(NodeNull, _NodeSimple)
|
||||
|
||||
/*
|
||||
* The constructor for complex types (object, array)
|
||||
* {...
|
||||
* [+] "label": value,
|
||||
* ...}
|
||||
* value = object || array
|
||||
*
|
||||
* Markup:
|
||||
* <li class="jsontree_node jsontree_node_(object|array) [expanded]">
|
||||
* <span class="jsontree_label-wrapper">
|
||||
* <span class="jsontree_label">
|
||||
* <span class="jsontree_expand-button" />
|
||||
* "label"
|
||||
* </span>
|
||||
* :
|
||||
* </span>
|
||||
* <div class="jsontree_value">
|
||||
* <b>{</b>
|
||||
* <ul class="jsontree_child-nodes" />
|
||||
* <b>}</b>
|
||||
* ,
|
||||
* </div>
|
||||
* </li>
|
||||
*
|
||||
* @abstract
|
||||
* @param label {string} - key name
|
||||
* @param val {Object | Array} - a value of complex types, object or array
|
||||
* @param isLast {boolean} - true if node is last in list of parent childNodes
|
||||
*/
|
||||
function _NodeComplex(label, val, isLast) {
|
||||
if (this.constructor === _NodeComplex) {
|
||||
throw new Error('This is abstract class')
|
||||
}
|
||||
|
||||
var self = this
|
||||
var el = document.createElement('li')
|
||||
var template = function(label, sym) {
|
||||
var comma = (!isLast) ? ',' : ''
|
||||
var str = ''
|
||||
str += '<div class="jsontree_value-wrapper">'
|
||||
str += '<div class="jsontree_value jsontree_value_' + self.type + '">'
|
||||
str += '<b>' + sym[0] + '</b>'
|
||||
str += '<span class="jsontree_show-more">…</span>'
|
||||
str += '<ul class="jsontree_child-nodes"></ul>'
|
||||
str += '<b>' + sym[1] + '</b>'
|
||||
str += '</div>' + comma + '</div>'
|
||||
if (label !== null) {
|
||||
var labelStr = ''
|
||||
labelStr += '<span class="jsontree_label-wrapper">'
|
||||
labelStr += '<span class="jsontree_label">'
|
||||
labelStr += '<span class="jsontree_expand-button"></span>"' + label + '"</span> : </span>'
|
||||
str = labelStr + str
|
||||
}
|
||||
|
||||
return str
|
||||
}
|
||||
var childNodesUl
|
||||
var labelEl
|
||||
var moreContentEl
|
||||
var childNodes = []
|
||||
|
||||
self.label = label
|
||||
self.isComplex = true
|
||||
|
||||
el.classList.add('jsontree_node')
|
||||
el.classList.add('jsontree_node_complex')
|
||||
el.innerHTML = template(label, self.sym)
|
||||
|
||||
childNodesUl = el.querySelector('.jsontree_child-nodes')
|
||||
|
||||
if (label !== null) {
|
||||
labelEl = el.querySelector('.jsontree_label')
|
||||
moreContentEl = el.querySelector('.jsontree_show-more')
|
||||
|
||||
labelEl.addEventListener('click', function(e) {
|
||||
if (e.altKey) {
|
||||
self.toggleMarked()
|
||||
return
|
||||
}
|
||||
|
||||
if (e.shiftKey) {
|
||||
document.getSelection().removeAllRanges()
|
||||
alert(self.getJSONPath())
|
||||
return
|
||||
}
|
||||
|
||||
self.toggle(e.ctrlKey || e.metaKey)
|
||||
}, false)
|
||||
|
||||
moreContentEl.addEventListener('click', function(e) {
|
||||
self.toggle(e.ctrlKey || e.metaKey)
|
||||
}, false)
|
||||
|
||||
self.isRoot = false
|
||||
} else {
|
||||
self.isRoot = true
|
||||
self.parent = null
|
||||
|
||||
el.classList.add('jsontree_node_expanded')
|
||||
}
|
||||
|
||||
self.el = el
|
||||
self.childNodes = childNodes
|
||||
self.childNodesUl = childNodesUl
|
||||
|
||||
utils.forEachNode(val, function(label, node, isLast) {
|
||||
self.addChild(new Node(label, node, isLast))
|
||||
})
|
||||
|
||||
self.isEmpty = !childNodes.length
|
||||
if (self.isEmpty) {
|
||||
el.classList.add('jsontree_node_empty')
|
||||
}
|
||||
}
|
||||
|
||||
utils.inherits(_NodeComplex, _NodeSimple)
|
||||
|
||||
utils.extend(_NodeComplex.prototype, {
|
||||
constructor: _NodeComplex,
|
||||
|
||||
/*
|
||||
* Add child node to list of child nodes
|
||||
*
|
||||
* @param child {Node} - child node
|
||||
*/
|
||||
addChild: function(child) {
|
||||
this.childNodes.push(child)
|
||||
this.childNodesUl.appendChild(child.el)
|
||||
child.parent = this
|
||||
},
|
||||
|
||||
/*
|
||||
* Expands this list of node child nodes
|
||||
*
|
||||
* @param isRecursive {boolean} - if true, expands all child nodes
|
||||
*/
|
||||
expand: function(isRecursive) {
|
||||
if (this.isEmpty) {
|
||||
return
|
||||
}
|
||||
|
||||
if (!this.isRoot) {
|
||||
this.el.classList.add('jsontree_node_expanded')
|
||||
}
|
||||
|
||||
if (isRecursive) {
|
||||
this.childNodes.forEach(function(item, i) {
|
||||
if (item.isComplex) {
|
||||
item.expand(isRecursive)
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
|
||||
/*
|
||||
* Collapses this list of node child nodes
|
||||
*
|
||||
* @param isRecursive {boolean} - if true, collapses all child nodes
|
||||
*/
|
||||
collapse: function(isRecursive) {
|
||||
if (this.isEmpty) {
|
||||
return
|
||||
}
|
||||
|
||||
if (!this.isRoot) {
|
||||
this.el.classList.remove('jsontree_node_expanded')
|
||||
}
|
||||
|
||||
if (isRecursive) {
|
||||
this.childNodes.forEach(function(item, i) {
|
||||
if (item.isComplex) {
|
||||
item.collapse(isRecursive)
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
|
||||
/*
|
||||
* Expands collapsed or collapses expanded node
|
||||
*
|
||||
* @param {boolean} isRecursive - Expand all child nodes if this node is expanded
|
||||
* and collapse it otherwise
|
||||
*/
|
||||
toggle: function(isRecursive) {
|
||||
if (this.isEmpty) {
|
||||
return
|
||||
}
|
||||
|
||||
this.el.classList.toggle('jsontree_node_expanded')
|
||||
|
||||
if (isRecursive) {
|
||||
var isExpanded = this.el.classList.contains('jsontree_node_expanded')
|
||||
|
||||
this.childNodes.forEach(function(item, i) {
|
||||
if (item.isComplex) {
|
||||
item[isExpanded ? 'expand' : 'collapse'](isRecursive)
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Find child nodes that match some conditions and handle it
|
||||
*
|
||||
* @param {Function} matcher
|
||||
* @param {Function} handler
|
||||
* @param {boolean} isRecursive
|
||||
*/
|
||||
findChildren: function(matcher, handler, isRecursive) {
|
||||
if (this.isEmpty) {
|
||||
return
|
||||
}
|
||||
|
||||
this.childNodes.forEach(function(item, i) {
|
||||
if (matcher(item)) {
|
||||
handler(item)
|
||||
}
|
||||
|
||||
if (item.isComplex && isRecursive) {
|
||||
item.findChildren(matcher, handler, isRecursive)
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
/*
|
||||
* The constructor for object values
|
||||
* {...
|
||||
* [+] "label": object,
|
||||
* ...}
|
||||
* object = {"abc": "def"}
|
||||
*
|
||||
* @constructor
|
||||
* @param label {string} - key name
|
||||
* @param val {Object} - value of object type, {"abc": "def"}
|
||||
* @param isLast {boolean} - true if node is last in list of siblings
|
||||
*/
|
||||
function NodeObject(label, val, isLast) {
|
||||
this.sym = ['{', '}']
|
||||
this.type = 'object'
|
||||
|
||||
_NodeComplex.call(this, label, val, isLast)
|
||||
}
|
||||
utils.inherits(NodeObject, _NodeComplex)
|
||||
|
||||
/*
|
||||
* The constructor for array values
|
||||
* {...
|
||||
* [+] "label": array,
|
||||
* ...}
|
||||
* array = [1,2,3]
|
||||
*
|
||||
* @constructor
|
||||
* @param label {string} - key name
|
||||
* @param val {Array} - value of array type, [1,2,3]
|
||||
* @param isLast {boolean} - true if node is last in list of siblings
|
||||
*/
|
||||
function NodeArray(label, val, isLast) {
|
||||
this.sym = ['[', ']']
|
||||
this.type = 'array'
|
||||
|
||||
_NodeComplex.call(this, label, val, isLast)
|
||||
}
|
||||
utils.inherits(NodeArray, _NodeComplex)
|
||||
|
||||
/* ---------- The tree constructor ---------- */
|
||||
|
||||
/*
|
||||
* The constructor for json tree.
|
||||
* It contains only one Node (Array or Object), without property name.
|
||||
* CSS-styles of .tree define main tree styles like font-family,
|
||||
* font-size and own margins.
|
||||
*
|
||||
* Markup:
|
||||
* <ul class="jsontree_tree clearfix">
|
||||
* {Node}
|
||||
* </ul>
|
||||
*
|
||||
* @constructor
|
||||
* @param jsonObj {Object | Array} - data for tree
|
||||
* @param domEl {DOMElement} - DOM-element, wrapper for tree
|
||||
*/
|
||||
function Tree(jsonObj, domEl) {
|
||||
this.wrapper = document.createElement('ul')
|
||||
this.wrapper.className = 'jsontree_tree clearfix'
|
||||
|
||||
this.rootNode = null
|
||||
|
||||
this.sourceJSONObj = jsonObj
|
||||
|
||||
this.loadData(jsonObj)
|
||||
this.appendTo(domEl)
|
||||
}
|
||||
|
||||
Tree.prototype = {
|
||||
constructor: Tree,
|
||||
|
||||
/**
|
||||
* Fill new data in current json tree
|
||||
*
|
||||
* @param {Object | Array} jsonObj - json-data
|
||||
*/
|
||||
loadData: function(jsonObj) {
|
||||
if (!utils.isValidRoot(jsonObj)) {
|
||||
alert('The root should be an object or an array')
|
||||
return
|
||||
}
|
||||
|
||||
this.sourceJSONObj = jsonObj
|
||||
|
||||
this.rootNode = new Node(null, jsonObj, 'last')
|
||||
this.wrapper.innerHTML = ''
|
||||
this.wrapper.appendChild(this.rootNode.el)
|
||||
},
|
||||
|
||||
/**
|
||||
* Appends tree to DOM-element (or move it to new place)
|
||||
*
|
||||
* @param {DOMElement} domEl
|
||||
*/
|
||||
appendTo: function(domEl) {
|
||||
domEl.appendChild(this.wrapper)
|
||||
},
|
||||
|
||||
/**
|
||||
* Expands all tree nodes (objects or arrays) recursively
|
||||
*
|
||||
* @param {Function} filterFunc - 'true' if this node should be expanded
|
||||
*/
|
||||
expand: function(filterFunc) {
|
||||
if (this.rootNode.isComplex) {
|
||||
if (typeof filterFunc === 'function') {
|
||||
this.rootNode.childNodes.forEach(function(item, i) {
|
||||
if (item.isComplex && filterFunc(item)) {
|
||||
item.expand()
|
||||
}
|
||||
})
|
||||
} else {
|
||||
this.rootNode.expand('recursive')
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Collapses all tree nodes (objects or arrays) recursively
|
||||
*/
|
||||
collapse: function() {
|
||||
if (typeof this.rootNode.collapse === 'function') {
|
||||
this.rootNode.collapse('recursive')
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns the source json-string (pretty-printed)
|
||||
*
|
||||
* @param {boolean} isPrettyPrinted - 'true' for pretty-printed string
|
||||
* @returns {string} - for exemple, '{"a":2,"b":3}'
|
||||
*/
|
||||
toSourceJSON: function(isPrettyPrinted) {
|
||||
if (!isPrettyPrinted) {
|
||||
return JSON.stringify(this.sourceJSONObj)
|
||||
}
|
||||
|
||||
var DELIMETER = '[%^$#$%^%]'
|
||||
var jsonStr = JSON.stringify(this.sourceJSONObj, null, DELIMETER)
|
||||
|
||||
jsonStr = jsonStr.split('\n').join('<br />')
|
||||
jsonStr = jsonStr.split(DELIMETER).join(' ')
|
||||
|
||||
return jsonStr
|
||||
},
|
||||
|
||||
/**
|
||||
* Find all nodes that match some conditions and handle it
|
||||
*/
|
||||
findAndHandle: function(matcher, handler) {
|
||||
this.rootNode.findChildren(matcher, handler, 'isRecursive')
|
||||
},
|
||||
|
||||
/**
|
||||
* Unmark all nodes
|
||||
*/
|
||||
unmarkAll: function() {
|
||||
this.rootNode.findChildren(function(node) {
|
||||
return true
|
||||
}, function(node) {
|
||||
node.unmark()
|
||||
}, 'isRecursive')
|
||||
}
|
||||
}
|
||||
|
||||
/* ---------- Public methods ---------- */
|
||||
return {
|
||||
/**
|
||||
* Creates new tree by data and appends it to the DOM-element
|
||||
*
|
||||
* @param jsonObj {Object | Array} - json-data
|
||||
* @param domEl {DOMElement} - the wrapper element
|
||||
* @returns {Tree}
|
||||
*/
|
||||
create: function(jsonObj, domEl) {
|
||||
return new Tree(jsonObj, domEl)
|
||||
}
|
||||
}
|
||||
})()
|
@ -267,9 +267,9 @@ const router = createRouter({
|
||||
})
|
||||
|
||||
export function resetRouter(): void {
|
||||
router.getRoutes().forEach((route) => {
|
||||
route.name && router.removeRoute(route.name)
|
||||
})
|
||||
router
|
||||
.getRoutes()
|
||||
.forEach((route) => route.name && router.removeRoute(route.name))
|
||||
constantRoutes.forEach((route: RouteRecordRaw) => router.addRoute(route))
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user