-
Notifications
You must be signed in to change notification settings - Fork 4
/
mousetrap.help.js
252 lines (214 loc) · 8.35 KB
/
mousetrap.help.js
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
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
/**
* Copyright 2012 Michael Sverdlin (github.com/Sveder)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Mousetrap.help.js is an extension to the Mousetrap.js library that automatically
* generates and shows a lightbox overlay with help text for the bound keys.
*
* @version 1.2.2
* @url https://github.com/Sveder/mousetrap.help
*/
window.Mousetrap = (function(Mousetrap) {
/* Constants */
/**
* Original Moustrap functions to pass the "overloaded" functions to.
*/
var _mousetrap_bind = Mousetrap.bind;
var _mousetrap_unbind = Mousetrap.unbind;
var _mousetrap_reset = Mousetrap.reset;
/**
* CSS style for the help overlay. Look at the unminified_help.css file
* for the unminified version.
*
* @type {string}
**/
var _DEFAULT_CSS_HELP_STYLE = ".mousetrap_lightbox{font-family:arial,sans-serif;position:fixed;top:10%;left:15%;width:65%;height:65%;border-radius:10px;background-color:#222;opacity:.85;z-index:1002;overflow:auto;color:#FFF;padding:25px}#mousetrap_title{margin-left:20px;padding-bottom:10px;font-size:1.17em;font-weight:700}#mousetrap_table{margin:7px}#mousetrap_table td{padding:2px 4px}#mousetrap_table .mousetrap_sequence{width:50%}#mousetrap_table .mousetrap_explanation{width:47%}.mousetrap_key{font-family:'courier new',monospace;font-size:120%;color:#FF0}.mousetrap_sequence{text-align:right}";
/* Private Variables */
/**
* Maps the char sequence and action to the help text, kinda mirroring _direct_map
*
* @type {Object}
**/
var _help_map = {};
/**
* The shortcut help div that should be added and removed as we want
* to show or hide the help.
*
* @type {Node|null}
*/
var _help_div;
/**
* Whether the help CSS was added to the DOM already. This should only happen once and only
* if the help is ever actually used so to not to pollute the DOM.
*
* @type {boolean}
*/
var _help_css_was_added = false;
/**
* Setup the help keybinding - ? to show and hide help and escape to hide it.
*/
function _setupHelpBindings()
{
Mousetrap.bind('?', _toggleHelp, "Show or hide this help overlay.");
Mousetrap.bind('esc', _hideHelp, "Hide this help overlay if it is showing.");
}
/**
* Ensure that the help CSS was actually added to the dom. It should only be added once.
* It also has to be right after the head element.
*/
function _ensureCSS()
{
//Only add CSS once:
if (_help_css_was_added)
{
return;
}
//Add the style element to just after the head so that other style declaration
//or linked CSS can override it:
var styleElement = document.createElement("style");
styleElement.type = "text/css";
var head = document.getElementsByTagName("head")[0];
if (styleElement.styleSheet)
{
styleElement.styleSheet.cssText = _DEFAULT_CSS_HELP_STYLE;
}
else
{
styleElement.appendChild(document.createTextNode(_DEFAULT_CSS_HELP_STYLE));
}
head.appendChild(styleElement);
_help_css_was_added = true;
}
/**
* Show auto generated help overlay.
* This creates a ton of HTML and appends it to the DOM.
*/
function _showHelp()
{
_ensureCSS();
//Start the lighbox HTML showing title and starting the div table to make it look pretty:
var mappingHtml = "<div class='mousetrap_lightbox'><span id='mousetrap_title'>Keyboard Shortcuts</span>";
mappingHtml += "<table id='mousetrap_table'>";
//Add all the mappings with their respective class:
for (var charSeq in _help_map)
{
var shortcut = charSeq;
//Change spaces to " then " like gmail does for sequences:
shortcut = shortcut.replace(/ /g, "</span> then <span class='mousetrap_key'>");
shortcut = shortcut.replace(/\+/g, "</span> + <span class='mousetrap_key'>");
shortcut = shortcut.replace(/,/g, "</span> , <span class='mousetrap_key'>");
var seqHTML = "<tr><td class='mousetrap_sequence'><span class='mousetrap_key'>";
seqHTML += shortcut;
seqHTML += "</span></td><td>:</td>";
var helpText = _help_map[charSeq];
mappingHtml += seqHTML + "<td class='mousetrap_explanation'>" + helpText + "</td></tr>";
}
mappingHtml += '</table>';
_help_div = document.createElement("div");
_help_div.innerHTML = mappingHtml;
document.getElementsByTagName('body')[0].appendChild(_help_div);
}
/*
* Toggle the help overlay - show it if hidden and hide if it is shown.
*/
function _toggleHelp()
{
//If _help_div is not null we're already showing help, so hide it instead:
if (_help_div)
{
_hideHelp();
return;
}
_showHelp();
}
/*
* Hide the help overlay if it exists.
*/
function _hideHelp()
{
//If the _help_div doesn't exist we're not showing help and there is nothing
//to hide:
if (!_help_div)
{
return;
}
document.getElementsByTagName('body')[0].removeChild(_help_div);
_help_div = null;
}
/**
* binds an event to mousetrap
*
* can be a single key, a combination of keys separated with +,
* an array of keys, or a sequence of keys separated by spaces
*
* be sure to list the modifier keys first to make sure that the
* correct key ends up getting bound (the last key in the pattern)
*
* @param {string|Array} keys
* @param {Function} callback
* @param {string=} action - 'keypress', 'keydown', or 'keyup'. If action is
* not one of those, then helpText will be overriden with the value of
* action.
* @param {string=} helpText The help text to show in the help lightbox.
* @returns {void}
*/
Mousetrap.bind = function(keys, callback, action, helpText) {
// if the third variable is not one of the allowed action values use that for help text
// (this is such a bad idea but for now I'll go with it)
if (action !== 'keyup' && action !== 'keydown' && action !== 'keypress' && action !== undefined) {
helpText = action;
action = undefined;
}
//Figure out help text - either the parameter or the bound function name:
helpText = helpText || callback.name;
//This is a stupid hack I need because Mousetrap.js uses this. in unbind
//and as I redefine it here this. becomes the global window object. This means
//I basically can't redefine unbind and just check that the bind in unbind is called.
//https://github.com/ccampbell/mousetrap/issues/84 - ARGH!
if (callback.toString() === (function() {}).toString())
{
if (_help_map[keys])
{
delete _help_map[keys];
}
}
else
{
_help_map[keys] = helpText;
}
return _mousetrap_bind(keys, callback, action);
};
Mousetrap.reset = function()
{
var ret = _mousetrap_reset();
_help_map = {};
_setupHelpBindings();
return ret;
};
/**
* Show the help lightbox (overlay).
*/
Mousetrap.showHelp = _showHelp;
/**
* Hide the help lightbox (overlay).
*/
Mousetrap.hideHelp = _hideHelp;
/**
* Toggle the visibility of the help lightbox (overlay).
*/
Mousetrap.toggleHelp = _toggleHelp;
//Add the help lightbox shortcut:
_setupHelpBindings();
return Mousetrap;
})(window.Mousetrap);