Extension:Accordion

From MediaWiki.org
Jump to: navigation, search


MediaWiki extensions manual - list
Crystal Clear action run.png
Accordion

Release status: beta

Implementation Tag
Description enable "accordion pagination" of sections of a page
Author(s) Robert Hänel (RoberthaenelTalk)
Last version 0.1 (12/22/2010)
MediaWiki 1.16
License No license specified
Download #Source
Example Simple Demo and the corresponding Wikitext
Tags
<accordion>
Hooks used
BeforePageDisplay

ParserFirstCallInit

Check usage (experimental)

Contents

[edit] Abstract

This extension might be useful for navigating large pages by hiding all but the current section using Java Script. It was inspired by this article.

[edit] Installation

Copy the Sources into two files named extensions/Accordion/Accordion.php and extensions/Accordion/Accordion.js and add the following line to your LocalSettings.php:

require_once( "$IP/extensions/Accordion/Accordion.php" );

[edit] Usage

Put the following tag around the content you want to enable for accordion pagination:

<accordion>
content
</accordion>

This will put any text between two consecutive headers (default: <h2> or == Header ==) into a hideable div. The different sections can be navigated by clicking on the respective headers or by using the previous and next links.

The following optional parameter can be provided in the <accordion> tag:

Parameter Default Explanation
level 2 Level of the headers marking the different section of the content. Must be a number between 1 and 6.

[edit] Source

[edit] Accordion.php

<?php
/**
 * Accordion extension -- accordion pagination with the <accordion> tag
 *
 * @file
 * @version 0.1
 * @author Robert Hänel
 * @link http://www.mediawiki.org/wiki/Extension:Accordion Documentation
 */
 
if ( !defined( 'MEDIAWIKI' ) ) {
        die( 'This is not a valid entry point.' );
}
 
// Extension credits that will show up on Special:Version
$wgExtensionCredits['parserhook'][] = array(
        'name' => 'Accordion',
        'version' => 0.1,
        'author' => 'Robert Hänel',
        'url' => 'http://www.mediawiki.org/wiki/Extension:Accordion',
        'description' => 'Accordion pagination with the <code>&lt;accordion&gt;</code> tag'
);
 
// Register hooks
$wgHooks['BeforePageDisplay'][] = 'wfAccordionOnBeforePageDisplay';
$wgHooks['ParserFirstCallInit'][] = 'wfAccordionRegisterHook';
 
/**
 * Register the <accordion> hook with the parser.
 *
 * @param $parser Object: instance of Parser
 * @return Boolean: true
 */
function wfAccordionRegisterHook( &$parser ) {
        $parser->setHook( 'accordion', 'wfAccordionCallback' );
        return true;
}
 
/**
 * Add Accordion.js to the page output.
 *
 * @param $out Object: instance of OutputPage
 * @return Boolean: true
 */
function wfAccordionOnBeforePageDisplay( &$out ) {
        global $wgScriptPath;
        $out->addScriptFile( $wgScriptPath . '/extensions/Accordion/Accordion.js' );
        return true;
}
 
/**
 * Actually does all the parsing for us; called by wfAccordionRegisterHook.
 */
function wfAccordionCallback( $input, $args, &$parser ) {
        $level = $args['level'];
        if ( !isset( $level ) ) {
                $level = 2;
        }
        $result = '<script type="text/javascript">var acc_hlevel = ' . $level . ';</script>';
        $result .= '<div id="acc_container">';
        $result .= $parser->recursiveTagParse( $input );
        $result .= '</div>';
        return $result;
}

[edit] Accordion.js

// addHandler function is defined in wikibits.js
addHandler( 'load', onloadListener );
 
function onloadListener() {
        if ( typeof( acc_hlevel ) !== 'undefined' ) {
                accordion_init( acc_hlevel );
        }
}
 
// @todo FIXME: this needs a different name in order not to conflict with
// jQuery's $ alias
function $( id ) {
        return document.getElementById( id );
}
 
