Utilisateur:Orlodrim/ancresbrisees.js

Note : après avoir enregistré la page, vous devrez forcer le rechargement complet du cache de votre navigateur pour voir les changements.

Mozilla / Firefox / Konqueror / Safari : maintenez la touche Majuscule (Shift) en cliquant sur le bouton Actualiser (Reload) ou pressez Maj-Ctrl-R (Cmd-R sur Apple Mac) ;

Chrome / Internet Explorer / Opera : maintenez la touche Ctrl en cliquant sur le bouton Actualiser ou pressez Ctrl-F5.
// Script pour faciliter la restauration des ancres brisées
// Partiellement basé sur http://fr.wikipedia.org/wiki/Utilisateur:Phe/Clickodrome.js

var banDefSummary = "Restauration des [[Projet:Restauration des ancres brisées|ancres brisées]]";
var banURLParam = "&rab=";
var banLastPos = new Array();

var wgAction_ = mw.config.get('wgAction');
var wgServer_ = mw.config.get('wgServer');
var wgScript_ = mw.config.get('wgScript');
var wgScriptPath_ = mw.config.get('wgScriptPath');
var wgTitle_ = mw.config.get('wgTitle');
var wgArticlePath_ = mw.config.get('wgArticlePath');
var wgPageName_ = mw.config.get('wgPageName');
var wgCanonicalNamespace_ = mw.config.get('wgCanonicalNamespace');

String.prototype.htmlize = function() {
  var chars = new Array('&','<','>','"');
  var entities = new Array('amp','lt','gt','quot');
  var string = this;
  for (var i=0; i<chars.length; i++) {
    var regex = new RegExp(chars[i], "g");
    string = string.replace(regex, '&' + entities[i] + ';');
  }
  return string;
}

function banIquo(x, y) {
  var xModY = ((x >= 0) ? x : y - (-x) % y) % y;
  return (x - xModY) / y;
}

function banGetPageURL(page) {
  return wgServer_ + wgArticlePath_.split('$1').join(encodeURI(page));
}

function banEscapeStr(str) {
  return "'" + str.replace(/\\/g, '\\\\').replace(/'/g, '\\\'').htmlize() + "'";
}

