'StyleBySection', 'url' => 'http://www.mediawiki.org/wiki/Extension:StyleBySection', 'author' => 'Francois Moreau', 'description' => 'Wraps sections according to header hierarchy', ); class StyleBySection { protected $opening_tag_level = ''; protected $closing_tag_level = ''; protected $_attributeRules = array(); protected $_titleExtractPattern = null; protected $_rulesCounter = array(); public function apply($rules = null, $parser, &$text) { if(is_array($rules)) { $this->_attributeRules = $rules; if(array_key_exists('_EXTRACT_TITLE_PATTERN', $this->_attributeRules) && is_string($this->_attributeRules['_EXTRACT_TITLE_PATTERN'])) { $this->_titleExtractPattern = $this->_attributeRules['_EXTRACT_TITLE_PATTERN']; unset($this->_attributeRules['_EXTRACT_TITLE_PATTERN']); } elseif(array_key_exists('wgVersion', $GLOBALS) && -1 < version_compare($GLOBALS['wgVersion'], '1.10')) { $this->_titleExtractPattern = '/(.*)<\/span>/'; } } $text = $this->_traverseText($text); return true; } private function _traverseText($text) { $text = "<_STYLEBYSECTION>$text"; $pointer = 0; $prev_pointer = 0; $result = ''; $pile = array(); while( (false !== $pointer)) { $result .= substr($text, $prev_pointer, $pointer-$prev_pointer); switch($this->_tagType($pointer, $text)) { case 'opening_tag': $header_level = $text[$pointer+2]; $current = end($pile); if($current && $header_level <= $current['level'] && 0 == $current['num_nesting'] ) { while($current && $header_level <= $current['level']) { $result .= $this->closing_tag_level; array_pop($pile); $current = end($pile); } } $result .= $this->_openingTagWithAttr($text, $pointer, $header_level); $this->_incrNesting($pile); $pile[] = array('level' => $header_level, 'num_nesting' => 1); break; case 'opening': $this->_incrNesting($pile); break; case 'closing': $this->_incrNesting($pile, -1); reset($pile); $closed_piles = false; while(list($key, $val) = each($pile)) { if(0 > $val['num_nesting']) { $result .= $this->closing_tag_level; unset($pile[$key]); $closed_piles = true; } } if($closed_piles) $pile = array_values($pile); break; } $prev_pointer = $pointer; $pointer = strpos($text, '<', 1+ $pointer); } $result .= substr($text, $prev_pointer); $result .= str_repeat($this->closing_tag_level, count($pile)); return str_replace ( array('<_STYLEBYSECTION>', ''), array('', ''), $result); } private function _tagType($pointer, $text) { if('h' == $text[$pointer+1] && chr($text[$pointer+2]) <= chr('6') && chr($text[$pointer+2]) >= chr('1')) { return 'opening_tag'; } if('/' == $text[$pointer+1]) { return 'closing'; } $tag_end_pos = strpos($text, '>', $pointer); if('/' == $text[$tag_end_pos-1]) { return 'autoclosing'; } return 'opening'; } private function _openingTagWithAttr($text, $pointer, $header_level) { $str_attr = ''; $header_content_start_pointer = 1 + strpos ( $text, '>', $pointer ); $header_content_end_pointer = strpos ( $text, "", $pointer ); $header_content = substr ( $text, $header_content_start_pointer, $header_content_end_pointer - $header_content_start_pointer); if(is_string($this->_titleExtractPattern)) { $is_found = preg_match($this->_titleExtractPattern, $header_content, $match); if($is_found && 2 == count($match)) { $header_content = trim($match[1]); } } $rules_by_priority = array_reverse ( $this->_attributeRules, $preserve_keys=true ); foreach($rules_by_priority as $rule_index => $rule) { $to_apply = false; if(array_key_exists('title=', $rule)) { $to_apply = $header_content == $rule['title=']; } elseif(array_key_exists('title-match', $rule)) { $to_apply = (bool) preg_match ( $rule['title-match'], $header_content ); } if($to_apply) { foreach($rule['attr'] as $name => $val) { if(!array_key_exists($rule_index, $this->_rulesCounter)) { $this->_rulesCounter[$rule_index] = 0; } if(strpos($val, '##COUNTER##')) ++$this->_rulesCounter[$rule_index]; $val = str_replace ( array('"', '##COUNTER##', '##LEVEL##'), array('"', $this->_rulesCounter[$rule_index], $header_level), $val) ; $str_attr .= ' ' . $name . '="' . $val . '"' ; } break; } } return sprintf($this->opening_tag_level, $str_attr); } private function _incrNesting(&$pile, $increment=1) { reset($pile); while(list($key, $val) = each($pile)) { $pile[$key]['num_nesting'] += $increment; } } } ?>