Extension:ShortLinksParser

From mediawiki.org
MediaWiki extensions manual
ShortLinksParser (SLP)
Release status: unmaintained
Implementation Parser extension , Link markup
Description Different version of interwiki links: Lets you configure base-urls with multiple placeholders for often used sources like Wikipedia.
Author(s) cagey83talk
Latest version 1.2 (2008-02-12)
MediaWiki 1.5
License GNU General Public License 2.0 or later
Download see description
see description

What can this extension do?[edit]

If you're linking often to the same external sources you have always to repeat certain parts of the URL which remain the same. This extension introduces a possibility to shorten this notation by providing reusable base-urls with placeholders.

Note: See See also for differences to interwiki links.

Usage[edit]

E.g. you have a lot of links to wikipedia so you would have to write again and again the same base URL with the name of the page appended:

http://en.wikipedia.org/wiki/A_PAGE and again
http://en.wikipedia.org/wiki/ANOTHER_PAGE.

Using the ShortLinksParser-Extension you can cut down the link to:
Wikipedia{A_PAGE} and
Wikipedia{ANOTHER_PAGE}
whereas the ShortLink Wikipedia is replaced by the base URL http://en.wikipedia.org/wiki/ and the page name is inserted for a placeholder.

Another reasonable field of application might be linking to items of other web applications, e.g. Project Management Tools, like Projektron BCS, Time Tracking or Bug Tracking Tools.

Download instructions[edit]

Please create a new folder in your MediaWiki Extension directory ($IP/extensions) named ShortLinksParser. Add the files shortLinksParser_class.php and ShortLinksParser.php to it.

Your directory structure should now look like this:

<root>
--extensions
----ShortLinksParser
------ShortLinksParser.php
------shortLinksParser_class.php

Note: $IP stands for the root directory of your MediaWiki installation, the same directory that holds LocalSettings.php.

Installation[edit]

Installation follows two steps:

1. Add the following to LocalSettings.php:

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

2. Configure the ShortLinks in ShortLinksParser.php as described in the next point.

Configuration parameters[edit]

Configuring a ShortLink is as easy as filling an associative array.
Please note: You can find the array in the extension file ShortLinksParser.php below.

For the above mentioned Wikipedia example this might be:

$a_shortLinks['Wikipedia'] = "http://de.wikipedia.org/wiki/{0}";

The number in braces is a placeholder. You can use insert placeholders on any position you want and as many as you want.

Multiple placeholders[edit]

An example for multiple placeholders

$a_shortLinks['MWiki'] = "http://www.mediawiki.org/wiki/{0}#{1}";

In your MediaWiki you could now define a ShortLink pointing to the MediaWiki Extension authors:

MWiki{Category:Extension|Extension_authors}

By default the pipe symbol (|) is used to separate the parameters.

Customizing the ShortLinks parameter separator[edit]

You can also use another symbol, but make sure this symbol can't be part of an URL. To define another char use the method setParamsDelimiter(String newParamsDelimiter) of the class shortLinksParser.

Customizing the look of a ShortLink[edit]

If you want to highlight a ShortLink e.g. with an icon, you can easily do that in CSS. Every generated ShortLink is surrounded with a div-Box which has a class assigned to it.
The name of the class follows a certain syntax: NAME_OF_THE_SHORTLINK-shortLinkContainer. For the above mentioned Wikipedia example this would be div.Wikipedia-shortLinkContainer.

You can either add the CSS-Code to existing CSS-files or use an extra file. To link to the extra file you can use the method setCssFile(String CssFileName) of the class shortLinksParser.

See also[edit]

Differences to interwiki links[edit]

The built-in interwiki links of the MediaWiki-Software are using basically the same approach. Differences are

  • Customizing the look of a ShortLink: There's a div box with a CSS class refering to the ShortLink around every ShortLink. You can use it to customize the look of a link (e.g. using an icon in front of every link). With interwiki links you only have the CSS class "extiw" assigned to every inverwiki link so you can't differentiate between prefixes.
  • Multiple placeholders: You can define several placeholders in a ShortLink. In the next version you can also overload a ShortLink with a different number of params pointing to different URLs of the same base URLs.

Code[edit]

