@mixd-id/web-scaffold 0.1.230406002 → 0.1.230406004
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 +1 -1
- package/src/components/HTMLEditor.vue +111 -42
- package/src/components/ListPage1.vue +3 -2
- package/src/utils/helpers.js +24 -1
- package/src/utils/helpers.mjs +1 -1
- package/src/utils/selection.js +4 -1
package/package.json
CHANGED
|
@@ -26,6 +26,9 @@
|
|
|
26
26
|
<button class="p-3" type="button" @click="createLink">
|
|
27
27
|
<svg width="14" height="14" class="fill-text-400 hover:fill-primary" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 512"><path d="M579.8 267.7c56.5-56.5 56.5-148 0-204.5c-50-50-128.8-56.5-186.3-15.4l-1.6 1.1c-14.4 10.3-17.7 30.3-7.4 44.6s30.3 17.7 44.6 7.4l1.6-1.1c32.1-22.9 76-19.3 103.8 8.6c31.5 31.5 31.5 82.5 0 114L422.3 334.8c-31.5 31.5-82.5 31.5-114 0c-27.9-27.9-31.5-71.8-8.6-103.8l1.1-1.6c10.3-14.4 6.9-34.4-7.4-44.6s-34.4-6.9-44.6 7.4l-1.1 1.6C206.5 251.2 213 330 263 380c56.5 56.5 148 56.5 204.5 0L579.8 267.7zM60.2 244.3c-56.5 56.5-56.5 148 0 204.5c50 50 128.8 56.5 186.3 15.4l1.6-1.1c14.4-10.3 17.7-30.3 7.4-44.6s-30.3-17.7-44.6-7.4l-1.6 1.1c-32.1 22.9-76 19.3-103.8-8.6C74 372 74 321 105.5 289.5L217.7 177.2c31.5-31.5 82.5-31.5 114 0c27.9 27.9 31.5 71.8 8.6 103.9l-1.1 1.6c-10.3 14.4-6.9 34.4 7.4 44.6s34.4 6.9 44.6-7.4l1.1-1.6C433.5 260.8 427 182 377 132c-56.5-56.5-148-56.5-204.5 0L60.2 244.3z"/></svg>
|
|
28
28
|
</button>
|
|
29
|
+
<button class="p-3" type="button" @click="removeFormat">
|
|
30
|
+
<svg width="14" height="14" class="fill-text-400 hover:fill-primary" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 384 512"><path d="M342.6 150.6c12.5-12.5 12.5-32.8 0-45.3s-32.8-12.5-45.3 0L192 210.7 86.6 105.4c-12.5-12.5-32.8-12.5-45.3 0s-12.5 32.8 0 45.3L146.7 256 41.4 361.4c-12.5 12.5-12.5 32.8 0 45.3s32.8 12.5 45.3 0L192 301.3 297.4 406.6c12.5 12.5 32.8 12.5 45.3 0s12.5-32.8 0-45.3L237.3 256 342.6 150.6z"/></svg>
|
|
31
|
+
</button>
|
|
29
32
|
</div>
|
|
30
33
|
|
|
31
34
|
<ContextMenu ref="headingContext">
|
|
@@ -105,7 +108,7 @@
|
|
|
105
108
|
</template>
|
|
106
109
|
<div class="flex-1 flex flex-col gap-5 p-5">
|
|
107
110
|
<div>
|
|
108
|
-
<Image class="min-h-[100px] bg-base-300 rounded-xl" ref="image" :src="newImage.
|
|
111
|
+
<Image class="min-h-[100px] bg-base-300 rounded-xl" ref="image" :src="newImage.src" editable="true"
|
|
109
112
|
@click="$refs.image.edit()" @change="onImageChanged">
|
|
110
113
|
<template #empty="{ instance }">
|
|
111
114
|
<div class="absolute right-0 top-0 bottom-0 left-0 flex items-center justify-center">
|
|
@@ -135,7 +138,7 @@
|
|
|
135
138
|
</div>
|
|
136
139
|
</Modal>
|
|
137
140
|
|
|
138
|
-
<Modal ref="linkModal" width="360" height="
|
|
141
|
+
<Modal ref="linkModal" width="360" height="400" dismissable="true">
|
|
139
142
|
<template v-slot:head>
|
|
140
143
|
<div class="relative p-5">
|
|
141
144
|
<h3>Add Link</h3>
|
|
@@ -149,8 +152,9 @@
|
|
|
149
152
|
</div>
|
|
150
153
|
</template>
|
|
151
154
|
<template v-slot:foot>
|
|
152
|
-
<div class="p-5">
|
|
153
|
-
<Button class="w-
|
|
155
|
+
<div class="p-5 flex flex-row gap-3">
|
|
156
|
+
<Button variant="secondary" class="w-[100px]" :disabled="!linkCanSave" @click="removeLink">Remove</Button>
|
|
157
|
+
<Button class="flex-1" :disabled="!linkCanSave" @click="addLink">Add Link</Button>
|
|
154
158
|
</div>
|
|
155
159
|
</template>
|
|
156
160
|
<div class="flex-1 flex flex-col gap-5 p-5">
|
|
@@ -174,8 +178,8 @@
|
|
|
174
178
|
</div>
|
|
175
179
|
</Modal>
|
|
176
180
|
|
|
177
|
-
<article ref="article" contenteditable="true" v-html="html" @paste="onPaste"
|
|
178
|
-
@input="onInput"
|
|
181
|
+
<article ref="article" contenteditable="true" v-html="html" @paste="onPaste" spellcheck="false"
|
|
182
|
+
@input="onInput" @click="onClick"
|
|
179
183
|
@blur="onBlur">
|
|
180
184
|
</article>
|
|
181
185
|
|
|
@@ -184,13 +188,16 @@
|
|
|
184
188
|
|
|
185
189
|
<script>
|
|
186
190
|
|
|
187
|
-
import * as Vue from "vue/dist/vue.esm-bundler";
|
|
188
191
|
import {restoreSelection, saveSelection} from "../utils/selection";
|
|
189
192
|
import {downsizeImage} from "../utils/helpers.mjs";
|
|
190
193
|
import axios from "axios";
|
|
191
194
|
|
|
192
195
|
export default{
|
|
193
196
|
|
|
197
|
+
emits: [ 'change', 'update:modelValue' ],
|
|
198
|
+
|
|
199
|
+
inject: [ 'alert' ],
|
|
200
|
+
|
|
194
201
|
props:{
|
|
195
202
|
modelValue: String,
|
|
196
203
|
uploadImage: String
|
|
@@ -228,6 +235,27 @@ export default{
|
|
|
228
235
|
this.updateModelValue()
|
|
229
236
|
},
|
|
230
237
|
|
|
238
|
+
onClick(e){
|
|
239
|
+
|
|
240
|
+
if(e.target.tagName === 'IMG'){
|
|
241
|
+
this.newImage = {
|
|
242
|
+
src: e.target.src,
|
|
243
|
+
width: e.target.getAttribute('width'),
|
|
244
|
+
height: e.target.getAttribute('height'),
|
|
245
|
+
maxWidth: e.target.style.maxWidth,
|
|
246
|
+
maxHeight: e.target.style.maxHeight,
|
|
247
|
+
element: e.target
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
else{
|
|
251
|
+
this.newImage = {
|
|
252
|
+
width: "",
|
|
253
|
+
height: "",
|
|
254
|
+
element: null
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
},
|
|
258
|
+
|
|
231
259
|
onBlur(){
|
|
232
260
|
this.$emit('change')
|
|
233
261
|
},
|
|
@@ -249,16 +277,25 @@ export default{
|
|
|
249
277
|
|
|
250
278
|
createLink(){
|
|
251
279
|
|
|
252
|
-
|
|
280
|
+
let { text = '', element, href = 'https://', target = '' } = saveSelection(this.$refs.article)
|
|
281
|
+
|
|
282
|
+
if(element && element.parentNode && element.parentNode.tagName === 'A'){
|
|
283
|
+
href = element.parentNode.href
|
|
284
|
+
target = element.parentNode.target
|
|
285
|
+
}
|
|
253
286
|
|
|
254
287
|
this.newLink = {
|
|
255
|
-
href
|
|
288
|
+
href,
|
|
256
289
|
text,
|
|
257
|
-
target
|
|
290
|
+
target
|
|
258
291
|
}
|
|
259
292
|
this.$refs.linkModal.open()
|
|
260
293
|
},
|
|
261
294
|
|
|
295
|
+
removeFormat(){
|
|
296
|
+
document.execCommand('removeFormat', false);
|
|
297
|
+
},
|
|
298
|
+
|
|
262
299
|
addLink(){
|
|
263
300
|
|
|
264
301
|
restoreSelection()
|
|
@@ -274,20 +311,29 @@ export default{
|
|
|
274
311
|
this.$refs.linkModal.close()
|
|
275
312
|
},
|
|
276
313
|
|
|
314
|
+
removeLink(){
|
|
315
|
+
|
|
316
|
+
const { element } = saveSelection(this.$refs.article)
|
|
317
|
+
|
|
318
|
+
if(element && element.parentNode && element.parentNode.tagName === 'A'){
|
|
319
|
+
element.parentNode.parentNode.replaceChild(element, element.parentNode)
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
this.newLink = null
|
|
323
|
+
this.$refs.linkModal.close()
|
|
324
|
+
|
|
325
|
+
this.updateModelValue()
|
|
326
|
+
},
|
|
327
|
+
|
|
277
328
|
createImage(){
|
|
278
329
|
|
|
279
330
|
saveSelection(this.$refs.article)
|
|
280
331
|
|
|
281
|
-
this.newImage = {
|
|
282
|
-
width: "",
|
|
283
|
-
height: ""
|
|
284
|
-
}
|
|
285
332
|
this.$refs.imageModal.open()
|
|
286
333
|
},
|
|
287
334
|
|
|
288
335
|
onImageChanged(base64, file){
|
|
289
|
-
this.newImage.
|
|
290
|
-
this.newImage.file = file
|
|
336
|
+
this.newImage.src = file
|
|
291
337
|
},
|
|
292
338
|
|
|
293
339
|
onImageAdd(){
|
|
@@ -322,39 +368,52 @@ export default{
|
|
|
322
368
|
|
|
323
369
|
async saveImage(){
|
|
324
370
|
|
|
325
|
-
const blob = await downsizeImage(this.newImage.
|
|
371
|
+
const blob = await downsizeImage(this.newImage.src, this.newImage.width ?? 600)
|
|
326
372
|
|
|
327
373
|
const data = new FormData()
|
|
328
374
|
data.append('image', blob)
|
|
329
375
|
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
376
|
+
try{
|
|
377
|
+
const res = await axios.post(this.uploadImage,
|
|
378
|
+
data,
|
|
379
|
+
{
|
|
380
|
+
headers: {
|
|
381
|
+
"Content-Type": "multipart/form-data",
|
|
382
|
+
},
|
|
383
|
+
}
|
|
384
|
+
)
|
|
385
|
+
|
|
386
|
+
const { url } = res.data
|
|
387
|
+
|
|
388
|
+
restoreSelection()
|
|
389
|
+
|
|
390
|
+
const props = {}
|
|
391
|
+
if(this.newImage.width)
|
|
392
|
+
props.width = this.newImage.width
|
|
393
|
+
if(this.newImage.height)
|
|
394
|
+
props.height = this.newImage.height
|
|
395
|
+
|
|
396
|
+
let propHtml = []
|
|
397
|
+
for(let key in props){
|
|
398
|
+
propHtml.push(`${key}='${props[key]}'`)
|
|
336
399
|
}
|
|
337
|
-
)
|
|
338
|
-
|
|
339
|
-
const { url } = res.data
|
|
340
400
|
|
|
341
|
-
|
|
401
|
+
if(this.newImage.element){
|
|
402
|
+
const aDiv = document.createElement("div")
|
|
403
|
+
aDiv.innerHTML = "<img src=\"" + url + "\" " + propHtml.join(' ') + "/>"
|
|
404
|
+
this.newImage.element.parentNode.replaceChild(aDiv.firstChild, this.newImage.element)
|
|
405
|
+
}
|
|
342
406
|
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
props.height = this.newImage.height
|
|
407
|
+
else{
|
|
408
|
+
document.execCommand("insertHTML", false,
|
|
409
|
+
"<img src=\"" + url + "\" " + propHtml.join(' ') + "/>");
|
|
410
|
+
}
|
|
348
411
|
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
412
|
+
this.$refs.imageModal.close()
|
|
413
|
+
}
|
|
414
|
+
catch(e){
|
|
415
|
+
this.alert(e.response.data)
|
|
352
416
|
}
|
|
353
|
-
|
|
354
|
-
document.execCommand("insertHTML", false,
|
|
355
|
-
"<img src=\"" + url + "\" " + propHtml.join(' ') + "/>");
|
|
356
|
-
|
|
357
|
-
this.$refs.imageModal.close()
|
|
358
417
|
},
|
|
359
418
|
|
|
360
419
|
onPaste(e){
|
|
@@ -373,7 +432,7 @@ export default{
|
|
|
373
432
|
updateModelValue(){
|
|
374
433
|
|
|
375
434
|
let html = this.$refs.article.innerHTML
|
|
376
|
-
html = html.replaceAll("<a ", "<Ahref ").replaceAll("</a>", "</Ahref>")
|
|
435
|
+
//html = html.replaceAll("<a ", "<Ahref ").replaceAll("</a>", "</Ahref>")
|
|
377
436
|
|
|
378
437
|
this.$emit('update:modelValue', html)
|
|
379
438
|
}
|
|
@@ -387,10 +446,20 @@ export default{
|
|
|
387
446
|
<style module>
|
|
388
447
|
|
|
389
448
|
.comp{
|
|
449
|
+
@apply flex-1 flex flex-col;
|
|
390
450
|
}
|
|
391
451
|
|
|
392
452
|
.comp article {
|
|
393
|
-
@apply min-h-[var(--h-cp)] w-full outline-none p-2;
|
|
453
|
+
@apply min-h-[var(--h-cp)] w-full outline-none p-2 leading-6;
|
|
454
|
+
@apply flex-1 overflow-auto;
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
.comp article a{
|
|
458
|
+
@apply text-primary underline;
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
.comp ol li{
|
|
462
|
+
@apply list-disc ml-6;
|
|
394
463
|
}
|
|
395
464
|
|
|
396
465
|
</style>
|
|
@@ -550,10 +550,11 @@ import {urlQuery} from "../utils/helpers.mjs";
|
|
|
550
550
|
import { Bar, Line } from 'vue-chartjs'
|
|
551
551
|
import Chart from 'chart.js/auto'
|
|
552
552
|
import dayjs from "dayjs";
|
|
553
|
+
import VirtualTable from "./VirtualTable.vue";
|
|
553
554
|
|
|
554
555
|
export default{
|
|
555
556
|
|
|
556
|
-
components: { Bar, Line },
|
|
557
|
+
components: { Bar, Line, VirtualTable },
|
|
557
558
|
|
|
558
559
|
inject: [ 'socket', 'confirm', 'alert', 'socketEmit', 'toast' ],
|
|
559
560
|
|
|
@@ -903,9 +904,9 @@ export default{
|
|
|
903
904
|
},
|
|
904
905
|
|
|
905
906
|
mounted() {
|
|
906
|
-
this.patch()
|
|
907
907
|
this.socket.onAny(this.onHooks)
|
|
908
908
|
window.addEventListener('focus', this.onFocus)
|
|
909
|
+
window.setTimeout(() => { this.patch() }, 300)
|
|
909
910
|
},
|
|
910
911
|
|
|
911
912
|
unmounted() {
|
package/src/utils/helpers.js
CHANGED
|
@@ -166,6 +166,28 @@ const bufferToStream = (buffer) => {
|
|
|
166
166
|
return stream
|
|
167
167
|
}
|
|
168
168
|
|
|
169
|
+
const sequelizeChunk = async (model, opt, callback, chunkSize = 5000) => {
|
|
170
|
+
|
|
171
|
+
let offset = 0
|
|
172
|
+
let iter = 0
|
|
173
|
+
while(true){
|
|
174
|
+
const items = await model.findAll({
|
|
175
|
+
...opt,
|
|
176
|
+
offset,
|
|
177
|
+
limit: chunkSize
|
|
178
|
+
})
|
|
179
|
+
|
|
180
|
+
if(items.length > 0){
|
|
181
|
+
await callback(items, iter)
|
|
182
|
+
offset += chunkSize
|
|
183
|
+
iter++
|
|
184
|
+
}
|
|
185
|
+
else{
|
|
186
|
+
break
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
169
191
|
|
|
170
192
|
module.exports = {
|
|
171
193
|
ceil,
|
|
@@ -181,5 +203,6 @@ module.exports = {
|
|
|
181
203
|
strSlug,
|
|
182
204
|
strVars,
|
|
183
205
|
writeStorage,
|
|
184
|
-
bufferToStream
|
|
206
|
+
bufferToStream,
|
|
207
|
+
sequelizeChunk
|
|
185
208
|
}
|
package/src/utils/helpers.mjs
CHANGED
|
@@ -30,9 +30,9 @@ const csvToArray = (str, delimiter = null) => {
|
|
|
30
30
|
const downsizeImage = async (url, targetWidth, imageType, quality, opt = {}) => {
|
|
31
31
|
|
|
32
32
|
let defaultImageType = 'image/jpeg'
|
|
33
|
+
targetWidth = isNaN(parseInt(targetWidth)) ? 2048 : parseInt(targetWidth)
|
|
33
34
|
|
|
34
35
|
if(url instanceof File){
|
|
35
|
-
|
|
36
36
|
defaultImageType = url.type
|
|
37
37
|
|
|
38
38
|
await (new Promise((resolve, reject) => {
|
package/src/utils/selection.js
CHANGED
|
@@ -16,7 +16,8 @@ const saveSelection = (container) =>{
|
|
|
16
16
|
start: start,
|
|
17
17
|
end: start + range.toString().length,
|
|
18
18
|
container,
|
|
19
|
-
text: range.toString()
|
|
19
|
+
text: range.toString(),
|
|
20
|
+
element: range.startContainer
|
|
20
21
|
}
|
|
21
22
|
|
|
22
23
|
return selection
|
|
@@ -56,6 +57,8 @@ const restoreSelection = () => {
|
|
|
56
57
|
const sel = window.getSelection();
|
|
57
58
|
sel.removeAllRanges();
|
|
58
59
|
sel.addRange(range);
|
|
60
|
+
|
|
61
|
+
return range
|
|
59
62
|
}
|
|
60
63
|
|
|
61
64
|
export {
|