مدیاویکی:Gadget-FormTemplates.js
ظاهر
نکته: پس از انتشار ممکن است برای دیدن تغییرات نیاز باشد که حافظهٔ نهانی مرورگر خود را پاک کنید.
- فایرفاکس / سافاری: کلید Shift را نگه دارید و روی دکمهٔ Reload کلیک کنید، یا کلیدهای Ctrl-F5 یا Ctrl-R را با هم فشار دهید (در رایانههای اپل مکینتاش کلیدهای ⌘-R)
- گوگل کروم: کلیدهای Ctrl+Shift+R را با هم فشار دهید (در رایانههای اپل مکینتاش کلیدهای ⌘-Shift-R)
- Edge: کلید Ctrl را نگهدارید و روی دکمهٔ Refresh کلیک کنید، یا کلیدهای Ctrl-F5 را با هم فشار دهید
(function () {
'use strict';
mw.loader.using(['mediawiki.util', 'mediawiki.api', 'oojs-ui-core', 'oojs-ui-windows']).then(function () {
if (mw.config.get('wgAction') !== 'edit' && mw.config.get('wgAction') !== 'submit') {
return;
}
var windowManager = new OO.ui.WindowManager({ classes: ['mw-ui-window-manager-centered'] });
$(document.body).append(windowManager.$element);
function ModernInfoboxDialog(config) {
ModernInfoboxDialog.super.call(this, config);
this.fields = {};
this.templateLoaded = false;
this.buttonsAdded = false;
this.upperButtonLayout = null; // دکمههای بالای پیشنمایش
this.lowerButtonLayout = null; // دکمههای زیر فونت
this.previewTextbox = null;
this.savedColors = {};
}
OO.inheritClass(ModernInfoboxDialog, OO.ui.ProcessDialog);
ModernInfoboxDialog.static.name = 'modernInfoboxDialog';
ModernInfoboxDialog.static.title = 'فرم الگو / Template Form';
ModernInfoboxDialog.static.actions = [
{ action: 'save', label: 'افزودن / Add', flags: ['primary', 'progressive'], icon: 'check' },
{ action: 'cancel', label: 'لغو / Cancel', flags: 'safe', icon: 'close' }
];
ModernInfoboxDialog.prototype.getBodyHeight = function () {
return this.templateLoaded ? 700 : 150; // افزایش ارتفاع فرم
};
ModernInfoboxDialog.prototype.initialize = function () {
ModernInfoboxDialog.super.prototype.initialize.call(this);
this.content = new OO.ui.PanelLayout({ padded: true, expanded: false });
var inputField = new OO.ui.ComboBoxInputWidget({
placeholder: 'نام صفحه الگو را وارد کنید... / Enter template page name...',
menu: { filterFromInput: true }
});
var menu = inputField.getMenu();
var fieldset = new OO.ui.FieldsetLayout();
inputField.on('change', function () {
var query = inputField.getValue().trim();
if (query.length < 2) {
menu.clearItems();
menu.toggle(false);
return;
}
var api = new mw.Api();
api.get({
action: 'query',
list: 'allpages',
apnamespace: 10,
apprefix: query,
aplimit: 10,
format: 'json'
}).done(function (data) {
menu.clearItems();
if (data.query && data.query.allpages) {
var suggestions = data.query.allpages.map(function (page) {
var label = page.title.replace('الگو:', '');
return new OO.ui.MenuOptionWidget({ data: label, label: label });
});
menu.addItems(suggestions);
menu.toggle(suggestions.length > 0);
}
});
});
var that = this;
menu.on('choose', function (item) {
if (item) {
inputField.setValue(item.getData());
loadTemplateData.call(that, item.getData());
}
});
var confirmButton = new OO.ui.ButtonWidget({ label: 'نمایش اطلاعات / Show Info', flags: ['progressive'], icon: 'search' });
confirmButton.on('click', function () {
var value = inputField.getValue().trim();
if (value) {
loadTemplateData.call(that, value);
} else {
OO.ui.alert('لطفاً نام صفحه را وارد کنید. / Please enter page name.');
}
});
function createFileInput(placeholder, defaultValue) {
var fileInput = new OO.ui.ComboBoxInputWidget({
placeholder: placeholder,
value: defaultValue || '',
menu: { filterFromInput: true }
});
var fileMenu = fileInput.getMenu();
fileInput.on('change', function (value) {
var query = value.trim();
if (query.length < 2) {
fileMenu.clearItems();
fileMenu.toggle(false);
return;
}
$.ajax({
url: 'https://commons.wikishia.net/w/api.php',
data: {
action: 'query',
list: 'allimages',
aiprefix: query,
ailimit: 10,
format: 'json',
origin: '*'
},
dataType: 'json',
success: function (data) {
fileMenu.clearItems();
if (data.query && data.query.allimages) {
var suggestions = data.query.allimages.map(function (image) {
var label = image.name;
return new OO.ui.MenuOptionWidget({ data: label, label: label });
});
fileMenu.addItems(suggestions);
fileMenu.toggle(suggestions.length > 0);
}
},
error: function (err) {
console.error('خطا در جستجوی فایلها: ', err);
}
});
});
fileMenu.on('choose', function (item) {
if (item) {
fileInput.setValue(item.getData());
}
});
return fileInput;
}
function validateWikitext(wikitext, params) {
var errors = [];
var regex = new RegExp('\\|\\s*([^=\\s]+)\\s*=\\s*([^\\n]+)', 'g');
var match;
while ((match = regex.exec(wikitext)) !== null) {
var paramName = match[1].trim();
var value = match[2].trim();
if (!params[paramName]) {
errors.push(`پارامتر "${paramName}" در این الگو تعریف نشده است. / Parameter "${paramName}" is not defined.`);
} else if (params[paramName].type === 'number' && !/^[0-9]+$/.test(value)) {
errors.push(`پارامتر "${paramName}" باید عدد انگلیسی باشد (مثل "200" نه "۲۰۰"). / Parameter "${paramName}" must be an English number (e.g., "200" not "۲۰۰").`);
}
}
return errors.length > 0 ? errors : null;
}
function loadTemplateData(templateName) {
var fullTitle = templateName.startsWith('الگو:') ? templateName : 'الگو:' + templateName;
var api = new mw.Api();
api.get({
action: 'templatedata',
titles: fullTitle,
format: 'json'
}).done(function (data) {
fieldset.clearItems();
this.fields = {};
this.templateLoaded = true;
this.updateSize();
var pages = data.pages;
if (!pages || Object.keys(pages).length === 0) {
OO.ui.alert('TemplateData برای این الگو یافت نشد. / TemplateData not found for this template.');
this.templateLoaded = false;
this.updateSize();
return;
}
var pageId = Object.keys(pages)[0];
var params = pages[pageId].params;
for (var paramName in params) {
var param = params[paramName];
var input;
var label = (typeof param.label === 'string') ? param.label : paramName;
var description = (typeof param.description === 'string') ? param.description : paramName;
var defaultValue = (typeof param.default === 'string') ? param.default : '';
if (param.type === 'wiki-file-name') {
input = createFileInput('نام فایل (مثل image.jpg، بدون [[File:]]) / File name (e.g., image.jpg, without [[File:]])', defaultValue);
} else if (param.type === 'number') {
input = new OO.ui.TextInputWidget({
type: 'number',
placeholder: description,
value: defaultValue
});
} else if (description.toLowerCase().includes('رنگ') || paramName.toLowerCase().includes('color')) {
var colorInput = $('<input>', {
type: 'color',
value: this.savedColors[paramName] || defaultValue || '#000000',
css: { width: '100%', height: '50px' }
});
input = new OO.ui.Widget({ $element: colorInput });
} else if (param.type === 'boolean' ||
(param.suggestedvalues && param.suggestedvalues.length === 2 &&
param.suggestedvalues.includes('yes') && param.suggestedvalues.includes('no'))) {
input = new OO.ui.DropdownWidget({
menu: {
items: [
new OO.ui.MenuOptionWidget({ data: 'yes', label: 'بله / Yes' }),
new OO.ui.MenuOptionWidget({ data: 'no', label: 'خیر / No' })
]
}
});
if (defaultValue) {
input.getMenu().selectItem(input.getMenu().findItemFromData(defaultValue));
}
} else {
input = new OO.ui.TextInputWidget({
placeholder: description,
value: defaultValue
});
}
this.fields[paramName] = input;
fieldset.addItems([
new OO.ui.FieldLayout(input, {
label: label,
align: 'top',
help: description
})
]);
input.on('change', function () {
var tempData = { templateName: inputField.getValue().trim(), fields: {} };
for (var p in that.fields) {
tempData.fields[p] = that.getFieldValue(that.fields[p]);
}
localStorage.setItem('modernInfoboxTempData', JSON.stringify(tempData));
});
}
var savedData = localStorage.getItem('modernInfoboxTempData');
if (savedData) {
var tempData = JSON.parse(savedData);
if (tempData.templateName === inputField.getValue().trim()) {
for (var paramName in tempData.fields) {
if (this.fields[paramName] && typeof this.fields[paramName].$element[0].value === 'string') {
this.fields[paramName].$element[0].value = tempData.fields[paramName];
} else if (this.fields[paramName] && typeof this.fields[paramName].setValue === 'function') {
this.fields[paramName].setValue(tempData.fields[paramName]);
}
}
}
}
if (!this.buttonsAdded) {
// دکمههای زیر فونت (ریست و ذخیره موقت)
var resetButton = new OO.ui.ButtonWidget({ label: 'ریست اطلاعات', flags: 'destructive', icon: 'trash' });
resetButton.on('click', function () {
for (var paramName in that.fields) {
var input = that.fields[paramName];
if (input && typeof input.setValue === 'function' && !(input.$element && input.$element.is('input[type="color"]'))) {
input.setValue('');
} else if (input instanceof OO.ui.DropdownWidget) {
input.getMenu().selectItem(null);
}
}
OO.ui.alert('فیلدها ریست شدند.');
});
var saveTempButton = new OO.ui.ButtonWidget({ label: 'ذخیره موقت', flags: 'progressive', icon: 'download' });
saveTempButton.on('click', function () {
var tempData = { templateName: inputField.getValue().trim(), fields: {} };
for (var paramName in that.fields) {
tempData.fields[paramName] = that.getFieldValue(that.fields[paramName]);
}
localStorage.setItem('modernInfoboxTempData', JSON.stringify(tempData));
OO.ui.alert('اطلاعات به صورت موقت ذخیره شد.');
});
// دکمههای بالای پیشنمایش
var previewButton = new OO.ui.ButtonWidget({ label: 'پیشنمایش', flags: 'progressive', icon: 'eye' });
var confirmEditButton = new OO.ui.ButtonWidget({ label: 'تأیید ویرایش', flags: 'progressive', icon: 'check' });
var saveColorsButton = new OO.ui.ButtonWidget({ label: 'ذخیره رنگها', flags: 'progressive', icon: 'tag' });
var cancelColorsButton = new OO.ui.ButtonWidget({ label: 'لغو رنگها', flags: 'destructive', icon: 'undo' });
this.previewTextbox = new OO.ui.MultilineTextInputWidget({ rows: 10, readOnly: false });
previewButton.on('click', function () {
var templateName = inputField.getValue().trim();
if (!templateName) {
OO.ui.alert('لطفاً نام الگو را وارد کنید.');
return;
}
var wikitext = '{{' + templateName;
for (var paramName in that.fields) {
var value = that.getFieldValue(that.fields[paramName]);
if (value) {
wikitext += '\n|' + paramName + '=' + value;
}
}
wikitext += '\n}}';
that.previewTextbox.setValue(wikitext);
});
confirmEditButton.on('click', function () {
var wikitext = that.previewTextbox.getValue();
var errors = validateWikitext(wikitext, params);
if (errors) {
OO.ui.alert('خطاها در ویکیمتن:\n' + errors.join('\n'));
return;
}
var regex = new RegExp('\\|\\s*([^=\\s]+)\\s*=\\s*([^\\n]+)', 'g');
var match;
var newValues = {};
while ((match = regex.exec(wikitext)) !== null) {
newValues[match[1]] = match[2].trim();
}
for (var paramName in that.fields) {
var input = that.fields[paramName];
if (newValues.hasOwnProperty(paramName)) {
if (input && typeof input.$element[0].value === 'string') {
input.$element[0].value = newValues[paramName];
} else if (input && typeof input.setValue === 'function') {
input.setValue(newValues[paramName]);
} else if (input instanceof OO.ui.DropdownWidget) {
input.getMenu().selectItem(input.getMenu().findItemFromData(newValues[paramName]));
}
} else {
if (input && typeof input.$element[0].value === 'string' && !(input.$element.is('input[type="color"]'))) {
input.$element[0].value = '';
} else if (input && typeof input.setValue === 'function') {
input.setValue('');
} else if (input instanceof OO.ui.DropdownWidget) {
input.getMenu().selectItem(null);
}
}
}
OO.ui.alert('ویرایش دستی تأیید شد.');
});
saveColorsButton.on('click', function () {
var hasColorField = false;
for (var paramName in that.fields) {
var input = that.fields[paramName];
if (input.$element && input.$element.is('input[type="color"]')) {
hasColorField = true;
that.savedColors[paramName] = input.$element.val();
}
}
if (hasColorField) {
OO.ui.alert('رنگها با موفقیت ذخیره شدند.');
} else {
OO.ui.alert('هیچ فیلد رنگی یافت نشد.');
}
});
cancelColorsButton.on('click', function () {
var hasColorField = false;
for (var paramName in that.fields) {
var input = that.fields[paramName];
if (input.$element && input.$element.is('input[type="color"]')) {
hasColorField = true;
input.$element.val(params[paramName].default || '#000000');
}
}
if (hasColorField) {
OO.ui.alert('تغییرات رنگ لغو شد.');
} else {
OO.ui.alert('هیچ فیلد رنگی یافت نشد.');
}
});
// چیدمان دکمهها
this.lowerButtonLayout = new OO.ui.HorizontalLayout({
items: [resetButton, saveTempButton]
});
this.upperButtonLayout = new OO.ui.HorizontalLayout({
items: [previewButton, confirmEditButton, saveColorsButton, cancelColorsButton]
});
this.buttonsAdded = true;
}
// اضافه کردن دکمههای زیر فونت
fieldset.addItems([this.lowerButtonLayout]);
// اضافه کردن دکمههای بالای پیشنمایش و خود پیشنمایش
fieldset.addItems([
this.upperButtonLayout,
new OO.ui.FieldLayout(this.previewTextbox, { label: 'پیشنمایش ویکیمتن', align: 'top' })
]);
}.bind(this)).fail(function (err) {
OO.ui.alert('خطا در بارگذاری TemplateData: ' + err);
this.templateLoaded = false;
this.updateSize();
}.bind(this));
}
this.content.$element.append(new OO.ui.FieldsetLayout({
items: [
new OO.ui.FieldLayout(inputField, { label: 'انتخاب الگو / Select Template', align: 'top' }),
new OO.ui.FieldLayout(confirmButton, { align: 'inline' }),
fieldset
]
}).$element);
this.$body.append(this.content.$element);
};
ModernInfoboxDialog.prototype.getFieldValue = function (input) {
if (input instanceof OO.ui.ComboBoxInputWidget) {
var selectedItem = input.getMenu().findSelectedItem();
return selectedItem ? selectedItem.getData() : input.getValue().trim();
} else if (input instanceof OO.ui.DropdownWidget) {
var selectedItem = input.getMenu().findSelectedItem();
return selectedItem ? selectedItem.getData() : '';
} else if (input.$element && input.$element.is('input[type="color"]')) {
return input.$element.val();
} else {
return input.getValue ? input.getValue().trim() : '';
}
};
ModernInfoboxDialog.prototype.getActionProcess = function (action) {
if (action === 'save') {
return new OO.ui.Process(function () {
var templateName = this.content.$element.find('input')[0].value.trim();
if (!templateName) {
OO.ui.alert('لطفاً نام الگو را وارد کنید.');
return;
}
var wikitext = '{{' + templateName;
for (var paramName in this.fields) {
var value = this.getFieldValue(this.fields[paramName]);
if (value) {
wikitext += '\n|' + paramName + '=' + value;
}
}
wikitext += '\n}}';
var editor = $('#wpTextbox1');
if (editor.length) {
editor.val(editor.val() + wikitext);
OO.ui.alert('الگو به ویرایشگر اضافه شد!');
this.close();
} else {
OO.ui.alert('ویرایشگر یافت نشد.');
}
}.bind(this));
} else if (action === 'cancel') {
return new OO.ui.Process(function () {
this.close();
}.bind(this));
}
return ModernInfoboxDialog.super.prototype.getActionProcess.call(this, action);
};
ModernInfoboxDialog.prototype.updateSize = function () {
ModernInfoboxDialog.super.prototype.updateSize.call(this);
if (this.templateLoaded) {
this.$element.addClass('template-loaded');
} else {
this.$element.removeClass('template-loaded');
}
};
ModernInfoboxDialog.prototype.onOpen = function () {
ModernInfoboxDialog.super.prototype.onOpen.call(this);
this.$element.find('input').first().focus();
};
var dialog = new ModernInfoboxDialog({ size: 'large' });
windowManager.addWindows([dialog]);
mw.util.addPortletLink(
'p-tb',
'#',
'فرم الگو / Template Form',
't-moderninfoboxform',
'باز کردن فرم الگو / Open template form'
).addEventListener('click', function (e) {
e.preventDefault();
windowManager.openWindow(dialog);
});
OO.ui.alert = function (message) {
const alertDiv = $('<div>')
.text(message)
.css({
position: 'fixed',
top: '20px',
left: '50%',
transform: 'translateX(-50%)',
zIndex: '20000',
backgroundColor: '#d4edda',
color: '#155724',
padding: '15px 20px',
borderRadius: '8px',
boxShadow: '0 4px 15px rgba(0, 0, 0, 0.2)',
maxWidth: '80%',
whiteSpace: 'pre-wrap',
transition: 'all 0.3s ease'
});
$(document.body).append(alertDiv);
setTimeout(() => alertDiv.fadeOut(500, () => alertDiv.remove()), 3000);
};
});
})();