Skip to content

Commit

Permalink
[FEATURE] Introduce a TagViewHelperTrait
Browse files Browse the repository at this point in the history
Contains assistance functions for ViewHelpers that use the tag builder to make tags.
  • Loading branch information
NamelessCoder committed Mar 5, 2015
1 parent 026b45b commit 7def7c1
Show file tree
Hide file tree
Showing 8 changed files with 155 additions and 92 deletions.
120 changes: 120 additions & 0 deletions Classes/Traits/TagViewHelperTrait.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
<?php
namespace FluidTYPO3\Vhs\Traits;

/*
* This file is part of the FluidTYPO3/Vhs project under GPLv2 or later.
*
* For the full copyright and license information, please read the
* LICENSE.md file that was distributed with this source code.
*/

/**
* Class TagViewHelperTrait
*
* Trait implemented by ViewHelpers which require access
* to functions dealing with tag generation.
*
* Has the following main responsibilities:
*
* - register additional HTML5-specific attributes for tag
* based ViewHelpers
* - custom rendering method which applies those attributes.
*/
trait TagViewHelperTrait {

/**
* Default implementation to register only the tag
* arguments along with universal attributes.
*
* @return void
*/
public function registerArguments() {
$this->registerUniversalTagAttributes();
}

/**
* Registers all standard and HTML5 universal attributes.
* Should be used inside registerArguments();
*
* @return void
* @api
*/
protected function registerUniversalTagAttributes() {
parent::registerUniversalTagAttributes();
$this->registerArgument('forceClosingTag', 'boolean', 'If TRUE, forces the created tag to use a closing tag. If FALSE, allows self-closing tags.', FALSE, FALSE);
$this->registerArgument('hideIfEmpty', 'boolean', 'Hide the tag completely if there is no tag content', FALSE, FALSE);
$this->registerTagAttribute('contenteditable', 'string', 'Specifies whether the contents of the element are editable.');
$this->registerTagAttribute('contextmenu', 'string', 'The value of the id attribute on the menu with which to associate the element as a context menu.');
$this->registerTagAttribute('draggable', 'string', 'Specifies whether the element is draggable.');
$this->registerTagAttribute('dropzone', 'string', 'Specifies what types of content can be dropped on the element, and instructs the UA about which actions to take with content when it is dropped on the element.');
$this->registerTagAttribute('translate', 'string', 'Specifies whether an element’s attribute values and contents of its children are to be translated when the page is localized, or whether to leave them unchanged.');
$this->registerTagAttribute('spellcheck', 'string', 'Specifies whether the element represents an element whose contents are subject to spell checking and grammar checking.');
$this->registerTagAttribute('hidden', 'string', 'Specifies that the element represents an element that is not yet, or is no longer, relevant.');
}

/**
* Renders the provided tag with the given name and any
* (additional) attributes not already provided as arguments.
*
* @param string $tagName
* @param mixed $content
* @param array $attributes
* @param array $nonEmptyAttributes
* @return string
*/
protected function renderTag($tagName, $content, array $attributes = array(), array $nonEmptyAttributes = array('id', 'class')) {
$trimmedContent = trim($content);
if (TRUE === empty($trimmedContent) && TRUE === (boolean) $this->arguments['hideIfEmpty']) {
return '';
}
if ('none' === $tagName || TRUE === empty($tagName)) {
// skip building a tag if special keyword "none" is used, or tag name is empty
return $trimmedContent;
}
$this->tag->setTagName($tagName);
$this->tag->addAttributes($attributes);
$this->tag->forceClosingTag($forceClosingTag);
$this->tag->setContent($content);
// process some attributes differently - if empty, remove the property:
foreach ($nonEmptyAttributes as $propertyName) {
$value = $this->arguments[$propertyName];
if (TRUE === empty($value)) {
$this->tag->removeAttribute($propertyName);
} else {
$this->tag->addAttribute($propertyName, $value);
}
}
return $this->tag->render();
}

/**
* Renders the provided tag and optionally appends or prepends
* it to the main tag's content depending on 'mode' which can
* be one of 'none', 'append' or 'prepend'
*
* @param string $tagName
* @param array $attributes
* @param boolean $forceClosingTag
* @param string $mode
* @return string
*/
protected function renderChildTag($tagName, $attributes = array(), $forceClosingTag = FALSE, $mode = 'none') {
$tagBuilder = clone $this->tag;
$tagBuilder->reset();
$tagBuilder->setTagName($tagName);
$tagBuilder->addAttributes($attributes);
$tagBuilder->forceClosingTag($forceClosingTag);
$childTag = $tagBuilder->render();
if ('append' === $mode || 'prepend' === $mode) {
$content = $this->tag->getContent();
if ('append' === $mode) {
$content = $content . $childTag;
} else {
$content = $childTag . $content;
}
$this->tag->setContent($content);
}
return $childTag;
}

}
51 changes: 3 additions & 48 deletions Classes/ViewHelpers/Media/AbstractMediaTagViewHelper.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
* LICENSE.md file that was distributed with this source code.
*/

use FluidTYPO3\Vhs\Traits\TagViewHelperTrait;

