// ==UserScript==
// @name Duolingo - Easy Accents
// @description Makes typing characters with accents and diacritics easy! Just use the Alt key!
// @match *://www.duolingo.com/*
// @author @HodofHod
// @version 0.1.9
// ==/UserScript==
/*
Copyright (c) 2013-2014 HodofHod (https://github.com/HodofHod)
Licensed under the MIT License (MIT)
Full text of the license is available at https://raw2.github.com/HodofHod/Userscripts/master/LICENSE
*/
// Technically, these are accents, diacritics, and ligatures,
// but accents is the commonest of those terms so that's the script's title.
// Some languages have characters that can be accented in many different ways
// (like the French 'e' or the Portuguese 'a'). While those letters are reachable by tapping ALT multiple times,
// it may become unweildy and annoying. I am open to other suggestions.
function inject(f) {
var script = document.createElement('script');
script.type = 'text/javascript';
script.setAttribute('name', 'easy_accents');
script.textContent = '(' + f.toString() + ')()';
document.body.appendChild(script);
}
inject(main);
function main(){
console.log('Duo Easy Accents');
var maps = {
es: {'A':'á', 'E':'é', 'I':'í', 'O':'ó', 'U':'úü', // Spanish
'N':'ñ', '1':'¡', '!':'¡', '?':'¿'},
fr: {'A':'àâæ', 'E':'èéêë', 'I':'îï', 'O':'ôœ', 'U':'ùûü', 'C':'ç'}, // French
pt: {'A':'ãáâà', 'E':'éê', 'I':'í', 'O':'õóô', 'U':'úü', 'C':'ç'}, // Portuguese
de: {'A':'ä', 'O':'ö', 'U':'ü', 'S':'ß'}, // German
it: {'A':'àá', 'E':'èé', 'I':'ìí', 'O':'òó', 'U':'ùú'}, // Italian
pl: {'A':'ą', 'C':'ć', 'E':'ę', 'L':'ł', 'N':'ń', // Polish
'O':'ó', 'S':'ś', 'X':'ź', 'Z':'żź'},
ro: {'A':'ăâ', 'I':'î', 'S':'şș', 'T':'ţț'}, // Romanian
hu: {'A':'á', 'E':'é', 'I':'í', 'O':'öóő', 'U':'üúű'}, // Hungarian
dn: {'A':'á', 'E':'éèë', 'I':'ï', 'O':'óö', 'U':'ü'}, // Dutch (Netherlands)
tr: {'C':'ç', 'G':'ğ', 'I':'ıİ', 'O':'ö', 'S':'ş', 'U':'ü'}, // Turkish
da: {'A':'æå', 'O':'ø'}, // Danish
ga: {'A':'á', 'E':'é', 'I':'í', 'O':'ó', 'U':'ú'}, // Irish
sv: {'A':'åä', 'O':'ö', 'E':'é'}, // Swedish
eo: {'C':'ĉ', 'G':'ĝ', 'H':'ĥ', 'J':'ĵ', 'S':'ŝ', 'U':'ŭ'}, // Esperanto
},
taps = 0,
last_press = [];
$(document).on('keydown', '[lang][lang!=en]', function (e) {
//If the pressed key isn't already pressed, return
if (!e.altKey || e.which===18) { return; }
//If the same key is pressed in a short period of time, increment taps
taps = (last_press[0] === e.which && new Date() - last_press[1] <= 750) ? taps+1 : 1;
//Get accented chr; taps-1 is the 0-indexed accented chr to get.
var chr = get_char(e.target.lang, String.fromCharCode(e.which), taps-1);
if (!chr){ return false; }
chr = e.shiftKey ? chr.toUpperCase() : chr;
//Insert chr into textarea; Replace last chr for multiple taps by taps>1
insert_char(this, chr, taps>1);
last_press = [e.which, new Date()];
//To override any other Alt+<x> hotkeys.
return false;
});
function get_char(lang, base, index){
if (!maps[lang]){ return false; }
var char_lst = maps[lang][base];
return char_lst ? char_lst[index % char_lst.length] : false;
}
function insert_char(textarea, new_char, del){
var text = textarea.value,
start = textarea.selectionStart,
end = textarea.selectionEnd;
//Insert the character. If we're rotating through alternate letters, remove the last character.
textarea.value = text.slice(0, del ? end-1 : start) + new_char + text.slice(end);
//Move the caret. If deleting the previous, the caret should remain. (Hence x+!del)
//If replacing selected text (and not deleting previous), caret should unselect and be start+1
textarea.setSelectionRange(start+!del, (end-start&&!del ? start : end) +!del);
}
$(document).on('keyup', '[lang][lang!=en]', function (e){
if (e.which === 18){ //ALT keyup
//Reset the last tapped key.
last_press = [];
//This ALT keyup isn't from an ALT+<x> combo, so modify the last char
if (taps===0){
var base = this.value.slice(this.selectionEnd-1, this.selectionEnd),
index;
$.each(maps[e.target.lang], function(key, val){
index = val.indexOf(base.toLowerCase());
if (index > -1){
base = (base.toUpperCase() === base) ? key : key.toLowerCase();
return false;
}
});
var chr = get_char(e.target.lang, base.toUpperCase(), index+1);
if (!chr){ return false; }
chr = /[A-Z]/.test(base) ? chr.toUpperCase() : chr;
insert_char(this, chr, true);
}
taps = 0;
return false;
}
});
}
Donate for the site OpenUserJS
Are you sure you want to go to an external site to donate a monetary value?
WARNING: Some countries laws may supersede the payment processors policy such as the GDPR and PayPal. While it is highly appreciated to donate, please check with your countries privacy and identity laws regarding privacy of information first. Use at your utmost discretion.