mirror of
https://github.com/neocities/neocities.git
synced 2025-04-25 01:32:36 +02:00
Fix keyboard binding for proprietary computer (mac)
This commit is contained in:
parent
b6a759d036
commit
6ef52c3020
3 changed files with 7 additions and 979 deletions
|
@ -1,961 +0,0 @@
|
||||||
/**
|
|
||||||
* Title: KeyboardJS
|
|
||||||
* Version: v0.4.1
|
|
||||||
* Description: KeyboardJS is a flexible and easy to use keyboard binding
|
|
||||||
* library.
|
|
||||||
* Author: Robert Hurst.
|
|
||||||
*
|
|
||||||
* Copyright 2011, Robert William Hurst
|
|
||||||
* Licenced under the BSD License.
|
|
||||||
* See https://raw.github.com/RobertWHurst/KeyboardJS/master/license.txt
|
|
||||||
*/
|
|
||||||
(function(context, factory) {
|
|
||||||
|
|
||||||
//INDEXOF POLLYFILL
|
|
||||||
[].indexOf||(Array.prototype.indexOf=function(a,b,c){for(c=this.length,b=(c+~~b)%c;b<c&&(!(b in this)||this[b]!==a);b++);return b^c?b:-1;});
|
|
||||||
|
|
||||||
//AMD
|
|
||||||
if(typeof define === 'function' && define.amd) { define(constructAMD); }
|
|
||||||
|
|
||||||
//CommonJS
|
|
||||||
else if(typeof module !== 'undefined') {constructCommonJS()}
|
|
||||||
|
|
||||||
//GLOBAL
|
|
||||||
else { constructGlobal(); }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Construct AMD version of the library
|
|
||||||
*/
|
|
||||||
function constructAMD() {
|
|
||||||
|
|
||||||
//create a library instance
|
|
||||||
return init(context);
|
|
||||||
|
|
||||||
//spawns a library instance
|
|
||||||
function init(context) {
|
|
||||||
var library;
|
|
||||||
library = factory(context, 'amd');
|
|
||||||
library.fork = init;
|
|
||||||
return library;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Construct CommonJS version of the library
|
|
||||||
*/
|
|
||||||
function constructCommonJS() {
|
|
||||||
|
|
||||||
//create a library instance
|
|
||||||
module.exports = init(context);
|
|
||||||
|
|
||||||
return;
|
|
||||||
|
|
||||||
//spawns a library instance
|
|
||||||
function init(context) {
|
|
||||||
var library;
|
|
||||||
library = factory(context, 'CommonJS');
|
|
||||||
library.fork = init;
|
|
||||||
return library;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Construct a Global version of the library
|
|
||||||
*/
|
|
||||||
function constructGlobal() {
|
|
||||||
var library;
|
|
||||||
|
|
||||||
//create a library instance
|
|
||||||
library = init(context);
|
|
||||||
|
|
||||||
//spawns a library instance
|
|
||||||
function init(context) {
|
|
||||||
var library, namespaces = [], previousValues = {};
|
|
||||||
|
|
||||||
library = factory(context, 'global');
|
|
||||||
library.fork = init;
|
|
||||||
library.noConflict = noConflict;
|
|
||||||
library.noConflict('KeyboardJS', 'k');
|
|
||||||
return library;
|
|
||||||
|
|
||||||
//sets library namespaces
|
|
||||||
function noConflict( ) {
|
|
||||||
var args, nI, newNamespaces;
|
|
||||||
|
|
||||||
newNamespaces = Array.prototype.slice.apply(arguments);
|
|
||||||
|
|
||||||
for(nI = 0; nI < namespaces.length; nI += 1) {
|
|
||||||
if(typeof previousValues[namespaces[nI]] === 'undefined') {
|
|
||||||
delete context[namespaces[nI]];
|
|
||||||
} else {
|
|
||||||
context[namespaces[nI]] = previousValues[namespaces[nI]];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
previousValues = {};
|
|
||||||
|
|
||||||
for(nI = 0; nI < newNamespaces.length; nI += 1) {
|
|
||||||
if(typeof newNamespaces[nI] !== 'string') {
|
|
||||||
throw new Error('Cannot replace namespaces. All new namespaces must be strings.');
|
|
||||||
}
|
|
||||||
previousValues[newNamespaces[nI]] = context[newNamespaces[nI]];
|
|
||||||
context[newNamespaces[nI]] = library;
|
|
||||||
}
|
|
||||||
|
|
||||||
namespaces = newNamespaces;
|
|
||||||
|
|
||||||
return namespaces;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
})(this, function(targetWindow, env) {
|
|
||||||
var KeyboardJS = {}, locales = {}, locale, map, macros, activeKeys = [], bindings = [], activeBindings = [],
|
|
||||||
activeMacros = [], aI, usLocale;
|
|
||||||
targetWindow = targetWindow || window;
|
|
||||||
|
|
||||||
///////////////////////
|
|
||||||
// DEFAULT US LOCALE //
|
|
||||||
///////////////////////
|
|
||||||
|
|
||||||
//define US locale
|
|
||||||
//If you create a new locale please submit it as a pull request or post
|
|
||||||
// it in the issue tracker at
|
|
||||||
// http://github.com/RobertWhurst/KeyboardJS/issues/
|
|
||||||
usLocale = {
|
|
||||||
"map": {
|
|
||||||
|
|
||||||
//general
|
|
||||||
"3": ["cancel"],
|
|
||||||
"8": ["backspace"],
|
|
||||||
"9": ["tab"],
|
|
||||||
"12": ["clear"],
|
|
||||||
"13": ["enter"],
|
|
||||||
"16": ["shift"],
|
|
||||||
"17": ["ctrl"],
|
|
||||||
"18": ["alt", "menu"],
|
|
||||||
"19": ["pause", "break"],
|
|
||||||
"20": ["capslock"],
|
|
||||||
"27": ["escape", "esc"],
|
|
||||||
"32": ["space", "spacebar"],
|
|
||||||
"33": ["pageup"],
|
|
||||||
"34": ["pagedown"],
|
|
||||||
"35": ["end"],
|
|
||||||
"36": ["home"],
|
|
||||||
"37": ["left"],
|
|
||||||
"38": ["up"],
|
|
||||||
"39": ["right"],
|
|
||||||
"40": ["down"],
|
|
||||||
"41": ["select"],
|
|
||||||
"42": ["printscreen"],
|
|
||||||
"43": ["execute"],
|
|
||||||
"44": ["snapshot"],
|
|
||||||
"45": ["insert", "ins"],
|
|
||||||
"46": ["delete", "del"],
|
|
||||||
"47": ["help"],
|
|
||||||
"91": ["command", "windows", "win", "super", "leftcommand", "leftwindows", "leftwin", "leftsuper"],
|
|
||||||
"92": ["command", "windows", "win", "super", "rightcommand", "rightwindows", "rightwin", "rightsuper"],
|
|
||||||
"145": ["scrolllock", "scroll"],
|
|
||||||
"186": ["semicolon", ";"],
|
|
||||||
"187": ["equal", "equalsign", "="],
|
|
||||||
"188": ["comma", ","],
|
|
||||||
"189": ["dash", "-"],
|
|
||||||
"190": ["period", "."],
|
|
||||||
"191": ["slash", "forwardslash", "/"],
|
|
||||||
"192": ["graveaccent", "`"],
|
|
||||||
"219": ["openbracket", "["],
|
|
||||||
"220": ["backslash", "\\"],
|
|
||||||
"221": ["closebracket", "]"],
|
|
||||||
"222": ["apostrophe", "'"],
|
|
||||||
|
|
||||||
//0-9
|
|
||||||
"48": ["zero", "0"],
|
|
||||||
"49": ["one", "1"],
|
|
||||||
"50": ["two", "2"],
|
|
||||||
"51": ["three", "3"],
|
|
||||||
"52": ["four", "4"],
|
|
||||||
"53": ["five", "5"],
|
|
||||||
"54": ["six", "6"],
|
|
||||||
"55": ["seven", "7"],
|
|
||||||
"56": ["eight", "8"],
|
|
||||||
"57": ["nine", "9"],
|
|
||||||
|
|
||||||
//numpad
|
|
||||||
"96": ["numzero", "num0"],
|
|
||||||
"97": ["numone", "num1"],
|
|
||||||
"98": ["numtwo", "num2"],
|
|
||||||
"99": ["numthree", "num3"],
|
|
||||||
"100": ["numfour", "num4"],
|
|
||||||
"101": ["numfive", "num5"],
|
|
||||||
"102": ["numsix", "num6"],
|
|
||||||
"103": ["numseven", "num7"],
|
|
||||||
"104": ["numeight", "num8"],
|
|
||||||
"105": ["numnine", "num9"],
|
|
||||||
"106": ["nummultiply", "num*"],
|
|
||||||
"107": ["numadd", "num+"],
|
|
||||||
"108": ["numenter"],
|
|
||||||
"109": ["numsubtract", "num-"],
|
|
||||||
"110": ["numdecimal", "num."],
|
|
||||||
"111": ["numdivide", "num/"],
|
|
||||||
"144": ["numlock", "num"],
|
|
||||||
|
|
||||||
//function keys
|
|
||||||
"112": ["f1"],
|
|
||||||
"113": ["f2"],
|
|
||||||
"114": ["f3"],
|
|
||||||
"115": ["f4"],
|
|
||||||
"116": ["f5"],
|
|
||||||
"117": ["f6"],
|
|
||||||
"118": ["f7"],
|
|
||||||
"119": ["f8"],
|
|
||||||
"120": ["f9"],
|
|
||||||
"121": ["f10"],
|
|
||||||
"122": ["f11"],
|
|
||||||
"123": ["f12"]
|
|
||||||
},
|
|
||||||
"macros": [
|
|
||||||
|
|
||||||
//secondary key symbols
|
|
||||||
['shift + `', ["tilde", "~"]],
|
|
||||||
['shift + 1', ["exclamation", "exclamationpoint", "!"]],
|
|
||||||
['shift + 2', ["at", "@"]],
|
|
||||||
['shift + 3', ["number", "#"]],
|
|
||||||
['shift + 4', ["dollar", "dollars", "dollarsign", "$"]],
|
|
||||||
['shift + 5', ["percent", "%"]],
|
|
||||||
['shift + 6', ["caret", "^"]],
|
|
||||||
['shift + 7', ["ampersand", "and", "&"]],
|
|
||||||
['shift + 8', ["asterisk", "*"]],
|
|
||||||
['shift + 9', ["openparen", "("]],
|
|
||||||
['shift + 0', ["closeparen", ")"]],
|
|
||||||
['shift + -', ["underscore", "_"]],
|
|
||||||
['shift + =', ["plus", "+"]],
|
|
||||||
['shift + (', ["opencurlybrace", "opencurlybracket", "{"]],
|
|
||||||
['shift + )', ["closecurlybrace", "closecurlybracket", "}"]],
|
|
||||||
['shift + \\', ["verticalbar", "|"]],
|
|
||||||
['shift + ;', ["colon", ":"]],
|
|
||||||
['shift + \'', ["quotationmark", "\""]],
|
|
||||||
['shift + !,', ["openanglebracket", "<"]],
|
|
||||||
['shift + .', ["closeanglebracket", ">"]],
|
|
||||||
['shift + /', ["questionmark", "?"]]
|
|
||||||
]
|
|
||||||
};
|
|
||||||
//a-z and A-Z
|
|
||||||
for (aI = 65; aI <= 90; aI += 1) {
|
|
||||||
usLocale.map[aI] = String.fromCharCode(aI + 32);
|
|
||||||
usLocale.macros.push(['shift + ' + String.fromCharCode(aI + 32) + ', capslock + ' + String.fromCharCode(aI + 32), [String.fromCharCode(aI)]]);
|
|
||||||
}
|
|
||||||
registerLocale('us', usLocale);
|
|
||||||
getSetLocale('us');
|
|
||||||
|
|
||||||
|
|
||||||
//////////
|
|
||||||
// INIT //
|
|
||||||
//////////
|
|
||||||
|
|
||||||
//enable the library
|
|
||||||
enable();
|
|
||||||
|
|
||||||
|
|
||||||
/////////
|
|
||||||
// API //
|
|
||||||
/////////
|
|
||||||
|
|
||||||
//assemble the library and return it
|
|
||||||
KeyboardJS.enable = enable;
|
|
||||||
KeyboardJS.disable = disable;
|
|
||||||
KeyboardJS.activeKeys = getActiveKeys;
|
|
||||||
KeyboardJS.releaseKey = removeActiveKey;
|
|
||||||
KeyboardJS.pressKey = addActiveKey;
|
|
||||||
KeyboardJS.on = createBinding;
|
|
||||||
KeyboardJS.clear = removeBindingByKeyCombo;
|
|
||||||
KeyboardJS.clear.key = removeBindingByKeyName;
|
|
||||||
KeyboardJS.locale = getSetLocale;
|
|
||||||
KeyboardJS.locale.register = registerLocale;
|
|
||||||
KeyboardJS.macro = createMacro;
|
|
||||||
KeyboardJS.macro.remove = removeMacro;
|
|
||||||
KeyboardJS.key = {};
|
|
||||||
KeyboardJS.key.name = getKeyName;
|
|
||||||
KeyboardJS.key.code = getKeyCode;
|
|
||||||
KeyboardJS.combo = {};
|
|
||||||
KeyboardJS.combo.active = isSatisfiedCombo;
|
|
||||||
KeyboardJS.combo.parse = parseKeyCombo;
|
|
||||||
KeyboardJS.combo.stringify = stringifyKeyCombo;
|
|
||||||
return KeyboardJS;
|
|
||||||
|
|
||||||
|
|
||||||
//////////////////////
|
|
||||||
// INSTANCE METHODS //
|
|
||||||
//////////////////////
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Enables KeyboardJS
|
|
||||||
*/
|
|
||||||
function enable() {
|
|
||||||
if(targetWindow.addEventListener) {
|
|
||||||
targetWindow.document.addEventListener('keydown', keydown, false);
|
|
||||||
targetWindow.document.addEventListener('keyup', keyup, false);
|
|
||||||
targetWindow.addEventListener('blur', reset, false);
|
|
||||||
targetWindow.addEventListener('webkitfullscreenchange', reset, false);
|
|
||||||
targetWindow.addEventListener('mozfullscreenchange', reset, false);
|
|
||||||
} else if(targetWindow.attachEvent) {
|
|
||||||
targetWindow.document.attachEvent('onkeydown', keydown);
|
|
||||||
targetWindow.document.attachEvent('onkeyup', keyup);
|
|
||||||
targetWindow.attachEvent('onblur', reset);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Exits all active bindings and disables KeyboardJS
|
|
||||||
*/
|
|
||||||
function disable() {
|
|
||||||
reset();
|
|
||||||
if(targetWindow.removeEventListener) {
|
|
||||||
targetWindow.document.removeEventListener('keydown', keydown, false);
|
|
||||||
targetWindow.document.removeEventListener('keyup', keyup, false);
|
|
||||||
targetWindow.removeEventListener('blur', reset, false);
|
|
||||||
targetWindow.removeEventListener('webkitfullscreenchange', reset, false);
|
|
||||||
targetWindow.removeEventListener('mozfullscreenchange', reset, false);
|
|
||||||
} else if(targetWindow.detachEvent) {
|
|
||||||
targetWindow.document.detachEvent('onkeydown', keydown);
|
|
||||||
targetWindow.document.detachEvent('onkeyup', keyup);
|
|
||||||
targetWindow.detachEvent('onblur', reset);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
////////////////////
|
|
||||||
// EVENT HANDLERS //
|
|
||||||
////////////////////
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Exits all active bindings. Optionally passes an event to all binding
|
|
||||||
* handlers.
|
|
||||||
* @param {KeyboardEvent} event [Optional]
|
|
||||||
*/
|
|
||||||
function reset(event) {
|
|
||||||
activeKeys = [];
|
|
||||||
pruneMacros();
|
|
||||||
pruneBindings(event);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Key down event handler.
|
|
||||||
* @param {KeyboardEvent} event
|
|
||||||
*/
|
|
||||||
function keydown(event) {
|
|
||||||
var keyNames, keyName, kI;
|
|
||||||
keyNames = getKeyName(event.keyCode);
|
|
||||||
if(keyNames.length < 1) { return; }
|
|
||||||
event.isRepeat = false;
|
|
||||||
for(kI = 0; kI < keyNames.length; kI += 1) {
|
|
||||||
keyName = keyNames[kI];
|
|
||||||
if (getActiveKeys().indexOf(keyName) != -1)
|
|
||||||
event.isRepeat = true;
|
|
||||||
addActiveKey(keyName);
|
|
||||||
}
|
|
||||||
executeMacros();
|
|
||||||
executeBindings(event);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Key up event handler.
|
|
||||||
* @param {KeyboardEvent} event
|
|
||||||
*/
|
|
||||||
function keyup(event) {
|
|
||||||
var keyNames, kI;
|
|
||||||
keyNames = getKeyName(event.keyCode);
|
|
||||||
if(keyNames.length < 1) { return; }
|
|
||||||
for(kI = 0; kI < keyNames.length; kI += 1) {
|
|
||||||
removeActiveKey(keyNames[kI]);
|
|
||||||
}
|
|
||||||
pruneMacros();
|
|
||||||
pruneBindings(event);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Accepts a key code and returns the key names defined by the current
|
|
||||||
* locale.
|
|
||||||
* @param {Number} keyCode
|
|
||||||
* @return {Array} keyNames An array of key names defined for the key
|
|
||||||
* code as defined by the current locale.
|
|
||||||
*/
|
|
||||||
function getKeyName(keyCode) {
|
|
||||||
return map[keyCode] || [];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Accepts a key name and returns the key code defined by the current
|
|
||||||
* locale.
|
|
||||||
* @param {Number} keyName
|
|
||||||
* @return {Number|false}
|
|
||||||
*/
|
|
||||||
function getKeyCode(keyName) {
|
|
||||||
var keyCode;
|
|
||||||
for(keyCode in map) {
|
|
||||||
if(!map.hasOwnProperty(keyCode)) { continue; }
|
|
||||||
if(map[keyCode].indexOf(keyName) > -1) { return keyCode; }
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
////////////
|
|
||||||
// MACROS //
|
|
||||||
////////////
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Accepts a key combo and an array of key names to inject once the key
|
|
||||||
* combo is satisfied.
|
|
||||||
* @param {String} combo
|
|
||||||
* @param {Array} injectedKeys
|
|
||||||
*/
|
|
||||||
function createMacro(combo, injectedKeys) {
|
|
||||||
if(typeof combo !== 'string' && (typeof combo !== 'object' || typeof combo.push !== 'function')) {
|
|
||||||
throw new Error("Cannot create macro. The combo must be a string or array.");
|
|
||||||
}
|
|
||||||
if(typeof injectedKeys !== 'object' || typeof injectedKeys.push !== 'function') {
|
|
||||||
throw new Error("Cannot create macro. The injectedKeys must be an array.");
|
|
||||||
}
|
|
||||||
macros.push([combo, injectedKeys]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Accepts a key combo and clears any and all macros bound to that key
|
|
||||||
* combo.
|
|
||||||
* @param {String} combo
|
|
||||||
*/
|
|
||||||
function removeMacro(combo) {
|
|
||||||
var macro;
|
|
||||||
if(typeof combo !== 'string' && (typeof combo !== 'object' || typeof combo.push !== 'function')) { throw new Error("Cannot remove macro. The combo must be a string or array."); }
|
|
||||||
for(mI = 0; mI < macros.length; mI += 1) {
|
|
||||||
macro = macros[mI];
|
|
||||||
if(compareCombos(combo, macro[0])) {
|
|
||||||
removeActiveKey(macro[1]);
|
|
||||||
macros.splice(mI, 1);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Executes macros against the active keys. Each macro's key combo is
|
|
||||||
* checked and if found to be satisfied, the macro's key names are injected
|
|
||||||
* into active keys.
|
|
||||||
*/
|
|
||||||
function executeMacros() {
|
|
||||||
var mI, combo, kI;
|
|
||||||
for(mI = 0; mI < macros.length; mI += 1) {
|
|
||||||
combo = parseKeyCombo(macros[mI][0]);
|
|
||||||
if(activeMacros.indexOf(macros[mI]) === -1 && isSatisfiedCombo(combo)) {
|
|
||||||
activeMacros.push(macros[mI]);
|
|
||||||
for(kI = 0; kI < macros[mI][1].length; kI += 1) {
|
|
||||||
addActiveKey(macros[mI][1][kI]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Prunes active macros. Checks each active macro's key combo and if found
|
|
||||||
* to no longer to be satisfied, each of the macro's key names are removed
|
|
||||||
* from active keys.
|
|
||||||
*/
|
|
||||||
function pruneMacros() {
|
|
||||||
var mI, combo, kI;
|
|
||||||
for(mI = 0; mI < activeMacros.length; mI += 1) {
|
|
||||||
combo = parseKeyCombo(activeMacros[mI][0]);
|
|
||||||
if(isSatisfiedCombo(combo) === false) {
|
|
||||||
for(kI = 0; kI < activeMacros[mI][1].length; kI += 1) {
|
|
||||||
removeActiveKey(activeMacros[mI][1][kI]);
|
|
||||||
}
|
|
||||||
activeMacros.splice(mI, 1);
|
|
||||||
mI -= 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//////////////
|
|
||||||
// BINDINGS //
|
|
||||||
//////////////
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a binding object, and, if provided, binds a key down hander and
|
|
||||||
* a key up handler. Returns a binding object that emits keyup and
|
|
||||||
* keydown events.
|
|
||||||
* @param {String} keyCombo
|
|
||||||
* @param {Function} keyDownCallback [Optional]
|
|
||||||
* @param {Function} keyUpCallback [Optional]
|
|
||||||
* @return {Object} binding
|
|
||||||
*/
|
|
||||||
function createBinding(keyCombo, keyDownCallback, keyUpCallback) {
|
|
||||||
var api = {}, binding, subBindings = [], bindingApi = {}, kI,
|
|
||||||
subCombo;
|
|
||||||
|
|
||||||
//break the combo down into a combo array
|
|
||||||
if(typeof keyCombo === 'string') {
|
|
||||||
keyCombo = parseKeyCombo(keyCombo);
|
|
||||||
}
|
|
||||||
|
|
||||||
//bind each sub combo contained within the combo string
|
|
||||||
for(kI = 0; kI < keyCombo.length; kI += 1) {
|
|
||||||
binding = {};
|
|
||||||
|
|
||||||
//stringify the combo again
|
|
||||||
subCombo = stringifyKeyCombo([keyCombo[kI]]);
|
|
||||||
|
|
||||||
//validate the sub combo
|
|
||||||
if(typeof subCombo !== 'string') { throw new Error('Failed to bind key combo. The key combo must be string.'); }
|
|
||||||
|
|
||||||
//create the binding
|
|
||||||
binding.keyCombo = subCombo;
|
|
||||||
binding.keyDownCallback = [];
|
|
||||||
binding.keyUpCallback = [];
|
|
||||||
|
|
||||||
//inject the key down and key up callbacks if given
|
|
||||||
if(keyDownCallback) { binding.keyDownCallback.push(keyDownCallback); }
|
|
||||||
if(keyUpCallback) { binding.keyUpCallback.push(keyUpCallback); }
|
|
||||||
|
|
||||||
//stash the new binding
|
|
||||||
bindings.push(binding);
|
|
||||||
subBindings.push(binding);
|
|
||||||
}
|
|
||||||
|
|
||||||
//build the binding api
|
|
||||||
api.clear = clear;
|
|
||||||
api.on = on;
|
|
||||||
return api;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Clears the binding
|
|
||||||
*/
|
|
||||||
function clear() {
|
|
||||||
var bI;
|
|
||||||
for(bI = 0; bI < subBindings.length; bI += 1) {
|
|
||||||
bindings.splice(bindings.indexOf(subBindings[bI]), 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Accepts an event name. and any number of callbacks. When the event is
|
|
||||||
* emitted, all callbacks are executed. Available events are key up and
|
|
||||||
* key down.
|
|
||||||
* @param {String} eventName
|
|
||||||
* @return {Object} subBinding
|
|
||||||
*/
|
|
||||||
function on(eventName ) {
|
|
||||||
var api = {}, callbacks, cI, bI;
|
|
||||||
|
|
||||||
//validate event name
|
|
||||||
if(typeof eventName !== 'string') { throw new Error('Cannot bind callback. The event name must be a string.'); }
|
|
||||||
if(eventName !== 'keyup' && eventName !== 'keydown') { throw new Error('Cannot bind callback. The event name must be a "keyup" or "keydown".'); }
|
|
||||||
|
|
||||||
//gather the callbacks
|
|
||||||
callbacks = Array.prototype.slice.apply(arguments, [1]);
|
|
||||||
|
|
||||||
//stash each the new binding
|
|
||||||
for(cI = 0; cI < callbacks.length; cI += 1) {
|
|
||||||
if(typeof callbacks[cI] === 'function') {
|
|
||||||
if(eventName === 'keyup') {
|
|
||||||
for(bI = 0; bI < subBindings.length; bI += 1) {
|
|
||||||
subBindings[bI].keyUpCallback.push(callbacks[cI]);
|
|
||||||
}
|
|
||||||
} else if(eventName === 'keydown') {
|
|
||||||
for(bI = 0; bI < subBindings.length; bI += 1) {
|
|
||||||
subBindings[bI].keyDownCallback.push(callbacks[cI]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//construct and return the sub binding api
|
|
||||||
api.clear = clear;
|
|
||||||
return api;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Clears the binding
|
|
||||||
*/
|
|
||||||
function clear() {
|
|
||||||
var cI, bI;
|
|
||||||
for(cI = 0; cI < callbacks.length; cI += 1) {
|
|
||||||
if(typeof callbacks[cI] === 'function') {
|
|
||||||
if(eventName === 'keyup') {
|
|
||||||
for(bI = 0; bI < subBindings.length; bI += 1) {
|
|
||||||
subBindings[bI].keyUpCallback.splice(subBindings[bI].keyUpCallback.indexOf(callbacks[cI]), 1);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
for(bI = 0; bI < subBindings.length; bI += 1) {
|
|
||||||
subBindings[bI].keyDownCallback.splice(subBindings[bI].keyDownCallback.indexOf(callbacks[cI]), 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Clears all binding attached to a given key combo. Key name order does not
|
|
||||||
* matter as long as the key combos equate.
|
|
||||||
* @param {String} keyCombo
|
|
||||||
*/
|
|
||||||
function removeBindingByKeyCombo(keyCombo) {
|
|
||||||
var bI, binding, keyName;
|
|
||||||
for(bI = 0; bI < bindings.length; bI += 1) {
|
|
||||||
binding = bindings[bI];
|
|
||||||
if(compareCombos(keyCombo, binding.keyCombo)) {
|
|
||||||
bindings.splice(bI, 1); bI -= 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Clears all binding attached to key combos containing a given key name.
|
|
||||||
* @param {String} keyName
|
|
||||||
*/
|
|
||||||
function removeBindingByKeyName(keyName) {
|
|
||||||
var bI, kI, binding;
|
|
||||||
if(keyName) {
|
|
||||||
for(bI = 0; bI < bindings.length; bI += 1) {
|
|
||||||
binding = bindings[bI];
|
|
||||||
for(kI = 0; kI < binding.keyCombo.length; kI += 1) {
|
|
||||||
if(binding.keyCombo[kI].indexOf(keyName) > -1) {
|
|
||||||
bindings.splice(bI, 1); bI -= 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
bindings = [];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Executes bindings that are active. Only allows the keys to be used once
|
|
||||||
* as to prevent binding overlap.
|
|
||||||
* @param {KeyboardEvent} event The keyboard event.
|
|
||||||
*/
|
|
||||||
function executeBindings(event) {
|
|
||||||
var bI, sBI, binding, bindingKeys, remainingKeys, cI, killEventBubble, kI, bindingKeysSatisfied,
|
|
||||||
index, sortedBindings = [], bindingWeight;
|
|
||||||
|
|
||||||
remainingKeys = [].concat(activeKeys);
|
|
||||||
for(bI = 0; bI < bindings.length; bI += 1) {
|
|
||||||
bindingWeight = extractComboKeys(bindings[bI].keyCombo).length;
|
|
||||||
if(!sortedBindings[bindingWeight]) { sortedBindings[bindingWeight] = []; }
|
|
||||||
sortedBindings[bindingWeight].push(bindings[bI]);
|
|
||||||
}
|
|
||||||
for(sBI = sortedBindings.length - 1; sBI >= 0; sBI -= 1) {
|
|
||||||
if(!sortedBindings[sBI]) { continue; }
|
|
||||||
for(bI = 0; bI < sortedBindings[sBI].length; bI += 1) {
|
|
||||||
binding = sortedBindings[sBI][bI];
|
|
||||||
bindingKeys = extractComboKeys(binding.keyCombo);
|
|
||||||
bindingKeysSatisfied = true;
|
|
||||||
for(kI = 0; kI < bindingKeys.length; kI += 1) {
|
|
||||||
if(remainingKeys.indexOf(bindingKeys[kI]) === -1) {
|
|
||||||
bindingKeysSatisfied = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(bindingKeysSatisfied && isSatisfiedCombo(binding.keyCombo)) {
|
|
||||||
activeBindings.push(binding);
|
|
||||||
for(kI = 0; kI < bindingKeys.length; kI += 1) {
|
|
||||||
index = remainingKeys.indexOf(bindingKeys[kI]);
|
|
||||||
if(index > -1) {
|
|
||||||
remainingKeys.splice(index, 1);
|
|
||||||
kI -= 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for(cI = 0; cI < binding.keyDownCallback.length; cI += 1) {
|
|
||||||
if (binding.keyDownCallback[cI](event, getActiveKeys(), binding.keyCombo) === false) {
|
|
||||||
killEventBubble = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(killEventBubble === true) {
|
|
||||||
event.preventDefault();
|
|
||||||
event.stopPropagation();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Removes bindings that are no longer satisfied by the active keys. Also
|
|
||||||
* fires the key up callbacks.
|
|
||||||
* @param {KeyboardEvent} event
|
|
||||||
*/
|
|
||||||
function pruneBindings(event) {
|
|
||||||
var bI, cI, binding, killEventBubble;
|
|
||||||
for(bI = 0; bI < activeBindings.length; bI += 1) {
|
|
||||||
binding = activeBindings[bI];
|
|
||||||
if(isSatisfiedCombo(binding.keyCombo) === false) {
|
|
||||||
for(cI = 0; cI < binding.keyUpCallback.length; cI += 1) {
|
|
||||||
if (binding.keyUpCallback[cI](event, getActiveKeys(), binding.keyCombo) === false) {
|
|
||||||
killEventBubble = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(killEventBubble === true) {
|
|
||||||
event.preventDefault();
|
|
||||||
event.stopPropagation();
|
|
||||||
}
|
|
||||||
activeBindings.splice(bI, 1);
|
|
||||||
bI -= 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////
|
|
||||||
// COMBO STRINGS //
|
|
||||||
///////////////////
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Compares two key combos returning true when they are functionally
|
|
||||||
* equivalent.
|
|
||||||
* @param {String} keyComboArrayA keyCombo A key combo string or array.
|
|
||||||
* @param {String} keyComboArrayB keyCombo A key combo string or array.
|
|
||||||
* @return {Boolean}
|
|
||||||
*/
|
|
||||||
function compareCombos(keyComboArrayA, keyComboArrayB) {
|
|
||||||
var cI, sI, kI;
|
|
||||||
keyComboArrayA = parseKeyCombo(keyComboArrayA);
|
|
||||||
keyComboArrayB = parseKeyCombo(keyComboArrayB);
|
|
||||||
if(keyComboArrayA.length !== keyComboArrayB.length) { return false; }
|
|
||||||
for(cI = 0; cI < keyComboArrayA.length; cI += 1) {
|
|
||||||
if(keyComboArrayA[cI].length !== keyComboArrayB[cI].length) { return false; }
|
|
||||||
for(sI = 0; sI < keyComboArrayA[cI].length; sI += 1) {
|
|
||||||
if(keyComboArrayA[cI][sI].length !== keyComboArrayB[cI][sI].length) { return false; }
|
|
||||||
for(kI = 0; kI < keyComboArrayA[cI][sI].length; kI += 1) {
|
|
||||||
if(keyComboArrayB[cI][sI].indexOf(keyComboArrayA[cI][sI][kI]) === -1) { return false; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks to see if a key combo string or key array is satisfied by the
|
|
||||||
* currently active keys. It does not take into account spent keys.
|
|
||||||
* @param {String} keyCombo A key combo string or array.
|
|
||||||
* @return {Boolean}
|
|
||||||
*/
|
|
||||||
function isSatisfiedCombo(keyCombo) {
|
|
||||||
var cI, sI, stage, kI, stageOffset = 0, index, comboMatches;
|
|
||||||
keyCombo = parseKeyCombo(keyCombo);
|
|
||||||
for(cI = 0; cI < keyCombo.length; cI += 1) {
|
|
||||||
comboMatches = true;
|
|
||||||
stageOffset = 0;
|
|
||||||
for(sI = 0; sI < keyCombo[cI].length; sI += 1) {
|
|
||||||
stage = [].concat(keyCombo[cI][sI]);
|
|
||||||
for(kI = stageOffset; kI < activeKeys.length; kI += 1) {
|
|
||||||
index = stage.indexOf(activeKeys[kI]);
|
|
||||||
if(index > -1) {
|
|
||||||
stage.splice(index, 1);
|
|
||||||
stageOffset = kI;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(stage.length !== 0) { comboMatches = false; break; }
|
|
||||||
}
|
|
||||||
if(comboMatches) { return true; }
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Accepts a key combo array or string and returns a flat array containing all keys referenced by
|
|
||||||
* the key combo.
|
|
||||||
* @param {String} keyCombo A key combo string or array.
|
|
||||||
* @return {Array}
|
|
||||||
*/
|
|
||||||
function extractComboKeys(keyCombo) {
|
|
||||||
var cI, sI, kI, keys = [];
|
|
||||||
keyCombo = parseKeyCombo(keyCombo);
|
|
||||||
for(cI = 0; cI < keyCombo.length; cI += 1) {
|
|
||||||
for(sI = 0; sI < keyCombo[cI].length; sI += 1) {
|
|
||||||
keys = keys.concat(keyCombo[cI][sI]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return keys;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Parses a key combo string into a 3 dimensional array.
|
|
||||||
* - Level 1 - sub combos.
|
|
||||||
* - Level 2 - combo stages. A stage is a set of key name pairs that must
|
|
||||||
* be satisfied in the order they are defined.
|
|
||||||
* - Level 3 - each key name to the stage.
|
|
||||||
* @param {String|Array} keyCombo A key combo string.
|
|
||||||
* @return {Array}
|
|
||||||
*/
|
|
||||||
function parseKeyCombo(keyCombo) {
|
|
||||||
var s = keyCombo, i = 0, op = 0, ws = false, nc = false, combos = [], combo = [], stage = [], key = '';
|
|
||||||
|
|
||||||
if(typeof keyCombo === 'object' && typeof keyCombo.push === 'function') { return keyCombo; }
|
|
||||||
if(typeof keyCombo !== 'string') { throw new Error('Cannot parse "keyCombo" because its type is "' + (typeof keyCombo) + '". It must be a "string".'); }
|
|
||||||
|
|
||||||
//remove leading whitespace
|
|
||||||
while(s.charAt(i) === ' ') { i += 1; }
|
|
||||||
while(true) {
|
|
||||||
if(s.charAt(i) === ' ') {
|
|
||||||
//white space & next combo op
|
|
||||||
while(s.charAt(i) === ' ') { i += 1; }
|
|
||||||
ws = true;
|
|
||||||
} else if(s.charAt(i) === ',') {
|
|
||||||
if(op || nc) { throw new Error('Failed to parse key combo. Unexpected , at character index ' + i + '.'); }
|
|
||||||
nc = true;
|
|
||||||
i += 1;
|
|
||||||
} else if(s.charAt(i) === '+') {
|
|
||||||
//next key
|
|
||||||
if(key.length) { stage.push(key); key = ''; }
|
|
||||||
if(op || nc) { throw new Error('Failed to parse key combo. Unexpected + at character index ' + i + '.'); }
|
|
||||||
op = true;
|
|
||||||
i += 1;
|
|
||||||
} else if(s.charAt(i) === '>') {
|
|
||||||
//next stage op
|
|
||||||
if(key.length) { stage.push(key); key = ''; }
|
|
||||||
if(stage.length) { combo.push(stage); stage = []; }
|
|
||||||
if(op || nc) { throw new Error('Failed to parse key combo. Unexpected > at character index ' + i + '.'); }
|
|
||||||
op = true;
|
|
||||||
i += 1;
|
|
||||||
} else if(i < s.length - 1 && s.charAt(i) === '!' && (s.charAt(i + 1) === '>' || s.charAt(i + 1) === ',' || s.charAt(i + 1) === '+')) {
|
|
||||||
key += s.charAt(i + 1);
|
|
||||||
op = false;
|
|
||||||
ws = false;
|
|
||||||
nc = false;
|
|
||||||
i += 2;
|
|
||||||
} else if(i < s.length && s.charAt(i) !== '+' && s.charAt(i) !== '>' && s.charAt(i) !== ',' && s.charAt(i) !== ' ') {
|
|
||||||
//end combo
|
|
||||||
if(op === false && ws === true || nc === true) {
|
|
||||||
if(key.length) { stage.push(key); key = ''; }
|
|
||||||
if(stage.length) { combo.push(stage); stage = []; }
|
|
||||||
if(combo.length) { combos.push(combo); combo = []; }
|
|
||||||
}
|
|
||||||
op = false;
|
|
||||||
ws = false;
|
|
||||||
nc = false;
|
|
||||||
//key
|
|
||||||
while(i < s.length && s.charAt(i) !== '+' && s.charAt(i) !== '>' && s.charAt(i) !== ',' && s.charAt(i) !== ' ') {
|
|
||||||
key += s.charAt(i);
|
|
||||||
i += 1;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
//unknown char
|
|
||||||
i += 1;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
//end of combos string
|
|
||||||
if(i >= s.length) {
|
|
||||||
if(key.length) { stage.push(key); key = ''; }
|
|
||||||
if(stage.length) { combo.push(stage); stage = []; }
|
|
||||||
if(combo.length) { combos.push(combo); combo = []; }
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return combos;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Stringifys a key combo.
|
|
||||||
* @param {Array|String} keyComboArray A key combo array. If a key
|
|
||||||
* combo string is given it will be returned.
|
|
||||||
* @return {String}
|
|
||||||
*/
|
|
||||||
function stringifyKeyCombo(keyComboArray) {
|
|
||||||
var cI, ccI, output = [];
|
|
||||||
if(typeof keyComboArray === 'string') { return keyComboArray; }
|
|
||||||
if(typeof keyComboArray !== 'object' || typeof keyComboArray.push !== 'function') { throw new Error('Cannot stringify key combo.'); }
|
|
||||||
for(cI = 0; cI < keyComboArray.length; cI += 1) {
|
|
||||||
output[cI] = [];
|
|
||||||
for(ccI = 0; ccI < keyComboArray[cI].length; ccI += 1) {
|
|
||||||
output[cI][ccI] = keyComboArray[cI][ccI].join(' + ');
|
|
||||||
}
|
|
||||||
output[cI] = output[cI].join(' > ');
|
|
||||||
}
|
|
||||||
return output.join(' ');
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/////////////////
|
|
||||||
// ACTIVE KEYS //
|
|
||||||
/////////////////
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the a copy of the active keys array.
|
|
||||||
* @return {Array}
|
|
||||||
*/
|
|
||||||
function getActiveKeys() {
|
|
||||||
return [].concat(activeKeys);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds a key to the active keys array, but only if it has not already been
|
|
||||||
* added.
|
|
||||||
* @param {String} keyName The key name string.
|
|
||||||
*/
|
|
||||||
function addActiveKey(keyName) {
|
|
||||||
if(keyName.match(/\s/)) { throw new Error('Cannot add key name ' + keyName + ' to active keys because it contains whitespace.'); }
|
|
||||||
if(activeKeys.indexOf(keyName) > -1) { return; }
|
|
||||||
activeKeys.push(keyName);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Removes a key from the active keys array.
|
|
||||||
* @param {String} keyNames The key name string.
|
|
||||||
*/
|
|
||||||
function removeActiveKey(keyName) {
|
|
||||||
var keyCode = getKeyCode(keyName);
|
|
||||||
if(keyCode === '91' || keyCode === '92') { activeKeys = []; } //remove all key on release of super.
|
|
||||||
else { activeKeys.splice(activeKeys.indexOf(keyName), 1); }
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/////////////
|
|
||||||
// LOCALES //
|
|
||||||
/////////////
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Registers a new locale. This is useful if you would like to add support for a new keyboard layout. It could also be useful for
|
|
||||||
* alternative key names. For example if you program games you could create a locale for your key mappings. Instead of key 65 mapped
|
|
||||||
* to 'a' you could map it to 'jump'.
|
|
||||||
* @param {String} localeName The name of the new locale.
|
|
||||||
* @param {Object} localeMap The locale map.
|
|
||||||
*/
|
|
||||||
function registerLocale(localeName, localeMap) {
|
|
||||||
|
|
||||||
//validate arguments
|
|
||||||
if(typeof localeName !== 'string') { throw new Error('Cannot register new locale. The locale name must be a string.'); }
|
|
||||||
if(typeof localeMap !== 'object') { throw new Error('Cannot register ' + localeName + ' locale. The locale map must be an object.'); }
|
|
||||||
if(typeof localeMap.map !== 'object') { throw new Error('Cannot register ' + localeName + ' locale. The locale map is invalid.'); }
|
|
||||||
|
|
||||||
//stash the locale
|
|
||||||
if(!localeMap.macros) { localeMap.macros = []; }
|
|
||||||
locales[localeName] = localeMap;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Swaps the current locale.
|
|
||||||
* @param {String} localeName The locale to activate.
|
|
||||||
* @return {Object}
|
|
||||||
*/
|
|
||||||
function getSetLocale(localeName) {
|
|
||||||
|
|
||||||
//if a new locale is given then set it
|
|
||||||
if(localeName) {
|
|
||||||
if(typeof localeName !== 'string') { throw new Error('Cannot set locale. The locale name must be a string.'); }
|
|
||||||
if(!locales[localeName]) { throw new Error('Cannot set locale to ' + localeName + ' because it does not exist. If you would like to submit a ' + localeName + ' locale map for KeyboardJS please submit it at https://github.com/RobertWHurst/KeyboardJS/issues.'); }
|
|
||||||
|
|
||||||
//set the current map and macros
|
|
||||||
map = locales[localeName].map;
|
|
||||||
macros = locales[localeName].macros;
|
|
||||||
|
|
||||||
//set the current locale
|
|
||||||
locale = localeName;
|
|
||||||
}
|
|
||||||
|
|
||||||
//return the current locale
|
|
||||||
return locale;
|
|
||||||
}
|
|
||||||
});
|
|
|
@ -47,7 +47,6 @@
|
||||||
<script src="/js/nav.min.js"></script>
|
<script src="/js/nav.min.js"></script>
|
||||||
<script src="/js/bootstrap.min.js"></script>
|
<script src="/js/bootstrap.min.js"></script>
|
||||||
<script src="/js/typeahead.bundle.js"></script>
|
<script src="/js/typeahead.bundle.js"></script>
|
||||||
<script src="/js/keyboard.js"></script>
|
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
$("a#like").tooltip({html: true})
|
$("a#like").tooltip({html: true})
|
||||||
|
|
|
@ -173,26 +173,16 @@
|
||||||
$('a#saveButton,a#saveAndExitButton').css('opacity', 1)
|
$('a#saveButton,a#saveAndExitButton').css('opacity', 1)
|
||||||
unsavedChanges = true
|
unsavedChanges = true
|
||||||
})
|
})
|
||||||
})
|
|
||||||
|
|
||||||
$().ready(function() {
|
editor.commands.addCommand({
|
||||||
KeyboardJS.on('ctrl + s', function(event, keysPressed, keyComboString) {
|
name: 'saveCommand',
|
||||||
saveTextFile(false)
|
bindKey: {win: 'Ctrl-S', mac: 'Command-S'},
|
||||||
event.preventDefault()
|
exec: function(editor) {
|
||||||
return false
|
saveTextFile(false)
|
||||||
});
|
}
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
/*
|
|
||||||
$(window).keypress(function(event) {
|
|
||||||
if(event.ctrlKey == true && event.key == 's') {
|
|
||||||
saveTextFile(false)
|
|
||||||
event.preventDefault()
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
})
|
|
||||||
*/
|
|
||||||
|
|
||||||
window.onbeforeunload = function() {
|
window.onbeforeunload = function() {
|
||||||
if(unsavedChanges == true)
|
if(unsavedChanges == true)
|
||||||
return "You have unsaved changes!"
|
return "You have unsaved changes!"
|
||||||
|
|
Loading…
Add table
Reference in a new issue