1*04fd306cSNickeau<?php 2*04fd306cSNickeau 3*04fd306cSNickeau 4*04fd306cSNickeaunamespace ComboStrap; 5*04fd306cSNickeau 6*04fd306cSNickeauuse ComboStrap\TagAttribute\StyleAttribute; 7*04fd306cSNickeau 8*04fd306cSNickeau/** 9*04fd306cSNickeau * Class SectionEdit 10*04fd306cSNickeau * @package ComboStrap 11*04fd306cSNickeau * Manage the edit button 12*04fd306cSNickeau * (ie add HTML comment that are parsed into forms 13*04fd306cSNickeau * for editor user) 14*04fd306cSNickeau */ 15*04fd306cSNickeauclass EditButton 16*04fd306cSNickeau{ 17*04fd306cSNickeau 18*04fd306cSNickeau 19*04fd306cSNickeau const SEC_EDIT_PATTERN = "/" . self::ENTER_HTML_COMMENT . "\s*" . self::EDIT_BUTTON_PREFIX . "({.*?})\s*" . self::CLOSE_HTML_COMMENT . "/"; 20*04fd306cSNickeau const EDIT_BUTTON_PREFIX = "EDIT"; 21*04fd306cSNickeau const WIKI_ID = "wiki-id"; 22*04fd306cSNickeau 23*04fd306cSNickeau const FORM_ID = "hid"; // id to be dokuwiki conform 24*04fd306cSNickeau const EDIT_MESSAGE = "name"; // name to be dokuwiki conform 25*04fd306cSNickeau 26*04fd306cSNickeau const CANONICAL = "edit-button"; 27*04fd306cSNickeau const ENTER_HTML_COMMENT = "<!--"; 28*04fd306cSNickeau const CLOSE_HTML_COMMENT = "-->"; 29*04fd306cSNickeau const SNIPPET_ID = "edit-button"; 30*04fd306cSNickeau 31*04fd306cSNickeau 32*04fd306cSNickeau /** 33*04fd306cSNickeau * The target drive the type of editor 34*04fd306cSNickeau * As of today, there is two type 35*04fd306cSNickeau * section and table 36*04fd306cSNickeau */ 37*04fd306cSNickeau const TARGET_ATTRIBUTE_NAME = "target"; 38*04fd306cSNickeau const TARGET_SECTION_VALUE = "section"; 39*04fd306cSNickeau /** 40*04fd306cSNickeau * The table does not have an edit form at all 41*04fd306cSNickeau * It's created by {@link \Doku_Renderer_xhtml::table_close()} 42*04fd306cSNickeau * They are not printed by default via CSS. Edittable show them by default via Javascript 43*04fd306cSNickeau */ 44*04fd306cSNickeau const TARGET_TABLE_VALUE = "table"; 45*04fd306cSNickeau public const EDIT_SECTION_TARGET = 'section'; 46*04fd306cSNickeau const RANGE = "range"; 47*04fd306cSNickeau const DOKUWIKI_FORMAT = "dokuwiki"; 48*04fd306cSNickeau const COMBO_FORMAT = "combo"; 49*04fd306cSNickeau const TAG = "edit-button"; 50*04fd306cSNickeau const CLASS_SUFFIX = "edit-button"; 51*04fd306cSNickeau 52*04fd306cSNickeau 53*04fd306cSNickeau private $label; 54*04fd306cSNickeau /** 55*04fd306cSNickeau * @var string 56*04fd306cSNickeau */ 57*04fd306cSNickeau private $wikiId; 58*04fd306cSNickeau 59*04fd306cSNickeau /** 60*04fd306cSNickeau * Edit type 61*04fd306cSNickeau * @var string 62*04fd306cSNickeau * This is the default 63*04fd306cSNickeau */ 64*04fd306cSNickeau private string $target = self::TARGET_SECTION_VALUE; 65*04fd306cSNickeau /** 66*04fd306cSNickeau * @var int 67*04fd306cSNickeau */ 68*04fd306cSNickeau private int $startPosition; 69*04fd306cSNickeau 70*04fd306cSNickeau private ?int $endPosition; 71*04fd306cSNickeau /** 72*04fd306cSNickeau * @var string $format - to conform or not to dokuwiki format 73*04fd306cSNickeau */ 74*04fd306cSNickeau private string $format = self::COMBO_FORMAT; 75*04fd306cSNickeau 76*04fd306cSNickeau /** 77*04fd306cSNickeau * the id of the heading, ie the id of the section 78*04fd306cSNickeau * Not really needed, just to be conform with Dokuwiki 79*04fd306cSNickeau * When the edit button is not for an outline may be null 80*04fd306cSNickeau */ 81*04fd306cSNickeau private ?string $outlineHeadingId = null; 82*04fd306cSNickeau /** 83*04fd306cSNickeau * @var ?int $sectionid - sequence id of the section used only by dokuwiki 84*04fd306cSNickeau * When the edit button is not for an outline may be null 85*04fd306cSNickeau */ 86*04fd306cSNickeau private ?int $outlineSectionId = null; 87*04fd306cSNickeau 88*04fd306cSNickeau 89*04fd306cSNickeau /** 90*04fd306cSNickeau * Section constructor. 91*04fd306cSNickeau */ 92*04fd306cSNickeau public function __construct($label) 93*04fd306cSNickeau { 94*04fd306cSNickeau $this->label = $label; 95*04fd306cSNickeau } 96*04fd306cSNickeau 97*04fd306cSNickeau 98*04fd306cSNickeau public static function create($label): EditButton 99*04fd306cSNickeau { 100*04fd306cSNickeau return new EditButton($label); 101*04fd306cSNickeau } 102*04fd306cSNickeau 103*04fd306cSNickeau public static function createFromCallStackArray($attributes): EditButton 104*04fd306cSNickeau { 105*04fd306cSNickeau $label = $attributes[\syntax_plugin_combo_edit::LABEL]; 106*04fd306cSNickeau $startPosition = $attributes[\syntax_plugin_combo_edit::START_POSITION]; 107*04fd306cSNickeau $endPosition = $attributes[\syntax_plugin_combo_edit::END_POSITION]; 108*04fd306cSNickeau $wikiId = $attributes[TagAttributes::WIKI_ID]; 109*04fd306cSNickeau $editButton = EditButton::create($label) 110*04fd306cSNickeau ->setStartPosition($startPosition) 111*04fd306cSNickeau ->setEndPosition($endPosition) 112*04fd306cSNickeau ->setWikiId($wikiId); 113*04fd306cSNickeau $headingId = $attributes[\syntax_plugin_combo_edit::HEADING_ID]; 114*04fd306cSNickeau if ($headingId !== null) { 115*04fd306cSNickeau $editButton->setOutlineHeadingId($headingId); 116*04fd306cSNickeau } 117*04fd306cSNickeau $sectionId = $attributes[\syntax_plugin_combo_edit::SECTION_ID]; 118*04fd306cSNickeau if ($sectionId !== null) { 119*04fd306cSNickeau $editButton->setOutlineSectionId($sectionId); 120*04fd306cSNickeau } 121*04fd306cSNickeau $format = $attributes[\syntax_plugin_combo_edit::FORMAT]; 122*04fd306cSNickeau if ($format !== null) { 123*04fd306cSNickeau $editButton->setFormat($format); 124*04fd306cSNickeau } 125*04fd306cSNickeau return $editButton; 126*04fd306cSNickeau 127*04fd306cSNickeau 128*04fd306cSNickeau } 129*04fd306cSNickeau 130*04fd306cSNickeau public static function deleteAll(string $html) 131*04fd306cSNickeau { 132*04fd306cSNickeau // Dokuwiki way is to delete 133*04fd306cSNickeau // but because they are comment, they are not shown 134*04fd306cSNickeau // We delete to serve clean page to search engine 135*04fd306cSNickeau return preg_replace(SEC_EDIT_PATTERN, '', $html); 136*04fd306cSNickeau } 137*04fd306cSNickeau 138*04fd306cSNickeau public static function replaceOrDeleteAll(string $html_output) 139*04fd306cSNickeau { 140*04fd306cSNickeau try { 141*04fd306cSNickeau return EditButton::replaceAll($html_output); 142*04fd306cSNickeau } catch (ExceptionNotAuthorized|ExceptionBadState $e) { 143*04fd306cSNickeau return EditButton::deleteAll($html_output); 144*04fd306cSNickeau } 145*04fd306cSNickeau } 146*04fd306cSNickeau 147*04fd306cSNickeau /** 148*04fd306cSNickeau * See {@link \Doku_Renderer_xhtml::finishSectionEdit()} 149*04fd306cSNickeau */ 150*04fd306cSNickeau public function toTag(): string 151*04fd306cSNickeau { 152*04fd306cSNickeau 153*04fd306cSNickeau /** 154*04fd306cSNickeau * The following data are mandatory from: 155*04fd306cSNickeau * {@link html_secedit_get_button} 156*04fd306cSNickeau */ 157*04fd306cSNickeau $wikiId = $this->getWikiId(); 158*04fd306cSNickeau 159*04fd306cSNickeau 160*04fd306cSNickeau /** 161*04fd306cSNickeau * We follow the order of Dokuwiki for compatibility purpose 162*04fd306cSNickeau */ 163*04fd306cSNickeau $data[self::TARGET_ATTRIBUTE_NAME] = $this->target; 164*04fd306cSNickeau 165*04fd306cSNickeau if ($this->format === self::COMBO_FORMAT) { 166*04fd306cSNickeau /** 167*04fd306cSNickeau * In the combo edit format, we had the dokuwiki id 168*04fd306cSNickeau * because the edit button may also be on the secondary slot 169*04fd306cSNickeau */ 170*04fd306cSNickeau $data[self::WIKI_ID] = $wikiId; 171*04fd306cSNickeau } 172*04fd306cSNickeau $data[self::EDIT_MESSAGE] = $this->label; 173*04fd306cSNickeau if ($this->format === self::COMBO_FORMAT) { 174*04fd306cSNickeau /** 175*04fd306cSNickeau * In the combo edit format, we had the dokuwiki id as form id 176*04fd306cSNickeau * to make it unique on the whole page 177*04fd306cSNickeau * because the edit button may also be on the secondary slot 178*04fd306cSNickeau */ 179*04fd306cSNickeau $slotPath = WikiPath::createMarkupPathFromId($wikiId); 180*04fd306cSNickeau $formId = ExecutionContext::getActualOrCreateFromEnv() 181*04fd306cSNickeau ->getIdManager() 182*04fd306cSNickeau ->generateNewHtmlIdForComponent(self::CANONICAL, $slotPath); 183*04fd306cSNickeau $data[self::FORM_ID] = $formId; 184*04fd306cSNickeau 185*04fd306cSNickeau 186*04fd306cSNickeau } else { 187*04fd306cSNickeau $data[self::FORM_ID] = $this->getHeadingId(); 188*04fd306cSNickeau $data["codeblockOffset"] = 0; // what is that ? 189*04fd306cSNickeau $data["secid"] = $this->getSectionId(); 190*04fd306cSNickeau } 191*04fd306cSNickeau $data[self::RANGE] = $this->getRange(); 192*04fd306cSNickeau 193*04fd306cSNickeau 194*04fd306cSNickeau return self::EDIT_BUTTON_PREFIX . Html::encode(json_encode($data)); 195*04fd306cSNickeau } 196*04fd306cSNickeau 197*04fd306cSNickeau /** 198*04fd306cSNickeau * 199*04fd306cSNickeau * @throws ExceptionBadArgument - if the wiki id could not be found 200*04fd306cSNickeau * @throws ExceptionNotEnabled 201*04fd306cSNickeau */ 202*04fd306cSNickeau public function toHtmlComment(): string 203*04fd306cSNickeau { 204*04fd306cSNickeau global $ACT; 205*04fd306cSNickeau if ($ACT === FetcherMarkup::MARKUP_DYNAMIC_EXECUTION_NAME) { 206*04fd306cSNickeau // ie weblog, they are generated via dynamic markup 207*04fd306cSNickeau // meaning that there is no button to edit the file 208*04fd306cSNickeau if (!PluginUtility::isTest()) { 209*04fd306cSNickeau return ""; 210*04fd306cSNickeau } 211*04fd306cSNickeau } 212*04fd306cSNickeau /** 213*04fd306cSNickeau * We don't encode there is only internal information 214*04fd306cSNickeau * and this is easier to see / debug the output 215*04fd306cSNickeau */ 216*04fd306cSNickeau return self::ENTER_HTML_COMMENT . " " . $this->toTag() . " " . self::CLOSE_HTML_COMMENT; 217*04fd306cSNickeau } 218*04fd306cSNickeau 219*04fd306cSNickeau public function __toString() 220*04fd306cSNickeau { 221*04fd306cSNickeau return "Section Edit $this->label"; 222*04fd306cSNickeau } 223*04fd306cSNickeau 224*04fd306cSNickeau 225*04fd306cSNickeau /** 226*04fd306cSNickeau * @throws ExceptionNotAuthorized - if the user cannot modify the page 227*04fd306cSNickeau * @throws ExceptionBadState - if the page is a revision page or the HTML is not the output of a page 228*04fd306cSNickeau */ 229*04fd306cSNickeau public static function replaceAll($html) 230*04fd306cSNickeau { 231*04fd306cSNickeau 232*04fd306cSNickeau if (!Identity::isWriter()) { 233*04fd306cSNickeau throw new ExceptionNotAuthorized("Page is not writable by the user"); 234*04fd306cSNickeau } 235*04fd306cSNickeau /** 236*04fd306cSNickeau * Delete the edit comment 237*04fd306cSNickeau * * if not writable 238*04fd306cSNickeau * * or an old revision 239*04fd306cSNickeau * Original: {@link html_secedit()} {@link html_secedit_get_button()} 240*04fd306cSNickeau */ 241*04fd306cSNickeau global $INFO; 242*04fd306cSNickeau if (isset($INFO)) { 243*04fd306cSNickeau // the page is a revision page 244*04fd306cSNickeau if ($INFO['rev']) { 245*04fd306cSNickeau throw new ExceptionBadState("Internal Error: No edit button can be added to a revision page"); 246*04fd306cSNickeau } 247*04fd306cSNickeau } 248*04fd306cSNickeau 249*04fd306cSNickeau 250*04fd306cSNickeau /** 251*04fd306cSNickeau * Request based because the button are added only for a user that can write 252*04fd306cSNickeau */ 253*04fd306cSNickeau $snippetManager = PluginUtility::getSnippetManager(); 254*04fd306cSNickeau $snippetManager->attachCssInternalStylesheet(self::SNIPPET_ID); 255*04fd306cSNickeau $snippetManager->attachJavascriptFromComponentId(self::SNIPPET_ID); 256*04fd306cSNickeau 257*04fd306cSNickeau /** 258*04fd306cSNickeau * The callback function on all edit comment 259*04fd306cSNickeau * @param $matches 260*04fd306cSNickeau * @return string 261*04fd306cSNickeau */ 262*04fd306cSNickeau $editFormCallBack = function ($matches) { 263*04fd306cSNickeau $json = Html::decode($matches[1]); 264*04fd306cSNickeau $data = json_decode($json, true); 265*04fd306cSNickeau 266*04fd306cSNickeau $target = $data[self::TARGET_ATTRIBUTE_NAME]; 267*04fd306cSNickeau 268*04fd306cSNickeau $message = $data[self::EDIT_MESSAGE]; 269*04fd306cSNickeau unset($data[self::EDIT_MESSAGE]); 270*04fd306cSNickeau if ($message === null || trim($message) === "") { 271*04fd306cSNickeau $message = "Edit {$target}"; 272*04fd306cSNickeau } 273*04fd306cSNickeau 274*04fd306cSNickeau if ($data === NULL) { 275*04fd306cSNickeau LogUtility::internalError("No data found in the edit comment", self::CANONICAL); 276*04fd306cSNickeau return ""; 277*04fd306cSNickeau } 278*04fd306cSNickeau $wikiId = $data[self::WIKI_ID]; 279*04fd306cSNickeau unset($data[self::WIKI_ID]); 280*04fd306cSNickeau if ($wikiId === null) { 281*04fd306cSNickeau try { 282*04fd306cSNickeau $page = MarkupPath::createPageFromExecutingId(); 283*04fd306cSNickeau } catch (ExceptionNotFound $e) { 284*04fd306cSNickeau LogUtility::internalError("A page id is mandatory for a edit button (no wiki id, no global ID were found). No edit buttons was created then.", self::CANONICAL); 285*04fd306cSNickeau return ""; 286*04fd306cSNickeau } 287*04fd306cSNickeau } else { 288*04fd306cSNickeau $page = MarkupPath::createMarkupFromId($wikiId); 289*04fd306cSNickeau } 290*04fd306cSNickeau $formId = $data[self::FORM_ID]; 291*04fd306cSNickeau unset($data[self::FORM_ID]); 292*04fd306cSNickeau $data["summary"] = $message; 293*04fd306cSNickeau try { 294*04fd306cSNickeau $data['rev'] = $page->getPathObject()->getRevisionOrDefault(); 295*04fd306cSNickeau } catch (ExceptionNotFound $e) { 296*04fd306cSNickeau //LogUtility::internalError("The file ({$page->getPathObject()}) does not exist, we cannot set the last modified time on the edit buttons.", self::CANONICAL); 297*04fd306cSNickeau } 298*04fd306cSNickeau $hiddenInputs = ""; 299*04fd306cSNickeau foreach ($data as $key => $val) { 300*04fd306cSNickeau $inputAttributes = TagAttributes::createEmpty() 301*04fd306cSNickeau ->addOutputAttributeValue("name", $key) 302*04fd306cSNickeau ->addOutputAttributeValue("value", $val) 303*04fd306cSNickeau ->addOutputAttributeValue("type", "hidden"); 304*04fd306cSNickeau $hiddenInputs .= $inputAttributes->toHtmlEmptyTag("input"); 305*04fd306cSNickeau } 306*04fd306cSNickeau $url = $page->getUrl() 307*04fd306cSNickeau ->withoutRewrite() 308*04fd306cSNickeau ->toHtmlString(); 309*04fd306cSNickeau $classPageEdit = StyleAttribute::addComboStrapSuffix(self::CLASS_SUFFIX); 310*04fd306cSNickeau 311*04fd306cSNickeau /** 312*04fd306cSNickeau * Important Note: the first div and the public class is mandatory for the edittable plugin 313*04fd306cSNickeau * See {@link editbutton.js file} 314*04fd306cSNickeau */ 315*04fd306cSNickeau $editTableClass = "editbutton_{$target}"; 316*04fd306cSNickeau return <<<EOF 317*04fd306cSNickeau<div class="$classPageEdit $editTableClass"> 318*04fd306cSNickeau <form id="$formId" method="post" action="{$url}"> 319*04fd306cSNickeau $hiddenInputs 320*04fd306cSNickeau <input name="do" type="hidden" value="edit"/> 321*04fd306cSNickeau <button type="submit" title="$message"> 322*04fd306cSNickeau </button> 323*04fd306cSNickeau </form> 324*04fd306cSNickeau</div> 325*04fd306cSNickeauEOF; 326*04fd306cSNickeau }; 327*04fd306cSNickeau 328*04fd306cSNickeau /** 329*04fd306cSNickeau * The replacement 330*04fd306cSNickeau */ 331*04fd306cSNickeau return preg_replace_callback(self::SEC_EDIT_PATTERN, $editFormCallBack, $html); 332*04fd306cSNickeau } 333*04fd306cSNickeau 334*04fd306cSNickeau 335*04fd306cSNickeau public function setWikiId(string $id): EditButton 336*04fd306cSNickeau { 337*04fd306cSNickeau $this->wikiId = $id; 338*04fd306cSNickeau return $this; 339*04fd306cSNickeau } 340*04fd306cSNickeau 341*04fd306cSNickeau /** 342*04fd306cSNickeau * Page / Section edit 343*04fd306cSNickeau * (This is known as the target for dokuwiki) 344*04fd306cSNickeau * @param string $target 345*04fd306cSNickeau * @return $this 346*04fd306cSNickeau * 347*04fd306cSNickeau */ 348*04fd306cSNickeau public function setTarget(string $target): EditButton 349*04fd306cSNickeau { 350*04fd306cSNickeau $this->target = $target; 351*04fd306cSNickeau return $this; 352*04fd306cSNickeau } 353*04fd306cSNickeau 354*04fd306cSNickeau public function setStartPosition(int $startPosition): EditButton 355*04fd306cSNickeau { 356*04fd306cSNickeau $this->startPosition = $startPosition; 357*04fd306cSNickeau return $this; 358*04fd306cSNickeau } 359*04fd306cSNickeau 360*04fd306cSNickeau public function setEndPosition(?int $endPosition): EditButton 361*04fd306cSNickeau { 362*04fd306cSNickeau $this->endPosition = $endPosition; 363*04fd306cSNickeau return $this; 364*04fd306cSNickeau } 365*04fd306cSNickeau 366*04fd306cSNickeau /** 367*04fd306cSNickeau * @return string the file character position range of the section to edit 368*04fd306cSNickeau */ 369*04fd306cSNickeau private function getRange(): string 370*04fd306cSNickeau { 371*04fd306cSNickeau $range = ""; 372*04fd306cSNickeau if (isset($this->startPosition)) { 373*04fd306cSNickeau $range = $this->startPosition; 374*04fd306cSNickeau } 375*04fd306cSNickeau $range = "$range-"; 376*04fd306cSNickeau if (isset($this->endPosition)) { 377*04fd306cSNickeau $range = "$range{$this->endPosition}"; 378*04fd306cSNickeau } 379*04fd306cSNickeau return $range; 380*04fd306cSNickeau 381*04fd306cSNickeau } 382*04fd306cSNickeau 383*04fd306cSNickeau public function toComboCallComboFormat(): Call 384*04fd306cSNickeau { 385*04fd306cSNickeau return $this->toComboCall(self::COMBO_FORMAT); 386*04fd306cSNickeau } 387*04fd306cSNickeau 388*04fd306cSNickeau public function toComboCall($format): Call 389*04fd306cSNickeau { 390*04fd306cSNickeau return Call::createComboCall( 391*04fd306cSNickeau \syntax_plugin_combo_edit::TAG, 392*04fd306cSNickeau DOKU_LEXER_SPECIAL, 393*04fd306cSNickeau [ 394*04fd306cSNickeau \syntax_plugin_combo_edit::START_POSITION => $this->startPosition, 395*04fd306cSNickeau \syntax_plugin_combo_edit::END_POSITION => $this->endPosition, 396*04fd306cSNickeau \syntax_plugin_combo_edit::LABEL => $this->label, 397*04fd306cSNickeau \syntax_plugin_combo_edit::FORMAT => $format, 398*04fd306cSNickeau \syntax_plugin_combo_edit::HEADING_ID => $this->getHeadingId(), 399*04fd306cSNickeau \syntax_plugin_combo_edit::SECTION_ID => $this->getSectionId(), 400*04fd306cSNickeau TagAttributes::WIKI_ID => $this->getWikiId() 401*04fd306cSNickeau ] 402*04fd306cSNickeau ); 403*04fd306cSNickeau } 404*04fd306cSNickeau 405*04fd306cSNickeau 406*04fd306cSNickeau /** 407*04fd306cSNickeau * 408*04fd306cSNickeau */ 409*04fd306cSNickeau private function getWikiId(): string 410*04fd306cSNickeau { 411*04fd306cSNickeau 412*04fd306cSNickeau $wikiId = $this->wikiId; 413*04fd306cSNickeau if ($wikiId !== null) { 414*04fd306cSNickeau return $wikiId; 415*04fd306cSNickeau } 416*04fd306cSNickeau 417*04fd306cSNickeau return ExecutionContext::getActualOrCreateFromEnv()->getRequestedPath()->getWikiId(); 418*04fd306cSNickeau 419*04fd306cSNickeau 420*04fd306cSNickeau } 421*04fd306cSNickeau 422*04fd306cSNickeau 423*04fd306cSNickeau public function toComboCallDokuWikiForm(): Call 424*04fd306cSNickeau { 425*04fd306cSNickeau return $this->toComboCall(self::DOKUWIKI_FORMAT); 426*04fd306cSNickeau } 427*04fd306cSNickeau 428*04fd306cSNickeau /** @noinspection PhpReturnValueOfMethodIsNeverUsedInspection */ 429*04fd306cSNickeau private function setFormat($format): EditButton 430*04fd306cSNickeau { 431*04fd306cSNickeau 432*04fd306cSNickeau if (!in_array($format, [self::DOKUWIKI_FORMAT, self::COMBO_FORMAT])) { 433*04fd306cSNickeau LogUtility::internalError("The tag format ($format) is not valid", self::CANONICAL); 434*04fd306cSNickeau return $this; 435*04fd306cSNickeau } 436*04fd306cSNickeau $this->format = $format; 437*04fd306cSNickeau return $this; 438*04fd306cSNickeau } 439*04fd306cSNickeau 440*04fd306cSNickeau public function setOutlineHeadingId($id): EditButton 441*04fd306cSNickeau { 442*04fd306cSNickeau $this->outlineHeadingId = $id; 443*04fd306cSNickeau return $this; 444*04fd306cSNickeau } 445*04fd306cSNickeau 446*04fd306cSNickeau /** 447*04fd306cSNickeau * @return string|null 448*04fd306cSNickeau */ 449*04fd306cSNickeau private function getHeadingId(): ?string 450*04fd306cSNickeau { 451*04fd306cSNickeau return $this->outlineHeadingId; 452*04fd306cSNickeau } 453*04fd306cSNickeau 454*04fd306cSNickeau private function getSectionId(): ?int 455*04fd306cSNickeau { 456*04fd306cSNickeau return $this->outlineSectionId; 457*04fd306cSNickeau } 458*04fd306cSNickeau 459*04fd306cSNickeau public function setOutlineSectionId(int $sectionSequenceId): EditButton 460*04fd306cSNickeau { 461*04fd306cSNickeau $this->outlineSectionId = $sectionSequenceId; 462*04fd306cSNickeau return $this; 463*04fd306cSNickeau } 464*04fd306cSNickeau 465*04fd306cSNickeau} 466