/**
* Base class for media related tag based view helpers which mostly
* adds HTML5 tag attributes.
Expand All @@ -18,53 +20,6 @@
*/
abstract class AbstractMediaTagViewHelper extends AbstractMediaViewHelper {

/**
* Registers all standard and HTML5 universal attributes.
* Should be used inside registerArguments();
*
* @return void
* @api
*/
protected function registerUniversalTagAttributes() {
parent::registerUniversalTagAttributes();
$this->registerTagAttribute('contenteditable', 'string', 'Specifies whether the contents of the element are editable.');
$this->registerTagAttribute('contextmenu', 'string', 'The value of the id attribute on the menu with which to associate the element as a context menu.');
$this->registerTagAttribute('draggable', 'string', 'Specifies whether the element is draggable.');
$this->registerTagAttribute('dropzone', 'string', 'Specifies what types of content can be dropped on the element, and instructs the UA about which actions to take with content when it is dropped on the element.');
$this->registerTagAttribute('translate', 'string', 'Specifies whether an element’s attribute values and contents of its children are to be translated when the page is localized, or whether to leave them unchanged.');
$this->registerTagAttribute('spellcheck', 'string', 'Specifies whether the element represents an element whose contents are subject to spell checking and grammar checking.');
$this->registerTagAttribute('hidden', 'string', 'Specifies that the element represents an element that is not yet, or is no longer, relevant.');
}

/**
* Renders the provided tag and optionally appends or prepends
* it to the main tag's content depending on 'mode' which can
* be one of 'none', 'append' or 'prepend'
*
* @param string $tagName
* @param array $attributes
* @param boolean $forceClosingTag
* @param string $mode
* @return string
*/
public function renderChildTag($tagName, $attributes = array(), $forceClosingTag = FALSE, $mode = 'none') {
$tagBuilder = clone $this->tag;
$tagBuilder->reset();
$tagBuilder->setTagName($tagName);
$tagBuilder->addAttributes($attributes);
$tagBuilder->forceClosingTag($forceClosingTag);
$childTag = $tagBuilder->render();
unset($tagBuilder);
if ('append' === $mode || 'prepend' === $mode) {
$content = $this->tag->getContent();
if ('append' === $mode) {
$content = $content . $childTag;
} else {
$content = $childTag . $content;
}
$this->tag->setContent($content);
}
return $childTag;
}
use TagViewHelperTrait;

}
5 changes: 4 additions & 1 deletion Classes/ViewHelpers/Media/AudioViewHelper.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
* LICENSE.md file that was distributed with this source code.
*/

use FluidTYPO3\Vhs\Traits\TagViewHelperTrait;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Fluid\Core\ViewHelper\Exception;

