OK, to finalna, poprawiona wersja wtyczki jQuery obsługującej klawiaturę. W odróżnieniu od poprzedniej nie ma żadnych wymagań poza samym jQuery, automatycznie także dba o to, żeby pola typu input i textarea nie były objęte działaniem tej funkcji, NAWET TE KTÓRE ZOSTANĄ UTWORZONE JUŻ PO JEJ WYWOŁANIU. Do dyspozycji są tradycyjnie zmienne jQuery._SHIFT, jQuery._CTRL i jQuery._ALT. Do wykorzystania na elemencie document, zapewnia globalną obsługę skrótów klawiaturowych.
Można przypisać sobie takie klawisze jak DEL (kod 46), CTRL+SHIFT+strzałki (zaznaczanie tekstu) czy np same strzałki (domyślnie przewijanie strony).
Uwagi:
- żeby przeglądarka nie obsłużyła skrótu domyślnego, funkcja obsługi musi zwrócić false (tylko false, nie 0, nie null, nie undefined)
- funkcja obsługi nie może uruchamiać elementów modalnych takich jak alert() i dialog() - inaczej poprawna obsługa tylko w Operze 10.x
Sprawdzone w poważnej aplikacji (edytorze graficznym).
/**
* Binds keyboard events, cross-browser compatible, prevents default handlers if listener returned false
* @param {string} events
* @param {function} listener
* @param {object} data
*/
jQuery.prototype.xbind = function(events, listener, data) {
var i, kEvents = ['keydown', 'keypress', 'keyup'], fEvents = events ? events.split(' ') : [], kEvent = true;
var set_EDIT = function() { jQuery._EDIT = true; }, clear_EDIT = function() { jQuery._EDIT = false; };
for (i in fEvents) if (kEvents.indexOf(fEvents[i]) < 0) kEvent = false;
if (kEvent) { // keyboard events
if (typeof(jQuery._SHIFT) == 'undefined') jQuery._SHIFT = false;
if (typeof(jQuery._CTRL) == 'undefined') jQuery._CTRL = false;
if (typeof(jQuery._ALT) == 'undefined') jQuery._ALT = false;
if (typeof(jQuery._PREVENT_DEFAULT) == 'undefined') jQuery._PREVENT_DEFAULT = false;
if (typeof(jQuery._EDIT == 'undefined')) jQuery._EDIT = false;
$(document).bind('DOMNodeInserted', function(event) {
if (['input','textarea'].indexOf(event.target.nodeName.toLowerCase()) >= 0)
$('input,textarea').unbind('focus', set_EDIT).unbind('blur', clear_EDIT).bind('focus', set_EDIT).bind('blur', clear_EDIT);
});
$(document).trigger('DOMNodeInserted');
$(this).bind(kEvents.join(' '), function(theEvent) {
var tag = this.nodeName ? this.nodeName.toLowerCase() : '?';
switch (theEvent.type) {
case 'keydown':
switch (theEvent.which) {
case 16: jQuery._SHIFT = true; break;
case 17: jQuery._CTRL = true; break;
case 18: jQuery._ALT = true; break;
default:
if (!jQuery._EDIT) {
if (fEvents.indexOf('keydown') >= 0 || fEventsOf('keypress') >= 0)
if (listener(theEvent, data) === false) {
theEvent.preventDefault(); // for Chrome
jQuery._PREVENT_DEFAULT = true;
} else {
jQuery._PREVENT_DEFAULT = false;
}
}
}
break;
case 'keypress':
if (jQuery._PREVENT_DEFAULT) {
theEvent.preventDefault(); // for Opera and Firefox
jQuery._PREVENT_DEFAULT = false;
}
break;
case 'keyup':
switch (theEvent.which) {
case 16: jQuery._SHIFT = false; break;
case 17: jQuery._CTRL = false; break;
case 18: jQuery._ALT = false; break;
default:
if (jQuery._PREVENT_DEFAULT) {
theEvent.preventDefault();
jQuery._PREVENT_DEFAULT = false;
}
if (!jQuery._EDIT) {
if (fEvents.indexOf('keyup') >= 0) if (listener(theEvent, data) === false) theEvent.preventDefault();
}
}
}
}, data);
} else { // all other events
$(this).bind(events, listener, data);
}
};
Prosty test:
<!doctype html>
jquery.xbind test
* { font-family: sans-serif; font-size: 10px; }
<script src="http://code.jquery.com/jquery-1.4.2.min.js"></script>
$(document).ready(function() {
var body = document.getElementsByTagName('body').item(0);
var div = document.createElement('div'); div.setAttribute('style', 'height:2048px;border:1px dotted blue');
var input = document.createElement('input'); input.setAttribute('type', 'text');
body.appendChild(input);
body.appendChild(div);
$(document).xbind('keydown', function(event) {
if (jQuery._CTRL && event.which == 82) {
div.appendChild(document.createTextNode('CTRL+R'));
div.appendChild(document.createElement('br'));
return false;
}
});
});