1<?php 2 3/** 4 * DokuWiki Plugin Numbered Headings; action component 5 * 6 * @license GPL 2 (http://www.gnu.org/licenses/gpl.html) 7 * @author Satoshi Sahara <sahara.satoshi@gmail.com> 8 */ 9class action_plugin_numberedheadings extends DokuWiki_Action_Plugin 10{ 11 /** 12 * Registers a callback function for a given event 13 */ 14 public function register(Doku_Event_Handler $controller) 15 { 16 $controller->register_hook( 17 'PARSER_HANDLER_DONE', 'BEFORE', $this, 'numbering', [] 18 ); 19 20 if ($this->getConf('fancy')) { 21 $controller->register_hook( 22 'RENDERER_CONTENT_POSTPROCESS', 'AFTER', $this, 'decorateTieredNumber' 23 ); 24 } 25 } 26 27 /** 28 * PARSER_HANDLER_DONE event handler 29 * convert plugin instruction to header 30 */ 31 public function numbering(Doku_Event $event) 32 { 33 // load helper object 34 static $numbering; 35 isset($numbering) || $numbering = $this->loadHelper($this->getPluginName()); 36 37 $instructions =& $event->data->calls; 38 39 foreach ($instructions as $k => &$ins) { 40 if ($ins[0] == 'plugin' && $ins[1][0] == 'numberedheadings') { 41 // initialise variables to be extracted from data array 42 // that was compacted in handle() process 43 unset($dash, $level, $number, $title, $format); 44 extract($ins[1][1]); 45 46 if (!isset($dash)) { // not numbered headings 47 // set tier1 only 48 $numbering->setTier1($level); 49 //unset($instructions[$k]); 50 continue; 51 } 52 53 // auto-detect the first tier (Tier1) level 54 $tier1 = $numbering->getTier1(); 55 if (!$tier1) { 56 $tier1 = $this->getConf('tier1') ?: $level; 57 $numbering->setTier1($tier1); 58 } 59 $tier = $level - $tier1 +1; 60 61 // non-visible numbered headings, marked with '--' 62 if ($dash > 1) { 63 // set the heading counter only if number seems meaningful 64 if ($number !== '') { 65 $numbering->setHeadingCounter($level, $number); 66 } 67 68 if (isset($format)) { 69 // set numbering format of current tier (and subtiers) in the page 70 $numbering->setTierFormat($format, $tier); 71 72 } elseif ($dash > 2 || $number === '' && $title === '' && $tier == 1) { 73 // reset numbering feature 74 // the first tier (Tier1) level should be decided in next match 75 $numbering->setTier1(); 76 $numbering->setTierFormat(); 77 $numbering->setHeadingCounter(); 78 } 79 //unset($instructions[$k]); 80 continue; 81 } 82 83 // set the heading counter 84 $numbering->setHeadingCounter($level, $number); 85 86 // build tiered numbers for hierarchical headings 87 $tieredNumbers = $numbering->getTieredNumbers($level); 88 if ($tieredNumbers) { 89 // append double spaces after tiered number to distinguish title 90 $tieredNumbers .= $this->getConf('fancy') ? ' ' : ' '; 91 } 92 $text = $tieredNumbers.$title; 93 94 // rewrite plugin call to header 95 $ins[0] = 'header'; 96 $ins[1] = [$text, $level, $ins[2]]; 97 } 98 } 99 unset($ins); 100 // reset numbering feature prior to process other pages 101 $numbering->setTier1(); 102 $numbering->setTierFormat(); 103 $numbering->setHeadingCounter(); 104 } 105 106 /** 107 * RENDERER_CONTENT_POSTPROCESS 108 * enclose tiered numbers of hierarchical headings in span tag 109 */ 110 public function decorateTieredNumber(Doku_Event $event) 111 { 112 if ($event->data[0] == 'xhtml') { 113 $search = '#(<h\d.*?>)(.+?)( )(?=.*?</h\d>)#'; 114 $replacement = '${1}<span class="plugin_numberedheadings">${2}</span>'."\t"; 115 $event->data[1] = preg_replace($search, $replacement, $event->data[1]); 116 } 117 } 118 119} 120