function in_array( arr, val ) {
        for ( i = 0; i < arr.length; i++ ) {
                if ( arr[i] == val ) {
                        return 1;
                }
        }
        return 0;
}
 
function scrollToElem( elem ) {
        var pos = 0;
        while( elem != null ) {
                pos += elem.offsetTop;
                elem = elem.offsetParent;
        }
        window.scrollTo( 0, pos );
}
 
function accordion_init( hlevel ) {
        var i = 0;
        /* skip adding elements to the current content-div until we get to the
                next h<hlevel> */
        var ignore = true;
        var headerNum = 0;
        var hname = 'H' + hlevel;
        var ignoreElem = [];
        for ( i = 1; i < hlevel; i++ ) {
                ignoreElem.push( ( 'H' + i ) );
        }
        i = 0;
        while ( $( 'acc_container' ).childNodes.length > i ) {
                var node = $( 'acc_container' ).childNodes[i];
                if ( node.nodeName == hname ) {
                        if ( headerNum != 0 ) {
                                var nextdiv = document.createElement( 'div' );
                                nextdiv.className = 'acc_next';
                                var next = document.createElement( 'a' );
                                next.className = 'acc_link';
                                next.innerHTML = 'next>>';
                                next.onclick = nextClicked;
                                nextdiv.appendChild( next );
                                $( 'content-' + headerNum ).appendChild( nextdiv );
                        }
                        headerNum++;
                        node.id = 'header-' + headerNum;
                        if ( ignore == true ) {
                                node.className = 'acc_header acc_header_first';
                        } else {
                                node.className = 'acc_header';
                        }
                        node.onclick = headerClicked;
                        div = document.createElement( 'div' );
                        div.id = 'content-' + headerNum;
                        div.className = 'acc_content';
                        div.style.display = ( headerNum == 1 ) ? 'block' : 'none';
                        $( 'acc_container' ).insertBefore( div, $( 'acc_container' ).childNodes[i + 1] );
                        if ( headerNum != 1 ) {
                                var prevdiv = document.createElement( 'div' );
                                prevdiv.className = 'acc_prev';
                                var prev = document.createElement( 'a' );
                                prev.className = 'acc_link';
                                prev.innerHTML = '&lt;&lt;previous';
                                prev.onclick = prevClicked;
                                prevdiv.appendChild( prev );
                                div.appendChild( prevdiv );
                        }
                        ignore = false;
                } else if ( in_array( ignoreElem, node.nodeName ) ) {
                        ignore = true;
                } else {
                        if ( headerNum != 0 && ignore == false ) {
                                var id = 'content-' + headerNum;
                                if ( id != node.id ) {
                                        $( id ).appendChild( node );
                                        i--;
                                }
                        }
                }
                i++;
        }
}
 
function headerClicked() {
        var contentId = this.id.replace( /header-/, 'content-' );
        var divs = $( 'acc_container' ).getElementsByTagName( 'div' );
        for ( i = 0; i<divs.length; i++ ) {
                if ( divs[i].id.match( /^content-/ ) ) {
                        divs[i].style.display = ( divs[i].id == contentId ) ? 'block' : 'none';
                }
        }
        scrollToElem( $( this.id ) );
}
 
function nextClicked() {
        var thisId = this.parentNode.parentNode.id;
        var nextId = 'content-' + ( parseInt( thisId.replace( /content-/, '' ) ) + 1 );
        $( thisId ).style.display = 'none';
        $( nextId ).style.display = 'block';
        scrollToElem( $( nextId.replace( /content-/, 'header-' ) ) );
}
 
function prevClicked() {
        var thisId = this.parentNode.parentNode.id;
        var prevId = 'content-' + ( parseInt( thisId.replace( /content-/, '' ) ) - 1 );
        $( thisId ).style.display = 'none';
        $( prevId ).style.display = 'block';
        scrollToElem( $( prevId.replace( /content-/, 'header-' ) ) );
}
Personal tools
Namespaces

Variants
Actions
Navigation
Support
Download
Development
Communication
Print/export
Toolbox