ShortLinksParser.php[edit]

/*
	This program is free software; you can redistribute it and/or
	modify it under the terms of the GNU General Public License
	as published by the Free Software Foundation, version 2
	of the License.
	
	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.
	
	You should have received a copy of the GNU General Public License
	along with this program; if not, write to the Free Software
	Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.

/**
 * Setup and Hooks for the ShortLinks extension, 
 * a possibility to abbreviate links similar to interwiki links
 *
 * @addtogroup Extensions
 * @author Thomas Klein
 * @copyright © 2008 Thomas Klein
 * @licence GNU General Public Licence 2.0 or later
 */



####################################################
# INITIALISIERUNG
####################################################
	
	error_reporting(E_ALL ^ E_NOTICE);
	setlocale(LC_ALL, 'de_DE');
	ini_set('display_errors', true); 
	header("Content-Type: text/html; charset=utf-8");
	
	if(!defined('MEDIAWIKI')) {
        echo( "This is an extension to the MediaWiki package and cannot be run standalone.\n" );
        die(-1);
   	}
   	
   	include("shortLinksParser_class.php");
   	
	global $wgHooks, $wgOut, $wgScriptPath;
  	
/*
 * @private array $a_shortLinks associative array that contains the shortLinks, 
 * whereas key is name of the shortLink and value the full url with placeholders
 */	
	$a_shortLinks = array();
	
# defining the ShortLinks
###################
	$a_shortLinks['Wikipedia'] 	   = "http://de.wikipedia.org/wiki/{0}";

# example to overload a ShortLink -
# which one is used depends on the number of params used for the ShortLink
############################################################
//	$a_shortLinks['Wikipedia'][] = "http://de.wikipedia.org/wiki/{0}";
//	$a_shortLinks['Wikipedia'][] = "http://de.wikipedia.org/wiki/{0}#{1}";
	
/**
 * @private object(shortLinks) $o_sl
 */
	$o_slp = null;
	
	try {
		$o_slp = new shortLinksParser($a_shortLinks);
		$o_slp->setParamsDelimiter("|");
		$o_slp->setLinkDelimiter(shortLinksParser::LINK_DELIMITER_BRACE);
		$o_slp->setCssFile($wgScriptPath."/extensions/ShortLinksParser/shortLinks.css");
	} catch (Exception $e) {
		die("<p>".$e->getMessage()."</p>");
	}
	
# in $o_cpm the method 'onArticleSave' get's called
###################################################
	$wgHooks['OutputPageBeforeHTML'][]  = $o_slp;
	$wgExtensionCredits['parserhook'][] = array(
		'version'     => '2008-09-15',
		'name'        => 'ShortLinksParser',
		'author'      => 'Thomas Klein (Member of the research project "4CforMedia" => http://www.4cformedia.de)',
		'email'       => 'thomas dot klein83 at gmail dot com',
		'url'         => 'http://www.mediawiki.org/wiki/Extension:ShortLinksParser',
		'description' => 'Lets you configure "ShortLinks" for often used URLs pointing '.
						 'to an external source like Wikipedia.',
		'descriptionmsg' => 'shortlinksparser-desc',
	);

shortLinksParser_class.php[edit]

/*
	This program is free software; you can redistribute it and/or
	modify it under the terms of the GNU General Public License
	as published by the Free Software Foundation, version 2
	of the License.
	
	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.
	
	You should have received a copy of the GNU General Public License
	along with this program; if not, write to the Free Software
	Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.

/**
 * Contains methods to search in a text for configured ($this->a_shortLinks) shortLinks
 * and replace them with the full URLs to an external source 
 * 
 * @addtogroup Extensions
 * @author Thomas Klein
 * @copyright © 2008 Thomas Klein
 * @licence GNU General Public Licence 2.0 or later
 * @version 1.2 
 */

