'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;
}
}
}
?>