mirror of
https://github.com/Ionaru/easy-markdown-editor
synced 2025-07-17 15:04:28 -06: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
|
- **placeholder**: Custom placeholder that should be displayed
|
||||||
- **previewRender**: Custom function for parsing the plaintext Markdown and returning HTML. Used when user previews.
|
- **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`.
|
- **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).
|
- **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`.
|
- **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">`
|
- **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...";
|
return "Loading...";
|
||||||
},
|
},
|
||||||
|
promptURLs: true, // Show a prompt window to insert URL for link or image
|
||||||
renderingConfig: {
|
renderingConfig: {
|
||||||
singleLineBreaks: false,
|
singleLineBreaks: false,
|
||||||
codeSyntaxHighlighting: true,
|
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.
|
* Action for toggling code block.
|
||||||
*/
|
*/
|
||||||
function toggleCodeBlock(editor) {
|
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 options = editor.options;
|
||||||
var url = "http://";
|
var url = "http://";
|
||||||
if(options.promptURLs) {
|
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);
|
_replaceSelection(cm, stat.link, options.insertTexts.link, url);
|
||||||
}
|
}
|
||||||
@ -13239,7 +13521,10 @@ function drawImage(editor) {
|
|||||||
var options = editor.options;
|
var options = editor.options;
|
||||||
var url = "http://";
|
var url = "http://";
|
||||||
if(options.promptURLs) {
|
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);
|
_replaceSelection(cm, stat.image, options.insertTexts.image, url);
|
||||||
}
|
}
|
||||||
@ -13845,12 +14130,13 @@ var insertTexts = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
var promptTexts = {
|
var promptTexts = {
|
||||||
link: "URL for link:",
|
link: "URL for the link:",
|
||||||
image: "The URL of image:"
|
image: "URL of the image:"
|
||||||
};
|
};
|
||||||
|
|
||||||
var blockStyles = {
|
var blockStyles = {
|
||||||
"bold": "**",
|
"bold": "**",
|
||||||
|
"code": "```",
|
||||||
"italic": "*"
|
"italic": "*"
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -13940,7 +14226,9 @@ function SimpleMDE(options) {
|
|||||||
|
|
||||||
|
|
||||||
// Set default options for parsing config
|
// 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
|
// Merging the insertTexts, with the given options
|
||||||
@ -13948,7 +14236,7 @@ function SimpleMDE(options) {
|
|||||||
|
|
||||||
|
|
||||||
// Merging the promptTexts, with the given options
|
// Merging the promptTexts, with the given options
|
||||||
options.promptTexts = extend({}, promptTexts, options.promptTexts || {});
|
options.promptTexts = promptTexts;
|
||||||
|
|
||||||
|
|
||||||
// Merging the blockStyles, with the given options
|
// 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 options = editor.options;
|
||||||
var url = "http://";
|
var url = "http://";
|
||||||
if(options.promptURLs) {
|
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);
|
_replaceSelection(cm, stat.link, options.insertTexts.link, url);
|
||||||
}
|
}
|
||||||
@ -632,7 +635,10 @@ function drawImage(editor) {
|
|||||||
var options = editor.options;
|
var options = editor.options;
|
||||||
var url = "http://";
|
var url = "http://";
|
||||||
if(options.promptURLs) {
|
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);
|
_replaceSelection(cm, stat.image, options.insertTexts.image, url);
|
||||||
}
|
}
|
||||||
@ -1238,8 +1244,8 @@ var insertTexts = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
var promptTexts = {
|
var promptTexts = {
|
||||||
link: "URL for link:",
|
link: "URL for the link:",
|
||||||
image: "The URL of image:"
|
image: "URL of the image:"
|
||||||
};
|
};
|
||||||
|
|
||||||
var blockStyles = {
|
var blockStyles = {
|
||||||
@ -1344,7 +1350,7 @@ function SimpleMDE(options) {
|
|||||||
|
|
||||||
|
|
||||||
// Merging the promptTexts, with the given options
|
// Merging the promptTexts, with the given options
|
||||||
options.promptTexts = extend({}, promptTexts, options.promptTexts || {});
|
options.promptTexts = promptTexts;
|
||||||
|
|
||||||
|
|
||||||
// Merging the blockStyles, with the given options
|
// Merging the blockStyles, with the given options
|
||||||
|
Loading…
x
Reference in New Issue
Block a user