ผลต่างระหว่างรุ่นของ "ผู้ใช้:Bebiezaza/iScript/helper.js"

จากวิกิพีเดีย สารานุกรมเสรี
เนื้อหาที่ลบ เนื้อหาที่เพิ่ม
Bebiezaza (คุย | ส่วนร่วม)
ย้อน 4 การแก้ไขของ Jon (WMF) (พูดคุย) ไปยังการแก้ไขของ Bebiezaza ด้วยสจห.: easier to just don't support mobile & minerva skin
ป้ายระบุ: ทำกลับ
Bebiezaza (คุย | ส่วนร่วม)
10.268
(ไม่แสดง 5 รุ่นระหว่างกลางโดยผู้ใช้ 2 คน)
บรรทัด 3: บรรทัด 3:
//
//
// Copyright (C) 2006-2022, Jutiphan Mongkolsuthree
// Copyright (C) 2006-2022, Jutiphan Mongkolsuthree
// 2021-2022, Bebiezaza
// 2021-2023, Bebiezaza
// Certain functions are copyrighted by their
// Certain functions are copyrighted by their
// respective copyright holders.
// respective copyright holders.
บรรทัด 99: บรรทัด 99:
if (!limitHeight) limitHeight = false;
if (!limitHeight) limitHeight = false;
// continue to each skin's function
// continue to each skin's function
if (["vector", "vector-2022"].indexOf(mw.config.get('skin')) !== -1) addMenuItem__Vector(menuID, menuTitle, itemTitle, itemID, itemDesc, color, event, limitHeight);
if (mw.config.get('skin') === "vector-2022") addMenuItem__Vector2022(menuID, menuTitle, itemTitle, itemID, itemDesc, color, event, limitHeight);
else if (mw.config.get('skin') === "vector") addMenuItem__Vector(menuID, menuTitle, itemTitle, itemID, itemDesc, color, event, limitHeight);
else addMenuItem__Monobook(menuID, menuTitle, itemTitle, itemID, itemDesc, color, event, limitHeight);
else addMenuItem__Monobook(menuID, menuTitle, itemTitle, itemID, itemDesc, color, event, limitHeight);
}
}
บรรทัด 182: บรรทัด 183:
});
});
return menuBox.lastChild.firstChild.appendChild(dropdownItem);
return menuBox.lastChild.firstChild.appendChild(dropdownItem);
}
function addMenuItem__Vector2022(menuID, menuTitle, itemTitle, itemID, itemTooltip, color, href, limitHeight) {
var menu = document.getElementById(menuID);
if (!menu) { // ofc, make the menu
var dropdownList = createElement('ul', "", {
'class': "vector-menu-content-list"
});
if (limitHeight) dropdownList.classList.add("iScript-vector2022-menu-limit-height");
var dropdown = createElement('div', [dropdownList], {
'class': "vector-menu-content"
})
menu = createElement('div', dropdown, {
'id': menuID,
'class': "vector-menu mw-portlet mw-portlet-" + menuID,
'title': "เครื่องมือของสคริปต์จัดให้"
});
var menuHolder = createElement('div', menu, {
'class': "vector-menu-content vector-dropdown-content",
'style': "padding: 0"
});
var menuHeader = createElement('label', createElement('span', menuTitle, { 'class': "vector-menu-heading-label" }), {
'id': menuID + "-dropdown-label",
'class': "vector-menu-heading",
'for': menuID + "-dropdown-checkbox"
});
var menuCheckbox = createElement('input', "", {
'type': "checkbox",
'id': menuID + "-dropdown-checkbox",
'class': "vector-menu-checkbox",
'role': "button",
'data-event-name': "ui.dropdown-" + menuID + '-dropdown',
'aria-label': menuTitle,
'aria-expanded': "false",
'aria-haspopup': "true"
});
var menuDropdownHandle = createElement('div', [menuCheckbox, menuHeader, menuHolder], {
'id': menuID + "-dropdown",
'class': "vector-menu vector-dropdown vector-menu-dropdown vector-page-tools-dropdown",
});
var menuLandmark = createElement('nav', menuDropdownHandle, {
'aira-label': "เครื่องมือของสคริปต์จัดให้"
});

var rightGroup = document.getElementById("right-navigation");
rightGroup.appendChild(menuLandmark);
}
var itemLink = createElement('a', createElement('span', itemTitle, ""), '');
if (href) itemLink.href = href;
if (itemTooltip) itemLink.title = itemTooltip;

var dropdownColor;
if (color !== "none") dropdownColor = "border-left: 10px solid " + color + ";";

var item = createElement('li', itemLink, {
'id': itemID,
// mw-list-item-js distinguishes portlet links added via javascript and the server
'class': "mw-list-item mw-list-item-js",
'style': dropdownColor
});
menu.lastChild.firstChild.appendChild(item);

return item;
}
}


