| 1,31 → 1,102 |
| /* |
| Surligneur de mot (glossaire) |
| |
| 0) tout d'abord la liste des mots est récupée (getMotsADefinitions) et stockée dans motsAyantDefinition |
| |
| 1) chaque mot de la liste subie une transformation progressive en pattern: |
| * les mots de moins de 3 caractères sont inchangés (exemple: "nu") |
| * les mots finissant en "eux/euse" sont généricisés |
| * les autres mots se voit ajoutée la possibilité de matcher sur \\w{0,2} |
| |
| 2) puis plusieurs RegExp sont baties à partir de la liste de pattern préliminaires |
| * regexp_complete permet d'assurer que le mot: |
| ** commence en début de ligne |
| ** suit un espace |
| ** ne suit pas un caractère |
| [ mais ne s'assure pas que le mot ne suit PAS un caractère accentué, cf notes à propos de \\b et l'UTF-8 ] |
| |
| * regexp_thin permet de s'assurer que le mot: |
| ** ne se trouve pas déjà encapsulé dans un <span rel="" class="definition_term">X</span> |
| ** ne se trouve pas comme attribut "rel" d'un <span rel="X" class="definition_term"></span> |
| ** n'est pas directement précédé d'un accent (parmis ceux utilisés dans la BDD, cf exclureSpan) |
| ** n'est pas directement précédé d'un caractère alphabétique |
| Et tente d'extraire une partie de contexte significative (jusqu'à 24 caractère car initialement le |
| test d'inclusion dans .definition_term était faire plus tardivement. |
| |
| 3) remplacerDefinitions() prend la liste des nodes susceptibles de nécessiter un traitement |
| et ignore ceux ayant déjà été traités [max_passages] fois (4 par défaut) |
| |
| 4) pour chaque node: |
| * le compteur de passage est incrémenté |
| * nesseciteSubstitution() est appellé |
| |
| == nesseciteSubstitution() ==: |
| ** Utilise regexp_thin pour extraire les mots restant à définir ainsi qu'une partie de leur contexte. |
| ** Utilise regexp_complete pour extraire les mots au plus proche de leur bodures avec un moindre risque d'erreur |
| ** exlue les faux positifs possibles de regexp_thin |
| ** renvoi les matches de regexp_thin (qui présente plus de contexte) |
| ============================= |
| |
| * pour chaque correspondance retournée par nesseciteSubstitution(), |
| le mot d'origine (tel que dans motsAyantDefinition) |
| est déterminé en utilisant le levenstein (un cache est mis en place, cf texte_to_mot() dans helpers.js). |
| |
| * rechercherEtRemplacerMotParDefinition() est appelée pour effectuer la substitution dans le node |
| |
| |
| Contraintes rencontrées: |
| 1) exclure les mots déjà défini via la regexp général plutôt qu'au coup par coup. |
| 2) vérifier les bordures |
| 3) vérifier bordure d'accents: |
| \\b(é) dans une regexp ne peut matcher une chaîne JS UTF-8 |
| http://stackoverflow.com/questions/2881445/utf-8-word-boundary-regex-in-javascript |
| */ |
| |
| var dictionnaire = new Array(); |
| var motsAyantDefinition = null; |
| var mouseX = null; |
| var mouseY = null; |
| var active = false; |
| var set = 'p, span, td, pre, div'; |
| var set = 'p, span:not(.definition_term), td, pre, div, li'; |
| |
| function getUrlBaseService() { |
| // provient de dictionnaire.config.js |
| return URL_BASE_SERVICE; |
| } |
| // Note: utiliser \\b plutôt que \\W pour matcher les bordures de mots |
| // en incluant début et fin de ligne |
| var regexp_complete = null; |
| |
| var regexp_context = null; |
| var regexp_thin = null; |
| |
| // nombre maximum de passages de la détection sur un node donné |
| var max_passages = 4; |
| |
| // echo $(mysql<<<"SELECT cle FROM definitions"|tr "[a-z,-]" o|sed -e 's/o//g' -e "s/\(.\)/\1\n/g"|sort -u) |
| // ç é è ê î ï ô (2013/07/03) |
| // TODO: http://xregexp.com/plugins/ |
| var exclureSpan = '([^' + |
| '(?:class="definition_term">)' + // mot contextualisé déjà dictionnarisé |
| '(?:rel=")' + // la valeur du rel="" d'un mot déjà dictionnarisé |
| 'çéèêîïô' + // les accents, non-traités dans la regexp générale et qui ne doivent pas |
| // être pris pour des bordures de mots |
| '\\w' + |
| ']|^){1,24}'; |
| |
| |
| function supprimerAccents(str) { |
| var rExps=[ |
| {re:/[\xC0-\xC6]/g, ch:'A'}, |
| {re:/[\xE0-\xE6]/g, ch:'a'}, |
| {re:/[\xC8-\xCB]/g, ch:'E'}, |
| {re:/[\xE8-\xEB]/g, ch:'e'}, |
| {re:/[\xCC-\xCF]/g, ch:'I'}, |
| {re:/[\xEC-\xEF]/g, ch:'i'}, |
| {re:/[\xD2-\xD6]/g, ch:'O'}, |
| {re:/[\xF2-\xF6]/g, ch:'o'}, |
| {re:/[\xD9-\xDC]/g, ch:'U'}, |
| {re:/[\xF9-\xFC]/g, ch:'u'}, |
| {re:/[\xD1]/g, ch:'N'}, |
| {re:/[\xF1]/g, ch:'n'} ]; |
| {re:/[\xC0-\xC6]/g, ch:'A'}, |
| {re:/[\xE0-\xE6]/g, ch:'a'}, |
| {re:/[\xC8-\xCB]/g, ch:'E'}, |
| {re:/[\xE8-\xEB]/g, ch:'e'}, |
| {re:/[\xCC-\xCF]/g, ch:'I'}, |
| {re:/[\xEC-\xEF]/g, ch:'i'}, |
| {re:/[\xD2-\xD6]/g, ch:'O'}, |
| {re:/[\xF2-\xF6]/g, ch:'o'}, |
| {re:/[\xD9-\xDC]/g, ch:'U'}, |
| {re:/[\xF9-\xFC]/g, ch:'u'}, |
| {re:/[\xD1]/g, ch:'N'}, |
| {re:/[\xF1]/g, ch:'n'} ]; |
| for(var i=0, len=rExps.length; i<len; i++) |
| str=str.replace(rExps[i].re, rExps[i].ch); |
| str=str.replace(rExps[i].re, rExps[i].ch); |
| return str; |
| }; |
| |
| 33,16 → 104,16 |
| // javascript ne me permet pas de faire mieux |
| function etendreChaineAccents(str) { |
| return str.replace('a',"(a|à|á|â|ã|ä|å)") |
| .replace('e',"(e|è|é|ê|ë)") |
| .replace('i',"(i|ì|í|î|ï)") |
| .replace('o',"(o|ò|ó|ô|õ|ö)") |
| .replace('u',"(u|ù|ú|û|ü)") |
| .replace('y',"(ýÿ)") |
| .replace('a',"(a|à|á|â|ã|ä|å)") |
| .replace('æ',"(ae|æ)") |
| .replace('ç',"(ç|c)") |
| .replace('ñ',"(ñ|n)") |
| .replace('œ',"(œ|oe)"); |
| .replace('e',"(e|è|é|ê|ë)") |
| .replace('i',"(i|ì|í|î|ï)") |
| .replace('o',"(o|ò|ó|ô|õ|ö)") |
| .replace('u',"(u|ù|ú|û|ü)") |
| .replace('y',"(ýÿ)") |
| .replace('a',"(a|à|á|â|ã|ä|å)") |
| .replace('æ',"(ae|æ)") |
| .replace('ç',"(ç|c)") |
| .replace('ñ',"(ñ|n)") |
| .replace('œ',"(œ|oe)"); |
| } |
| |
| function afficherLienDefinitions() { |
| 49,9 → 120,10 |
| html = '<div id="conteneur_activation_definition"><a href="#">rechercher les définitions</a></div>'; |
| $('#conteneur_activation_definition').live('click', function(event) { |
| event.preventDefault(); |
| supprimerToutesDefinitions(); |
| //supprimerToutesDefinitions(); |
| if(motsAyantDefinition == null) { |
| getMotsADefinitions(); |
| ajouterListenerDefinitions(); |
| } else { |
| $(set).remplacerDefinitions(motsAyantDefinition); |
| } |
| 66,66 → 138,123 |
| } |
| |
| $.fn.remplacerDefinitions = function(mots) { |
| this.each(function() { |
| $(this).contents().filter(function() { |
| return this.nodeType == 3; |
| }).each(function() { |
| element = $(this); |
| texte = element.text(); |
| if(texte != "") { |
| $.each(mots, function(index, valeur) { |
| texte = rechercherEtRemplacerMotParDefinition(texte, valeur); |
| }); |
| element.replaceWith(texte); |
| } |
| }); |
| }); |
| return this; |
| this.each(function() { |
| $(this).contents().filter(function() { |
| return (this.nodeType == 3 && ! (($(this).data("count") || 0) > max_passages)); |
| }).each(function() { |
| $(this).data("count", ($(this).data("count") || 0) + 1); |
| ttexte = texte = $(this).text(); |
| matches_list = nesseciteSubstitution(texte)[0]; |
| if(!matches_list) return true; // TODO: data("count") = max_passages ? |
| |
| for(i in matches_list) { |
| couple = matches_list[i]; |
| mot_contextualise = couple[2]; |
| cle = texte_to_mot(mot_contextualise); |
| |
| if(! (ttexte = rechercherEtRemplacerMotParDefinition(texte, cle, couple))) break; |
| texte = ttexte; |
| } |
| $(this).replaceWith(texte); |
| }); |
| }); |
| return this; |
| } |
| |
| function rechercherEtRemplacerMotParDefinition(texte, mot) { |
| exclureSpan = '[^(?:class="definition_term">)]'; |
| regExp = new RegExp(exclureSpan+"[ |,|-|;|.]+("+mot+")[a-zA-Z]{1}", 'ig'); |
| termeDansTexte = regExp.exec(texte); |
| if(termeDansTexte != null && termeDansTexte.length > 1) { |
| motOriginal = termeDansTexte[1]; |
| templateMotADefinition = formaterTemplateMotADefinition(motOriginal); |
| texte = texte.replace(motOriginal, templateMotADefinition); |
| } |
| function rechercherEtRemplacerMotParDefinition(texte, mot, couple) { |
| var full_contexte = couple[0], |
| prefix_solo = couple[1], |
| mot_contextualise = couple[2]; |
| |
| return texte; |
| // cf exclureSpan |
| if(new RegExp('((?:class="definition_term">)|(?:rel=")|(?:[çéèêîïô]))(' + mot + "\\w{0,2}" + ')' + "\\b", "ig").test(full_contexte)) return; |
| |
| templateMotADefinition = formaterTemplateMotADefinition(mot_contextualise, mot); |
| bloc_replace = full_contexte.replace(mot_contextualise, templateMotADefinition); |
| return texte.replace(full_contexte, bloc_replace); |
| } |
| |
| |
| function nesseciteSubstitution(texte) { |
| var liste = [], liste_complete = []; |
| |
| // regexp d'extraction du contexte, sans limite aux bords de "mot", |
| // peu amener des faux positifs, et notamment ne pas matcher au mieux. |
| // Eg: subsessiles match "sessile" et non "subsessile". |
| while( (matches_c = regexp_thin.exec(texte)) ) { |
| //liste.push(getUnique(clean(matches_c))); |
| liste.push(matches_c); |
| } |
| |
| if(liste.length == 0) return [null]; |
| |
| // regexp de validation des bordure de mots, ne conserve que des matches correct |
| // vis-à-vis de la bordure gauche |
| while( (matches_c = regexp_complete.exec(texte)) ) { |
| liste_complete.push(matches_c[1]); |
| } |
| |
| // si une match n'est pas dans le tableau des mots autorisés (indexOf) |
| for(var i = 0; i < liste.length; i++) { |
| if($.inArray(liste[i][2], liste_complete) == -1) liste.splice(i, 1); |
| } |
| |
| return [liste, liste_complete] |
| } |
| |
| |
| function getMotsADefinitions() { |
| $.ajax({ |
| url: getUrlBaseService()+'mots/', |
| url: URL_BASE_SERVICE+'mots/', // provient de dictionnaire.config.js |
| success: function(data) { |
| motsAyantDefinition = data; |
| batirRegexp(motsAyantDefinition); |
| $(set).remplacerDefinitions(motsAyantDefinition); |
| |
| }, |
| dataType: "JSON", |
| global: false |
| }); |
| |
| ajouterListenerDefinitions(); |
| } |
| |
| function formaterTemplateMotADefinition(motOriginal) { |
| motSimplifie = supprimerAccents(motOriginal); |
| function batirRegexp(mots) { |
| var restr = ''; |
| $.each(mots, function(index, mot) { |
| if(restr != '') restr += '|'; |
| |
| if(mot.length < 3) { |
| restr += mot; |
| } |
| // gestion masculin/féminin en "eux/euse" |
| else if(mot.substr(-1) == 'x') { |
| restr += mot.slice(0, -1) + "(?:x|se|ses)"; |
| } |
| else if(mot.substr(-4) == 'euse') { // TODO: fix DB |
| restr += mot.slice(0, -2) + "(?:x|se|ses)"; |
| } |
| else |
| restr += mot + "\\w{0,2}"; |
| }); |
| |
| regexp_complete = new RegExp("(?:\\s|^|\\W)(" + restr + ")\\b", "ig"); // accents |
| regexp_thin = new RegExp(exclureSpan + "(" + restr + ")\\b", "ig"); |
| } |
| |
| function formaterTemplateMotADefinition(motOriginal, motSimplifie) { |
| definitionHtml = '<span rel="'+motSimplifie+'" class="definition_term">' |
| +motOriginal+ |
| '</span>'; |
| +motOriginal+ |
| '</span>'; |
| return definitionHtml; |
| } |
| |
| function ajouterListenerDefinitions() { |
| $('.definition_term').live('mouseover mouseout', function(event) { |
| if (event.type == 'mouseover') { |
| event.preventDefault(); |
| afficherDefinition($(this)); |
| } else { |
| cacherPopupsDefinitions(); |
| } |
| if (event.type == 'mouseover') { |
| event.preventDefault(); |
| afficherDefinition($(this)); |
| } else { |
| cacherPopupsDefinitions(); |
| } |
| }); |
| } |
| |
| 143,7 → 272,7 |
| date = new Date(); |
| mot = element.attr('rel'); |
| $.ajax({ |
| url: getUrlBaseService()+'def/'+mot, |
| url: URL_BASE_SERVICE+'def/'+mot, // provient de dictionnaire.config.js |
| success: function(data) { |
| retour = data; |
| definition = retour.valeur; |
| 168,9 → 297,9 |
| mot = element.attr('rel'); |
| data = dictionnaire[mot]; |
| defHtml = '<div class="definition_container">'+ |
| '<span class="definition_container_fleche"></span>'+ |
| '<span class="definition">'+data+'</span>'+ |
| '</div>'; |
| '<span class="definition_container_fleche"></span>'+ |
| '<span class="definition">'+data+'</span>'+ |
| '</div>'; |
| return defHtml; |
| } |
| |
| 187,7 → 316,8 |
| }); |
| |
| $(document).ready(function() { |
| $.getScript(URL_BASE_SERVICE + "../../../scripts/helpers.js"); |
| getMotsADefinitions(); |
| ajouterListenerDefinitions(); |
| afficherLienDefinitions(); |
| }); |
| |