« MediaWiki:Common.js » : différence entre les versions
Page de l’interface de MediaWiki
Autres actions
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. | * 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). | |||
* ============================================================ */ | * ============================================================ */ | ||
| 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 : Product key: XXXXX-XXXXX-XXXXX 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> | '<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- | 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 = | 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 : 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;
}
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();
}
})();