บรรทัด 221: บรรทัด 284:
if (!insertAfter) insertAfter = "p-lang";
if (!insertAfter) insertAfter = "p-lang";
// continue to each skin's function
// continue to each skin's function
if (["vector", "vector-2022"].indexOf(mw.config.get('skin')) !== -1) makeSidebox__Vector(sidebarTitle, sidebarID, insertAfter);
if (mw.config.get('skin') === "vector-2022") makeSidebox__Vector2022(sidebarTitle, sidebarID, insertAfter);
else if (mw.config.get('skin') === "vector") makeSidebox__Vector(sidebarTitle, sidebarID, insertAfter);
else makeSidebox__Monobook(sidebarTitle, sidebarID, insertAfter);
else makeSidebox__Monobook(sidebarTitle, sidebarID, insertAfter);
}
}
บรรทัด 268: บรรทัด 332:
return sidebarBox.insertBefore(sidebarNav, insertAfterID.nextElementSibling);
return sidebarBox.insertBefore(sidebarNav, insertAfterID.nextElementSibling);
}
}
}
function makeSidebox__Vector2022(title, id, insertAfter) {
var sidebar = document.getElementById("mw-panel");

if (!insertAfter) insertAfter = sidebar.lastElementChild.previousElementSibling.id;
else if (insertAfter === "p-tb") insertAfter = "p-interaction";
var insertAfterElement = document.getElementById(insertAfter).nextElementSibling;
var sideboxHeader = createElement('div', title, { 'class': "vector-menu-heading" });
var sideboxList = createElement('ul', "", { 'class': "vector-menu-content-list" });
var sideboxDiv = createElement('div', sideboxList, {
'class': "vector-menu-content"
});
var sidebox = createElement('div', [sideboxHeader, sideboxDiv], {
'id': id,
'class': "vector-menu mw-portlet mw-portlet-" + id
});
if (insertAfterElement.parentNode.parentNode.parentNode === sidebar) {
sidebar.firstElementChild.firstElementChild.insertBefore(sidebox, insertAfterElement);
} else console.error("Could not create new sidebar navigation group because insertAfter is not a child of #mw-panel");

return sidebox;
}
}


บรรทัด 309: บรรทัด 396:
if (!href) href = "#";
if (!href) href = "#";
// continue to each skin's function
// continue to each skin's function
if (["vector", "vector-2022"].indexOf(mw.config.get('skin')) !== -1) addTab__Vector(href, itemTitle, itemID, itemDesc, nextnodeid);
if (mw.config.get('skin') === "vector-2022") addTab__Vector2022(href, itemTitle, itemID, itemDesc, nextnodeid);
else if (mw.config.get('skin') === "vector") addTab__Vector(href, itemTitle, itemID, itemDesc, nextnodeid);
else addTab__Monobook(href, itemTitle, itemID, itemDesc, nextnodeid, childOf);
else addTab__Monobook(href, itemTitle, itemID, itemDesc, nextnodeid, childOf);
}
}
บรรทัด 350: บรรทัด 438:
return parent.insertBefore(tab, nextnodeid);
return parent.insertBefore(tab, nextnodeid);
}
}
}
function addTab__Vector2022(href, title, id, tooltip, nextnode) {
var itemLink = createElement('a', createElement('span', title, ""), "");
if (href) itemLink.href = href;
if (tooltip) itemLink.title = tooltip;

var item = createElement('li', itemLink, {
// mw-list-item-js distinguishes portlet links added via javascript and the server
'id': id, 'class': "vector-tab-noicon mw-list-item mw-list-item-js"
});

if (!nextnode) {
var parent = document.getElementById("p-cactions").lastElementChild.lastElementChild;
parent.appendChild(item);
} else {
var parent = nextnode.parentNode;
item.classList.add("collapsible");
parent.insertBefore(item, nextnode);
}

return item;
}
}



