1<?php 2 3class FeatureToc { 4 var $_anchor_locator; 5 var $_document_updater; 6 7 function FeatureToc() { 8 $this->set_anchor_locator(new FeatureTocAnchorLocatorHeaders()); 9 $this->set_document_updater(new FeatureTocDocumentUpdaterPrependPage()); 10 } 11 12 function handle_after_parse($params) { 13 $pipeline =& $params['pipeline']; 14 $document =& $params['document']; 15 $media =& $params['media']; 16 17 $toc =& $this->find_toc_anchors($pipeline, $media, $document); 18 $this->update_document($toc, $pipeline, $media, $document); 19 } 20 21 function handle_before_document($params) { 22 $pipeline =& $params['pipeline']; 23 $document =& $params['document']; 24 $media =& $params['media']; 25 $page_heights =& $params['page-heights']; 26 27 $toc =& $this->find_toc_anchors($pipeline, $media, $document); 28 $this->update_page_numbers($toc, $pipeline, $document, $page_heights, $media); 29 } 30 31 function &find_toc_anchors(&$pipeline, &$media, &$document) { 32 $locator =& $this->get_anchor_locator(); 33 $toc =& $locator->run($pipeline, $media, $document); 34 return $toc; 35 } 36 37 function &get_anchor_locator() { 38 return $this->_anchor_locator; 39 } 40 41 function &get_document_updater() { 42 return $this->_document_updater; 43 } 44 45 function guess_page(&$element, $page_heights, &$media) { 46 $page_index = 0; 47 $bottom = mm2pt($media->height() - $media->margins['top']); 48 do { 49 $bottom -= $page_heights[$page_index]; 50 $page_index ++; 51 } while ($element->get_top() < $bottom); 52 53 return $page_index; 54 } 55 56 function install(&$pipeline, $params) { 57 $dispatcher =& $pipeline->get_dispatcher(); 58 $dispatcher->add_observer('after-parse', array(&$this, 'handle_after_parse')); 59 $dispatcher->add_observer('before-document', array(&$this, 'handle_before_document')); 60 61 if (isset($params['location'])) { 62 switch ($params['location']) { 63 case 'placeholder': 64 $this->set_document_updater(new FeatureTocDocumentUpdaterPlaceholder()); 65 break; 66 case 'before': 67 $this->set_document_updater(new FeatureTocDocumentUpdaterPrependPage()); 68 break; 69 case 'after': 70 default: 71 $this->set_document_updater(new FeatureTocDocumentUpdaterAppendPage()); 72 break; 73 }; 74 }; 75 } 76 77 function set_anchor_locator(&$locator) { 78 $this->_anchor_locator =& $locator; 79 } 80 81 function set_document_updater(&$updater) { 82 $this->_document_updater =& $updater; 83 } 84 85 function make_toc_name_element_id($index) { 86 return sprintf('html2ps-toc-name-%d', $index); 87 } 88 89 function make_toc_page_element_id($index) { 90 return sprintf('html2ps-toc-page-%d', $index); 91 } 92 93 function update_document(&$toc, &$pipeline, &$media, &$document) { 94 $code = ''; 95 $index = 1; 96 foreach ($toc as $toc_element) { 97 $code .= sprintf(' 98<div id="html2ps-toc-%s" class="html2ps-toc-wrapper html2ps-toc-%d-wrapper"> 99<div id="%s" class="html2ps-toc-name html2ps-toc-%d-name"><a href="#%s">%s</a></div> 100<div id="%s" class="html2ps-toc-page html2ps-toc-%d-page">0000</div> 101</div>%s', 102 $index, 103 $toc_element['level'], 104 $this->make_toc_name_element_id($index), 105 $toc_element['level'], 106 $toc_element['anchor'], 107 $toc_element['name'], 108 $this->make_toc_page_element_id($index), 109 $toc_element['level'], 110 "\n"); 111 $index++; 112 }; 113 114 $toc_box_document =& $pipeline->parser->process('<body><div>'.$code.'</div></body>', $pipeline, $media); 115 $context =& new FlowContext(); 116 $pipeline->layout_engine->process($toc_box_document, $media, $pipeline->get_output_driver(), $context); 117 $toc_box =& $toc_box_document->content[0]; 118 119 $document_updater =& $this->get_document_updater(); 120 $document_updater->run($toc_box, $media, $document); 121 } 122 123 function update_page_numbers(&$toc, &$pipeline, &$document, &$page_heights, &$media) { 124 for ($i = 0, $size = count($toc); $i < $size; $i++) { 125 $toc_element =& $document->get_element_by_id($this->make_toc_page_element_id($i+1)); 126 $element =& $toc[$i]['element']; 127 128 $toc_element->content[0]->content[0]->words[0] = $this->guess_page($element, $page_heights, $media); 129 }; 130 } 131} 132 133class FeatureTocAnchorLocatorHeaders { 134 var $_locations; 135 var $_last_generated_anchor_id; 136 137 function FeatureTocAnchorLocatorHeaders() { 138 $this->set_locations(array()); 139 $this->_last_generated_anchor_id = 0; 140 } 141 142 function generate_toc_anchor_id() { 143 $this->_last_generated_anchor_id++; 144 $id = $this->_last_generated_anchor_id; 145 return sprintf('html2ps-toc-element-%d', $id); 146 } 147 148 function get_locations() { 149 return $this->_locations; 150 } 151 152 function process_node($params) { 153 $node =& $params['node']; 154 155 if (preg_match('/^h(\d)$/i', $node->get_tagname(), $matches)) { 156 if (!$node->get_id()) { 157 $id = $this->generate_toc_anchor_id(); 158 $node->set_id($id); 159 }; 160 161 $this->_locations[] = array('name' => $node->get_content(), 162 'level' => (int)$matches[1], 163 'anchor' => $node->get_id(), 164 'element' => &$node); 165 }; 166 } 167 168 function &run(&$pipeline, &$media, &$document) { 169 $this->set_locations(array()); 170 $walker =& new TreeWalkerDepthFirst(array(&$this, 'process_node')); 171 $walker->run($document); 172 $locations = $this->get_locations(); 173 174 foreach ($locations as $location) { 175 $location['element']->setCSSProperty(CSS_HTML2PS_LINK_DESTINATION, $location['element']->get_id()); 176 177 // $id = $location['element']->get_id(); 178 // $pipeline->output_driver->anchors[$id] =& $location['element']->make_anchor($media, $id); 179 }; 180 181 return $locations; 182 } 183 184 function set_locations($locations) { 185 $this->_locations = $locations; 186 } 187} 188 189class FeatureTocDocumentUpdaterAppendPage { 190 function FeatureTocDocumentUpdaterAppendPage() { 191 } 192 193 function run(&$toc_box, &$media, &$document) { 194 $toc_box->setCSSProperty(CSS_PAGE_BREAK_BEFORE, PAGE_BREAK_ALWAYS); 195 $document->append_child($toc_box); 196 } 197} 198 199class FeatureTocDocumentUpdaterPrependPage { 200 function FeatureTocDocumentUpdaterPrependPage() { 201 } 202 203 function run(&$toc_box, &$media, &$document) { 204 $toc_box->setCSSProperty(CSS_PAGE_BREAK_AFTER, PAGE_BREAK_ALWAYS); 205 $document->insert_before($toc_box, $document->content[0]); 206 } 207} 208 209class FeatureTocDocumentUpdaterPlaceholder { 210 function FeatureTocDocumentUpdaterPlaceholder() { 211 } 212 213 function run(&$toc_box, &$media, &$document) { 214 $placeholder =& $document->get_element_by_id('html2ps-toc'); 215 $placeholder->append_child($toc_box); 216 } 217} 218 219?>