function banNormalizeLink(s) {
  var i = s.indexOf("#");
  if (i == -1) i = s.length;
  var article = s.substr(0, i).replace(/^ +/, "").replace(/ +$/, "").replace(/ /g, "_");
  if (article == "")
    article = wgPageName_;
  else if (article[0] == ":")
    article = article.substr(1);
  article = article.substr(0, 1).toUpperCase() + article.substr(1); // Ne marche que dans l'espace principal
  var anchor = s.substr(i + 1).replace(/ +$/, "").replace(/ /g, "_");
  anchor = encodeURI(anchor).replace(/%/g, ".");
  while (true) {
    var match = /[;,/?@&=+$!~*\'()]/.exec(anchor);
    if (!match) break;
    var i = match.index;
    var cEnc = anchor.charCodeAt(i).toString(16).toUpperCase();
    anchor = anchor.substr(0, i) + "." + cEnc + anchor.substr(i + 1);
  }
  return article + "#" + anchor;
}

function banExternalLink(link) {
  var s = (link[0] == ":") ? link.substr(1) : link;
  var i = s.indexOf(":");
  if (i == 0) return false;
  s = s.substr(0, i).toLowerCase();
  return s.length == 1 || (s.length == 2 && s != "wp") || s == "wikt";
}

var banAjax = {
  http: function(bundle) {
    var xmlhttp = new XMLHttpRequest();
    if (!xmlhttp) return false;
    xmlhttp.onreadystatechange = function() {
      if (xmlhttp.readyState == 4)
        banAjax.httpComplete(xmlhttp, bundle);
    };
    xmlhttp.open(bundle.method ? bundle.method : "GET", bundle.url, true);
    if (bundle.headers) {
      for (var field in bundle.headers)
        xmlhttp.setRequestHeader(field, bundle.headers[field]);
    }
    xmlhttp.send(null);
  },
  httpComplete: function(xmlhttp, bundle) {
    if (xmlhttp.status == 200 || xmlhttp.status == 302)
      bundle.onSuccess(xmlhttp, bundle);
    else if (bundle.onFailure)
      bundle.onFailure(xmlhttp, bundle);
  }
};

// Cases à cocher et liens sur les pages du projet
// ***********************************************

function banPageInProject() {
  var prefix = "Restauration des ancres brisées/";
  if (wgCanonicalNamespace_ != "Projet") return false;
  if (wgTitle_.substr(0, prefix.length) != prefix) return false;
  var subpage = wgTitle_.substr(prefix.length);
  return (subpage.length == 1 || subpage == "0-9" || subpage == "Autres"
          || subpage == "Multiple");
}

function banGetLineArticle(line) {
  return line.getElementsByTagName('a')[0].innerHTML;
}

/* return true if a part of the element is striked */
function banIsItemStriked(e) {
  return e.getElementsByTagName('s').length != 0;
}

function banFormatProjectPage() {
  var content = document.getElementById("bodyContent");

  var submit = document.createElement("button");
  submit.type = "submit";
  submit.innerHTML = "Valider";
  //submit.onclick = dist_edit_submit_change_step1;
  submit.onclick = banSubmit;
  content.appendChild(submit);

  var li = content.getElementsByTagName("li");
  var anchors = "";
  for (var j = 0; j < li.length; j++) {
    var article = banGetLineArticle(li[j]);
    if (j == 0 || banGetLineArticle(li[j - 1]) != article) {
      anchors = "";
      for (var k = j; k < li.length && banGetLineArticle(li[k]) == article; k++) {
        if (k > j) anchors += "|";
        anchors += li[k].getElementsByTagName('a')[1].innerHTML;
      }
    }
    if (wgTitle_ != "Restauration des ancres brisées/Multiple") {
      var lineLinks = li[j].getElementsByTagName('a');
      var l1 = lineLinks[0];
      var l2 = lineLinks[1];
      var l3 = lineLinks[2];
      l1.href = wgServer_ + wgScript_ + '?title=' + encodeURIComponent(article)
          + '&action=edit&rab=' + encodeURIComponent(anchors)
          + '#editform';
      l1.target = 'banwindow1';
      l2.target = 'banwindow2';
    }
    var input1 = document.createElement('input');
    input1.type = 'checkbox';
    input1.checked = banIsItemStriked(li[j]);
    var input2 = document.createElement('input');
    input2.type = 'checkbox';
    input2.checked = false;
    li[j].insertBefore(input2, li[j].firstChild);
    li[j].insertBefore(input1, li[j].firstChild);
  }
}

function dist_edit_change_text(text) {
  var content = document.getElementById('bodyContent');
  var input = content.getElementsByTagName("input");
  var li =  content.getElementsByTagName("li");
  if (li.length * 2 != input.length) {
      alert('bad li/input count ' + li.length + ' ' + input.length)
      return text;
  }
  liensRestants = 0;
  new_text = '';
  lines = text.split('\n');
  var k = 0;
  for (var j = 0; j < lines.length; ++j) {
        if (lines[j].indexOf('*') == 0) {
              if (k >= li.length) {
                  alert('something feel bad, k >= input.length');
                  return text;
              }
              if (input[k*2].disabled || input[k*2+1].checked) {
              } else if (input[k*2].checked && lines[j].indexOf('<s>') == -1) {
                  new_text += '*<s>' + lines[j].slice(1) + '</s>\n';
              } else {
                  new_text += lines[j] + '\n';
                  liensRestants++;
              }
              k++;
        } else  {
              new_text += lines[j] + '\n';
        }
  }

  if (k * 2 != input.length) {
        alert('k != input.length' + k + ' ' + input.length);
        return text;
  }

  return new_text;
}

function dist_edit_submit_change_step2(doc, newform, form) {
  var l = form.getElementsByTagName('textarea')[0];
  var t = document.createElement('textarea');
  t.style.display = "none";
  t.name = l.name;
  t.value = dist_edit_change_text(l.value);
  newform.appendChild(t);

  l = form.getElementsByTagName('input');
  for (i = l.length; i--; ) {
    if (l[i].name == 'wpSummary') {
      l[i].value = "Mise à jour : " + liensRestants + " liens restants";
      l[i].style.display = "none";
    } else if (l[i].name == 'wpSave') {
    } else if (l[i].name == 'wpPreview') {
    } else if (l[i].name == 'wpDiff') {
    } else {
      l[i].style.display = "none";
    }
    newform.appendChild(l[i]);
  }
}


function banSubmit() {
  var xml_http_client = new XMLHttpRequest();
  this.disabled = true;

  url_name = wgServer_ + wgScript_ + "?title=" + wgPageName_ + "&action=edit";
  banAjax.http({url: url_name, onSuccess: banSubmit2});
}

function banSubmit2(xmlreq, data) {
  var parser = new DOMParser();
  var doc = parser.parseFromString(xmlreq.responseText, 'application/xhtml+xml');

  newform = document.createElement('form');
  form = doc.getElementById('editform');

  dist_edit_submit_change_step2(doc, newform, form);

  newform.name = form.name;
  newform.method = form.method;
  newform.id = form.id;
  newform.action = form.action;
  newform.style.display = "none";
  document.getElementById('bodyContent').appendChild(newform);
  newform.submit();
  //window.location = banGetPageURL("Projet:Restauration des ancres brisées");
}

// Recherche des ancres sur les pages d'édition
// ********************************************

var banBSIndex = -1;
var banBSMsg, banBSRevisions, banBSFirst, banBSLast, banBSCurrent;
var banBSText, banBSLinkN, banBSContinue, banBSTimestamp;

/* Rend inactif un lien javascript, de façon visible. */
function banDisableLink(link) {
  link.href = "javascript:;";
  link.style.color = "silver";
  link.style.cursor = "default";
  link.style.textDecoration = "none";
}

/* Recherche la première occurence d'une ancre à partir d'une position donnée. */
function banFindNext(s, link, start) {
  var i = start, j, k, pageLink;
  var linkN = banNormalizeLink(link);
  while (true) {
    i = s.indexOf("[[", i);
    if (i == -1) return false;
    i += 2;
    j = s.indexOf("]]", i);
    if (j == -1) return false;
    pageLink = s.substr(i, j - i);
    k = pageLink.indexOf("|");
    if (k != -1)
      pageLink = pageLink.substr(0, k);
    else
      k = pageLink.length;
    if (pageLink.indexOf("#") != -1 && linkN == banNormalizeLink(pageLink))
      return [i, i + k];
    i = j + 2;
  }
}

// Recherche dichotomique de la date d'ajout d'un lien
function banGetDate(index, link) {
  banBSMsg = document.getElementById("banMsgBS" + index);
  var s = document.getElementById("editform").getElementsByTagName("textarea")[0].value;
  var pos = banFindNext(s, link, 0);
  if (!pos) {
    banBSMsg.innerHTML = "[non trouvé dans la version actuelle]"
    return;
  }
  if (banBSIndex != -1) return;
  banBSIndex = index;
  banDisableLink(document.getElementById("banDate" + index));
  banBSText = s.substr(pos[0] - 2, pos[1] - pos[0] + 3);
  banBSLinkN = banNormalizeLink(link);
  banBSMsg.innerHTML = "[initialisation recherche]";
  var request = wgServer_ + wgScriptPath_ + '/api.php?format=xml'
          + '&action=query&rawcontinue=&prop=revisions&rvlimit=500'
          + '&rvprop=ids|timestamp&titles=' + encodeURIComponent(wgPageName_);
  banAjax.http({url: request, onSuccess: banGetDate2});
}

function banGetDate2(request, data) {
  var lst = request.responseXML.getElementsByTagName("revisions");
  if (!lst) {
    banBSMsg.innerHTML = "[erreur]";
    banBSIndex = -1;
    return;
  }
  banBSRevisions = lst[0].childNodes;
  banBSFirst = -1;
  banBSLast = banBSRevisions.length;
  banBSContinue = request.responseXML.getElementsByTagName("query-continue").length > 0;
  banGetDateBS();
}

function banGetDateBS() {
  banBSCurrent = banIquo(banBSFirst + banBSLast, 2);
  if (banBSCurrent == banBSFirst) {
    if (banBSFirst == -1) {
      banBSMsg.innerHTML = "[erreur : lien non trouvé]";
      banBSIndex = -1;
    }
    else if (banBSLast == banBSRevisions.length) {
      if (banBSContinue) {
        banBSMsg.innerHTML = "[erreur : ajouté avant les " + banBSLast + " dernières révisions]";
        banBSIndex = -1;
      }
      else {
        banBSTimestamp = banBSRevisions[banBSCurrent].getAttribute("timestamp");
        var lnk = wgServer_ + wgScript_ + "?oldid=" + banBSRevisions[banBSCurrent].getAttribute("revid");
        banBSMsg.innerHTML = "[ajouté à la création le <a href=\"" + lnk
                + "\" target=\"_blank\">" + banBSTimestamp + "</a>]";
      }
    }
    else {
      banBSTimestamp = banBSRevisions[banBSCurrent].getAttribute("timestamp");
      var lnk = wgServer_ + wgScript_ + "?oldid="
              + banBSRevisions[banBSCurrent + 1].getAttribute("revid") + "&diff="
              + banBSRevisions[banBSCurrent].getAttribute("revid");
      banBSMsg.innerHTML = "[ajouté le <a href=\"" + lnk + "\" target=\"_blank\">"
              + banBSTimestamp + "</a>]";
    }
    if (banBSIndex != -1) {
      // Recherche la version de la cible au moment de l'ajout du lien
      var targetTitle = banBSLinkN.substr(0, banBSLinkN.indexOf("#"));
      var request = wgServer_ + wgScriptPath_ + '/api.php?format=xml'
          + '&action=query&rawcontinue=&prop=revisions&rvlimit=500'
          + '&rvprop=ids|timestamp&titles=' + encodeURIComponent(targetTitle);
      banAjax.http({url: request, onSuccess: banGetDateTarget});
    }
  }
  else {
    banBSMsg.innerHTML = "[dichotomie sur " + (banBSLast - banBSFirst - 1) + " révisions]";
    var request = wgServer_ + wgScript_ + "?action=raw&oldid="
            + banBSRevisions[banBSCurrent].getAttribute("revid");
    banAjax.http({url: request, onSuccess: banGetDateBS2});
  }
}

function banGetDateBS2(xmlreq, data) {
  var linkFound = xmlreq.responseText.indexOf(banBSText) != -1;
  if (linkFound)
    banBSFirst = banBSCurrent;
  else
    banBSLast = banBSCurrent;
  banGetDateBS();
}

function banGetDateTarget(xmlreq, data) {
  msg = banBSMsg.innerHTML;
  msg = msg.substr(0, msg.length - 1);

  var lst = xmlreq.responseXML.getElementsByTagName("revisions");
  if (lst.length == 0)
    msg += ", pas de page cible";
  else {
    var targetRev = lst[0].childNodes;
    var i = 0;
    for (; i < targetRev.length; i++) {
      if (targetRev[i].getAttribute("timestamp") < banBSTimestamp) {
        var lnk = wgServer_ + wgScript_ + "?oldid=" + targetRev[i].getAttribute("revid") + banBSLinkN.substr(banBSLinkN.indexOf("#"));
        msg += ", <a href=\"" + lnk + "\" target=\"_blank\">cible à cette date</a>";
        break;
      }
    }
    if (i == targetRev.length) {
      msg += ", page cible créée après";
    }
  }
  banBSMsg.innerHTML = msg + "]";
  banBSIndex = -1;
}

// Sélection des ancres dans le code wiki

function banSetSelection(start, end) {
  var txt = document.getElementById('editform').getElementsByTagName('textarea')[0];
  txt.focus();
  txt.setSelectionRange(start, start);
  var evt = document.createEvent('KeyEvents');
  evt.initKeyEvent('keypress', true, true, window, false, false, false, false, 0, 32);
  txt.dispatchEvent(evt);
  evt = document.createEvent('KeyEvents');
  evt.initKeyEvent('keypress', true, true, window, false, false, false, false, 8, 0);
  txt.dispatchEvent(evt);
  txt.setSelectionRange(start, end);
}

/* Sélectionne l'occurence suivante d'une ancre brisée donnée. */
function banSelectAnchor(index, link) {
  var s = document.getElementById("editform").getElementsByTagName("textarea")[0].value;
  var pos = banFindNext(s, link, banLastPos[index]);
  var msg = document.getElementById("banMsg" + index);
  if (!pos) var pos = banFindNext(s, link, 0);
  if (!pos) {
    msg.innerHTML = "(non trouvé)";
    return;
  }
  banLastPos[index] = pos[1];
  msg.innerHTML = banFindNext(s, link, pos[1]) ? "" : "[dernière occurence]";
  banSetSelection(pos[0], pos[1]);
}

function banJSLink(index, link) {
  return link.htmlize() + " (<a href=\"javascript:banSelectAnchor(" + index + ","
          + encodeURI(banEscapeStr(link)) + ");\">chercher</a> | "
          + "<a href=\"" + banGetPageURL(banNormalizeLink(link)) + "\" target=\"banwindow2\">voir cible</a> | "
          + "<a id=\"banDate" + index + "\" href=\"javascript:banGetDate(" + index + ","
          + encodeURI(banEscapeStr(link)) + ")\">date d'ajout</a>) "
          + "<span id=\"banMsg" + index + "\"></span> "
          + "<span id=\"banMsgBS" + index + "\"></span>";
}

/* Crée des liens sous la fenêtre d'édition pour chercher les différentes
   occurences des ancres brisées de l'article. */
function banFormatEditPage(anchors, initSummary, selectFirst) {
  var banList = document.getElementById("banList");
  if (banList == null) {
    var banList = document.createElement("span");
    banList.id = "banList";
    var p = document.getElementById("MediaWiki-summary");
    p.insertBefore(banList, p.firstChild);
  }
  if (initSummary) {
    var wpSummary = document.getElementById("wpSummary");
    if (wpSummary) wpSummary.value = banDefSummary;
    var wpMinoredit = document.getElementById("wpMinoredit");
    if (wpMinoredit) wpMinoredit.checked = true;
  }
  var copyWarn = document.getElementById("editpage-copywarn");
  if (copyWarn) copyWarn.style.display = "none";

  banList.innerHTML = "<b>Ancres brisées :</b><br />"
  for (var i = 0; i < anchors.length; i++) {
    banLastPos[i] = 0;
    banList.innerHTML += banJSLink(i, anchors[i]) + "<br />";
  }
  if (selectFirst && anchors.length > 0) {
    banSelectAnchor(0, anchors[0]);
  }
}

// Vérification d'une page indépendamment du projet
// ************************************************

var banCheckRunning = false;
var banCheckLinks, banCheckBLinks, banCheckArticle, banCheckStatus, banCheckDocSpans;
var banCheckOtherProjects;

function banCheckPage() {
  if (banCheckRunning) {
    alert("La vérification est déjà en cours");
    return;
  }

  var i = 0, j, k, pageLink;
  banCheckLinks = new Array();
  banCheckBLinks = new Array();
  banCheckArticle = "";
  banCheckOtherProjects = 0;
  var s = document.getElementById("editform").getElementsByTagName("textarea")[0].value;
  while (true) {
    i = s.indexOf("[[", i);
    if (i == -1) break;
    i += 2;
    j = s.indexOf("]]", i);
    if (j == -1) break;
    pageLink = s.substr(i, j - i);
    k = pageLink.indexOf("|");
    if (k != -1) pageLink = pageLink.substr(0, k);
    if (pageLink.indexOf("#") != -1)
      banCheckLinks.push(banNormalizeLink(pageLink));
  }
  if (banCheckLinks.length == 0) {
    alert("Cette page ne contient aucun lien ancré");
    return;
  }
  banCheckRunning = true;
  banCheckLinks.sort();

  banCheckStatus = document.createElement('span');
  var p = document.getElementById("MediaWiki-summary");
  p.insertBefore(banCheckStatus, p.firstChild);
  banCheckNext(0);
}

function banCheckNext(index) {
  for (; index < banCheckLinks.length; index++) {
    var link = banCheckLinks[index];
    if (banExternalLink(link)) {
      banCheckOtherProjects++;
      continue;
    }
    if (index > 0 && link == banCheckLinks[index - 1]) continue;
    banCheckStatus.innerHTML = "Vérification des liens ancrés en cours... (" + (index + 1) + " / " + banCheckLinks.length + ")<br />";
    var sharpPos = link.indexOf("#")
    var article = link.substr(0, sharpPos);
    if (banCheckArticle != article) {
      banCheckArticle = article;
      var request = wgServer_ + wgScript_ + '?title=' + encodeURIComponent(article);
      //banCheckStatus.innerHTML += request.htmlize() + "<br />";
      banAjax.http({url: request, onSuccess: banCheckNextSuccess,
                    onFailure: banCheckNextFailure, index: index});
      return;
    }
    var linkFound = false;
    if (banCheckDocSpans != null) {
      var anchor = link.substr(sharpPos + 1);
      for (var i = 0; i < banCheckDocSpans.length; i++) {
        if (banCheckDocSpans[i].getAttribute("id") == anchor) {
          linkFound = true;
          break;
        }
      }
    }
    if (!linkFound) {
      banCheckBLinks.push(link);
    }
  }
  banCheckRunning = false;
  banCheckStatus.parentNode.removeChild(banCheckStatus);
  alert("Liens ancrés : " + banCheckLinks.length +
        "\nLiens brisés distincts : " + banCheckBLinks.length +
        "\nLiens interwiki (non vérifiés) : " + banCheckOtherProjects);
  if (banCheckBLinks.length == 0) return;
  banFormatEditPage(banCheckBLinks, false, false);
}

function banCheckNextSuccess(xmlreq, data) {
  if (xmlreq.responseText.length == 0) {
    banCheckNextFailure(xmlreq, data);
    return;
  }
  var parser = new DOMParser();
  var doc = parser.parseFromString(xmlreq.responseText, 'application/xhtml+xml');
  banCheckDocSpans = doc.getElementsByTagName("*");
  banCheckNext(data.index);
}

function banCheckNextFailure(xmlreq, data) {
  banCheckDocSpans = null;
  banCheckNext(data.index);
}

// Chargement selon le type de page
// ********************************

$(function() {
  if (wgAction_ == "edit" || wgAction_ == "submit") {
    if (document.URL.indexOf(banURLParam) != -1) {
      var url = document.URL;
      var rabPos = url.indexOf(banURLParam) + banURLParam.length;
      var rabEnd = url.indexOf('#', rabPos);
      var anchors = decodeURIComponent(url.substr(rabPos, rabEnd - rabPos)).split("|");
      banFormatEditPage(anchors, true, true);
    }
    else {
      mw.loader.using( 'mediawiki.util', function() {
          mw.util.addPortletLink("p-tb", "javascript:banCheckPage();", "Ancres brisées", "r-ban", "Rechercher les ancres brisées");
      } );
    }
  }
  else if (wgAction_ == "view" && banPageInProject()) {
    banFormatProjectPage();
  }
});