รุ่นแก้ไขเมื่อ 14:10, 22 มีนาคม 2566

// ==============================================================
// สคริปต์จัดให้: helper module
//
// Copyright (C) 2006-2022, Jutiphan Mongkolsuthree
// 2021-2023, Bebiezaza
// Certain functions are copyrighted by their
// respective copyright holders.
//
// Created: 01/12/2006
// Rewritten: 20/10/2021
// Replaced: 
// ==============================================================
// Available functions => prerequisites of
//
// createElement            => addMenuItem, makeSidebox, addTab
// addMenuItem              => addMenu, addWPMenu
// addMenu                  => <main>(notify.js, notifyFiles.js, speedyAFD.js)
// addWPMenu                => <main>(projectMenu.js)
// makeSidebox              => Sidebox(iScript.js)
// addToolboxLink           => Sidebox(iScript.js)
// addBookmarkLink          => Sidebox(iScript.js)
// addTab                   => editSection0 & lastDiff (mainTabs.js), (admin.js), <main>(editor.js)
// 
// selectUploader           => addAFDRequest(speedyAFD.js), addFileTemplate(notifyFiles.js)
// getBEYear                => addTemplate(notify.js), addFileTemplate(notifyFiles.js)
// dynamicSort              => populateWPMenu(projectMenu.js)
// getSelText               => copyvioCheck & createRedirect(sidebox.js), replacetxt(editor.js)
// userIsInGroup            => <main>(admin.js)
// openInNewWindow          => revert.js
// ==============================================================
// Additional Credits Information:
// ==============================================================
// dynamicSort function
// Source: //stackoverflow.com/questions/1129216/sort-array-of-objects-by-string-property-value
// ==============================================================
/* <pre><nowiki> */

/* --------------- Anatomy --------------- */

/**
 * Better createElement, with the ability to add child element and attributes as you create the element
 * 
 * @param { String } nodename Required. The name of the element you want to create
 * @param { Array } child Child elements you want to put inside this element
 * @param { Object } attributes Styles, Classes, IDs, etc
 * @returns HTML Node
 */
function createElement(nodename, child, attributes) {
    var element = document.createElement(nodename);
    if (!(child instanceof Array)) child = [child];

    for (var i = 0; i < child.length; i++) {
        var childMembers = child[i];
        if (typeof childMembers == 'string') childMembers = document.createTextNode(childMembers);
        if (childMembers) element.appendChild(childMembers);
    }

    if (typeof attributes == 'object') {
        for (var k in attributes) {
            switch (k) {
                case 'class':
                    element.className = attributes[k];
                    break;
                default:
                    element.setAttribute(k, attributes[k]);
            }
        }
    }
    return element;
}

/**
 * Helps add functions to the action menu (top bar)
 * @param { String } menuID Required. ID of the dropdown menu, can be repeated; syntax should be p-<desc>
 * @param { String } menuTitle Required. Title of the dropdown menu, can be repeated
 * @param { String } itemTitle Required. Title of the individual item
 * @param { String } itemID ID of the individual item; default: <item_title>
 * @param { String } itemDesc Description of the individual item
 * @param { String } color Predefined colour codes: notice, growth, style, content, merge, serious, or "default"
 * @param { String } event The behaviour you want to execute; default: "#"
 * @param { boolean } limitHeight True if you want to limit the list to 10 and uses scroll, only applies to the first use of each menu_id; default: false
 * @returns Element in the menu. If declared for the first time, returns the new menu too
 */