Expand All @@ -26,7 +27,9 @@
* @package Vhs
* @subpackage ViewHelpers\Media
*/
class AudioViewHelper extends AbstractMediaTagViewHelper {
class AudioViewHelper extends AbstractMediaViewHelper {

use TagViewHelperTrait;

/**
* @var string
Expand Down
5 changes: 4 additions & 1 deletion Classes/ViewHelpers/Media/VideoViewHelper.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
* LICENSE.md file that was distributed with this source code.
*/

use FluidTYPO3\Vhs\Traits\TagViewHelperTrait;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Fluid\Core\ViewHelper\Exception;

Expand All @@ -26,7 +27,9 @@
* @package Vhs
* @subpackage ViewHelpers\Media
*/
class VideoViewHelper extends AbstractMediaTagViewHelper {
class VideoViewHelper extends AbstractMediaViewHelper {

use TagViewHelperTrait;

/**
* @var string
Expand Down
5 changes: 4 additions & 1 deletion Classes/ViewHelpers/Page/Header/LinkViewHelper.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
* LICENSE.md file that was distributed with this source code.
*/

use FluidTYPO3\Vhs\Traits\TagViewHelperTrait;
use TYPO3\CMS\Fluid\Core\ViewHelper\AbstractTagBasedViewHelper;

/**
Expand All @@ -19,6 +20,8 @@
*/
class LinkViewHelper extends AbstractTagBasedViewHelper {

use TagViewHelperTrait;

/**
* @var string
*/
Expand Down Expand Up @@ -46,7 +49,7 @@ public function render() {
if ('BE' === TYPO3_MODE) {
return;
}
$GLOBALS['TSFE']->getPageRenderer()->addMetaTag($this->tag->render());
$GLOBALS['TSFE']->getPageRenderer()->addMetaTag($this->renderTag($this->tagName));
}

}
5 changes: 4 additions & 1 deletion Classes/ViewHelpers/Page/Header/MetaViewHelper.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
* LICENSE.md file that was distributed with this source code.
*/

use FluidTYPO3\Vhs\Traits\TagViewHelperTrait;
use TYPO3\CMS\Fluid\Core\ViewHelper\AbstractTagBasedViewHelper;

/**
Expand All @@ -22,6 +23,8 @@
*/
class MetaViewHelper extends AbstractTagBasedViewHelper {

use TagViewHelperTrait;

/**
* @var string
*/
Expand Down Expand Up @@ -51,7 +54,7 @@ public function render() {
return;
}
if (TRUE === isset($this->arguments['content']) && FALSE === empty($this->arguments['content'])) {
$GLOBALS['TSFE']->getPageRenderer()->addMetaTag($this->tag->render());
$GLOBALS['TSFE']->getPageRenderer()->addMetaTag($this->renderTag($this->tagName));
}
}

Expand Down
17 changes: 10 additions & 7 deletions Classes/ViewHelpers/Page/Menu/AbstractMenuViewHelper.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
*/

use FluidTYPO3\Vhs\Service\PageSelectService;
use FluidTYPO3\Vhs\Traits\TagViewHelperTrait;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Fluid\Core\ViewHelper\AbstractTagBasedViewHelper;
use TYPO3\CMS\Frontend\Page\PageRepository;
Expand All @@ -23,6 +24,8 @@
*/
abstract class AbstractMenuViewHelper extends AbstractTagBasedViewHelper {

use TagViewHelperTrait;

/**
* @var string
*/
Expand Down Expand Up @@ -628,24 +631,24 @@ public function renderContent($menu) {
if (0 === count($menu) && FALSE === $deferredRendering) {
return NULL;
}
$this->tag->setTagName($this->getWrappingTagName());
$this->tag->forceClosingTag(TRUE);
if (TRUE === $deferredRendering) {
$tagContent = $this->autoRender($menu);
$this->tag->setContent($tagContent);
$deferredContent = $this->tag->render();
$this->viewHelperVariableContainer->addOrUpdate('FluidTYPO3\Vhs\ViewHelpers\Page\Menu\AbstractMenuViewHelper', 'deferredString', $deferredContent);
$this->viewHelperVariableContainer->addOrUpdate('FluidTYPO3\Vhs\ViewHelpers\Page\Menu\AbstractMenuViewHelper', 'deferredArray', $menu);
$this->viewHelperVariableContainer->addOrUpdate(
'FluidTYPO3\Vhs\ViewHelpers\Page\Menu\AbstractMenuViewHelper', 'deferredString', $deferredContent
);
$this->viewHelperVariableContainer->addOrUpdate(
'FluidTYPO3\Vhs\ViewHelpers\Page\Menu\AbstractMenuViewHelper', 'deferredArray', $menu
);
$output = $this->renderChildren();
$this->unsetDeferredVariableStorage();
} else {
$content = $this->renderChildren();
if (0 < strlen(trim($content))) {
$output = $content;
} else {
$tagContent = $this->autoRender($menu);
$this->tag->setContent($tagContent);
$output = $this->tag->render();
$output = $this->renderTag($this->getWrappingTagName(), $this->autoRender($menu));
}
}
return $output;
Expand Down
39 changes: 6 additions & 33 deletions Classes/ViewHelpers/TagViewHelper.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
* LICENSE.md file that was distributed with this source code.
*/

use FluidTYPO3\Vhs\Traits\TagViewHelperTrait;
use TYPO3\CMS\Fluid\Core\ViewHelper\AbstractTagBasedViewHelper;

/**
Expand All @@ -22,53 +23,25 @@
*/
class TagViewHelper extends AbstractTagBasedViewHelper {

use TagViewHelperTrait;

/**
* @return void
*/
public function initializeArguments() {
parent::initializeArguments();
$this->registerUniversalTagAttributes();
$this->registerArgument('name', 'string', 'Tag name', TRUE);
$this->registerArgument('hideIfEmpty', 'boolean', 'Hide the tag completely if there is no tag content', FALSE, FALSE);
}

/**
* @return string
*/
public function render() {
$this->arguments['class'] = trim($this->arguments['class']);
$this->arguments['class'] = trim((string) $this->arguments['class']);
$this->arguments['class'] = str_replace(',', ' ', $this->arguments['class']);
$content = $this->renderChildren();
$trimmedContent = trim($content);
if (TRUE === empty($trimmedContent) && TRUE === (boolean) $this->arguments['hideIfEmpty']) {
return '';
}
if ('none' === $this->arguments['name'] || TRUE === empty($this->arguments['name'])) {
// skip building a tag if special keyword "none" is used, or tag name is empty
return $content;
}
// process a few key variables to support values coming from TCEforms storage:
if (FALSE === empty($this->arguments['class'])) {
$class = str_replace(',', ' ', $this->arguments['class']);
$this->tag->addAttribute('class', $class);
}
$this->tag->setTagName($this->arguments['name']);
$this->tag->setContent($content);
return $this->tag->render();
}

/**
* @param array $attributes
* @return void
*/
protected function applyAttributes($attributes) {
if (NULL === $attributes) {
return;
}
foreach ($attributes as $attributeName => $attributeValue) {
if ('none' !== $attributeValue && (FALSE === empty($attributeValue) || 0 === $attributeValue || '0' === $attributeValue)) {
$this->tag->addAttribute($attributeName, $attributeValue);
}
}
return $this->renderTag($this->arguments['name'], $content);
}

}

0 comments on commit 7def7c1

Please sign in to comment.