U optimize right menu

This commit is contained in:
zhenorzz 2021-05-17 22:22:13 +08:00
parent a6fbf9501c
commit 1ca710618c
9 changed files with 1211 additions and 131 deletions

View 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

View 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>

View 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>

View File

@ -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,
}
}

View 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

View File

@ -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

View 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;
}

View 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">&hellip;</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('&nbsp;&nbsp;&nbsp;&nbsp;')
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)
}
}
})()

View File

@ -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))
} }