function addMenuItem(menuID, menuTitle, itemTitle, itemID, itemDesc, color, event, limitHeight) {
    // colour handler thingy
    switch (color) {
        case 'none': color = 'none'; break; // no color
        case 'notice': color = '#1e90ff'; break; // light blue; default
        case 'growth': color = '#228b22'; break; // green
        case 'style': color = '#f4c430'; break; // yellow
        case 'content': color = '#f28500'; break; // orange
        case 'merge': color = '#9932cc'; break; // purple
        case 'serious': color = '#b22222'; break; // dark red
        default: color = '#1e90ff'; // light blue; default (TODO: no color should be default)
    }
    // helps cleanup any missing var
    if (!event) event = "#";
    if (!itemID) itemID = "p-" + itemTitle;
    if (!limitHeight) limitHeight = false;
    // continue to each skin's function
    if (mw.config.get('skin') === "vector-2022") addMenuItem__Vector2022(menuID, menuTitle, itemTitle, itemID, itemDesc, color, event, limitHeight);
    else if (mw.config.get('skin') === "vector") addMenuItem__Vector(menuID, menuTitle, itemTitle, itemID, itemDesc, color, event, limitHeight);
    else addMenuItem__Monobook(menuID, menuTitle, itemTitle, itemID, itemDesc, color, event, limitHeight);
}
function addMenuItem__Monobook(menuID, menuTitle, itemTitle, itemID, itemDesc, color, event, limitHeight) {
    var menu = document.getElementById(menuID);
    if (menu) var menuBox = menu; // checks if the element has been repeated
    else {
        menuTitle += "▼";
        var dropdownList = createElement('ul', "", {
            'class': "iScript-monobook-menu-content-list"
        });
        if (limitHeight) dropdownList.classList.add("iScript-monobook-menu-dropdown-limit-height");
        var menuBox = createElement('li', [menuTitle, dropdownList], {
            'id': menuID,
            'class': "iScript-monobook-menu-dropdown"
        });
        var navParent = document.getElementById("p-cactions").getElementsByTagName("ul")[0];
        navParent.appendChild(menuBox);
    }
    var itemTitle_span = createElement('span', itemTitle, "");
    var dropdownLink = createElement('a', itemTitle_span, {
        'href': event,
        'title': itemDesc
    });

    var dropdownColor;
    if (color === "none") dropdownColor = "";
    else dropdownColor = "border-left: 10px solid " + color + ";"
    
    var dropdownItem = createElement('li', dropdownLink, {
        'id': itemID,  
        'style': dropdownColor
    });
    return menuBox.lastChild.appendChild(dropdownItem);
}
function addMenuItem__Vector(menuID, menuTitle, itemTitle, itemID, itemDesc, color, event, limitHeight) {
    var menu = document.getElementById(menuID);
    if (menu) var menuBox = menu; // checks if the element has been repeated
    else {
        var dropdownList = createElement('ul', "", {
            'class': "vector-menu-content-list"
        });
        if (limitHeight) dropdownList.classList.add("iScript-vector-menu-dropdown-limit-height");
        var dropdownDiv = createElement('div', dropdownList, {
            'class': "vector-menu-content"
        });
        var menuHeader_span = createElement('span', menuTitle, "");
        var menuHeader = createElement('h3', menuHeader_span, {
            'id': menuID + "-label",
            'class': "vector-menu-heading"
        });
        var menuCheckbox = createElement('input', "", {
            'type': "checkbox",
            'id': menuID + "-checkbox",
            'class': "vector-menu-checkbox",
            'aria-labelledby': menuID + "-label",
            'role': "button",
            'aria-haspopup': "true",
            'data-event-name': "ui.dropdown-" + menuID
        });
        var menuBox = createElement('nav', [menuCheckbox, menuHeader, dropdownDiv], {
            'id': menuID,
            'class': "mw-portlet mw-portlet-cactions vector-menu-dropdown-noicon vector-menu vector-menu-dropdown vector-dropdown",
            'aria-labelledby': menuID + "-label",
            'role': "navigation",
            'title': "From iScript"
        });
        var navParent = document.getElementById("p-cactions").parentNode;
        var searchBox = document.getElementById("p-search");
        if (searchBox.parentNode == navParent) navParent.insertBefore(menuBox, searchBox); // old vector
        else navParent.appendChild(menuBox); // new vector
    }
    var itemTitle_span = createElement('span', itemTitle, "");
    var dropdownLink = createElement('a', itemTitle_span, {
        'href': event,
        'title': itemDesc
    });
    var dropdownItem = createElement('li', dropdownLink, {
        'id': itemID,
        'class': "mw-list-item",
        'style': "border-left: 10px solid " + color + ";"
    });
    return menuBox.lastChild.firstChild.appendChild(dropdownItem);
}
function addMenuItem__Vector2022(menuID, menuTitle, itemTitle, itemID, itemTooltip, color, href, limitHeight) {
    var menu = document.getElementById(menuID);
    if (!menu) { // ofc, make the menu
        var dropdownList = createElement('ul', "", {
            'class': "vector-menu-content-list"
        });
        if (limitHeight) dropdownList.classList.add("iScript-vector2022-menu-limit-height");
        var dropdown = createElement('div', [dropdownList], {
            'class': "vector-menu-content"
        })
        menu = createElement('div', dropdown, {
            'id': menuID,
            'class': "vector-menu mw-portlet mw-portlet-" + menuID,
            'title': "เครื่องมือของสคริปต์จัดให้"
        });
        var menuHolder = createElement('div', menu, {
            'class': "vector-menu-content vector-dropdown-content",
            'style': "padding: 0"
        });
        var menuHeader = createElement('label', createElement('span', menuTitle, { 'class': "vector-menu-heading-label" }), {
            'id': menuID + "-dropdown-label",
            'class': "vector-menu-heading",
            'for': menuID + "-dropdown-checkbox"
        });
        var menuCheckbox = createElement('input', "", {
            'type': "checkbox",
            'id': menuID + "-dropdown-checkbox",
            'class': "vector-menu-checkbox",
            'role': "button",
            'data-event-name': "ui.dropdown-" + menuID + '-dropdown',
            'aria-label': menuTitle,
            'aria-expanded': "false",
            'aria-haspopup': "true"
        });
        var menuDropdownHandle = createElement('div', [menuCheckbox, menuHeader, menuHolder], {
            'id': menuID + "-dropdown",
            'class': "vector-menu vector-dropdown vector-menu-dropdown vector-page-tools-dropdown",
        });
        var menuLandmark = createElement('nav', menuDropdownHandle, {
            'aira-label': "เครื่องมือของสคริปต์จัดให้"
        });

        var rightGroup = document.getElementById("right-navigation");
        rightGroup.appendChild(menuLandmark);
    }
    var itemLink = createElement('a', createElement('span', itemTitle, ""), '');
    if (href) itemLink.href = href;
    if (itemTooltip) itemLink.title = itemTooltip;

    var dropdownColor;
    if (color !== "none") dropdownColor = "border-left: 10px solid " + color + ";";

    var item = createElement('li', itemLink, {
        'id': itemID,
        // mw-list-item-js distinguishes portlet links added via javascript and the server
        'class': "mw-list-item mw-list-item-js",
        'style': dropdownColor
    });
    menu.lastChild.firstChild.appendChild(item);

    return item;
}

