Rev 15 | Rev 17 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed
/*Surligneur de mot (glossaire)0) tout d'abord la liste des mots est récupée (getMotsADefinitions) et stockée dans motsAyantDefinition1) 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étiqueEt tente d'extraire une partie de contexte significative (jusqu'à 24 caractère car initialement letest d'inclusion dans .definition_term était faire plus tardivement.3) remplacerDefinitions() prend la liste des nodes susceptibles de nécessiter un traitementet 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é* necessiteSubstitution() est appellé== necessiteSubstitution() ==:** 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 necessiteSubstitution(),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 nodeContraintes 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 bordures3) vérifier bordure d'accents:\\b(é) dans une regexp ne peut matcher une chaîne JS UTF-8http://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 = '#zone-droite p, #zone-droite span:not(.definition_term), #zone-droite td, #zone-droite pre, #zone-droite div, #zone-droite li';var urlPage = window.location.href;// Note: utiliser \\b plutôt que \\W pour matcher les bordures de mots// en incluant début et fin de lignevar regexp_complete = 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 afficherLienDefinitions() {html = '<div id="conteneur_activation_definition"><a href="#">rechercher les définitions</a></div>';$('#conteneur_activation_definition').live('click', function(event) {event.preventDefault();//supprimerToutesDefinitions();if(motsAyantDefinition == null) {getMotsADefinitions();ajouterListenerDefinitions();} else {$(set).remplacerDefinitions(motsAyantDefinition);}});$('body').append(html);}$.fn.remplacerDefinitions = function(mots) {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 = necessiteSubstitution(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, couple) {var full_contexte = couple[0],prefix_solo = couple[1],mot_contextualise = couple[2];// cf exclureSpanif(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 necessiteSubstitution(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(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 gauchewhile( (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: URL_BASE_SERVICE+'mots/', // provient de dictionnaire.config.jssuccess: function(data) {motsAyantDefinition = data;batirRegexp(motsAyantDefinition);$(set).remplacerDefinitions(motsAyantDefinition);},dataType: "JSON",global: false});}function getMotsADefinitionsEtRemplacer() {if(motsAyantDefinition == null) {getMotsADefinitions();} else {if(regexp_complete == null || regexp_thin == null) {batirRegexp(motsAyantDefinition);}$(set).remplacerDefinitions(motsAyantDefinition);}}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 DBrestr += mot.slice(0, -2) + "(?:x|se|ses)";}elserestr += mot + "\\w{0,2}";});regexp_complete = new RegExp("(?:\\s|^|\\W)(" + restr + ")\\b", "ig"); // accentsregexp_thin = new RegExp(exclureSpan + "(" + restr + ")\\b", "ig");}function formaterTemplateMotADefinition(motOriginal, motSimplifie) {definitionHtml = '<span rel="'+motSimplifie+'" class="definition_term">'+motOriginal+'</span>';return definitionHtml;}function ajouterListenerDefinitions() {$('.definition_term').live('mouseover mouseout', function(event) {if (event.type == 'mouseover') {event.preventDefault();afficherDefinition($(this));} else {cacherPopupsDefinitions();}});}function afficherDefinition(element) {mot = element.attr('rel');if(dictionnaire[mot] != null) {element.after(formaterDefinition(element));afficherPopupDefinition();} else {chargerDefinitionDistante(element);}}function chargerDefinitionDistante(element) {date = new Date();mot = element.attr('rel');$.ajax({url: URL_BASE_SERVICE+'def/'+mot, // provient de dictionnaire.config.jssuccess: function(data) {retour = data;definition = retour.valeur;dictionnaire[mot] = definition;element.after(formaterDefinition(element));afficherPopupDefinition();},dataType: "JSON",global: false,async: false});}function afficherPopupDefinition() {$(".definition_container").css({'top':mouseY + 20,'left':mouseX - 10}).fadeIn('slow');}function cacherPopupsDefinitions() {$(".definition_container").remove();}function formaterDefinition(element) {mot = element.attr('rel');data = dictionnaire[mot];defHtml = '<div class="definition_container">'+'<span class="definition_container_fleche"></span>'+'<span class="definition">'+data+'</span>'+'</div>';return defHtml;}function supprimerToutesDefinitions() {$('.definition_term').each(function() {$(this).replaceWith($(this).html());});cacherPopupsDefinitions();}$(document).bind('mousemove', function(e){mouseX = e.pageX;mouseY = e.pageY - $(window).scrollTop();});$(document).ajaxStop(function() {urlPage = $(this)[0].URL;getMotsADefinitionsEtRemplacer();});$(document).ready(function() {$.ajax({url: URL_BASE_SERVICE + "../../../scripts/helpers.js",dataType: "script",global: false});getMotsADefinitionsEtRemplacer();ajouterListenerDefinitions();});