1<?php 2 3namespace dokuwiki\plugin\prosemirror\parser; 4 5class TextNode extends Node implements InlineNodeInterface 6{ 7 /** @var TextNode */ 8 public $previous; 9 10 /** @var Node */ 11 protected $parent; 12 13 /** @var Mark[] */ 14 protected $marks = []; 15 16 protected $text = ''; 17 18 public function __construct($data, Node $parent, Node $previous = null) 19 { 20 $this->parent = &$parent; 21 if ($previous !== false) { 22 $this->previous = &$previous; 23 } 24 25 $this->text = $data['text'] ?? ''; 26 if (isset($data['marks'])) { 27 $this->setMarks($data['marks']); 28 } 29 } 30 31 public function getPrefixSyntax() 32 { 33 $doc = ''; 34 35 /** @var Mark[] $openingMarks */ 36 $openingMarks = []; 37 foreach ($this->marks as $mark) { 38 if ($mark->isOpeningMark()) { 39 $previousOpeningMark = end($openingMarks); 40 if ($previousOpeningMark) { 41 $mark->setPrevious($previousOpeningMark); 42 $previousOpeningMark->setNext($mark); 43 } 44 $openingMarks[] = $mark; 45 } 46 } 47 48 if (!empty($openingMarks)) { 49 $mark = $openingMarks[0]->getFirst(); 50 $doc .= $mark->getOpeningSyntax(); 51 while ($mark = $mark->getNext()) { 52 $doc .= $mark->getOpeningSyntax(); 53 } 54 55 foreach ($openingMarks as $mark) { 56 $mark->setNext(null); 57 $mark->setPrevious(null); 58 } 59 } 60 return $doc; 61 } 62 63 public function getPostfixSyntax() 64 { 65 $doc = ''; 66 /** @var Mark[] $closingMarks */ 67 $closingMarks = []; 68 foreach ($this->marks as $mark) { 69 if ($mark->isClosingMark()) { 70 $previousClosingMark = end($closingMarks); 71 if ($previousClosingMark) { 72 $mark->setPrevious($previousClosingMark); 73 $previousClosingMark->setNext($mark); 74 } 75 $closingMarks[] = $mark; 76 } 77 } 78 79 if (!empty($closingMarks)) { 80 $mark = $closingMarks[0]->getLast(); 81 $doc .= $mark->getClosingSyntax(); 82 while ($mark = $mark->getPrevious()) { 83 $doc .= $mark->getClosingSyntax(); 84 } 85 86 foreach ($closingMarks as $mark) { 87 $mark->setNext(null); 88 $mark->setPrevious(null); 89 } 90 } 91 92 return $doc; 93 } 94 95 public function getInnerSyntax() 96 { 97 return $this->text; 98 } 99 100 101 public function toSyntax() 102 { 103 $prefix = $this->getPrefixSyntax(); 104 $inner = $this->getInnerSyntax(); 105 $postfix = $this->getPostfixSyntax(); 106 return $prefix . $inner . $postfix; 107 } 108 109 /** 110 * @param array $marks 111 * 112 * @return $this 113 * @throws \Exception 114 */ 115 protected function setMarks(array $marks) 116 { 117 foreach ($marks as $markData) { 118 $currentMark = new Mark($markData, $this); 119 $type = $currentMark->getType(); 120 $this->marks[$type] = $currentMark; 121 if ($this->previous !== null) { 122 $this->previous->increaseMark($type); 123 } 124 } 125 return $this; 126 } 127 128 /** 129 * @param string $markType 130 */ 131 public function increaseMark($markType) 132 { 133 if (!isset($this->marks[$markType])) { 134 return; 135 } 136 137 $this->marks[$markType]->incrementTail(); 138 if ($this->previous !== null) { 139 $this->previous->increaseMark($markType); 140 } 141 } 142 143 public function getStartingNodeMarkScore($markType) 144 { 145 if ($this === $this->previous) { 146 throw new \Exception('circular reference: ' . $this->text); 147 } 148 if (!isset($this->marks[$markType])) { 149 // we don't have that mark 150 return null; 151 } 152 if ($this->previous === null) { 153 // we are the first node 154 return $this->marks[$markType]->getTailLength(); 155 } 156 157 $earlierMarkScore = $this->previous->getStartingNodeMarkScore($markType); 158 if ($earlierMarkScore === null) { 159 // the mark begins with us 160 return $this->marks[$markType]->getTailLength(); 161 } 162 return $earlierMarkScore; 163 } 164} 165