22 public static $id = 0;
34 $parser->setHook(
'imagemap', [
'ImageMap',
'render' ] );
55 $descTypesCanonical =
'top-right, bottom-right, bottom-left, top-left, none';
57 $defaultLinkAttribs =
false;
74 $bits = explode(
'|',
$line, 2 );
75 if (
count( $bits ) == 1 ) {
82 if ( !$imageTitle || !$imageTitle->inNamespace(
NS_FILE ) ) {
90 $imageHTML =
$parser->makeImage( $imageTitle, $parsedOptions );
91 $parser->replaceLinkHolders( $imageHTML );
92 $imageHTML =
$parser->mStripState->unstripBoth( $imageHTML );
93 $imageHTML = Sanitizer::normalizeCharReferences( $imageHTML );
95 $domDoc =
new DOMDocument();
97 $ok = $domDoc->loadXML( $imageHTML );
102 $xpath =
new DOMXPath( $domDoc );
103 $imgs = $xpath->query(
'//img' );
104 if ( !$imgs->length ) {
107 $imageNode = $imgs->item( 0 );
108 $thumbWidth = $imageNode->getAttribute(
'width' );
109 $thumbHeight = $imageNode->getAttribute(
'height' );
112 if ( !$imageObj || !$imageObj->exists() ) {
118 $denominator = $imageObj->getWidth() + $imageObj->getHeight();
119 $numerator = $thumbWidth + $thumbHeight;
120 if ( $denominator <= 0 || $numerator <= 0 ) {
123 $scale = $numerator / $denominator;
128 $cmd = strtok(
$line,
" \t" );
129 if ( $cmd ==
'desc' ) {
130 $typesText =
wfMessage(
'imagemap_desc_types' )->inContentLanguage()->text();
131 if ( $descTypesCanonical != $typesText ) {
133 $typesText = $descTypesCanonical .
', ' . $typesText;
135 $types = array_map(
'trim', explode(
',', $typesText ) );
136 $type = trim( strtok(
'' ) );
137 $descType = array_search(
$type, $types );
138 if ( $descType > 4 ) {
140 $descType = $descType - 5;
143 if ( $descType ===
false || $descType < 0 ) {
144 return self::error(
'imagemap_invalid_desc', $typesText );
153 if ( preg_match(
'/^ \[\[ ([^|]*+) \| ([^\]]*+) \]\] \w* $ /x',
$link, $m ) ) {
155 $alt = trim( $m[2] );
156 } elseif ( preg_match(
'/^ \[\[ ([^\]]*+) \]\] \w* $ /x',
$link, $m ) ) {
158 if ( is_null(
$title ) ) {
159 return self::error(
'imagemap_invalid_title', $lineNum );
161 $alt =
$title->getFullText();
165 if ( preg_match(
'/^ \[ ([^\s]*+) \s ([^\]]*+) \] \w* $ /x',
$link, $m ) ) {
167 $alt = trim( $m[2] );
169 } elseif ( preg_match(
'/^ \[ ([^\]]*+) \] \w* $ /x',
$link, $m ) ) {
170 $title = $alt = trim( $m[1] );
174 return self::error(
'imagemap_no_link', $lineNum );
177 return self::error(
'imagemap_invalid_title', $lineNum );
180 $shapeSpec = substr(
$line, 0, -strlen(
$link ) );
183 $shape = strtok( $shapeSpec,
" \t" );
190 if ( !is_array( $coords ) ) {
196 if ( !is_array( $coords ) ) {
202 $coord = strtok(
" \t" );
203 while ( $coord !==
false ) {
205 $coord = strtok(
" \t" );
207 if ( !
count( $coords ) ) {
208 return self::error(
'imagemap_missing_coord', $lineNum );
210 if (
count( $coords ) % 2 !== 0 ) {
211 return self::error(
'imagemap_poly_odd', $lineNum );
215 return self::error(
'imagemap_unrecognised_shape', $lineNum );
219 foreach ( $coords
as $i => $c ) {
220 $coords[$i] = intval( round( $c * $scale ) );
231 } elseif (
$title->getFragment() !=
'' &&
$title->getPrefixedDBkey() ==
'' ) {
238 if ( $shape !=
'default' ) {
242 $attribs[
'coords'] = implode(
',', $coords );
245 if ( $shape !=
'default' ) {
250 if ( $shape ==
'default' ) {
266 if ( $mapHTML ==
'' ) {
275 $mapName =
"ImageMap_" . ++self::$id .
'_' . mt_rand( 0, 0x7fffffff );
276 $mapHTML =
"<map name=\"$mapName\">\n$mapHTML</map>\n";
279 $imageNode->setAttribute(
'usemap',
"#$mapName" );
283 $anchor = $imageNode->parentNode;
285 $div =
$parent->insertBefore(
new DOMElement(
'div' ), $anchor );
286 $div->setAttribute(
'class',
'noresize' );
287 if ( $defaultLinkAttribs ) {
288 $defaultAnchor = $div->appendChild(
new DOMElement(
'a' ) );
292 $imageParent = $defaultAnchor;
299 if ( $mapHTML !=
'' ) {
300 $mapDoc =
new DOMDocument();
301 $mapDoc->loadXML( $mapHTML );
302 $mapNode = $domDoc->importNode( $mapDoc->documentElement,
true );
303 $div->appendChild( $mapNode );
306 $imageParent->appendChild( $imageNode->cloneNode(
true ) );
307 $parent->removeChild( $anchor );
310 $xpath =
new DOMXPath( $domDoc );
311 $magnify = $xpath->query(
'//div[@class="magnify"]' );
312 if ( !$magnify->length && $descType != self::NONE ) {
314 if ( $descType == self::TOP_LEFT || $descType == self::BOTTOM_LEFT ) {
317 $marginLeft = $thumbWidth - 20;
319 if ( $descType == self::TOP_LEFT || $descType == self::TOP_RIGHT ) {
320 $marginTop = -$thumbHeight;
326 $div->setAttribute(
'style',
"height: {$thumbHeight}px; width: {$thumbWidth}px; " );
327 $descWrapper = $div->appendChild(
new DOMElement(
'div' ) );
328 $descWrapper->setAttribute(
'style',
329 "margin-left: {$marginLeft}px; " .
330 "margin-top: {$marginTop}px; " .
334 $descAnchor = $descWrapper->appendChild(
new DOMElement(
'a' ) );
335 $descAnchor->setAttribute(
'href', $imageTitle->getLocalURL() );
336 $descAnchor->setAttribute(
338 wfMessage(
'imagemap_description' )->inContentLanguage()->
text()
340 $descImg = $descAnchor->appendChild(
new DOMElement(
'img' ) );
341 $descImg->setAttribute(
343 wfMessage(
'imagemap_description' )->inContentLanguage()->
text()
345 $url = $config->get(
'ExtensionAssetsPath' ) .
'/ImageMap/desc-20.png';
346 $descImg->setAttribute(
348 OutputPage::transformResourcePath( $config, $url )
350 $descImg->setAttribute(
'style',
'border: none;' );
356 $output = preg_replace(
'/<\?xml[^?]*\?>/',
'', $domDoc->saveXML(
null, LIBXML_NOEMPTYTAG ) );
385 for ( $i = 0; $i < $count; $i++ ) {
386 $coord = strtok(
" \t" );
387 if ( $coord ===
false ) {
388 return self::error(
'imagemap_missing_coord', $lineNum );
390 if ( !is_numeric( $coord ) || $coord > 1e9 || $coord < 0 ) {
391 return self::error(
'imagemap_invalid_coord', $lineNum );
393 $coords[$i] = $coord;