Jump to content
Basculer le menu
Changer de menu des préférences
Basculer le menu personnel
Non connecté(e)
Votre adresse IP sera visible au public si vous faites des modifications.

« MediaWiki:Common.js » : différence entre les versions

Page de l’interface de MediaWiki
Gadget téléchargements — formulaire d'ajout (Infothèque)
 
Gadget téléchargements v2 — galerie multi-images + clé de série (Infothèque)
Ligne 12 : Ligne 12 :
  * aucun n'est trouvé sur la page).
  * aucun n'est trouvé sur la page).
  *
  *
  * Le format (disquette / CD / ZIP) est traduit automatiquement
  * - Le format (disquette / CD / ZIP) est traduit automatiquement
  * en icône — voir ITH_DL_FORMATS ci-dessous. Adapte les noms de
  *   en icône — voir ITH_DL_FORMATS ci-dessous.
  * fichiers si tu uploades tes icônes sous d'autres noms.
* - Plusieurs images possibles : 1 image = insérée telle quelle,
*  2+ images = galerie en grille (<gallery mode="packed">).
* - Un champ "Clé de produit / n° de série" facultatif, ajouté
  *   proprement à la description (formaté en <code>).
* - Toute valeur libre insérée dans le wikitexte a ses "|"
*  échappés en {{!}}, sinon un pipe tapé par l'utilisateur
*  casserait l'appel du modèle (même souci que celui qui
*  cassait le rendu du tableau — voir Modèle:Téléchargements).
  * ============================================================ */
  * ============================================================ */


Ligne 26 : Ligne 33 :
         autre: { label: 'Autre (icône personnalisée)', wikitext: '' }
         autre: { label: 'Autre (icône personnalisée)', wikitext: '' }
     };
     };
    function escapePipes(str) {
        return String(str || '').split('|').join('{{!}}');
    }


     function init() {
     function init() {
Ligne 59 : Ligne 70 :
             '<label>Langue<input type="text" id="ith-dl-langue" value="Français"></label>' +
             '<label>Langue<input type="text" id="ith-dl-langue" value="Français"></label>' +
             '<label>Description<textarea id="ith-dl-description" rows="2" placeholder="Notes libres, facultatif"></textarea></label>' +
             '<label>Description<textarea id="ith-dl-description" rows="2" placeholder="Notes libres, facultatif"></textarea></label>' +
            '<label>Clé de produit / n° de série<textarea id="ith-dl-serial" rows="2" placeholder="Facultatif. Une ligne par clé, ex :&#10;Product key: XXXXX-XXXXX-XXXXX&#10;Code key: 341-0005934"></textarea></label>' +
             '<label>Format<select id="ith-dl-format"></select></label>' +
             '<label>Format<select id="ith-dl-format"></select></label>' +
             '<label id="ith-dl-format-autre-wrap" style="display:none">Icône personnalisée (wikitexte)<input type="text" id="ith-dl-format-autre" placeholder="[[Fichier:Mon icône.png|centré]]"></label>' +
             '<label id="ith-dl-format-autre-wrap" style="display:none">Icône personnalisée (wikitexte)<input type="text" id="ith-dl-format-autre" placeholder="[[Fichier:Mon icône.png|centré]]"></label>' +
             '<label>Image<input type="text" id="ith-dl-image" placeholder="[[Fichier:Photo.jpg|centré|vignette]] (facultatif)"></label>' +
             '<label>Images (photos, boîtes, disques...)</label>' +
             '<label>Liens de téléchargement <span class="ith-dl-req">*</span>' +
            '<div id="ith-dl-images"></div>' +
            '<button type="button" id="ith-dl-add-image" class="ith-dl-btn-secondary ith-dl-btn-small">+ Ajouter une image</button>' +
             '<label style="margin-top:12px">Liens de téléchargement <span class="ith-dl-req">*</span>' +
             '<textarea id="ith-dl-liens" rows="3" placeholder="Une ligne par lien, format : URL | Texte du lien"></textarea>' +
             '<textarea id="ith-dl-liens" rows="3" placeholder="Une ligne par lien, format : URL | Texte du lien"></textarea>' +
             '</label>' +
             '</label>' +
Ligne 85 : Ligne 99 :
             autreWrap.style.display = select.value === 'autre' ? '' : 'none';
             autreWrap.style.display = select.value === 'autre' ? '' : 'none';
         });
         });
        var imagesWrap = box.querySelector('#ith-dl-images');
        function addImageRow() {
            var row = document.createElement('div');
            row.className = 'ith-dl-image-row';
            row.innerHTML =
                '<input type="text" class="ith-dl-image-file" placeholder="Nom du fichier, ex : Win95disks.jpg">' +
                '<input type="text" class="ith-dl-image-caption" placeholder="Légende (facultatif)">' +
                '<button type="button" class="ith-dl-btn-remove-image" title="Retirer">×</button>';
            row.querySelector('.ith-dl-btn-remove-image').addEventListener('click', function () {
                imagesWrap.removeChild(row);
            });
            imagesWrap.appendChild(row);
        }
        addImageRow(); // une première ligne par défaut
        box.querySelector('#ith-dl-add-image').addEventListener('click', addImageRow);


         box.querySelector('#ith-dl-cancel').addEventListener('click', closeModal);
         box.querySelector('#ith-dl-cancel').addEventListener('click', closeModal);
