<commit_before><?php
namespace wcf\system\html\input\node;
use wcf\data\smiley\Smiley;
use wcf\data\smiley\SmileyCache;
use wcf\system\bbcode\BBCodeHandler;
use wcf\system\bbcode\HtmlBBCodeParser;
use wcf\system\html\node\AbstractHtmlNodeProcessor;
use wcf\util\DOMUtil;
use wcf\util\JSON;

/**
 * Processes `<img>` to handle embedded attachments.
 * 
 * @author      <NAME>
 * @copyright	2001-2019 WoltLab GmbH
 * @license     GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
 * @package     WoltLabSuite\Core\System\Html\Input\Node
 * @since       3.0
 */
class HtmlInputNodeImg extends AbstractHtmlInputNode {
	/**
	 * number of found smilies
	 * @var integer
	 */
	protected $smiliesFound = 0;
	
	/**
	 * @inheritDoc
	 */
	protected $tagName = 'img';
	
	/**
	 * @inheritDoc
	 */
	public function isAllowed(AbstractHtmlNodeProcessor $nodeProcessor) {
		if (BBCodeHandler::getInstance()->isAvailableBBCode('img')) {
			return [];
		}
		
		$foundImage = false;
		
		// check if there are only attachments, media or smilies
		/** @var \DOMElement $element */
		foreach ($nodeProcessor->getDocument()->getElementsByTagName('img') as $element) {
			$class = $element->getAttribute('class');
			if (!preg_match('~\b(?:woltlabAttachment|woltlabSuiteMedia|smiley)\b~', $class)) {
				$foundImage = true;
				break;
			}
		}
		
		if (!$foundImage) {
			return [];
		}
		
		return ['img'];
	}
	
	/**
	 * @inheritDoc
	 */
	public function process(array $elements, AbstractHtmlNodeProcessor $htmlNodeProcessor) {
		$this->smiliesFound = 0;
		
		/** @var \DOMElement $element */
		foreach ($elements as $element) {
			$class = $element->getAttribute('class');
			if (preg_match('~\bwoltlabAttachment\b~', $class)) {
				$this->handleAttachment($element, $class);
			}
			else if (preg_match('~\bwoltlabSuiteMedia\b~', $class)) {
				$this->handleMedium($element, $class);
			}
			else if (preg_match('~\bsmiley\b~', $class)) {
				$this->handleSmiley($element);
			}
		}
	}
	
	/**
	 * Returns the number of smilies found within the message.
	 * 
	 * @return      integer
	 */
	public function getSmileyCount() {
		return $this->smiliesFound;
	}
	
	/**
	 * Replaces image element with attachment metacode element. 
	 * 
	 * @param	\DOMElement	$element
	 * @param	string		$class
	 */
	protected function handleAttachment(\DOMElement $element, $class) {
		$attachmentID = intval($element->getAttribute('data-attachment-id'));
		if (!$attachmentID) {
			return;
		}
		
		$float = 'none';
		$thumbnail = false;
		
		if (strpos($element->getAttribute('src'), 'thumbnail=1') !== false) {
			$thumbnail = true;
		}
		
		if (preg_match('~\bmessageFloatObject(?P<float>Left|Right)\b~', $class, $matches)) {
			$float = ($matches['float'] === 'Left') ? 'left' : 'right';
		}
		
		$attributes = [
			$attachmentID,
			$float,
			$thumbnail
		];
		
		$newElement = $element->ownerDocument->createElement('woltlab-metacode');
		$newElement->setAttribute('data-name', 'attach');
		$newElement->setAttribute('data-attributes', base64_encode(JSON::encode($attributes)));
		DOMUtil::replaceElement($element, $newElement, false);
	}
	