/**
 * For adding iScript notify function to the top bar
 * @param { String } itemTitle Required. Title of the individual item
 * @param { String } itemID ID of the individual item; default: <item_title>
 * @param { String } itemDesc Description of the individual item
 * @param { String } color Predefined colour codes: notice, growth, style, content, merge, serious, or "default"
 * @param { String } event The behaviour you want to execute; default: "#"
 * @returns Element in the menu. If declared for the first time, returns the new menu too
 */
function addMenu(itemTitle, itemID, itemDesc, color, event) {
    return addMenuItem("p-iScript-notify", "แจ้ง", itemTitle, itemID, itemDesc, color, event, false);
}

/**
 * For adding iScript add Wikiprojects function to the top bar
 * @param { String } itemTitle Required. Title of the individual item
 * @param { String } itemID ID of the individual item; default: <item_title>
 * @param { String } itemDesc Description of the individual item
 * @param { String } event The behaviour you want to execute; default: "#"
 * @returns Element in the menu. If declared for the first time, returns the new menu too
 */
function addWPMenu(itemTitle, itemID, itemDesc, event) {
    return addMenuItem("p-iScript-wpProjects", "แจ้งอยู่ในโครงการ", itemTitle, itemID, itemDesc, 'notice', event, true);
}

/**
 * Helps create new sidebar group
 * @param { String } sidebarTitle Required. The name you want the header of the section to appear
 * @param { String } sidebarID ID of the sidebar group
 * @param { String } insertAfter ID of the sidebar group you want to place after; default: "p-lang"
 * @returns New sidebar group
 */
