mirror of
https://github.com/thomiceli/opengist.git
synced 2024-12-23 04:52:40 +00:00
Wrap editor code in DOMContentLoaded
This commit is contained in:
parent
2aee52e06c
commit
0eb1b103d0
1 changed files with 139 additions and 134 deletions
273
public/editor.js
vendored
273
public/editor.js
vendored
|
@ -2,156 +2,161 @@ import {EditorView, gutter, keymap, lineNumbers} from "@codemirror/view"
|
||||||
import {Compartment, EditorState, Facet, SelectionRange} from "@codemirror/state"
|
import {Compartment, EditorState, Facet, SelectionRange} from "@codemirror/state"
|
||||||
import {indentLess} from "@codemirror/commands";
|
import {indentLess} from "@codemirror/commands";
|
||||||
|
|
||||||
EditorView.theme({}, {dark: true})
|
document.addEventListener('DOMContentLoaded', () => {
|
||||||
|
EditorView.theme({}, {dark: true})
|
||||||
|
|
||||||
let editorsjs = []
|
let editorsjs = []
|
||||||
let editorsParentdom = document.getElementById('editors')
|
let editorsParentdom = document.getElementById('editors')
|
||||||
let allEditorsdom = document.querySelectorAll('#editors > .editor')
|
let allEditorsdom = document.querySelectorAll('#editors > .editor')
|
||||||
let firstEditordom = allEditorsdom[0]
|
let firstEditordom = allEditorsdom[0]
|
||||||
|
|
||||||
const txtFacet = Facet.define({
|
const txtFacet = Facet.define({
|
||||||
combine(values) {
|
combine(values) {
|
||||||
return values[0]
|
return values[0]
|
||||||
}
|
|
||||||
})
|
|
||||||
let indentSize = new Compartment, wrapMode = new Compartment, indentType = new Compartment
|
|
||||||
|
|
||||||
const newEditor = (dom, value = '') => {
|
|
||||||
let editor = new EditorView({
|
|
||||||
doc: value,
|
|
||||||
parent: dom,
|
|
||||||
extensions: [
|
|
||||||
lineNumbers(), gutter({class: "cm-mygutter"}),
|
|
||||||
keymap.of([{key: "Tab", run: customIndentMore, shift: indentLess}]),
|
|
||||||
indentSize.of(EditorState.tabSize.of(2)),
|
|
||||||
wrapMode.of([]),
|
|
||||||
indentType.of(txtFacet.of("space")),
|
|
||||||
]
|
|
||||||
})
|
|
||||||
|
|
||||||
dom.querySelector('.editor-indent-type').onchange = (e) => {
|
|
||||||
let newTabType = e.target.value
|
|
||||||
setIndentType(editor, !['tab', 'space'].includes(newTabType) ? 'space' : newTabType)
|
|
||||||
}
|
|
||||||
|
|
||||||
dom.querySelector('.editor-indent-size').onchange = (e) => {
|
|
||||||
let newTabSize = parseInt(e.target.value)
|
|
||||||
setIndentSize(editor, ![2, 4, 8].includes(newTabSize) ? 2 : newTabSize)
|
|
||||||
}
|
|
||||||
|
|
||||||
dom.querySelector('.editor-wrap-mode').onchange = (e) => {
|
|
||||||
let newWrapMode = e.target.value
|
|
||||||
setLineWrapping(editor, newWrapMode === 'soft')
|
|
||||||
}
|
|
||||||
|
|
||||||
dom.addEventListener("drop", (e) => {
|
|
||||||
e.preventDefault(); // prevent the browser from opening the dropped file
|
|
||||||
e.target.closest('.editor').querySelector('input.form-filename').value = e.dataTransfer.files[0].name
|
|
||||||
});
|
|
||||||
|
|
||||||
// remove editor on delete
|
|
||||||
let deleteBtns = dom.querySelector('button.delete-file')
|
|
||||||
if (deleteBtns !== null) {
|
|
||||||
deleteBtns.onclick = () => {
|
|
||||||
editorsjs.splice(editorsjs.indexOf(editor), 1);
|
|
||||||
dom.remove()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
editor.dom.addEventListener("input", function inputConfirmLeave() {
|
|
||||||
if (!editor.inView) return; // skip events outside the viewport
|
|
||||||
|
|
||||||
editor.dom.removeEventListener("input", inputConfirmLeave);
|
|
||||||
window.onbeforeunload = () => {
|
|
||||||
return 'Are you sure you want to quit?';
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return editor;
|
|
||||||
}
|
|
||||||
|
|
||||||
function getIndentation(state) {
|
|
||||||
if (indentType.get(state).value === 'tab') {
|
|
||||||
return '\t';
|
|
||||||
}
|
|
||||||
return ' '.repeat(indentSize.get(state).value);
|
|
||||||
}
|
|
||||||
|
|
||||||
function customIndentMore({state, dispatch}) {
|
|
||||||
let indentation = getIndentation(state)
|
|
||||||
dispatch({
|
|
||||||
...state.update(changeBySelectedLine(state, (line, changes) => {
|
|
||||||
changes.push({from: state.selection.ranges[0].from, insert: indentation})
|
|
||||||
})), selection: {
|
|
||||||
anchor: state.selection.ranges[0].from + indentation.length,
|
|
||||||
head: state.selection.ranges[0].from + indentation.length,
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
return true
|
let indentSize = new Compartment, wrapMode = new Compartment, indentType = new Compartment
|
||||||
}
|
|
||||||
|
|
||||||
function changeBySelectedLine(state, f) {
|
const newEditor = (dom, value = '') => {
|
||||||
let atLine = -1
|
let editor = new EditorView({
|
||||||
return state.changeByRange(range => {
|
doc: value,
|
||||||
let changes = []
|
parent: dom,
|
||||||
for (let line = state.doc.lineAt(range.from); ;) {
|
extensions: [
|
||||||
if (line.number > atLine) {
|
lineNumbers(), gutter({class: "cm-mygutter"}),
|
||||||
f(line, changes)
|
keymap.of([{key: "Tab", run: customIndentMore, shift: indentLess}]),
|
||||||
atLine = line.number
|
indentSize.of(EditorState.tabSize.of(2)),
|
||||||
|
wrapMode.of([]),
|
||||||
|
indentType.of(txtFacet.of("space")),
|
||||||
|
]
|
||||||
|
})
|
||||||
|
|
||||||
|
dom.querySelector('.editor-indent-type').onchange = (e) => {
|
||||||
|
let newTabType = e.target.value
|
||||||
|
setIndentType(editor, !['tab', 'space'].includes(newTabType) ? 'space' : newTabType)
|
||||||
|
}
|
||||||
|
|
||||||
|
dom.querySelector('.editor-indent-size').onchange = (e) => {
|
||||||
|
let newTabSize = parseInt(e.target.value)
|
||||||
|
setIndentSize(editor, ![2, 4, 8].includes(newTabSize) ? 2 : newTabSize)
|
||||||
|
}
|
||||||
|
|
||||||
|
dom.querySelector('.editor-wrap-mode').onchange = (e) => {
|
||||||
|
let newWrapMode = e.target.value
|
||||||
|
setLineWrapping(editor, newWrapMode === 'soft')
|
||||||
|
}
|
||||||
|
|
||||||
|
dom.addEventListener("drop", (e) => {
|
||||||
|
e.preventDefault(); // prevent the browser from opening the dropped file
|
||||||
|
e.target.closest('.editor').querySelector('input.form-filename').value = e.dataTransfer.files[0].name
|
||||||
|
});
|
||||||
|
|
||||||
|
// remove editor on delete
|
||||||
|
let deleteBtns = dom.querySelector('button.delete-file')
|
||||||
|
if (deleteBtns !== null) {
|
||||||
|
deleteBtns.onclick = () => {
|
||||||
|
editorsjs.splice(editorsjs.indexOf(editor), 1);
|
||||||
|
dom.remove()
|
||||||
}
|
}
|
||||||
if (range.to <= line.to) break
|
|
||||||
line = state.doc.lineAt(line.number + 1)
|
|
||||||
}
|
}
|
||||||
let changeSet = state.changes(changes)
|
|
||||||
return {changes, range: new SelectionRange(changeSet.mapPos(range.anchor, 1), changeSet.mapPos(range.head, 1))}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
function setIndentType(view, type) {
|
editor.dom.addEventListener("input", function inputConfirmLeave() {
|
||||||
view.dispatch({effects: indentType.reconfigure(txtFacet.of(type))})
|
if (!editor.inView) return; // skip events outside the viewport
|
||||||
}
|
|
||||||
|
|
||||||
function setIndentSize(view, size) {
|
editor.dom.removeEventListener("input", inputConfirmLeave);
|
||||||
view.dispatch({effects: indentSize.reconfigure(EditorState.tabSize.of(size))})
|
window.onbeforeunload = () => {
|
||||||
}
|
return 'Are you sure you want to quit?';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
function setLineWrapping(view, enable) {
|
return editor;
|
||||||
if (enable) {
|
|
||||||
view.dispatch({effects: wrapMode.reconfigure(EditorView.lineWrapping)})
|
|
||||||
} else {
|
|
||||||
view.dispatch({effects: wrapMode.reconfigure([])})
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
let arr = [...allEditorsdom]
|
function getIndentation(state) {
|
||||||
arr.forEach(el => {
|
if (indentType.get(state).value === 'tab') {
|
||||||
// in case we edit the gist contents
|
return '\t';
|
||||||
let currEditor = newEditor(el, el.querySelector('.form-filecontent').value)
|
}
|
||||||
editorsjs.push(currEditor)
|
return ' '.repeat(indentSize.get(state).value);
|
||||||
})
|
}
|
||||||
|
|
||||||
document.getElementById('add-file').onclick = () => {
|
function customIndentMore({state, dispatch}) {
|
||||||
let newEditorDom = firstEditordom.cloneNode(true)
|
let indentation = getIndentation(state)
|
||||||
|
dispatch({
|
||||||
|
...state.update(changeBySelectedLine(state, (line, changes) => {
|
||||||
|
changes.push({from: state.selection.ranges[0].from, insert: indentation})
|
||||||
|
})), selection: {
|
||||||
|
anchor: state.selection.ranges[0].from + indentation.length,
|
||||||
|
head: state.selection.ranges[0].from + indentation.length,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
// reset the filename of the new cloned element
|
function changeBySelectedLine(state, f) {
|
||||||
newEditorDom.querySelector('input[name="name"]').value = ""
|
let atLine = -1
|
||||||
|
return state.changeByRange(range => {
|
||||||
|
let changes = []
|
||||||
|
for (let line = state.doc.lineAt(range.from); ;) {
|
||||||
|
if (line.number > atLine) {
|
||||||
|
f(line, changes)
|
||||||
|
atLine = line.number
|
||||||
|
}
|
||||||
|
if (range.to <= line.to) break
|
||||||
|
line = state.doc.lineAt(line.number + 1)
|
||||||
|
}
|
||||||
|
let changeSet = state.changes(changes)
|
||||||
|
return {
|
||||||
|
changes,
|
||||||
|
range: new SelectionRange(changeSet.mapPos(range.anchor, 1), changeSet.mapPos(range.head, 1))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// removing the previous codemirror editor
|
function setIndentType(view, type) {
|
||||||
let newEditorDomCM = newEditorDom.querySelector('.cm-editor')
|
view.dispatch({effects: indentType.reconfigure(txtFacet.of(type))})
|
||||||
newEditorDomCM.remove()
|
}
|
||||||
|
|
||||||
// creating the new codemirror editor and append it in the editor div
|
function setIndentSize(view, size) {
|
||||||
editorsjs.push(newEditor(newEditorDom))
|
view.dispatch({effects: indentSize.reconfigure(EditorState.tabSize.of(size))})
|
||||||
editorsParentdom.append(newEditorDom)
|
}
|
||||||
}
|
|
||||||
|
|
||||||
document.querySelector('form#create').onsubmit = () => {
|
function setLineWrapping(view, enable) {
|
||||||
let j = 0
|
if (enable) {
|
||||||
document.querySelectorAll('.form-filecontent').forEach((e) => {
|
view.dispatch({effects: wrapMode.reconfigure(EditorView.lineWrapping)})
|
||||||
e.value = encodeURIComponent(editorsjs[j++].state.doc.toString())
|
} else {
|
||||||
|
view.dispatch({effects: wrapMode.reconfigure([])})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let arr = [...allEditorsdom]
|
||||||
|
arr.forEach(el => {
|
||||||
|
// in case we edit the gist contents
|
||||||
|
let currEditor = newEditor(el, el.querySelector('.form-filecontent').value)
|
||||||
|
editorsjs.push(currEditor)
|
||||||
})
|
})
|
||||||
}
|
|
||||||
|
|
||||||
document.onsubmit = () => {
|
document.getElementById('add-file').onclick = () => {
|
||||||
window.onbeforeunload = null;
|
let newEditorDom = firstEditordom.cloneNode(true)
|
||||||
}
|
|
||||||
|
// reset the filename of the new cloned element
|
||||||
|
newEditorDom.querySelector('input[name="name"]').value = ""
|
||||||
|
|
||||||
|
// removing the previous codemirror editor
|
||||||
|
let newEditorDomCM = newEditorDom.querySelector('.cm-editor')
|
||||||
|
newEditorDomCM.remove()
|
||||||
|
|
||||||
|
// creating the new codemirror editor and append it in the editor div
|
||||||
|
editorsjs.push(newEditor(newEditorDom))
|
||||||
|
editorsParentdom.append(newEditorDom)
|
||||||
|
}
|
||||||
|
|
||||||
|
document.querySelector('form#create').onsubmit = () => {
|
||||||
|
let j = 0
|
||||||
|
document.querySelectorAll('.form-filecontent').forEach((e) => {
|
||||||
|
e.value = encodeURIComponent(editorsjs[j++].state.doc.toString())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
document.onsubmit = () => {
|
||||||
|
window.onbeforeunload = null;
|
||||||
|
}
|
||||||
|
})
|
Loading…
Reference in a new issue