Skip to content

Commit 1603452

Browse files
pdanpdanrstoenescu
authored andcommitted
* fix(QEditor): Misc fixes quasarframework#5134, quasarframework#5833, quasarframework#5277, quasarframework#4315 * More improvements for caret * Update editor-caret.js * Update editor-caret.js * Update editor-caret.js * Update editor-caret.js
1 parent 68afe50 commit 1603452

File tree

4 files changed

+124
-71
lines changed

4 files changed

+124
-71
lines changed

ui/dev/components/form/editor.vue

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@
7777
<q-editor
7878
ref="editor"
7979
class="bg-grey"
80+
max-height="300px"
8081
v-model="model"
8182
:flat="flat"
8283
:square="square"

ui/src/components/editor/QEditor.js

Lines changed: 41 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -254,7 +254,7 @@ export default Vue.extend({
254254

255255
watch: {
256256
value (v) {
257-
if (this.editWatcher) {
257+
if (this.editWatcher === true) {
258258
this.__setContent(v)
259259
}
260260
else {
@@ -265,7 +265,7 @@ export default Vue.extend({
265265

266266
methods: {
267267
__onInput () {
268-
if (this.editWatcher) {
268+
if (this.editWatcher === true) {
269269
const val = this.isViewingSource
270270
? this.$refs.content.innerText
271271
: this.$refs.content.innerHTML
@@ -301,14 +301,37 @@ export default Vue.extend({
301301
},
302302

303303
__onBlur () {
304-
this.caret.save()
304+
this.$q.platform.is.ie !== true && this.caret.save()
305305
this.$emit('blur')
306306
},
307307

308+
__onMouseup (e) {
309+
this.caret.save()
310+
if (this.$listeners.mouseup !== void 0) {
311+
this.$emit('mouseup', e)
312+
}
313+
},
314+
315+
__onKeyup (e) {
316+
this.caret.save()
317+
if (this.$listeners.keyup !== void 0) {
318+
this.$emit('keyup', e)
319+
}
320+
},
321+
322+
__onTouchend (e) {
323+
this.caret.save()
324+
if (this.$listeners.touchend !== void 0) {
325+
this.$emit('touchend', e)
326+
}
327+
},
328+
308329
runCmd (cmd, param, update = true) {
309330
this.focus()
331+
this.caret.restore()
310332
this.caret.apply(cmd, param, () => {
311333
this.focus()
334+
this.caret.restore()
312335
if (this.$q.platform.is.ie === true || this.$q.platform.is.edge === true) {
313336
this.$nextTick(this.__onInput)
314337
}
@@ -375,7 +398,7 @@ export default Vue.extend({
375398
key: 'qedt_btm',
376399
staticClass: 'q-editor__toolbar row no-wrap items-center scroll-x',
377400
class: this.toolbarBackgroundClass
378-
}, getLinkEditor(h, this))
401+
}, getLinkEditor(h, this, this.$q.platform.is.ie))
379402
)
380403

381404
toolbars = h('div', {
@@ -384,6 +407,19 @@ export default Vue.extend({
384407
}, bars)
385408
}
386409

410+
const on = {
411+
...this.$listeners,
412+
input: this.__onInput,
413+
keydown: this.__onKeydown,
414+
click: this.__onClick,
415+
blur: this.__onBlur,
416+
417+
// save caret
418+
mouseup: this.__onMouseup,
419+
keyup: this.__onKeyup,
420+
touchend: this.__onTouchend
421+
}
422+
387423
return h(
388424
'div',
389425
{
@@ -414,13 +450,7 @@ export default Vue.extend({
414450
domProps: isSSR
415451
? { innerHTML: this.value }
416452
: undefined,
417-
on: {
418-
...this.$listeners,
419-
input: this.__onInput,
420-
keydown: this.__onKeydown,
421-
click: this.__onClick,
422-
blur: this.__onBlur
423-
}
453+
on
424454
}
425455
)
426456
]

ui/src/components/editor/editor-caret.js

Lines changed: 77 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,12 @@ function getBlockElement (el, parent) {
33
return null
44
}
55

6+
const nodeName = el.nodeName.toLowerCase()
7+
8+
if (['div', 'li', 'ul', 'ol', 'blockquote'].includes(nodeName) === true) {
9+
return el
10+
}
11+
612
const
713
style = window.getComputedStyle
814
? window.getComputedStyle(el)
@@ -37,67 +43,74 @@ export class Caret {
3743
constructor (el, vm) {
3844
this.el = el
3945
this.vm = vm
46+
this._range = null
4047
}
4148

4249
get selection () {
43-
if (!this.el) {
44-
return
45-
}
46-
const sel = document.getSelection()
47-
// only when the selection in element
48-
if (isChildOf(sel.anchorNode, this.el) && isChildOf(sel.focusNode, this.el)) {
49-
return sel
50+
if (this.el) {
51+
const sel = document.getSelection()
52+
53+
// only when the selection in element
54+
if (isChildOf(sel.anchorNode, this.el) && isChildOf(sel.focusNode, this.el)) {
55+
return sel
56+
}
5057
}
58+
59+
return null
5160
}
5261

5362
get hasSelection () {
54-
return this.selection
63+
return this.selection !== null
5564
? this.selection.toString().length > 0
56-
: null
65+
: false
5766
}
5867

5968
get range () {
6069
const sel = this.selection
6170

62-
if (!sel) {
63-
return
71+
if (sel !== null && sel.rangeCount) {
72+
return sel.getRangeAt(0)
6473
}
6574

66-
return sel.rangeCount
67-
? sel.getRangeAt(0)
68-
: null
75+
return this._range
6976
}
7077

7178
get parent () {
7279
const range = this.range
73-
if (!range) {
74-
return
80+
81+
if (range !== null) {
82+
const node = range.startContainer
83+
84+
return node.nodeType === document.ELEMENT_NODE
85+
? node
86+
: node.parentNode
7587
}
7688

77-
const node = range.startContainer
78-
return node.nodeType === document.ELEMENT_NODE
79-
? node
80-
: node.parentNode
89+
return null
8190
}
8291

8392
get blockParent () {
8493
const parent = this.parent
85-
if (!parent) {
86-
return
94+
95+
if (parent !== null) {
96+
return getBlockElement(parent, this.el)
8797
}
88-
return getBlockElement(parent, this.el)
98+
99+
return null
89100
}
90101

91102
save (range = this.range) {
92-
this._range = range
103+
if (range !== null) {
104+
this._range = range
105+
}
93106
}
94107

95108
restore (range = this._range) {
96109
const
97110
r = document.createRange(),
98111
sel = document.getSelection()
99112

100-
if (range) {
113+
if (range !== null) {
101114
r.setStart(range.startContainer, range.startOffset)
102115
r.setEnd(range.endContainer, range.endOffset)
103116
sel.removeAllRanges()
@@ -114,15 +127,22 @@ export class Caret {
114127
? this.parent
115128
: this.blockParent
116129

117-
return el
130+
return el !== null
118131
? el.nodeName.toLowerCase() === name.toLowerCase()
119132
: false
120133
}
121134

122-
hasParents (list) {
123-
const el = this.parent
124-
return el
125-
? list.includes(el.nodeName.toLowerCase())
135+
hasParents (list, recursive, el = this.parent) {
136+
if (el === null) {
137+
return false
138+
}
139+
140+
if (el !== null && list.includes(el.nodeName.toLowerCase() === true) {
141+
return true
142+
}
143+
144+
return recursive === true
145+
? this.hasParents(list, recursive, el.parentNode)
126146
: false
127147
}
128148

@@ -148,33 +168,29 @@ export class Caret {
148168
return false
149169
default:
150170
const state = document.queryCommandState(cmd)
151-
return param ? state === param : state
171+
return param !== void 0 ? state === param : state
152172
}
153173
}
154174

155175
getParentAttribute (attrib) {
156-
if (this.parent) {
176+
if (this.parent !== null) {
157177
return this.parent.getAttribute(attrib)
158178
}
179+
180+
return null
159181
}
160182

161183
can (name) {
162184
if (name === 'outdent') {
163-
return this.hasParents(['blockquote', 'li'])
185+
return this.hasParents(['blockquote', 'li'], true)
164186
}
187+
165188
if (name === 'indent') {
166-
const parentName = this.parent ? this.parent.nodeName.toLowerCase() : false
167-
if (parentName === 'blockquote') {
168-
return false
169-
}
170-
if (parentName === 'li') {
171-
const previousEl = this.parent.previousSibling
172-
return previousEl && previousEl.nodeName.toLowerCase() === 'li'
173-
}
174-
return false
189+
return this.hasParents(['li'], true)
175190
}
191+
176192
if (name === 'link') {
177-
return this.selection || this.is('link')
193+
return this.selection !== null || this.is('link')
178194
}
179195
}
180196

@@ -191,7 +207,9 @@ export class Caret {
191207
}
192208
else if (cmd === 'print') {
193209
done()
210+
194211
const win = window.open()
212+
195213
win.document.write(`
196214
<!doctype html>
197215
<html>
@@ -205,57 +223,57 @@ export class Caret {
205223
`)
206224
win.print()
207225
win.close()
226+
208227
return
209228
}
210229
else if (cmd === 'link') {
211-
const link = this.getParentAttribute('href')
212-
if (!link) {
230+
const
231+
link = this.getParentAttribute('href'),
232+
range = this.range
233+
234+
if (link === null) {
213235
const selection = this.selectWord(this.selection)
214236
const url = selection ? selection.toString() : ''
237+
215238
if (!url.length) {
216239
return
217240
}
241+
218242
this.vm.editLinkUrl = urlRegex.test(url) ? url : 'https://'
219243
document.execCommand('createLink', false, this.vm.editLinkUrl)
220244
}
221245
else {
222246
this.vm.editLinkUrl = link
223247
}
248+
224249
this.vm.$nextTick(() => {
225-
this.range.selectNodeContents(this.parent)
250+
range.selectNodeContents(this.parent)
226251
this.save()
227252
})
253+
228254
return
229255
}
230256
else if (cmd === 'fullscreen') {
231257
this.vm.toggleFullscreen()
232258
done()
259+
233260
return
234261
}
235262
else if (cmd === 'viewsource') {
236-
this.vm.isViewingSource = !this.vm.isViewingSource
263+
this.vm.isViewingSource = this.vm.isViewingSource === false
237264
this.vm.__setContent(this.vm.value)
238265
done()
266+
239267
return
240268
}
241269

242-
if (this.vm.$q.platform.is.ie === true || this.vm.$q.platform.is.edge === true) {
243-
// workaround for IE/Edge, otherwise it messes up
244-
// the DOM of toolbar
245-
const dummyDiv = document.createElement('div')
246-
this.vm.$refs.content.appendChild(dummyDiv)
247-
document.execCommand(cmd, false, param)
248-
dummyDiv.remove()
249-
}
250-
else {
251-
document.execCommand(cmd, false, param)
252-
}
270+
document.execCommand(cmd, false, param)
253271

254272
done()
255273
}
256274

257275
selectWord (sel) {
258-
if (!sel || !sel.isCollapsed) {
276+
if (sel === null || sel.isCollapsed !== true || /* IE 11 */ sel.modify === void 0) {
259277
return sel
260278
}
261279

0 commit comments

Comments
 (0)