mirror of
https://github.com/sparksuite/simplemde-markdown-editor.git
synced 2024-05-19 14:16:43 +02:00
Optional prompt windows to Link and Image
This commit is contained in:
parent
eb568ddbde
commit
5a53199586
|
@ -94,9 +94,6 @@ simplemde.value("This text will appear in the editor");
|
|||
- **placeholder**: Custom placeholder that should be displayed
|
||||
- **previewRender**: Custom function for parsing the plaintext Markdown and returning HTML. Used when user previews.
|
||||
- **promptURLs**: If set to `true`, a prompt window come if you insert link or image. Defaults to `false`.
|
||||
- **promptTexts**: An object of prompt text.
|
||||
-- image (Default: `The URL of image:`)
|
||||
-- link (Default: `URL for link:`)
|
||||
- **renderingConfig**: Adjust settings for parsing the Markdown during previewing (not editing).
|
||||
- **singleLineBreaks**: If set to `false`, disable parsing GFM single line breaks. Defaults to `true`.
|
||||
- **codeSyntaxHighlighting**: If set to `true`, will highlight using [highlight.js](https://github.com/isagalaev/highlight.js). Defaults to `false`. To use this feature you must include highlight.js on your page. For example, include the script and the CSS files like:<br>`<script src="https://cdn.jsdelivr.net/highlight.js/latest/highlight.min.js"></script>`<br>`<link rel="stylesheet" href="https://cdn.jsdelivr.net/highlight.js/latest/styles/github.min.css">`
|
||||
|
@ -149,6 +146,7 @@ var simplemde = new SimpleMDE({
|
|||
|
||||
return "Loading...";
|
||||
},
|
||||
promptURLs: true, // Show a prompt window to insert URL for link or image
|
||||
renderingConfig: {
|
||||
singleLineBreaks: false,
|
||||
codeSyntaxHighlighting: true,
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -13139,7 +13139,286 @@ function toggleStrikethrough(editor) {
|
|||
* Action for toggling code block.
|
||||
*/
|
||||
function toggleCodeBlock(editor) {
|
||||
_toggleBlock(editor, "code", "```\r\n", "\r\n```");
|
||||
var fenceCharsToInsert = editor.options.blockStyles.code;
|
||||
|
||||
function fencing_line(line) {
|
||||
/* return true, if this is a ``` or ~~~ line */
|
||||
if(typeof line !== "object") {
|
||||
throw "fencing_line() takes a 'line' object (not a line number, or line text). Got: " + typeof line + ": " + line;
|
||||
}
|
||||
return line.styles && line.styles[2] && line.styles[2].indexOf("formatting-code-block") !== -1;
|
||||
}
|
||||
|
||||
function token_state(token) {
|
||||
// base goes an extra level deep when mode backdrops are used, e.g. spellchecker on
|
||||
return token.state.base.base || token.state.base;
|
||||
}
|
||||
|
||||
function code_type(cm, line_num, line, firstTok, lastTok) {
|
||||
/*
|
||||
* Return "single", "indented", "fenced" or false
|
||||
*
|
||||
* cm and line_num are required. Others are optional for efficiency
|
||||
* To check in the middle of a line, pass in firstTok yourself.
|
||||
*/
|
||||
line = line || cm.getLineHandle(line_num);
|
||||
firstTok = firstTok || cm.getTokenAt({
|
||||
line: line_num,
|
||||
ch: 1
|
||||
});
|
||||
lastTok = lastTok || (!!line.text && cm.getTokenAt({
|
||||
line: line_num,
|
||||
ch: line.text.length - 1
|
||||
}));
|
||||
var types = firstTok.type ? firstTok.type.split(" ") : [];
|
||||
if(lastTok && token_state(lastTok).indentedCode) {
|
||||
// have to check last char, since first chars of first line aren"t marked as indented
|
||||
return "indented";
|
||||
} else if(types.indexOf("comment") === -1) {
|
||||
// has to be after "indented" check, since first chars of first indented line aren"t marked as such
|
||||
return false;
|
||||
} else if(token_state(firstTok).fencedChars || token_state(lastTok).fencedChars || fencing_line(line)) {
|
||||
return "fenced";
|
||||
} else {
|
||||
return "single";
|
||||
}
|
||||
}
|
||||
|
||||
function insertFencingAtSelection(cm, cur_start, cur_end, fenceCharsToInsert) {
|
||||
var start_line_sel = cur_start.line + 1,
|
||||
end_line_sel = cur_end.line + 1,
|
||||
sel_multi = cur_start.line !== cur_end.line,
|
||||
repl_start = fenceCharsToInsert + "\n",
|
||||
repl_end = "\n" + fenceCharsToInsert;
|
||||
if(sel_multi) {
|
||||
end_line_sel++;
|
||||
}
|
||||
// handle last char including \n or not
|
||||
if(sel_multi && cur_end.ch === 0) {
|
||||
repl_end = fenceCharsToInsert + "\n";
|
||||
end_line_sel--;
|
||||
}
|
||||
_replaceSelection(cm, false, [repl_start, repl_end]);
|
||||
cm.setSelection({
|
||||
line: start_line_sel,
|
||||
ch: 0
|
||||
}, {
|
||||
line: end_line_sel,
|
||||
ch: 0
|
||||
});
|
||||
}
|
||||
|
||||
var cm = editor.codemirror,
|
||||
cur_start = cm.getCursor("start"),
|
||||
cur_end = cm.getCursor("end"),
|
||||
tok = cm.getTokenAt({
|
||||
line: cur_start.line,
|
||||
ch: cur_start.ch || 1
|
||||
}), // avoid ch 0 which is a cursor pos but not token
|
||||
line = cm.getLineHandle(cur_start.line),
|
||||
is_code = code_type(cm, cur_start.line, line, tok);
|
||||
var block_start, block_end, lineCount;
|
||||
|
||||
if(is_code === "single") {
|
||||
// similar to some SimpleMDE _toggleBlock logic
|
||||
var start = line.text.slice(0, cur_start.ch).replace("`", ""),
|
||||
end = line.text.slice(cur_start.ch).replace("`", "");
|
||||
cm.replaceRange(start + end, {
|
||||
line: cur_start.line,
|
||||
ch: 0
|
||||
}, {
|
||||
line: cur_start.line,
|
||||
ch: 99999999999999
|
||||
});
|
||||
cur_start.ch--;
|
||||
if(cur_start !== cur_end) {
|
||||
cur_end.ch--;
|
||||
}
|
||||
cm.setSelection(cur_start, cur_end);
|
||||
cm.focus();
|
||||
} else if(is_code === "fenced") {
|
||||
if(cur_start.line !== cur_end.line || cur_start.ch !== cur_end.ch) {
|
||||
// use selection
|
||||
|
||||
// find the fenced line so we know what type it is (tilde, backticks, number of them)
|
||||
for(block_start = cur_start.line; block_start >= 0; block_start--) {
|
||||
line = cm.getLineHandle(block_start);
|
||||
if(fencing_line(line)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
var fencedTok = cm.getTokenAt({
|
||||
line: block_start,
|
||||
ch: 1
|
||||
});
|
||||
var fence_chars = token_state(fencedTok).fencedChars;
|
||||
var start_text, start_line;
|
||||
var end_text, end_line;
|
||||
// check for selection going up against fenced lines, in which case we don't want to add more fencing
|
||||
if(fencing_line(cm.getLineHandle(cur_start.line))) {
|
||||
start_text = "";
|
||||
start_line = cur_start.line;
|
||||
} else if(fencing_line(cm.getLineHandle(cur_start.line - 1))) {
|
||||
start_text = "";
|
||||
start_line = cur_start.line - 1;
|
||||
} else {
|
||||
start_text = fence_chars + "\n";
|
||||
start_line = cur_start.line;
|
||||
}
|
||||
if(fencing_line(cm.getLineHandle(cur_end.line))) {
|
||||
end_text = "";
|
||||
end_line = cur_end.line;
|
||||
if(cur_end.ch === 0) {
|
||||
end_line += 1;
|
||||
}
|
||||
} else if(cur_end.ch !== 0 && fencing_line(cm.getLineHandle(cur_end.line + 1))) {
|
||||
end_text = "";
|
||||
end_line = cur_end.line + 1;
|
||||
} else {
|
||||
end_text = fence_chars + "\n";
|
||||
end_line = cur_end.line + 1;
|
||||
}
|
||||
if(cur_end.ch === 0) {
|
||||
// full last line selected, putting cursor at beginning of next
|
||||
end_line -= 1;
|
||||
}
|
||||
cm.operation(function() {
|
||||
// end line first, so that line numbers don't change
|
||||
cm.replaceRange(end_text, {
|
||||
line: end_line,
|
||||
ch: 0
|
||||
}, {
|
||||
line: end_line + (end_text ? 0 : 1),
|
||||
ch: 0
|
||||
});
|
||||
cm.replaceRange(start_text, {
|
||||
line: start_line,
|
||||
ch: 0
|
||||
}, {
|
||||
line: start_line + (start_text ? 0 : 1),
|
||||
ch: 0
|
||||
});
|
||||
});
|
||||
cm.setSelection({
|
||||
line: start_line + (start_text ? 1 : 0),
|
||||
ch: 0
|
||||
}, {
|
||||
line: end_line + (start_text ? 1 : -1),
|
||||
ch: 0
|
||||
});
|
||||
cm.focus();
|
||||
} else {
|
||||
// no selection, search for ends of this fenced block
|
||||
var search_from = cur_start.line;
|
||||
if(fencing_line(cm.getLineHandle(cur_start.line))) { // gets a little tricky if cursor is right on a fenced line
|
||||
if(code_type(cm, cur_start.line + 1) === "fenced") {
|
||||
block_start = cur_start.line;
|
||||
search_from = cur_start.line + 1; // for searching for "end"
|
||||
} else {
|
||||
block_end = cur_start.line;
|
||||
search_from = cur_start.line - 1; // for searching for "start"
|
||||
}
|
||||
}
|
||||
if(block_start === undefined) {
|
||||
for(block_start = search_from; block_start >= 0; block_start--) {
|
||||
line = cm.getLineHandle(block_start);
|
||||
if(fencing_line(line)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(block_end === undefined) {
|
||||
lineCount = cm.lineCount();
|
||||
for(block_end = search_from; block_end < lineCount; block_end++) {
|
||||
line = cm.getLineHandle(block_end);
|
||||
if(fencing_line(line)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
cm.operation(function() {
|
||||
cm.replaceRange("", {
|
||||
line: block_start,
|
||||
ch: 0
|
||||
}, {
|
||||
line: block_start + 1,
|
||||
ch: 0
|
||||
});
|
||||
cm.replaceRange("", {
|
||||
line: block_end - 1,
|
||||
ch: 0
|
||||
}, {
|
||||
line: block_end,
|
||||
ch: 0
|
||||
});
|
||||
});
|
||||
cm.focus();
|
||||
}
|
||||
} else if(is_code === "indented") {
|
||||
if(cur_start.line !== cur_end.line || cur_start.ch !== cur_end.ch) {
|
||||
// use selection
|
||||
block_start = cur_start.line;
|
||||
block_end = cur_end.line;
|
||||
if(cur_end.ch === 0) {
|
||||
block_end--;
|
||||
}
|
||||
} else {
|
||||
// no selection, search for ends of this indented block
|
||||
for(block_start = cur_start.line; block_start >= 0; block_start--) {
|
||||
line = cm.getLineHandle(block_start);
|
||||
if(line.text.match(/^\s*$/)) {
|
||||
// empty or all whitespace - keep going
|
||||
continue;
|
||||
} else {
|
||||
if(code_type(cm, block_start, line) !== "indented") {
|
||||
block_start += 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
lineCount = cm.lineCount();
|
||||
for(block_end = cur_start.line; block_end < lineCount; block_end++) {
|
||||
line = cm.getLineHandle(block_end);
|
||||
if(line.text.match(/^\s*$/)) {
|
||||
// empty or all whitespace - keep going
|
||||
continue;
|
||||
} else {
|
||||
if(code_type(cm, block_end, line) !== "indented") {
|
||||
block_end -= 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// if we are going to un-indent based on a selected set of lines, and the next line is indented too, we need to
|
||||
// insert a blank line so that the next line(s) continue to be indented code
|
||||
var next_line = cm.getLineHandle(block_end + 1),
|
||||
next_line_last_tok = next_line && cm.getTokenAt({
|
||||
line: block_end + 1,
|
||||
ch: next_line.text.length - 1
|
||||
}),
|
||||
next_line_indented = next_line_last_tok && token_state(next_line_last_tok).indentedCode;
|
||||
if(next_line_indented) {
|
||||
cm.replaceRange("\n", {
|
||||
line: block_end + 1,
|
||||
ch: 0
|
||||
});
|
||||
}
|
||||
|
||||
for(var i = block_start; i <= block_end; i++) {
|
||||
cm.indentLine(i, "subtract"); // TODO: this doesn't get tracked in the history, so can't be undone :(
|
||||
}
|
||||
cm.focus();
|
||||
} else {
|
||||
// insert code formatting
|
||||
var no_sel_and_starting_of_line = (cur_start.line === cur_end.line && cur_start.ch === cur_end.ch && cur_start.ch === 0);
|
||||
var sel_multi = cur_start.line !== cur_end.line;
|
||||
if(no_sel_and_starting_of_line || sel_multi) {
|
||||
insertFencingAtSelection(cm, cur_start, cur_end, fenceCharsToInsert);
|
||||
} else {
|
||||
_replaceSelection(cm, false, ["`", "`"]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -13225,7 +13504,10 @@ function drawLink(editor) {
|
|||
var options = editor.options;
|
||||
var url = "http://";
|
||||
if(options.promptURLs) {
|
||||
url = prompt(options.promptTexts.link) || "http://";
|
||||
url = prompt(options.promptTexts.link);
|
||||
if(!url) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
_replaceSelection(cm, stat.link, options.insertTexts.link, url);
|
||||
}
|
||||
|
@ -13239,7 +13521,10 @@ function drawImage(editor) {
|
|||
var options = editor.options;
|
||||
var url = "http://";
|
||||
if(options.promptURLs) {
|
||||
url = prompt(options.promptTexts.image) || "http://";
|
||||
url = prompt(options.promptTexts.image);
|
||||
if(!url) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
_replaceSelection(cm, stat.image, options.insertTexts.image, url);
|
||||
}
|
||||
|
@ -13845,12 +14130,13 @@ var insertTexts = {
|
|||
};
|
||||
|
||||
var promptTexts = {
|
||||
link: "URL for link:",
|
||||
image: "The URL of image:"
|
||||
link: "URL for the link:",
|
||||
image: "URL of the image:"
|
||||
};
|
||||
|
||||
var blockStyles = {
|
||||
"bold": "**",
|
||||
"code": "```",
|
||||
"italic": "*"
|
||||
};
|
||||
|
||||
|
@ -13940,7 +14226,9 @@ function SimpleMDE(options) {
|
|||
|
||||
|
||||
// Set default options for parsing config
|
||||
options.parsingConfig = options.parsingConfig || {};
|
||||
options.parsingConfig = extend({
|
||||
highlightFormatting: true // needed for toggleCodeBlock to detect types of code
|
||||
}, options.parsingConfig || {});
|
||||
|
||||
|
||||
// Merging the insertTexts, with the given options
|
||||
|
@ -13948,7 +14236,7 @@ function SimpleMDE(options) {
|
|||
|
||||
|
||||
// Merging the promptTexts, with the given options
|
||||
options.promptTexts = extend({}, promptTexts, options.promptTexts || {});
|
||||
options.promptTexts = promptTexts;
|
||||
|
||||
|
||||
// Merging the blockStyles, with the given options
|
||||
|
|
27
dist/simplemde.min.js
vendored
27
dist/simplemde.min.js
vendored
File diff suppressed because one or more lines are too long
|
@ -618,7 +618,10 @@ function drawLink(editor) {
|
|||
var options = editor.options;
|
||||
var url = "http://";
|
||||
if(options.promptURLs) {
|
||||
url = prompt(options.promptTexts.link) || "http://";
|
||||
url = prompt(options.promptTexts.link);
|
||||
if(!url) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
_replaceSelection(cm, stat.link, options.insertTexts.link, url);
|
||||
}
|
||||
|
@ -632,7 +635,10 @@ function drawImage(editor) {
|
|||
var options = editor.options;
|
||||
var url = "http://";
|
||||
if(options.promptURLs) {
|
||||
url = prompt(options.promptTexts.image) || "http://";
|
||||
url = prompt(options.promptTexts.image);
|
||||
if(!url) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
_replaceSelection(cm, stat.image, options.insertTexts.image, url);
|
||||
}
|
||||
|
@ -1238,8 +1244,8 @@ var insertTexts = {
|
|||
};
|
||||
|
||||
var promptTexts = {
|
||||
link: "URL for link:",
|
||||
image: "The URL of image:"
|
||||
link: "URL for the link:",
|
||||
image: "URL of the image:"
|
||||
};
|
||||
|
||||
var blockStyles = {
|
||||
|
@ -1344,7 +1350,7 @@ function SimpleMDE(options) {
|
|||
|
||||
|
||||
// Merging the promptTexts, with the given options
|
||||
options.promptTexts = extend({}, promptTexts, options.promptTexts || {});
|
||||
options.promptTexts = promptTexts;
|
||||
|
||||
|
||||
// Merging the blockStyles, with the given options
|
||||
|
|
Loading…
Reference in a new issue