1<?php 2 3require_once DOKU_PLUGIN . 'odt/ODT/ODTDocument.php'; 4 5/** 6 * ODTList: 7 * Class containing static code for handling lists. 8 * 9 * @license GPL 2 (http://www.gnu.org/licenses/gpl.html) 10 * @author LarsDW223 11 */ 12class ODTList 13{ 14 /** 15 * Opens a list. 16 * The list style specifies if the list is an ordered or unordered list. 17 * 18 * @param bool $continue Continue numbering? 19 * @param string $styleName Name of style to use for the list 20 */ 21 static public function listOpen(ODTInternalParams $params, $continue=false, $styleName, $element=NULL, $attributes=NULL) { 22 $params->document->paragraphClose(); 23 24 $properties = array(); 25 ODTUtility::openHTMLElement ($params, $properties, $element, $attributes); 26 27 $list = new ODTElementList($styleName, $continue); 28 $params->document->state->enter($list); 29 $list->setHTMLElement ($element); 30 31 $params->content .= $list->getOpeningTag(); 32 } 33 34 /** 35 * Close a list 36 */ 37 static public function listClose(ODTInternalParams $params) { 38 $table = $params->document->state->getCurrentTable(); 39 if (isset($table) && $table->getListInterrupted()) { 40 // Do not do anything as long as list is interrupted 41 return; 42 } 43 44 if ($params->document->state->getInListItem()) { 45 // If we are still inside a list item then close it first, 46 // to prevent an error or broken document. 47 $params->document->listItemClose(); 48 } 49 50 // Eventually modify last list paragraph first 51 self::replaceLastListParagraph($params); 52 53 ODTUtility::closeHTMLElement ($params, $params->document->state->getHTMLElement()); 54 $list = $params->document->state->getCurrentList(); 55 $params->content .= $list->getClosingTag(); 56 57 $position = $list->getListLastParagraphPosition(); 58 $params->document->state->leave(); 59 60 // If we are still in a list save the last paragraph position 61 // in the current list (needed for nested lists!). 62 $list = $params->document->state->getCurrentList(); 63 if (isset($list)) { 64 $list->setListLastParagraphPosition($position); 65 } 66 } 67 68 /** 69 * Open a list item 70 * 71 * @param int $level The nesting level 72 */ 73 static public function listItemOpen(ODTInternalParams $params, $level, $element=NULL, $attributes=NULL) { 74 if (!isset($params->document->state)) { 75 // ??? Can't be... 76 return; 77 } 78 if (!isset($element)) { 79 $element = 'li'; 80 } 81 82 // Set marker that list interruption has stopped!!! 83 $table = $params->document->state->getCurrentTable(); 84 if (isset($table)) { 85 $table->setListInterrupted(false); 86 } 87 88 $properties = array(); 89 ODTUtility::openHTMLElement ($params, $properties, $element, $attributes); 90 91 // Attention: 92 // we save the list level here but it might be wrong. 93 // Someone can start a list with level 2 without having created 94 // a list with level 1 before. 95 // When the correct list level is needed better use 96 // $params->document->state->countClass('list'), see table_open(). 97 $list_item = new ODTElementListItem($level); 98 $params->document->state->enter($list_item); 99 $list_item->setHTMLElement ($element); 100 101 $params->content .= $list_item->getOpeningTag(); 102 } 103 104 /** 105 * Close a list item 106 */ 107 static public function listItemClose(ODTInternalParams $params) { 108 $table = $params->document->state->getCurrentTable(); 109 if (isset($table) && $table->getListInterrupted()) { 110 // Do not do anything as long as list is interrupted 111 return; 112 } 113 114 if ($params->document->state->getInListContent()) { 115 // If we are still inside list content then close it first, 116 // to prevent an error or broken document. 117 $params->document->listContentClose(); 118 } 119 120 ODTUtility::closeHTMLElement ($params, $params->document->state->getHTMLElement()); 121 $params->document->closeCurrentElement(); 122 } 123 124 /** 125 * Open a list header 126 * 127 * @param int $level The nesting level 128 */ 129 static public function listHeaderOpen(ODTInternalParams $params, $level, $element=NULL, $attributes=NULL) { 130 if ( !isset($params->document->state) ) { 131 // ??? Can't be... 132 return; 133 } 134 if (!isset($element)) { 135 $element = 'li'; 136 } 137 138 // Set marker that list interruption has stopped!!! 139 $table = $params->document->state->getCurrentTable(); 140 if (isset($table)) { 141 $table->setListInterrupted(false); 142 } 143 144 $properties = array(); 145 ODTUtility::openHTMLElement ($params, $properties, $element, $attributes); 146 147 // Attention: 148 // we save the list level here but it might be wrong. 149 // Someone can start a list with level 2 without having created 150 // a list with level 1 before. 151 // When the correct list level is needed better use 152 // $params->document->state->countClass('list'), see table_open(). 153 $list_header = new ODTElementListHeader($level); 154 $params->document->state->enter($list_header); 155 $list_header->setHTMLElement ($element); 156 157 $params->content .= $list_header->getOpeningTag(); 158 } 159 160 /** 161 * Close a list header 162 */ 163 static public function listHeaderClose(ODTInternalParams $params) { 164 $table = $params->document->state->getCurrentTable(); 165 if (isset($table) && $table->getListInterrupted()) { 166 // Do not do anything as long as list is interrupted 167 return; 168 } 169 ODTUtility::closeHTMLElement ($params, $params->document->state->getHTMLElement()); 170 $params->document->closeCurrentElement(); 171 } 172 173 /** 174 * Open list content/a paragraph in a list item 175 */ 176 static public function listContentOpen(ODTInternalParams $params, $element=NULL, $attributes=NULL) { 177 // The default style for list content is body but it should always be 178 // overwritten. It's just assigned here to guarantee some style name is 179 // always set in case of an error also. 180 $styleName = $params->document->getStyleName('body'); 181 $list = $params->document->state->getCurrentList(); 182 if (isset($list)) { 183 $listStyleName = $list->getStyleName(); 184 if ($listStyleName == $params->document->getStyleName('list')) { 185 $styleName = $params->document->getStyleName('list content'); 186 } 187 if ($listStyleName == $params->document->getStyleName('numbering')) { 188 $styleName = $params->document->getStyleName('numbering content'); 189 } 190 } 191 192 $params->document->paragraphOpen($styleName); 193 } 194 195 /** 196 * Close list content/a paragraph in a list item 197 */ 198 static public function listContentClose(ODTInternalParams $params) { 199 $table = $params->document->state->getCurrentTable(); 200 if (isset($table) && $table->getListInterrupted()) { 201 // Do not do anything as long as list is interrupted 202 return; 203 } 204 $params->document->paragraphClose(); 205 } 206 207 /** 208 * The function replaces the last paragraph of a list 209 * with a style having the properties of 'List_Last_Paragraph'. 210 * 211 * The function does NOT change the last paragraph of nested lists. 212 */ 213 static protected function replaceLastListParagraph(ODTInternalParams $params) { 214 $list = $params->document->state->getCurrentList(); 215 if (isset($list)) { 216 // We are in a list. 217 $list_count = $params->document->state->countClass('list'); 218 $position = $list->getListLastParagraphPosition(); 219 220 if ($list_count != 1 || $position == -1) { 221 // Do nothing if this is a nested list or the position was not saved 222 return; 223 } 224 225 $last_p_style = NULL; 226 if (preg_match('/<text:p text:style-name="[^"]*">/', $params->content, $matches, 0, $position) === 1) { 227 $last_p_style = substr($matches [0], strlen('<text:p text:style-name=')); 228 $last_p_style = trim($last_p_style, '">'); 229 } else { 230 // Nothing found??? 231 return; 232 } 233 234 // Create a style for putting a bottom margin for this last paragraph of the list 235 // (if not done yet, the name must be unique!) 236 237 // If we have a standard list content paragraph style then we use the 238 // corresponding always existing first and last default styles 239 if ($last_p_style == $params->document->getStyleName('list content')) { 240 $style_name = $params->document->getStyleName('list last'); 241 } else if ($last_p_style == $params->document->getStyleName('numbering content')) { 242 $style_name = $params->document->getStyleName('numbering last'); 243 } else { 244 $style_name = 'LastListParagraph_'.$last_p_style; 245 if (!$params->document->styleExists($style_name)) { 246 // ...no, create style as copy of style 'list first' or 'numbering first' 247 if ($list->getStyleName() == $params->document->getStyleName('list')) { 248 $style_last = $params->document->getStyleByAlias('list first'); 249 } else { 250 $style_last = $params->document->getStyleByAlias('numbering first'); 251 } 252 if (isset($style_last)) { 253 $style_body = $params->document->getStyle($last_p_style); 254 $style_display_name = 'Last '.$style_body->getProperty('style-display-name'); 255 $style_obj = clone $style_last; 256 257 if (isset($style_obj)) { 258 $style_obj->setProperty('style-name', $style_name); 259 $style_obj->setProperty('style-parent', $last_p_style); 260 $style_obj->setProperty('style-display-name', $style_display_name); 261 $top = $style_last->getProperty('margin-top'); 262 if (!isset($top)) { 263 $style_obj->setProperty('margin-top', $style_body->getProperty('margin-top')); 264 } 265 $params->document->addStyle($style_obj); 266 } 267 } 268 } 269 } 270 271 // Finally replace style name of last paragraph. 272 $params->content = substr_replace ($params->content, 273 '<text:p text:style-name="'.$style_name.'">', 274 $position, strlen($matches[0])); 275 } 276 } 277} 278