class shortLinksParser {
	
	
/**
 * @static const s_patternShortLink_partly also contains German "Umlaute"
 */	
	const s_patternShortLink_partly = '([\s\wäöüÄÖÜß\?_|#\!\'\";,+*-/:=()]+)';

/**
 * @static const s_patternUrlParam
 */
	const s_patternUrlParam = '!{([0-9])}+!i';
/**
 * @static const LINK_DELIMITER_BRACE
 */
	const LINK_DELIMITER_BRACE = 0;
	
/**
 * @static const LINK_DELIMITER_PARENTHESIS
 */
	const LINK_DELIMITER_PARENTHESIS = 50;
	
/**
 * @static const LINK_DELIMITER_BRACKET
 */
	const LINK_DELIMITER_BRACKET = 100;
	
/**
 * @private int $i_linkDelimiterSymbolStart
 */
	private $i_linkDelimiterSymbolStart;

/**
 * @private int $i_linkDelimiterSymbolEnd
 */
	private $i_linkDelimiterSymbolEnd;
	
/*
 * @private array $a_shortLinks
 */
	private $a_shortLinks;
	
/**
 * @private string $s_paramsDelimiter
 */
	private $s_paramsDelimiter;

/**
 * @private array $a_orderOfShortLinksParams
 */
	private $a_orderOfShortLinksParams;
	
/*********************************************************
 * Constructor
 *
 * @param array $a_shortLinks
 */
	public function __construct($a_shortLinks) {
		
	# set default values for class vars
	###################################
		$this->s_paramsDelimiter = "|";
		$this->i_linkDelimiterSymbolStart = "{";
		$this->i_linkDelimiterSymbolEnd = "}";
		$this->s_cssFilePath = null;
		$this->a_shortLinks = array();
		$this->a_orderOfShortLinksParams  = array();
		
	# check each shortLink for valid form
	#####################################
		foreach ($a_shortLinks as $s_nameShortLink => $m_shortLink) {
			
		# in case of overloaded ShortLinks
		##################################
			if (is_array($m_shortLink) && !empty($m_shortLink)) {
				
				foreach ($m_shortLink as $s_shortLink)
					$this->handleShortLink($s_shortLink,$s_nameShortLink);	
					
			}
		# in case of one ShortLink has only one equivalent
		################################################## 
			else
				$this->handleShortLink($m_shortLink,$s_nameShortLink);
		
		}
	}//__construct

	
/*********************************************************
 * Assigns the given ShortLink to the list of available ShortLinks
 * and checks if there was already one with the same name 
 * but different params. 
 * Otherwise throws an exception for an overloaded ShortLink  
 *
 * @param string $s_shortLink
 * @param string $s_nameShortLink
 * 
 * @throws exception for overloaded ShortLink
 */	
	private function handleShortLink($s_shortLink,$s_nameShortLink) {
		
	/**
	 * @private array $a_matchesUrlParams matches of URL params
	 */
		$a_matchesUrlParams = array();
		
	# replace all URL params through placeholders readable for the function "vsprintf"
	# if there are any URL params
	################################################
		preg_match_all(shortLinksParser::s_patternUrlParam, 
					   $s_shortLink,
					   $a_matchesUrlParams,
					   PREG_SET_ORDER);
					   
	# if there's no placeholder defined, throw a error message
	#################################
		if (empty($a_matchesUrlParams)) {
			
			throw new Exception("<strong>Error on line ".__LINE__." in extension ".__CLASS__." -</strong> " .
            		"Make sure there's at least 1 placeholder (number in braces on any part of the URL) ".
					"in the shortLink defined!");
					die(-1);
		}
		
	/**
	 * @private array $a_orderOfShortLinksParams
	 */
		$a_orderOfShortLinksParams = array();
		
	# replace each placeholder by symbols
	#####################################
		foreach ($a_matchesUrlParams as $a_match) {
			$a_orderOfShortLinksParams[] = $a_match[1];
			$s_shortLink = str_replace($a_match[0],"%s",$s_shortLink);
		}
		
	# remember the order of the ShortLink params
	############################################
		$this->a_orderOfShortLinksParams[$s_nameShortLink][] = $a_orderOfShortLinksParams;
			
	# in case the shortLink name was already defined, 
	# check if this is an alternative
	# with a different numbers of placeholders
	#################################################
			
		if (isset($this->a_shortLinks[$s_nameShortLink]) && 
		   (count($a_matchesUrlParams) == count($this->a_orderOfShortLinksParams[$s_nameShortLink][0]))) {
		
		   	throw new Exception("<strong>Error on line ".__LINE__." in extension ".__CLASS__." -</strong> " .
            	"If you use several ShortLinks with the same name, make sure ".
				"they have a different number of placeholders!");
				die(-1);
		}	
			
		$this->a_shortLinks[$s_nameShortLink][] = $s_shortLink;
		
	}//handleShortLink
	
	
/*********************************************************
 * Sets the delimiter for params in the ShortLinks
 *
 * @param string $s_paramsDelimiter
 */	
	public function setParamsDelimiter($s_paramsDelimiter) {
	
	/**
	 * @private string $s_validUrlDelimiterChars
	 */
		$s_validUrlDelimiterChars = "|\(){}$;";
		
	# check for valid URL params delimiter
	######################################
		for ($i = 0; $i < $s_paramsDelimiter;$i++) {
		
			if (strstr($s_validUrlDelimiterChars[$i],$s_paramsDelimiter)!==FALSE) {
				throw new Exception("<strong>Error on line ".__LINE__." in extension ".__CLASS__." -</strong> " .
	            		"Please use only non URL chars for the delimiter. \"".
						$s_validUrlDelimiterChars[$i]."\" can be part of an URL!");
				die(-1);
			}
		}
		
		$this->s_paramsDelimiter = $s_paramsDelimiter;
		
	}//setUrlParamsDelimiter
	
	
/*********************************************************
 * Sets the delimiter for params in the ShortLinks
 *
 * @param int $i_linkDelimiterSymbol must be a class constant beginning with LINK_DELIMITER
 * 
 * @throws Exception for wrong type of param
 */
	public function setLinkDelimiter($i_linkDelimiterSymbol) {
		
		switch ($i_linkDelimiterSymbol) {
			
			case shortLinksParser::LINK_DELIMITER_BRACE:
				//do nothing because this is the default case
				break;
			case shortLinksParser::LINK_DELIMITER_PARENTHESIS:
				$this->i_linkDelimiterSymbolStart = "\(";
				$this->i_linkDelimiterSymbolEnd = "\)";
				break;
				
			case shortLinksParser::LINK_DELIMITER_BRACKET:
				$this->i_linkDelimiterSymbolStart = "\[";
				$this->i_linkDelimiterSymbolEnd = "\]";
				break;
				
			default:
				throw new Exception("<strong>Error on line ".__LINE__." in extension ".__CLASS__." -</strong> " .
	            		"Wrong param type for \"\$i_linkDelimiterSymbol\". Please use only ".
						"class constants beginning with LINK_DELIMITER.");
				die(-1);
				break;
		}
	}//setLinkDelimiter
	
	
/*********************************************************
 * Sets the path to an external css file
 *
 * @param string $s_cssFileName
 */
	public function setCssFile($s_cssFileName) {
		
		$this->s_cssFilePath = $s_cssFileName;
		
	}//setCssFile
	
/*********************************************************
 * Hook for the MediaWiki
 *
 * @param object $o_out the OutputPage to which wikitext is added 
 * @param string $s_text the HTML text that is being added
 *
 * @return boolean
 */
	public function onOutputPageBeforeHTML(&$o_out, &$s_text) {
	
	# register the CSS-File for the ShortLink-Icons if it was set
	#############################################################
		if ($this->s_cssFilePath != null) {
			$o_out->addLink(
				array('rel' => 'stylesheet',
					  'type' => 'text/css',
					  'href' => $this->s_cssFilePath,
				)
			);
		}
		
	# check the text for each shortLink pattern
	###########################################
		foreach ($this->a_shortLinks as $s_shortLinkName => $a_shortLinks) {
			
		/**
		 * @private string $s_patternToCheck
		 */
			$s_patternToCheck = "!(".$s_shortLinkName."){1}".
								$this->i_linkDelimiterSymbolStart.
								shortLinksParser::s_patternShortLink_partly.
								$this->i_linkDelimiterSymbolEnd.
								"!i";
			
		/**
		 * @private array $a_matches
		 */
			$a_matches = array();
			
			preg_match_all($s_patternToCheck, 
						   $s_text,
						   $a_matches,
						   PREG_SET_ORDER);
			
		# if empty, proceed with the next pattern or end the loop
		#########################################################
			if (empty($a_matches))
				continue;
				
		# replace all shortLinks with their URL equivalent 
		################################################## 
			foreach ($a_matches as $a_match) {
				
			/**
			 * @private string $s_pageName
			 */
				$s_pageName  = null;
				
			/**
			 * @private string $s_shortLink
			 */
				$s_shortLink = $a_match[2];
				
			# check for an abbreviated name of the URL
			# like wiki links
			###########################################
				if (strpos($s_shortLink," ") !== FALSE) {
					
					$s_pageName = substr($s_shortLink,strpos($s_shortLink," "));
				
				# only keep the params
				###################### 
					$s_shortLink = substr($s_shortLink,0,-strlen($s_pageName));
				}
				else 
					$s_pageName = $s_shortLink;
				
			/**
			 * @private array $a_urlParams
			 */
				$a_urlParams = explode($this->s_paramsDelimiter,$s_shortLink);
				
			# if the number of given URL params matches the number of placeholders
			# defined in $this->a_shortLinks
			###################################################################################
				
			/**
			 * @private int $i_shortLinkVariant
			 */
				$i_shortLinkVariant = -1;
				
			/**
			 * @private string $s_replacementLink
			 */
				$s_replacementLink = null;
				
				for($i = 0; $i < count($a_shortLinks); $i++) {
					
					if (count($a_urlParams) == count($this->a_orderOfShortLinksParams[$s_shortLinkName][$i])) {
						$i_shortLinkVariant = $i;
						break;
					}	
				}
				
			# if the shortLinks with given number of params is not available
			# mark it
			################################################################ 
				if ($i_shortLinkVariant == -1) {
					$s_replacementLink = $a_match[0]." (-> <em>wrong number of params!</em>)";
				}
				else {
					
					# reorder ShortLinks params depending on the 
					# configured placeholders in ShortLinsParser.php
					################################################
					
				/**
				 * @private array $a_reorderdUrlParams
				 */
					$a_reorderdUrlParams = 
						$this->reorderUrlParams($a_urlParams,
												$this->a_orderOfShortLinksParams[$s_shortLinkName][$i_shortLinkVariant]);
					
					
				/**
				 * @private string $s_fullURL
				 */
					$s_fullURL = vsprintf($this->a_shortLinks[$s_shortLinkName][$i_shortLinkVariant],
										  $a_reorderdUrlParams);
					
					$s_replacementLink = "<span class=\"".$s_shortLinkName."-shortLinkContainer shortLinkContainer\">".
										 "<a href=\"".$s_fullURL."\" class=\"external text\" ".
										 "target=\"_newTab\" title=\"".$s_fullURL."\" ".
										 "rel=\"nofollow\">".$s_pageName."</a></span>";
					
				}	
			
			# replace the ShortLink with the acutal URL
			###########################################
				$s_text = str_replace($a_match[0],
									  $s_replacementLink,
									  $s_text);
			}	
		}
		
		return true;
	}//onOutputPageBeforeHTML
	
	
/**
 * Reorders the Urls params by the numbers of the placeholders
 * defined in ShortLinksParser.php
 *
 * @param array $a_urlParams
 * @param array $a_order
 * 
 * @return array $a_reorderdUrlParams
 */
	private function reorderUrlParams($a_urlParams,$a_order) {
		
	/**
	 * @private array $a_reorderdUrlParams
	 */
		$a_reorderdUrlParams = array();
		
		for ($i = 0; $i < count($a_order); $i++)
			$a_reorderdUrlParams[$i] = $a_urlParams[$a_order[$i]];
		
		return $a_reorderdUrlParams;
		
	}//reorderUrlParams
	
}//shortLinksParser

History[edit]

Revision Release Date Description
1.2 Dezember 02, 2008
  • bugfix for German-Umlaute and the special char &
1.1 September 15, 2008
  • added ShortLink overloading
  • changed surrounding div box to a surrounding span tag
  • added general CSS class "shortLinkContainer" to each ShortLink to simplify the definition of style rules for all ShortLinks
  • added configuration method "setLinkDelimiter" for choosing between multiple link delimiters (brace, paranthesis, bracket)
  • improved error messages
1.0 September 03 2008
  • the first version :-)