Mister_Z / Wofh: Tactics Exporter

// ==UserScript==
// @name         Wofh: Tactics Exporter
// @namespace    https://ru.waysofhistory.com/
// @version      1.6.1
// @description  Позволяет экспортировать тактику из игры и импортировать её обратно.
// @author       Regis
// @contributor  Mister_Z
// @match        https://*.waysofhistory.com/gen/html/*
// @grant        unsafeWindow
// @license      MIT
// ==/UserScript==

(function() {
    'use strict';

    var $ = unsafeWindow.jQuery;
    if (!$) {
        return;
    }

    if (!unsafeWindow.tabTacticsEdit) {
        // Некорректная страница, либо несовместимая версия
        return;
    }

    var global = unsafeWindow;
    installButtonHook();


    function prepareTacticForSave(tacticToSave) {
        return tacticToSave.extractData(true);
    }

    function getTacticsWindow() {
        var activeWindow = global.wndMgr.getActiveWnd();
        if (activeWindow && activeWindow.name === "tactics") {
            return activeWindow;
        } else {
            return null;
        }
    }

    function pad2(x) {
        var s = "" + x;
        return s.length > 1 ? s : "0" + s;
    }

    function exportTactic() {
        var wnd = getTacticsWindow();
        if (!wnd) {
            alert("No tactics window");
            return;
        }
        var activeTactic = null;
        var allTactics = wnd.data.tacticsData.tactics.list;
        for (var i = 0; i < allTactics.length; i++) {
            var tactic = allTactics[i];
            if (tactic.active) {
                activeTactic = tactic;
                break;
            }
        }

        if (!activeTactic) {
            alert("No active tactics selected");
            return;
        }

        var accountName = wofh.account.name;

        var date = new Date();
        var timeStamp = Math.round(date.getTime() / 1000);

        var formattedDate = date.getFullYear() + pad2(date.getMonth() + 1) + pad2(date.getDate()) + "-" + pad2(date.getHours()) + pad2(date.getMinutes());


        var tacticData = prepareTacticForSave(activeTactic);
        var exportedObject = {
            "name": activeTactic.name + " (" + accountName + "-" + formattedDate + ")",
            "data": tacticData,
            "exportTs": timeStamp
        };
        var serialized = JSON.stringify(exportedObject);
        return serialized;
    }

    function addTactic(wnd, tacticObject) {
        function copyFields(from, to) {
            to.name = from.name;
            to.data = null; // Clear "data" field for the old tactic object

            to.waves = from.waves;
            to.rules = from.rules;
            to.reserve2 = from.reserve2;
        }

        var tactic;
        var data = wnd.data;
        if (data.tactics.list.length === servBuffer.temp.tacticsData.templates.length) {
            tactic = wnd.getNewTactic();
            copyFields(tacticObject, tactic);

            data.tactics.list.push(tactic);

            wnd.cont.find('.view-tactics-editMain-tacticList').append(global.tmplMgr.tactics.tacticName(tactic));
        } else {
            tactic = data.tactics.list[data.tactics.list.length - 1]; // Индекс новой тактики (всегда в конце массива)
            copyFields(tacticObject, tactic);

            if (!data.activeTactic || data.activeTactic.index === tactic.index) {
                wnd.cont.find('.view-tactics-editMain-tacticNameWrp.-active').removeClass('-active');
            }
        }

        var tacticsNameWrapper = wnd.cont.find('.view-tactics-editMain-tacticNameWrp[data-index="' + tactic.index + '"]');
        tacticsNameWrapper.trigger('click');
        tacticsNameWrapper.find('.view-tactics-editMain-tacticName').text(tacticObject.name);
    }

    function restoreSavedTactic(tacticData) {
        delete tacticData.exportTs;
        return new Tactic(tacticData);
    }

    function enableSaveButton(editWindow) {
        editWindow.setCanSaveTactic(true);
    }

    function importTactic(text) {
        var wnd = getTacticsWindow();
        if (!wnd) {
            alert("No tactics window");
            return;
        }
        try {
            var tacticData = JSON.parse(text);
        } catch (e) {
            alert("Некорректный текст тактики: \n" + 'Ошибка ' + e.name + ":" + e.message);
            return;
        }

        var tactic = restoreSavedTactic(tacticData);
        addTactic(wnd.edit, tactic);
        enableSaveButton(wnd.edit);
    }

    function doImport() {
        var code = prompt('Вставьте сохраненную тактику');
        if (code) {
            importTactic(code);
        }
    }

    function doExport() {
        var serialized = exportTactic();
        if (serialized) {
            if (serialized.length < 1000) {
                // Just show alert
                alert(serialized);
            } else {
                // Show text in new window
                var w = window.open("");
                w.document.write(serialized);
            }
        }
    }


    /**
     * Shows import/export buttons.
     */
    function addButtons() {
        var saveTacticsContainer = $('.js-saveTactic').parent();
        if (saveTacticsContainer.length > 0) {
            if (saveTacticsContainer.find('.tactics-addon-export-btn').length === 0) {
                saveTacticsContainer.prepend($('<button class="button1 tactics-addon-import-btn"/>').text("Импорт").on('click', doImport));
                saveTacticsContainer.prepend($('<button class="button1 tactics-addon-export-btn"/>').text("Экспорт").on('click', doExport));
            }
        }
    }

    function installButtonHook() {
        var original_afterShow = tabTacticsEdit.prototype.afterShow;

        tabTacticsEdit.prototype.afterShow = function () {
            original_afterShow.apply(this, arguments);
            addButtons();
        };
        if (global.console) {
            global.console.log('Export Tactics addon installed');
        }
    }
})();