/* richTextarea { methodes { constructeur : crée l'objet addToHistory : ajoute la valeur courante du champ à l'historique historyNext : va à la prochaine valeur dans l'historique relativement à la courante. historyBack ; va à la precedente valeur relativement à la courante. insert(str) : insere la chaine str à la position du curseur ou à la fin de la selection checkKeysAction : verifie si une action a été definie pour la combinaison de touche. addShortKey(ctrl, alt, shift, key) : ajoute un raccourci clavier ou le remplaçe si existant ;) } proprietes { scrollPos : position du scroll à backup avant la perte du focus cursorStartPos : position de debut de selection ou curseur à backup avant la perte du focus cursorEndPos : position de fin de selection ou curseur à backup avant la perte du focus history : tableau de chaine, historique des valeurs successive du textarea cursorHistory : tableau d'entiers, historique des positions successive du curseur scrollHistory : tableau d'entiers, historique des positions successive du scroll currentInHistory : position actuelle au sein de l'historique keysAction : tableau de touche de raccourcis. Il est de la forme : keysAction[ctrlKey][altKey][shiftKey][keyCode] = functtion {}; } evenements { onvaluechange : evenement declancher à la modification du champs, preferable à onchange. } raccourcis { CTRL + Z : annuler derniere action CTRL + Y : refaire action CTRL + D : dupliquer la ligne ou la selection courante TAB : insert une tabulation RETURN : saut à la ligne en ajoutant les tabulation de debut de ligne selon le contexte. HOME : retour au debut de la ligne, ou au debut apres les indentations. CTRL + M : ouvre un prompt et cherche l'expression retournée. CTRL + SHIT + M : cherche la prochaine occurence entrée dans le prompt CTRL + / : ouvre un prompt et va à la ligne indiquee. ALT + P : indique la ligne. } } */ /*************************************************************************************************/ /* Modification de l'objet window pour ne pas provoquer de conflits entre les raccourcis clavier */ /*************************************************************************************************/ /* window.keysAction = new Array(); var wkA = window.keysAction; for(var i = 0; i < 2; i++) { wkA[i] = new Array(); for(var j = 0; j < 2; j++) { wkA[i][j] = new Array(); for(var k = 0; k < 2; k++) { wkA[i][j][k] = new Array(0); } } } window.checkKeysAction = function (e) { var ctrl = 0; var alt = 0; var shift = 0; var keyCode = 0; var kA = this.keysAction; if (e.ctrlKey) var ctrl = 1; if (e.altKey) var alt = 1; if (e.shiftKey) var shift = 1; if (e.keyCode) var keyCode = e.keyCode; if ( !kA || !kA[ctrl] || !kA[ctrl][alt] || !kA[ctrl][alt][shift] || !kA[ctrl][alt][shift][keyCode] ) { return true; } else { e.preventDefault(); e.returnValue = false; return false; } }; window.addEventListener('keydown', window.checkKeysAction, true); */ /*****************************************************/ /* Fonction de création des instance de richTextarea */ /*****************************************************/ function richTextarea (span) { /* Creation de l'element DOM */ var rTa = document.createElement('textarea'); /**************************************/ /* definition des nouvelle proprietes */ /**************************************/ rTa.scrollPos = 0; rTa.cursorStartPos = 0; rTa.cursorEndPos = 0; rTa.history = new Array(); rTa.scrollHistory = new Array(); rTa.cursorHistory = new Array(); rTa.currentInHistory = 0; rTa.keysAction = new Array(); rTa.lookForMatches = new Array(); rTa.lookForPos = 0; rTa.lookForCursorPos = 0; rTa.lookForExp = ''; /********************************************/ /* declaration de l'evenement onvaluechange */ /********************************************/ rTa.onvaluechange = null; /************************************************************************/ /* affectation de la structure "à la xPath" pour les raccourcis clavier */ /************************************************************************/ var kA = rTa.keysAction; for(var i = 0; i < 2; i++) { kA[i] = new Array(); for(var j = 0; j < 2; j++) { kA[i][j] = new Array(); for(var k = 0; k < 2; k++) { kA[i][j][k] = new Array(0); } } } /******************************************/ /* initialisation des ctrl + z / ctrl + y */ /******************************************/ rTa.history[0] = ''; rTa.scrollHistory[0] = 0; rTa.cursorHistory[0] = 0; /****************************/ /* affectation des methodes */ /****************************/ /* historique */ rTa.addToHistory = function () { if (this.history[this.currentInHistory] == this.value) return false; this.currentInHistory++; var cI = this.currentInHistory; while ( cI < this.history.length - 1 ) this.history.pop(); this.history[cI] = this.value; this.cursorHistory[cI] = this.selectionStart; this.scrollHistory[cI] = this.scrollTop; return true; }; rTa.historyNext = function () { if ( this.currentInHistory < (this.history.length - 1) ) this.currentInHistory++; var cI = this.currentInHistory; var sR = this.cursorHistory[cI]; this.value = this.history[cI]; this.scrollTop = this.scrollHistory[cI]; this.setSelectionRange(sR, sR); return true; }; rTa.historyBack = function () { if ( this.currentInHistory > 0 ) this.currentInHistory--; var cI = this.currentInHistory; var sR = this.cursorHistory[cI]; this.value = this.history[cI]; this.scrollTop = this.scrollHistory[cI]; this.setSelectionRange(sR, sR); return true; }; /* insertion dans le champ */ rTa.insert = function (str, pos) { var start = pos?pos:this.selectionStart; var end = pos?pos:this.selectionEnd; var scrollPos = this.scrollTop; var lg = str.length; this.value = this.value.substring(0, end) + str + this.value.substring(end); this.setSelectionRange(start + lg, end + lg); this.addToHistory(); this.scrollTop = scrollPos; this.focus(); return true; }; rTa.replace = function (str, near, next) { var start = near || this.selectionStart; var end = next || this.selectionEnd; var scrollPos = this.scrollTop; this.value = this.value.substring(0, start) + str + this.value.substring(end); this.setSelectionRange(start, start + str.length); this.addToHistory(); this.scrollTop = scrollPos; } /**** BEGIN WOP ****/ /* rTa.inserto = function (str, pos) { var start = pos || this.selectionStart; var trueStart = this.selectionStart; var end = this.selectionEnd; var scrollPos = this.scrollTop; this.value = this.value.substring(0, start) + str + this.value.substring(start); this.setSelectionRange(trueStart, end); this.addToHistory(); this.scrollTop = scrollPos; return true; } */ /**** END WOP ****/ /* Execute la fonction liée à un raccourcis clavier */ rTa.checkKeysAction = function (e) { var ctrl = 0; var alt = 0; var shift = 0; var keyCode = 0; var kA = this.keysAction; if (e.ctrlKey) var ctrl = 1; if (e.altKey) var alt = 1; if (e.shiftKey) var shift = 1; if (e.keyCode) var keyCode = e.keyCode; if ( !kA || !kA[ctrl] || !kA[ctrl][alt] || !kA[ctrl][alt][shift] || !kA[ctrl][alt][shift][keyCode] ) return false; e.preventDefault(); return kA[ctrl][alt][shift][keyCode](e); }; /* Ajoute un raccourcis clavier */ rTa.addShortKey = function (ctrl, alt, shift, key, action) { rTa.keysAction[ctrl][alt][shift][key] = action; //window.keysAction[ctrl][alt][shift][key] = 1; // Bloque le raccourcis de browser au passage ;) }; /******************************/ /* affectation des evenements */ /******************************/ rTa.onblurev = function () { this.cursorStartPos = this.selectionStart; this.cursorEndPos = this.selectionEnd; }; rTa.onfocusev = function () { this.scrollTop = this.scrollPos; this.setSelectionRange(this.cursorStartPos, this.cursorEndPos); }; rTa.onkeydownev = function (event) { if (this.value != this.valueBefore) { this.addToHistory(); this.valueBefore = this.value; } return !this.checkKeysAction(event); }; rTa.onkeyupev = function (event) { if ( this.value != this.valueBefore && !this.historyNavigate ) this.addToHistory(); if ( this.value != this.valueBefore && this.onvaluechange ) this.onvaluechange(event); this.historyNavigate = false; this.valueBefore = this.value; //span.innerText = this.getPos(); }; rTa.onwheel = function () { this.scrollPos = this.scrollTop; } rTa.addEventListener('blur', rTa.onblurev, false); rTa.addEventListener('focus', rTa.onfocusev, false); rTa.addEventListener('keydown', rTa.onkeydownev, false); rTa.addEventListener('keyup', rTa.onkeyupev, false); rTa.addEventListener('scroll', rTa.onwheel, false); /*******************************************************/ /* definition des fonction pour les raccourcis de base */ /*******************************************************/ rTa.enter = function (e) { //touche entrer var lignes = rTa.value.substring(0, rTa.selectionStart).split("\n"); var ligne = lignes[lignes.length - 1]; var exp = /^[\t *]*/g; var tab = ligne.match(exp); return rTa.insert("\n" + tab); }; rTa.duplicate = function (e) { //touche CTRL + D var st = rTa.selectionStart; var en = rTa.selectionEnd; if (st == en) { var lignes = rTa.value.substring(0, st).split("\n"); var et = rTa.value.substring(st).split("\n"); var endligne = ''; if (et[0]) endligne = et[0]; var ligne = endligne + "\n" + lignes[lignes.length - 1]; } else { var ligne = rTa.value.substring(st, en); } rTa.scrollTop += 20 * ((ligne.match("\n")?ligne.match("\n").length:0.5)); return rTa.insert(ligne); }; rTa.undo = function (e) { //touche CTRL + Z return rTa.historyBack(); }; rTa.redo = function (e) { //touche CTRL + Y return rTa.historyNext(); }; rTa.tab = function (e) { //touche TAB return rTa.insert("\t"); }; /**** BEGIN WOP **** / rTa.tabo = function(e) { if (rTa.selectionStart == rTa.selectionEnd) return rTa.insert("\t"); var count = rTa.value.substring(rTa.selectionStart, rTa.selectionEnd).split("\n"); var ret = true; var pos = 0; var tot = 0; for ( var i = 1; i < count.length - 1; i++) { pos = rTa.selectionStart + tot; alert(pos); tot += count[i].length + 1; ret = ret && rTa.inserto("\t", pos); } return ret; } /**/ rTa.taba = function () { var start = rTa.selectionStart; var end = rTa.selectionEnd; if (start == end) return rTa.insert("\t"); return rTa.replace(rTa.value.substring(start, end).replace(/\n/g, "\n\t")); } /**** END WOP ****/ rTa.startPos = function (e) { // HOME var sS = rTa.selectionStart; var lignes = rTa.value.substring(0, sS).split("\n"); var endligne = rTa.value.substring(sS).split("\n")[0]; var ligne = lignes[lignes.length - 1]; var exp = /^[\t|| ]*/g; var nP = 0; if (ligne.length == 0) { var tmp = endligne.match(exp)?endligne.match(exp)[0].length:0; nP = sS + tmp; } else { nP = sS - ligne.length; } rTa.setSelectionRange(nP, nP); return true; } rTa.goTo = function (e) { // CTRL + / aller à la ligne numreo ... var line = prompt("Aller à la ligne numéro : "); if (!line) return true; var z = rTa.value; var lines = z.split("\n"); var k = 0; for (var i = 0; i < line - 1; i++) { k += lines[i].length + 1; } a = lines[line - 1].length; rTa.scrollTop = rTa.scrollHeight * (line / lines.length) - 100; rTa.setSelectionRange(k, k + a); return true; } rTa.find = function () { // CTRL + M cherche la regex ... rTa.lookForExp = prompt("Rechercher l'expression suivante : ", rTa.lookForExp); var expi = new RegExp(rTa.lookForExp, 'g'); rTa.lookForMatches = rTa.value.match(expi); rTa.lookForPos = 0; rTa.lookForCursorPos = 0; rTa.findNext(); return true; } rTa.findNext = function () { // CTRL + SHIFT + M cherche la regex suivante. if (!rTa.lookForMatches || !rTa.lookForMatches.length) { alert('Pas de correspondances trouvées'); return false; } if (rTa.lookForPos >= rTa.lookForMatches.length) { alert('Fin du document, retour au debut'); rTa.lookForPos = 0; rTa.lookForCursorPos = 0; } var mt = rTa.lookForMatches[rTa.lookForPos]; var st = rTa.value.indexOf(mt, rTa.lookForCursorPos); var x = rTa.value.substring(0, st).split("\n").length; var y = rTa.value.split("\n").length; rTa.scrollTop = rTa.scrollHeight * (x / y) - 100; rTa.setSelectionRange(st, st + mt.length); rTa.lookForCursorPos = st + 1; rTa.focus(); rTa.lookForPos++; return true; } rTa.getPos = function () { var a = rTa.value.substring(0, rTa.selectionStart).match(/\n/g); if (!a) a = 0; else a = a.length; return a; } rTa.alertPos = function () { alert(this.getPos()); } /********************************/ /* ajout des raccourcis de base */ /********************************/ // CTRL ALT SHIFT KeyCode rTa.addShortKey(1, 1, 0, 90, rTa.undo); // CTRL + ALT + Z rTa.addShortKey(1, 1, 0, 89, rTa.redo); // CTRL + ALT + Y rTa.addShortKey(1, 0, 0, 68, rTa.duplicate); // CTRL + D rTa.addShortKey(0, 0, 0, 9, rTa.taba); // TAB rTa.addShortKey(0, 0, 0, 13, rTa.enter); // RETURN rTa.addShortKey(0, 0, 0, 36, rTa.startPos); // HOME /* rTa.addShortKey(1, 0, 0, 191, rTa.goTo); // CTRL + / ou CTRL + : sous windows rTa.addShortKey(1, 0, 0, 59, rTa.goTo); // CTRL + / ou CTRL + : sous ubunutu kde4 */ rTa.addShortKey(1, 0, 0, 77, rTa.find); // CTRL + M rechercher rTa.addShortKey(1, 0, 1, 77, rTa.findNext); // CTRL + SHIFT + M rechercher suivant rTa.addShortKey(1, 1, 0, 80, rTa.alertPos); // ALT + P : indique la ligne return rTa; }