MediaWiki:Common.js
Page de l’interface de MediaWiki
Autres actions
Note : après avoir publié vos modifications, il se peut que vous deviez forcer le rechargement complet du cache de votre navigateur pour voir les changements.
- Firefox / Safari : maintenez la touche Maj (Shift) en cliquant sur le bouton Actualiser ou appuyez sur Ctrl + F5 ou Ctrl + R (⌘ + R sur un Mac).
- Google Chrome : appuyez sur Ctrl + Maj + R (⌘ + Shift + R sur un Mac).
- Edge : maintenez la touche Ctrl en cliquant sur le bouton Actualiser ou pressez Ctrl + F5.
/* 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 : Product key: XXXXX-XXXXX-XXXXX 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;
}
// Une boîte grise par ligne, comme sur l'ancien wiki (une par clé/numéro).
var serialBlock = serialLines.map(function (l) {
return '<div class="ith-dl-serialbox">' + l + '</div>';
}).join('');
return description ? description + '\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();
// MediaWiki n'affiche un lien externe que si l'URL a un schéma
// (http://, https://, ftp://...) — sans ça, le [url texte]
// s'affiche tel quel comme du texte brut avec les crochets.
if (url && !/^[a-z][a-z0-9+.-]*:\/\//i.test(url)) {
url = 'https://' + url;
}
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();
}
})();