vue-editify 0.1.17 → 0.1.19
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -3
- package/examples/App.vue +62 -53
- package/examples/main.ts +4 -4
- package/lib/components/button/button.vue.d.ts +11 -11
- package/lib/components/checkbox/checkbox.vue.d.ts +8 -8
- package/lib/components/colors/colors.vue.d.ts +4 -4
- package/lib/components/icon/icon.vue.d.ts +1 -1
- package/lib/components/insertImage/insertImage.vue.d.ts +9 -9
- package/lib/components/insertLink/insertLink.vue.d.ts +2 -2
- package/lib/components/insertTable/insertTable.vue.d.ts +2 -2
- package/lib/components/insertVideo/insertVideo.vue.d.ts +9 -9
- package/lib/components/layer/layer.vue.d.ts +9 -9
- package/lib/components/menu/menu.vue.d.ts +4 -4
- package/lib/components/toolbar/toolbar.vue.d.ts +9 -9
- package/lib/components/tooltip/tooltip.vue.d.ts +1 -1
- package/lib/components/triangle/triangle.vue.d.ts +4 -4
- package/lib/editify/editify.vue.d.ts +88 -70
- package/lib/editify/props.d.ts +11 -3
- package/lib/editify.es.js +65 -46
- package/lib/editify.umd.js +1 -1
- package/lib/index.d.ts +1 -1
- package/lib/style.css +1 -1
- package/package.json +45 -45
- package/src/components/button/button.less +145 -145
- package/src/components/button/button.vue +197 -197
- package/src/components/button/props.ts +95 -95
- package/src/components/checkbox/checkbox.less +84 -84
- package/src/components/checkbox/checkbox.vue +68 -68
- package/src/components/checkbox/props.ts +49 -49
- package/src/components/colors/colors.less +75 -75
- package/src/components/colors/colors.vue +36 -36
- package/src/components/colors/props.ts +29 -29
- package/src/components/icon/icon.less +14 -14
- package/src/components/icon/icon.vue +12 -12
- package/src/components/icon/props.ts +11 -11
- package/src/components/insertImage/insertImage.less +135 -135
- package/src/components/insertImage/insertImage.vue +146 -146
- package/src/components/insertImage/props.ts +43 -43
- package/src/components/insertLink/insertLink.less +64 -64
- package/src/components/insertLink/insertLink.vue +58 -58
- package/src/components/insertLink/props.ts +16 -16
- package/src/components/insertTable/insertTable.less +54 -54
- package/src/components/insertTable/insertTable.vue +85 -85
- package/src/components/insertTable/props.ts +27 -27
- package/src/components/insertVideo/insertVideo.less +135 -135
- package/src/components/insertVideo/insertVideo.vue +146 -146
- package/src/components/insertVideo/props.ts +43 -43
- package/src/components/layer/layer.less +49 -49
- package/src/components/layer/layer.vue +598 -598
- package/src/components/layer/props.ts +71 -71
- package/src/components/menu/menu.less +63 -63
- package/src/components/menu/menu.vue +1569 -1569
- package/src/components/menu/props.ts +17 -17
- package/src/components/toolbar/props.ts +35 -35
- package/src/components/toolbar/toolbar.less +89 -89
- package/src/components/toolbar/toolbar.vue +1101 -1101
- package/src/components/tooltip/props.ts +21 -21
- package/src/components/tooltip/tooltip.less +23 -23
- package/src/components/tooltip/tooltip.vue +37 -37
- package/src/components/triangle/props.ts +26 -26
- package/src/components/triangle/triangle.less +79 -79
- package/src/components/triangle/triangle.vue +65 -65
- package/src/core/function.ts +1144 -1144
- package/src/core/rule.ts +259 -259
- package/src/core/tool.ts +1137 -1137
- package/src/css/base.less +30 -30
- package/src/css/hljs.less +54 -54
- package/src/editify/editify.less +404 -403
- package/src/editify/editify.vue +803 -792
- package/src/editify/props.ts +156 -146
- package/src/hljs/index.ts +197 -197
- package/src/icon/iconfont.css +219 -219
- package/src/index.ts +32 -32
- package/src/locale/en_US.ts +88 -88
- package/src/locale/index.ts +12 -12
- package/src/locale/zh_CN.ts +88 -88
- package/tsconfig.json +27 -27
- package/tsconfig.node.json +11 -11
- package/vite-env.d.ts +1 -1
- package/vite.config.ts +42 -42
@@ -1,146 +1,146 @@
|
|
1
|
-
<template>
|
2
|
-
<div class="editify-image">
|
3
|
-
<div class="editify-image-header">
|
4
|
-
<div @click="current = 'upload'" class="editify-image-header-item" :class="{ active: current == 'upload' }" :style="activeStyle('upload')">{{ $editTrans('uploadImage') }}</div>
|
5
|
-
<div @click="current = 'remote'" class="editify-image-header-item" :class="{ active: current == 'remote' }" :style="activeStyle('remote')">{{ $editTrans('remoteImage') }}</div>
|
6
|
-
<div class="editify-image-header-slider" :class="current" :style="{ backgroundColor: color || '' }"></div>
|
7
|
-
</div>
|
8
|
-
<!-- 网络图片 -->
|
9
|
-
<div class="editify-image-remote" v-if="current == 'remote'">
|
10
|
-
<input v-model.trim="remoteUrl" :placeholder="$editTrans('imageUrlPlaceholder')" @blur="handleInputBlur" @focus="handleInputFocus" />
|
11
|
-
<div class="editify-image-remote-footer" :style="{ color: color }">
|
12
|
-
<span @click="insertRemoteImage">{{ $editTrans('insert') }}</span>
|
13
|
-
</div>
|
14
|
-
</div>
|
15
|
-
<!-- 上传图片 -->
|
16
|
-
<div class="editify-image-upload" v-else>
|
17
|
-
<Icon value="upload"></Icon>
|
18
|
-
<input :multiple="multiple" accept="image/*" @change="selectFile" type="file" />
|
19
|
-
</div>
|
20
|
-
</div>
|
21
|
-
</template>
|
22
|
-
<script setup lang="ts">
|
23
|
-
import { file as DapFile } from 'dap-util'
|
24
|
-
import Icon from '../icon/icon.vue'
|
25
|
-
import { InsertImageProps } from './props'
|
26
|
-
import { ComponentInternalInstance, computed, inject, ref, watch } from 'vue'
|
27
|
-
import { ObjectType } from '../../core/tool'
|
28
|
-
|
29
|
-
defineOptions({
|
30
|
-
name: 'InsertImage'
|
31
|
-
})
|
32
|
-
const props = defineProps(InsertImageProps)
|
33
|
-
const emits = defineEmits(['change', 'insert'])
|
34
|
-
|
35
|
-
const $editTrans = inject<(key: string) => any>('$editTrans')!
|
36
|
-
const editify = inject<ComponentInternalInstance>('editify')!
|
37
|
-
|
38
|
-
//当前展示的面板,取值remote和upload
|
39
|
-
const current = ref<'remote' | 'upload'>('upload')
|
40
|
-
//远程图片链接
|
41
|
-
const remoteUrl = ref<string>('')
|
42
|
-
|
43
|
-
const activeStyle = computed<(name: 'remote' | 'upload') => ObjectType>(() => {
|
44
|
-
return (name: 'remote' | 'upload') => {
|
45
|
-
if (current.value == name) {
|
46
|
-
return {
|
47
|
-
color: props.color
|
48
|
-
}
|
49
|
-
}
|
50
|
-
return {}
|
51
|
-
}
|
52
|
-
})
|
53
|
-
|
54
|
-
//获取文件后缀
|
55
|
-
const getSuffix = (file: File) => {
|
56
|
-
const index = file.name.lastIndexOf('.')
|
57
|
-
if (index <= 0) {
|
58
|
-
return ''
|
59
|
-
}
|
60
|
-
return file.name.substring(index + 1)
|
61
|
-
}
|
62
|
-
//输入框获取焦点
|
63
|
-
const handleInputFocus = (e: Event) => {
|
64
|
-
if (props.color) {
|
65
|
-
;(<HTMLInputElement>e.currentTarget).style.borderColor = props.color
|
66
|
-
}
|
67
|
-
}
|
68
|
-
//输入框失去焦点
|
69
|
-
const handleInputBlur = (e: Event) => {
|
70
|
-
;(<HTMLInputElement>e.currentTarget).style.borderColor = ''
|
71
|
-
}
|
72
|
-
//插入网络图片
|
73
|
-
const insertRemoteImage = () => {
|
74
|
-
emits('insert', remoteUrl.value)
|
75
|
-
}
|
76
|
-
//选择文件
|
77
|
-
const selectFile = async (e: Event) => {
|
78
|
-
const inputEle = <HTMLInputElement>e.currentTarget
|
79
|
-
const files = inputEle.files
|
80
|
-
if (!files || !files.length) {
|
81
|
-
return
|
82
|
-
}
|
83
|
-
let filterFiles = []
|
84
|
-
for (let i = 0; i < files.length; i++) {
|
85
|
-
const file = files[i]
|
86
|
-
const suffix = getSuffix(file)
|
87
|
-
const isMatch = props.accept.some(item => {
|
88
|
-
return item.toLocaleLowerCase() == suffix.toLocaleLowerCase()
|
89
|
-
})
|
90
|
-
//后缀不符合
|
91
|
-
if (!isMatch) {
|
92
|
-
//如果自定义了异常处理
|
93
|
-
if (typeof props.handleError == 'function') {
|
94
|
-
props.handleError.apply(editify.proxy!, ['suffixError', file])
|
95
|
-
}
|
96
|
-
continue
|
97
|
-
}
|
98
|
-
//超过最大值
|
99
|
-
if (props.maxSize && file.size / 1024 > props.maxSize) {
|
100
|
-
//如果自定义了异常处理
|
101
|
-
if (typeof props.handleError == 'function') {
|
102
|
-
props.handleError.apply(editify.proxy!, ['maxSizeError', file])
|
103
|
-
}
|
104
|
-
continue
|
105
|
-
}
|
106
|
-
//没达到最小值
|
107
|
-
if (props.minSize && file.size / 1024 < props.minSize) {
|
108
|
-
//如果自定义了异常处理
|
109
|
-
if (typeof props.handleError == 'function') {
|
110
|
-
props.handleError.apply(editify.proxy!, ['minSizeError', file])
|
111
|
-
}
|
112
|
-
continue
|
113
|
-
}
|
114
|
-
filterFiles.push(file)
|
115
|
-
}
|
116
|
-
//有文件可上传
|
117
|
-
if (filterFiles.length) {
|
118
|
-
let images = []
|
119
|
-
//自定义上传方法
|
120
|
-
if (typeof props.customUpload == 'function') {
|
121
|
-
images = (await props.customUpload.apply(editify.proxy!, [filterFiles])) || []
|
122
|
-
}
|
123
|
-
//默认上传方法
|
124
|
-
else {
|
125
|
-
for (let i = 0; i < filterFiles.length; i++) {
|
126
|
-
const url = await DapFile.dataFileToBase64(filterFiles[i])
|
127
|
-
images.push(url)
|
128
|
-
}
|
129
|
-
}
|
130
|
-
images.forEach(url => {
|
131
|
-
emits('insert', url)
|
132
|
-
})
|
133
|
-
}
|
134
|
-
//清空文件选择框
|
135
|
-
inputEle.value = ''
|
136
|
-
}
|
137
|
-
|
138
|
-
//监听current变更触发change事件
|
139
|
-
watch(
|
140
|
-
() => current.value,
|
141
|
-
() => {
|
142
|
-
emits('change')
|
143
|
-
}
|
144
|
-
)
|
145
|
-
</script>
|
146
|
-
<style scoped src="./insertImage.less"></style>
|
1
|
+
<template>
|
2
|
+
<div class="editify-image">
|
3
|
+
<div class="editify-image-header">
|
4
|
+
<div @click="current = 'upload'" class="editify-image-header-item" :class="{ active: current == 'upload' }" :style="activeStyle('upload')">{{ $editTrans('uploadImage') }}</div>
|
5
|
+
<div @click="current = 'remote'" class="editify-image-header-item" :class="{ active: current == 'remote' }" :style="activeStyle('remote')">{{ $editTrans('remoteImage') }}</div>
|
6
|
+
<div class="editify-image-header-slider" :class="current" :style="{ backgroundColor: color || '' }"></div>
|
7
|
+
</div>
|
8
|
+
<!-- 网络图片 -->
|
9
|
+
<div class="editify-image-remote" v-if="current == 'remote'">
|
10
|
+
<input v-model.trim="remoteUrl" :placeholder="$editTrans('imageUrlPlaceholder')" @blur="handleInputBlur" @focus="handleInputFocus" />
|
11
|
+
<div class="editify-image-remote-footer" :style="{ color: color }">
|
12
|
+
<span @click="insertRemoteImage">{{ $editTrans('insert') }}</span>
|
13
|
+
</div>
|
14
|
+
</div>
|
15
|
+
<!-- 上传图片 -->
|
16
|
+
<div class="editify-image-upload" v-else>
|
17
|
+
<Icon value="upload"></Icon>
|
18
|
+
<input :multiple="multiple" accept="image/*" @change="selectFile" type="file" />
|
19
|
+
</div>
|
20
|
+
</div>
|
21
|
+
</template>
|
22
|
+
<script setup lang="ts">
|
23
|
+
import { file as DapFile } from 'dap-util'
|
24
|
+
import Icon from '../icon/icon.vue'
|
25
|
+
import { InsertImageProps } from './props'
|
26
|
+
import { ComponentInternalInstance, computed, inject, ref, watch } from 'vue'
|
27
|
+
import { ObjectType } from '../../core/tool'
|
28
|
+
|
29
|
+
defineOptions({
|
30
|
+
name: 'InsertImage'
|
31
|
+
})
|
32
|
+
const props = defineProps(InsertImageProps)
|
33
|
+
const emits = defineEmits(['change', 'insert'])
|
34
|
+
|
35
|
+
const $editTrans = inject<(key: string) => any>('$editTrans')!
|
36
|
+
const editify = inject<ComponentInternalInstance>('editify')!
|
37
|
+
|
38
|
+
//当前展示的面板,取值remote和upload
|
39
|
+
const current = ref<'remote' | 'upload'>('upload')
|
40
|
+
//远程图片链接
|
41
|
+
const remoteUrl = ref<string>('')
|
42
|
+
|
43
|
+
const activeStyle = computed<(name: 'remote' | 'upload') => ObjectType>(() => {
|
44
|
+
return (name: 'remote' | 'upload') => {
|
45
|
+
if (current.value == name) {
|
46
|
+
return {
|
47
|
+
color: props.color
|
48
|
+
}
|
49
|
+
}
|
50
|
+
return {}
|
51
|
+
}
|
52
|
+
})
|
53
|
+
|
54
|
+
//获取文件后缀
|
55
|
+
const getSuffix = (file: File) => {
|
56
|
+
const index = file.name.lastIndexOf('.')
|
57
|
+
if (index <= 0) {
|
58
|
+
return ''
|
59
|
+
}
|
60
|
+
return file.name.substring(index + 1)
|
61
|
+
}
|
62
|
+
//输入框获取焦点
|
63
|
+
const handleInputFocus = (e: Event) => {
|
64
|
+
if (props.color) {
|
65
|
+
;(<HTMLInputElement>e.currentTarget).style.borderColor = props.color
|
66
|
+
}
|
67
|
+
}
|
68
|
+
//输入框失去焦点
|
69
|
+
const handleInputBlur = (e: Event) => {
|
70
|
+
;(<HTMLInputElement>e.currentTarget).style.borderColor = ''
|
71
|
+
}
|
72
|
+
//插入网络图片
|
73
|
+
const insertRemoteImage = () => {
|
74
|
+
emits('insert', remoteUrl.value)
|
75
|
+
}
|
76
|
+
//选择文件
|
77
|
+
const selectFile = async (e: Event) => {
|
78
|
+
const inputEle = <HTMLInputElement>e.currentTarget
|
79
|
+
const files = inputEle.files
|
80
|
+
if (!files || !files.length) {
|
81
|
+
return
|
82
|
+
}
|
83
|
+
let filterFiles = []
|
84
|
+
for (let i = 0; i < files.length; i++) {
|
85
|
+
const file = files[i]
|
86
|
+
const suffix = getSuffix(file)
|
87
|
+
const isMatch = props.accept.some(item => {
|
88
|
+
return item.toLocaleLowerCase() == suffix.toLocaleLowerCase()
|
89
|
+
})
|
90
|
+
//后缀不符合
|
91
|
+
if (!isMatch) {
|
92
|
+
//如果自定义了异常处理
|
93
|
+
if (typeof props.handleError == 'function') {
|
94
|
+
props.handleError.apply(editify.proxy!, ['suffixError', file])
|
95
|
+
}
|
96
|
+
continue
|
97
|
+
}
|
98
|
+
//超过最大值
|
99
|
+
if (props.maxSize && file.size / 1024 > props.maxSize) {
|
100
|
+
//如果自定义了异常处理
|
101
|
+
if (typeof props.handleError == 'function') {
|
102
|
+
props.handleError.apply(editify.proxy!, ['maxSizeError', file])
|
103
|
+
}
|
104
|
+
continue
|
105
|
+
}
|
106
|
+
//没达到最小值
|
107
|
+
if (props.minSize && file.size / 1024 < props.minSize) {
|
108
|
+
//如果自定义了异常处理
|
109
|
+
if (typeof props.handleError == 'function') {
|
110
|
+
props.handleError.apply(editify.proxy!, ['minSizeError', file])
|
111
|
+
}
|
112
|
+
continue
|
113
|
+
}
|
114
|
+
filterFiles.push(file)
|
115
|
+
}
|
116
|
+
//有文件可上传
|
117
|
+
if (filterFiles.length) {
|
118
|
+
let images = []
|
119
|
+
//自定义上传方法
|
120
|
+
if (typeof props.customUpload == 'function') {
|
121
|
+
images = (await props.customUpload.apply(editify.proxy!, [filterFiles])) || []
|
122
|
+
}
|
123
|
+
//默认上传方法
|
124
|
+
else {
|
125
|
+
for (let i = 0; i < filterFiles.length; i++) {
|
126
|
+
const url = await DapFile.dataFileToBase64(filterFiles[i])
|
127
|
+
images.push(url)
|
128
|
+
}
|
129
|
+
}
|
130
|
+
images.forEach(url => {
|
131
|
+
emits('insert', url)
|
132
|
+
})
|
133
|
+
}
|
134
|
+
//清空文件选择框
|
135
|
+
inputEle.value = ''
|
136
|
+
}
|
137
|
+
|
138
|
+
//监听current变更触发change事件
|
139
|
+
watch(
|
140
|
+
() => current.value,
|
141
|
+
() => {
|
142
|
+
emits('change')
|
143
|
+
}
|
144
|
+
)
|
145
|
+
</script>
|
146
|
+
<style scoped src="./insertImage.less"></style>
|
@@ -1,43 +1,43 @@
|
|
1
|
-
import { ExtractPublicPropTypes, PropType } from 'vue'
|
2
|
-
|
3
|
-
export type InsertImageUploadErrorType = 'suffixError' | 'maxSizeError' | 'minSizeError'
|
4
|
-
|
5
|
-
export const InsertImageProps = {
|
6
|
-
//主题色
|
7
|
-
color: {
|
8
|
-
type: String,
|
9
|
-
default: ''
|
10
|
-
},
|
11
|
-
//支持的图片类型数组
|
12
|
-
accept: {
|
13
|
-
type: Array as PropType<string[]>,
|
14
|
-
default: null
|
15
|
-
},
|
16
|
-
//是否支持多选
|
17
|
-
multiple: {
|
18
|
-
type: Boolean,
|
19
|
-
default: false
|
20
|
-
},
|
21
|
-
//单个文件最大值
|
22
|
-
maxSize: {
|
23
|
-
type: Number,
|
24
|
-
default: null
|
25
|
-
},
|
26
|
-
//单个文件最小值
|
27
|
-
minSize: {
|
28
|
-
type: Number,
|
29
|
-
default: null
|
30
|
-
},
|
31
|
-
//是否自定义上传图片
|
32
|
-
customUpload: {
|
33
|
-
type: Function as PropType<(files: File[]) => string[] | Promise<string[]>>,
|
34
|
-
default: null
|
35
|
-
},
|
36
|
-
//处理上传图片异常
|
37
|
-
handleError: {
|
38
|
-
type: Function as PropType<(error: InsertImageUploadErrorType, file: File) => void>,
|
39
|
-
default: null
|
40
|
-
}
|
41
|
-
}
|
42
|
-
|
43
|
-
export type InsertImagePropsType = ExtractPublicPropTypes<typeof InsertImageProps>
|
1
|
+
import { ExtractPublicPropTypes, PropType } from 'vue'
|
2
|
+
|
3
|
+
export type InsertImageUploadErrorType = 'suffixError' | 'maxSizeError' | 'minSizeError'
|
4
|
+
|
5
|
+
export const InsertImageProps = {
|
6
|
+
//主题色
|
7
|
+
color: {
|
8
|
+
type: String,
|
9
|
+
default: ''
|
10
|
+
},
|
11
|
+
//支持的图片类型数组
|
12
|
+
accept: {
|
13
|
+
type: Array as PropType<string[]>,
|
14
|
+
default: null
|
15
|
+
},
|
16
|
+
//是否支持多选
|
17
|
+
multiple: {
|
18
|
+
type: Boolean,
|
19
|
+
default: false
|
20
|
+
},
|
21
|
+
//单个文件最大值
|
22
|
+
maxSize: {
|
23
|
+
type: Number,
|
24
|
+
default: null
|
25
|
+
},
|
26
|
+
//单个文件最小值
|
27
|
+
minSize: {
|
28
|
+
type: Number,
|
29
|
+
default: null
|
30
|
+
},
|
31
|
+
//是否自定义上传图片
|
32
|
+
customUpload: {
|
33
|
+
type: Function as PropType<(files: File[]) => string[] | Promise<string[]>>,
|
34
|
+
default: null
|
35
|
+
},
|
36
|
+
//处理上传图片异常
|
37
|
+
handleError: {
|
38
|
+
type: Function as PropType<(error: InsertImageUploadErrorType, file: File) => void>,
|
39
|
+
default: null
|
40
|
+
}
|
41
|
+
}
|
42
|
+
|
43
|
+
export type InsertImagePropsType = ExtractPublicPropTypes<typeof InsertImageProps>
|
@@ -1,64 +1,64 @@
|
|
1
|
-
.editify-link {
|
2
|
-
display: block;
|
3
|
-
width: 280px;
|
4
|
-
padding: 10px 14px;
|
5
|
-
|
6
|
-
.editify-link-label {
|
7
|
-
display: block;
|
8
|
-
text-align: left;
|
9
|
-
margin-bottom: 10px;
|
10
|
-
font-size: @font-size;
|
11
|
-
color: @font-color;
|
12
|
-
}
|
13
|
-
|
14
|
-
input {
|
15
|
-
appearance: none;
|
16
|
-
-webkit-appearance: none;
|
17
|
-
-moz-appearance: none;
|
18
|
-
display: block;
|
19
|
-
width: 100%;
|
20
|
-
margin: 0 0 10px 0;
|
21
|
-
padding: 4px 2px;
|
22
|
-
border: none;
|
23
|
-
font-size: @font-size;
|
24
|
-
color: @font-color;
|
25
|
-
border-bottom: 1px solid @border-color;
|
26
|
-
line-height: 1.5;
|
27
|
-
transition: border-color 500ms;
|
28
|
-
background-color: transparent;
|
29
|
-
outline: none;
|
30
|
-
box-sizing: border-box;
|
31
|
-
|
32
|
-
&::-webkit-input-placeholder,
|
33
|
-
&::placeholder {
|
34
|
-
color: @font-color-disabled;
|
35
|
-
font-family: inherit;
|
36
|
-
font-size: inherit;
|
37
|
-
vertical-align: middle;
|
38
|
-
}
|
39
|
-
}
|
40
|
-
|
41
|
-
.editify-link-footer {
|
42
|
-
display: flex;
|
43
|
-
justify-content: space-between;
|
44
|
-
align-items: center;
|
45
|
-
width: 100%;
|
46
|
-
|
47
|
-
.editify-link-operations {
|
48
|
-
display: flex;
|
49
|
-
justify-content: flex-start;
|
50
|
-
align-items: center;
|
51
|
-
|
52
|
-
& > span {
|
53
|
-
cursor: pointer;
|
54
|
-
opacity: 0.8;
|
55
|
-
transition: all 200ms;
|
56
|
-
font-size: @font-size;
|
57
|
-
|
58
|
-
&:hover {
|
59
|
-
opacity: 1;
|
60
|
-
}
|
61
|
-
}
|
62
|
-
}
|
63
|
-
}
|
64
|
-
}
|
1
|
+
.editify-link {
|
2
|
+
display: block;
|
3
|
+
width: 280px;
|
4
|
+
padding: 10px 14px;
|
5
|
+
|
6
|
+
.editify-link-label {
|
7
|
+
display: block;
|
8
|
+
text-align: left;
|
9
|
+
margin-bottom: 10px;
|
10
|
+
font-size: @font-size;
|
11
|
+
color: @font-color;
|
12
|
+
}
|
13
|
+
|
14
|
+
input {
|
15
|
+
appearance: none;
|
16
|
+
-webkit-appearance: none;
|
17
|
+
-moz-appearance: none;
|
18
|
+
display: block;
|
19
|
+
width: 100%;
|
20
|
+
margin: 0 0 10px 0;
|
21
|
+
padding: 4px 2px;
|
22
|
+
border: none;
|
23
|
+
font-size: @font-size;
|
24
|
+
color: @font-color;
|
25
|
+
border-bottom: 1px solid @border-color;
|
26
|
+
line-height: 1.5;
|
27
|
+
transition: border-color 500ms;
|
28
|
+
background-color: transparent;
|
29
|
+
outline: none;
|
30
|
+
box-sizing: border-box;
|
31
|
+
|
32
|
+
&::-webkit-input-placeholder,
|
33
|
+
&::placeholder {
|
34
|
+
color: @font-color-disabled;
|
35
|
+
font-family: inherit;
|
36
|
+
font-size: inherit;
|
37
|
+
vertical-align: middle;
|
38
|
+
}
|
39
|
+
}
|
40
|
+
|
41
|
+
.editify-link-footer {
|
42
|
+
display: flex;
|
43
|
+
justify-content: space-between;
|
44
|
+
align-items: center;
|
45
|
+
width: 100%;
|
46
|
+
|
47
|
+
.editify-link-operations {
|
48
|
+
display: flex;
|
49
|
+
justify-content: flex-start;
|
50
|
+
align-items: center;
|
51
|
+
|
52
|
+
& > span {
|
53
|
+
cursor: pointer;
|
54
|
+
opacity: 0.8;
|
55
|
+
transition: all 200ms;
|
56
|
+
font-size: @font-size;
|
57
|
+
|
58
|
+
&:hover {
|
59
|
+
opacity: 1;
|
60
|
+
}
|
61
|
+
}
|
62
|
+
}
|
63
|
+
}
|
64
|
+
}
|
@@ -1,58 +1,58 @@
|
|
1
|
-
<template>
|
2
|
-
<div class="editify-link">
|
3
|
-
<div class="editify-link-label">{{ $editTrans('linkAddress') }}</div>
|
4
|
-
<input @focus="handleInputFocus" @blur="handleInputBlur" :placeholder="$editTrans('linkTextEnterPlaceholder')" v-model.trim="linkText" type="text" />
|
5
|
-
<input @focus="handleInputFocus" @blur="handleInputBlur" :placeholder="$editTrans('linkUrlEnterPlaceholder')" v-model.trim="linkUrl" type="url" />
|
6
|
-
<div class="editify-link-footer">
|
7
|
-
<Checkbox v-model="newOpen" :label="$editTrans('newWindowOpen')" :color="color" :size="10"></Checkbox>
|
8
|
-
<div class="editify-link-operations">
|
9
|
-
<span :style="{ color: color }" @click="insertLink">{{ $editTrans('insertLink') }}</span>
|
10
|
-
</div>
|
11
|
-
</div>
|
12
|
-
</div>
|
13
|
-
</template>
|
14
|
-
<script setup lang="ts">
|
15
|
-
import { inject, ref, watch } from 'vue'
|
16
|
-
import Checkbox from '../checkbox/checkbox.vue'
|
17
|
-
import { InsertLinkProps } from './props'
|
18
|
-
|
19
|
-
defineOptions({
|
20
|
-
name: 'InsertLink'
|
21
|
-
})
|
22
|
-
const props = defineProps(InsertLinkProps)
|
23
|
-
const emits = defineEmits(['insert'])
|
24
|
-
|
25
|
-
const $editTrans = inject<(key: string) => any>('$editTrans')!
|
26
|
-
|
27
|
-
//链接地址
|
28
|
-
const linkUrl = ref<string>('')
|
29
|
-
//链接文本
|
30
|
-
const linkText = ref<string>('')
|
31
|
-
//是否新窗口打开
|
32
|
-
const newOpen = ref<boolean>(false)
|
33
|
-
|
34
|
-
watch(
|
35
|
-
() => props.text,
|
36
|
-
newVal => {
|
37
|
-
linkText.value = newVal
|
38
|
-
},
|
39
|
-
{
|
40
|
-
immediate: true
|
41
|
-
}
|
42
|
-
)
|
43
|
-
//输入框获取焦点
|
44
|
-
const handleInputFocus = (e: Event) => {
|
45
|
-
if (props.color) {
|
46
|
-
;(<HTMLInputElement>e.currentTarget).style.borderColor = props.color
|
47
|
-
}
|
48
|
-
}
|
49
|
-
//输入框失去焦点
|
50
|
-
const handleInputBlur = (e: Event) => {
|
51
|
-
;(<HTMLInputElement>e.currentTarget).style.borderColor = ''
|
52
|
-
}
|
53
|
-
//插入链接
|
54
|
-
const insertLink = () => {
|
55
|
-
emits('insert', linkText.value, linkUrl.value, newOpen.value)
|
56
|
-
}
|
57
|
-
</script>
|
58
|
-
<style scoped src="./insertLink.less"></style>
|
1
|
+
<template>
|
2
|
+
<div class="editify-link">
|
3
|
+
<div class="editify-link-label">{{ $editTrans('linkAddress') }}</div>
|
4
|
+
<input @focus="handleInputFocus" @blur="handleInputBlur" :placeholder="$editTrans('linkTextEnterPlaceholder')" v-model.trim="linkText" type="text" />
|
5
|
+
<input @focus="handleInputFocus" @blur="handleInputBlur" :placeholder="$editTrans('linkUrlEnterPlaceholder')" v-model.trim="linkUrl" type="url" />
|
6
|
+
<div class="editify-link-footer">
|
7
|
+
<Checkbox v-model="newOpen" :label="$editTrans('newWindowOpen')" :color="color" :size="10"></Checkbox>
|
8
|
+
<div class="editify-link-operations">
|
9
|
+
<span :style="{ color: color }" @click="insertLink">{{ $editTrans('insertLink') }}</span>
|
10
|
+
</div>
|
11
|
+
</div>
|
12
|
+
</div>
|
13
|
+
</template>
|
14
|
+
<script setup lang="ts">
|
15
|
+
import { inject, ref, watch } from 'vue'
|
16
|
+
import Checkbox from '../checkbox/checkbox.vue'
|
17
|
+
import { InsertLinkProps } from './props'
|
18
|
+
|
19
|
+
defineOptions({
|
20
|
+
name: 'InsertLink'
|
21
|
+
})
|
22
|
+
const props = defineProps(InsertLinkProps)
|
23
|
+
const emits = defineEmits(['insert'])
|
24
|
+
|
25
|
+
const $editTrans = inject<(key: string) => any>('$editTrans')!
|
26
|
+
|
27
|
+
//链接地址
|
28
|
+
const linkUrl = ref<string>('')
|
29
|
+
//链接文本
|
30
|
+
const linkText = ref<string>('')
|
31
|
+
//是否新窗口打开
|
32
|
+
const newOpen = ref<boolean>(false)
|
33
|
+
|
34
|
+
watch(
|
35
|
+
() => props.text,
|
36
|
+
newVal => {
|
37
|
+
linkText.value = newVal
|
38
|
+
},
|
39
|
+
{
|
40
|
+
immediate: true
|
41
|
+
}
|
42
|
+
)
|
43
|
+
//输入框获取焦点
|
44
|
+
const handleInputFocus = (e: Event) => {
|
45
|
+
if (props.color) {
|
46
|
+
;(<HTMLInputElement>e.currentTarget).style.borderColor = props.color
|
47
|
+
}
|
48
|
+
}
|
49
|
+
//输入框失去焦点
|
50
|
+
const handleInputBlur = (e: Event) => {
|
51
|
+
;(<HTMLInputElement>e.currentTarget).style.borderColor = ''
|
52
|
+
}
|
53
|
+
//插入链接
|
54
|
+
const insertLink = () => {
|
55
|
+
emits('insert', linkText.value, linkUrl.value, newOpen.value)
|
56
|
+
}
|
57
|
+
</script>
|
58
|
+
<style scoped src="./insertLink.less"></style>
|
@@ -1,16 +1,16 @@
|
|
1
|
-
import { ExtractPublicPropTypes } from 'vue'
|
2
|
-
|
3
|
-
export const InsertLinkProps = {
|
4
|
-
//主题色
|
5
|
-
color: {
|
6
|
-
type: String,
|
7
|
-
default: ''
|
8
|
-
},
|
9
|
-
//预置的链接文本值
|
10
|
-
text: {
|
11
|
-
type: String,
|
12
|
-
default: ''
|
13
|
-
}
|
14
|
-
}
|
15
|
-
|
16
|
-
export type InsertLinkPropsType = ExtractPublicPropTypes<typeof InsertLinkProps>
|
1
|
+
import { ExtractPublicPropTypes } from 'vue'
|
2
|
+
|
3
|
+
export const InsertLinkProps = {
|
4
|
+
//主题色
|
5
|
+
color: {
|
6
|
+
type: String,
|
7
|
+
default: ''
|
8
|
+
},
|
9
|
+
//预置的链接文本值
|
10
|
+
text: {
|
11
|
+
type: String,
|
12
|
+
default: ''
|
13
|
+
}
|
14
|
+
}
|
15
|
+
|
16
|
+
export type InsertLinkPropsType = ExtractPublicPropTypes<typeof InsertLinkProps>
|