Fire Event Programmatically in Javascript and bind with Shortcut key

In most desktop applications, shortcut keys are standard configuration, for some of them, indispensible. This is not the case for web applications, both the designer and users don't care about shortcut keys. One of the reasons is many web applications are small and simple, don't have many UI elements, only a few simple buttons like Ok and Cancel, 99% of so called web application are just some kind of CMS, interacting with a database, major operations include create, update, delete, retrieve(the CRUD). The second reason is web application itself lives in a browser which already registered most of the frequently used shortcut keys, the convention is Ctrl + W to colse a window or tab, Ctrl + T to create a new tab, Ctrl + S to save the current web page, Ctrl + P to print the page, Alt + D to focus in the address bar, Ctrl + D to add the page to Favorite, etc. To overwrite them would face a tough challenge: there compatibility problem across the browser platform and it will undermine the user experience because of the inconsistency from page to page.

What if you really want it? The answer is do it yourself. If you need to click a button 20 times a day, instead moving your mouse over the button , click an then switch back to keyboard, using a shortcut key can significantly save your time. You can even package a series of actions into one shortcut key, for example, create a new post, paste content and save. This is so called automation, or a fancier name: macro. With a small piece of snippet Javascript code you can paste to the console, you can create your own automation or macro to boost your productivity.

Paste the following code to your Javascript console, it contains two modules, first one is for firing event on a DOM element, the second is a utility to register shortcut key.

 
function triggerEvent(el, eventName, options) {
  var event;
  if (window.CustomEvent) {
      event = new CustomEvent(eventName, options);
  } else {
    event = document.createEvent('CustomEvent');
    event.initCustomEvent(eventName, true, true, options);
  }
  el.dispatchEvent(event);
}
 
