Skip to content

Commit

Permalink
fix: Major changes to editor line structure and handling & Fixes to m…
Browse files Browse the repository at this point in the history
…ath element close function

Tries to patch #5
  • Loading branch information
Esinko committed Oct 15, 2021
1 parent 8aaf089 commit 3c310d7
Showing 1 changed file with 96 additions and 27 deletions.
123 changes: 96 additions & 27 deletions src/js/editor/editor.js
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ const Utils = new (class _Utils {
*/
getSelectedNode(){
const node = document.getSelection().focusNode
if(node === null) return null
return (node.nodeType == 3 ? node.parentNode : node)
}

Expand Down Expand Up @@ -386,6 +387,24 @@ const Utils = new (class _Utils {
dummy.remove()
//sel.setPosition(sel.anchorNode, offset)
}

// TODO: Start using this with Utils.waitFor
/**
* Execute a function & await a promise in async context
* @param {*} input
* @param {*} promise
* @returns
*/
async asyncTrigger(input, promise){
return new Promise((resolve, reject) => {
promise.then((...args) => {
resolve(...args)
}).catch((...args) => {
reject(...args)
})
input()
})
}
})

// Math utilities (wrapper for MathQuill)
Expand Down Expand Up @@ -537,6 +556,7 @@ const Math = new (class _Math {
mathObject.image.remove()
mathObject.container.remove()
delete this.collection[id]
this.events.dispatchEvent(new CustomEvent("blur", { detail: mathObject }))
return
}

Expand Down Expand Up @@ -610,10 +630,12 @@ class Editor {
*/
async setContent(data, id){
// UI compatibility
this.watchDocument = false
this.target = {
i: id
}
this.hook.innerHTML = ""
// eslint-disable-next-line no-constant-condition

// Create construct
let construct = []
Expand Down Expand Up @@ -671,6 +693,7 @@ class Editor {
}

// Write the elements to the editor
let addedContent = false
for(let line of construct){
let lineElement = null
for(let element of line){
Expand All @@ -685,16 +708,21 @@ class Editor {
}
if(line.length === 0) {
lineElement = document.createElement("div")
if(window.browser === "firefox") lineElement.appendChild(document.createElement("br")) // Firefox line activator
lineElement.appendChild(document.createElement("br")) // line activator
}
if(lineElement) {
this.hook.appendChild(lineElement)
addedContent = true
}
if(lineElement) this.hook.appendChild(lineElement)
}
if(!addedContent) this.hook.innerHTML = `<div>${this.activator}</div>` // If no content was added, activate first line

// Toggle all math
for(let id in Math.collection){
Math.open(id)
Math.close(id)
await Math.open(id)
await Math.close(id)
}
this.watchDocument = true
}

/**
Expand Down Expand Up @@ -741,7 +769,8 @@ class Editor {
case "br": {
// This is a manual line-break
if(window.browser !== "firefox"){ // Does not mean anything on firefox
format.push("")
// <br> in a line by itself does not do anything on Chrome either
if(element.parentNode.childNodes.length !== 1) format.push("")
}
break
}
Expand Down Expand Up @@ -814,25 +843,23 @@ class Editor {
}

// Firefox patch: Make sure we are not in a math container
if(event.code === "Enter"){
if(window.browser === "firefox"){
const selection = document.getSelection()
const direction = selection.anchorOffset // 0 is left, 1 is right
if(selection.anchorNode.nodeName.toLowerCase() === "a" && selection.anchorNode.childNodes.length === 1 && selection.anchorNode.childNodes[0].nodeName.toLowerCase() === "img"){
event.preventDefault()
if(direction === 0){
const line = document.createElement("div")
line.appendChild(document.createElement("br")) // this.activator
this.activeLine.before(line)
Utils.selectByIndex(0, line)
}else {
const line = document.createElement("div")
line.appendChild(document.createElement("br")) // this.activator
this.activeLine.after(line)
Utils.selectByIndex(0, line)
}
return // Forced to return
if(event.code === "Enter" && window.browser === "firefox"){
const selection = document.getSelection()
const direction = selection.anchorOffset // 0 is left, 1 is right
if(selection.anchorNode.nodeName.toLowerCase() === "a" && selection.anchorNode.childNodes.length === 1 && selection.anchorNode.childNodes[0].nodeName.toLowerCase() === "img"){
event.preventDefault()
if(direction === 0){
const line = document.createElement("div")
line.appendChild(document.createElement("br")) // this.activator
this.activeLine.before(line)
Utils.selectByIndex(0, line)
}else {
const line = document.createElement("div")
line.appendChild(document.createElement("br")) // this.activator
this.activeLine.after(line)
Utils.selectByIndex(0, line)
}
return // Forced to return
}
}

Expand All @@ -850,8 +877,21 @@ class Editor {
Utils.selectByIndex(Utils.getNodeIndex(this.hook, newLine), this.hook) // Move into new line
}else {
// Create new line after current active line
Math.close(this.activeMathElement.id)
await Utils.waitForEvent(Math.events, "blur")
const id = this.activeMathElement.id
const offset = Utils.getNodeIndex(this.activeLine, this.activeMathElement.container)
await Utils.asyncTrigger(() => {Math.close(id)}, Utils.waitForEvent(Math.events, "blur"))
// Make sure the math element just closed still exists (may get deleted if empty)
if(Math.collection[id] === undefined) {
// Return caret to previous selection
// If line is empty, select the start
if(this.activeLine.childNodes.length === 1 && this.activeLine.childNodes[0].nodeName.toLowerCase() === "br"){
Utils.selectByIndex(Utils.getNodeIndex(this.hook, this.activeLine), this.hook)
}else {
// Make sure the editor is not empty
if(this.hook.childNodes.length !== 0) Utils.selectByIndex(offset - 1, this.activeLine)
}
return
}
// Make new line
const newLine = document.createElement("div")
this.activeLine.after(newLine)
Expand All @@ -864,6 +904,19 @@ class Editor {
return
}

// Disable shift+Enter
if(event.key === "Enter" && this.activeMathElement === null){
// Causes issues at least on chromium, prevention is required
event.preventDefault()
// Create a new line normally
const newLine = document.createElement("div")
newLine.innerHTML = "<br>"
this.activeLine.after(newLine)
this.activeLine = newLine
Utils.selectByIndex(Utils.getNodeIndex(this.hook, this.activeLine), this.hook)
console.debug("[ EDITOR ] Active line change to", this.activeLine)
}

// Arrow key control
if(event.code === "ArrowLeft" || event.code === "ArrowRight"){
await Utils.toggleAnchorMode(Utils.getObjectPropertyArray(Math.collection, "container"), true)
Expand Down Expand Up @@ -947,7 +1000,7 @@ class Editor {
})

// Document content modification listener
const observerCallback = async () => {
const observerCallback = async e => {
// Enable/disable
if(!this.watchDocument) return

Expand All @@ -960,6 +1013,13 @@ class Editor {
Utils.selectByIndex(0, this.hook)
}

// Text modified? What is activeLine?
const parentLine = e && e.addedNodes && e.addedNodes[0] !== null ? Utils.getParentLine() : null
if(parentLine && this.activeLine !== parentLine){
this.activeLine = parentLine
console.debug("[ EDITOR ] Active line change to", this.activeLine)
}

// Firefox patch: If the image element is in the beginning/end of a line, remove textNodes from within the container
if(window.browser === "firefox"){
for(const id in Math.collection){
Expand Down Expand Up @@ -1009,7 +1069,6 @@ class Editor {
// Firefox patch: Detect useless br tags in empty lines
if(window.browser === "firefox"){
if(this.activeMathElement !== null && this.activeMathElement.isOpen === false && this.activeMathElement.image !== null && this.activeMathElement.image.parentNode !== null){
console.log(this.activeMathElement.image.parentNode.parentNode.childNodes)
if(this.activeMathElement.image.parentNode.parentNode.childNodes[0].nodeName.toLowerCase() === "br" && this.activeMathElement.image.parentNode.parentNode.childNodes.length === 2){
this.activeMathElement.image.parentNode.parentNode.childNodes[0].remove()
}
Expand All @@ -1028,6 +1087,15 @@ class Editor {
// Get selection data and make sure it's valid
const selection = document.getSelection()
const line = selection.anchorNode.parentElement === this.hook ? selection.anchorNode : Utils.getParentLine(selection.anchorNode)

// If we have only one line in the editor, we can focus that (as there are no other options)
if(this.hook.childNodes.length === 1 && this.activeLine !== this.hook.childNodes[0]) {
this.activeLine = this.hook.childNodes[0]
Utils.selectByIndex(0, this.hook)
console.debug("[ EDITOR ] Active line change to", this.activeLine)
return
}

if(!Utils.isSomeParent(selection.anchorNode, this.hook)) return

// Update active line
Expand All @@ -1038,6 +1106,7 @@ class Editor {
})
window.addEventListener("keydown", async event => {
if(event.code === "ArrowUp" || event.code === "ArrowDown"){
// Move with arrow keys
const selection = document.getSelection()
const line = selection.anchorNode.parentElement === this.hook ? selection.anchorNode : Utils.getParentLine(selection.anchorNode)
if(!Utils.isSomeParent(selection.anchorNode, this.hook)) return
Expand Down

0 comments on commit 3c310d7

Please sign in to comment.