MediaWiki:Gadget-TuneBook.js
Appearance
Note: After publishing, you may have to bypass your browser's cache to see the changes.
- Firefox / Safari: Hold Shift while clicking Reload, or press either Ctrl-F5 or Ctrl-R (⌘-R on a Mac)
- Google Chrome: Press Ctrl-Shift-R (⌘-Shift-R on a Mac)
- Edge: Hold Ctrl while clicking Refresh, or press Ctrl-F5.
(function ($, mw, OO) {
"use strict";
// Carica le librerie OOUI richieste
mw.loader.using(["oojs-ui-core", "oojs-ui-widgets", "oojs-ui-windows"]).done(function () {
console.log("✅ TuneBook Selection Gadget loaded with improvements.");
/********************************************************************
* 1) Dialog Definition: TuneBookSelectionDialog
********************************************************************/
function TuneBookSelectionDialog(config) {
TuneBookSelectionDialog.super.call(this, config);
}
OO.inheritClass(TuneBookSelectionDialog, OO.ui.ProcessDialog);
TuneBookSelectionDialog.static.name = 'tunebookSelectionDialog';
TuneBookSelectionDialog.static.title = 'Collect Sheet Music for your TuneBook';
// Se vuoi una dimensione dinamica, override getBodyHeight:
TuneBookSelectionDialog.prototype.getBodyHeight = function () {
return 600; // Altezza fissa (modifica se necessario)
};
TuneBookSelectionDialog.static.actions = [
{ action: 'cancel', label: 'Cancel', flags: 'safe' },
{ action: 'accept', label: 'Copy selected', flags: ['primary', 'progressive'] }
];
TuneBookSelectionDialog.prototype.initialize = function () {
TuneBookSelectionDialog.super.prototype.initialize.call(this);
this.content = new OO.ui.PanelLayout({
padded: true,
expanded: false,
scrollable: true
});
this.content.$element.css('min-height', '600px');
this.$body.append(this.content.$element);
// Array per memorizzare i blocchi ABC e le relative checkbox
this.abcBlocks = [];
this.checkboxes = [];
// Mostra un messaggio di caricamento
this.content.$element.append($('<p>').text('Loading ABC blocks…'));
// Avvia il recupero ed il parsing dei blocchi ABC
this.retrieveAndParseABCBlocks();
};
TuneBookSelectionDialog.prototype.retrieveAndParseABCBlocks = function () {
var dialog = this;
var currentPage = mw.config.get('wgPageName');
var api = new mw.Api();
console.log("Retrieving wikitext for page:", currentPage);
api.get({
action: 'query',
prop: 'revisions',
titles: currentPage,
rvprop: 'content',
formatversion: 2
}).done(function (data) {
console.log("Wikitext data received:", data);
if (data.query.pages && data.query.pages.length) {
var page = data.query.pages[0];
if (!page.revisions || !page.revisions.length) {
dialog.content.$element.empty().append($('<p>').text('No content found.'));
return;
}
var content = page.revisions[0].content;
console.log("Wikitext content:", content);
// Usa la regexp per estrarre i blocchi ABC
var blocks = parseAllABCBlocks(content);
console.log("Parsed ABC blocks:", blocks);
if (!blocks.length) {
dialog.content.$element.empty().append($('<p>').text('No ABC blocks found.'));
return;
}
dialog.abcBlocks = blocks;
dialog.buildCheckboxList();
}
}).fail(function (err) {
console.error("Error retrieving wikitext:", err);
dialog.content.$element.empty().append($('<p>').text('Error retrieving content.'));
});
};
/**
* Estrae tutti i blocchi ABC dal wikitext, ignorando quelli vuoti o senza "X:".
*/
function parseAllABCBlocks(content) {
var blocks = [];
var regex = /<section\s+begin\s*=\s*[^>]+\/>\s*([\s\S]*?)\s*<section\s+end\s*=\s*[^>]+\/?>/gi;
var match;
while ((match = regex.exec(content)) !== null) {
var rawBlock = match[1].trim();
if (!rawBlock || !rawBlock.match(/X:/)) {
continue;
}
blocks.push(rawBlock);
}
return blocks;
}
TuneBookSelectionDialog.prototype.buildCheckboxList = function () {
var dialog = this;
this.content.$element.empty();
this.content.$element.append($('<p>').text('Select the tune you want to add to your TuneBook:'));
this.abcBlocks.forEach(function (block, index) {
// Tenta di estrarre una riga titolo (prima riga "T:")
var titleMatch = block.match(/^\s*T:\s*(.+)$/m);
var title = titleMatch ? titleMatch[1].trim() : "Block " + (index + 1);
var checkbox = new OO.ui.CheckboxInputWidget({ selected: true });
var field = new OO.ui.FieldLayout(checkbox, {
label: title,
align: 'inline'
});
dialog.content.$element.append(field.$element);
dialog.checkboxes.push({ checkbox: checkbox, block: block });
});
};
TuneBookSelectionDialog.prototype.onOpen = function () {
TuneBookSelectionDialog.super.prototype.onOpen.call(this);
if (this.checkboxes.length === 0) {
this.$actionArea.find('button[data-action="accept"]').prop('disabled', true);
}
};
// Modifica: al click su "accept", prima di copiare i blocchi, verifica/crea la pagina nel namespace dell'utente
TuneBookSelectionDialog.prototype.getActionProcess = function (action) {
var dialog = this;
if (action === 'accept') {
return new OO.ui.Process(function () {
var selectedBlocks = dialog.checkboxes
.filter(function (item) { return item.checkbox.isSelected(); })
.map(function (item) { return item.block; });
console.log("Selected ABC blocks:", selectedBlocks);
if (selectedBlocks.length === 0) {
dialog.close({ action: action });
return;
}
// Verifica e, se necessario, crea la pagina TuneBook, poi copia i blocchi selezionati
ensureTuneBookPage(function(tuneBookTitle) {
copyBlocksToTuneBook(selectedBlocks, tuneBookTitle);
});
dialog.close({ action: action });
});
} else if (action === 'cancel') {
return new OO.ui.Process(function () {
console.log("Dialog cancelled.");
dialog.close({ action: action });
});
}
return TuneBookSelectionDialog.super.prototype.getActionProcess.call(this, action);
};
/**
* Verifica se esiste la pagina TuneBook dell'utente (User:SafeUsername/TuneBook).
* Se non esiste, la crea inserendo un testo iniziale (più newline).
* Una volta completato, richiama il callback con il titolo della pagina.
*/
function ensureTuneBookPage(callback) {
var api = new mw.Api();
var username = mw.config.get('wgUserName');
if (!username) {
alert("You must be logged in to use this feature.");
return;
}
var safeUsername = username.replace(/\s+/g, '_');
var tuneBookTitle = 'User:' + safeUsername + '/TuneBook';
api.get({
action: 'query',
titles: tuneBookTitle,
formatversion: 2
}).done(function(data) {
var page = data.query.pages[0];
if (page.missing !== undefined) {
if (confirm("The page " + tuneBookTitle + " does not exist. Do you want to create it?")) {
// Testo iniziale da inserire nella pagina appena creata
var initialText = "The Traditional Tune Archive TuneBook creation system\n\n";
api.postWithToken('csrf', {
action: 'edit',
title: tuneBookTitle,
text: initialText,
summary: 'Automatically creating TuneBook page'
}).done(function(result) {
if (result.edit && result.edit.result === 'Success') {
callback(tuneBookTitle);
} else {
alert("Error creating TuneBook page.");
}
}).fail(function(err) {
console.error("Error creating TuneBook page:", err);
alert("Error creating TuneBook page.");
});
} else {
alert("Operation cancelled.");
}
} else {
// La pagina esiste già
callback(tuneBookTitle);
}
}).fail(function(err) {
console.error("Error checking TuneBook page:", err);
alert("Error checking TuneBook page.");
});
}
/**
* Copia i blocchi ABC selezionati nella pagina specificata tramite l'API.
* Ogni blocco viene "wrappato" aggiungendo, prima e dopo, una riga di commento (con "%")
* e dei newline, garantendo la separazione necessaria per abcjs.
*/
function copyBlocksToTuneBook(blocks, tuneBookTitle) {
var api = new mw.Api();
// Per ciascun blocco, aggiunge newline e una riga di commento prima e dopo
var wrappedBlocks = blocks.map(function(block) {
return "\n\n%\n" + block + "\n%\n\n";
});
var textToAppend = wrappedBlocks.join("");
console.log("Appending the following text to", tuneBookTitle, ":", textToAppend);
api.postWithToken('csrf', {
action: 'edit',
title: tuneBookTitle,
appendtext: textToAppend,
summary: 'Copied selected ABC blocks via TuneBook selection dialog'
}).done(function (result) {
console.log("API post result:", result); // Mostra l'oggetto result completo
if (result.edit && result.edit.captcha) {
console.log("Captcha challenge detected:", result.edit.captcha);
}
if (result.edit && result.edit.result === 'Success') {
var domain = window.location.origin; // Oppure imposta manualmente, ad es. "https://mioDominio.org"
var urlTitle = tuneBookTitle.replace(/\s+/g, '_');
var tuneBookUrl = domain + '/wiki/' + urlTitle;
// Creiamo un messaggio che include un vero link cliccabile
var messageHtml = new OO.ui.HtmlSnippet(
'Tunes successfully added to your own <br><br><center><a href="' + tuneBookUrl + '" target="_blank">TuneBook</a></center> <br>You can find it in My Pages under your Personal Menu or simply click the link above (<em>which will open a new tab</em>).'
);
// Mostriamo un dialogo di tipo OO.ui.MessageDialog con il testo HTML
var windowManager = new OO.ui.WindowManager();
$(document.body).append(windowManager.$element);
var messageDialog = new OO.ui.MessageDialog();
windowManager.addWindows([ messageDialog ]);
windowManager.openWindow(messageDialog, {
title: 'Success',
message: messageHtml
});
} else {
console.log("Unexpected API result:", result);
alert('Error copying Tunes to ' + tuneBookTitle);
}
}).fail(function (err) {
console.error("Error during API post:", err);
alert('API error.');
});
}
/********************************************************************
* 2) Toolbox Integration: Add link to open the dialog
********************************************************************/
function openTuneBookSelectionDialog() {
var windowManager = new OO.ui.WindowManager();
$(document.body).append(windowManager.$element);
var dialog = new TuneBookSelectionDialog();
windowManager.addWindows([dialog]);
windowManager.openWindow(dialog);
}
function addTuneBookSelectionLink() {
var $actions = $('#p-cactions ul');
if ($actions.length === 0) { return; }
if ($('#tunebook-selection').length === 0) {
var $newLink = $('<li><a href="#" id="tunebook-selection">📋 Create a TuneBook</a></li>');
$actions.append($newLink);
console.log("TuneBook selection link added to Actions.");
}
}
$(document).on('click', '#tunebook-selection', function (e) {
e.preventDefault();
openTuneBookSelectionDialog();
});
// Inizializza
$(addTuneBookSelectionLink);
});
})(jQuery, mediaWiki, OO);