MediaWiki:Common.js

Материал из PanoramaWiki
Перейти к: навигация, поиск

Замечание. Возможно, после сохранения вам придётся очистить кэш своего браузера, чтобы увидеть изменения.

  • Firefox / Safari: Удерживая клавишу Shift, нажмите на панели инструментов Обновить либо нажмите Ctrl-F5 или Ctrl-R (⌘-R на Mac)
  • Google Chrome: Нажмите Ctrl-Shift-R (⌘-Shift-R на Mac)
  • Internet Explorer: Удерживая Ctrl, нажмите Обновить либо нажмите Ctrl-F5
  • Opera: Выберите очистку кэша в меню Инструменты → Настройки
(function (win, doc, nav, params, namespace, undefined) {
    'use strict';

    var util = {
        keycode: {
            ESCAPE: 27
        },
        getRequest: function () {
            if (win.XDomainRequest) {
                return new win.XDomainRequest();
            }
            if (win.XMLHttpRequest) {
                return new win.XMLHttpRequest();
            }
            return null;
        },
        loadScript: function (src, parent, callback) {
            var script = doc.createElement('script');
            script.src = src;

            script.addEventListener('load', function onLoad() {
                this.removeEventListener('load', onLoad, false);
                callback();
            }, false);

            parent.appendChild(script);
        },
        loadResource: function (url, callback) {
            var request = this.getRequest();

            if (!request) {
                return null;
            }

            request.onload = function () {
                callback(this.responseText);
            };
            request.open('GET', url, true);

            win.setTimeout(function () {
                request.send();
            }, 0);

            return request;
        },
        getStyleList: function (element) {
            var value = element.getAttribute('class');
            if (!value) {
                return [];
            }
            return value.replace(/\s+/g, ' ').trim().split(' ');
        },
        hasStyleName: function (element, name) {
            var list = this.getStyleList(element);
            return !!list.length && list.indexOf(name) >= 0;
        },
        addStyleName: function (element, name) {
            var list = this.getStyleList(element);
            list.push(name);
            element.setAttribute('class', list.join(' '));
        },
        removeStyleName: function (element, name) {
            var list = this.getStyleList(element), index = list.indexOf(name);
            if (index >= 0) {
                list.splice(index, 1);
                element.setAttribute('class', list.join(' '));
            }
        },
        isSupportedBrowser: function () {
            return 'localStorage' in win &&
                   'querySelector' in doc &&
                   'addEventListener' in win &&
                   'getComputedStyle' in win && doc.compatMode === 'CSS1Compat';
        }
    };

    // Button

    var Button = function Button(element, contentElement) {
        var self = this;

        element.addEventListener('click', function (event) {
            self.onClick(event);
        }, false);

        this._element = element;
        this._contentElement = contentElement || this._element;
    };

    Button.prototype.onClick = function () {};

    Button.prototype.setText = function (text) {
        this._contentElement.textContent = text;
        return this;
    };

    // Select

    var Select = function Select(form, itemName) {
        var self = this;

        form.reset();

        form.addEventListener('click', function (event) {
            var target = event.target;
            if ('value' in target) {
                self.onSelect(target.value);
            }
        }, false);

        form.addEventListener('change', function (event) {
            var target = event.target;
            if (target.checked) {
                self.onChange(target.value);
            }
        }, false);

        this._form = form;
        this._itemName = itemName;
    };

    Select.prototype.onSelect = function () {};

    Select.prototype.onChange = function () {};

    Select.prototype.isHidden = function () {
        return this._form.hasAttribute('hidden');
    };

    Select.prototype.getItems = function () {
        return this._form[this._itemName] || [];
    };

    Select.prototype.getValue = function () {
        var i, n, items = this.getItems();
        for (i = 0, n = items.length; i < n; i++) {
            if (items[i].checked) {
                return items[i].value;
            }
        }
        return '';
    };

    Select.prototype.setValue = function (value) {
        var i, n, items = this.getItems();
        if (value === this.getValue()) {
            return this;
        }
        for (i = 0, n = items.length; i < n; i++) {
            if (items[i].value === value) {
                items[i].checked = true;
                this.onChange(value);
                break;
            }
        }
        return this;
    };

    Select.prototype.setHidden = function (hidden) {
        hidden = !!hidden;
        if (hidden !== this.isHidden()) {
            this._form[(hidden ? 'set' : 'remove') + 'Attribute']('hidden', '');
            this.onHiddenChange(hidden);
        }
        return this;
    };

    Select.prototype.onHiddenChange = function () {};

    // Widget

    var Widget = function Widget(options) {
        var self = this,
            active,
            select = options.select,
            element = options.element,
            storage = options.storage,
            autoMode = options.autoMode,
            pageLang = options.pageLang,
            userLang = options.userLang,
            translator = options.translator,
            leftButton = options.leftButton,
            rightButton = options.rightButton,
            closeButton = options.closeButton,
            defaultLang;

        this._element = element;
        this._pageLang = pageLang;
        this._translator = translator;

        this.onStateChange = function (name, enable) {
            if (name === 'active') {
                storage.setValue('active', enable);
            }
        };

        select.onSelect = function (lang) {
            this.setHidden(true);
            self.translate(lang);
        };

        select.onChange = function (lang) {
            storage.setValue('lang', lang);
            rightButton.setText(lang);
            self.setState('invalid', lang === pageLang);
        };

        select.onHiddenChange = function (hidden) {
            var docElem = doc.documentElement, formRect;
            self.setState('expanded', !hidden);
            if (!hidden) {
                self.setState('right', false)
                    .setState('bottom', false);
                element.focus();
                formRect = this._form.getBoundingClientRect();

                if (formRect.right + (win.pageXOffset || docElem.scrollLeft) + 1 >= Math.max(docElem.clientWidth, docElem.scrollWidth)) {
                    self.setState('right', true);
                }

                if (formRect.bottom + (win.pageYOffset || docElem.scrollTop) + 1 >= Math.max(docElem.clientHeight, docElem.scrollHeight)) {
                    self.setState('bottom', true);
                }
            }
        };

        element.addEventListener('blur', function () {
            select.setHidden(true);
        }, false);

        element.addEventListener('keydown', function (event) {
            switch (event.keyCode) {
                case util.keycode.ESCAPE:
                    select.setHidden(true);
                    break;
            }
        }, false);

        translator.on('error', function () {
            this.abort();
            self.setState('busy', false)
                .setState('error', true);
        });

        translator.on('progress', function (progress) {
            switch (progress) {
                case 0:
                    self.setState('busy', true)
                        .setState('active', true);
                    break;

                case 100:
                    self.setState('done', true)
                        .setState('busy', false);
                    break;
            }
        });

        leftButton.onClick = function () {
            select.setHidden(true);
            self.translate(select.getValue());
        };

        rightButton.onClick = function () {
            if (self.hasState('active')) {
                translator.undo();
                self.setState('busy', false)
                    .setState('done', false)
                    .setState('error', false)
                    .setState('active', false);
            } else {
                select.setHidden(!select.isHidden());
            }
        };

        closeButton.onClick = function () {
            select.setHidden(true);
        };

        defaultLang = storage.getValue('lang') || userLang;

        if (defaultLang) {
            select.setValue(defaultLang);
            active = storage.getValue('active');
            if (active || (autoMode && active === undefined)) {
                this.translate(defaultLang);
            }
        }
    };

    Widget.prototype.hasState = function (name) {
        return util.hasStyleName(this._element, 'yt-state_' + name);
    };

    Widget.prototype.setState = function (name, enable) {
        var hasState = this.hasState(name);
        enable = !!enable;
        if (enable === hasState) {
            return this;
        }
        util[(enable ? 'add' : 'remove') + 'StyleName'](
            this._element, 'yt-state_' + name
        );
        this.onStateChange(name, enable);
        return this;
    };

    Widget.prototype.translate = function (targetLang) {
        if (targetLang && !this.hasState('active')) {
            this._translator.translate(this._pageLang, targetLang);
        }
        return this;
    };

    Widget.prototype.onStateChange = function () {};

    // Storage

    var Storage = function Storage(name) {
        this._name = name;
        try {
            this._data = win.JSON.parse(win.localStorage[name]);
        } catch (error) {
            this._data = {};
        }
    };

    Storage.prototype.getValue = function (prop) {
        return this._data[prop];
    };

    Storage.prototype.setValue = function (prop, value) {
        this._data[prop] = value;
        try {
            win.localStorage[this._name] = win.JSON.stringify(this._data);
        } catch (error) {}
    };

    var wrapper = doc.getElementById(params.widgetId);

    if (!wrapper || !util.isSupportedBrowser()) {
        return;
    }

    var initWidget = function () {
        util.loadScript('https://yastatic.net/s3/translate/v18.9.4/js/tr_page.js', wrapper, function () {
            util.loadResource('https://translate.yandex.net/website-widget/v1/widget.html',
                function (responseText) {
                    var element;

                    if (!responseText) {
                        return;
                    }

                    wrapper.innerHTML = responseText;
                    element = wrapper.querySelector('.yt-widget');
                    if (params.widgetTheme) {
                        element.setAttribute('data-theme', params.widgetTheme);
                    }

                    new Widget({
                        select: new Select(element.querySelector('.yt-listbox'), 'yt-lang'),
                        element: element,
                        storage: new Storage('yt-widget'),
                        autoMode: params.autoMode === 'true',
                        pageLang: params.pageLang,
                        userLang: (nav.language || nav.userLanguage || '').split('-')[0],
                        translator: new namespace.PageTranslator({
                            srv: 'tr-url-widget',
                            sid: '5d424e35.5bba81e5.19361281',
                            url: 'https://translate.yandex.net/api/v1/tr.json/translate',
                            autoSync: true,
                            maxPortionLength: 600
                        }),
                        leftButton: new Button(element.querySelector('.yt-button_type_left')),
                        rightButton: new Button(
                            element.querySelector('.yt-button_type_right'),
                            element.querySelector('.yt-button_type_right > .yt-button__text')
                        ),
                        closeButton: new Button(element.querySelector('.yt-button_type_close'))
                    });
                }
            );
        });
    };

    if (doc.readyState === 'complete' || doc.readyState === 'interactive') {
        initWidget();
    } else {
        doc.addEventListener('DOMContentLoaded', initWidget, false);
    }
})(this, this.document, this.navigator, {"pageLang":"","autoMode":"","widgetTheme":"","widgetId":""}, this.yt = this.yt || {});
/* Размещённый здесь код JavaScript будет загружаться пользователям при обращении к каждой странице */