<commit_before><?php
require_once('../application/displayblock.class.inc.php');
/**
 * This class manages the special template format used internally to build the iTop web pages
 */
class DisplayTemplate
{
	protected $m_sTemplate;
	protected $m_aTags;
	static protected $iBlockCount = 0;
	
	public function __construct($sTemplate)
	{
		$this->m_aTags = array('itopblock', 'itoptabs', 'itoptab', 'itoptoggle');
		$this->m_sTemplate = $sTemplate;
	}
	
	public function Render(web_page $oPage, $aParams = array())
	{
		$this->m_sTemplate = MetaModel::ApplyParams($this->m_sTemplate, $aParams);
		$iStart = 0;
		$iEnd = strlen($this->m_sTemplate);
		$iCount = 0;
		$iBeforeTagPos = $iStart;
		$iAfterTagPos = $iStart;
		while($sTag = $this->GetNextTag($iStart, $iEnd))
		{
			$sContent = $this->GetTagContent($sTag, $iStart, $iEnd);
			$iAfterTagPos = $iEnd + strlen('</'.$sTag.'>');
			$sOuterTag = substr($this->m_sTemplate, $iStart, $iAfterTagPos - $iStart);
			$oPage->add(substr($this->m_sTemplate, $iBeforeTagPos, $iStart - $iBeforeTagPos));
			if ($sTag == DisplayBlock::TAG_BLOCK)
			{
				$oBlock = DisplayBlock::FromTemplate($sOuterTag);
				if (is_object($oBlock))
				{
					$oBlock->Display($oPage, 'block_'.self::$iBlockCount);
				}
				self::$iBlockCount++;
			}
			else
			{
				$aAttributes = $this->GetTagAttributes($sTag, $iStart, $iEnd);
				//$oPage->p("Tag: $sTag - ($iStart, $iEnd)");
				$this->RenderTag($oPage, $sTag, $aAttributes, $sContent);
	
			}
			$iAfterTagPos = $iEnd + strlen('</'.$sTag.'>');
			$iBeforeTagPos = $iAfterTagPos;
			$iStart = $iEnd;
			$iEnd = strlen($this->m_sTemplate); 
			$iCount++;
			if ($iCount > 10) break; //@@@ Why ?? Debug ??
		}
		$oPage->add(substr($this->m_sTemplate, $iAfterTagPos));
	}
	
	public function GetNextTag(&$iStartPos, &$iEndPos)
	{
		$iChunkStartPos = $iStartPos;
		$sNextTag = null;
		$iStartPos = $iEndPos;
		foreach($this->m_aTags as $sTag)
		{
			// Search for the opening tag
			$iOpeningPos = stripos($this->m_sTemplate, '<'.$sTag.' ', $iChunkStartPos);
			if ($iOpeningPos === false)
			{
				$iOpeningPos = stripos($this->m_sTemplate, '<'.$sTag.'>', $iChunkStartPos);
			}
			if ($iOpeningPos !== false)
			{
				$iClosingPos = stripos($this->m_sTemplate, '</'.$sTag.'>', $iOpeningPos);
			}
			if ( ($iOpeningPos !== false) && ($iClosingPos !== false))
			{
				if ($iOpeningPos < $iStartPos)
				{
					// This is the next tag
					$iStartPos = $iOpeningPos;
					$iEndPos = $iClosingPos;
					$sNextTag = $sTag;
				}
			}
		}
		return $sNextTag;
	}
	
	public function GetTagContent($sTag, $iStartPos, $iEndPos)
	{
		$sContent  = "";
		$iContentStart = strpos($this->m_sTemplate, '>', $iStartPos); // Content of tag start immediatly after the first closing bracket
		if ($iContentStart !== false)
		{
			$sContent = substr($this->m_sTemplate, 1+$iContentStart, $iEndPos - $iContentStart - 1);
		}
		return $sContent;
	}

	public function GetTagAttributes($sTag, $iStartPos, $iEndPos)
	{
		$aAttr  = array();
		$iAttrStart = strpos($this->m_sTemplate, ' ', $iStartPos); // Attributes start just after the first space
		$iAttrEnd = strpos($this->m_sTemplate, '>', $iStartPos); // Attributes end just before the first closing bracket
		if ( ($iAttrStart !== false) && ($iAttrEnd !== false) && ($iAttrEnd > $iAttrStart))
		{
			$sAttributes = substr($this->m_sTemplate, 1+$iAttrStart, $iAttrEnd - $iAttrStart - 1);
			$aAttributes = explode(' ', $sAttributes);
			foreach($aAttributes as $sAttr)
			{
				if ( preg_match('/(.+) *= *"(.+)"$/', $sAttr, $aMatches) )
				{
					$aAttr[strtolower($aMatches[1])] = $aMatches[2];
				}
			}
		}
		return $aAttr;
	}
	
