mirror of https://github.com/status-im/codimd.git
feat: add table tools which extends from @susisu/mte-kernel
port of the code from: https://github.com/susisu/mte-demo/blob/master/src/main.js Signed-off-by: Max Wu <jackymaxj@gmail.com>
This commit is contained in:
parent
c9df47daba
commit
02feb973e1
|
@ -38,6 +38,7 @@
|
|||
"@hackmd/lz-string": "~1.4.4",
|
||||
"@hackmd/meta-marked": "~0.4.4",
|
||||
"@passport-next/passport-openid": "~1.0.0",
|
||||
"@susisu/mte-kernel": "^2.1.0",
|
||||
"archiver": "~3.1.1",
|
||||
"async": "~3.1.0",
|
||||
"aws-sdk": "~2.503.0",
|
||||
|
|
|
@ -4,6 +4,7 @@ import config from './config'
|
|||
import statusBarTemplate from './statusbar.html'
|
||||
import toolBarTemplate from './toolbar.html'
|
||||
import './markdown-lint'
|
||||
import { initTableEditor } from './table-editor'
|
||||
|
||||
/* config section */
|
||||
const isMac = CodeMirror.keyMap.default === CodeMirror.keyMap.macDefault
|
||||
|
@ -623,6 +624,8 @@ export default class Editor {
|
|||
placeholder: "← Start by entering a title here\n===\nVisit /features if you don't know what to do.\nHappy hacking :)"
|
||||
})
|
||||
|
||||
this.tableEditor = initTableEditor(this.editor)
|
||||
|
||||
return this.editor
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,199 @@
|
|||
/* global CodeMirror, $ */
|
||||
import { TableEditor, Point, options, Alignment, FormatType } from '@susisu/mte-kernel'
|
||||
|
||||
// port of the code from: https://github.com/susisu/mte-demo/blob/master/src/main.js
|
||||
|
||||
// text editor interface
|
||||
// see https://doc.esdoc.org/github.com/susisu/mte-kernel/class/lib/text-editor.js~ITextEditor.html
|
||||
class TextEditorInterface {
|
||||
constructor (editor) {
|
||||
this.editor = editor
|
||||
this.doc = editor.getDoc()
|
||||
this.transaction = false
|
||||
this.onDidFinishTransaction = null
|
||||
}
|
||||
|
||||
getCursorPosition () {
|
||||
const { line, ch } = this.doc.getCursor()
|
||||
return new Point(line, ch)
|
||||
}
|
||||
|
||||
setCursorPosition (pos) {
|
||||
this.doc.setCursor({ line: pos.row, ch: pos.column })
|
||||
}
|
||||
|
||||
setSelectionRange (range) {
|
||||
this.doc.setSelection(
|
||||
{ line: range.start.row, ch: range.start.column },
|
||||
{ line: range.end.row, ch: range.end.column }
|
||||
)
|
||||
}
|
||||
|
||||
getLastRow () {
|
||||
return this.doc.lineCount() - 1
|
||||
}
|
||||
|
||||
acceptsTableEdit () {
|
||||
return true
|
||||
}
|
||||
|
||||
getLine (row) {
|
||||
return this.doc.getLine(row)
|
||||
}
|
||||
|
||||
insertLine (row, line) {
|
||||
const lastRow = this.getLastRow()
|
||||
if (row > lastRow) {
|
||||
const lastLine = this.getLine(lastRow)
|
||||
this.doc.replaceRange(
|
||||
'\n' + line,
|
||||
{ line: lastRow, ch: lastLine.length },
|
||||
{ line: lastRow, ch: lastLine.length }
|
||||
)
|
||||
} else {
|
||||
this.doc.replaceRange(
|
||||
line + '\n',
|
||||
{ line: row, ch: 0 },
|
||||
{ line: row, ch: 0 }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
deleteLine (row) {
|
||||
const lastRow = this.getLastRow()
|
||||
if (row >= lastRow) {
|
||||
if (lastRow > 0) {
|
||||
const preLastLine = this.getLine(lastRow - 1)
|
||||
const lastLine = this.getLine(lastRow)
|
||||
this.doc.replaceRange(
|
||||
'',
|
||||
{ line: lastRow - 1, ch: preLastLine.length },
|
||||
{ line: lastRow, ch: lastLine.length }
|
||||
)
|
||||
} else {
|
||||
const lastLine = this.getLine(lastRow)
|
||||
this.doc.replaceRange(
|
||||
'',
|
||||
{ line: lastRow, ch: 0 },
|
||||
{ line: lastRow, ch: lastLine.length }
|
||||
)
|
||||
}
|
||||
} else {
|
||||
this.doc.replaceRange(
|
||||
'',
|
||||
{ line: row, ch: 0 },
|
||||
{ line: row + 1, ch: 0 }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
replaceLines (startRow, endRow, lines) {
|
||||
const lastRow = this.getLastRow()
|
||||
if (endRow > lastRow) {
|
||||
const lastLine = this.getLine(lastRow)
|
||||
this.doc.replaceRange(
|
||||
lines.join('\n'),
|
||||
{ line: startRow, ch: 0 },
|
||||
{ line: lastRow, ch: lastLine.length }
|
||||
)
|
||||
} else {
|
||||
this.doc.replaceRange(
|
||||
lines.join('\n') + '\n',
|
||||
{ line: startRow, ch: 0 },
|
||||
{ line: endRow, ch: 0 }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
transact (func) {
|
||||
this.transaction = true
|
||||
func()
|
||||
this.transaction = false
|
||||
if (this.onDidFinishTransaction) {
|
||||
this.onDidFinishTransaction.call(undefined)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function initTableEditor (editor) {
|
||||
// create an interface to the text editor
|
||||
const editorIntf = new TextEditorInterface(editor)
|
||||
// create a table editor object
|
||||
const tableEditor = new TableEditor(editorIntf)
|
||||
// options for the table editor
|
||||
const opts = options({
|
||||
smartCursor: true,
|
||||
formatType: FormatType.NORMAL
|
||||
})
|
||||
// keymap of the commands
|
||||
// from https://github.com/susisu/mte-demo/blob/master/src/main.js
|
||||
const keyMap = CodeMirror.normalizeKeyMap({
|
||||
Tab: () => { tableEditor.nextCell(opts) },
|
||||
'Shift-Tab': () => { tableEditor.previousCell(opts) },
|
||||
Enter: () => { tableEditor.nextRow(opts) },
|
||||
'Ctrl-Enter': () => { tableEditor.escape(opts) },
|
||||
'Cmd-Enter': () => { tableEditor.escape(opts) },
|
||||
'Shift-Ctrl-Left': () => { tableEditor.alignColumn(Alignment.LEFT, opts) },
|
||||
'Shift-Cmd-Left': () => { tableEditor.alignColumn(Alignment.LEFT, opts) },
|
||||
'Shift-Ctrl-Right': () => { tableEditor.alignColumn(Alignment.RIGHT, opts) },
|
||||
'Shift-Cmd-Right': () => { tableEditor.alignColumn(Alignment.RIGHT, opts) },
|
||||
'Shift-Ctrl-Up': () => { tableEditor.alignColumn(Alignment.CENTER, opts) },
|
||||
'Shift-Cmd-Up': () => { tableEditor.alignColumn(Alignment.CENTER, opts) },
|
||||
'Shift-Ctrl-Down': () => { tableEditor.alignColumn(Alignment.NONE, opts) },
|
||||
'Shift-Cmd-Down': () => { tableEditor.alignColumn(Alignment.NONE, opts) },
|
||||
'Ctrl-Left': () => { tableEditor.moveFocus(0, -1, opts) },
|
||||
'Cmd-Left': () => { tableEditor.moveFocus(0, -1, opts) },
|
||||
'Ctrl-Right': () => { tableEditor.moveFocus(0, 1, opts) },
|
||||
'Cmd-Right': () => { tableEditor.moveFocus(0, 1, opts) },
|
||||
'Ctrl-Up': () => { tableEditor.moveFocus(-1, 0, opts) },
|
||||
'Cmd-Up': () => { tableEditor.moveFocus(-1, 0, opts) },
|
||||
'Ctrl-Down': () => { tableEditor.moveFocus(1, 0, opts) },
|
||||
'Cmd-Down': () => { tableEditor.moveFocus(1, 0, opts) },
|
||||
'Ctrl-K Ctrl-I': () => { tableEditor.insertRow(opts) },
|
||||
'Cmd-K Cmd-I': () => { tableEditor.insertRow(opts) },
|
||||
'Ctrl-L Ctrl-I': () => { tableEditor.deleteRow(opts) },
|
||||
'Cmd-L Cmd-I': () => { tableEditor.deleteRow(opts) },
|
||||
'Ctrl-K Ctrl-J': () => { tableEditor.insertColumn(opts) },
|
||||
'Cmd-K Cmd-J': () => { tableEditor.insertColumn(opts) },
|
||||
'Ctrl-L Ctrl-J': () => { tableEditor.deleteColumn(opts) },
|
||||
'Cmd-L Cmd-J': () => { tableEditor.deleteColumn(opts) },
|
||||
'Alt-Shift-Ctrl-Left': () => { tableEditor.moveColumn(-1, opts) },
|
||||
'Alt-Shift-Cmd-Left': () => { tableEditor.moveColumn(-1, opts) },
|
||||
'Alt-Shift-Ctrl-Right': () => { tableEditor.moveColumn(1, opts) },
|
||||
'Alt-Shift-Cmd-Right': () => { tableEditor.moveColumn(1, opts) },
|
||||
'Alt-Shift-Ctrl-Up': () => { tableEditor.moveRow(-1, opts) },
|
||||
'Alt-Shift-Cmd-Up': () => { tableEditor.moveRow(-1, opts) },
|
||||
'Alt-Shift-Ctrl-Down': () => { tableEditor.moveRow(1, opts) },
|
||||
'Alt-Shift-Cmd-Down': () => { tableEditor.moveRow(1, opts) }
|
||||
})
|
||||
// enable keymap if the cursor is in a table
|
||||
function updateActiveState () {
|
||||
const tableTools = $('.toolbar .table-tools')
|
||||
const active = tableEditor.cursorIsInTable(opts)
|
||||
if (active) {
|
||||
tableTools.show()
|
||||
tableTools.parent().scrollLeft(tableTools.parent()[0].scrollWidth)
|
||||
editor.setOption('extraKeys', keyMap)
|
||||
} else {
|
||||
tableTools.hide()
|
||||
editor.setOption('extraKeys', null)
|
||||
tableEditor.resetSmartCursor()
|
||||
}
|
||||
}
|
||||
// event subscriptions
|
||||
editor.on('cursorActivity', () => {
|
||||
if (!editorIntf.transaction) {
|
||||
updateActiveState()
|
||||
}
|
||||
})
|
||||
editor.on('changes', () => {
|
||||
if (!editorIntf.transaction) {
|
||||
updateActiveState()
|
||||
}
|
||||
})
|
||||
editorIntf.onDidFinishTransaction = () => {
|
||||
updateActiveState()
|
||||
}
|
||||
|
||||
return tableEditor
|
||||
}
|
|
@ -401,6 +401,9 @@ module.exports = {
|
|||
|
||||
module: {
|
||||
rules: [{
|
||||
test: /\.mjs$/,
|
||||
type: 'javascript/auto'
|
||||
}, {
|
||||
test: /\.js$/,
|
||||
use: [{ loader: 'babel-loader' }],
|
||||
exclude: [/node_modules/, /public\/vendor/]
|
||||
|
|
Loading…
Reference in New Issue