MediaWiki:Gadget-site.js

From TibiaCraft
Jump to navigationJump 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)
  • Edge: Hold Ctrl while clicking Refresh, or press Ctrl-F5.
/**
 * Scripts placed here are loaded on both desktop and mobile views.
 *
 * Desktop-only scripts should go in [[MediaWiki:Common.js]]
 * Mobile-only scripts should go in [[MediaWiki:Minerva.js]].
 */

( function() {
    'use strict';

    /* Variables for interface text used throughout the script, for ease of translating */
    var i18n = {
        // Collapsible elements and page loader
        hideText: 'hide',
        showText: 'show',
        loadErrorTitle: 'An error occurred loading the content'
    };

    /* Fired whenever wiki content is added. (#mw-content-text, live preview, load page, etc.) */
    mw.hook( 'wikipage.content' ).add( function( $wikipageContent ) {


        /**
         * 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.collapsible-rows' ) ) {
                        var $collapsibleRows = $collapsible.nextUntil( '.collapsible-rows' );
                        if ( $collapsibleRows.hasClass( 'collapsible-row' ) ) {
                            $collapsibleRows = $collapsibleRows.filter( 'collapsible-row' );
                        } else {
                            $collapsibleRows.addClass( 'collapsible-row' );
                        }
                        if ( $collapsible.hasClass( 'collapsed' ) && !$collapsibleRows.hasClass( 'collapsed' ) ) {
                            $collapsibleRows.addClass( 'collapsed' );
                        }
                        $collapsible = $collapsible.add( $collapsibleRows );
                    } else 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.first().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.first().hasClass( 'collapsed' ) ) {
                        $toggleLink.text( showText );
                    } else {
                        $toggleLink.text( hideText );
                    }

                    // Stop table sorting activating when clicking the link
                    e.stopPropagation();
                } );

                $collapsible.data( 'made-collapsible', true );
            } );
        }() );

        /**
         * Set minimum height for animations to prevent moving the page if the frames
         * differ in height
         */
        ( function() {
            // Set frames to be visible for measuring height
            var $animated = $wikipageContent.find( '.animated' ).addClass( 'animated-visible' );

            // Group frames per animation
            var animateds = [];
            $animated.each( function() {
                animateds.push( {
                    $: $( this ).find( '> .animated-subframe' ).addBack()
                        .find( '> *:not(.animated-subframe)' ),
                } );
            } );

            // Get highest frame for each animation (if heights differ)
            $.each( animateds, function() {
                var minHeight = 0, differentHeights;
                this.$.each( function() {
                    var height = this.offsetHeight;
                    differentHeights = differentHeights || minHeight && height !== minHeight;
                    minHeight = Math.max( height, minHeight );
                } );

                if ( differentHeights ) {
                    this.height = minHeight;
                }
            } );

            // Set animation to be at least as tall as the tallest frame,
            // and set the non-active frames to be hidden again
            $animated.each( function( i ) {
                $( this ).css( 'min-height', animateds[i].height );
            } ).removeClass( 'animated-visible' );

            // Load all images in the animation as soon as the animated content becomes visible
            var animatedObserver = new IntersectionObserver( function( entries ) {
                entries.forEach( function( entry ) {
                    if ( entry.isIntersecting && !entry.target.classList.contains( 'animated-lazyloaded' ) ) {
                        $( entry.target ).find( 'img' ).attr( 'loading', 'eager' );
                        entry.target.classList.add( 'animated-lazyloaded' );
                        animatedObserver.unobserve( entry.target );
                    }
                } );
            } );

            // Observe every animation
            $animated.each( function() {
                animatedObserver.observe(this);
            } );
        }() );


    } );
    /* End wiki content hook */


    /* Fires when DOM is ready */
    $( function() {


        /**
         * Element animator
         *
         * Cycles through a set of elements (or "frames") on a 2 second timer per frame
         * Add the "animated" class to the frame containing the elements to animate.
         * Optionally, add the "animated-active" class to the frame to display first.
         * Optionally, add the "animated-subframe" class to a frame, and the
         * "animated-active" class to a subframe within, in order to designate a set of
         * subframes which will only be cycled every time the parent frame is displayed.
         * Animations with the "animated-paused" class will be skipped each interval.
         *
         * Requires some styling from [[MediaWiki:Gadget-site-styles.css]].
         */
        ( function() {
            var $content = $( '#mw-content-text' );
            var advanceFrame = function( parentElem, parentSelector ) {
                var curFrame = parentElem.querySelector( parentSelector + ' > .animated-active' );
                $( curFrame ).removeClass( 'animated-active' );
                var $nextFrame = $( curFrame && curFrame.nextElementSibling || parentElem.firstElementChild );
                return $nextFrame.addClass( 'animated-active' );
            };

            // Set the name of the hidden property
            var hidden;
            if ( typeof document.hidden !== 'undefined' ) {
                hidden = 'hidden';
            } else if ( typeof document.msHidden !== 'undefined' ) {
                hidden = 'msHidden';
            } else if ( typeof document.webkitHidden !== 'undefined' ) {
                hidden = 'webkitHidden';
            }

            setInterval( function() {
                if ( hidden && document[hidden] ) {
                    return;
                }
                $content.find( '.animated' ).each( function() {
                    if ( $( this ).hasClass( 'animated-paused' ) ) {
                        return;
                    }

                    var $nextFrame = advanceFrame( this, '.animated' );
                    if ( $nextFrame.hasClass( 'animated-subframe' ) ) {
                        advanceFrame( $nextFrame[0], '.animated-subframe' );
                    }
                } );
            }, 2000 );
        }() );
    } );
    /* End DOM ready */
}() );