Ligne 97 : Ligne 127 :
         function closeModal() {
         function closeModal() {
             document.body.removeChild(overlay);
             document.body.removeChild(overlay);
        }
        function buildImageWikitext() {
            var rows = Array.prototype.slice.call(imagesWrap.querySelectorAll('.ith-dl-image-row'));
            var images = rows.map(function (row) {
                var file = row.querySelector('.ith-dl-image-file').value.trim();
                var caption = row.querySelector('.ith-dl-image-caption').value.trim();
                return { file: file, caption: caption };
            }).filter(function (img) { return img.file; });
            if (images.length === 0) {
                return '';
            }
            if (images.length === 1) {
                var f = images[0].file.replace(/^Fichier:/i, '');
                var parts = ['[[Fichier:' + f, 'centré', 'vignette'];
                if (images[0].caption) parts.push(images[0].caption);
                return parts.join('|') + ']]';
            }
            var lines = images.map(function (img) {
                var f = img.file.replace(/^Fichier:/i, '');
                return 'Fichier:' + f + (img.caption ? '|' + img.caption : '');
            });
            return '<gallery mode="packed">\n' + lines.join('\n') + '\n</gallery>';
        }
        function buildDescriptionWithSerial(description, serialRaw) {
            var serialLines = serialRaw.split('\n').map(function (l) { return l.trim(); }).filter(Boolean);
            if (serialLines.length === 0) {
                return description;
            }
            var serialBlock = "'''Clé de produit :'''<br>" +
                serialLines.map(function (l) { return '<code>' + l + '</code>'; }).join('<br>');
            return description ? description + '\n\n' + serialBlock : serialBlock;
         }
         }


Ligne 112 : Ligne 176 :
             var version = box.querySelector('#ith-dl-version').value.trim();
             var version = box.querySelector('#ith-dl-version').value.trim();
             var langue = box.querySelector('#ith-dl-langue').value.trim();
             var langue = box.querySelector('#ith-dl-langue').value.trim();
             var description = box.querySelector('#ith-dl-description').value.trim();
             var descriptionRaw = box.querySelector('#ith-dl-description').value.trim();
            var serialRaw = box.querySelector('#ith-dl-serial').value.trim();
            var description = buildDescriptionWithSerial(descriptionRaw, serialRaw);
             var formatKey = select.value;
             var formatKey = select.value;
             var format = formatKey === 'autre'
             var format = formatKey === 'autre'
                 ? box.querySelector('#ith-dl-format-autre').value.trim()
                 ? box.querySelector('#ith-dl-format-autre').value.trim()
                 : ITH_DL_FORMATS[formatKey].wikitext;
                 : ITH_DL_FORMATS[formatKey].wikitext;
             var image = box.querySelector('#ith-dl-image').value.trim();
             var image = buildImageWikitext();
             var liens = buildLiens(liensRaw);
             var liens = buildLiens(liensRaw);


