glib-web 2.1.0 → 2.2.0
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.
|
@@ -1,34 +1,53 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div :style="$styles()" :class="$classes()">
|
|
3
|
+
<v-tabs v-model="mode" fixed-tabs>
|
|
4
|
+
<v-tab>Editor</v-tab>
|
|
5
|
+
<v-tab>Code</v-tab>
|
|
6
|
+
</v-tabs>
|
|
7
|
+
|
|
3
8
|
<v-progress-linear v-if="showProgress" v-model="progress.value" />
|
|
9
|
+
|
|
10
|
+
<!-- Remove the editor to avoid circular updating between this editor and the raw field. -->
|
|
4
11
|
<VueEditor
|
|
5
|
-
v-
|
|
12
|
+
v-if="!rawMode"
|
|
13
|
+
id="rich-editor"
|
|
14
|
+
v-model="htmlValue"
|
|
6
15
|
:editor-toolbar="customToolbar"
|
|
7
16
|
use-custom-image-handler
|
|
8
|
-
@text-change="
|
|
17
|
+
@text-change="onEditorChange"
|
|
9
18
|
@image-added="uploadImage"
|
|
10
19
|
/>
|
|
11
|
-
|
|
12
|
-
<
|
|
13
|
-
v-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
20
|
+
<!-- Hide these fields but don't remove them because these are the values that will get submitted. -->
|
|
21
|
+
<div :style="{ display: rawMode ? 'block' : 'none' }">
|
|
22
|
+
<v-textarea
|
|
23
|
+
id="raw-editor"
|
|
24
|
+
v-model="producedValue"
|
|
25
|
+
:name="spec.name"
|
|
26
|
+
:style="$styles()"
|
|
27
|
+
:class="$classes()"
|
|
28
|
+
:outlined="$classes().includes('outlined')"
|
|
29
|
+
@input="onCodeChange"
|
|
30
|
+
></v-textarea>
|
|
31
|
+
<v-text-field
|
|
32
|
+
v-for="(imageKey, index) in imageKeys"
|
|
33
|
+
:key="index"
|
|
34
|
+
:label="`Image ${index + 1}`"
|
|
35
|
+
:style="$styles()"
|
|
36
|
+
:outlined="$classes().includes('outlined')"
|
|
37
|
+
type="text"
|
|
38
|
+
:name="imageUploader.name"
|
|
39
|
+
:value="images[imageKey]"
|
|
40
|
+
/>
|
|
41
|
+
</div>
|
|
19
42
|
</div>
|
|
20
43
|
</template>
|
|
21
44
|
|
|
22
45
|
<script>
|
|
23
46
|
import Uploader from "../../utils/uploader";
|
|
24
|
-
import { VueEditor } from "vue2-editor";
|
|
47
|
+
import { VueEditor, Quill } from "vue2-editor";
|
|
25
48
|
import TurndownService from "turndown";
|
|
26
49
|
import { gfm } from "turndown-plugin-gfm";
|
|
27
50
|
|
|
28
|
-
// import EventController, {
|
|
29
|
-
// DISABLE_SUBMIT_BUTTON
|
|
30
|
-
// } from "../../utils/global-event-controller";
|
|
31
|
-
|
|
32
51
|
export default {
|
|
33
52
|
components: { VueEditor },
|
|
34
53
|
props: {
|
|
@@ -41,26 +60,52 @@ export default {
|
|
|
41
60
|
[{ list: "ordered" }, { list: "bullet" }],
|
|
42
61
|
["image", "link"]
|
|
43
62
|
],
|
|
44
|
-
|
|
45
|
-
cleanValue:
|
|
63
|
+
htmlValue: "",
|
|
64
|
+
cleanValue: null,
|
|
65
|
+
producedValue: "",
|
|
46
66
|
images: {},
|
|
47
67
|
imageKeys: [],
|
|
48
68
|
progress: { value: -1 },
|
|
49
69
|
imageUploader: {},
|
|
50
|
-
produce:
|
|
70
|
+
produce: null,
|
|
71
|
+
mode: null,
|
|
51
72
|
turndownService: new TurndownService({ headingStyle: "atx" })
|
|
52
73
|
}),
|
|
53
74
|
computed: {
|
|
54
|
-
showProgress
|
|
75
|
+
showProgress() {
|
|
55
76
|
return this.progress.value >= 0;
|
|
56
77
|
},
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
78
|
+
rawMode() {
|
|
79
|
+
return this.mode == 1;
|
|
80
|
+
}
|
|
81
|
+
},
|
|
82
|
+
watch: {
|
|
83
|
+
cleanValue(val, oldVal) {
|
|
84
|
+
if (oldVal == null) {
|
|
85
|
+
// Don't update `producedValue` if this is first-time initialization to preserve the original value.
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
switch (this.produce) {
|
|
89
|
+
case "html":
|
|
90
|
+
this.producedValue = val;
|
|
91
|
+
break;
|
|
92
|
+
case "markdown":
|
|
93
|
+
this.producedValue = this.turndownService.turndown(val);
|
|
94
|
+
break;
|
|
95
|
+
default:
|
|
96
|
+
console.log(`Unsupported format: ${this.produce}`);
|
|
97
|
+
}
|
|
98
|
+
},
|
|
99
|
+
producedValue(val) {
|
|
100
|
+
switch (this.produce) {
|
|
101
|
+
case "html":
|
|
102
|
+
this.htmlValue = val;
|
|
103
|
+
break;
|
|
104
|
+
case "markdown":
|
|
105
|
+
this.htmlValue = this.toHtmlValue(val);
|
|
106
|
+
break;
|
|
107
|
+
default:
|
|
108
|
+
console.log(`Unsupported format: ${this.produce}`);
|
|
64
109
|
}
|
|
65
110
|
}
|
|
66
111
|
},
|
|
@@ -69,6 +114,8 @@ export default {
|
|
|
69
114
|
},
|
|
70
115
|
methods: {
|
|
71
116
|
$ready() {
|
|
117
|
+
this.produce = this.spec.produce || "markdown";
|
|
118
|
+
|
|
72
119
|
this.turndownService.use(gfm);
|
|
73
120
|
this.turndownService.addRule("strikethrough", {
|
|
74
121
|
filter: ["del", "s", "strike"],
|
|
@@ -77,29 +124,39 @@ export default {
|
|
|
77
124
|
}
|
|
78
125
|
});
|
|
79
126
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
const image = vm.spec.images[index - 1];
|
|
85
|
-
if (
|
|
86
|
-
image &&
|
|
87
|
-
vm.$type.isString(image.value) &&
|
|
88
|
-
vm.$type.isString(image.fileUrl)
|
|
89
|
-
) {
|
|
90
|
-
const url = image.fileUrl;
|
|
91
|
-
const key = url.hashCode().toString();
|
|
92
|
-
vm.images[key] = image.value;
|
|
93
|
-
return url;
|
|
94
|
-
}
|
|
95
|
-
return "{{IMAGE_NOT_FOUND}}";
|
|
127
|
+
this.turndownService.addRule("codeblock", {
|
|
128
|
+
filter: ["pre"],
|
|
129
|
+
replacement: function(content) {
|
|
130
|
+
return "```\n" + content + "```";
|
|
96
131
|
}
|
|
97
|
-
);
|
|
132
|
+
});
|
|
98
133
|
|
|
99
134
|
this.imageUploader = this.spec.imageUploader;
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
135
|
+
|
|
136
|
+
// Convert initial markdown value to html for displaying.
|
|
137
|
+
this.producedValue = this.spec.value || "";
|
|
138
|
+
this.htmlValue = this.toHtmlValue(this.producedValue);
|
|
139
|
+
},
|
|
140
|
+
toHtmlValue(producedValue) {
|
|
141
|
+
const vm = this;
|
|
142
|
+
var value = producedValue.replace(/\{\{image([0-9]+)\}\}/g, function(
|
|
143
|
+
_,
|
|
144
|
+
index
|
|
145
|
+
) {
|
|
146
|
+
const image = vm.spec.images[index - 1];
|
|
147
|
+
if (
|
|
148
|
+
image &&
|
|
149
|
+
vm.$type.isString(image.value) &&
|
|
150
|
+
vm.$type.isString(image.fileUrl)
|
|
151
|
+
) {
|
|
152
|
+
const url = image.fileUrl;
|
|
153
|
+
const key = url.hashCode().toString();
|
|
154
|
+
vm.images[key] = image.value;
|
|
155
|
+
return url;
|
|
156
|
+
}
|
|
157
|
+
return "{{IMAGE_NOT_FOUND}}";
|
|
158
|
+
});
|
|
159
|
+
return this.produce == "markdown" ? Utils.format.markdown(value) : value;
|
|
103
160
|
},
|
|
104
161
|
uploadImage: function(file, editor, cursorLocation) {
|
|
105
162
|
let vm = this;
|
|
@@ -127,9 +184,11 @@ export default {
|
|
|
127
184
|
});
|
|
128
185
|
}
|
|
129
186
|
},
|
|
130
|
-
|
|
187
|
+
onEditorChange() {
|
|
131
188
|
this.separateOutImages();
|
|
132
|
-
|
|
189
|
+
this.onCodeChange();
|
|
190
|
+
},
|
|
191
|
+
onCodeChange() {
|
|
133
192
|
Utils.type.ifObject(this.spec.onChange, onChange => {
|
|
134
193
|
this.$nextTick(() => {
|
|
135
194
|
const params = {
|
|
@@ -148,7 +207,7 @@ export default {
|
|
|
148
207
|
var index = 0;
|
|
149
208
|
vm.imageKeys.clear();
|
|
150
209
|
// TODO: Fix to avoid replacing <video src="">
|
|
151
|
-
this.cleanValue = this.
|
|
210
|
+
this.cleanValue = this.htmlValue.replace(/src="([^"]+)"/g, function(
|
|
152
211
|
_,
|
|
153
212
|
imageValue
|
|
154
213
|
) {
|
|
@@ -220,9 +279,13 @@ export default {
|
|
|
220
279
|
height: 375px;
|
|
221
280
|
}
|
|
222
281
|
*/
|
|
223
|
-
.ql-toolbar.sticky {
|
|
282
|
+
/* .ql-toolbar.sticky {
|
|
224
283
|
position: fixed;
|
|
225
284
|
z-index: 99;
|
|
226
285
|
background-color: white;
|
|
286
|
+
} */
|
|
287
|
+
#rich-editor,
|
|
288
|
+
#raw-editor {
|
|
289
|
+
height: 350px;
|
|
227
290
|
}
|
|
228
291
|
</style>
|
package/components/markdown.vue
CHANGED
|
@@ -61,6 +61,15 @@ export default {
|
|
|
61
61
|
& > span > :last-child {
|
|
62
62
|
margin-bottom: 0;
|
|
63
63
|
}
|
|
64
|
+
pre {
|
|
65
|
+
background-color: #f0f0f0;
|
|
66
|
+
padding: 8px 10px;
|
|
67
|
+
|
|
68
|
+
& > code {
|
|
69
|
+
background-color: transparent;
|
|
70
|
+
padding: 0;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
64
73
|
}
|
|
65
74
|
.line-clamp {
|
|
66
75
|
display: -webkit-box;
|
|
@@ -20,6 +20,17 @@ export default {
|
|
|
20
20
|
v => (v ? true : spec.message)
|
|
21
21
|
]);
|
|
22
22
|
});
|
|
23
|
+
Utils.type.ifObject(val.format, spec => {
|
|
24
|
+
augmentedRules = augmentedRules.concat([
|
|
25
|
+
v => {
|
|
26
|
+
console.log("VALIDATE1");
|
|
27
|
+
if (v && !v.match(spec.regex)) {
|
|
28
|
+
return spec.message;
|
|
29
|
+
}
|
|
30
|
+
return true;
|
|
31
|
+
}
|
|
32
|
+
]);
|
|
33
|
+
});
|
|
23
34
|
});
|
|
24
35
|
return augmentedRules;
|
|
25
36
|
},
|