diff --git a/PortableInfobox.i18n.php b/PortableInfobox.i18n.php index 870916c..87b78de 100644 --- a/PortableInfobox.i18n.php +++ b/PortableInfobox.i18n.php @@ -3,9 +3,11 @@ $messages = []; $messages[ 'en' ] = [ 'portable-infobox-desc' => 'Create portable infoboxes which can be rendered using clean semantic HTML markup on - any skin / platform using using easy to understand powerful XML-like markup' + any skin / platform using using easy to understand powerful XML-like markup', + 'unimplemented-infobox-tag' => 'Unimplemented infobox tag: <$1>' ]; $messages[ 'qqq' ] = [ - 'portable-infobox-desc' => 'Portable Infobox extension description' -]; \ No newline at end of file + 'portable-infobox-desc' => 'Portable Infobox extension description', + 'unimplemented-infobox-tag' => 'Error message for using unimplemented infobox tag; $1 is the tag name without pointy braces' +]; diff --git a/PortableInfobox.setup.php b/PortableInfobox.setup.php index 4a711f7..e8cebd0 100644 --- a/PortableInfobox.setup.php +++ b/PortableInfobox.setup.php @@ -49,7 +49,6 @@ $wgAutoloadClasses[ 'PortableInfoboxHooks' ] = $dir . 'PortableInfoboxHooks.clas // hooks $wgHooks[ 'ParserFirstCallInit' ][] = 'PortableInfoboxParserTagController::parserTagInit'; $wgHooks['BeforePageDisplay'][] = 'PortableInfoboxHooks::onBeforePageDisplay'; -$wgHooks[ 'SkinAfterBottomScripts' ][] = 'PortableInfoboxHooks::onSkinAfterBottomScripts'; // i18n mapping $wgExtensionMessagesFiles[ 'PortableInfobox' ] = $dir . 'PortableInfobox.i18n.php'; diff --git a/PortableInfoboxHooks.class.php b/PortableInfoboxHooks.class.php index 85ef34e..48d2d4e 100644 --- a/PortableInfoboxHooks.class.php +++ b/PortableInfoboxHooks.class.php @@ -5,22 +5,4 @@ class PortableInfoboxHooks { Wikia::addAssetsToOutput('portable_infobox_scss'); return true; } - - /** - * Adds assets on the bottom of the body tag for special maps page - * - * @param {String} $skin - * @param {String} $text - * - * @return bool - */ - public static function onSkinAfterBottomScripts( $skin, &$text ) { - $scripts = AssetsManager::getInstance()->getURL( 'portable_infobox_js' ); - - foreach ( $scripts as $script ) { - $text .= Html::linkedScript( $script ); - } - - return true; - } } diff --git a/controllers/PortableInfoboxParserTagController.class.php b/controllers/PortableInfoboxParserTagController.class.php index 99c2be8..b012326 100644 --- a/controllers/PortableInfoboxParserTagController.class.php +++ b/controllers/PortableInfoboxParserTagController.class.php @@ -30,7 +30,14 @@ class PortableInfoboxParserTagController extends WikiaController { $infoboxParser = new Wikia\PortableInfobox\Parser\XmlParser( $frame->getNamedArguments() ); $infoboxParser->setExternalParser( ( new Wikia\PortableInfobox\Parser\MediaWikiParserService( $parser, $frame ) ) ); - $data = $infoboxParser->getDataFromXmlString( $markup ); + + try { + $data = $infoboxParser->getDataFromXmlString( $markup ); + } catch ( \Wikia\PortableInfobox\Parser\Nodes\UnimplementedNodeException $e ) { + + return [ $this->renderUnimplementedTagErrorMesssage( $e->getMessage() ), 'markerType' => 'nowiki' ]; + } + //save for later api usage $this->saveToParserOutput( $parser->getOutput(), $data ); @@ -40,6 +47,13 @@ class PortableInfoboxParserTagController extends WikiaController { return [ $renderedValue, 'markerType' => 'general' ]; } + private function renderUnimplementedTagErrorMesssage( $tagName ) { + $renderedValue = ' ' + . wfMessage( 'unimplemented-infobox-tag', [ $tagName ] )->escaped() + . ''; + return $renderedValue; + } + protected function saveToParserOutput( \ParserOutput $parserOutput, $raw ) { if ( !empty( $raw ) ) { $infoboxes = $parserOutput->getProperty( self::INFOBOXES_PROPERTY_NAME ); diff --git a/crowdin.conf b/crowdin.conf new file mode 100644 index 0000000..8479400 --- /dev/null +++ b/crowdin.conf @@ -0,0 +1,4 @@ +[crowdin.project] +projectid = "ext-PortableInfobox" +format = "mediawiki" +source.file = "PortableInfobox.i18n.php" diff --git a/scripts/PortableInfobox.js b/scripts/PortableInfobox.js deleted file mode 100644 index eafefc3..0000000 --- a/scripts/PortableInfobox.js +++ /dev/null @@ -1,23 +0,0 @@ -'use strict'; - -(function($, vignette) { - var infoboxImages = $('.portable-infobox-image'); - - /** - * @desc loads infobox image image - * @param {number} index - array index - * @param {string} img - img html - */ - function loadImage(index, img) { - var $img = $(img), - url = $img.data('url'), - options = { - mode: vignette.mode.scaleToWidth, - width: $img.parent().width() - }; - - $img.attr('src', vignette.getThumbURL(url, options)); - } - - infoboxImages.each(loadImage); -})(jQuery, Vignette); diff --git a/services/Parser/Nodes/NodeImage.php b/services/Parser/Nodes/NodeImage.php index c74fe85..e56c858 100644 --- a/services/Parser/Nodes/NodeImage.php +++ b/services/Parser/Nodes/NodeImage.php @@ -8,11 +8,16 @@ class NodeImage extends Node { public function getData() { return [ - 'value' => $this->resolveImageUrl( $this->getValueWithDefault( $this->xmlNode ) ), + 'url' => $this->resolveImageUrl( $imageName ), + 'name' => $this->getValueWithDefault( $this->xmlNode ), 'alt' => $this->getValueWithDefault( $this->xmlNode->{self::ALT_TAG_NAME} ) ]; } + public function isEmpty( $data ) { + return !( isset( $data[ 'url' ] ) ) || empty( $data[ 'url' ] ); + } + public function resolveImageUrl( $filename ) { global $wgContLang; $title = \Title::newFromText( diff --git a/services/Parser/Nodes/NodeUnimplemented.php b/services/Parser/Nodes/NodeUnimplemented.php index a45ef81..ef79139 100644 --- a/services/Parser/Nodes/NodeUnimplemented.php +++ b/services/Parser/Nodes/NodeUnimplemented.php @@ -2,12 +2,9 @@ namespace Wikia\PortableInfobox\Parser\Nodes; class NodeUnimplemented extends Node { - public function getType() { - return parent::getType() . '(unimplemented)'; - } public function getData() { - throw new UnimplementedNodeException('Unimplemented node type'); + throw new UnimplementedNodeException( $this->getType() ); } } diff --git a/services/PortableInfoboxRenderService.class.php b/services/PortableInfoboxRenderService.class.php index d0d3c95..2e21f39 100644 --- a/services/PortableInfoboxRenderService.class.php +++ b/services/PortableInfoboxRenderService.class.php @@ -2,6 +2,7 @@ class PortableInfoboxRenderService extends WikiaService { const LOGGER_LABEL = 'portable-infobox-render-not-supported-type'; + const THUMBNAIL_WIDTH = 270; private $templates = [ 'wrapper' => 'PortableInfoboxWrapper.mustache', @@ -75,33 +76,34 @@ class PortableInfoboxRenderService extends WikiaService { * @param array $comparisonData * @return string - comparison HTML */ - private function renderComparisonItem( $comparisonData ) { + private function renderComparisonItem( $comparisonData ) + { $comparisonHTMLContent = ''; - foreach ( $comparisonData as $set ) { + foreach ($comparisonData as $set) { $setHTMLContent = ''; - if ( $set['isEmpty'] ) { + if ($set['isEmpty']) { continue; } - foreach ( $set['data']['value'] as $item ) { - $type = $item[ 'type' ]; + foreach ($set['data']['value'] as $item) { + $type = $item['type']; - if ( $item['isEmpty'] ) { + if ($item['isEmpty']) { continue; } - if ( $type === 'header' ) { + if ($type === 'header') { $setHTMLContent .= $this->renderItem( 'comparison-set-header', - [ 'content' => $this->renderItem( $type, $item[ 'data' ] ) ] + ['content' => $this->renderItem($type, $item['data'])] ); } else { - if ( $this->validateType( $type ) ) { + if ($this->validateType($type)) { $setHTMLContent .= $this->renderItem( 'comparison-set-item', - [ 'content' => $this->renderItem( $type, $item[ 'data' ] ) ] + ['content' => $this->renderItem($type, $item['data'])] ); } } @@ -110,7 +112,13 @@ class PortableInfoboxRenderService extends WikiaService { $comparisonHTMLContent .= $this->renderItem( 'comparison-set', [ 'content' => $setHTMLContent ] ); } - return $this->renderItem( 'comparison', [ 'content' => $comparisonHTMLContent ] ); + if ( !empty( $comparisonHTMLContent ) ) { + $output = $this->renderItem('comparison', [ 'content' => $comparisonHTMLContent ] ); + } else { + $output = ''; + } + + return $output; } /** @@ -145,6 +153,14 @@ class PortableInfoboxRenderService extends WikiaService { * @return string - HTML */ private function renderItem( $type, array $data ) { + //TODO: with validated the performance of render Service and in the next phase we want to refactor it (make + // it modular) While doing this we also need to move this logic to appropriate image render class + if ( $type === 'image' ) { + $data[ 'thumbnail' ] = VignetteRequest::fromUrl( $data[ 'url' ] ) + ->scaleToWidth( self::THUMBNAIL_WIDTH ) + ->url(); + } + return $this->templateEngine->clearData() ->setData( $data ) ->render( $this->templates[ $type ] ); diff --git a/styles/PortableInfobox.scss b/styles/PortableInfobox.scss index a32dd55..3726d75 100644 --- a/styles/PortableInfobox.scss +++ b/styles/PortableInfobox.scss @@ -84,23 +84,23 @@ $infobox-section-header-background: transparentize($color-links, 0.9); } } - .portable-infobox-comparision { + .portable-infobox-comparison { border-collapse: collapse; width: 100%; } - .portable-infobox-comparision-set { + .portable-infobox-comparison-set { display: block; } - .portable-infobox-comparision-set-header { + .portable-infobox-comparison-set-header { box-sizing: border-box; display: block; text-align: left; width: 100%; } - .portable-infobox-comparision-item { + .portable-infobox-comparison-item { box-sizing: border-box; vertical-align: top; width: $infobox-width / 2; diff --git a/templates/PortableInfoboxItemComparison.mustache b/templates/PortableInfoboxItemComparison.mustache index 3cc37a9..b53e40a 100644 --- a/templates/PortableInfoboxItemComparison.mustache +++ b/templates/PortableInfoboxItemComparison.mustache @@ -1,5 +1,5 @@
- +
{{{content}}}
diff --git a/templates/PortableInfoboxItemComparisonSet.mustache b/templates/PortableInfoboxItemComparisonSet.mustache index e6ddae9..0bf151d 100644 --- a/templates/PortableInfoboxItemComparisonSet.mustache +++ b/templates/PortableInfoboxItemComparisonSet.mustache @@ -1 +1 @@ -{{{content}}} +{{{content}}} diff --git a/templates/PortableInfoboxItemComparisonSetHeader.mustache b/templates/PortableInfoboxItemComparisonSetHeader.mustache index 5262a30..041ee12 100644 --- a/templates/PortableInfoboxItemComparisonSetHeader.mustache +++ b/templates/PortableInfoboxItemComparisonSetHeader.mustache @@ -1 +1 @@ -{{{content}}} +{{{content}}} diff --git a/templates/PortableInfoboxItemComparisonSetItem.mustache b/templates/PortableInfoboxItemComparisonSetItem.mustache index f71e5b9..c045bf4 100644 --- a/templates/PortableInfoboxItemComparisonSetItem.mustache +++ b/templates/PortableInfoboxItemComparisonSetItem.mustache @@ -1 +1 @@ -{{{content}}} +{{{content}}} diff --git a/templates/PortableInfoboxItemImage.mustache b/templates/PortableInfoboxItemImage.mustache index 22ae5e1..13f1dd3 100644 --- a/templates/PortableInfoboxItemImage.mustache +++ b/templates/PortableInfoboxItemImage.mustache @@ -1,5 +1,7 @@
- {{alt}} + + {{alt}} +
\ No newline at end of file diff --git a/tests/ImageFilenameSanitizerTest.php b/tests/ImageFilenameSanitizerTest.php index 3e6155b..b273ed1 100644 --- a/tests/ImageFilenameSanitizerTest.php +++ b/tests/ImageFilenameSanitizerTest.php @@ -79,6 +79,18 @@ class ImageFilenameSanitizerTest extends WikiaBaseTest { 'en', '', 'Empty file name' + ], + [ + '[[File:image.jpg|300px|lorem ipsum]]', + 'es', + 'image.jpg', + 'Link to filename with canonical namespace, width and caption on a non-EN wiki ' + ], + [ + '[[File:image.jpg|lorem ipsum]]', + 'es', + 'image.jpg', + 'Link to filename with canonical namespace and caption on a non-EN wiki ' ] ]; } diff --git a/tests/ParserNodesTest.php b/tests/ParserNodesTest.php index 7059c8d..6b66faa 100644 --- a/tests/ParserNodesTest.php +++ b/tests/ParserNodesTest.php @@ -36,7 +36,8 @@ class PortableInfoboxParserNodesTest extends WikiaBaseTest { $node = $this->getMockBuilder( 'Wikia\PortableInfobox\Parser\Nodes\NodeImage' )->setConstructorArgs( [ $xml, [ 'image2' => 'aaa.jpg', 'alt-source' => 'bbb' ] ] )->setMethods( [ 'resolveImageUrl' ] )->getMock(); $node->expects( $this->any() )->method( 'resolveImageUrl' )->will( $this->returnValue( 'aaa.jpg' ) ); - $this->assertTrue( $node->getData()[ 'value' ] == 'aaa.jpg', 'value is not aaa.jpg' ); + $this->assertTrue( $node->getData()[ 'url' ] == 'aaa.jpg', 'value is not aaa.jpg' ); + $this->assertTrue( $node->getData()[ 'name' ] == 'aaa.jpg', 'value is not aaa.jpg' ); $this->assertTrue( $node->getData()[ 'alt' ] == 'bbb', 'alt is not bbb' ); $this->assertTrue( $nodeDefault->getData()[ 'alt' ] == 'default-alt', 'default alt' ); } diff --git a/tests/PortableInfoboxRenderServiceTest.php b/tests/PortableInfoboxRenderServiceTest.php index 43a12bb..808f39b 100644 --- a/tests/PortableInfoboxRenderServiceTest.php +++ b/tests/PortableInfoboxRenderServiceTest.php @@ -81,6 +81,20 @@ class PortableInfoboxRenderServiceTest extends PHPUnit_Framework_TestCase { 'output' => '', 'description' => 'Only image' ], + [ + 'input' => [ + [ + 'type' => 'pair', + 'data' => [ + 'label' => 'test label', + 'value' => 'test value' + ], + 'isEmpty' => false + ] + ], + 'output' => '', + 'description' => 'Only pair' + ], [ 'input' => [ [ @@ -135,6 +149,289 @@ class PortableInfoboxRenderServiceTest extends PHPUnit_Framework_TestCase { ], 'output' => '', 'description' => 'Simple infobox with title, empty image and key-value pair' + ], + [ + 'input' => [ + [ + 'type' => 'title', + 'data' => [ + 'value' => 'Test Title' + ], + 'isEmpty' => false + ], + [ + 'type' => 'image', + 'data' => [ + 'alt' => 'image alt', + 'value' => 'http://image.jpg' + ], + 'isEmpty' => false + ], + [ + 'type' => 'pair', + 'data' => [], + 'isEmpty' => true + ] + ], + 'output' => '', + 'description' => 'Simple infobox with title, image and empty key-value pair' + ], + [ + 'input' => [ + [ + 'type' => 'title', + 'data' => [ + 'value' => 'Test Title' + ], + 'isEmpty' => false + ], + [ + 'type' => 'image', + 'data' => [ + 'alt' => 'image alt', + 'value' => 'http://image.jpg' + ], + 'isEmpty' => false + ], + [ + 'type' => 'group', + 'data' => [ + 'value' => [ + [ + 'type' => 'header', + 'data' => [ + 'value' => 'Test Header' + ], + 'isEmpty' => false + ], + [ + 'type' => 'pair', + 'data' => [ + 'label' => 'test label', + 'value' => 'test value' + ], + 'isEmpty' => false, + ], + [ + 'type' => 'pair', + 'data' => [ + 'label' => 'test label', + 'value' => 'test value' + ], + 'isEmpty' => false + ] + ] + ], + 'isEmpty' => false + ] + ], + 'output' => '', + 'description' => 'Infobox with title, image and group with header two key-value pairs' + ], + [ + 'input' => [ + [ + 'type' => 'title', + 'data' => [ + 'value' => 'Test Title' + ], + 'isEmpty' => false + ], + [ + 'type' => 'image', + 'data' => [ + 'alt' => 'image alt', + 'value' => 'http://image.jpg' + ], + 'isEmpty' => false + ], + [ + 'type' => 'group', + 'data' => [ + 'value' => [ + [ + 'type' => 'header', + 'data' => [ + 'value' => 'Test Header' + ], + 'isEmpty' => false + ], + ] + ], + 'isEmpty' => true + ] + ], + 'output' => '', + 'description' => 'Infobox with title, image and empty group with header' + ], + [ + 'input' => [ + [ + 'type' => 'comparison', + 'data' => [ + 'value' => [ + [ + 'type' => 'set', + 'data' => [], + 'isEmpty' => true + ], + [ + 'type' => 'set', + 'data' => [], + 'isEmpty' => true + ], + ], + ], + 'isEmpty' => true + ] + ], + 'output' => '', + 'description' => 'Infobox with empty comparison' + ], + [ + 'input' => [ + [ + 'type' => 'comparison', + 'data' => [ + 'value' => [ + [ + 'type' => 'set', + 'data' => [], + 'isEmpty' => true + ], + [ + 'type' => 'set', + 'data' => [ + 'value' => [ + [ + 'type' => 'header', + 'data' => [ + 'value' => 'Test Header' + ], + 'isEmpty' => false + ], + [ + 'type' => 'pair', + 'data' => [ + 'label' => 'test label', + 'value' => 'test value' + ], + 'isEmpty' => false, + ], + [ + 'type' => 'pair', + 'data' => [ + 'label' => 'test label', + 'value' => 'test value' + ], + 'isEmpty' => false + ] + ] + ], + 'isEmpty' => false + ], + ], + ], + 'isEmpty' => false + ] + ], + 'output' => '', + 'description' => 'Infobox with comparison with two sets of which one is empty' + ], + [ + 'input' => [ + [ + 'type' => 'footer', + 'data' => [], + 'isEmpty' => true + ] + ], + 'output' => '', + 'description' => 'Infobox with empty footer' + ], + [ + 'input' => [ + [ + 'type' => 'footer', + 'data' => [ + 'links' => '

Links

' + ], + 'isEmpty' => false + ] + ], + 'output' => '', + 'description' => 'Infobox with footer' ] ]; }