about summary refs log tree commit diff stats
path: root/wiki/lib/scripts/hotkeys.js
blob: 76a277aea2ad6b09e7d2850def2b16678b58d90d (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
pre { line-height: 125%; }
td.linenos .normal { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }
span.linenos { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }
td.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
span.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
.highlight .hll { background-color: #ffffcc }
.highlight .c { color: #888888 } /* Comment */
.highlight .err { color: #a61717; background-color: #e3d2d2 } /* Error */
.highlight .k { color: #008800; font-weight: bold } /* Keyword */
.highlight .ch { color: #888888 } /* Comment.Hashbang */
.highlight .cm { color: #888888 } /* Comment.Multiline */
.highlight .cp { color: #cc0000; font-weight: bold } /* Comment.Preproc */
.highlight .cpf { color: #888888 } /* Comment.PreprocFile */
.highlight .c1 { color: #888888 } /* Comment.Single */
.highlight .cs { color: #cc0000; font-weight: bold; background-color: #fff0f0 } /* Comment.Special */
.highlight .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */
.highlight .ge { font-style: italic } /* Generic.Emph */
.highlight .ges { font-weight: bold; font-style: italic } /* Generic.EmphStrong */
.highlight .gr { color: #aa0000 } /* Generic.Error */
.highlight .gh { color: #333333 } /* Generic.Heading */
.highlight .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */
.highlight .go { color: #888888 } /* Generic.Output */
.highlight .gp { color: #555555 } /* Generic.Prompt */
.highlight .gs { font-weight: bold } /* Generic.Strong */
.highlight .gu { color: #666666 } /* Generic.Subheading */
.highlight .gt { color: #aa0000 } /* Generic.Traceback */
.highlight .kc { color: #008800; font-weight: bold } /* Keyword.Constant */
.highlight .kd { color: #008800; font-weight: bold } /* Keyword.Declaration */
.highlight .kn { color: #008800; font-weight: bold } /* Keyword.Namespace */
.highlight .kp { color: #008800 } /* Keyword.Pseudo */
.highlight .kr { color: #008800; font-weight: bold } /* Keyword.Reserved */
.highlight .kt { color: #888888; font-weight: bold } /* Keyword.Type */
.highlight .m { color: #0000DD; font-weight: bold } /* Literal.Number */
.highlight .s { color: #dd2200; background-color: #fff0f0 } /* Literal.String */
.highlight .na { color: #336699 } /* Name.Attribute */
.highlight .nb { color: #003388 } /* Name.Builtin */
.highlight .nc { color: #bb0066; font-weight: bold } /* Name.Class */
.highlight .no { color: #003366; font-weight: bold } /* Name.Constant */
.highlight .nd { color: #555555 } /* Name.Decorator */
.highlight .ne { color: #bb0066; font-weight: bold } /* Name.Exception */
.highlight .nf { color: #0066bb; font-weight: bold } /* Name.Function */
.highlight .nl { color: #336699; font-style: italic } /* Name.Label */
.highlight .nn { color: #bb0066; font-weight: bold } /* Name.Namespace */
.highlight .py { color: #336699; font-weight: bold } /* Name.Property */
.highlight .nt { color: #bb0066; font-weight: bold } /* Name.Tag */
.highlight .nv { color: #336699 } /* Name.Variable */
.highlight .ow { color: #008800 } /* Operator.Word */
.highlight .w { color: #bbbbbb } /* Text.Whitespace */
.highlight .mb { color: #0000DD; font-weight: bold } /* Literal.Number.Bin */
.highlight .mf { color: #0000DD; font-weight: bold } /* Literal.Number.Float */
.highlight .mh { color: #0000DD; font-weight: bold } /* Literal.Number.Hex */
.highlight .mi { color: #0000DD; font-weight: bold } /* Literal.Number.Integer */
.highlight .mo { color: #0000DD; font-weight: bold } /* Literal.Number.Oct */
.highlight .sa { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Affix */
.highlight .sb { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Backtick */
.highlight .sc { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Char */
.highlight .dl { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Delimiter */
.highlight .sd { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Doc */
.highlight .s2 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Double */
.highlight .se { color: #0044dd; background-color: #fff0f0 } /* Literal.String.Escape */
.highlight .sh { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Heredoc */
.highlight .si { color: #3333bb; background-color: #fff0f0 } /* Literal.String.Interpol */
.highlight .sx { color: #22bb22; background-color: #f0fff0 } /* Literal.String.Other */
.highlight .sr { color: #008800; background-color: #fff0ff } /* Literal.String.Regex */
.highlight .s1 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Single */
.highlight .ss { color: #aa6600; background-color: #fff0f0 } /* Literal.String.Symbol */
.highlight .bp { color: #003388 } /* Name.Builtin.Pseudo */
.highlight .fm { color: #0066bb; font-weight: bold } /* Name.Function.Magic */
.highlight .vc { color: #336699 } /* Name.Variable.Class */
.highlight .vg { color: #dd7700 } /* Name.Variable.Global */
.highlight .vi { color: #3333bb } /* Name.Variable.Instance */
.highlight .vm { color: #336699 } /* Name.Variable.Magic */
.highlight .il { color: #0000DD; font-weight: bold } /* Literal.Number.Integer.Long */
# Copyright (C) 2009, 2010  Roman Zimbelmann <romanz@lavabit.com>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.

"""
This module can catch interrupt signals which would otherwise
rise a KeyboardInterrupt exception and handle it by pushing
a Ctrl+C (ASCII value 3) to the curses getch stack.
"""

import curses
import signal

_do_catch_interrupt = True

def catch_interrupt(boolean=True):
	"""Should interrupts be caught and simulate a ^C press in curses?"""
	global _do_catch_interrupt
	old_value = _do_catch_interrupt
	_do_catch_interrupt = bool(boolean)
	return old_value

# The handler which will be used in signal.signal()
def _interrupt_handler(a1, a2):
	global _do_catch_interrupt
	# if a keyboard-interrupt occurs...
	if _do_catch_interruptpre { line-height: 125%; }
td.linenos .normal { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }
span.linenos { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }
td.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
span.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
.highlight .hll { background-color: #ffffcc }
.highlight .c { color: #888888 } /* Comment */
.highlight .err { color: #a61717; background-color: #e3d2d2 } /* Error */
.highlight .k { color: #008800; font-weight: bold } /* Keyword */
.highlight .ch { color: #888888 } /* Comment.Hashbang */
.highlight .cm { color: #888888 } /* Comment.Multiline */
.highlight .cp { color: #cc0000; font-weight: bold } /* Comment.Preproc */
.highlight .cpf { color: #888888 } /* Comment.PreprocFile */
.highlight .c1 { color: #888888 } /* Comment.Single */
.highlight .cs { color: #cc0000; font-weight: bold; background-color: #fff0f0 } /* Comment.Special */
.highlight .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */
.highlight .ge { font-style: italic } /* Generic.Emph */
.highlight .ges { font-weight: bold; font-style: italic } /* Generic.EmphStrong */
.highlight .gr { color: #aa0000 } /* Generic.Error */
.highlight .gh { color: #333333 } /* Generic.Heading */
.highlight .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */
.highlight .go { color: #888888 } /* Generic.Output */
.highlight .gp { color: #555555 } /* Generic.Prompt */
.highlight .gs { font-weight: bold } /* Generic.Strong */
.highlight .gu { color: #666666 } /* Generic.Subheading */
.highlight .gt { color: #aa0000 } /* Generic.Traceback */
.highlight .kc { color: #008800; font-weight: bold } /* Keyword.Constant */
.highlight .kd { color: #008800; font-weight: bold } /* Keyword.Declaration */
.highlight .kn { color: #008800; font-weight: bold } /* Keyword.Namespace */
.highlight .kp { color: #008800 } /* Keyword.Pseudo */
.highlight .kr { color: #008800; font-weight: bold } /* Keyword.Reserved */
.highlight .kt { color: #888888; font-weight: bold } /* Keyword.Type */
.highlight .m { color: #0000DD; font-weight: bold } /* Literal.Number */
.highlight .s { color: #dd2200; background-color: #fff0f0 } /* Literal.String */
.highlight .na { color: #336699 } /* Name.Attribute */
.highlight .nb { color: #003388 } /* Name.Builtin */
.highlight .nc { color: #bb0066; font-weight: bold } /* Name.Class */
.highlight .no { color: #003366; font-weight: bold } /* Name.Constant */
.highlight .nd { color: #555555 } /* Name.Decorator */
.highlight .ne { color: #bb0066; font-weight: bold } /* Name.Exception */
.highlight .nf { color: #0066bb; font-weight: bold } /* Name.Function */
.highlight .nl { color: #336699; font-style: italic } /* Name.Label */
.highlight .nn { color: #bb0066; font-weight: bold } /* Name.Namespace */
.highlight .py { color: #336699; font-weight: bold } /* Name.Property */
.highlight .nt { color: #bb0066; font-weight: bold } /* Name.Tag */
.highlight .nv { color: #336699 } /* Name.Variable */
.highlight .ow { color: #008800 } /* Operator.Word */
.highlight .w { color: #bbbbbb } /* Text.Whitespace */
.highlight .mb { color: #0000DD; font-weight: bold } /* Literal.Number.Bin */
.highlight .mf { color: #0000DD; font-weight: bold } /* Literal.Number.Float */
.highlight .mh { color: #0000DD; font-weight: bold } /* Literal.Number.Hex */
.highlight .mi { color: #0000DD; font-weight: bold } /* Literal.Number.Integer */
.highlight .mo { color: #0000DD; font-weight: bold } /* Literal.Number.Oct */
.highlight .sa { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Affix */
.highlight .sb { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Backtick */
.highlight .sc { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Char */
.highlight .dl { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Delimiter */
.highlight .sd { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Doc */
.highlight .s2 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Double */
.highlight .se { color: #0044dd; background-color: #fff0f0 } /* Literal.String.Escape */
.highlight .sh { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Heredoc */
.highlight .si { color: #3333bb; background-color: #fff0f0 } /* Literal.String.Interpol */
.highlight .sx { color: #22bb22; background-color: #f0fff0 } /* Literal.String.Other */
.highlight .sr { color: #008800; background-color: #fff0ff } /* Literal.String.Regex */
.highlight .s1 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Single */
.highlight .ss { color: #aa6600; background-color: #fff0f0 } /* Literal.String.Symbol */
.highlight .bp { color: #003388 } /* Name.Builtin.Pseudo */
.highlight .fm { color: #0066bb; font-weight: bold } /* Name.Function.Magic */
.highlight .vc { color: #336699 } /* Name.Variable.Class */
.highlight .vg { color: #dd7700 } /* Name.Variable.Global */
.highlight .vi { color: #3333bb } /* Name.Variable.Instance */
.highlight .vm { color: #336699 } /* Name.Variable.Magic */
.highlight .il { color: #0000DD; font-weight: bold } /* Literal.Number.Integer.Long */
/**
 * Some of these scripts were taken from TinyMCE (http://tinymce.moxiecode.com/) and were modified for DokuWiki
 *
 * Class handles accesskeys using javascript and also provides ability
 * to register and use other hotkeys as well.
 *
 * @author Marek Sacha <sachamar@fel.cvut.cz>
 */
function Hotkeys() {

    this.shortcuts = new Array();

    /**
     * Set modifier keys, for instance:
     *  this.modifier = 'ctrl';
     *  this.modifier = 'ctrl+shift';
     *  this.modifier = 'ctrl+alt+shift';
     *  this.modifier = 'alt';
     *  this.modifier = 'alt+shift';
     *
     *  overwritten in intitialize (see below)
     */
    this.modifier = 'ctrl+alt';

    /**
     * Initialization
     *
     * This function looks up all the accesskeys used in the current page
     * (at anchor elements and button elements [type="submit"]) and registers
     * appropriate shortcuts.
     *
     * Secondly, initialization registers listeners on document to catch all
     * keyboard events.
     *
     * @author Marek Sacha <sachamar@fel.cvut.cz>
     */
    this.initialize = function() {
        var t = this;

        //switch modifier key based on OS FS#1958
        if(is_macos){
            t.modifier = 'ctrl+alt';
        }else{
            t.modifier = 'alt';
        }

        /**
         * Lookup all anchors with accesskey and register event - go to anchor
         * target.
         */
        var anchors = document.getElementsByTagName("a");
        t.each(anchors, function(a) {
            if (a.accessKey != "") {
                t.addShortcut(t.modifier + '+' + a.accessKey, function() {
                    location.href = a.href;
                });
                a.accessKey = '';
            }
        });

        /**
         * Lookup all button [type="submit"] with accesskey and register event -
         * perform "click" on a button.
         */
        var inputs = document.getElementsByTagName("button");
        t.each(inputs, function(i) {
            if (i.type == "submit" && i.accessKey != "") {
                t.addShortcut(t.modifier + '+' + i.accessKey, function() {
                    i.click();
                });
                i.accessKey = '';
            }
        });

        /**
         * Lookup all buttons with accesskey and register event -
         * perform "click" on a button.
         */
        var buttons = document.getElementsByTagName("button");
        t.each(buttons, function(b) {
            if (b.accessKey != "") {
                t.addShortcut(t.modifier + '+' + b.accessKey, function() {
                    b.click();
                });
                b.accessKey = '';
            }
        });

        /**
         * Register listeners on document to catch keyboard events.
         */

        addEvent(document,'keyup',function (e) {
            return t.onkeyup.call(t,e);
        });

        addEvent(document,'keypress',function (e) {
            return t.onkeypress.call(t,e);
        });

        addEvent(document,'keydown',function (e) {
            return t.onkeydown.call(t,e);
        });
    };

    /**
     * Keyup processing function
     * Function returns true if keyboard event has registered handler, and
     * executes the handler function.
     *
     * @param e KeyboardEvent
     * @author Marek Sacha <sachamar@fel.cvut.cz>
     * @return b boolean
     */
    this.onkeyup = function(e) {
        var t = this;
        var v = t.findShortcut(e);
        if (v != null && v != false) {
            v.func.call(t);
            return false;
        }
        return true;
    };

    /**
     * Keydown processing function
     * Function returns true if keyboard event has registered handler
     *
     * @param e KeyboardEvent
     * @author Marek Sacha <sachamar@fel.cvut.cz>
     * @return b boolean
     */
    this.onkeydown = function(e) {
        var t = this;
        var v = t.findShortcut(e);
        if (v != null && v != false) {
            return false;
        }
        return true;
    };

    /**
     * Keypress processing function
     * Function returns true if keyboard event has registered handler
     *
     * @param e KeyboardEvent
     * @author Marek Sacha <sachamar@fel.cvut.cz>
     * @return b
     */
    this.onkeypress = function(e) {
        var t = this;
        var v = t.findShortcut(e);
        if (v != null && v != false) {
            return false;
        }
        return true;
    };

    /**
     * Register new shortcut
     *
     * This function registers new shortcuts, each shortcut is defined by its
     * modifier keys and a key (with + as delimiter). If shortcut is pressed
     * cmd_function is performed.
     *
     * For example:
     *  pa = "ctrl+alt+p";
     *  pa = "shift+alt+s";
     *
     * Full example of method usage:
     *  hotkeys.addShortcut('ctrl+s',function() {
     *      document.getElementByID('form_1').submit();
     *  });
     *
     * @param pa String description of the shortcut (ctrl+a, ctrl+shift+p, .. )
     * @param cmd_func Function to be called if shortcut is pressed
     * @author Marek Sacha <sachamar@fel.cvut.cz>
     */
    this.addShortcut = function(pa, cmd_func) {
        var t = this;

        var o = {
            func : cmd_func,
            alt : false,
            ctrl : false,
            shift : false
        };

        t.each(t.explode(pa, '+'), function(v) {
            switch (v) {
                case 'alt':
                case 'ctrl':
                case 'shift':
                    o[v] = true;
                    break;

                default:
                    o.charCode = v.charCodeAt(0);
                    o.keyCode = v.toUpperCase().charCodeAt(0);
            }
        });

        t.shortcuts.push((o.ctrl ? 'ctrl' : '') + ',' + (o.alt ? 'alt' : '') + ',' + (o.shift ? 'shift' : '') + ',' + o.keyCode,  o);

        return true;
    };

    /**
     * @property isMac
     */
    this.isMac = is_macos;

    /**
     * Apply function cb on each element of o in the namespace of s
     * @param o Array of objects
     * @param cb Function to be called on each object
     * @param s Namespace to be used during call of cb (default namespace is o)
     * @author Marek Sacha <sachamar@fel.cvut.cz>
     */
    this.each = function(o, cb, s) {
        var n, l;

        if (!o)
            return 0;

        s = s || o;

        if (o.length !== undefined) {
            // Indexed arrays, needed for Safari
            for (n=0, l = o.length; n < l; n++) {
                if (cb.call(s, o[n], n, o) === false)
                    return 0;
            }
        } else {
            // Hashtables
            for (n in o) {
                if (o.hasOwnProperty(n)) {
                    if (cb.call(s, o[n], n, o) === false)
                        return 0;
                }
            }
        }

        return 1;
    };

    /**
     * Explode string according to delimiter
     * @param s String
     * @param d Delimiter (default ',')
     * @author Marek Sacha <sachamar@fel.cvut.cz>
     * @return a Array of tokens
     */
    this.explode = function(s, d) {
        return  s.split(d || ',');
    };

    /**
     * Find if the shortcut was registered
     *
     * @param e KeyboardEvent
     * @author Marek Sacha <sachamar@fel.cvut.cz>
     * @return v Shortcut structure or null if not found
     */
    this.findShortcut = function (e) {
        var t = this;
        var v = null;

        /* No modifier key used - shortcut does not exist */
        if (!e.altKey && !e.ctrlKey && !e.metaKey) {
            return v;
        }

        t.each(t.shortcuts, function(o) {
            if (o.ctrl != e.ctrlKey)
                return;

            if (o.alt != e.altKey)
                return;

            if (o.shift != e.shiftKey)
                return;

            if (e.keyCode == o.keyCode || (e.charCode && e.charCode == o.charCode)) {
                v = o;
                return;
            }
        });
        return v;
    };
}

/**
 * Init function for hotkeys. Called from js.php, to ensure hotkyes are initialized after toolbar.
 * Call of addInitEvent(initializeHotkeys) is unnecessary now.
 *
 * @author Marek Sacha <sachamar@fel.cvut.cz>
 */
function initializeHotkeys() {
    var hotkeys = new Hotkeys();
    hotkeys.initialize();
}