mirror of
https://github.com/BookStackApp/BookStack.git
synced 2024-10-01 01:36:00 -04:00
Expanded the available editor shortcuts in both editors
Adds formatting on ctrl+nums for everything on formats dropdown. Closes #85.
This commit is contained in:
parent
9d61eecd81
commit
ac7a8a8e1e
@ -193,30 +193,6 @@ module.exports = function (ngApp, events) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
scope.tinymce.extraSetups.push(tinyMceSetup);
|
scope.tinymce.extraSetups.push(tinyMceSetup);
|
||||||
|
|
||||||
// Custom tinyMCE plugins
|
|
||||||
tinymce.PluginManager.add('customhr', function (editor) {
|
|
||||||
editor.addCommand('InsertHorizontalRule', function () {
|
|
||||||
let hrElem = document.createElement('hr');
|
|
||||||
let cNode = editor.selection.getNode();
|
|
||||||
let parentNode = cNode.parentNode;
|
|
||||||
parentNode.insertBefore(hrElem, cNode);
|
|
||||||
});
|
|
||||||
|
|
||||||
editor.addButton('hr', {
|
|
||||||
icon: 'hr',
|
|
||||||
tooltip: 'Horizontal line',
|
|
||||||
cmd: 'InsertHorizontalRule'
|
|
||||||
});
|
|
||||||
|
|
||||||
editor.addMenuItem('hr', {
|
|
||||||
icon: 'hr',
|
|
||||||
text: 'Horizontal line',
|
|
||||||
cmd: 'InsertHorizontalRule',
|
|
||||||
context: 'insert'
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
tinymce.init(scope.tinymce);
|
tinymce.init(scope.tinymce);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -257,6 +233,21 @@ module.exports = function (ngApp, events) {
|
|||||||
extraKeys[`${metaKey}-S`] = function(cm) {scope.$emit('save-draft');};
|
extraKeys[`${metaKey}-S`] = function(cm) {scope.$emit('save-draft');};
|
||||||
// Show link selector
|
// Show link selector
|
||||||
extraKeys[`Shift-${metaKey}-K`] = function(cm) {showLinkSelector()};
|
extraKeys[`Shift-${metaKey}-K`] = function(cm) {showLinkSelector()};
|
||||||
|
// Insert Link
|
||||||
|
extraKeys[`${metaKey}-K`] = function(cm) {insertLink()};
|
||||||
|
// FormatShortcuts
|
||||||
|
extraKeys[`${metaKey}-1`] = function(cm) {replaceLineStart('##');};
|
||||||
|
extraKeys[`${metaKey}-2`] = function(cm) {replaceLineStart('###');};
|
||||||
|
extraKeys[`${metaKey}-3`] = function(cm) {replaceLineStart('####');};
|
||||||
|
extraKeys[`${metaKey}-4`] = function(cm) {replaceLineStart('#####');};
|
||||||
|
extraKeys[`${metaKey}-5`] = function(cm) {replaceLineStart('');};
|
||||||
|
extraKeys[`${metaKey}-d`] = function(cm) {replaceLineStart('');};
|
||||||
|
extraKeys[`${metaKey}-6`] = function(cm) {replaceLineStart('>');};
|
||||||
|
extraKeys[`${metaKey}-q`] = function(cm) {replaceLineStart('>');};
|
||||||
|
extraKeys[`${metaKey}-7`] = function(cm) {wrapSelection('\n```\n', '\n```');};
|
||||||
|
extraKeys[`${metaKey}-8`] = function(cm) {wrapSelection('`', '`');};
|
||||||
|
extraKeys[`Shift-${metaKey}-E`] = function(cm) {wrapSelection('`', '`');};
|
||||||
|
extraKeys[`${metaKey}-9`] = function(cm) {wrapSelection('<p class="callout info">', '</div>');};
|
||||||
cm.setOption('extraKeys', extraKeys);
|
cm.setOption('extraKeys', extraKeys);
|
||||||
|
|
||||||
// Update data on content change
|
// Update data on content change
|
||||||
@ -309,6 +300,73 @@ module.exports = function (ngApp, events) {
|
|||||||
cm.setSelections(cursor);
|
cm.setSelections(cursor);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Helper to replace the start of the line
|
||||||
|
function replaceLineStart(newStart) {
|
||||||
|
let cursor = cm.getCursor();
|
||||||
|
let lineContent = cm.getLine(cursor.line);
|
||||||
|
let lineLen = lineContent.length;
|
||||||
|
let lineStart = lineContent.split(' ')[0];
|
||||||
|
|
||||||
|
// Remove symbol if already set
|
||||||
|
if (lineStart === newStart) {
|
||||||
|
lineContent = lineContent.replace(`${newStart} `, '');
|
||||||
|
cm.replaceRange(lineContent, {line: cursor.line, ch: 0}, {line: cursor.line, ch: lineLen});
|
||||||
|
cm.setCursor({line: cursor.line, ch: cursor.ch - (newStart.length + 1)});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let alreadySymbol = /^[#>`]/.test(lineStart);
|
||||||
|
let posDif = 0;
|
||||||
|
if (alreadySymbol) {
|
||||||
|
posDif = newStart.length - lineStart.length;
|
||||||
|
lineContent = lineContent.replace(lineStart, newStart).trim();
|
||||||
|
} else if (newStart !== '') {
|
||||||
|
posDif = newStart.length + 1;
|
||||||
|
lineContent = newStart + ' ' + lineContent;
|
||||||
|
}
|
||||||
|
cm.replaceRange(lineContent, {line: cursor.line, ch: 0}, {line: cursor.line, ch: lineLen});
|
||||||
|
cm.setCursor({line: cursor.line, ch: cursor.ch + posDif});
|
||||||
|
}
|
||||||
|
|
||||||
|
function wrapLine(start, end) {
|
||||||
|
let cursor = cm.getCursor();
|
||||||
|
let lineContent = cm.getLine(cursor.line);
|
||||||
|
let lineLen = lineContent.length;
|
||||||
|
let newLineContent = lineContent;
|
||||||
|
|
||||||
|
if (lineContent.indexOf(start) === 0 && lineContent.slice(-end.length) === end) {
|
||||||
|
newLineContent = lineContent.slice(start.length, lineContent.length - end.length);
|
||||||
|
} else {
|
||||||
|
newLineContent = `${start}${lineContent}${end}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
cm.replaceRange(newLineContent, {line: cursor.line, ch: 0}, {line: cursor.line, ch: lineLen});
|
||||||
|
cm.setCursor({line: cursor.line, ch: cursor.ch + (newLineContent.length - lineLen)});
|
||||||
|
}
|
||||||
|
|
||||||
|
function wrapSelection(start, end) {
|
||||||
|
let selection = cm.getSelection();
|
||||||
|
if (selection === '') return wrapLine(start, end);
|
||||||
|
let newSelection = selection;
|
||||||
|
let frontDiff = 0;
|
||||||
|
let endDiff = 0;
|
||||||
|
|
||||||
|
if (selection.indexOf(start) === 0 && selection.slice(-end.length) === end) {
|
||||||
|
newSelection = selection.slice(start.length, selection.length - end.length);
|
||||||
|
endDiff = -(end.length + start.length);
|
||||||
|
} else {
|
||||||
|
newSelection = `${start}${selection}${end}`;
|
||||||
|
endDiff = start.length + end.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
let selections = cm.listSelections()[0];
|
||||||
|
cm.replaceSelection(newSelection);
|
||||||
|
let headFirst = selections.head.ch <= selections.anchor.ch;
|
||||||
|
selections.head.ch += headFirst ? frontDiff : endDiff;
|
||||||
|
selections.anchor.ch += headFirst ? endDiff : frontDiff;
|
||||||
|
cm.setSelections([selections]);
|
||||||
|
}
|
||||||
|
|
||||||
// Handle image upload and add image into markdown content
|
// Handle image upload and add image into markdown content
|
||||||
function uploadImage(file) {
|
function uploadImage(file) {
|
||||||
if (file === null || file.type.indexOf('image') !== 0) return;
|
if (file === null || file.type.indexOf('image') !== 0) return;
|
||||||
@ -351,6 +409,16 @@ module.exports = function (ngApp, events) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function insertLink() {
|
||||||
|
let cursorPos = cm.getCursor('from');
|
||||||
|
let selectedText = cm.getSelection() || '';
|
||||||
|
let newText = `[${selectedText}]()`;
|
||||||
|
cm.focus();
|
||||||
|
cm.replaceSelection(newText);
|
||||||
|
let cursorPosDiff = (selectedText === '') ? -3 : -1;
|
||||||
|
cm.setCursor(cursorPos.line, cursorPos.ch + newText.length+cursorPosDiff);
|
||||||
|
}
|
||||||
|
|
||||||
// Show the image manager and handle image insertion
|
// Show the image manager and handle image insertion
|
||||||
function showImageManager() {
|
function showImageManager() {
|
||||||
let cursorPos = cm.getCursor('from');
|
let cursorPos = cm.getCursor('from');
|
||||||
|
@ -52,14 +52,36 @@ function editorPaste(e, editor) {
|
|||||||
function registerEditorShortcuts(editor) {
|
function registerEditorShortcuts(editor) {
|
||||||
// Headers
|
// Headers
|
||||||
for (let i = 1; i < 5; i++) {
|
for (let i = 1; i < 5; i++) {
|
||||||
editor.addShortcut('meta+' + i, '', ['FormatBlock', false, 'h' + i]);
|
editor.shortcuts.add('meta+' + i, '', ['FormatBlock', false, 'h' + (i+1)]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Other block shortcuts
|
// Other block shortcuts
|
||||||
editor.addShortcut('meta+q', '', ['FormatBlock', false, 'blockquote']);
|
editor.shortcuts.add('meta+5', '', ['FormatBlock', false, 'p']);
|
||||||
editor.addShortcut('meta+d', '', ['FormatBlock', false, 'p']);
|
editor.shortcuts.add('meta+d', '', ['FormatBlock', false, 'p']);
|
||||||
editor.addShortcut('meta+e', '', ['codeeditor', false, 'pre']);
|
editor.shortcuts.add('meta+6', '', ['FormatBlock', false, 'blockquote']);
|
||||||
editor.addShortcut('meta+shift+E', '', ['FormatBlock', false, 'code']);
|
editor.shortcuts.add('meta+q', '', ['FormatBlock', false, 'blockquote']);
|
||||||
|
editor.shortcuts.add('meta+7', '', ['codeeditor', false, 'pre']);
|
||||||
|
editor.shortcuts.add('meta+e', '', ['codeeditor', false, 'pre']);
|
||||||
|
editor.shortcuts.add('meta+8', '', ['FormatBlock', false, 'code']);
|
||||||
|
editor.shortcuts.add('meta+shift+E', '', ['FormatBlock', false, 'code']);
|
||||||
|
// Loop through callout styles
|
||||||
|
editor.shortcuts.add('meta+9', '', function() {
|
||||||
|
let selectedNode = editor.selection.getNode();
|
||||||
|
let formats = ['info', 'success', 'warning', 'danger'];
|
||||||
|
|
||||||
|
if (!selectedNode || selectedNode.className.indexOf('callout') === -1) {
|
||||||
|
editor.formatter.apply('calloutinfo');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let i = 0; i < formats.length; i++) {
|
||||||
|
if (selectedNode.className.indexOf(formats[i]) === -1) continue;
|
||||||
|
let newFormat = (i === formats.length -1) ? formats[0] : formats[i+1];
|
||||||
|
editor.formatter.apply('callout' + newFormat);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
editor.formatter.apply('p');
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -173,7 +195,32 @@ function codePlugin() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function hrPlugin() {
|
||||||
|
window.tinymce.PluginManager.add('customhr', function (editor) {
|
||||||
|
editor.addCommand('InsertHorizontalRule', function () {
|
||||||
|
let hrElem = document.createElement('hr');
|
||||||
|
let cNode = editor.selection.getNode();
|
||||||
|
let parentNode = cNode.parentNode;
|
||||||
|
parentNode.insertBefore(hrElem, cNode);
|
||||||
|
});
|
||||||
|
|
||||||
|
editor.addButton('hr', {
|
||||||
|
icon: 'hr',
|
||||||
|
tooltip: 'Horizontal line',
|
||||||
|
cmd: 'InsertHorizontalRule'
|
||||||
|
});
|
||||||
|
|
||||||
|
editor.addMenuItem('hr', {
|
||||||
|
icon: 'hr',
|
||||||
|
text: 'Horizontal line',
|
||||||
|
cmd: 'InsertHorizontalRule',
|
||||||
|
context: 'insert'
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
module.exports = function() {
|
module.exports = function() {
|
||||||
|
hrPlugin();
|
||||||
codePlugin();
|
codePlugin();
|
||||||
let settings = {
|
let settings = {
|
||||||
selector: '#html-editor',
|
selector: '#html-editor',
|
||||||
@ -207,10 +254,10 @@ module.exports = function() {
|
|||||||
{title: "Code Block", icon: "code", cmd: 'codeeditor', format: 'codeeditor'},
|
{title: "Code Block", icon: "code", cmd: 'codeeditor', format: 'codeeditor'},
|
||||||
{title: "Inline Code", icon: "code", inline: "code"},
|
{title: "Inline Code", icon: "code", inline: "code"},
|
||||||
{title: "Callouts", items: [
|
{title: "Callouts", items: [
|
||||||
{title: "Success", block: 'p', exact: true, attributes : {'class' : 'callout success'}},
|
{title: "Info", format: 'calloutinfo'},
|
||||||
{title: "Info", block: 'p', exact: true, attributes : {'class' : 'callout info'}},
|
{title: "Success", format: 'calloutsuccess'},
|
||||||
{title: "Warning", block: 'p', exact: true, attributes : {'class' : 'callout warning'}},
|
{title: "Warning", format: 'calloutwarning'},
|
||||||
{title: "Danger", block: 'p', exact: true, attributes : {'class' : 'callout danger'}}
|
{title: "Danger", format: 'calloutdanger'}
|
||||||
]},
|
]},
|
||||||
],
|
],
|
||||||
style_formats_merge: false,
|
style_formats_merge: false,
|
||||||
@ -219,6 +266,10 @@ module.exports = function() {
|
|||||||
alignleft: {selector: 'p,h1,h2,h3,h4,h5,h6,td,th,div,ul,ol,li,table,img', classes: 'align-left'},
|
alignleft: {selector: 'p,h1,h2,h3,h4,h5,h6,td,th,div,ul,ol,li,table,img', classes: 'align-left'},
|
||||||
aligncenter: {selector: 'p,h1,h2,h3,h4,h5,h6,td,th,div,ul,ol,li,table,img', classes: 'align-center'},
|
aligncenter: {selector: 'p,h1,h2,h3,h4,h5,h6,td,th,div,ul,ol,li,table,img', classes: 'align-center'},
|
||||||
alignright: {selector: 'p,h1,h2,h3,h4,h5,h6,td,th,div,ul,ol,li,table,img', classes: 'align-right'},
|
alignright: {selector: 'p,h1,h2,h3,h4,h5,h6,td,th,div,ul,ol,li,table,img', classes: 'align-right'},
|
||||||
|
calloutsuccess: {block: 'p', exact: true, attributes: {class: 'callout success'}},
|
||||||
|
calloutinfo: {block: 'p', exact: true, attributes: {class: 'callout info'}},
|
||||||
|
calloutwarning: {block: 'p', exact: true, attributes: {class: 'callout warning'}},
|
||||||
|
calloutdanger: {block: 'p', exact: true, attributes: {class: 'callout danger'}}
|
||||||
},
|
},
|
||||||
file_browser_callback: function (field_name, url, type, win) {
|
file_browser_callback: function (field_name, url, type, win) {
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user