User:L10nM4st3r/wikimenu.js
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>