User:L10nM4st3r/wikimenu.js

From Uncyclopedia, the content-free encyclopedia
Jump to navigation Jump to search

Note: After saving, you have to bypass your browser's cache to see the changes.

  • Internet Explorer: hold down the Ctrl key and click the Refresh or Reload button, or press Ctrl+F5.
  • Firefox: hold down the Shift key while clicking Reload; alternatively press Ctrl+F5 or Ctrl-Shift-R.
  • Opera, Konqueror and Safari users can just click the Reload button.
  • Chrome: press Ctrl+F5 or Shift+F5
//<nowiki>
// TODO LIST:
// * Make the buttons like "User Groups", "Page Info" and "Subpages" all show the data in the menus themselves, instead of taking you to the special pages
// * Make the menus resizable
// * Add a settings menu.



/*************************************************************************************************************************
**************************************************************************************************************************
************************************************** The Searchbar *********************************************************
**************************************************************************************************************************
*************************************************************************************************************************/

document.getElementById("p-search-label").remove()
document.getElementById("searchButton").remove()
document.getElementById("content").style = "margin-top:3.7em"
document.getElementById("searchBody").style = "background:none;border:none;position:fixed;top:0em;left:2%;z-index:9999"
//document.getElementById("p-personal").childNodes.forEach(function(n){n.style = "z-index:9998;left:-1.6em;top:3.2em;position:absolute"})
document.getElementById("p-cactions").style = "top:2em;position:absolute"

document.getElementById("pt-watchlist").remove()
document.getElementById("pt-preferences").remove()
document.getElementById("pt-sandbox").remove()
document.getElementById("pt-mycontris").remove()




/*************************************************************************************************************************
**************************************************************************************************************************
****************************************************** SETUP *************************************************************
**************************************************************************************************************************
*************************************************************************************************************************/



var primaryMenuNumber = -1;
const openedMenus = {};
var menuNumber = 0;

var horizontalPosition = "left:35%;";
var searhbarHorizontalPosition = "calc(35% - 2em)";
var verticalPosition = "top:0.5em;";
var menuVerticalPosition = "top:2.5em;";
var minimumMenuWidth = "min-width:15em;";

const version = "Alpha";

document.getElementById("searchBody").style.left = ((screen.availWidth * 0.35) - 185) + "px"


/*************************************************************************************************************************
**************************************************************************************************************************
*********************************************** Handling of menus ********************************************************
**************************************************************************************************************************
*************************************************************************************************************************/

const topMenu = document.createElement("div");
topMenu.style = "position:fixed; z-index:2147483647;" + horizontalPosition + verticalPosition;
document.getElementById("p-personal").appendChild(topMenu);


function createMenu(menuId, prePinned){
    const output = document.createElement("div");
    const header = document.createElement("div");

    header.style = "padding-bottom: 3px;padding-top: 6px; cursor: move";
    output.style = "overflow-x:hidden;overflow-y:auto;background-color:white; border-style: solid; border-width:1px; position:absolute; z-index:2147483646; width:" + ("width" in menus[menuId] ? menus[menuId].width : "10%") + "; min-height:20em;" + horizontalPosition + menuVerticalPosition + minimumMenuWidth;

    output.appendChild(header);
    header.appendChild(document.createTextNode(menus[menuId].title));

    openedMenus[menuNumber] = {menu: output, properties: {}, input: {}, menuId: menuId, id: menuNumber};
    menuNumber ++;

    if (!prePinned) {
        const pinButton = createButton(
            "Pin", "Pin this menu, allowing you to open another menu",
            null, header, "display:inline;position:absolute;right:0;top:0;"
        );
        pinButton.addEventListener('click', function(){
            primaryMenuNumber = -1;
            pinButton.remove();
        })
    }

    topMenu.appendChild(output);
    makeElementDraggable(output, header)

    return menuNumber-1;
}


