پرش به محتوا

مدیاویکی: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);
        };
    });
})();