goodteditor-ui 1.0.53 → 1.0.55
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/package.json +14 -12
- package/src/components/ui/Tooltip.md +33 -7
- package/src/components/ui/Tooltip.vue +23 -4
- package/src/components/ui/WysiwygEditor/WysiwygEditor.md +2 -1
- package/src/components/ui/WysiwygEditor/WysiwygEditor.vue +16 -8
- package/src/components/ui/WysiwygEditor/constants.d.ts +9 -1
- package/src/components/ui/WysiwygEditor/constants.js +14 -4
- package/src/components/ui/WysiwygEditor/renders/Image.vue +91 -98
- package/src/components/ui/WysiwygEditor/renders/Link.vue +45 -42
- package/src/components/ui/WysiwygEditor/renders/ToolbarPopover.vue +1 -1
- package/src/components/ui/WysiwygEditor/renders/components/Tooltip.vue +31 -0
- package/src/components/ui/WysiwygEditor/tools-and-commands.js +8 -8
- package/vue.config.js +1 -1
- package/src/components/ui/WysiwygEditor/renders/components/Popover.vue +0 -15
- package/src/components/ui/WysiwygEditor/renders/components/WithPopover.vue +0 -35
package/package.json
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "goodteditor-ui",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.55",
|
|
4
4
|
"main": "index.js",
|
|
5
5
|
"homepage": "https://goodt-ui.netlify.app/",
|
|
6
6
|
"scripts": {
|
|
7
|
-
"serve": "
|
|
8
|
-
"build": "
|
|
7
|
+
"serve": "vue-cli-service styleguidist",
|
|
8
|
+
"build": "vue-cli-service styleguidist:build",
|
|
9
9
|
"dev": "vue-cli-service serve",
|
|
10
10
|
"docs:build": "set NODE_ENV=development && npm run build",
|
|
11
11
|
"docs:deploy": "npx netlify deploy --dir=docs --prod"
|
|
@@ -29,18 +29,20 @@
|
|
|
29
29
|
},
|
|
30
30
|
"devDependencies": {
|
|
31
31
|
"@babel/plugin-syntax-dynamic-import": "^7.8.3",
|
|
32
|
-
"@vue/cli-plugin-babel": "^
|
|
33
|
-
"@vue/cli-plugin-eslint": "^
|
|
34
|
-
"@vue/cli-service": "^
|
|
35
|
-
"axios": "^0.
|
|
32
|
+
"@vue/cli-plugin-babel": "^5.0.8",
|
|
33
|
+
"@vue/cli-plugin-eslint": "^5.0.8",
|
|
34
|
+
"@vue/cli-service": "^5.0.8",
|
|
35
|
+
"axios": "^1.0.0",
|
|
36
36
|
"babel-eslint": "^10.1.0",
|
|
37
|
-
"eslint": "^
|
|
38
|
-
"eslint-plugin-vue": "^
|
|
37
|
+
"eslint": "^7.5.0",
|
|
38
|
+
"eslint-plugin-vue": "^9.25.0",
|
|
39
39
|
"less": "^3.13.1",
|
|
40
|
-
"less-loader": "^
|
|
40
|
+
"less-loader": "^7.0.0",
|
|
41
41
|
"netlify-cli": "^5.0.1",
|
|
42
|
-
"vue-styleguidist": "4.
|
|
43
|
-
"vue-
|
|
42
|
+
"vue-cli-plugin-styleguidist": "~4.72.4",
|
|
43
|
+
"vue-styleguidist": "^4.72.4",
|
|
44
|
+
"vue-template-compiler": "^2.6.12",
|
|
45
|
+
"webpack": "^5.91.0"
|
|
44
46
|
},
|
|
45
47
|
"peerDependencies": {
|
|
46
48
|
"vue": "^2.6.12",
|
|
@@ -2,7 +2,7 @@ Simple example
|
|
|
2
2
|
|
|
3
3
|
```vue
|
|
4
4
|
<template>
|
|
5
|
-
<div class="pos-rel pad-l5">
|
|
5
|
+
<div class="pos-rel pad-l5 text-center">
|
|
6
6
|
<ui-select
|
|
7
7
|
class="pos-abs pos-top-left"
|
|
8
8
|
v-model="position"
|
|
@@ -10,13 +10,9 @@ Simple example
|
|
|
10
10
|
></ui-select>
|
|
11
11
|
<ui-tooltip :position="position">
|
|
12
12
|
<template #target="{ events, binds }">
|
|
13
|
-
<
|
|
14
|
-
class="pad-l2 bg-green color-white radius text-center"
|
|
15
|
-
v-on="events"
|
|
16
|
-
v-bind="binds"
|
|
17
|
-
>
|
|
13
|
+
<button class="btn btn-success w-33 pad-v-l1" v-on="events" v-bind="binds">
|
|
18
14
|
hover me
|
|
19
|
-
</
|
|
15
|
+
</button>
|
|
20
16
|
</template>
|
|
21
17
|
<div>Title</div>
|
|
22
18
|
<div>
|
|
@@ -52,3 +48,33 @@ export default {
|
|
|
52
48
|
};
|
|
53
49
|
</script>
|
|
54
50
|
```
|
|
51
|
+
|
|
52
|
+
Advanced example. Using the trigger on 'click' and custom tooltip styling
|
|
53
|
+
|
|
54
|
+
```vue
|
|
55
|
+
<template>
|
|
56
|
+
<div class="pos-rel pad-l5 text-center">
|
|
57
|
+
<ui-tooltip position="top" trigger-on="click" :positionOffset="[10, 10]">
|
|
58
|
+
<template #target="{ events, binds }">
|
|
59
|
+
<button class="btn btn-success w-33 pad-v-l1" v-on="events" v-bind="binds">
|
|
60
|
+
click me
|
|
61
|
+
</button>
|
|
62
|
+
</template>
|
|
63
|
+
<template #tooltip>
|
|
64
|
+
<div class="panel">
|
|
65
|
+
<div class="panel-body">
|
|
66
|
+
<p>Remove the hover from me so that I disappear</p>
|
|
67
|
+
<p>or just click somewhere outside.</p>
|
|
68
|
+
</div>
|
|
69
|
+
</div>
|
|
70
|
+
</template>
|
|
71
|
+
</ui-tooltip>
|
|
72
|
+
</div>
|
|
73
|
+
</template>
|
|
74
|
+
<script>
|
|
75
|
+
import UiTooltip from './Tooltip.vue';
|
|
76
|
+
export default {
|
|
77
|
+
components: { UiTooltip }
|
|
78
|
+
};
|
|
79
|
+
</script>
|
|
80
|
+
```
|
|
@@ -1,21 +1,30 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div class="ui-tooltip">
|
|
3
|
-
|
|
3
|
+
<!--
|
|
4
|
+
@slot Target slot
|
|
5
|
+
@binding {Object} binds tooltip props (use v-bind)
|
|
6
|
+
@binding {Object} events tooltip events (use v-on)
|
|
7
|
+
@binding {boolean} visible whether tooltip is visible
|
|
8
|
+
-->
|
|
9
|
+
<slot name="target" v-bind="{ events: targetEvents, binds: targetBinds, visible }"></slot>
|
|
4
10
|
<ui-popover
|
|
5
11
|
v-bind="popoverOptions"
|
|
6
12
|
:show.sync="popoverShow"
|
|
13
|
+
ref="popover"
|
|
7
14
|
@mouseenter.native="onPopoverMouseEnter"
|
|
8
15
|
@mouseleave.native="onPopoverMouseLeave"
|
|
9
16
|
>
|
|
10
17
|
<!--
|
|
11
18
|
@slot Tooltip slot
|
|
19
|
+
@binding {Function} hide function to hide tooltip
|
|
12
20
|
-->
|
|
13
|
-
<slot name="tooltip">
|
|
21
|
+
<slot name="tooltip" v-bind="{ hide }">
|
|
14
22
|
<div class="tooltip">
|
|
15
23
|
<!--
|
|
16
24
|
@slot Tooltip content slot
|
|
25
|
+
@binding {Function} hide function to hide tooltip
|
|
17
26
|
-->
|
|
18
|
-
<slot></slot>
|
|
27
|
+
<slot v-bind="{ hide }"></slot>
|
|
19
28
|
</div>
|
|
20
29
|
</slot>
|
|
21
30
|
</ui-popover>
|
|
@@ -91,6 +100,9 @@ export default {
|
|
|
91
100
|
'data-popover': this.popoverTargetId,
|
|
92
101
|
};
|
|
93
102
|
},
|
|
103
|
+
visible() {
|
|
104
|
+
return this.popoverShow;
|
|
105
|
+
}
|
|
94
106
|
},
|
|
95
107
|
watch: {
|
|
96
108
|
show: {
|
|
@@ -109,7 +121,7 @@ export default {
|
|
|
109
121
|
if (val) {
|
|
110
122
|
this.popoverShow = true;
|
|
111
123
|
} else {
|
|
112
|
-
this.timeout = setTimeout(
|
|
124
|
+
this.timeout = setTimeout(this.hide, hideDelay);
|
|
113
125
|
}
|
|
114
126
|
},
|
|
115
127
|
onTargetMouseEnter(e) {
|
|
@@ -127,6 +139,13 @@ export default {
|
|
|
127
139
|
onPopoverMouseLeave(e) {
|
|
128
140
|
this.setShow(false);
|
|
129
141
|
},
|
|
142
|
+
hide() {
|
|
143
|
+
this.popoverShow = false;
|
|
144
|
+
/**
|
|
145
|
+
* Event emitted after tooltip is hidden
|
|
146
|
+
*/
|
|
147
|
+
this.$emit('hidden');
|
|
148
|
+
}
|
|
130
149
|
},
|
|
131
150
|
};
|
|
132
151
|
</script>
|
|
@@ -2,7 +2,7 @@ Simple example
|
|
|
2
2
|
```vue
|
|
3
3
|
<template>
|
|
4
4
|
<div class="pad-l5">
|
|
5
|
-
<ui-wysiwyg-editor v-model="model"></ui-wysiwyg-editor>
|
|
5
|
+
<ui-wysiwyg-editor v-model="model" :autofocus="false"></ui-wysiwyg-editor>
|
|
6
6
|
</div>
|
|
7
7
|
</template>
|
|
8
8
|
<script>
|
|
@@ -28,6 +28,7 @@ Advanced example. Using custom tool groups, bubble menu and 'change' event inste
|
|
|
28
28
|
value: model,
|
|
29
29
|
tools,
|
|
30
30
|
focusVisible: false,
|
|
31
|
+
autofocus: false,
|
|
31
32
|
bubbleMenu: { isEnabled: true}
|
|
32
33
|
}"
|
|
33
34
|
@change="onChange"></ui-wysiwyg-editor>
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
<div
|
|
16
16
|
v-for="({ title, group }, groupIndex) of toolGroups"
|
|
17
17
|
:key="groupIndex"
|
|
18
|
-
class="col col-
|
|
18
|
+
class="col col-vbot col-auto">
|
|
19
19
|
<div class="d-flex flex-col flex-v-center">
|
|
20
20
|
<div v-if="resolveGroupTitle(title, groupIndex) !== ''" class="group-header">
|
|
21
21
|
<!--
|
|
@@ -64,7 +64,7 @@ import { debounce } from '../utils/Helpers';
|
|
|
64
64
|
import Grid from '../Grid.vue';
|
|
65
65
|
import { resolveExtensions } from './extensions';
|
|
66
66
|
import { buildToolGroups, bindContext } from './utils';
|
|
67
|
-
import { DefaultTools } from './constants';
|
|
67
|
+
import { DefaultTools, WysiwygAutofocus } from './constants';
|
|
68
68
|
|
|
69
69
|
/**
|
|
70
70
|
* @typedef {Omit<import('@tiptap/extension-bubble-menu').BubbleMenuOptions, 'element'>} BubbleMenuOptions
|
|
@@ -119,6 +119,13 @@ export default {
|
|
|
119
119
|
focusVisible: {
|
|
120
120
|
type: Boolean,
|
|
121
121
|
default: true
|
|
122
|
+
},
|
|
123
|
+
/**
|
|
124
|
+
* whether to force the cursor to jump in the editor on initialization
|
|
125
|
+
*/
|
|
126
|
+
autofocus: {
|
|
127
|
+
type: [Boolean, String, Number],
|
|
128
|
+
default: WysiwygAutofocus.END
|
|
122
129
|
}
|
|
123
130
|
},
|
|
124
131
|
data: () => ({
|
|
@@ -174,20 +181,21 @@ export default {
|
|
|
174
181
|
this.onSelectionUpdateDebounced = debounce(this.onSelectionUpdate, 300);
|
|
175
182
|
},
|
|
176
183
|
mounted() {
|
|
177
|
-
const {
|
|
184
|
+
const { $refs, value, bubbleMenu, autofocus, editorClass, onSelectionUpdateDebounced } = this;
|
|
185
|
+
const { isEnabled: isBubbleMenuEnabled, ...bubbleMenuOptions } = bubbleMenu;
|
|
178
186
|
|
|
179
187
|
this.editor = new Editor({
|
|
180
|
-
content:
|
|
188
|
+
content: value,
|
|
181
189
|
extensions: resolveExtensions({
|
|
182
190
|
bubbleMenu: {
|
|
183
|
-
element: isBubbleMenuEnabled ?
|
|
191
|
+
element: isBubbleMenuEnabled ? $refs.menu : null,
|
|
184
192
|
...bubbleMenuOptions
|
|
185
193
|
}
|
|
186
194
|
}),
|
|
187
|
-
autofocus
|
|
195
|
+
autofocus,
|
|
188
196
|
editorProps: {
|
|
189
197
|
attributes: {
|
|
190
|
-
class:
|
|
198
|
+
class: editorClass,
|
|
191
199
|
style: 'min-height: 100%; height: 0;'
|
|
192
200
|
}
|
|
193
201
|
},
|
|
@@ -197,7 +205,7 @@ export default {
|
|
|
197
205
|
onBlur: () => {
|
|
198
206
|
this.onChange();
|
|
199
207
|
},
|
|
200
|
-
onSelectionUpdate:
|
|
208
|
+
onSelectionUpdate: onSelectionUpdateDebounced
|
|
201
209
|
});
|
|
202
210
|
},
|
|
203
211
|
activated() {
|
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
Image
|
|
10
10
|
} from './renders';
|
|
11
11
|
|
|
12
|
-
export type
|
|
12
|
+
export type WysiwygRender = Readonly<{
|
|
13
13
|
BUTTON: Button;
|
|
14
14
|
COLOR_PICKER: ColorPicker;
|
|
15
15
|
INPUT_UNITS: InputUnits;
|
|
@@ -127,6 +127,14 @@ export type ToolType = Readonly<{
|
|
|
127
127
|
INSERT_IMAGE: 'insertImage'
|
|
128
128
|
}>;
|
|
129
129
|
|
|
130
|
+
export type WysiwygAutofocus = Readonly<{
|
|
131
|
+
START: 'start',
|
|
132
|
+
END: 'end',
|
|
133
|
+
ALL: 'all',
|
|
134
|
+
ENABLED: true,
|
|
135
|
+
DISABLED: false
|
|
136
|
+
}>;
|
|
137
|
+
|
|
130
138
|
export type DefaultTools = Array<{
|
|
131
139
|
title: string,
|
|
132
140
|
group: Array<string|ITool>
|
|
@@ -14,7 +14,8 @@ import {
|
|
|
14
14
|
* @typedef {import('./constants').MarkType} MarkType
|
|
15
15
|
* @typedef {import('./constants').CommandType} CommandType
|
|
16
16
|
* @typedef {import('./constants').ToolType} ToolType
|
|
17
|
-
* @typedef {import('./constants').
|
|
17
|
+
* @typedef {import('./constants').WysiwygRender} WysiwygRender
|
|
18
|
+
* @typedef {import('./constants').WysiwygAutofocus} WysiwygAutofocus
|
|
18
19
|
* @typedef {import('./constants').ICommand} ICommand
|
|
19
20
|
* @typedef {import('./constants').ITool} ITool
|
|
20
21
|
*/
|
|
@@ -147,9 +148,9 @@ export const createCommand = ({
|
|
|
147
148
|
});
|
|
148
149
|
|
|
149
150
|
/**
|
|
150
|
-
* @type
|
|
151
|
+
* @type WysiwygRender
|
|
151
152
|
*/
|
|
152
|
-
export const
|
|
153
|
+
export const WysiwygRender = Object.freeze({
|
|
153
154
|
BUTTON: Button,
|
|
154
155
|
COLOR_PICKER: ColorPicker,
|
|
155
156
|
INPUT_UNITS: InputUnits,
|
|
@@ -166,7 +167,7 @@ export const Render = Object.freeze({
|
|
|
166
167
|
*/
|
|
167
168
|
export const createTool = ({
|
|
168
169
|
name = '',
|
|
169
|
-
render =
|
|
170
|
+
render = WysiwygRender.BUTTON,
|
|
170
171
|
title = 'Unknown tool',
|
|
171
172
|
icon = 'help-circle-outline',
|
|
172
173
|
exec = () => {},
|
|
@@ -184,6 +185,15 @@ export const createTool = ({
|
|
|
184
185
|
...optionalRest
|
|
185
186
|
});
|
|
186
187
|
|
|
188
|
+
/** @type WysiwygAutofocus */
|
|
189
|
+
export const WysiwygAutofocus = Object.freeze({
|
|
190
|
+
START: 'start',
|
|
191
|
+
END: 'end',
|
|
192
|
+
ALL: 'all',
|
|
193
|
+
ENABLED: true,
|
|
194
|
+
DISABLED: false
|
|
195
|
+
});
|
|
196
|
+
|
|
187
197
|
export const DefaultTools = [
|
|
188
198
|
{
|
|
189
199
|
title: 'Оформление',
|
|
@@ -1,111 +1,115 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<
|
|
3
|
-
<template #
|
|
2
|
+
<ui-tooltip @hidden="onHidden">
|
|
3
|
+
<template #target="{ binds, events, visible }">
|
|
4
4
|
<button
|
|
5
|
+
v-bind="binds"
|
|
6
|
+
v-on="events"
|
|
5
7
|
:title="title"
|
|
6
|
-
:class="{ 'btn-outline': !
|
|
8
|
+
:class="{ 'btn-outline': !visible }"
|
|
7
9
|
class="btn btn-small btn-icon btn-primary"
|
|
8
|
-
@click="
|
|
10
|
+
@click="onClick">
|
|
9
11
|
<div class="icon">
|
|
10
12
|
<i class="mdi" :class="icon"></i>
|
|
11
13
|
</div>
|
|
12
14
|
</button>
|
|
13
15
|
</template>
|
|
14
|
-
<
|
|
15
|
-
<div class="
|
|
16
|
-
<div class="
|
|
17
|
-
<div class="
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
<div class="
|
|
21
|
-
<
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
</div>
|
|
16
|
+
<div class="w-f2">
|
|
17
|
+
<div class="row row-hgap-3 mar-bot-l1">
|
|
18
|
+
<div class="col col-vmid text-truncate">
|
|
19
|
+
<div class="form-label form-label-xsmall text-truncate">Url</div>
|
|
20
|
+
</div>
|
|
21
|
+
<div class="col col-vmid col-12-12">
|
|
22
|
+
<div class="form-control form-control-icon-right w-12-12">
|
|
23
|
+
<input-autocomplete
|
|
24
|
+
v-model.trim.lazy="image.url"
|
|
25
|
+
:append-to-body="false"
|
|
26
|
+
size="small"
|
|
27
|
+
@change="onChange" />
|
|
28
|
+
<div class="icon" @click="browse">
|
|
29
|
+
<i class="mdi mdi-folder cursor-pointer color-grey" />
|
|
29
30
|
</div>
|
|
30
31
|
</div>
|
|
31
32
|
</div>
|
|
33
|
+
</div>
|
|
32
34
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
</div>
|
|
35
|
+
<div class="row row-hgap-3 mar-bot-l1">
|
|
36
|
+
<div class="col col-vmid text-truncate">
|
|
37
|
+
<label for="resp" class="form-label form-label-small text-truncate">
|
|
38
|
+
Отзывчивое изображение
|
|
39
|
+
</label>
|
|
40
|
+
</div>
|
|
41
|
+
<div class="col col-vmid col-auto">
|
|
42
|
+
<input
|
|
43
|
+
id="resp"
|
|
44
|
+
v-model="image.isResponsive"
|
|
45
|
+
type="checkbox"
|
|
46
|
+
class="switch switch-small pull-right"
|
|
47
|
+
@change="onChange">
|
|
47
48
|
</div>
|
|
49
|
+
</div>
|
|
48
50
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
51
|
+
<div class="row row-hgap-3 mar-bot-l1">
|
|
52
|
+
<div class="col col-vmid text-truncate">
|
|
53
|
+
<label class="form-label form-label-xsmall text-truncate">
|
|
54
|
+
Выровнять изображение
|
|
55
|
+
</label>
|
|
56
|
+
</div>
|
|
57
|
+
<div class="col col-vmid col-12-12">
|
|
58
|
+
<ui-select
|
|
59
|
+
v-model="image.align"
|
|
60
|
+
:options="$options.static.AlignOptions"
|
|
61
|
+
:append-to-body="false"
|
|
62
|
+
size="small"
|
|
63
|
+
class="w-100"
|
|
64
|
+
@change="onChange" />
|
|
63
65
|
</div>
|
|
66
|
+
</div>
|
|
64
67
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
</
|
|
68
|
+
<div class="row row-hgap-l1">
|
|
69
|
+
<div class="col">
|
|
70
|
+
<div class="row row-hgap-3">
|
|
71
|
+
<div class="col col-vmid text-truncate">
|
|
72
|
+
<div class="form-label form-label-xsmall text-truncate">Ширина</div>
|
|
73
|
+
</div>
|
|
74
|
+
<div class="col col-vmid col-12-12">
|
|
75
|
+
<input-units
|
|
76
|
+
v-model="image.width"
|
|
77
|
+
:units="$options.static.SizeUnits"
|
|
78
|
+
:disabled="image.isResponsive"
|
|
79
|
+
:append-to-body="false"
|
|
80
|
+
size="small"
|
|
81
|
+
@change="onChange">
|
|
82
|
+
</input-units>
|
|
80
83
|
</div>
|
|
81
84
|
</div>
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
85
|
+
</div>
|
|
86
|
+
<div class="col">
|
|
87
|
+
<div class="row row-hgap-3">
|
|
88
|
+
<div class="col col-vmid text-truncate">
|
|
89
|
+
<div class="form-label form-label-xsmall text-truncate">Высота</div>
|
|
90
|
+
</div>
|
|
91
|
+
<div class="col col-vmid col-12-12">
|
|
92
|
+
<input-units
|
|
93
|
+
v-model="image.height"
|
|
94
|
+
:units="$options.static.SizeUnits"
|
|
95
|
+
:disabled="image.isResponsive"
|
|
96
|
+
:append-to-body="false"
|
|
97
|
+
size="small"
|
|
98
|
+
@change="onChange">
|
|
99
|
+
</input-units>
|
|
96
100
|
</div>
|
|
97
101
|
</div>
|
|
98
102
|
</div>
|
|
99
103
|
</div>
|
|
100
|
-
</
|
|
101
|
-
</
|
|
104
|
+
</div>
|
|
105
|
+
</ui-tooltip>
|
|
102
106
|
</template>
|
|
103
107
|
|
|
104
108
|
<script>
|
|
105
109
|
import InputAutocomplete from '../../InputAutocomplete.vue';
|
|
106
110
|
import InputUnits from '../../InputUnits.vue';
|
|
107
111
|
import UiSelect from '../../Select.vue';
|
|
108
|
-
import
|
|
112
|
+
import UiTooltip from './components/Tooltip.vue';
|
|
109
113
|
import { useRender, RenderMixinTypes } from './mixins';
|
|
110
114
|
|
|
111
115
|
const SizeUnits = ['rem', 'em', '%', 'px', 'vh', 'vw'];
|
|
@@ -141,29 +145,21 @@ export default {
|
|
|
141
145
|
InputAutocomplete,
|
|
142
146
|
InputUnits,
|
|
143
147
|
UiSelect,
|
|
144
|
-
|
|
148
|
+
UiTooltip
|
|
145
149
|
},
|
|
146
150
|
mixins: [useRender()],
|
|
147
151
|
data: () => ({
|
|
148
|
-
isPopoverShown: false,
|
|
149
152
|
image: { ...defaultImgSettings }
|
|
150
153
|
}),
|
|
151
|
-
watch: {
|
|
152
|
-
isPopoverShown(isShown) {
|
|
153
|
-
if (isShown === false) {
|
|
154
|
-
this.image = { ...defaultImgSettings };
|
|
155
|
-
return;
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
this.setImageSettings();
|
|
159
|
-
}
|
|
160
|
-
},
|
|
161
154
|
static: {
|
|
162
155
|
SizeUnits,
|
|
163
156
|
AlignOptions
|
|
164
157
|
},
|
|
165
158
|
methods: {
|
|
166
159
|
...RenderMixinTypes,
|
|
160
|
+
onClick() {
|
|
161
|
+
this.setImageSettings();
|
|
162
|
+
},
|
|
167
163
|
setImageSettings() {
|
|
168
164
|
const attrs = this.tool.getValue();
|
|
169
165
|
|
|
@@ -184,21 +180,18 @@ export default {
|
|
|
184
180
|
...(height && { height })
|
|
185
181
|
};
|
|
186
182
|
},
|
|
187
|
-
async browse(
|
|
188
|
-
/* to avoid overlap with FileManager's popup */
|
|
189
|
-
togglePopover();
|
|
190
|
-
|
|
183
|
+
async browse() {
|
|
191
184
|
await this.tool.exec(this.image);
|
|
192
185
|
const { src: url } = this.tool.getValue();
|
|
193
|
-
|
|
194
186
|
this.image = { ...this.image, url };
|
|
195
187
|
this.emitExecuted();
|
|
196
|
-
|
|
197
|
-
togglePopover();
|
|
198
188
|
},
|
|
199
189
|
onChange() {
|
|
200
190
|
this.tool.exec(this.image);
|
|
201
191
|
this.emitExecuted();
|
|
192
|
+
},
|
|
193
|
+
onHidden() {
|
|
194
|
+
this.image = { ...defaultImgSettings };
|
|
202
195
|
}
|
|
203
196
|
}
|
|
204
197
|
};
|
|
@@ -1,44 +1,53 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<
|
|
3
|
-
<template #
|
|
2
|
+
<ui-tooltip>
|
|
3
|
+
<template #target="{ binds, events, visible }">
|
|
4
4
|
<button
|
|
5
|
+
v-bind="binds"
|
|
6
|
+
v-on="events"
|
|
5
7
|
:title="title"
|
|
6
|
-
:class="{ 'btn-outline': !
|
|
8
|
+
:class="{ 'btn-outline': !visible }"
|
|
7
9
|
class="btn btn-small btn-icon btn-primary"
|
|
8
|
-
@click="
|
|
10
|
+
@click="onClick">
|
|
9
11
|
<div class="icon">
|
|
10
12
|
<i class="mdi" :class="icon"></i>
|
|
11
13
|
</div>
|
|
12
14
|
</button>
|
|
13
15
|
</template>
|
|
14
|
-
<
|
|
15
|
-
<div class="
|
|
16
|
-
<div class="
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
<div class="
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
16
|
+
<template #default="{ hide }">
|
|
17
|
+
<div class="w-f2">
|
|
18
|
+
<div class="row row-hgap-3 mar-bot-l1">
|
|
19
|
+
<div class="col col-vmid text-truncate">
|
|
20
|
+
<div class="form-label form-label-xsmall text-truncate">Url</div>
|
|
21
|
+
</div>
|
|
22
|
+
<div class="col col-vmid col-12-12">
|
|
23
|
+
<ui-input-autocomplete v-model="url" class="w-100" size="small" />
|
|
24
|
+
</div>
|
|
25
|
+
</div>
|
|
26
|
+
<div class="row row-hgap-3 mar-bot-l1">
|
|
27
|
+
<div class="col col-vmid text-truncate">
|
|
28
|
+
<div class="form-label form-label-xsmall text-truncate">Target</div>
|
|
29
|
+
</div>
|
|
30
|
+
<div class="col col-vmid col-12-12">
|
|
31
|
+
<ui-select
|
|
32
|
+
v-model="target"
|
|
33
|
+
:append-to-body="false"
|
|
34
|
+
:options="$options.static.TargetTypeOptions"
|
|
35
|
+
class="w-100"
|
|
36
|
+
size="small" />
|
|
37
|
+
</div>
|
|
38
|
+
</div>
|
|
39
|
+
<button class="btn btn-primary btn-small w-100" @click="() => execute(hide)">
|
|
40
|
+
Применить
|
|
41
|
+
</button>
|
|
32
42
|
</div>
|
|
33
|
-
</
|
|
34
|
-
|
|
35
|
-
</with-popover>
|
|
43
|
+
</template>
|
|
44
|
+
</ui-tooltip>
|
|
36
45
|
</template>
|
|
37
46
|
|
|
38
47
|
<script>
|
|
39
|
-
import
|
|
48
|
+
import UiInputAutocomplete from '../../InputAutocomplete.vue';
|
|
40
49
|
import UiSelect from '../../Select.vue';
|
|
41
|
-
import
|
|
50
|
+
import UiTooltip from './components/Tooltip.vue';
|
|
42
51
|
import { useRender, RenderMixinTypes } from './mixins';
|
|
43
52
|
|
|
44
53
|
const TargetType = {
|
|
@@ -48,15 +57,14 @@ const TargetType = {
|
|
|
48
57
|
|
|
49
58
|
export default {
|
|
50
59
|
components: {
|
|
51
|
-
|
|
52
|
-
|
|
60
|
+
UiInputAutocomplete,
|
|
61
|
+
UiTooltip,
|
|
53
62
|
UiSelect
|
|
54
63
|
},
|
|
55
64
|
mixins: [useRender()],
|
|
56
65
|
data: () => ({
|
|
57
66
|
url: '',
|
|
58
67
|
target: null,
|
|
59
|
-
isPopoverShown: false
|
|
60
68
|
}),
|
|
61
69
|
static: {
|
|
62
70
|
TargetTypeOptions: [
|
|
@@ -64,22 +72,17 @@ export default {
|
|
|
64
72
|
{ label: 'self', value: TargetType.SELF }
|
|
65
73
|
]
|
|
66
74
|
},
|
|
67
|
-
watch: {
|
|
68
|
-
isPopoverShown(isShown) {
|
|
69
|
-
if (isShown) {
|
|
70
|
-
const { url = '', target = TargetType.BLANK } = this.tool.getValue();
|
|
71
|
-
this.url = url;
|
|
72
|
-
this.target = target;
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
},
|
|
76
75
|
methods: {
|
|
77
76
|
...RenderMixinTypes,
|
|
78
|
-
|
|
77
|
+
onClick () {
|
|
78
|
+
const { url = '', target = TargetType.BLANK } = this.tool.getValue();
|
|
79
|
+
this.url = url;
|
|
80
|
+
this.target = target;
|
|
81
|
+
},
|
|
82
|
+
execute(hide) {
|
|
79
83
|
const { tool, url, target } = this;
|
|
80
84
|
tool.exec({ url, target });
|
|
81
|
-
|
|
82
|
-
this.isPopoverShown = false;
|
|
85
|
+
hide();
|
|
83
86
|
this.emitExecuted();
|
|
84
87
|
}
|
|
85
88
|
}
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
<i class="mdi" :class="icon"></i>
|
|
9
9
|
</div>
|
|
10
10
|
</button>
|
|
11
|
-
<popover :show.sync="popoverShow" v-bind="popoverOptions">
|
|
11
|
+
<popover :show.sync="popoverShow" v-bind="popoverOptions" position="bottom-end">
|
|
12
12
|
<ui-datalist
|
|
13
13
|
class="w-100 pull-left"
|
|
14
14
|
v-bind="{ size: 'small', options: tool.options }"
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<tooltip
|
|
3
|
+
v-bind="$attrs"
|
|
4
|
+
position="bottom"
|
|
5
|
+
trigger-on="click"
|
|
6
|
+
:hide-delay="450"
|
|
7
|
+
:append-to-body="false"
|
|
8
|
+
@hidden="$emit('hidden')">
|
|
9
|
+
<template #target="{ binds, events, visible }">
|
|
10
|
+
<slot name="target" v-bind="{ binds, events, visible }"></slot>
|
|
11
|
+
</template>
|
|
12
|
+
<template #tooltip="{ hide }">
|
|
13
|
+
<div class="panel">
|
|
14
|
+
<div class="panel-body">
|
|
15
|
+
<div class="close pos-abs pos-top-right mar-2" @click="hide">
|
|
16
|
+
<i class="mdi mdi-close color-grey" />
|
|
17
|
+
</div>
|
|
18
|
+
<slot v-bind="{ hide }"></slot>
|
|
19
|
+
</div>
|
|
20
|
+
</div>
|
|
21
|
+
</template>
|
|
22
|
+
</tooltip>
|
|
23
|
+
</template>
|
|
24
|
+
|
|
25
|
+
<script>
|
|
26
|
+
import Tooltip from '../../../Tooltip.vue';
|
|
27
|
+
|
|
28
|
+
export default {
|
|
29
|
+
components: { Tooltip }
|
|
30
|
+
};
|
|
31
|
+
</script>
|
|
@@ -3,7 +3,7 @@ import {
|
|
|
3
3
|
MarkType,
|
|
4
4
|
CommandType,
|
|
5
5
|
ToolType,
|
|
6
|
-
|
|
6
|
+
WysiwygRender,
|
|
7
7
|
createTool,
|
|
8
8
|
createCommand,
|
|
9
9
|
} from './constants';
|
|
@@ -409,7 +409,7 @@ export const ToolsMap = {
|
|
|
409
409
|
}),
|
|
410
410
|
[ToolType.PARAGRAPH_STYLE]: createTool({
|
|
411
411
|
name: ToolType.PARAGRAPH_STYLE,
|
|
412
|
-
render:
|
|
412
|
+
render: WysiwygRender.SELECT,
|
|
413
413
|
title: 'Стиль параграфа',
|
|
414
414
|
exec(command) {
|
|
415
415
|
if (command.name in CommandMap && command.isEnabled()) {
|
|
@@ -432,7 +432,7 @@ export const ToolsMap = {
|
|
|
432
432
|
}),
|
|
433
433
|
[ToolType.FONT_SIZE]: createTool({
|
|
434
434
|
name: ToolType.FONT_SIZE,
|
|
435
|
-
render:
|
|
435
|
+
render: WysiwygRender.INPUT_UNITS,
|
|
436
436
|
title: 'Размер шрифта',
|
|
437
437
|
exec(value) {
|
|
438
438
|
this.editor.commands.setFontSize(value);
|
|
@@ -453,7 +453,7 @@ export const ToolsMap = {
|
|
|
453
453
|
}),
|
|
454
454
|
[ToolType.TEXT_COLOR]: createTool({
|
|
455
455
|
name: ToolType.TEXT_COLOR,
|
|
456
|
-
render:
|
|
456
|
+
render: WysiwygRender.COLOR_PICKER,
|
|
457
457
|
icon: 'format-color-fill',
|
|
458
458
|
title: 'Цвет',
|
|
459
459
|
exec(value) {
|
|
@@ -465,7 +465,7 @@ export const ToolsMap = {
|
|
|
465
465
|
}),
|
|
466
466
|
[ToolType.FONT_FAMILY]: createTool({
|
|
467
467
|
name: ToolType.FONT_FAMILY,
|
|
468
|
-
render:
|
|
468
|
+
render: WysiwygRender.INPUT_AUTO,
|
|
469
469
|
title: 'Семейство шрифта',
|
|
470
470
|
exec(value) {
|
|
471
471
|
this.editor.commands.setFontFamily(value);
|
|
@@ -511,7 +511,7 @@ export const ToolsMap = {
|
|
|
511
511
|
}),
|
|
512
512
|
[ToolType.IMAGE]: createTool({
|
|
513
513
|
name: ToolType.IMAGE,
|
|
514
|
-
render:
|
|
514
|
+
render: WysiwygRender.IMAGE,
|
|
515
515
|
icon: 'image-plus',
|
|
516
516
|
title: 'Изображение',
|
|
517
517
|
async exec({ url = null, isResponsive, align, width, height }) {
|
|
@@ -615,7 +615,7 @@ export const ToolsMap = {
|
|
|
615
615
|
}),
|
|
616
616
|
[ToolType.LINK]: createTool({
|
|
617
617
|
name: ToolType.LINK,
|
|
618
|
-
render:
|
|
618
|
+
render: WysiwygRender.LINK,
|
|
619
619
|
icon: 'link-plus',
|
|
620
620
|
title: 'Ссылка',
|
|
621
621
|
getValue() {
|
|
@@ -694,7 +694,7 @@ export const ToolsMap = {
|
|
|
694
694
|
}),
|
|
695
695
|
[ToolType.TABLE]: createTool({
|
|
696
696
|
name: ToolType.TABLE,
|
|
697
|
-
render:
|
|
697
|
+
render: WysiwygRender.TOOLBAR_POPOVER,
|
|
698
698
|
icon: 'table-plus',
|
|
699
699
|
title: 'таблица',
|
|
700
700
|
options: Object.values(TableOptionsMap)
|
package/vue.config.js
CHANGED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
<script>
|
|
2
|
-
import Popover from '../../../Popover.vue';
|
|
3
|
-
|
|
4
|
-
export default {
|
|
5
|
-
extends: Popover,
|
|
6
|
-
methods: {
|
|
7
|
-
addEventListeners() {
|
|
8
|
-
window.addEventListener('blur', this.onWinBlur);
|
|
9
|
-
},
|
|
10
|
-
removeEventListeners() {
|
|
11
|
-
window.removeEventListener('blur', this.onWinBlur);
|
|
12
|
-
}
|
|
13
|
-
}
|
|
14
|
-
};
|
|
15
|
-
</script>
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
<template>
|
|
2
|
-
<div :data-popover="popoverTargetId">
|
|
3
|
-
<slot name="button" v-bind="{ togglePopover }"></slot>
|
|
4
|
-
|
|
5
|
-
<popover :show.sync="popoverShow" v-bind="popoverOptions">
|
|
6
|
-
<div class="dropdown pad-l1 pad-top-l2">
|
|
7
|
-
<div class="close pos-abs pos-top-right mar-2" @click="togglePopover">
|
|
8
|
-
<i class="mdi mdi-close color-grey" />
|
|
9
|
-
</div>
|
|
10
|
-
<slot v-bind="{ togglePopover }"></slot>
|
|
11
|
-
</div>
|
|
12
|
-
</popover>
|
|
13
|
-
</div>
|
|
14
|
-
</template>
|
|
15
|
-
|
|
16
|
-
<script>
|
|
17
|
-
import WithPopover from '../../../utils/WithPopover';
|
|
18
|
-
import Popover from './Popover.vue';
|
|
19
|
-
|
|
20
|
-
export default {
|
|
21
|
-
components: { Popover },
|
|
22
|
-
mixins: [WithPopover],
|
|
23
|
-
props: {
|
|
24
|
-
show: {
|
|
25
|
-
type: Boolean,
|
|
26
|
-
default: false
|
|
27
|
-
}
|
|
28
|
-
},
|
|
29
|
-
watch: {
|
|
30
|
-
popoverShow(val) {
|
|
31
|
-
this.$nextTick(() => this.$emit('update:show', val));
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
};
|
|
35
|
-
</script>
|