-
Notifications
You must be signed in to change notification settings - Fork 220
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #267 from weseek/rc/2.3.9
release v2.3.9
- Loading branch information
Showing
14 changed files
with
266 additions
and
157 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
167 changes: 167 additions & 0 deletions
167
resource/js/components/PageEditor/MarkdownListHelper.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,167 @@ | ||
import * as codemirror from 'codemirror'; | ||
|
||
class MarkdownListHelper { | ||
|
||
constructor() { | ||
// https://github.com/codemirror/CodeMirror/blob/c7853a989c77bb9f520c9c530cbe1497856e96fc/addon/edit/continuelist.js#L14 | ||
// https://regex101.com/r/7BN2fR/5 | ||
this.indentAndMarkRE = /^(\s*)(>[> ]*|[*+-] \[[x ]\]\s|[*+-]\s|(\d+)([.)]))(\s*)/; | ||
this.indentAndMarkOnlyRE = /^(\s*)(>[> ]*|[*+-] \[[x ]\]|[*+-]|(\d+)[.)])(\s*)$/; | ||
|
||
this.newlineAndIndentContinueMarkdownList = this.newlineAndIndentContinueMarkdownList.bind(this); | ||
this.pasteText = this.pasteText.bind(this); | ||
|
||
this.getBol = this.getBol.bind(this); | ||
this.getEol = this.getEol.bind(this); | ||
this.getStrFromBol = this.getStrFromBol.bind(this); | ||
this.getStrToEol = this.getStrToEol.bind(this); | ||
} | ||
|
||
/** | ||
* wrap codemirror.commands.newlineAndIndentContinueMarkdownList | ||
* @param {any} editor An editor instance of CodeMirror | ||
*/ | ||
newlineAndIndentContinueMarkdownList(editor) { | ||
// get strings from current position to EOL(end of line) before break the line | ||
const strToEol = this.getStrToEol(editor); | ||
|
||
if (this.indentAndMarkRE.test(strToEol)) { | ||
codemirror.commands.newlineAndIndent(editor); | ||
// replace the line with strToEol (abort auto indent) | ||
editor.getDoc().replaceRange(strToEol, this.getBol(editor), this.getEol(editor)); | ||
} | ||
else { | ||
codemirror.commands.newlineAndIndentContinueMarkdownList(editor); | ||
} | ||
} | ||
|
||
/** | ||
* paste text | ||
* @param {any} editor An editor instance of CodeMirror | ||
* @param {any} event | ||
* @param {string} text | ||
*/ | ||
pasteText(editor, event, text) { | ||
// get strings from BOL(beginning of line) to current position | ||
const strFromBol = this.getStrFromBol(editor); | ||
|
||
const matched = strFromBol.match(this.indentAndMarkRE); | ||
// when match indentAndMarkOnlyRE | ||
// (this means the current position is the beginning of the list item) | ||
if (this.indentAndMarkOnlyRE.test(strFromBol)) { | ||
const adjusted = this.adjustPastedData(strFromBol, text); | ||
|
||
// replace | ||
if (adjusted != null) { | ||
event.preventDefault(); | ||
editor.getDoc().replaceRange(adjusted, this.getBol(editor), editor.getCursor()); | ||
} | ||
} | ||
} | ||
|
||
/** | ||
* return adjusted pasted data by indentAndMark | ||
* | ||
* @param {string} indentAndMark | ||
* @param {string} text | ||
* @returns adjusted pasted data | ||
* returns null when adjustment is not necessary | ||
*/ | ||
adjustPastedData(indentAndMark, text) { | ||
let adjusted = null; | ||
|
||
// list data (starts with indent and mark) | ||
if (text.match(this.indentAndMarkRE)) { | ||
const indent = indentAndMark.match(this.indentAndMarkRE)[1]; | ||
|
||
// splice to an array of line | ||
const lines = text.match(/[^\r\n]+/g); | ||
// indent | ||
const replacedLines = lines.map((line) => { | ||
return indent + line; | ||
}) | ||
|
||
adjusted = replacedLines.join('\n'); | ||
} | ||
// listful data | ||
else if (this.isListfulData(text)) { | ||
// do nothing (return null) | ||
} | ||
// not listful data | ||
else { | ||
// append `indentAndMark` at the beginning of all lines (except the first line) | ||
const replacedText = text.replace(/(\r\n|\r|\n)/g, "$1" + indentAndMark); | ||
// append `indentAndMark` to the first line | ||
adjusted = indentAndMark + replacedText; | ||
} | ||
|
||
return adjusted; | ||
} | ||
|
||
/** | ||
* evaluate whether `text` is list like data or not | ||
* @param {string} text | ||
*/ | ||
isListfulData(text) { | ||
// return false if includes at least one blank line | ||
// see https://stackoverflow.com/a/16369725 | ||
if (text.match(/^\s*[\r\n]/m) != null) { | ||
return false; | ||
} | ||
|
||
const lines = text.match(/[^\r\n]+/g); | ||
// count lines that starts with indent and mark | ||
let isListful = false; | ||
let count = 0; | ||
lines.forEach((line) => { | ||
if (line.match(this.indentAndMarkRE)) { | ||
count++; | ||
} | ||
// ensure to be true if it is 50% or more | ||
if (count >= lines.length / 2) { | ||
isListful = true; | ||
return; | ||
} | ||
}); | ||
|
||
return isListful; | ||
} | ||
|
||
/** | ||
* return the postion of the BOL(beginning of line) | ||
*/ | ||
getBol(editor) { | ||
const curPos = editor.getCursor(); | ||
return { line: curPos.line, ch: 0 }; | ||
} | ||
|
||
/** | ||
* return the postion of the EOL(end of line) | ||
*/ | ||
getEol(editor) { | ||
const curPos = editor.getCursor(); | ||
const lineLength = editor.getDoc().getLine(curPos.line).length; | ||
return { line: curPos.line, ch: lineLength }; | ||
} | ||
|
||
/** | ||
* return strings from BOL(beginning of line) to current position | ||
*/ | ||
getStrFromBol(editor) { | ||
const curPos = editor.getCursor(); | ||
return editor.getDoc().getRange(this.getBol(editor), curPos); | ||
} | ||
|
||
/** | ||
* return strings from current position to EOL(end of line) | ||
*/ | ||
getStrToEol(editor) { | ||
const curPos = editor.getCursor(); | ||
return editor.getDoc().getRange(curPos, this.getEol(editor)); | ||
} | ||
} | ||
|
||
// singleton pattern | ||
const instance = new MarkdownListHelper(); | ||
Object.freeze(instance); | ||
export default instance; |
Oops, something went wrong.