function makeSidebox(sidebarTitle, sidebarID, insertAfter) {
    // cleanup missing var
    if (!sidebarID) sidebarID = "p-" + sidebarTitle;
    if (!insertAfter) insertAfter = "p-lang";
    // continue to each skin's function
    if (mw.config.get('skin') === "vector-2022") makeSidebox__Vector2022(sidebarTitle, sidebarID, insertAfter);
    else if (mw.config.get('skin') === "vector") makeSidebox__Vector(sidebarTitle, sidebarID, insertAfter);
    else makeSidebox__Monobook(sidebarTitle, sidebarID, insertAfter);
}
function makeSidebox__Monobook(sidebarTitle, sidebarID, insertAfter) {
    var sidebarBox = document.getElementById("sidebar");
    var insertAfterID = document.getElementById(insertAfter);
    var sidebarHeader = createElement('h3', sidebarTitle, {
        'id': sidebarID + "-label"
    });
    var sidebarList = createElement('ul', "", "");
    var sidebarDiv = createElement('div', sidebarList, {
        'class': "pBody"
    });
    var sidebarNav = createElement('nav', [sidebarHeader, sidebarDiv], {
        'id': sidebarID,
        'class': "portlet mw-portlet mw-portlet-tb",
        'aria-labelledby': sidebarID + "-label",
        'role': "navigation"
    });
    if (insertAfterID.nextElementSibling.parentNode === sidebarBox) {
	    return sidebarBox.insertBefore(sidebarNav, insertAfterID.nextElementSibling);
    }
}
function makeSidebox__Vector(sidebarTitle, sidebarID, insertAfter) {
    var sidebarBox = document.getElementById("mw-panel");
    var insertAfterID = document.getElementById(insertAfter);
    var sidebarTitle_span = createElement('span', sidebarTitle, "");
    var sidebarHeader = createElement('h3', sidebarTitle_span, {
        'id': sidebarID + "-label",
        'aria-label': "",
        class: "vector-menu-heading"
    });
    var sidebarList = createElement('ul', "", {
        'class': "vector-menu-content-list"
    });
    var sidebarDiv = createElement('div', sidebarList, {
        'class': "vector-menu-content body" // body ใช้ใน <1.36 ซึ่งเหลือแค่ uncyclopedia ที่ยังใช้อยู่
    });
    var sidebarNav = createElement('nav', [sidebarHeader, sidebarDiv], {
        'id': sidebarID,
        'class': "mw-portlet mw-portlet-tb vector-menu vector-menu-portal portal",
        'aria-labelledby': sidebarID + "-label",
        'role': "navigation"
    });
    if (insertAfterID.nextElementSibling.parentNode === sidebarBox) {
	    return sidebarBox.insertBefore(sidebarNav, insertAfterID.nextElementSibling);
    }
}
function makeSidebox__Vector2022(title, id, insertAfter) {
    var sidebar = document.getElementById("mw-panel");

    if (!insertAfter) insertAfter = sidebar.lastElementChild.previousElementSibling.id;
    else if (insertAfter === "p-tb") insertAfter = "p-interaction";
    var insertAfterElement = document.getElementById(insertAfter).nextElementSibling;
    
    var sideboxHeader = createElement('div', title, { 'class': "vector-menu-heading" });
    var sideboxList = createElement('ul', "", { 'class': "vector-menu-content-list" });
    var sideboxDiv = createElement('div', sideboxList, {
        'class': "vector-menu-content"
    });
    var sidebox = createElement('div', [sideboxHeader, sideboxDiv], {
        'id': id,
        'class': "vector-menu mw-portlet mw-portlet-" + id
    });
    
    if (insertAfterElement.parentNode.parentNode.parentNode === sidebar) {
        sidebar.firstElementChild.firstElementChild.insertBefore(sidebox, insertAfterElement);
    } else console.error("Could not create new sidebar navigation group because insertAfter is not a child of #mw-panel");

    return sidebox;
}

