+
+/**
+ * New base template for a skin's template extended from QuickTemplate
+ * this class features helper methods that provide common ways of interacting
+ * with the data stored in the QuickTemplate
+ */
+abstract class BaseTemplate extends QuickTemplate {
+
+ /**
+ * Create an array of common toolbox items from the data in the quicktemplate
+ * stored by SkinTemplate.
+ * The resulting array is built acording to a format intended to be passed
+ * through makeListItem to generate the html.
+ */
+ function getToolbox() {
+ wfProfileIn( __METHOD__ );
+
+ $toolbox = array();
+ if ( $this->data['notspecialpage'] ) {
+ $toolbox['whatlinkshere'] = $this->data['nav_urls']['whatlinkshere'];
+ $toolbox['whatlinkshere']['id'] = 't-whatlinkshere';
+ if ( $this->data['nav_urls']['recentchangeslinked'] ) {
+ $toolbox['recentchangeslinked'] = $this->data['nav_urls']['recentchangeslinked'];
+ $toolbox['recentchangeslinked']['msg'] = 'recentchangeslinked-toolbox';
+ $toolbox['recentchangeslinked']['id'] = 't-recentchangeslinked';
+ }
+ }
+ if( isset( $this->data['nav_urls']['trackbacklink'] ) && $this->data['nav_urls']['trackbacklink'] ) {
+ $toolbox['trackbacklink'] = $this->data['nav_urls']['trackbacklink'];
+ $toolbox['trackbacklink']['id'] = 't-trackbacklink';
+ }
+ if ( $this->data['feeds'] ) {
+ $toolbox['feeds']['id'] = 'feedlinks';
+ $toolbox['feeds']['links'] = array();
+ foreach ( $this->data['feeds'] as $key => $feed ) {
+ $toolbox['feeds']['links'][$key] = $feed;
+ $toolbox['feeds']['links'][$key]['id'] = "feed-$key";
+ $toolbox['feeds']['links'][$key]['rel'] = 'alternate';
+ $toolbox['feeds']['links'][$key]['type'] = "application/{$key}+xml";
+ $toolbox['feeds']['links'][$key]['class'] = 'feedlink';
+ }
+ }
+ foreach ( array( 'contributions', 'log', 'blockip', 'emailuser', 'upload', 'specialpages' ) as $special ) {
+ if ( $this->data['nav_urls'][$special] ) {
+ $toolbox[$special] = $this->data['nav_urls'][$special];
+ $toolbox[$special]['id'] = "t-$special";
+ }
+ }
+ if ( !empty( $this->data['nav_urls']['print']['href'] ) ) {
+ $toolbox['print'] = $this->data['nav_urls']['print'];
+ $toolbox['print']['rel'] = 'alternate';
+ $toolbox['print']['msg'] = 'printableversion';
+ }
+ if ( !empty( $this->data['nav_urls']['permalink']['href'] ) ) {
+ $toolbox['permalink'] = $this->data['nav_urls']['permalink'];
+ $toolbox['permalink']['id'] = 't-permalink';
+ } elseif ( $this->data['nav_urls']['permalink']['href'] === '' ) {
+ $toolbox['permalink'] = $this->data['nav_urls']['permalink'];
+ unset( $toolbox['permalink']['href'] );
+ $toolbox['ispermalink']['tooltiponly'] = true;
+ $toolbox['ispermalink']['id'] = 't-ispermalink';
+ $toolbox['ispermalink']['msg'] = 'permalink';
+ }
+ wfRunHooks( 'BaseTemplateToolbox', array( &$this, &$toolbox ) );
+ wfProfileOut( __METHOD__ );
+ return $toolbox;
+ }
+
+ /**
+ * Create an array of personal tools items from the data in the quicktemplate
+ * stored by SkinTemplate.
+ * The resulting array is built acording to a format intended to be passed
+ * through makeListItem to generate the html.
+ * This is in reality the same list as already stored in personal_urls
+ * however it is reformatted so that you can just pass the individual items
+ * to makeListItem instead of hardcoding the element creation boilerplate.
+ */
+ function getPersonalTools() {
+ $personal_tools = array();
+ foreach( $this->data['personal_urls'] as $key => $ptool ) {
+ # The class on a personal_urls item is meant to go on the <a> instead
+ # of the <li> so we have to use a single item "links" array instead
+ # of using most of the personal_url's keys directly
+ $personal_tools[$key] = array();
+ $personal_tools[$key]["links"][] = array();
+ $personal_tools[$key]["links"][0]["single-id"] = $personal_tools[$key]["id"] = "pt-$key";
+ if ( isset($ptool["active"]) ) {
+ $personal_tools[$key]["active"] = $ptool["active"];
+ }
+ foreach ( array("href", "class", "text") as $k ) {
+ if ( isset($ptool[$k]) )
+ $personal_tools[$key]["links"][0][$k] = $ptool[$k];
+ }
+ }
+ return $personal_tools;
+ }
+
+ /**
+ * Makes a link, usually used by makeListItem to generate a link for an item
+ * in a list used in navigation lists, portlets, portals, sidebars, etc...
+ *
+ * $key is a string, usually a key from the list you are generating this link from
+ * $item is an array containing some of a specific set of keys.
+ * The text of the link will be generated either from the contents of the "text"
+ * key in the $item array, if a "msg" key is present a message by that name will
+ * be used, and if neither of those are set the $key will be used as a message name.
+ * If a "href" key is not present makeLink will just output htmlescaped text.
+ * The href, id, class, rel, and type keys are used as attributes for the link if present.
+ * If an "id" or "single-id" (if you don't want the actual id to be output on the link)
+ * is present it will be used to generate a tooltip and accesskey for the link.
+ * If you don't want an accesskey, set $item['tooltiponly'] = true;
+ */
+ function makeLink( $key, $item ) {
+ if ( isset( $item['text'] ) ) {
+ $text = $item['text'];
+ } else {
+ $text = $this->translator->translate( isset( $item['msg'] ) ? $item['msg'] : $key );
+ }
+
+ if ( !isset( $item['href'] ) ) {
+ return htmlspecialchars( $text );
+ }
+
+ $attrs = array();
+ foreach ( array( 'href', 'id', 'class', 'rel', 'type' ) as $attr ) {
+ if ( isset( $item[$attr] ) ) {
+ $attrs[$attr] = $item[$attr];
+ }
+ }
+
+ if ( isset( $item['id'] ) ) {
+ $item['single-id'] = $item['id'];
+ }
+ if ( isset( $item['single-id'] ) ) {
+ if ( isset( $item['tooltiponly'] ) && $item['tooltiponly'] ) {
+ $attrs['title'] = $this->skin->titleAttrib( $item['single-id'] );
+ if ( $attrs['title'] === false ) {
+ unset( $attrs['title'] );
+ }
+ } else {
+ $attrs = array_merge(
+ $attrs,
+ $this->skin->tooltipAndAccesskeyAttribs( $item['single-id'] )
+ );
+ }
+ }
+
+ return Html::element( 'a', $attrs, $text );
+ }
+
+ /**
+ * Generates a list item for a navigation, portlet, portal, sidebar... etc list
+ * $key is a string, usually a key from the list you are generating this link from
+ * $item is an array of list item data containing some of a specific set of keys.
+ * The "id" and "class" keys will be used as attributes for the list item,
+ * if "active" contains a value of true a "active" class will also be appended to class.
+ * If you want something other than a <li> you can pass a tag name such as
+ * "tag" => "span" in the $options array to change the tag used.
+ * link/content data for the list item may come in one of two forms
+ * A "links" key may be used, in which case it should contain an array with
+ * a list of links to include inside the list item, see makeLink for the format
+ * of individual links array items.
+ * Otherwise the relevant keys from the list item $item array will be passed
+ * to makeLink instead. Note however that "id" and "class" are used by the
+ * list item directly so they will not be passed to makeLink
+ * (however the link will still support a tooltip and accesskey from it)
+ * If you need an id or class on a single link you should include a "links"
+ * array with just one link item inside of it.
+ */
+ function makeListItem( $key, $item, $options = array() ) {
+ if ( isset( $item['links'] ) ) {
+ $html = '';
+ foreach ( $item['links'] as $linkKey => $link ) {
+ $html .= $this->makeLink( $linkKey, $link );
+ }
+ } else {
+ $link = array();
+ foreach ( array( 'text', 'msg', 'href', 'rel', 'type', 'tooltiponly' ) as $k ) {
+ if ( isset( $item[$k] ) ) {
+ $link[$k] = $item[$k];
+ }
+ }
+ if ( isset( $item['id'] ) ) {
+ // The id goes on the <li> not on the <a> for single links
+ // but makeSidebarLink still needs to know what id to use when
+ // generating tooltips and accesskeys.
+ $link['single-id'] = $item['id'];
+ }
+ $html = $this->makeLink( $key, $link );
+ }
+
+ $attrs = array();
+ foreach ( array( 'id', 'class' ) as $attr ) {
+ if ( isset( $item[$attr] ) ) {
+ $attrs[$attr] = $item[$attr];
+ }
+ }
+ if ( isset( $item['active'] ) && $item['active'] ) {
+ if ( !isset( $attrs['class'] ) ) {
+ $attrs['class'] = '';
+ }
+ $attrs['class'] .= ' active';
+ $attrs['class'] = trim( $attrs['class'] );
+ }
+ return Html::rawElement( isset( $options['tag'] ) ? $options['tag'] : 'li', $attrs, $html );
+ }
+
+ function makeSearchInput( $attrs = array() ) {
+ $realAttrs = array(
+ 'type' => 'search',
+ 'name' => 'search',
+ 'value' => isset( $this->data['search'] ) ? $this->data['search'] : '',
+ );
+ $realAttrs = array_merge( $realAttrs, $this->skin->tooltipAndAccesskeyAttribs( 'search' ), $attrs );
+ return Html::element( 'input', $realAttrs );
+ }
+
+ function makeSearchButton( $mode, $attrs = array() ) {
+ switch( $mode ) {
+ case 'go':
+ case 'fulltext':
+ $realAttrs = array(
+ 'type' => 'submit',
+ 'name' => $mode,
+ 'value' => $this->translator->translate( $mode == 'go' ? 'searcharticle' : 'searchbutton' ),
+ );
+ $realAttrs = array_merge(
+ $realAttrs,
+ $this->skin->tooltipAndAccesskeyAttribs( "search-$mode" ),
+ $attrs
+ );
+ return Html::element( 'input', $realAttrs );
+ case 'image':
+ $buttonAttrs = array(
+ 'type' => 'submit',
+ 'name' => 'button',
+ );
+ $buttonAttrs = array_merge(
+ $buttonAttrs,
+ $this->skin->tooltipAndAccesskeyAttribs( 'search-fulltext' ),
+ $attrs
+ );
+ unset( $buttonAttrs['src'] );
+ unset( $buttonAttrs['alt'] );
+ $imgAttrs = array(
+ 'src' => $attrs['src'],
+ 'alt' => isset( $attrs['alt'] ) ? $attrs['alt'] : $this->translator->translate( 'searchbutton' ),
+ );
+ return Html::rawElement( 'button', $buttonAttrs, Html::element( 'img', $imgAttrs ) );
+ default:
+ throw new MWException( 'Unknown mode passed to BaseTemplate::makeSearchButton' );
+ }
+ }
+
+ /**
+ * Returns an array of footerlinks trimmed down to only those footer links that
+ * are valid.
+ * If you pass "flat" as an option then the returned array will be a flat array
+ * of footer icons instead of a key/value array of footerlinks arrays broken
+ * up into categories.
+ */
+ function getFooterLinks( $option = null ) {
+ $footerlinks = $this->data['footerlinks'];
+
+ // Reduce footer links down to only those which are being used
+ $validFooterLinks = array();
+ foreach( $footerlinks as $category => $links ) {
+ $validFooterLinks[$category] = array();
+ foreach( $links as $link ) {
+ if( isset( $this->data[$link] ) && $this->data[$link] ) {
+ $validFooterLinks[$category][] = $link;
+ }
+ }
+ if ( count( $validFooterLinks[$category] ) <= 0 ) {
+ unset( $validFooterLinks[$category] );
+ }
+ }
+
+ if ( $option == 'flat' ) {
+ // fold footerlinks into a single array using a bit of trickery
+ $validFooterLinks = call_user_func_array(
+ 'array_merge',
+ array_values( $validFooterLinks )
+ );
+ }
+
+ return $validFooterLinks;
+ }
+
+ /**
+ * Returns an array of footer icons filtered down by options relevant to how
+ * the skin wishes to display them.
+ * If you pass "icononly" as the option all footer icons which do not have an
+ * image icon set will be filtered out.
+ * If you pass "nocopyright" then MediaWiki's copyright icon will not be included
+ * in the list of footer icons. This is mostly useful for skins which only
+ * display the text from footericons instead of the images and don't want a
+ * duplicate copyright statement because footerlinks already rendered one.
+ */
+ function getFooterIcons( $option = null ) {
+ // Generate additional footer icons
+ $footericons = $this->data['footericons'];
+
+ if ( $option == 'icononly' ) {
+ // Unset any icons which don't have an image
+ foreach ( $footericons as $footerIconsKey => &$footerIconsBlock ) {
+ foreach ( $footerIconsBlock as $footerIconKey => $footerIcon ) {
+ if ( !is_string( $footerIcon ) && !isset( $footerIcon['src'] ) ) {
+ unset( $footerIconsBlock[$footerIconKey] );
+ }
+ }
+ }
+ // Redo removal of any empty blocks
+ foreach ( $footericons as $footerIconsKey => &$footerIconsBlock ) {
+ if ( count( $footerIconsBlock ) <= 0 ) {
+ unset( $footericons[$footerIconsKey] );
+ }
+ }
+ } elseif ( $option == 'nocopyright' ) {
+ unset( $footericons['copyright']['copyright'] );
+ if ( count( $footericons['copyright'] ) <= 0 ) {
+ unset( $footericons['copyright'] );
+ }
+ }
+
+ return $footericons;
+ }
+
+ /**
+ * Output the basic end-page trail including bottomscripts, reporttime, and
+ * debug stuff. This should be called right before outputting the closing
+ * body and html tags.
+ */
+ function printTrail() { ?>
+<?php $this->html('bottomscripts'); /* JS call to runBodyOnloadHook */ ?>
+<?php $this->html('reporttime') ?>
+<?php if ( $this->data['debug'] ): ?>
+<!-- Debug output:
+<?php $this->text( 'debug' ); ?>
+
+-->
+<?php endif;
+ }
+
+}
+