Ligne 201 : Ligne 267 :


     function buildParamLines(n, data) {
     function buildParamLines(n, data) {
        // edition/version/langue/description = texte libre -> pipes échappés.
        // format/image/liens = wikitexte déjà construit ([[...]], <gallery>, [url texte])
        // dont les pipes internes sont protégés par [[ ]] / <gallery> / pas de pipe du tout.
         return [
         return [
             ' |edition' + n + '=' + data.edition,
             ' |edition' + n + '=' + escapePipes(data.edition),
             ' |version' + n + '=' + data.version,
             ' |version' + n + '=' + escapePipes(data.version),
             ' |langue' + n + '=' + data.langue,
             ' |langue' + n + '=' + escapePipes(data.langue),
             ' |description' + n + '=' + data.description,
             ' |description' + n + '=' + escapePipes(data.description),
             ' |format' + n + '=' + data.format,
             ' |format' + n + '=' + data.format,
             ' |image' + n + '=' + data.image,
             ' |image' + n + '=' + data.image,

Version du 12 août 2026 à 10:33

/* Tout JavaScript présent ici sera exécuté par tous les utilisateurs à chaque chargement de page. */

/* ============================================================
 * Infothèque — Gadget "Ajouter un téléchargement"
 * À coller dans : MediaWiki:Common.js (à la suite du contenu existant)
 *
 * N'agit que sur la page d'édition en mode source (là où
 * #wpTextbox1 existe). Ajoute un bouton qui ouvre un petit
 * formulaire, puis insère automatiquement le bon bloc de
 * paramètres numérotés dans l'appel {{Téléchargements|...}}
 * existant (ou en crée un nouveau à l'endroit du curseur si
 * aucun n'est trouvé sur la page).
 *
 * - Le format (disquette / CD / ZIP) est traduit automatiquement
 *   en icône — voir ITH_DL_FORMATS ci-dessous.
 * - Plusieurs images possibles : 1 image = insérée telle quelle,
 *   2+ images = galerie en grille (<gallery mode="packed">).
 * - Un champ "Clé de produit / n° de série" facultatif, ajouté
 *   proprement à la description (formaté en <code>).
 * - Toute valeur libre insérée dans le wikitexte a ses "|"
 *   échappés en {{!}}, sinon un pipe tapé par l'utilisateur
 *   casserait l'appel du modèle (même souci que celui qui
 *   cassait le rendu du tableau — voir Modèle:Téléchargements).
 * ============================================================ */

(function () {
    'use strict';

    var ITH_DL_FORMATS = {
        disquette: { label: 'Disquette', wikitext: '[[Fichier:Icône disquettes.png|centré]]' },
        cd: { label: 'CD-ROM / DVD', wikitext: '[[Fichier:Icone_CD.png|centré|sans_cadre]]' },
        zip: { label: 'Fichier ZIP / téléchargement numérique', wikitext: '[[Fichier:Zipfldr.dll 14 123-3.png|centré|sans_cadre]]' },
        autre: { label: 'Autre (icône personnalisée)', wikitext: '' }
    };

    function escapePipes(str) {
        return String(str || '').split('|').join('{{!}}');
    }

    function init() {
        var textarea = document.getElementById('wpTextbox1');
        if (!textarea) {
            return; // pas en édition source
        }
        addButton(textarea);
    }

    function addButton(textarea) {
        var btn = document.createElement('button');
        btn.type = 'button';
        btn.id = 'ith-dl-add-btn';
        btn.className = 'ith-dl-add-btn';
        btn.textContent = '+ Ajouter un téléchargement';
        btn.addEventListener('click', function () {
            openModal(textarea);
        });
        textarea.parentNode.insertBefore(btn, textarea);
    }

    function openModal(textarea) {
        var overlay = document.createElement('div');
        overlay.className = 'ith-dl-overlay';

        var box = document.createElement('div');
        box.className = 'ith-dl-modal';
        box.innerHTML =
            '<h3>Ajouter un téléchargement</h3>' +
            '<label>Édition <span class="ith-dl-req">*</span><input type="text" id="ith-dl-edition" placeholder="Ex : Windows 95"></label>' +
            '<label>Version<input type="text" id="ith-dl-version" placeholder="Ex : OSR 2.5 OEM 4.03.1216"></label>' +
            '<label>Langue<input type="text" id="ith-dl-langue" value="Français"></label>' +
            '<label>Description<textarea id="ith-dl-description" rows="2" placeholder="Notes libres, facultatif"></textarea></label>' +
            '<label>Clé de produit / n° de série<textarea id="ith-dl-serial" rows="2" placeholder="Facultatif. Une ligne par clé, ex :&#10;Product key: XXXXX-XXXXX-XXXXX&#10;Code key: 341-0005934"></textarea></label>' +
            '<label>Format<select id="ith-dl-format"></select></label>' +
            '<label id="ith-dl-format-autre-wrap" style="display:none">Icône personnalisée (wikitexte)<input type="text" id="ith-dl-format-autre" placeholder="[[Fichier:Mon icône.png|centré]]"></label>' +
            '<label>Images (photos, boîtes, disques...)</label>' +
            '<div id="ith-dl-images"></div>' +
            '<button type="button" id="ith-dl-add-image" class="ith-dl-btn-secondary ith-dl-btn-small">+ Ajouter une image</button>' +
            '<label style="margin-top:12px">Liens de téléchargement <span class="ith-dl-req">*</span>' +
            '<textarea id="ith-dl-liens" rows="3" placeholder="Une ligne par lien, format : URL | Texte du lien"></textarea>' +
            '</label>' +
            '<div class="ith-dl-actions">' +
            '<button type="button" id="ith-dl-cancel" class="ith-dl-btn-secondary">Annuler</button>' +
            '<button type="button" id="ith-dl-submit" class="ith-dl-btn-primary">Ajouter</button>' +
            '</div>' +
            '<p class="ith-dl-error" id="ith-dl-error" style="display:none"></p>';

        overlay.appendChild(box);
        document.body.appendChild(overlay);

        var select = box.querySelector('#ith-dl-format');
        Object.keys(ITH_DL_FORMATS).forEach(function (key) {
            var opt = document.createElement('option');
            opt.value = key;
            opt.textContent = ITH_DL_FORMATS[key].label;
            select.appendChild(opt);
        });
        select.addEventListener('change', function () {
            var autreWrap = box.querySelector('#ith-dl-format-autre-wrap');
            autreWrap.style.display = select.value === 'autre' ? '' : 'none';
        });

        var imagesWrap = box.querySelector('#ith-dl-images');
        function addImageRow() {
            var row = document.createElement('div');
            row.className = 'ith-dl-image-row';
            row.innerHTML =
                '<input type="text" class="ith-dl-image-file" placeholder="Nom du fichier, ex : Win95disks.jpg">' +
                '<input type="text" class="ith-dl-image-caption" placeholder="Légende (facultatif)">' +
                '<button type="button" class="ith-dl-btn-remove-image" title="Retirer">×</button>';
            row.querySelector('.ith-dl-btn-remove-image').addEventListener('click', function () {
                imagesWrap.removeChild(row);
            });
            imagesWrap.appendChild(row);
        }
        addImageRow(); // une première ligne par défaut
        box.querySelector('#ith-dl-add-image').addEventListener('click', addImageRow);

        box.querySelector('#ith-dl-cancel').addEventListener('click', closeModal);
        overlay.addEventListener('click', function (e) {
            if (e.target === overlay) closeModal();
        });

        box.querySelector('#ith-dl-submit').addEventListener('click', function () {
            submit(textarea);
        });

        function closeModal() {
            document.body.removeChild(overlay);
        }

        function buildImageWikitext() {
            var rows = Array.prototype.slice.call(imagesWrap.querySelectorAll('.ith-dl-image-row'));
            var images = rows.map(function (row) {
                var file = row.querySelector('.ith-dl-image-file').value.trim();
                var caption = row.querySelector('.ith-dl-image-caption').value.trim();
                return { file: file, caption: caption };
            }).filter(function (img) { return img.file; });

            if (images.length === 0) {
                return '';
            }
            if (images.length === 1) {
                var f = images[0].file.replace(/^Fichier:/i, '');
                var parts = ['[[Fichier:' + f, 'centré', 'vignette'];
                if (images[0].caption) parts.push(images[0].caption);
                return parts.join('|') + ']]';
            }
            var lines = images.map(function (img) {
                var f = img.file.replace(/^Fichier:/i, '');
                return 'Fichier:' + f + (img.caption ? '|' + img.caption : '');
            });
            return '<gallery mode="packed">\n' + lines.join('\n') + '\n</gallery>';
        }

        function buildDescriptionWithSerial(description, serialRaw) {
            var serialLines = serialRaw.split('\n').map(function (l) { return l.trim(); }).filter(Boolean);
            if (serialLines.length === 0) {
                return description;
            }
            var serialBlock = "'''Clé de produit :'''<br>" +
                serialLines.map(function (l) { return '<code>' + l + '</code>'; }).join('<br>');
            return description ? description + '\n\n' + serialBlock : serialBlock;
        }

        function submit(ta) {
            var edition = box.querySelector('#ith-dl-edition').value.trim();
            var liensRaw = box.querySelector('#ith-dl-liens').value.trim();
            var errEl = box.querySelector('#ith-dl-error');

            if (!edition || !liensRaw) {
                errEl.textContent = 'Édition et au moins un lien de téléchargement sont obligatoires.';
                errEl.style.display = '';
                return;
            }

            var version = box.querySelector('#ith-dl-version').value.trim();
            var langue = box.querySelector('#ith-dl-langue').value.trim();
            var descriptionRaw = box.querySelector('#ith-dl-description').value.trim();
            var serialRaw = box.querySelector('#ith-dl-serial').value.trim();
            var description = buildDescriptionWithSerial(descriptionRaw, serialRaw);
            var formatKey = select.value;
            var format = formatKey === 'autre'
                ? box.querySelector('#ith-dl-format-autre').value.trim()
                : ITH_DL_FORMATS[formatKey].wikitext;
            var image = buildImageWikitext();
            var liens = buildLiens(liensRaw);

            var data = {
                edition: edition,
                version: version,
                langue: langue,
                description: description,
                format: format,
                image: image,
                liens: liens
            };

            insertIntoTextarea(ta, data);
            closeModal();
        }
    }

    function buildLiens(raw) {
        var lines = raw.split('\n').map(function (l) { return l.trim(); }).filter(Boolean);
        var formatted = lines.map(function (line) {
            var parts = line.split('|');
            var url = (parts[0] || '').trim();
            var texte = (parts[1] || 'Téléchargement').trim();
            return '[' + url + ' ' + texte + ']';
        });
        if (formatted.length === 1) {
            return formatted[0];
        }
        return formatted.map(function (f) { return '* ' + f; }).join('\n');
    }

    function insertIntoTextarea(textarea, data) {
        var text = textarea.value;
        var startIdx = text.indexOf('{{Téléchargements');

        if (startIdx === -1) {
            var block = '{{Téléchargements\n' + buildParamLines(1, data) + '\n}}';
            insertAtCursor(textarea, block);
            return;
        }

        // Trouve l'accolade fermante correspondante en comptant la profondeur des {{ }}.
        var depth = 0;
        var endIdx = -1;
        for (var i = startIdx; i < text.length - 1; i++) {
            if (text[i] === '{' && text[i + 1] === '{') { depth++; i++; }
            else if (text[i] === '}' && text[i + 1] === '}') {
                depth--; i++;
                if (depth === 0) { endIdx = i; break; }
            }
        }

        if (endIdx === -1) {
            // Structure inattendue : on n'insère pas au hasard, on ajoute un nouveau bloc à part.
            var fallback = '{{Téléchargements\n' + buildParamLines(1, data) + '\n}}';
            insertAtCursor(textarea, fallback);
            return;
        }

        var callText = text.slice(startIdx, endIdx + 1);
        var maxIndex = 0;
        var re = /edition(\d+)\s*=/g;
        var m;
        while ((m = re.exec(callText))) {
            maxIndex = Math.max(maxIndex, parseInt(m[1], 10));
        }
        var nextIndex = maxIndex + 1;

        if (nextIndex > 10) {
            alert('Ce tableau contient déjà 10 téléchargements (le maximum géré par le modèle). Préviens l\'admin du wiki pour étendre le modèle.');
            return;
        }

        var paramLines = buildParamLines(nextIndex, data);
        // insère juste avant le "}}" final (donc avant l'avant-dernier caractère de endIdx)
        var insertPos = endIdx - 1;
        var newText = text.slice(0, insertPos) + '\n' + paramLines + text.slice(insertPos);
        textarea.value = newText;
        textarea.dispatchEvent(new Event('input', { bubbles: true }));
        textarea.focus();
    }

    function buildParamLines(n, data) {
        // edition/version/langue/description = texte libre -> pipes échappés.
        // format/image/liens = wikitexte déjà construit ([[...]], <gallery>, [url texte])
        // dont les pipes internes sont protégés par [[ ]] / <gallery> / pas de pipe du tout.
        return [
            ' |edition' + n + '=' + escapePipes(data.edition),
            ' |version' + n + '=' + escapePipes(data.version),
            ' |langue' + n + '=' + escapePipes(data.langue),
            ' |description' + n + '=' + escapePipes(data.description),
            ' |format' + n + '=' + data.format,
            ' |image' + n + '=' + data.image,
            ' |liens' + n + '=' + data.liens
        ].join('\n');
    }

    function insertAtCursor(textarea, text) {
        var start = textarea.selectionStart || 0;
        var end = textarea.selectionEnd || 0;
        var before = textarea.value.slice(0, start);
        var after = textarea.value.slice(end);
        textarea.value = before + text + after;
        textarea.dispatchEvent(new Event('input', { bubbles: true }));
        textarea.focus();
    }

    if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', init);
    } else {
        init();
    }
})();