function openMenu(menuId, inheritFromMenu) {
    let currentMenuPosTop = inheritFromMenu != null ? inheritFromMenu.menu.style.top : "2.5em";
    let currentMenuPosLeft = inheritFromMenu != null ? inheritFromMenu.menu.style.left : "0";
    let inheritedProperties = inheritFromMenu != null ? inheritFromMenu.properties : undefined;

    // If opening another menu, make sure to close the current primary menu.
    if (primaryMenuNumber >= 0 && inheritFromMenu == null)
        closeMenu(primaryMenuNumber);

    // Create the menu
    let newMenuNumber = createMenu(menuId, inheritFromMenu != null ? primaryMenuNumber !== inheritFromMenu.id : false);

    // This will run if it is not inheriting from a menu (opening from the top bar), or is inheriting from the current primary menu
    if (inheritFromMenu == null || primaryMenuNumber === inheritFromMenu.id)
        primaryMenuNumber = newMenuNumber;

    // Get the menu node
    const currentMenu = openedMenus[newMenuNumber].menu;
    if (inheritedProperties !== undefined) {openedMenus[newMenuNumber].properties = inheritedProperties;}

    const keys = Object.keys(menus[menuId].onOpen);
    keys.sort();
    keys.forEach(function(arr){
        menus[menuId].onOpen[arr](openedMenus[newMenuNumber]).forEach(function(data){
            if (data.type === "button") {
                const button = createButton(data.text, data.tooltip, data.onClick, currentMenu);
                if (data.singleUse === true){
                    button.addEventListener('click', function(){button.disabled = true});
                }
                if ("name" in data) {
                    openedMenus[newMenuNumber].input[data.name] = button;
                }
            }
            else if (data.type === "text") {
                const textElement = document.createElement("p");
                textElement.innerHTML = data.text;

                if("tooltip" in data) textElement.setAttribute("title", data.tooltip);
                if("style" in data) textElement.style = data.style;

                currentMenu.appendChild(textElement);
            }

            else if (data.type === "text_input") {
                const input = document.createElement("input");
                input.setAttribute("type", "text");
                if("tooltip" in data) input.setAttribute("title", data.tooltip);

                if ("placeholder" in data) input.placeholder = data.placeholder;
                if ("value" in data && data.value !== undefined) input.value = data.value;
                if ("maxLength" in data) input.maxlength = data.maxLength;
                input.style = "width:97%";

                currentMenu.appendChild(input);
                if ("name" in data) {
                    input.addEventListener("input", function(){
                        openedMenus[newMenuNumber].properties[data.name] = input.value;
                    });
                    openedMenus[newMenuNumber].properties[data.name] = input.value;
                    openedMenus[newMenuNumber].input[data.name] = input;
                }
            }
            else if (data.type === "multiline_text_input") {
                const input = document.createElement("textarea");
                if("tooltip" in data) input.setAttribute("title", data.tooltip);

                if ("placeholder" in data) input.placeholder = data.placeholder;
                if ("value" in data && data.value !== undefined) input.value = data.value;
                input.style = "width:100%;height:" + ("height" in data ? data.height : "5em");

                currentMenu.appendChild(input);
                if ("name" in data) {
                    input.addEventListener("input", function(){
                        openedMenus[newMenuNumber].properties[data.name] = input.value;
                    });
                    openedMenus[newMenuNumber].properties[data.name] = input.value;
                    openedMenus[newMenuNumber].input[data.name] = input;
                }
            }
        })
    });

    ///// Close the menu
    createButton(
          "Close", "Close this menu",
          function(){closeMenu(newMenuNumber)},
          currentMenu,
          "position: absolute; bottom: 0; width:100%"
    );

    // Make sure to delete this data last, otherwise it causes issues
    if (inheritFromMenu != null) closeMenu(inheritFromMenu);

    currentMenu.style.top = currentMenuPosTop;
    currentMenu.style.left = currentMenuPosLeft;
}

function closeMenu(menu) {
    // If a menu ID is passed, turn it into the menu data
    if (typeof menu === "number"){menu = openedMenus[menu]}

    if (menu.id === primaryMenuNumber){primaryMenuNumber = -1;}

    // Delete the menu element
    if (menu) menu.menu.remove();

    // Delete the menu data
    delete openedMenus[menu.id];
}


// Creates a button with correct styling and functionality.
function createButton(text, tooltipText, onClick, addTo, style) {
    const button = document.createElement("input");

    button.setAttribute('title', tooltipText);
    button.setAttribute('type', "button");
    button.value = text;
    button.style = "cursor:pointer;" + (style != undefined ? style : "display:block; width:100%;");

    if (onClick != null) button.addEventListener('click', onClick);

    if (addTo != null) addTo.appendChild(button);
    return button;
}


/*************************************************************************************************************************
**************************************************************************************************************************
************************************************** Draggable Menus *******************************************************
**************************************************************************************************************************
*************************************************************************************************************************/


function makeElementDraggable(elmnt, dragable) {
  var pos1 = 0, pos2 = 0, pos3 = 0, pos4 = 0;
  if (dragable) {
    // if present, the header is where you move the DIV from:
    dragable.onmousedown = dragMouseDown;
  } else {
    // otherwise, move the DIV from anywhere inside the DIV:
    elmnt.onmousedown = dragMouseDown;
  }

  function dragMouseDown(e) {

    elmnt.parentElement.childNodes.forEach(function(e){e.style.zIndex = 2147483046})
    elmnt.style.zIndex = 2147483646

    e = e || window.event;
    e.preventDefault();
    // get the mouse cursor position at startup:
    pos3 = e.clientX;
    pos4 = e.clientY;
    document.onmouseup = closeDragElement;
    // call a function whenever the cursor moves:
    document.onmousemove = elementDrag;
  }

  function elementDrag(e) {
    e = e || window.event;
    e.preventDefault();
    // calculate the new cursor position:
    pos1 = pos3 - e.clientX;
    pos2 = pos4 - e.clientY;
    pos3 = e.clientX;
    pos4 = e.clientY;
    // set the element's new position:
    elmnt.style.top = (elmnt.offsetTop - pos2) + "px";
    elmnt.style.left = (elmnt.offsetLeft - pos1) + "px";
  }

  function closeDragElement() {
    // stop moving when mouse button is released:
    document.onmouseup = null;
    document.onmousemove = null;
  }
}