shortcut = {
    'all_shortcuts':{},//All the shortcuts are stored in this array
    'add': function(shortcut_combination,callback,opt) {
        //Provide a set of default options
        var default_options = {
            'type':'keydown',
            'propagate':false,
            'disable_in_input':false,
            'target':document,
            'keycode':false
        }
        if(!opt) opt = default_options;
        else {
            for(var dfo in default_options) {
                if(typeof opt[dfo] == 'undefined') opt[dfo] = default_options[dfo];
            }
        }
 
        var ele = opt.target;
        if(typeof opt.target == 'string') ele = document.getElementById(opt.target);
        var ths = this;
        shortcut_combination = shortcut_combination.toLowerCase();
 
        //The function to be called at keypress
        var func = function(e) {
            e = e || window.event;
 
            if(opt['disable_in_input']) { //Don't enable shortcut keys in Input, Textarea fields
                var element;
                if(e.target) element=e.target;
                else if(e.srcElement) element=e.srcElement;
                if(element.nodeType==3) element=element.parentNode;
 
                if(element.tagName == 'INPUT' || element.tagName == 'TEXTAREA') return;
            }
 
            //Find Which key is pressed
            if (e.keyCode) code = e.keyCode;
            else if (e.which) code = e.which;
            var character = String.fromCharCode(code).toLowerCase();
 
            if(code == 188) character=","; //If the user presses , when the type is onkeydown
            if(code == 190) character="."; //If the user presses , when the type is onkeydown
 
            var keys = shortcut_combination.split("+");
            //Key Pressed - counts the number of valid keypresses - if it is same as the number of keys, the shortcut function is invoked
            var kp = 0;
 
            //Work around for stupid Shift key bug created by using lowercase - as a result the shift+num combination was broken
            var shift_nums = {
                "`":"~",
                "1":"!",
                "2":"@",
                "3":"#",
                "4":"$",
                "5":"%",
                "6":"^",
                "7":"&",
                "8":"*",
                "9":"(",
                "0":")",
                "-":"_",
                "=":"+",
                ";":":",
                "'":"\"",
                ",":"<",
                ".":">",
                "/":"?",
                "\\":"|"
            }
            //Special Keys - and their codes
            var special_keys = {
                'esc':27,
                'escape':27,
                'tab':9,
                'space':32,
                'return':13,
                'enter':13,
                'backspace':8,
 
                'scrolllock':145,
                'scroll_lock':145,
                'scroll':145,
                'capslock':20,
                'caps_lock':20,
                'caps':20,
                'numlock':144,
                'num_lock':144,
                'num':144,
 
                'pause':19,
                'break':19,
 
                'insert':45,
                'home':36,
                'delete':46,
                'end':35,
 
                'pageup':33,
                'page_up':33,
                'pu':33,
 
                'pagedown':34,
                'page_down':34,
                'pd':34,
 
                'left':37,
                'up':38,
                'right':39,
                'down':40,
 
                'f1':112,
                'f2':113,
                'f3':114,
                'f4':115,
                'f5':116,
                'f6':117,
                'f7':118,
                'f8':119,
                'f9':120,
                'f10':121,
                'f11':122,
                'f12':123
            }
 
            var modifiers = { 
                shift: { wanted:false, pressed:false},
                ctrl : { wanted:false, pressed:false},
                alt  : { wanted:false, pressed:false},
                meta : { wanted:false, pressed:false}    //Meta is Mac specific
            };
 
            if(e.ctrlKey)    modifiers.ctrl.pressed = true;
            if(e.shiftKey)    modifiers.shift.pressed = true;
            if(e.altKey)    modifiers.alt.pressed = true;
            if(e.metaKey)   modifiers.meta.pressed = true;
 
            for(var i=0; k=keys[i],i<keys.length; i++) {
                //Modifiers
                if(k == 'ctrl' || k == 'control') {
                    kp++;
                    modifiers.ctrl.wanted = true;
 
                } else if(k == 'shift') {
                    kp++;
                    modifiers.shift.wanted = true;
 
                } else if(k == 'alt') {
                    kp++;
                    modifiers.alt.wanted = true;
                } else if(k == 'meta') {
                    kp++;
                    modifiers.meta.wanted = true;
                } else if(k.length > 1) { //If it is a special key
                    if(special_keys[k] == code) kp++;
 
                } else if(opt['keycode']) {
                    if(opt['keycode'] == code) kp++;
 
                } else { //The special keys did not match
                    if(character == k) kp++;
                    else {
                        if(shift_nums[character] && e.shiftKey) { //Stupid Shift key bug created by using lowercase
                            character = shift_nums[character]; 
                            if(character == k) kp++;
                        }
                    }
                }
            }
 
            if(kp == keys.length && 
                        modifiers.ctrl.pressed == modifiers.ctrl.wanted &&
                        modifiers.shift.pressed == modifiers.shift.wanted &&
                        modifiers.alt.pressed == modifiers.alt.wanted &&
                        modifiers.meta.pressed == modifiers.meta.wanted) {
                callback(e);
 
                if(!opt['propagate']) { //Stop the event
                    //e.cancelBubble is supported by IE - this will kill the bubbling process.
                    e.cancelBubble = true;
                    e.returnValue = false;
 
                    //e.stopPropagation works in Firefox.
                    if (e.stopPropagation) {
                        e.stopPropagation();
                        e.preventDefault();
                    }
                    return false;
                }
            }
        }
        this.all_shortcuts[shortcut_combination] = {
            'callback':func, 
            'target':ele, 
            'event': opt['type']
        };
        //Attach the function with the event
        if(ele.addEventListener) ele.addEventListener(opt['type'], func, false);
        else if(ele.attachEvent) ele.attachEvent('on'+opt['type'], func);
        else ele['on'+opt['type']] = func;
    },
 
    //Remove the shortcut - just specify the shortcut and I will remove the binding
    'remove':function(shortcut_combination) {
        shortcut_combination = shortcut_combination.toLowerCase();
        var binding = this.all_shortcuts[shortcut_combination];
        delete(this.all_shortcuts[shortcut_combination])
        if(!binding) return;
        var type = binding['event'];
        var ele = binding['target'];
        var callback = binding['callback'];
 
        if(ele.detachEvent) ele.detachEvent('on'+type, callback);
        else if(ele.removeEventListener) ele.removeEventListener(type, callback, false);
        else ele['on'+type] = false;
    }
}
 

To simulate the clicking of a button, do the following

 
shortcut.add("Ctrl+D", function(){
    (
    function newArticle(){
        var newButton = document.getElementsByClassName("button_default")[3].childNodes[0];
        triggerEvent(newButton, "mousedown",{bubbles: true, cancelable: true});
        triggerEvent(newButton, "mouseup",{bubbles: true, cancelable: true});
    }
    )();
});
 
shortcut.add("Ctrl+S", function(){
    (
        function saveArticle(){
            var saveButton = $(".panel_default .button_innerbox",document.getElementsByClassName("dialogbox_default")[1]);
            triggerEvent(saveButton, "mousedown",{bubbles: true, cancelable: true});
            triggerEvent(saveButton, "mouseup",{bubbles: true, cancelable: true});        
        }
    )();
});
 

Sometimes you need to trigger event inside an iFrame element, for example, some web based editors use iFrame as edit area, you want to bind some editing actions to a shortcut key, you can set the target as the iFrame element. Here is an example

 
    shortcut.add("Alt+C", function(){
        //console.log("clear format");
        clearFormatFromIframe();
        },
        {'target':document.getElementsByClassName("editor_design")[0].childNodes[0].contentDocument});
 

This should be executed everytime the iFrame is created, you can put the invocation in the onload event of the iFrame.