/**
 * Add links to iScript's toolbox
 * @param { String } href Required. Link URL
 * @param { String } itemText Required. Link text
 * @param { String } itemID Required. ID of the list item, should be unique
 * @param { String } itemDesc Text to show when hovering over the link, without accesskey suffix
 * @returns Element in the iScript toolbox
 */
function addToolboxLink(href, itemText, itemID, itemDesc) {
    return mw.util.addPortletLink("p-iScriptTools", href, itemText, itemID, itemDesc);
}

/**
 * Add bookmarks to iScript's bookmark
 * @param { String } href Required. Link URL
 * @param { String } itemText Required. Link text
 * @param { String } itemID Required. ID of the list item, should be unique
 * @param { String } itemDesc Text to show when hovering over the link, without accesskey suffix
 * @returns Element in the iScript bookmark
 */
function addBookmarkLink(href, itemText, itemID, itemDesc) {
    return mw.util.addPortletLink("p-iBookmarks", href, itemText, itemID, itemDesc);
}

/**
 * Helps add functions to the main action tab (top bar)
 * @param { String } itemTitle Required. The name you want the tab to appear
 * @param { String } itemID Required. ID of the tab, should be unique
 * @param { String } itemDesc Required. Text to show when hovering over the link, without accesskey suffix
 * @param { String } href Required. Link URL
 * @param { Node } nextnodeid HTML Node of the tab you want to place before
 * @param { Boolean } childOf Only applied to monobook skin. True if new tab should be sticked together with parent.
 * @returns Element in the main action tab
 */
function addTab(href, itemTitle, itemID, itemDesc, nextnodeid, childOf) {
    // cleanup missing var
    if (!itemID) itemID = "ca-" + itemTitle;
    if (!href) href = "#";
    // continue to each skin's function
    if (mw.config.get('skin') === "vector-2022") addTab__Vector2022(href, itemTitle, itemID, itemDesc, nextnodeid);
    else if (mw.config.get('skin') === "vector") addTab__Vector(href, itemTitle, itemID, itemDesc, nextnodeid);
    else addTab__Monobook(href, itemTitle, itemID, itemDesc, nextnodeid, childOf);
}
function addTab__Monobook(href, itemTitle, itemID, itemDesc, nextnodeid, childOf) {
    var itemLink = createElement('a', itemTitle, {
        'href': href,
        'title': itemDesc
    });
    var tab = createElement('li', itemLink, {
        'id': itemID,
        'class': "mw-list-item"
    });
    
    if (!nextnodeid || nextnodeid == "") {
        var parent = document.getElementById("ca-watch").parentNode;
        return parent.appendChild(tab);
    } else {
        var parent = nextnodeid.parentNode;
        if (childOf) nextnodeid.previousSibling.classList.add("istalk");
        return parent.insertBefore(tab, nextnodeid);
    }
}
function addTab__Vector(href, itemTitle, itemID, itemDesc, nextnodeid) {
    var itemTitle_span = createElement('span', itemTitle, "");
    var itemLink = createElement('a', itemTitle_span, {
        'href': href,
        'title': itemDesc
    });
    var tab = createElement('li', itemLink, {
        'id': itemID,
        'class': "vector-tab-noicon mw-list-item"
    });

    if (!nextnodeid || nextnodeid == "") {
        var parent = document.getElementById("p-cactions").childNodes[5].childNodes[1];
        return parent.appendChild(tab);
    } else {
        tab.classList.add("collapsible");
        var parent = nextnodeid.parentNode;
        return parent.insertBefore(tab, nextnodeid);
    }
}
function addTab__Vector2022(href, title, id, tooltip, nextnode) {
    var itemLink = createElement('a', createElement('span', title, ""), "");
    if (href) itemLink.href = href;
    if (tooltip) itemLink.title = tooltip;

    var item = createElement('li', itemLink, {
        // mw-list-item-js distinguishes portlet links added via javascript and the server
        'id': id, 'class': "vector-tab-noicon mw-list-item mw-list-item-js"
    });

    if (!nextnode) {
        var parent = document.getElementById("p-cactions").lastElementChild.lastElementChild;
        parent.appendChild(item);
    } else {
        var parent = nextnode.parentNode;
        item.classList.add("collapsible");
        parent.insertBefore(item, nextnode);
    }

    return item;
}

