MediaWiki:FloatingToc/code.js
Jump to navigation
Jump to search
Note: After publishing, you may have to bypass your browser's cache to see the changes.
- Firefox / Safari: Hold Shift while clicking Reload, or press either Ctrl-F5 or Ctrl-R (⌘-R on a Mac)
- Google Chrome: Press Ctrl-Shift-R (⌘-Shift-R on a Mac)
- Internet Explorer / Edge: Hold Ctrl while clicking Refresh, or press Ctrl-F5
- Opera: Press Ctrl-F5.
/** * @name FloatingToc * @author Pecoes, KhangND * @desc Makes the Table of Contents floatable * @doc https://dev.fandom.com/wiki/FloatingToc * @files used: * [[File:Ui-icons_ffffff_256x240.png]] * [[File:Ui-icons_222222_256x240.png]] */ (function (mw, $, window) { if (mw.config.get('skin') === 'fandomdesktop') return; var root = $("#toc"); if (window.FloatingTocLoaded || !root.length) return; window.FloatingTocLoaded = true; function importArticle(page) { const isScript = page.split(".").pop() === "js"; return $.ajax({ url: mw.config.get("wgLoadScript"), data: { mode: "articles", only: isScript ? "scripts" : "styles", articles: "u:dev:MediaWiki:" + page, }, }).then(function (content) { $("head").append($(isScript ? "<script>" : "<style>").html(content)); }); } var css = importArticle("FloatingToc.css"); var colors = (window.dev || {}).colors ? $.Deferred().resolve() : importArticle("Colors/code.js"); var i18n = ((window.dev || {}).i18n || {}).loadMessages ? $.Deferred().resolve() : importArticle("I18n-js/code.js"); var jQueryUI = mw.loader.using([ "jquery.ui.dialog", "jquery.ui.draggable", "jquery.ui.resizable", "jquery.effects.slide", ]); $.when(i18n, css, colors, jQueryUI) .then(function () { return window.dev.i18n.loadMessages("FloatingToc"); }) .then(function (_i18n) { var colors = window.dev.colors; var pageBright = colors.parse(colors.wikia.page).isBright(); var menuBright = colors.parse(colors.wikia.menu).isBright(); var iconLight = 'url("https://images.wikia.nocookie.net/dev/images/c/c2/Ui-icons_ffffff_256x240.png")'; var iconDark = 'url("https://images.wikia.nocookie.net/dev/images/a/aa/Ui-icons_222222_256x240.png")'; var styles = ".toc-dialog{\ border: 2px solid $border;\ }\ .toc-dialog .ui-dialog-titlebar {\ background: $menu;\ border: 1px solid $menu;\ color: $contrast;\ }\ .toc-dialog.ui-widget-content .ui-icon {\ background-image: $menu-icons;\ }\ .toc-dialog.ui-widget-content a {\ color: $link;\ }\ .toc-dialog,\ .toc-dialog .toc {\ background-color: $page;\ color: $text;\ }\ #toc-open {\ border: 1px solid $page-border-gray;\ background-image: $page-icons;\ }\ .toc-btn, .toc-btn:hover {\ background-image: $menu-icons;\ }\ .toc-btn:hover {\ background-color: $gradient;\ }"; mw.util.addCSS( colors.replace(styles, { "page-border-gray": colors.wikia.border, "menu-icons": menuBright ? iconDark : iconLight, "page-icons": pageBright ? iconDark : iconLight, }) ); var win = $(window), page = $("#WikiaPage"), rail = $("#WikiaRail"), navHeight = $("#globalNavigation").height(), barHeight = $("#WikiaBarWrapper").height(), speed = 250, i18n = _i18n.msg, options = $.extend( { auto: false, enableKey: true, }, window.FloatingToc ); // root ToC components var rootToc = { top: root.offset().top, width: root.outerWidth(), height: root.outerHeight(), }; // creates a clone of the root ToC // and transforms it to jQuery UI Dialog var toc = { resizing: false, padWrap: 0, wrapper: $(), clone: $("<nav>", { class: "toc show", id: "tocDialog", title: i18n("contents").plain(), css: { display: "none" }, appendTo: page, }), state: function () { var w = rootToc.width; var h = Math.min( rootToc.height, win.height() - navHeight - barHeight ); return { position: [(win.width() - w) / 2, navHeight], width: w, height: h, maxWidth: win.height() * (w / h), maxHeight: win.height() - navHeight - barHeight, }; }, toggle: function (action) { var links = $(".toc-link"); if (links.css("display") === "none") links.show(speed); else links.hide(speed); if (root.css("display") === "none") root.slideDown(speed, toc.keepPos(action)); else root.slideUp(speed, toc.keepPos(action)); }, keepPos: function (action) { var winPos = win.scrollTop(); if (action === "open" && winPos > rootToc.top + rootToc.height) { win.scrollTop(winPos - rootToc.height); } if (action === "close") { if (!options.enableKey) { win.scrollTop(rootToc.top - navHeight); return; } if (winPos > rootToc.top) win.scrollTop(winPos + rootToc.height); } }, fixPos: function () { if (toc.wrapper.css("position") === "fixed") return; toc.wrapper.css({ top: toc.wrapper.offset().top - win.scrollTop(), left: toc.wrapper.offset().left - win.scrollLeft(), position: "fixed", }); }, reset: function () { toc.clone.dialog("option", toc.state()); }, dock: function () { toc.clone.dialog("option", { width: rail.width() + parseInt(page.css("padding-right")) - toc.padWrap, position: [rail.offset().left, navHeight], }); }, back: function () { win.scrollTop(0); }, open: function () { toc.clone.dialog("open"); }, close: function () { toc.clone.dialog("close"); }, button: function (action) { return $("<button>", { class: "toc-btn", id: "toc-" + action, title: i18n(action).plain(), click: toc[action], }); }, onOpen: function () { toc.reset(); toc.fixPos(); toc.toggle("open"); }, onClose: function () { toc.toggle("close"); }, onCreate: function () { // sets properties toc.wrapper = $(this).parent(); toc.padWrap = (parseInt(toc.wrapper.css("border-width")) + parseInt(toc.wrapper.css("padding"))) * 2; // modifies components toc.toggle(); toc.wrapper.find(".ui-dialog-titlebar-close").remove(); $("<div>", { id: "toc-btns", appendTo: toc.wrapper.find(".ui-dialog-titlebar"), append: [ toc.button("back"), toc.button("dock"), toc.button("reset"), toc.button("close"), ], }); toc.wrapper.draggable({ scroll: false, containment: "window", }); }, init: function () { var selector = root.find("ol")[0] ? "ol" : "ul"; toc.clone.append(root.find(selector + ":first")[0].outerHTML); toc.clone.dialog( $.extend( { dialogClass: "toc-dialog", show: { effect: "slideDown", duration: speed }, hide: { effect: "slideUp", duration: speed }, create: toc.onCreate, open: toc.onOpen, close: toc.onClose, resizeStart: function () { toc.resizing = true; }, resizeStop: function () { toc.resizing = false; toc.fixPos(); }, }, toc.state() ) ); win.on("resize", function () { if (!toc.resizing && toc.clone.dialog("isOpen")) toc.reset(); }); // overrides click $(this).on("click", function () { if (toc.clone.dialog("isOpen")) toc.close(); else toc.open(); }); }, }; // adds ToC links to h2, h3 $("#mw-content-text") .find("h2,h3") .find(".mw-headline") .after( $("<a>", { class: "toc-link", href: "", title: i18n("toc").plain(), click: function () { win.scrollTop(rootToc.top - navHeight); return false; }, }) ); var tocButton = $("<button>", { id: "toc-open", title: i18n("open").plain(), appendTo: root.find("div:first"), }).one("click", toc.init); if (options.auto) tocButton.trigger("click"); if (options.enableKey) { $(document).on("keyup", function (e) { var elem = document.activeElement; if ( $("body").hasClass("ve") || $("html").hasClass("ve-active") || elem.tagName === "INPUT" || elem.tagName === "TEXTAREA" || elem.hasAttribute("contenteditable") ) return; if (e.key === "t") tocButton.trigger("click"); }); } }); })(mw, $, window);