Wikipédia:Brouillons/interface ajax/js

Un article de Wikipédia, l'encyclopédie libre.

//

  1. /**
  2. * Scriptus
  3. *
  4. * La fonction Scriptus sert à rédiger sur wikipédia de manière naturelle,
  5. * par simple doubleclic et confimation de sauvegarde.
  6. * La définition de ce script se trouve ici :
  7. * http://fr.wikipedia.org/wiki/Wikip%C3%A9dia:Brouillons/interface_ajax
  8. *
  9. * Le code du script est librement inspiré du système de modification-inline
  10. * de Olivier Lance
  11. * http://olance.developpez.com/articles/web/javascript/modification-inline/
  12. *
  13. * Auteurs : ivo talvet (fr:user:Tavernier) , JoKerozen (fr:user:JoKerozen)
  14. * Date de dernière révision : 15 octobre 2007
  15. * copié-collé depuis
  16. * http://fr.wikipedia.org/w/index.php?title=MediaWiki:JSScripts/Scriptus&oldid=21566322
  17. *
  18. * oldid tokens via action=edit
  19. * http://fr.wikipedia.org/w/index.php?title=Wikip%C3%A9dia:Brouillons/interface_ajax/js&oldid=21985960
  20. * oldid clic section
  21. * http://fr.wikipedia.org/w/index.php?title=Wikip%C3%A9dia:Brouillons/interface_ajax/js&oldid=23786371
  22. * oldid bouton test -> sous5
  23. * http://fr.wikipedia.org/w/index.php?title=Wikip%C3%A9dia:Brouillons/interface_ajax/js&oldid=24260671
  24. *
  25. * @todo : pouvoir modifier plusieurs paragraphes avant d'envoyer le concaténat au serveur
  26. * @todo : convertir les fonctions en méthodes et regrouper en une seule classe ?
  27. */
  28.  
  29. /**
  30. * Fait quelques tests préliminaires puis
  31. * place des eventListeners là où on veut que le script réagisse
  32. */
  33. function Scriptus() {
  34.     if (!wgIsArticle) return;
  35.     if (wgNamespaceNumber & 1) return; //si impair (discussion), retour
  36.     if (  (wgPageName.search('Wikipédia:Le_Bistro') != -1)
  37.         ||(wgPageName.search('Wikipédia:Bulletin_des_administrateurs') != -1)
  38.         ||(document.getElementById("transformeEnPageDeDiscussion"))
  39.        ) return;
  40.  
  41.     var article = document.getElementById("bodyContent");
  42.    
  43.     for (var node=0 ; node < article.childNodes.length ; node++) {
  44.         if(article.childNodes[node].tagName != "P") {continue;}
  45.         addClass(article.childNodes[node], "scParagraphe");
  46.     }
  47.  
  48.     var paragraphes = getElementsByClass("scParagraphe");
  49.     for (var para=0; para<paragraphes.length; para++) {
  50.         paragraphes[para].addEventListener("dblclick", function() {findBlocScriptus(this);}, false);
  51.     }
  52. }
  53.  
  54. /**
  55. * Une fois un évènement capturé, effectue la requête de
  56. * wikitexte à la bdd en fonction du numéro de section
  57. */
  58. function findBlocScriptus(clicSur) {
  59.     if (document.getElementsByTagName('textarea').length) return;
  60.  
  61.     var paragraphes = getElementsByClass("scParagraphe");
  62.  
  63.     for (var index=0; index<paragraphes.length; index++) {
  64.         if (paragraphes[index] == clicSur) break;
  65.     }
  66.  
  67.     var xhrRawSource = wpajaxScriptus.http({ url: wgServer + wgScriptPath
  68.                                +'/index.php?title='
  69.                                + encodeURIComponent(wgPageName)
  70.                                + '&action=raw&maxage=0',
  71.                            async: false,
  72.                            });
  73.  
  74.     var rawSource = xhrRawSource.responseText;
  75.  
  76.     var blocsTous = new Array();
  77.     var flagIter = 0;
  78.     var paragraphes = new Array();
  79.     var flagIterParagraphe = 0;
  80.     var ruptures = ['\n\n', '\n=', '\n*', '\n#', '\n;', '\n:', '{{', '<'];
  81.  
  82.     for (var iter=0; iter <= rawSource.length ; iter++) {
  83.         if (iter == 0) continue; // eventuel arg error
  84.         if (rawSource.toString().charCodeAt(iter) == 10) { // 10 = "\n"
  85.             if (rawSource.toString().charCodeAt(iter-1) == 10) { // deux "\n" successifs
  86.                 paragraphes.push(rawSource.slice(flagIterParagraphe, iter));
  87.                 flagIterParagraphe = iter;
  88.  
  89.                 blocsTous.push(rawSource.slice(flagIter, iter));
  90.                 flagIter = iter;
  91.             }
  92.         }
  93.         if (rawSource.toString().charCodeAt(iter) == 61) { // 61 = "="
  94.             if (rawSource.toString().charCodeAt(iter-1) == 10) { // un "=" précédé d'un "\n"
  95.                 blocsTous.push(rawSource.slice(flagIter, iter));
  96.                 flagIter = iter;
  97.             }
  98.         }
  99.         if (iter == rawSource.length) {
  100.             paragraphes.push(rawSource.slice(flagIterParagraphe, iter)); // on "vide" le raw
  101.         }
  102.     }
  103.  
  104.     var raw = paragraphes[index];
  105.  
  106. //    console.log(index, ":", raw);
  107.  
  108.     afficheBlocScriptus(raw, index, rawSource);
  109. }
  110.  
  111. /**
  112. * Affiche un textarea avec le wikitexte et une interface
  113. */
  114. function afficheBlocScriptus(raw, index, fullraw) {
  115.     var bloc = getElementsByClass('scParagraphe')[index];
  116.  
  117.     var interface = document.createElement("div");
  118.     interface.id = "scInterface";
  119.  
  120.     bloc.parentNode.insertBefore(interface, bloc.nextSibling);
  121.  
  122.     var journal = document.createElement("div");
  123.     journal.textContent = "journal";
  124.  
  125.     interface.appendChild(journal);
  126.  
  127.     var form = document.createElement("form");
  128.     form.className = 'ajaxedit';
  129.     form.name = 'ajaxEditForm';
  130.     form.method = 'get';
  131.     form.action = "javascript:postScriptus();";
  132.  
  133.     var wpTextbox1 = raw;
  134.  
  135.     var textarea = document.createElement("textarea");
  136.     textarea.className = "ajaxTextarea";
  137.     var lines = wpTextbox1.split(/\n/).length;
  138.     var nbchars = wpTextbox1.length;
  139.  
  140.     textarea.appendChild(document.createTextNode(raw));
  141.     form.appendChild(textarea);
  142.  
  143.     var summary = document.createElement("input");
  144.     summary.type = "Text";
  145.     summary.name = "wpSummary";
  146.     summary.id = "wpSummary"
  147.     summary.value="Veuillez résumer vos modifications"
  148.     form.appendChild(summary);
  149.  
  150.     var save = document.createElement("input");
  151.     save.type = "button";
  152.     save.value = "Envoyer"
  153.     form.appendChild(save);
  154.  
  155.     var preview = document.createElement("input");
  156.     preview.type = "button";
  157.     preview.value = "Prévisualisation"
  158.     form.appendChild(preview);
  159.  
  160.     var annuler = document.createElement("input");
  161.     annuler.type = "button";
  162.     annuler.value = "Annuler"
  163.     form.appendChild(annuler);
  164.  
  165.     var tester = document.createElement("input");
  166.     tester.type = "button";
  167.     tester.value = "Tester"
  168.     form.appendChild(tester);
  169.  
  170.     interface.appendChild(form);
  171.  
  172.     var largeur = form.offsetWidth;
  173.     var colones = largeur*10/75;
  174.     var nblines = nbchars/colones+lines;
  175.     textarea.rows = nblines;
  176.  
  177.     save.addEventListener("click", function(){postScriptus(index, fullraw)}, false);
  178.     annuler.addEventListener("click", function(){interface.parentNode.removeChild(interface)}, false);
  179.     preview.addEventListener("click", previsualisationScriptus, false);
  180.     tester.addEventListener("click", testScriptus, false);
  181. }
  182.  
  183. /**
  184. * Fonction liée au bouton "tester" de l'interface
  185. */
  186. function testScriptus() {
  187.     return true;
  188. }
  189.  
  190. /**
  191. * Envoye le wikitexte modifié au serveur
  192. */
  193. function postScriptus(index, fullraw) {
  194.  
  195.     var rawTable = new Array();
  196.     var flagIter = 0;
  197.  
  198.     for (var iter=0; iter <= fullraw.length ; iter++) {
  199.         if (fullraw.toString().charCodeAt(iter) == 10) {
  200.             if (iter == 0) continue; // eventuel arg error
  201.             if (fullraw.toString().charCodeAt(iter-1) == 10) {// 2 lf successifs
  202.                 rawTable.push(fullraw.slice(flagIter, iter));
  203.                 // ^ on ajoute le contenu raw du paragraphe dans le tableau "paragraphes"
  204.                 flagIter = iter;
  205.             }
  206.         }
  207.         if ((iter == fullraw.length) && (iter != flagIter)) {
  208.             rawTable.push(fullraw.slice(flagIter, iter)); // on "vide" le raw
  209.         }
  210.     }
  211.  
  212.     var locWikitext = document.getElementsByTagName('textarea')[0].value;
  213.  
  214.     rawTable[index] = locWikitext;
  215.  
  216.     var iter = 0;
  217.     var wpTextbox1 = "";
  218.     while (rawTable[iter]) {
  219.         wpTextbox1 += encodeURIComponent(rawTable[iter]);
  220.         iter++;
  221.     }
  222.  
  223.     var wpSummary = encodeURIComponent(document.getElementById('wpSummary').value);
  224.     if (wpSummary == encodeURI("Veuillez résumer vos modifications")) wpSummary = "";
  225.  
  226.     console.log("fullraw : ", fullraw);
  227.     console.log("rawTable : ", rawTable);
  228.     console.log("wpTextBox1 : ", wpTextbox1);
  229.  
  230.     //var wpEdittime = document.getElementById('hiddenEdittime').value;
  231.     //var wpEditToken = document.getElementById('hiddenEditToken').value;
  232.     //var wpStarttime = document.getElementById('hiddenStarttime').value;
  233.  
  234.  
  235.     var xhrApi = wpajaxScriptus.http({ url: wgServer + wgScriptPath + '/api.php?action=query&prop=info&titles='
  236.                                             + wgPageName
  237.                                             + '&intoken=edit&format=xml'
  238.                                      , async:false });
  239.     var parser = new DOMParser();
  240.     var doc = parser.parseFromString(xhrApi.responseText, 'text/xml');
  241.  
  242.     var edittime = doc.getElementsByTagName('page')[0].getAttribute('touched');
  243.     var ed1 = edittime.split('-')[0]+edittime.split('-')[1]+edittime.split('-')[2];
  244.     var ed2 = ed1.split('T')[0]+ed1.split('T')[1];
  245.     var ed3 = ed2.split(':')[0]+ed2.split(':')[1]+ed2.split(':')[2];
  246.     var edfin = ed3.split('Z')[0]
  247.  
  248.     var date = new Date(); //ca doit être fait au tout début, pas lorsqu'on appuye sur le bouton de sauvegarde.
  249.  
  250.     var wpEdittime = edfin;
  251.     var wpEditToken = encodeURIComponent(doc.getElementsByTagName('page')[0].getAttribute('edittoken'));
  252.     var wpStarttime = getTimeStampScriptus(date);
  253.  
  254.     if (document.getElementById('ca-unwatch')) {
  255.       var suivi = '&wpWatchthis=1';
  256.     } else {
  257.       var suivi = '';
  258.     }
  259.  
  260.     var headers = new Array();
  261.     headers['Content-Type'] = 'application/x-www-form-urlencoded';
  262.  
  263.     document.HttpWPedit = wpajaxScriptus.http({ url: wgServer + wgScriptPath + '/index.php?title='
  264.                                  + encodeURIComponent(wgPageName)
  265.                                  + '&action=submit',
  266.                           method: "POST",
  267.                           headers: headers,
  268.                           async: false,
  269.                           data: 'wpSave=Sauvegarder&wpTextbox1=' + wpTextbox1
  270.                                 + '&wpStarttime=' + wpStarttime
  271.                                 + '&wpEdittime=' + wpEdittime
  272.                                 + '&wpEditToken=' + wpEditToken
  273.                                 + suivi
  274.                                 + '&wpSummary=' + wpSummary + encodeURIComponent(' (mpa)')});
  275.     apresModifScriptus();
  276. }
  277.  
  278.  
  279. function previsualisationScriptus(wpEdittime, wpEditToken, wpStarttime) {
  280.  
  281.     if (document.getElementById('wikiPreview')) {
  282.         var oldpreview = document.getElementById('wikiPreview').parentNode.removeChild(document.getElementById('wikiPreview'));
  283.     }
  284.  
  285.     var wpTextbox1 = encodeURIComponent(document.getElementsByTagName('textarea')[0].value);
  286.     var wpSummary = encodeURIComponent(document.getElementById('wpSummary').value);
  287.     if (wpSummary == encodeURI("Veuillez résumer vos modifications")) wpSummary = "";
  288.  
  289.     // recuperation des champ hidden
  290.  
  291.     //var wpEdittime = document.getElementById('hiddenEdittime').value;
  292.     //var wpEditToken = document.getElementById('hiddenEditToken').value;
  293.     //var wpStarttime = document.getElementById('hiddenStarttime').value;
  294.  
  295.     if (document.getElementById('ca-unwatch')) {
  296.       var suivi = '&wpWatchthis=1';
  297.     } else {
  298.       var suivi = '';
  299.     }
  300.  
  301.     document.HttpWPpreview = wpajaxScriptus.http({ url: wgServer + wgScriptPath + '/index.php?title='
  302.                                  + encodeURIComponent(wgPageName)
  303.                                  + '&action=submit',
  304.                           method: "POST",
  305.                           async: false,
  306.                           data: 'wpSave=1&wpTextbox1=' + wpTextbox1
  307.                                 + '&wpStarttime=' + wpStarttime
  308.                                 + '&wpEdittime=' + wpEdittime
  309.                                 + '&wpEditToken=' + wpEditToken
  310.                                 + '&wpPreview=Prévisualisation'
  311.                                 + suivi
  312.                                 + '&wpSummary=' + wpSummary + encodeURIComponent(' (mpa)')});
  313.  
  314.     var parser = new DOMParser();
  315.  
  316.     var previewRetour = parser.parseFromString(document.HttpWPpreview.responseText, 'application/xhtml+xml');
  317.     var previewHtml = previewRetour.getElementById('wikiPreview');
  318.     var previewDiv = document.createElement("div");
  319.     previewDiv = previewHtml;
  320.  
  321.     var titre = previewDiv.getElementsByTagName('h2')[0];
  322.  
  323.     var Aretirer = previewDiv.getElementsByTagName('div')[0];
  324.     previewDiv.removeChild(Aretirer);
  325.  
  326.     var form = getElementsByClass('ajaxedit')[0];
  327.  
  328.     previewDiv = form.parentNode.parentNode.insertBefore(previewDiv, form.parentNode.nextSibling);
  329.     previewDiv.style.border = "2px solid #FF8080";
  330.     previewDiv.style.backgroundColor = "#FCFFE5";
  331.     titre.style.color = "#FF8080";
  332.  
  333.     var fermeturePreview = document.createElement("span");
  334.     fermeturePreview.style.fontSize = "xx-small";
  335.     fermeturePreview.style.fontWeight = "normal";
  336.     fermeturePreview.style.cssFloat = "none";
  337.     fermeturePreview = titre.appendChild(fermeturePreview);
  338.     fermeturePreview.innerHTML = '<a href="javascript:var temporaire = document.getElementById(\'wikiPreview\').parentNode.removeChild(document.getElementById(\'wikiPreview\'));" title="Fermer la prévisualisation">fermer</a>'; //virer le innerHTML
  339.  
  340. }
  341.  
  342.  
  343. function apresModifScriptus() {
  344.  
  345.     var parser = new DOMParser();
  346.  
  347.     var doc = parser.parseFromString(document.HttpWPedit.responseText, 'application/xhtml+xml');
  348.  
  349.     document.importNode(doc.getElementsByTagName('html')[0],true);
  350.     var actuel = document.getElementsByTagName('html')[0];
  351.     var parentActuel = actuel.parentNode;
  352.     parentActuel.removeChild(actuel);
  353.     document.appendChild(doc.getElementsByTagName('html')[0]);
  354.  
  355.     //on relance les scripts sur le dom
  356.     runOnloadHook();
  357.  
  358. }
  359.  
  360.  
  361. var wpajaxScriptus = { // depuis http://fr.wikipedia.org/wiki/Utilisateur:EDUCA33E/LiveRC.js
  362.   http: function(bundle) {
  363.     // mandatory: bundle.url
  364.     // optional:  bundle.async
  365.     // optional:  bundle.method
  366.     // optional:  bundle.headers
  367.     // optional:  bundle.data
  368.     // optional:  bundle.onSuccess (xmlhttprequest, bundle)
  369.     // optional:  bundle.onFailure (xmlhttprequest, bundle)
  370.     // optional:  bundle.otherStuff OK too, passed to onSuccess and onFailure
  371.     var xmlhttp;
  372.         try {xmlhttp = new XMLHttpRequest();} catch (e) {xmlhttp = false}
  373.  
  374.     if (xmlhttp) {
  375.       xmlhttp.onreadystatechange = function() {
  376.         if (xmlhttp.readyState == 4) {
  377.           wpajaxScriptus.httpComplete(xmlhttp,bundle);
  378.         }
  379.       }
  380.       xmlhttp.open(bundle.method ? bundle.method : "GET",bundle.url,bundle.async == false ? false : true);
  381.       if (bundle.headers) {
  382.         for (var field in bundle.headers)
  383.           xmlhttp.setRequestHeader(field,bundle.headers[field]);
  384.       }
  385.       xmlhttp.send(bundle.data ? bundle.data : null);
  386.     }
  387.  
  388.     return xmlhttp;
  389.   },
  390.  
  391.   httpComplete: function(xmlhttp,bundle) {
  392.  
  393.     if (xmlhttp.status == 200 || xmlhttp.status == 302) {
  394.       if (bundle.onSuccess) {
  395.         bundle.onSuccess(xmlhttp,bundle);
  396.       } else if (bundle.onFailure) {
  397.       bundle.onFailure(xmlhttp,bundle);
  398.       } else {
  399.       // A activer en debug mode ?
  400.       if (xmlhttp.statusText != "OK") alert(xmlhttp.statusText);
  401.       }
  402.     }
  403.   }
  404. };
  405.  
  406. //depuis advancedcontribs de Maloq
  407. function toNString(num, length)
  408. {
  409.         num = num + ""
  410.  
  411.         while(num.length < length)
  412.                 num = "0" + num
  413.  
  414.         return num
  415. }
  416.  
  417. //renvoi le timeStamp depuis l'object date. A corriger avec le décalage horaire
  418. function getTimeStampScriptus(date)
  419. {
  420.     return date.getFullYear() +
  421.         toNString(date.getMonth() + 1, 2) +
  422.         toNString(date.getDate(), 2) +
  423.         toNString(date.getHours() + (date.getTimezoneOffset() / 60), 2) +
  424.         toNString(date.getMinutes(), 2) +
  425.         toNString(date.getSeconds(), 2)
  426. }
  427.  
  428. addLoadEvent(Scriptus);
  429.  
  430. //