	protected function RenderTag($oPage, $sTag, $aAttributes, $sContent)
	{
		static $iTabContainerCount = 0;
		switch($sTag)
		{
			case 'itoptabs':
				$oPage->AddTabContainer('Tabs_'.$iTabContainerCount);
				$oPage->SetCurrentTabContainer('Tabs_'.$iTabContainerCount);
				$iTabContainerCount++;
				//$oPage->p('Content:<pre>'.htmlentities($sContent).'</pre>');
				$oTemplate = new DisplayTemplate($sContent);
				$oTemplate->Render($oPage, array()); // no params to apply, they have already been applied
				$oPage->SetCurrentTabContainer('');
			break;
			
			case 'itoptab':
				$oPage->SetCurrentTab(str_replace('_', ' ', $aAttributes['name']));
				$oTemplate = new DisplayTemplate($sContent);
				$oTemplate->Render($oPage, array()); // no params to apply, they have already been applied
				//$oPage->p('iTop Tab Content:<pre>'.htmlentities($sContent).'</pre>');
				$oPage->SetCurrentTab('');
			break;
			
			case 'itoptoggle':
				$oPage->StartCollapsibleSection($aAttributes['name']);
				$oTemplate = new DisplayTemplate($sContent);
				$oTemplate->Render($oPage, array()); // no params to apply, they have already been applied
				//$oPage->p('iTop Tab Content:<pre>'.htmlentities($sContent).'</pre>');
				$oPage->EndCollapsibleSection();
			break;
			
			case 'itopblock': // No longer used, handled by DisplayBlock::FromTemplate see above
				$oPage->add("<!-- Application Error: should be handled by DisplayBlock::FromTemplate -->");
			break;
			
			default:
				// Unknown tag, just ignore it or now -- output an HTML comment
				$oPage->add("<!-- unsupported tag: $sTag -->");
		}
	}<commit_msg>Cosmetic bug fix: the triangle image of the collapsible section was not displayed properly if the "section" was initially open.<commit_after><?php
require_once('../application/displayblock.class.inc.php');
/**
 * This class manages the special template format used internally to build the iTop web pages
 */
class DisplayTemplate
{
	protected $m_sTemplate;
	protected $m_aTags;
	static protected $iBlockCount = 0;
	
	public function __construct($sTemplate)
	{
		$this->m_aTags = array('itopblock', 'itoptabs', 'itoptab', 'itoptoggle');
		$this->m_sTemplate = $sTemplate;
	}
	
	public function Render(web_page $oPage, $aParams = array())
	{
		$this->m_sTemplate = MetaModel::ApplyParams($this->m_sTemplate, $aParams);
		$iStart = 0;
		$iEnd = strlen($this->m_sTemplate);
		$iCount = 0;
		$iBeforeTagPos = $iStart;
		$iAfterTagPos = $iStart;
		while($sTag = $this->GetNextTag($iStart, $iEnd))
		{
			$sContent = $this->GetTagContent($sTag, $iStart, $iEnd);
			$iAfterTagPos = $iEnd + strlen('</'.$sTag.'>');
			$sOuterTag = substr($this->m_sTemplate, $iStart, $iAfterTagPos - $iStart);
			$oPage->add(substr($this->m_sTemplate, $iBeforeTagPos, $iStart - $iBeforeTagPos));
			if ($sTag == DisplayBlock::TAG_BLOCK)
			{
				$oBlock = DisplayBlock::FromTemplate($sOuterTag);
				if (is_object($oBlock))
				{
					$oBlock->Display($oPage, 'block_'.self::$iBlockCount);
				}
				self::$iBlockCount++;
			}
			else
			{
				$aAttributes = $this->GetTagAttributes($sTag, $iStart, $iEnd);
				//$oPage->p("Tag: $sTag - ($iStart, $iEnd)");
				$this->RenderTag($oPage, $sTag, $aAttributes, $sContent);
	
			}
			$iAfterTagPos = $iEnd + strlen('</'.$sTag.'>');
			$iBeforeTagPos = $iAfterTagPos;
			$iStart = $iEnd;
			$iEnd = strlen($this->m_sTemplate); 
			$iCount++;
			if ($iCount > 10) break; //@@@ Why ?? Debug ??
		}
		$oPage->add(substr($this->m_sTemplate, $iAfterTagPos));
	}
	
