Create box function

Really useful for making boxes 👍

Version au 28/07/2023. Voir la dernière version.

Vous devrez installer une extension telle que Tampermonkey, Greasemonkey ou Violentmonkey pour installer ce script.

Vous devrez installer une extension telle que Tampermonkey ou Violentmonkey pour installer ce script.

Vous devrez installer une extension telle que Tampermonkey ou Violentmonkey pour installer ce script.

Vous devrez installer une extension telle que Tampermonkey ou Userscripts pour installer ce script.

Vous devrez installer une extension telle que Tampermonkey pour installer ce script.

Vous devrez installer une extension de gestionnaire de script utilisateur pour installer ce script.

(J'ai déjà un gestionnaire de scripts utilisateur, laissez-moi l'installer !)

Vous devrez installer une extension telle que Stylus pour installer ce style.

Vous devrez installer une extension telle que Stylus pour installer ce style.

Vous devrez installer une extension telle que Stylus pour installer ce style.

Vous devrez installer une extension du gestionnaire de style pour utilisateur pour installer ce style.

Vous devrez installer une extension du gestionnaire de style pour utilisateur pour installer ce style.

Vous devrez installer une extension du gestionnaire de style pour utilisateur pour installer ce style.

(J'ai déjà un gestionnaire de style utilisateur, laissez-moi l'installer!)

// ==UserScript==
// @name         Create box function
// @namespace    create_box_owot
// @version      1.3
// @description  Really useful for making boxes 👍
// @author       e_g.
// @match        https://ourworldoftext.com/*
// @icon         https://www.google.com/s2/favicons?sz=64&domain=ourworldoftext.com
// @grant        none
// ==/UserScript==

setupModals = function(){
    //Box creator modal
    function makeBoxCreatorModal() {
        var modal = new Modal();
        modal.createForm();
        modal.createCheckboxField();
        modal.setFormTitle("Let's create a box!\n");
        for(var inputs of ["x", "y", "width", "height", "borderSize"]){
            window[inputs] = modal.addEntry(inputs, "text", "number").input;
        };
        for(var inputs of ["mainColor", "borderColor", "textColor", "textBgColor"]){
            window[inputs] = modal.addEntry(inputs, "color").input;
        };
        for(var inputs of ["title", "description", "footer"]){
            window[inputs] = modal.addEntry(inputs, "text", "string").input;
        };
        for(var inputs of ["titleAlign", "descAlign", "footerAlign"]){ //thanks poopman
            window[inputs+"Options"] = [
                { label: "Left", value: "left"},
                { label: "Center", value: "center", default: (inputs == "footerAlign" ? false : true) },
                { label: "Right", value: "right", default: (inputs == "footerAlign" ? true : false)},
            ];
            window[inputs] = (inputs == "footerAlign" ? "right" : "center");
            createRadioButtons(modal, inputs, window[inputs+"Options"]);
        }; //poopman's part stops here
        modal.setMaximumSize(500, 600);
        for(var inputs of ["footer2space", "borderCollision", "fullActions"]){
            window[inputs] = modal.addCheckbox(inputs)
            window[inputs].cbElm.title = {
                footer2space: "2 horizontal spaces instead of 1. Doesn't apply when using centered footer.",
                borderCollision: "Makes the text stick to the border instead of having a spacement.",
                fullActions: "Makes you able to make bigger borders or make boxes bigger than 512 characters."
            }[inputs];
        };
        modal.onSubmit(function(){
            createBox({
                x: +x.value,
                y: +y.value,
                width: +width.value,
                height: +height.value,
                borderSize: +borderSize.value,
                mainColor: parseInt(mainColor.value, 16),
                borderColor: parseInt(borderColor.value, 16),
                textColor: parseInt(textColor.value, 16),
                textBgColor: parseInt(textBgColor.value, 16),
                title: title.value,
                description: description.value,
                footer: footer.value,
                titleAlign: document.querySelector('input[name="titleAlign"]:checked').value, //thanks poopman
                descAlign: document.querySelector('input[name="descAlign"]:checked').value,
                footerAlign: document.querySelector('input[name="footerAlign"]:checked').value, //poopman's part stops here
                footer2space: footer2space.cbElm.checked,
                borderCollision: borderCollision.cbElm.checked,
                fullActions: fullActions.cbElm.checked
            });
        });
        modal.client.firstChild.append(...modal.client.children[1].children);
        modal.client.firstChild.insertBefore(modal.client.firstChild.children[2], modal.client.firstChild.lastChild.nextSibling);
        w.ui.boxCreatorModal = modal;
    };
    makeBoxCreatorModal();
    function createRadioButtons(modal, name, options) { //thanks poopman
        const radioDiv = document.createElement("div");
        radioDiv.style.display = "flex";
        const radioText = document.createElement("label");
        radioText.innerHTML = name + ":";
        radioDiv.appendChild(radioText);
        for (const option of options) {
            const label = document.createElement("label");
            label.style.marginRight = "10px";
            const input = document.createElement("input");
            input.type = "radio";
            input.name = name;
            input.value = option.value;
            if (option.default) {
                input.checked = true;
            }
            label.appendChild(input);
            label.appendChild(document.createTextNode(option.label));
            radioDiv.appendChild(label);
        }
        modal.formField.appendChild(radioDiv);
    } //poopman's part stops here
    //Create menu option
    menu.addOption("Create box", function(){
        var region = RegionSelection();
        region.init();
        region.startSelection();
        region.onselection(function(xy, _, width, height){
            var options = w.ui.boxCreatorModal.client.firstChild.children[1];
            options.children[1].value = xy[0] * 16 + xy[2];
            options.children[3].value = xy[1] * 8 + xy[3];
            options.children[5].value = width;
            options.children[7].value = height;
            w.ui.boxCreatorModal.open();
        });
    });
}
setupModals();