/*************************************************************************************************************************
**************************************************************************************************************************
*************************************** Handling of modules and data storage *********************************************
**************************************************************************************************************************
*************************************************************************************************************************/

const menuButtonsPriority = {};

// Used to make sure a menu button isn't added twice
const addedMenuButtons = [];


function addToTopMenu(item, text, priority){
    item.setAttribute("indexValue", text)

    let isAdded = false;
    // Check to see if a higher-priority button exists. If it does, add it before.
    topMenu.childNodes.forEach(function(existingButton){
        if (menuButtonsPriority[existingButton.getAttribute("indexValue")] > priority) {
            topMenu.insertBefore(item, existingButton);

            menuButtonsPriority[text] = priority;
            isAdded = true;
        }
    })

    if(!isAdded) {
        // Object was not yet added, meaning it has higher priority than any already added object
        topMenu.appendChild(item);
        menuButtonsPriority[text] = priority;
    }
}



window.WikiMenus = {
    version: version,
    editAd: " (using [[wikibooks:en:User:L10nM4st3r/WikiMenu|WikiMenu Version-"+version+"]])",
    addMenuButton: function(text, tooltip, menuId, priority){
        if (addedMenuButtons.includes(menuId)) return;
        addedMenuButtons.push(menuId)

        var button = createButton(
            text, tooltip,
            function(){
                if (primaryMenuNumber !== -1 && openedMenus[primaryMenuNumber].menuId === menuId){closeMenu(primaryMenuNumber);return}
                openMenu(menuId, primaryMenuNumber !== -1 ? openedMenus[primaryMenuNumber] : null)
            },
            null, "display:inline;"
        );

        addToTopMenu(button, text, priority);
        return button;
    },
    registerPrimaryMenu: function(id, title, width){
        if (id in primaryMenus) {
            let numId = primaryMenus[id];
            if (menus[numId].is_placeholder) {
                delete menus[numId].is_placeholder
                menus[numId].title = title;
                menus[numId].width = width;
            }
            return numId;
        };
        menus.push({title: title, id: menus.length, onOpen: {}, width: width});
        primaryMenus[id] = menus.length - 1;
        return menus.length - 1;
    },
    getPrimaryMenu: function(id){
        if (id in primaryMenus) return primaryMenus[id];

        // If the menu does not exist yet, create a placeholder that can be used by modules, while we wait for the real menu to be registered
        menus.push({id: menus.length, onOpen: {}, is_placeholder: true});
        primaryMenus[id] = menus.length - 1;
        return menus.length - 1;
    },
    registerMenu: function(title, width){
        menus.push({title: title, id: menus.length, onOpen: {}, width: width});
        return menus.length - 1;
    },
    onMenuOpened: function(menuId, onOpenFunct, priority){
        if ((priority !== undefined ? priority : 0) in menus[menuId].onOpen) mw.notify("Error adding menu handle function with priority "+priority+", priority already exists. Maybe someday I'll implement a fix for this...")
        menus[menuId].onOpen[priority !== undefined ? priority : 0] = onOpenFunct;
    },
    openMenu: openMenu,
    closeMenu: closeMenu
};
window.mwAPI = new mw.Api();


var menus = [];
var primaryMenus = {};

/*************************************************************************************************************************
**************************************************************************************************************************
*********************************************** Loading of modules *******************************************************
**************************************************************************************************************************
*************************************************************************************************************************/

var activatedModulePaths = [
    "User:L10nM4st3r/wikimenu/page_utils.js",
    "User:L10nM4st3r/wikimenu/chat_utils.js",
    "User:L10nM4st3r/wikimenu/user_utils.js",
    "User:L10nM4st3r/wikimenu/user_templating.js",
    "User:L10nM4st3r/wikimenu/user_reporting.js",
    "User:L10nM4st3r/wikimenu/remote_editing.js",
    "User:L10nM4st3r/wikimenu/misc_utils.js",
];

const ModulePrefixPath = "https://" + mw.config.get("wgServerName") + "/w/index.php?title={path}&action=raw&ctype=text/javascript"

// Load the module files
activatedModulePaths.forEach(function(modulePath){
    let realModulePath = modulePath;
    if (!modulePath.startsWith("https://"))
        realModulePath = ModulePrefixPath.replace("{path}", modulePath);
    mw.loader.load(realModulePath);
})


//</nowiki>