mirror of
https://gitee.com/goploy/goploy.git
synced 2024-12-12 12:45:19 +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
|
Date Transform
|
||||||
</el-button>
|
</el-button>
|
||||||
|
<el-button
|
||||||
|
type="text"
|
||||||
|
size="medium"
|
||||||
|
@click="showTransformDialog('json')"
|
||||||
|
>
|
||||||
|
JSON Pretty
|
||||||
|
</el-button>
|
||||||
<el-button
|
<el-button
|
||||||
type="text"
|
type="text"
|
||||||
size="medium"
|
size="medium"
|
||||||
@ -81,52 +88,8 @@
|
|||||||
:close-on-click-modal="false"
|
:close-on-click-modal="false"
|
||||||
>
|
>
|
||||||
<el-row class="transform-content">
|
<el-row class="transform-content">
|
||||||
<el-row v-show="transformType === 'time'">
|
<TheDatetransform v-model="transformType" />
|
||||||
<el-button
|
<TheJSONPretty v-model="transformType" />
|
||||||
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>
|
|
||||||
<el-row v-show="transformType === 'password'">
|
<el-row v-show="transformType === 'password'">
|
||||||
<el-checkbox-group v-model="password.checkbox">
|
<el-checkbox-group v-model="password.checkbox">
|
||||||
<el-checkbox :label="1">A-Z</el-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 cronstrue from 'cronstrue/i18n'
|
||||||
import { humanSize } from '@/utils'
|
import { humanSize } from '@/utils'
|
||||||
import { md5 as hashByMD5 } from '@/utils/md5'
|
import { md5 as hashByMD5 } from '@/utils/md5'
|
||||||
|
|
||||||
import { defineComponent } from 'vue'
|
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 useRandomPWD from './composables/useRandomPWD'
|
||||||
import useUnicode from './composables/useUnicode'
|
import useUnicode from './composables/useUnicode'
|
||||||
import useRGBTransform from './composables/useRGBTransform'
|
import useRGBTransform from './composables/useRGBTransform'
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
components: {
|
components: {
|
||||||
|
TheDatetransform,
|
||||||
|
TheJSONPretty,
|
||||||
VueQrcode,
|
VueQrcode,
|
||||||
},
|
},
|
||||||
setup() {
|
setup() {
|
||||||
const {
|
|
||||||
timeExchange,
|
|
||||||
dateExchange,
|
|
||||||
timestamp,
|
|
||||||
timestampToDate,
|
|
||||||
dateToTimestamp,
|
|
||||||
} = useDateTransform()
|
|
||||||
|
|
||||||
const { password, createPassword } = useRandomPWD()
|
const { password, createPassword } = useRandomPWD()
|
||||||
|
|
||||||
const { unicode, unicodeUnescapeStr } = useUnicode()
|
const { unicode, unicodeUnescapeStr } = useUnicode()
|
||||||
@ -328,11 +287,6 @@ export default defineComponent({
|
|||||||
const { cHexExchange, rgbExchange, hexToRGB, rgbToHex } = useRGBTransform()
|
const { cHexExchange, rgbExchange, hexToRGB, rgbToHex } = useRGBTransform()
|
||||||
|
|
||||||
return {
|
return {
|
||||||
timeExchange,
|
|
||||||
dateExchange,
|
|
||||||
timestamp,
|
|
||||||
timestampToDate,
|
|
||||||
dateToTimestamp,
|
|
||||||
password,
|
password,
|
||||||
createPassword,
|
createPassword,
|
||||||
unicode,
|
unicode,
|
||||||
@ -357,6 +311,10 @@ export default defineComponent({
|
|||||||
md5: {
|
md5: {
|
||||||
text: '',
|
text: '',
|
||||||
},
|
},
|
||||||
|
json: {
|
||||||
|
view: 'raw',
|
||||||
|
input: '',
|
||||||
|
},
|
||||||
cron: {
|
cron: {
|
||||||
expression: '',
|
expression: '',
|
||||||
chinese: '',
|
chinese: '',
|
||||||
@ -368,6 +326,7 @@ export default defineComponent({
|
|||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
hashByMD5,
|
hashByMD5,
|
||||||
|
|
||||||
showTransformDialog(type) {
|
showTransformDialog(type) {
|
||||||
this.transformVisible = true
|
this.transformVisible = true
|
||||||
this.transformType = type
|
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 {
|
export function resetRouter(): void {
|
||||||
router.getRoutes().forEach((route) => {
|
router
|
||||||
route.name && router.removeRoute(route.name)
|
.getRoutes()
|
||||||
})
|
.forEach((route) => route.name && router.removeRoute(route.name))
|
||||||
constantRoutes.forEach((route: RouteRecordRaw) => router.addRoute(route))
|
constantRoutes.forEach((route: RouteRecordRaw) => router.addRoute(route))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user