MediaWiki:LoadPage.js

From ARK Wiki
Jump to navigation Jump to search

In other languages: DeutschEspañolFrançaisItaliano日本語PolskiPortuguês do BrasilРусскийไทย


Note: After saving, 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: Hold Ctrl while clicking Refresh, or press Ctrl-F5
  • Opera: Go to Menu → Settings (Opera → Preferences on a Mac) and then to Privacy & security → Clear browsing data → Cached images and files.
/**
 * Page loader
 *
 * Allows a page to be downloaded and displayed on demand.
 * Use with [[Template:LoadPage]]
 */
mw.hook('wikipage.content').add(function($wikipageContent) {
    var I18n = arkCreateI18nInterface('LoadPage', {
    	en: {
	        hideText: 'hide',
    	    showText: 'show',
        	loadErrorTitle: 'An error occurred loading the content'
    	}
    });

    // #region Collapsible elements
    /* Add the "collapsible" class to an element and the child element with class "collapsible-content"
     * (or everything but the header row if a table) will be hidden when the element is collapsed.
     *
     * * Add the class "collapsed" to the element to make it start out collapsed.
     * * Add either "collapsetoggle-left" or "collapsetoggle-inline" to the element to choose the collapse
     *   toggle alignment (defaults to right).
     * * Add an ID in the format of "collapsible-<x>" to the element to make any element with the class
     *  "collapsetoggle-custom" and a matching class in the format of "collapsible-<x>-toggle" control
     *   the collapsing instead of the standard button.
     *   If the custom toggle contains an element with the "jslink" class, only that will be clickable.
     */
    (function() {
        var $collapsibles = $wikipageContent.find('.collapsible');
        if (!$collapsibles.length) {
            return;
        }
        
        var $toggleTemplate = $('<span>').addClass('collapsetoggle').append(
            '[', $('<span>').addClass('jslink'), ']'
        );
        $collapsibles.each(function() {
            var $collapsible = $(this);
            if ($collapsible.data('made-collapsible')) {
                return true;
            }
            
            var $children = $collapsible.children();
            var showText = $collapsible.data('expandtext') || I18n('showText');
            var hideText = $collapsible.data('collapsetext') || I18n('hideText');
            
            // If there is no content area, add it
            if (!$collapsible.is('table') && !$children.filter('.collapsible-content').length) {
                if ($collapsible.is('tr')) {
                    $children.addClass('collapsible-content');
                } else {
                    $collapsible.wrapInner('<div class="collapsible-content">');
                    $children = $collapsible.children();
                }
            }
            
            var $toggle;
            var id = $collapsible.attr('id');
            if (id && id.match(/^collapsible-./)) {
                $toggle = $($wikipageContent[0].getElementsByClassName(id + '-toggle'))
                    .filter('.collapsetoggle-custom').css('visibility', 'visible');
            }
            
            // Create and insert the toggle button if there is no custom one
            if (!$toggle || !$toggle.length) {
                var $toggleContainer;
                if ($collapsible.is('table')) {
                    var $rows = $children.filter('thead').children();
                    if (!$rows.length) {
                        $rows = $children.filter('tbody').first().children();
                        if (!$rows.length) {
                            $rows = $children.filter('tr');
                        }
                    }
                    $toggleContainer = $rows.first().children().last();
                } else {
                    $toggleContainer = $children.first();
                    if ($toggleContainer.hasClass('collapsible-content')) {
                        $toggleContainer = $collapsible;
                    }
                }
                
                $toggle = $toggleTemplate.clone();
                if ($toggleContainer !== $collapsible
                    && ($collapsible.hasClass('collapsetoggle-inline') || $collapsible.hasClass('collapse-button-none'))) {
                    $toggleContainer.append($toggle);
                } else {
                    $toggleContainer.prepend($toggle);
                }
            }
            
            var $toggleLink = $toggle.find('.jslink');
            if (!$toggleLink.length) {
                $toggleLink = $toggle;
            }
            $toggleLink.attr('tabindex', 0).text(hideText);
            
            // Find max toggle size, and set its min-width to it
            var hideWidth = $toggle.width();
            $toggleLink.text(showText);
            var showWidth = $toggle.width();
            if (hideWidth !== showWidth) {
                $toggle.css('min-width', hideWidth > showWidth ? hideWidth : showWidth);
            }
            
            // Set the text back to hide if it's not collapsed to begin with
            if (!$collapsible.hasClass('collapsed')) {
                $toggleLink.text(hideText);
            }
            
            $toggleLink.on('click keydown', function(e) {
                // Only trigger on enter press
                if (e.keyCode && e.keyCode !== 13) {
                    return;
                }
                
                // Don't toggle when clicking buttons or links inside the toggle
                var $target = $(e.target);
                if ($target.is('button') || $target.is('a')) {
                    return;
                }
                
                $collapsible.toggleClass('collapsed');
                if ($collapsible.hasClass('collapsed')) {
                    $toggleLink.text(showText);
                } else {
                    $toggleLink.text(hideText);
                }
                
                // Stop table sorting activating when clicking the link
                e.stopPropagation();
            });
            
            $collapsible.data('made-collapsible', true);
        });
    }());
    // #endregion

    // #region Page loader
    (function() {
        var $loadPage = $wikipageContent.find('.load-page');
        if (!$loadPage.length) {
            return;
        }

        // We need the spinner to show loading is happening, but we don't want
        // to have a delay while the module downloads, so we'll load this now,
        // regardless of if something is clicked
        mw.loader.load('jquery.spinner');

        // Create button starting with hide text
        // Will be changed to the show text while calculating the maximum button size
        var $buttonTemplate = $('<span>').addClass('mw-editsection-like load-page-button')
            .append('[', $('<span>').addClass('jslink').text(I18n('hideText')), ']');

        var extractList = function($contentContainer, listClass) {
            var $content = $contentContainer.find('.mw-parser-output > ul > li > ul').children(':not(.nbttree-inherited)');
            if (listClass) {
                $content.addClass(listClass);
            }

            return $content;
        };

        $loadPage.each(function() {
            var $body = $(this);
            var page = $body.data('page');
            if (!page) {
                return;
            }

            var template = $body.data('template');
            var treeview = $body.data('treeview');
            var treeviewClass = $body.data('treeviewclass');
            var $heading;
            var $contentContainer;
            var $content;
            var $button = $buttonTemplate.clone();
            var $buttonLink = $button.find('.jslink');
            if (treeview) {
                $heading = $body;
                $contentContainer = $('<div>');
            } else {
                $heading = $body.children().first();
                $contentContainer = $body.find('.load-page-content');
            }

            // Add the button
            $heading.append($button);

            // Move the edit button to the right spot
            $contentContainer.find('.mw-editsection, .mw-editsection-like').insertAfter($button);

            // Find max button width, and set its min-width to it
            var hideWidth = $button.width();
            $buttonLink.text(I18n('showText'));
            var showWidth = $button.width();

            if (hideWidth !== showWidth) {
                $button.css('min-width', hideWidth > showWidth ? hideWidth : showWidth);
            }

            $buttonLink.click(function() {
                if ($body.hasClass('pageloader-contentloaded')) {
                    if ($buttonLink.text() === I18n('showText')) {
                        if (treeview) {
                            $content.insertAfter($body);
                        } else {
                            $contentContainer.show();
                        }
                        $buttonLink.text(I18n('hideText'));
                    } else {
                        if (treeview) {
                            $content.detach();
                        } else {
                            $contentContainer.hide();
                        }
                        $buttonLink.text(I18n('showText'));
                    }
                    return;
                }

                // See if this was loaded elsewhere before making a request
                var gotContent;
                $('.pageloader-contentloaded').each(function() {
                    var $fLoader = $(this);
                    if ($fLoader.data('page') === page && $fLoader.data('pageloader-content')) {
                        $contentContainer.html($fLoader.data('pageloader-content')).removeClass('noscript');
                        mw.hook('wikipage.content').fire($contentContainer);

                        if (treeview) {
                            $body.find('.noscript').remove();
                            $content = extractList($contentContainer, treeviewClass);
                            $content.insertAfter($body);
                        }

                        $buttonLink.text(I18n('hideText'));
                        $body.addClass('pageloader-contentloaded');
                        gotContent = true;
                        return false;
                    }
                });
                if (gotContent) {
                    return;
                }

                // Just in-case the spinner module is still not ready yet
                var $spinner = $();
                mw.loader.using('jquery.spinner', function() {
                    // $spinner will be false if the content somehow loaded before the module did
                    if ($spinner) {
                        $spinner = $.createSpinner().addClass('mw-editsection-like')
                            .css('min-width', $button.css('min-width'));
                        $button.hide().after($spinner);
                    }
                });

                var requestData = {
                    action: 'parse',
                    prop: 'text|modules|jsconfigvars'
                };
                if (template) {
                    requestData.page = page;
                } else {
                    requestData.title = mw.config.get('wgPageName');
                    requestData.text = '{' + '{:' + page + '}}';
                }
                new mw.Api().get(requestData).done(function(data) {
                    // Add config and modules
                    if (data.parse.jsconfigvars) {
                        mw.config.set(data.parse.jsconfigvars);
                    }
                    if (data.parse.modules) {
                        mw.loader.load(data.parse.modules.concat(
                            data.parse.modulescripts,
                            data.parse.modulestyles
                      ));
                    }

                    var html = data.parse.text['*'];
                    $contentContainer.html(html).removeClass('noscript');

                    // Resolve self-links
                    if (template) {
                        var curPage = '/' + mw.config.get('wgPageName');
                        $contentContainer.find('a').each(function() {
                            var $link = $(this);
                            if ($link.attr('href') === curPage) {
                                $link.replaceWith($('<strong>').addClass('selflink').append($link.contents()));
                            }
                        });
                        html = $contentContainer.html();
                    }

                    $body.data('pageloader-content', html);

                    // Fire content hook on the new content, running all this stuff again and more :)
                    mw.hook('wikipage.content').fire($contentContainer);

                    if (treeview) {
                        $body.find('.noscript').remove();
                        $content = extractList($contentContainer, treeviewClass);
                        $content.insertAfter($body);
                    }

                    $spinner.remove();
                    $spinner = false;
                    $buttonLink.text(I18n('hideText'));
                    $button.show();
                    $body.addClass('pageloader-contentloaded');
                }).fail(function(_, error) {
                    $spinner.remove();
                    $spinner = false;
                    $button.show();

                    var errorText = '';
                    if (error.textStatus) {
                        errorText = error.textStatus;
                    } else if (error.error) {
                        errorText = error.error.info;
                    }

                    mw.notify(errorText, { title: I18n('loadErrorTitle'), autoHide: false });
                });
            });
        });
    }());
    // #endregion
});