diff --git a/settings.json.template b/settings.json.template index ceb9efb31..404ce1c78 100644 --- a/settings.json.template +++ b/settings.json.template @@ -69,6 +69,30 @@ "lang": "en-gb" }, + /* Pad Shortcut Keys */ + "padShortcutEnabled" : { + "altF9" : true, + "altC" : true, + "cmdShift2" : true, + "delete" : true, + "return" : true, + "cmdS" : true, + "tab" : true, + "cmdZ" : true, + "cmdY" : true, + "cmdI" : true, + "cmdB" : true, + "cmdU" : true, + "cmd5" : true, + "cmdShiftL" : true, + "cmdShiftN" : true, + "cmdShiftC" : true, + "cmdH" : true, + "ctrlHome" : true, + "pageUp" : true, + "pageDown" : true, + }, + /* Should we suppress errors from being visible in the default Pad Text? */ "suppressErrorsInPadText" : false, diff --git a/src/node/hooks/express/specialpages.js b/src/node/hooks/express/specialpages.js index e8d7795a6..b9f86367c 100644 --- a/src/node/hooks/express/specialpages.js +++ b/src/node/hooks/express/specialpages.js @@ -41,6 +41,12 @@ exports.expressCreateServer = function (hook_name, args, cb) { res.cookie('language', settings.padOptions.lang); } + // Enable the pad shortcut keys from settings.json + if (settings.padShortcutEnabled !== undefined) + { + res.cookie('padShortcutEnabled', JSON.stringify(settings.padShortcutEnabled)); + } + // The below might break for pads being rewritten var isReadOnly = req.url.indexOf("/p/r.") === 0; diff --git a/src/node/utils/Settings.js b/src/node/utils/Settings.js index b765670a6..9f31e5579 100644 --- a/src/node/utils/Settings.js +++ b/src/node/utils/Settings.js @@ -100,7 +100,33 @@ exports.padOptions = { "alwaysShowChat": false, "chatAndUsers": false, "lang": "en-gb" -} +}, + +/** + * Whether certain shortcut keys are enabled for a user in the pad + */ +exports.padShortcutEnabled = { + "altF9" : true, + "altC" : true, + "delete" : true, + "cmdShift2" : true, + "return" : true, + "cmdS" : true, + "tab" : true, + "cmdZ" : true, + "cmdY" : true, + "cmdB" : true, + "cmdI" : true, + "cmdU" : true, + "cmd5" : true, + "cmdShiftL" : true, + "cmdShiftN" : true, + "cmdShiftC" : true, + "cmdH" : true, + "ctrlHome" : true, + "pageUp" : true, + "pageDown" : true, +}, /** * The toolbar buttons and order. diff --git a/src/static/js/ace2_inner.js b/src/static/js/ace2_inner.js index 8576ee336..88abbf865 100644 --- a/src/static/js/ace2_inner.js +++ b/src/static/js/ace2_inner.js @@ -61,6 +61,7 @@ function Ace2Inner(){ var SkipList = require('./skiplist'); var undoModule = require('./undomodule').undoModule; var AttributeManager = require('./AttributeManager'); + var readCookie = require('./pad_utils').readCookie; var DEBUG = false; //$$ build script replaces the string "var DEBUG=true;//$$" with "var DEBUG=false;" // changed to false @@ -3633,6 +3634,37 @@ function Ace2Inner(){ function handleKeyEvent(evt) { + // Get the enabled shortcut keys + // If it can't find the cookie, use default values + // Cookie should normally be set + // See settings.json + var padShortcutEnabled = JSON.parse(decodeURIComponent(readCookie('padShortcutEnabled'))); + if (!padShortcutEnabled) + { + padShortcutEnabled = { + "altF9" : true, + "altC" : true, + "cmdShift2" : true, + "delete" : true, + "return" : true, + "cmdS" : true, + "tab" : true, + "cmdZ" : true, + "cmdY" : true, + "cmdI" : true, + "cmdB" : true, + "cmdU" : true, + "cmd5" : true, + "cmdShiftL" : true, + "cmdShiftN" : true, + "cmdShiftC" : true, + "cmdH" : true, + "ctrlHome" : true, + "pageUp" : true, + "pageDown" : true, + } + } + // if (DEBUG && window.DONT_INCORP) return; if (!isEditable) return; var type = evt.type; @@ -3716,7 +3748,7 @@ function Ace2Inner(){ specialHandled = _.contains(specialHandledInHook, true); } - if ((!specialHandled) && altKey && isTypeForSpecialKey && keyCode == 120){ + if ((!specialHandled) && altKey && isTypeForSpecialKey && keyCode == 120 && padShortcutEnabled.altF9){ // Alt F9 focuses on the File Menu and/or editbar. // Note that while most editors use Alt F10 this is not desirable // As ubuntu cannot use Alt F10.... @@ -3726,14 +3758,14 @@ function Ace2Inner(){ firstEditbarElement.focus(); evt.preventDefault(); } - if ((!specialHandled) && altKey && keyCode == 67 && type === "keydown"){ + if ((!specialHandled) && altKey && keyCode == 67 && type === "keydown" && padShortcutEnabled.altC){ // Alt c focuses on the Chat window $(this).blur(); parent.parent.chat.show(); parent.parent.$("#chatinput").focus(); evt.preventDefault(); } - if ((!specialHandled) && evt.ctrlKey && shiftKey && keyCode == 50 && type === "keydown"){ + if ((!specialHandled) && evt.ctrlKey && shiftKey && keyCode == 50 && type === "keydown" && padShortcutEnabled.cmdShift2){ // Control-Shift-2 shows a gritter popup showing a line author var lineNumber = rep.selEnd[0]; var alineAttrs = rep.alines[lineNumber]; @@ -3811,7 +3843,7 @@ function Ace2Inner(){ time: '4000' }); } - if ((!specialHandled) && isTypeForSpecialKey && keyCode == 8) + if ((!specialHandled) && isTypeForSpecialKey && keyCode == 8 && padShortcutEnabled.delete) { // "delete" key; in mozilla, if we're at the beginning of a line, normalize now, // or else deleting a blank line can take two delete presses. @@ -3825,7 +3857,7 @@ function Ace2Inner(){ doDeleteKey(evt); specialHandled = true; } - if ((!specialHandled) && isTypeForSpecialKey && keyCode == 13) + if ((!specialHandled) && isTypeForSpecialKey && keyCode == 13 && padShortcutEnabled.return) { // return key, handle specially; // note that in mozilla we need to do an incorporation for proper return behavior anyway. @@ -3839,7 +3871,7 @@ function Ace2Inner(){ }, 0); specialHandled = true; } - if ((!specialHandled) && isTypeForSpecialKey && keyCode == 27) + if ((!specialHandled) && isTypeForSpecialKey && keyCode == 27 && padShortcutEnabled.cmdS) { // prevent esc key; // in mozilla versions 14-19 avoid reconnecting pad. @@ -3848,7 +3880,7 @@ function Ace2Inner(){ evt.preventDefault(); specialHandled = true; } - if ((!specialHandled) && isTypeForCmdKey && String.fromCharCode(which).toLowerCase() == "s" && (evt.metaKey || evt.ctrlKey) && !evt.altKey) /* Do a saved revision on ctrl S */ + if ((!specialHandled) && isTypeForCmdKey && String.fromCharCode(which).toLowerCase() == "s" && (evt.metaKey || evt.ctrlKey) && !evt.altKey && padShortcutEnabled.cmdS) /* Do a saved revision on ctrl S */ { evt.preventDefault(); var originalBackground = parent.parent.$('#revisionlink').css("background") @@ -3859,7 +3891,7 @@ function Ace2Inner(){ parent.parent.pad.collabClient.sendMessage({"type":"SAVE_REVISION"}); /* The parent.parent part of this is BAD and I feel bad.. It may break something */ specialHandled = true; } - if ((!specialHandled) && isTypeForSpecialKey && keyCode == 9 && !(evt.metaKey || evt.ctrlKey)) + if ((!specialHandled) && isTypeForSpecialKey && keyCode == 9 && !(evt.metaKey || evt.ctrlKey) && padShortcutEnabled.tab) { // tab fastIncorp(5); @@ -3868,7 +3900,7 @@ function Ace2Inner(){ //scrollSelectionIntoView(); specialHandled = true; } - if ((!specialHandled) && isTypeForCmdKey && String.fromCharCode(which).toLowerCase() == "z" && (evt.metaKey || evt.ctrlKey) && !evt.altKey) + if ((!specialHandled) && isTypeForCmdKey && String.fromCharCode(which).toLowerCase() == "z" && (evt.metaKey || evt.ctrlKey) && !evt.altKey && padShortcutEnabled.cmdZ) { // cmd-Z (undo) fastIncorp(6); @@ -3883,7 +3915,7 @@ function Ace2Inner(){ } specialHandled = true; } - if ((!specialHandled) && isTypeForCmdKey && String.fromCharCode(which).toLowerCase() == "y" && (evt.metaKey || evt.ctrlKey)) + if ((!specialHandled) && isTypeForCmdKey && String.fromCharCode(which).toLowerCase() == "y" && (evt.metaKey || evt.ctrlKey) && padShortcutEnabled.cmdY) { // cmd-Y (redo) fastIncorp(10); @@ -3891,7 +3923,7 @@ function Ace2Inner(){ doUndoRedo("redo"); specialHandled = true; } - if ((!specialHandled) && isTypeForCmdKey && String.fromCharCode(which).toLowerCase() == "b" && (evt.metaKey || evt.ctrlKey)) + if ((!specialHandled) && isTypeForCmdKey && String.fromCharCode(which).toLowerCase() == "b" && (evt.metaKey || evt.ctrlKey) && padShortcutEnabled.cmdB) { // cmd-B (bold) fastIncorp(13); @@ -3899,7 +3931,7 @@ function Ace2Inner(){ toggleAttributeOnSelection('bold'); specialHandled = true; } - if ((!specialHandled) && isTypeForCmdKey && String.fromCharCode(which).toLowerCase() == "i" && (evt.metaKey || evt.ctrlKey)) + if ((!specialHandled) && isTypeForCmdKey && String.fromCharCode(which).toLowerCase() == "i" && (evt.metaKey || evt.ctrlKey) && padShortcutEnabled.cmdI) { // cmd-I (italic) fastIncorp(14); @@ -3907,7 +3939,7 @@ function Ace2Inner(){ toggleAttributeOnSelection('italic'); specialHandled = true; } - if ((!specialHandled) && isTypeForCmdKey && String.fromCharCode(which).toLowerCase() == "u" && (evt.metaKey || evt.ctrlKey)) + if ((!specialHandled) && isTypeForCmdKey && String.fromCharCode(which).toLowerCase() == "u" && (evt.metaKey || evt.ctrlKey) && padShortcutEnabled.cmdU) { // cmd-U (underline) fastIncorp(15); @@ -3915,7 +3947,7 @@ function Ace2Inner(){ toggleAttributeOnSelection('underline'); specialHandled = true; } - if ((!specialHandled) && isTypeForCmdKey && String.fromCharCode(which).toLowerCase() == "5" && (evt.metaKey || evt.ctrlKey) && evt.altKey !== true) + if ((!specialHandled) && isTypeForCmdKey && String.fromCharCode(which).toLowerCase() == "5" && (evt.metaKey || evt.ctrlKey) && evt.altKey !== true && padShortcutEnabled.cmd5) { // cmd-5 (strikethrough) fastIncorp(13); @@ -3923,7 +3955,7 @@ function Ace2Inner(){ toggleAttributeOnSelection('strikethrough'); specialHandled = true; } - if ((!specialHandled) && isTypeForCmdKey && String.fromCharCode(which).toLowerCase() == "l" && (evt.metaKey || evt.ctrlKey) && evt.shiftKey) + if ((!specialHandled) && isTypeForCmdKey && String.fromCharCode(which).toLowerCase() == "l" && (evt.metaKey || evt.ctrlKey) && evt.shiftKey && padShortcutEnabled.cmdShiftL) { // cmd-shift-L (unorderedlist) fastIncorp(9); @@ -3931,7 +3963,7 @@ function Ace2Inner(){ doInsertUnorderedList() specialHandled = true; } - if ((!specialHandled) && isTypeForCmdKey && (String.fromCharCode(which).toLowerCase() == "n" || String.fromCharCode(which) == 1) && (evt.metaKey || evt.ctrlKey) && evt.shiftKey) + if ((!specialHandled) && isTypeForCmdKey && (String.fromCharCode(which).toLowerCase() == "n" || String.fromCharCode(which) == 1) && (evt.metaKey || evt.ctrlKey) && evt.shiftKey && padShortcutEnabled.cmdShiftN) { // cmd-shift-N (orderedlist) fastIncorp(9); @@ -3939,13 +3971,13 @@ function Ace2Inner(){ doInsertOrderedList() specialHandled = true; } - if ((!specialHandled) && isTypeForCmdKey && String.fromCharCode(which).toLowerCase() == "c" && (evt.metaKey || evt.ctrlKey) && evt.shiftKey) { + if ((!specialHandled) && isTypeForCmdKey && String.fromCharCode(which).toLowerCase() == "c" && (evt.metaKey || evt.ctrlKey) && evt.shiftKey && padShortcutEnabled.cmdShiftC) { // cmd-shift-C (clearauthorship) fastIncorp(9); evt.preventDefault(); CMDS.clearauthorship(); } - if ((!specialHandled) && isTypeForCmdKey && String.fromCharCode(which).toLowerCase() == "h" && (evt.ctrlKey)) + if ((!specialHandled) && isTypeForCmdKey && String.fromCharCode(which).toLowerCase() == "h" && (evt.ctrlKey) && padShortcutEnabled.cmdH) { // cmd-H (backspace) fastIncorp(20); @@ -3953,7 +3985,7 @@ function Ace2Inner(){ doDeleteKey(); specialHandled = true; } - if((evt.which == 36 && evt.ctrlKey == true)){ setScrollY(0); } // Control Home send to Y = 0 + if((evt.which == 36 && evt.ctrlKey == true) && padShortcutEnabled.ctrlHome){ setScrollY(0); } // Control Home send to Y = 0 if((evt.which == 33 || evt.which == 34) && type == 'keydown' && !evt.ctrlKey){ evt.preventDefault(); // This is required, browsers will try to do normal default behavior on page up / down and the default behavior SUCKS @@ -3972,12 +4004,12 @@ function Ace2Inner(){ var linesCount = rep.lines.length(); // total count of lines in pad IE 10 var numberOfLinesInViewport = newVisibleLineRange[1] - newVisibleLineRange[0]; // How many lines are in the viewport right now? - if(isPageUp){ + if(isPageUp && padShortcutEnabled.pageUp){ rep.selEnd[0] = rep.selEnd[0] - numberOfLinesInViewport; // move to the bottom line +1 in the viewport (essentially skipping over a page) rep.selStart[0] = rep.selStart[0] - numberOfLinesInViewport; // move to the bottom line +1 in the viewport (essentially skipping over a page) } - if(isPageDown){ // if we hit page down + if(isPageDown && padShortcutEnabled.pageDown){ // if we hit page down if(rep.selEnd[0] >= oldVisibleLineRange[0]){ // If the new viewpoint position is actually further than where we are right now rep.selStart[0] = oldVisibleLineRange[1] -1; // dont go further in the page down than what's visible IE go from 0 to 50 if 50 is visible on screen but dont go below that else we miss content rep.selEnd[0] = oldVisibleLineRange[1] -1; // dont go further in the page down than what's visible IE go from 0 to 50 if 50 is visible on screen but dont go below that else we miss content