	/**
	 * Replaces image element with media metacode element.
	 * 
	 * @param	\DOMElement	$element
	 * @param	string		$class
	 */
	protected function handleMedium(\DOMElement $element, $class) {
		$mediumID = intval($element->getAttribute('data-media-id'));
		if (!$mediumID) {
			return;
		}
		
		$float = 'none';
		$thumbnail = 'original';
		
		if (preg_match('~thumbnail=(?P<thumbnail>tiny|small|large|medium)\b~', $element->getAttribute('src'), $matches)) {
			$thumbnail = $matches['thumbnail'];
		}
		
		if (preg_match('~\bmessageFloatObject(?P<float>Left|Right)\b~', $class, $matches)) {
			$float = ($matches['float'] === 'Left') ? 'left' : 'right';
		}
		
		$attributes = [
			$mediumID,
			$thumbnail,
			$float
		];
		
		$newElement = $element->ownerDocument->createElement('woltlab-metacode');
		$newElement->setAttribute('data-name', 'wsm');
		$newElement->setAttribute('data-attributes', base64_encode(JSON::encode($attributes)));
		DOMUtil::replaceElement($element, $newElement, false);
		
		// The media bbcode is a block element that may not be placed inside inline elements.
		$parent = $newElement;
		$blockLevelParent = null;
		$blockElements = HtmlBBCodeParser::getInstance()->getBlockBBCodes();
		while ($parent = $parent->parentNode) {
			switch ($parent->nodeName) {
				case 'a':
					// Permit the media element to be placed inside a link.
					break 2;
				
				case 'blockquote':
				case 'body':
				case 'code':
				case 'div':
				case 'p':
				case 'td':
				case 'woltlab-quote':
				case 'woltlab-spoiler':
					$blockLevelParent = $parent;
					break 2;
				
				case 'woltlab-metacode':
					if (in_array($parent->getAttribute('data-name'), $blockElements)) {
						$blockLevelParent = $parent;
						break 2;
					}
					break;
			}<commit_msg>Permit `wsm` to be placed inside `<li>`<commit_after><?php
namespace wcf\system\html\input\node;
use wcf\data\smiley\Smiley;
use wcf\data\smiley\SmileyCache;
use wcf\system\bbcode\BBCodeHandler;
use wcf\system\bbcode\HtmlBBCodeParser;
use wcf\system\html\node\AbstractHtmlNodeProcessor;
use wcf\util\DOMUtil;
use wcf\util\JSON;

/**
 * Processes `<img>` to handle embedded attachments.
 * 
 * @author      <NAME>
 * @copyright	2001-2019 WoltLab GmbH
 * @license     GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
 * @package     WoltLabSuite\Core\System\Html\Input\Node
 * @since       3.0
 */
class HtmlInputNodeImg extends AbstractHtmlInputNode {
	/**
	 * number of found smilies
	 * @var integer
	 */
	protected $smiliesFound = 0;
	
	/**
	 * @inheritDoc
	 */
	protected $tagName = 'img';
	
	/**
	 * @inheritDoc
	 */
	public function isAllowed(AbstractHtmlNodeProcessor $nodeProcessor) {
		if (BBCodeHandler::getInstance()->isAvailableBBCode('img')) {
			return [];
		}
		
		$foundImage = false;
		
		// check if there are only attachments, media or smilies
		/** @var \DOMElement $element */
		foreach ($nodeProcessor->getDocument()->getElementsByTagName('img') as $element) {
			$class = $element->getAttribute('class');
			if (!preg_match('~\b(?:woltlabAttachment|woltlabSuiteMedia|smiley)\b~', $class)) {
				$foundImage = true;
				break;
			}
		}
		
		if (!$foundImage) {
			return [];
		}
		
		return ['img'];
	}
	
	/**
	 * @inheritDoc
	 */
	public function process(array $elements, AbstractHtmlNodeProcessor $htmlNodeProcessor) {
		$this->smiliesFound = 0;
		
		/** @var \DOMElement $element */
		foreach ($elements as $element) {
			$class = $element->getAttribute('class');
			if (preg_match('~\bwoltlabAttachment\b~', $class)) {
				$this->handleAttachment($element, $class);
			}
			else if (preg_match('~\bwoltlabSuiteMedia\b~', $class)) {
				$this->handleMedium($element, $class);
			}
			else if (preg_match('~\bsmiley\b~', $class)) {
				$this->handleSmiley($element);
			}
		}
	}
	
	/**
	 * Returns the number of smilies found within the message.
	 * 
	 * @return      integer
	 */
	public function getSmileyCount() {
		return $this->smiliesFound;
	}
	
	/**
	 * Replaces image element with attachment metacode element. 
	 * 
	 * @param	\DOMElement	$element
	 * @param	string		$class
	 */
	protected function handleAttachment(\DOMElement $element, $class) {
		$attachmentID = intval($element->getAttribute('data-attachment-id'));
		if (!$attachmentID) {
			return;
		}
		
		$float = 'none';
		$thumbnail = false;
		
		if (strpos($element->getAttribute('src'), 'thumbnail=1') !== false) {
			$thumbnail = true;
		}
		
		if (preg_match('~\bmessageFloatObject(?P<float>Left|Right)\b~', $class, $matches)) {
			$float = ($matches['float'] === 'Left') ? 'left' : 'right';
		}
		
		$attributes = [
			$attachmentID,
			$float,
			$thumbnail
		];
		
		$newElement = $element->ownerDocument->createElement('woltlab-metacode');
		$newElement->setAttribute('data-name', 'attach');
		$newElement->setAttribute('data-attributes', base64_encode(JSON::encode($attributes)));
		DOMUtil::replaceElement($element, $newElement, false);
	}
	
	/**
	 * Replaces image element with media metacode element.
	 * 
	 * @param	\DOMElement	$element
	 * @param	string		$class
	 */
	protected function handleMedium(\DOMElement $element, $class) {
		$mediumID = intval($element->getAttribute('data-media-id'));
		if (!$mediumID) {
			return;
		}
		
		$float = 'none';
		$thumbnail = 'original';
		
		if (preg_match('~thumbnail=(?P<thumbnail>tiny|small|large|medium)\b~', $element->getAttribute('src'), $matches)) {
			$thumbnail = $matches['thumbnail'];
		}
		
		if (preg_match('~\bmessageFloatObject(?P<float>Left|Right)\b~', $class, $matches)) {
			$float = ($matches['float'] === 'Left') ? 'left' : 'right';
		}
		
		$attributes = [
			$mediumID,
			$thumbnail,
			$float
		];
		
		$newElement = $element->ownerDocument->createElement('woltlab-metacode');
		$newElement->setAttribute('data-name', 'wsm');
		$newElement->setAttribute('data-attributes', base64_encode(JSON::encode($attributes)));
		DOMUtil::replaceElement($element, $newElement, false);
		
		// The media bbcode is a block element that may not be placed inside inline elements.
		$parent = $newElement;
		$blockLevelParent = null;
		$blockElements = HtmlBBCodeParser::getInstance()->getBlockBBCodes();
		while ($parent = $parent->parentNode) {
			switch ($parent->nodeName) {
				case 'a':
					// Permit the media element to be placed inside a link.
					break 2;
				
				case 'blockquote':
				case 'body':
				case 'code':
				case 'div':
				case 'li':
				case 'p':
				case 'td':
				case 'woltlab-quote':
				case 'woltlab-spoiler':
					$blockLevelParent = $parent;
					break 2;
				
				case 'woltlab-metacode':
					if (in_array($parent->getAttribute('data-name'), $blockElements)) {
						$blockLevelParent = $parent;
						break 2;
					}
					break;
			}
{'fraction_non_alphanumeric': 0.16523322877668725, 'fraction_numerical': 0.0040473540422948494, 'mean_word_length': 3.7134000953743445, 'pattern_counts': {'":': 0, '<': 18, '<?xml version=': 0, '>': 68, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2499979', 'n_tokens_mistral': 3806, 'n_tokens_neox': 3200, 'n_words': 660}