Regis / Wofh: Tactics Exporter

// ==UserScript==
// @name         Wofh: Tactics Exporter
// @namespace    https://ru.waysofhistory.com/
// @version      1.8
// @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 saveTextAsFile(textToWrite, fileName) {
        var textFileAsBlob = new Blob([textToWrite], {type: 'text/plain'});

        var downloadLink = document.createElement("a");
        downloadLink.download = fileName;
        downloadLink.innerHTML = "Download File";
        if (window.webkitURL != null) {
            // Chrome allows the link to be clicked
            // without actually adding it to the DOM.
            downloadLink.href = window.webkitURL.createObjectURL(textFileAsBlob);
        }
        else {
            // Firefox requires the link to be added to the DOM
            // before it can be clicked.
            downloadLink.href = window.URL.createObjectURL(textFileAsBlob);
            downloadLink.onclick = function destroyClickedElement(event) {
                document.body.removeChild(event.target);
            };
            downloadLink.style.display = "none";
            document.body.appendChild(downloadLink);
        }

        downloadLink.click();
    }


    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 exportTacticJson() {
        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
        };
        return exportedObject;
    }

    function exportTactic() {
        var data = exportTacticJson();
        if (data) {
            var serialized = JSON.stringify(data);
            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 data = wnd.data;
        var tactic = data.tactics.getLastElem(); // Индекс новой тактики (всегда в конце массива)
        // Проверяем есть ли уже созданная "новая тактика"
        if( !tactic || tactic.getId() ){
            tactic = wnd.getNewTactic();
            copyFields(tacticObject, tactic);
            data.tactics.addElem(tactic);

            wnd.cont.find('.view-tactics-editMain-tacticList').append(global.tmplMgr.tactics.tacticName({tactic:tactic}));
        }
        else{
            copyFields(tacticObject, tactic);

            // Если новая тактика ранее была активной, сбрасываем активность (чтобы избежать редактирования имени). Также устанавливаем имя заново, т.к. оно могло быть изменено ранее
            if( !data.activeTactic || wnd.data.activeTactic.getIndex() === tactic.getIndex() )
                wnd.cont.find('.view-tactics-editMain-tacticNameWrp.-active').removeClass('-active');
        }

        /*

        var tactic;
        var data = wnd.data;
        if (data.tactics.list.length === servBuffer.temp.tacticsData.tactics.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);
            }
        }
    }

    function doExportToFile() {
        var data = exportTacticJson();

        if (data) {
            var serialized = JSON.stringify(data);
            saveTextAsFile(serialized, data.name + ".tactics.json");
        }
    }


    /**
     * 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));
                saveTacticsContainer.prepend($('<button class="button1 tactics-addon-export-to-file-btn"/>').text("Экспорт в файл").on('click', doExportToFile));
            }
        }
    }

    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');
        }
    }
})();