/* --------------- Physiology --------------- */

/**
 * Get file's uploader name you want
 * @param { String } pageName Required. Page name of targeted page 
 * @returns Selected uploader's name as String
 */
function selectUploader(pageName) {
    var uploaders = iScriptAPI.getUploaders(pageName);
    var uploadersNew = [];
    
    var number = 0, uploaderList = "";
    for (var count in uploaders) {
        if (uploaderList.indexOf(uploaders[count]) == -1) {
            if (number > 0) uploaderList += "; ";
            uploaderList += number + " => " + uploaders[count];
            uploadersNew.push(uploaders[count]);
            number++;
        }
    }

    var uploaderNum = parseInt(window.prompt("กรุณาเลือกชื่อผู้ใช้ที่ต้องการจะแจ้ง\n" + uploaderList, ""));
    if (isNaN(uploaderNum) || uploaderNum < 0 || uploaderNum >= uploadersNew.length) {
        alert("ไม่มีชื่อผู้ใช้ที่เลือก หยุดการดำเนินการ");
        return null;
    }

    return uploadersNew[uploaderNum];
}

/**
 * get Bhuddhist Era Year
 * @returns Bhuddhist Era year (Number)
 */
function getBEYear() {
    var jsDate = new Date();
    var year = jsDate.getFullYear() + 543;
    return year;
}

/**
 * Dynamic sort function that sorts objects by their value that you pass; use with Array.sort()
 * @param {*} property property inside object inside array
 * @returns sort order
 */
function dynamicSort(property) {
    var sortOrder = 1;
    if(property[0] === "-") {
        sortOrder = -1;
        property = property.substr(1);
    }
    return function (a,b) {
        /* next line works with strings and numbers, 
         * and you may want to customize it to your needs */
        var result = (a[property] < b[property]) ? -1 : (a[property] > b[property]) ? 1 : 0;
        return result * sortOrder;
    }
}

/**
 * Get selected text
 * @returns Selected text
 */
function getSelText() {
    var a = "";
    if (window.getSelection && window.getSelection().toString() && $(window.getSelection()).attr('type') != "Caret") {
        a = window.getSelection().toString();
        return a
    } else if (document.getSelection && document.getSelection().toString() && $(document.getSelection()).attr('type') != "Caret") {
        a = document.getSelection().toString();
        return a
    } else {
        var b = document.selection && document.selection.createRange();
        if (!(typeof b === "undefined") && b.text && b.text.toString()) {
            a = b.text;
            return a
        }
    }
    if (window.getSelection) {
        selText = window.getSelection()
    } else if (document.getSelection) {
        selText = document.getSelection()
    } else if (document.selection) {
        selText = document.selection.createRange();
        selText = selText.text
    } else {
        return ""
    }
}

/**
 * Check if the user is in a local user group
 * @param { String } userGroup local user group you are trying to find
 * @returns Boolean
 */
function userIsInGroup(userGroup) {
    for (var i = 0; i < mw.config.get('wgUserGroups').length; i++) {
        if (mw.config.get('wgUserGroups')[i] == userGroup) return true;
    }
    return false;
}

/**
 * Opens a new browser window, or a new tab, depending on your browser settings and the parameter values.
 * @param { String } a Specifies the URL of the page to open. If no URL is specified, a new window/tab with about:blank is opened
 * @param { String } b Specifies the target attribute or the name of the window; default = _blank
 */
function openInNewWindow(a, b) {
    if (!b) {
        b = '_blank'
    }
    window.open(a, b);
}

$(document).ready(function() {
    // for test cases
});

/* </nowiki></pre> */