	public function GetNextTag(&$iStartPos, &$iEndPos)
	{
		$iChunkStartPos = $iStartPos;
		$sNextTag = null;
		$iStartPos = $iEndPos;
		foreach($this->m_aTags as $sTag)
		{
			// Search for the opening tag
			$iOpeningPos = stripos($this->m_sTemplate, '<'.$sTag.' ', $iChunkStartPos);
			if ($iOpeningPos === false)
			{
				$iOpeningPos = stripos($this->m_sTemplate, '<'.$sTag.'>', $iChunkStartPos);
			}
			if ($iOpeningPos !== false)
			{
				$iClosingPos = stripos($this->m_sTemplate, '</'.$sTag.'>', $iOpeningPos);
			}
			if ( ($iOpeningPos !== false) && ($iClosingPos !== false))
			{
				if ($iOpeningPos < $iStartPos)
				{
					// This is the next tag
					$iStartPos = $iOpeningPos;
					$iEndPos = $iClosingPos;
					$sNextTag = $sTag;
				}
			}
		}
		return $sNextTag;
	}
	
	public function GetTagContent($sTag, $iStartPos, $iEndPos)
	{
		$sContent  = "";
		$iContentStart = strpos($this->m_sTemplate, '>', $iStartPos); // Content of tag start immediatly after the first closing bracket
		if ($iContentStart !== false)
		{
			$sContent = substr($this->m_sTemplate, 1+$iContentStart, $iEndPos - $iContentStart - 1);
		}
		return $sContent;
	}

	public function GetTagAttributes($sTag, $iStartPos, $iEndPos)
	{
		$aAttr  = array();
		$iAttrStart = strpos($this->m_sTemplate, ' ', $iStartPos); // Attributes start just after the first space
		$iAttrEnd = strpos($this->m_sTemplate, '>', $iStartPos); // Attributes end just before the first closing bracket
		if ( ($iAttrStart !== false) && ($iAttrEnd !== false) && ($iAttrEnd > $iAttrStart))
		{
			$sAttributes = substr($this->m_sTemplate, 1+$iAttrStart, $iAttrEnd - $iAttrStart - 1);
			$aAttributes = explode(' ', $sAttributes);
			foreach($aAttributes as $sAttr)
			{
				if ( preg_match('/(.+) *= *"(.+)"$/', $sAttr, $aMatches) )
				{
					$aAttr[strtolower($aMatches[1])] = $aMatches[2];
				}
			}
		}
		return $aAttr;
	}
	
	protected function RenderTag($oPage, $sTag, $aAttributes, $sContent)
	{
		static $iTabContainerCount = 0;
		switch($sTag)
		{
			case 'itoptabs':
				$oPage->AddTabContainer('Tabs_'.$iTabContainerCount);
				$oPage->SetCurrentTabContainer('Tabs_'.$iTabContainerCount);
				$iTabContainerCount++;
				//$oPage->p('Content:<pre>'.htmlentities($sContent).'</pre>');
				$oTemplate = new DisplayTemplate($sContent);
				$oTemplate->Render($oPage, array()); // no params to apply, they have already been applied
				$oPage->SetCurrentTabContainer('');
			break;
			
			case 'itoptab':
				$oPage->SetCurrentTab(str_replace('_', ' ', $aAttributes['name']));
				$oTemplate = new DisplayTemplate($sContent);
				$oTemplate->Render($oPage, array()); // no params to apply, they have already been applied
				//$oPage->p('iTop Tab Content:<pre>'.htmlentities($sContent).'</pre>');
				$oPage->SetCurrentTab('');
			break;
			
			case 'itoptoggle':
				$sName = isset($aAttributes['name']) ? $aAttributes['name'] : 'Tagada';
				$bOpen = isset($aAttributes['open']) ? $aAttributes['open'] : true;
				$oPage->StartCollapsibleSection($sName, $bOpen);
				$oTemplate = new DisplayTemplate($sContent);
				$oTemplate->Render($oPage, array()); // no params to apply, they have already been applied
				//$oPage->p('iTop Tab Content:<pre>'.htmlentities($sContent).'</pre>');
				$oPage->EndCollapsibleSection();
			break;
			
			case 'itopblock': // No longer used, handled by DisplayBlock::FromTemplate see above
				$oPage->add("<!-- Application Error: should be handled by DisplayBlock::FromTemplate -->");
			break;
			
			default:
				// Unknown tag, just ignore it or now -- output an HTML comment
				$oPage->add("<!-- unsupported tag: $sTag -->");
		}
	}
{'fraction_non_alphanumeric': 0.18262806236080179, 'fraction_numerical': 0.0022271714922048997, 'mean_word_length': 3.970940959409594, 'pattern_counts': {'":': 0, '<': 33, '<?xml version=': 0, '>': 117, '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': '5266740', 'n_tokens_mistral': 4403, 'n_tokens_neox': 3841, 'n_words': 768}