diff --git a/app/javascript/template_builder/dynamic_menu.vue b/app/javascript/template_builder/dynamic_menu.vue
index 2762ee78e..cd6ac19a8 100644
--- a/app/javascript/template_builder/dynamic_menu.vue
+++ b/app/javascript/template_builder/dynamic_menu.vue
@@ -468,7 +468,7 @@ export default {
}
},
mounted () {
- this.editor.view.dom.addEventListener('mousedown', this.onMouseDown)
+ this.editor.view.dom.parentElement.addEventListener('mousedown', this.onMouseDown)
document.addEventListener('mouseup', this.onMouseUp)
@@ -476,7 +476,7 @@ export default {
},
beforeUnmount () {
if (!this.editor.isDestroyed) {
- this.editor.view.dom.removeEventListener('mousedown', this.onMouseDown)
+ this.editor.view.dom.parentElement.removeEventListener('mousedown', this.onMouseDown)
this.editor.off('transaction', this.onTransaction)
}
diff --git a/app/javascript/template_builder/dynamic_section.vue b/app/javascript/template_builder/dynamic_section.vue
index bc9fe2b94..05aa949bc 100644
--- a/app/javascript/template_builder/dynamic_section.vue
+++ b/app/javascript/template_builder/dynamic_section.vue
@@ -2,6 +2,7 @@
import { shallowRef } from 'vue'
import { DOMSerializer, Fragment } from '@tiptap/pm/model'
+import { TextSelection } from '@tiptap/pm/state'
import { findTable, CellSelection } from '@tiptap/pm/tables'
import { v4 } from 'uuid'
import { IconPlus, IconX } from '@tabler/icons-vue'
@@ -964,6 +966,48 @@ export default {
return true
},
+ closestPosAtCoords ({ clientX, clientY }) {
+ const view = this.editor.view
+ const rect = view.dom.getBoundingClientRect()
+ const left = Math.min(Math.max(clientX, rect.left + 1), rect.right - 1)
+ const top = Math.min(Math.max(clientY, rect.top + 1), rect.bottom - 1)
+ const caret = document.caretPositionFromPoint?.(left, top, { shadowRoots: [view.root] })
+
+ if (caret && view.dom.contains(caret.offsetNode)) {
+ return view.posAtDOM(caret.offsetNode, caret.offset)
+ } else {
+ return view.posAtCoords({ left, top }).pos
+ }
+ },
+ onMarginMouseDown (event) {
+ const view = this.editor.view
+
+ if (event.button !== 0 || !this.editable || this.isDrawMode || view.dom.contains(event.target)) {
+ return
+ }
+
+ event.preventDefault()
+
+ const anchor = this.closestPosAtCoords(event)
+
+ const selectTo = (e) => {
+ const { doc, tr } = view.state
+
+ view.dispatch(tr.setSelection(TextSelection.between(doc.resolve(anchor), doc.resolve(this.closestPosAtCoords(e)))))
+ }
+
+ const onMouseUp = () => {
+ window.removeEventListener('mousemove', selectTo)
+ window.removeEventListener('mouseup', onMouseUp)
+ }
+
+ selectTo(event)
+
+ view.focus()
+
+ window.addEventListener('mousemove', selectTo)
+ window.addEventListener('mouseup', onMouseUp)
+ },
onEditorPointerDown (event) {
if (!this.isDrawMode || !this.editable || this.isDraggingField) {
return