Index: includes/Linker.php =================================================================== --- includes/Linker.php (revision 17123) +++ includes/Linker.php (working copy) @@ -456,7 +456,7 @@ /** @todo document */ function makeImageLinkObj( $nt, $label, $alt, $align = '', $width = false, $height = false, $framed = false, - $thumb = false, $manual_thumb = '', $page = null ) + $thumb = false, $manual_thumb = '', $page = null, $link = '' ) { global $wgContLang, $wgUser, $wgThumbLimits, $wgGenerateThumbnailOnParse; @@ -506,7 +506,7 @@ $width = min( $img->getWidth(), $wgThumbLimits[$wopt] ); } - return $prefix.$this->makeThumbLinkObj( $img, $label, $alt, $align, $width, $height, $framed, $manual_thumb ).$postfix; + return $prefix.$this->makeThumbLinkObj( $img, $label, $alt, $align, $width, $height, $framed, $manual_thumb, $link ).$postfix; } if ( $width && $img->exists() ) { @@ -544,30 +544,117 @@ wfDebug( "makeImageLinkObj2: '$width'x'$height'\n" ); $u = $nt->escapeLocalURL(); + $target = self::determineImageLinkTarget ( $link, $u ); if ( $error ) { $s = $error; } elseif ( $url == '' ) { $s = $this->makeBrokenImageLinkObj( $img->getTitle() ); //$s .= "
{$alt}
{$url}
\n"; } else { - $s = '' . - ''.$alt.''; + 'longdesc="'.$u.'" />'; + if ($target) $s = '' . $s . ''; } if ( '' != $align ) { $s = "
{$s}
"; } return str_replace("\n", ' ',$prefix.$s.$postfix); } + + /** + * @desc: There are 4 types of image links: + * 1) The image description page (default). + * 2) An internal image link (i.e. to another wiki page, not the image description page). + * 3) An external image link, off to some other site. + * 4) No link at all. + */ + static private function determineImageLinkTarget ( $text, $fallback_url ) { + global $wgAllowNoImageTarget, $wgAllowInternalImageTarget, $wgAllowExternalImageTarget; + // no special linking allowed, so just return. + if ( !$wgAllowNoImageTarget && !$wgAllowInternalImageTarget && !$wgAllowExternalImageTarget) { + return $fallback_url; + } + + // if there was no attempt to use special linking, then no point in doing any work. + if ( !$text ) { + return $fallback_url; + } + + // Requested no image link. + $mwNone =& MagicWord::get( 'img_none' ); + if ($wgAllowNoImageTarget && ! is_null( $mwNone->matchVariableStartToEnd($text) ) ) { + return null; + } + + // Requested an internal link. + if ($wgAllowInternalImageTarget) { + // this is taken from excerpts of the replaceInternalLinks() function. + $m = array(); + $tc = Title::legalChars() . '#%'; + $el = "/^\[\[([{$tc}]+)]]$/sD"; + if ( preg_match($el, trim($text), $m) ) { + # Don't allow internal links to pages containing + # PROTO: where PROTO is a valid URL protocol; these + # should probably be external links, with one square + # bracket. Just use the default description link instead. + if (preg_match('/^(\b(?:' . wfUrlProtocols() . '))/', $m[1])) { + return $fallback_url; + } + $link = $m[1]; + $nt = Title::newFromText( $link ); + if( !$nt ) { + return $fallback_url; + } + // otherwise use the internal URL. + return $nt->escapeLocalURL(); + } + } + + // Requested an external link. + if ($wgAllowExternalImageTarget) { + // this is taken from the replaceExternalLinks() function. + $bits = preg_split( EXT_LINK_BRACKETED, $text, -1, PREG_SPLIT_DELIM_CAPTURE ); + if ( empty ( $bits[1] ) ) { + return $fallback_url; + } + + $external_url = $bits[1]; + + # The characters '<' and '>' (which were escaped by + # removeHTMLtags()) should not be included in + # URLs, per RFC 2396. + $m2 = array(); + if (preg_match('/&(lt|gt);/', $external_url, $m2, PREG_OFFSET_CAPTURE)) { + $external_url = substr($external_url, 0, $m2[0][1]); + } + + $external_url = Sanitizer::cleanUrl( $external_url ); + + # Register link in the output object. + # Replace unnecessary URL escape codes with the referenced character + # This prevents spammers from hiding links from the filters + $pasteurized = Parser::replaceUnusualEscapes( $external_url ); + + //### Q: How to call this? + //### $this->mOutput->addExternalLink( $pasteurized ); + //### Is there some kind of global variable, or a function or something to get this? + + return $external_url; + } + + // The user gave us a link= parameter, but the link looks to be malformed. Use the standard image description linking as a fallback. + return $fallback_url; + } + /** * Make HTML for a thumbnail including image, border and caption * $img is an Image object */ - function makeThumbLinkObj( $img, $label = '', $alt, $align = 'right', $boxwidth = 180, $boxheight=false, $framed=false , $manual_thumb = "" ) { + function makeThumbLinkObj( $img, $label = '', $alt, $align = 'right', $boxwidth = 180, $boxheight=false, $framed=false , $manual_thumb = "", $link = "" ) { global $wgStylePath, $wgContLang, $wgGenerateThumbnailOnParse; $thumbUrl = ''; $error = ''; @@ -622,6 +709,7 @@ } $u = $img->getEscapeLocalURL(); + $target = self::determineImageLinkTarget ( $link, $u ); $more = htmlspecialchars( wfMsg( 'thumbnail-more' ) ); $magnifyalign = $wgContLang->isRTL() ? 'left' : 'right'; @@ -639,10 +727,11 @@ $s .= $this->makeBrokenImageLinkObj( $img->getTitle() ); $zoomicon = ''; } else { - $s .= ''. - ''.$alt.''; + $s .= ''.$alt.''; + 'longdesc="'.$u.'" />'; + if ($target) $s .= ''; if ( $framed ) { $zoomicon=""; } else { @@ -698,8 +787,6 @@ * * @param $title Title object. * @param $text String: pre-sanitized HTML - * @param $nourl Boolean: Mask absolute URLs, so the parser doesn't - * linkify them (it is currently not context-aware) * @return string HTML * * @public Index: includes/Parser.php =================================================================== --- includes/Parser.php (revision 17123) +++ includes/Parser.php (working copy) @@ -436,7 +436,7 @@ /** * Replaces all occurrences of HTML-style comments and the given tags - * in the text with a random marker and returns teh next text. The output + * in the text with a random marker and returns the next text. The output * parameter $matches will be an associative array filled with data in * the form: * 'UNIQ-xxxxx' => array( @@ -1681,12 +1681,6 @@ if ( $ns == NS_IMAGE ) { wfProfileIn( "$fname-image" ); if ( !wfIsBadImage( $nt->getDBkey(), $this->mTitle ) ) { - # recursively parse links inside the image caption - # actually, this will parse them in any other parameters, too, - # but it might be hard to fix that, and it doesn't matter ATM - $text = $this->replaceExternalLinks($text); - $text = $this->replaceInternalLinks($text); - # cloak any absolute URLs inside the image markup, so replaceExternalLinks() won't touch them $s .= $prefix . $this->armorLinks( $this->makeImage( $nt, $text ) ) . $trail; $this->mOutput->addImage( $nt->getDBkey() ); @@ -4270,13 +4264,15 @@ # Check if the options text is of the form "options|alt text" # Options are: - # * thumbnail make a thumbnail with enlarge-icon and caption, alignment depends on lang - # * left no resizing, just left align. label is used for alt= only - # * right same, but right aligned - # * none same, but not aligned - # * ___px scale to ___ pixels width, no aligning. e.g. use in taxobox - # * center center the image - # * framed Keep original image size, no magnify-button. + # * thumbnail make a thumbnail with enlarge-icon and caption, alignment depends on lang + # * left no resizing, just left align. label is used for alt= only + # * right same, but right aligned + # * none same, but not aligned + # * ___px scale to ___ pixels width, no aligning. e.g. use in taxobox + # * center center the image + # * framed Keep original image size, no magnify-button. + # * thumb=___ use manually specified thumbnail. + # * link=___ Specify an image link target besides the image description page. $part = explode( '|', $options); @@ -4289,11 +4285,12 @@ $mwCenter =& MagicWord::get( 'img_center' ); $mwFramed =& MagicWord::get( 'img_framed' ); $mwPage =& MagicWord::get( 'img_page' ); + $mwLink =& MagicWord::get( 'img_link' ); $caption = ''; $width = $height = $framed = $thumb = false; $page = null; - $manual_thumb = '' ; + $manual_thumb = $link = '' ; foreach( $part as $val ) { if ( $wgUseImageResize && ! is_null( $mwThumb->matchVariableStartToEnd($val) ) ) { @@ -4330,10 +4327,18 @@ } } elseif ( ! is_null( $mwFramed->matchVariableStartToEnd($val) ) ) { $framed=true; + } elseif ( ! is_null( $match = $mwLink->matchVariableStartToEnd($val) ) ) { + # use manually specified link target + $link = $match; } else { - $caption = $val; + $caption .= ($caption ? "|" : "") . $val; } } + + # recursively parse links inside the image caption + $caption = $this->replaceExternalLinks($caption); + $caption = $this->replaceInternalLinks($caption); + # Strip bad stuff out of the alt text $alt = $this->replaceLinkHoldersText( $caption ); @@ -4345,7 +4350,7 @@ # Linker does the rest $sk =& $this->mOptions->getSkin(); - return $sk->makeImageLinkObj( $nt, $caption, $alt, $align, $width, $height, $framed, $thumb, $manual_thumb, $page ); + return $sk->makeImageLinkObj( $nt, $caption, $alt, $align, $width, $height, $framed, $thumb, $manual_thumb, $page, $link ); } /** Index: includes/DefaultSettings.php =================================================================== --- includes/DefaultSettings.php (revision 17123) +++ includes/DefaultSettings.php (working copy) @@ -2300,4 +2300,15 @@ $wgEnableAPI = true; $wgEnableWriteAPI = false; +/** + * Options for whether an image can link to things besides the standard image description page. + * First allows users to specify an External link target for an image. + * Second allows users to specify an Internal wiki link target for an image. + * Third allows users to specify no link target for an image. + * Default setting for all three is off. + */ +$wgAllowExternalImageTarget = false; +$wgAllowInternalImageTarget = false; +$wgAllowNoImageTarget = false; + ?> Index: languages/messages/MessagesEn.php =================================================================== --- languages/messages/MessagesEn.php (revision 17123) +++ languages/messages/MessagesEn.php (working copy) @@ -247,6 +247,7 @@ 'end' => array( 0, '__END__' ), 'img_thumbnail' => array( 1, 'thumbnail', 'thumb' ), 'img_manualthumb' => array( 1, 'thumbnail=$1', 'thumb=$1'), + 'img_link' => array( 1, 'link=$1', 'target=$1' ), 'img_right' => array( 1, 'right' ), 'img_left' => array( 1, 'left' ), 'img_none' => array( 1, 'none' ),