createBox = function(box){
    // Errors and warnings
    if(box.x === undefined) return console.error("X position isn't specified.");
    if(box.y === undefined) return console.error("Y position isn't specified.");
    if(box.width * box.height > 512 && !box.fullActions) return console.error("To make boxes bigger than 512 characters, add the arg fullActions and set it as true.");
    if(box.title.length > box.width - box.borderSize * 4 - !box.borderCollision * 2) return console.error("Title too big" + (box.title.length <= box.width - box.borderSize * 4 ? ", set borderCollision to true so you can use that title." : ""));
    if(box.footer && box.footer.length > box.width - box.borderSize * 4 - !box.borderCollision * 2 + box.footer2space) return console.error("Footer too big");
    if(box.borderSize * 4 >= box.width / 1.5 && !box.fullActions) return console.error("Box's main content is too small. Proceed by adding the arg fullActions to the args and setting it to true.");
    box.size = box.width * box.height + ((box.width - box.borderSize * 4) * (box.height - box.borderSize * 2)) * !!box.borderSize + box.title.length + box.description.length + (box.footer ? box.footer.length : 0);
    if(state.worldModel.char_rate.reduce((x, y) => x * y / 1e3) * 24 < box.size) return console.error("Your rate limit is too low to draw the box");
    if(state.worldModel.char_rate.reduce((x, y) => x * y / 1e3) * 2 < box.size) console.warn("The box might be messed up because your rate limit is too low for the box's size.");
    if(box.x % 1){
        box.x = Math.floor(box.x);
        console.warn(`The x value is a decimal value. It will be rounded to ${box.x}.`);
    };
    if(box.y % 1){
        box.y = Math.floor(box.y);
        console.warn(`The y value is a decimal value. It will be rounded to ${box.y}.`);
    };
    if(box.width % 1){
        box.width = Math.floor(box.width);
        console.warn(`The width size is a decimal value. It will be rounded to ${box.width}.`);
    };
    if(box.height % 1){
        box.height = Math.floor(box.height);
        console.warn(`The height size is a decimal value. It will be rounded to ${box.height}.`);
    };
    if(box.borderSize % 1){
        box.borderSize = Math.round(box.borderSize);
        console.warn(`The border size is a decimal value. It will be rounded to ${box.borderSize}.`);
    };
    if(box.borderSize * 4 >= box.width / 2) console.warn("Consider reducing border's size to add space for the main content!");
    if(box.footer2space && box.borderCollision) console.warn("Both footer2space and borderCollision are activated, this may cause conflict for the box.");
    // Avoid glitching when a word is too big for the box
    if(!box.description.endsWith(" ") && box.description.split(" ").at(-1).length > box.width - box.borderSize * 4 - 2) box.description += " ";
    // Rest of description's separating setup + see if it's too big for the box
    if(box.description.length > box.width - box.borderSize * 4 - !box.borderCollision * 2 && box.description.split(" ").length > 1){
        box.formattedDesc = [...box.description.match(RegExp(`.{0,${box.width - box.borderSize * 4 - !box.borderCollision * 2}} |.{${box.width - box.borderSize * 4 - !box.borderCollision * 2}}`, "g")), box.description.split(" ").at(-1)];
        if(box.formattedDesc.slice(-2).join("").length <= box.width - box.borderSize * 4 - !box.borderCollision * 2) box.formattedDesc = [...box.formattedDesc.slice(0, box.formattedDesc.length - 2), box.formattedDesc.slice(-2).join("")];
        box.formattedDesc = box.formattedDesc.map(x => x.replace(/ +$/, ""));
    }
    else box.formattedDesc = box.description.match(RegExp(`.{0,${box.width - box.borderSize * 4 - !box.borderCollision * 2}}`, "g"));
    box.formattedDesc = box.formattedDesc.filter(x => x != "");
    if(box.formattedDesc.length == 1 && box.formattedDesc[0] == "") box.formattedDesc = [];
    if(box.formattedDesc.length > box.height - box.borderSize * 2 - 2 - !box.borderCollision * 2 - !!box.footer * 2) return console.error("Description too long for the size of this box. Try setting borderCollision to true, or if that doesn't work, set a bigger size for the box or shorten the description.");
    //Make the box and box's border (reversed order)
    if(box.borderSize) filltoxy(box.x, box.y, box.width, box.height, "█", box.borderColor);
    filltoxy(box.x + box.borderSize * 2, box.y + box.borderSize, box.width - box.borderSize * 4, box.height - box.borderSize * 2, "█", box.mainColor);
    //Alignment formula of title and draw it
    if(!box.titleAlign) box.titleAlign = "center";
    if(box.titleAlign == "center"){
        box.titleFormula = Math.ceil(box.x + box.width / 2 - box.title.length / 2);
    }
    else if(box.titleAlign == "left"){
        box.titleFormula = Math.ceil(box.x + box.borderSize * 2 + !box.borderCollision);
    }
    else if(box.titleAlign == "right"){
        box.titleFormula = Math.ceil(box.x + (box.width - box.borderSize * 2 - !box.borderCollision - box.title.length));
    }
    else{
        console.warn("titleAlign had an invalid align, and was automatically assigned to center (the valid ones are: center, left, right)");
        box.titleAlign = "center";
        box.titleFormula = Math.ceil(box.x + box.width / 2 - box.title.length / 2);
    };
    texttoxy(box.titleFormula, box.y + box.borderSize + !box.borderCollision, box.title, box.textColor, box.textBgColor);
    //Alignment formula of description and draw it
    if(!box.descAlign) box.descAlign = "center";
    if(box.descAlign == "center"){
        box.descFormula = function(formattedDesc, descIndex){
            return Math.ceil(box.x + box.width / 2 - formattedDesc[descIndex - box.borderSize - 3].length / 2);
        };
    }
    else if(box.descAlign == "left"){
        box.descFormula = function(){
            return Math.ceil(box.x + box.borderSize * 2 + !box.borderCollision);
        };
    }
    else if(box.descAlign == "right"){
        box.descFormula = function(formattedDesc, descIndex){
            return Math.ceil(box.x + (box.width - box.borderSize * 2 - !box.borderCollision - formattedDesc[descIndex - box.borderSize - 3].length));
        };
    }
    else{
        console.warn("descAlign had an invalid align, and was automatically assigned to center (the valid ones are: center, left, right)");
        box.descAlign = "center";
        box.descFormula = function(formattedDesc, descIndex){
            return Math.ceil(box.x + box.width / 2 - formattedDesc[descIndex - box.borderSize - 3].length / 2);
        };
    };
    for(box.descIndex = box.borderSize + 3; box.descIndex < box.formattedDesc.length + box.borderSize + 3; box.descIndex++){
        texttoxy(box.descFormula(box.formattedDesc, box.descIndex), box.y + box.descIndex - !!box.borderCollision, box.formattedDesc[box.descIndex - box.borderSize - 3], box.textColor, box.textBgColor);
    };
    //Alignment formula of footer and draw it IF there's any
    if(!box.footer) return;
    if(!box.footerAlign) box.footerAlign = "right";
    if(box.footerAlign == "center"){
        box.footerFormula = Math.ceil(box.x + box.width / 2 - box.footer.length / 2);
    }
    else if(box.footerAlign == "left"){
        box.footerFormula = Math.ceil(box.x + box.borderSize * 2 + !box.borderCollision + !!box.footer2space);
    }
    else if(box.footerAlign == "right"){
        box.footerFormula = Math.ceil(box.x + (box.width - box.borderSize * 2 - !box.borderCollision - !!box.footer2space - box.footer.length));
    }
    else{
        console.warn("footerAlign had an invalid align, and was automatically assigned to right (the valid ones are: center, left, right)");
        box.footerAlign = "right";
        box.footerFormula = Math.ceil(box.x + (box.width - box.borderSize * 2 - !box.borderCollision - !!box.footer2space - box.footer.length));
    };
    texttoxy(box.footerFormula, box.y + box.height - box.borderSize - 1 - !box.borderCollision, box.footer, box.textColor, box.textBgColor);
}