1<?php 2 3namespace dokuwiki\plugin\prosemirror\parser; 4 5class Mark 6{ 7 8 public static $markOrder = [ 9 'strong' => 1, 10 'underline' => 2, 11 'em' => 3, 12 'code' => 4, 13 'subscript' => 5, 14 'superscript' => 6, 15 'deleted' => 7, 16 'unformatted' => 99, 17 ]; 18 19 protected $type; 20 protected $attrs; 21 22 protected $tailLength = 0; 23 24 /** @var Mark */ 25 protected $previousMark = null; 26 27 /** @var Mark */ 28 protected $nextMark = null; 29 30 /** @var TextNode */ 31 protected $parent; 32 33 public function __construct($data, &$parent) 34 { 35 $this->type = $data['type']; 36 if (isset($data['attrs'])) { 37 $this->attrs = $data['attrs']; 38 } 39 $this->parent = &$parent; 40 } 41 42 public function setPrevious($previousMark) 43 { 44 $this->previousMark = &$previousMark; 45 } 46 47 public function setNext($nextMark) 48 { 49 $this->nextMark = &$nextMark; 50 } 51 52 public function isOpeningMark() 53 { 54 return $this->parent->getStartingNodeMarkScore($this->type) === $this->getTailLength(); 55 } 56 57 public function isClosingMark() 58 { 59 return $this->tailLength === 0; 60 } 61 62 public function incrementTail() 63 { 64 $this->tailLength += 1; 65 } 66 67 public function getTailLength() 68 { 69 return $this->tailLength; 70 } 71 72 public function getType() 73 { 74 return $this->type; 75 } 76 77 /** 78 * @param Mark $newPrevious 79 * @param null|Mark $newNext 80 * 81 * @return Mark 82 */ 83 public function switchPlaces(Mark $newPrevious, $newNext) 84 { 85 $oldPrevious = $this->previousMark; 86 $this->previousMark = &$newPrevious; 87 $this->nextMark = &$newNext; 88 if (null !== $newNext) { 89 $newNext->setPrevious($this); 90 } 91 return $oldPrevious; 92 } 93 94 public function sort() 95 { 96 if ($this->previousMark === null) { 97 return true; 98 } 99 if ($this->previousMark->getTailLength() > $this->tailLength) { 100 // the marks that ends later must be printed in front of those that end earlier 101 return true; 102 } 103 if ($this->previousMark->getTailLength() === $this->tailLength) { 104 if (self::$markOrder[$this->previousMark->getType()] < self::$markOrder[$this->type]) { 105 return true; 106 } 107 } 108 109 $newPrevious = $this->previousMark->switchPlaces($this, $this->nextMark); 110 $this->nextMark = &$this->previousMark; 111 $this->previousMark = &$newPrevious; 112 if (null !== $newPrevious) { 113 $newPrevious->setNext($this); 114 } 115 116 return false; 117 } 118 119 public function getFirst() 120 { 121 if (!$this->previousMark) { 122 return $this; 123 } 124 return $this->previousMark->getFirst(); 125 } 126 127 public function getLast() 128 { 129 if (!$this->nextMark) { 130 return $this; 131 } 132 return $this->nextMark->getLast(); 133 } 134 135 public function getPrevious() 136 { 137 return $this->previousMark; 138 } 139 140 public function getNext() 141 { 142 return $this->nextMark; 143 } 144 145 protected static $openingMarks = [ 146 'strong' => '**', 147 'em' => '//', 148 'underline' => '__', 149 'code' => '\'\'', 150 'subscript' => '<sub>', 151 'superscript' => '<sup>', 152 'deleted' => '<del>', 153 ]; 154 155 protected static $closingMarks = [ 156 'strong' => '**', 157 'em' => '//', 158 'underline' => '__', 159 'code' => '\'\'', 160 'subscript' => '</sub>', 161 'superscript' => '</sup>', 162 'deleted' => '</del>', 163 ]; 164 165 public function getOpeningSyntax() 166 { 167 if ($this->type !== 'unformatted') { 168 return self::$openingMarks[$this->type]; 169 } 170 return $this->getUnformattedSyntax('opening'); 171 } 172 173 public function getClosingSyntax() 174 { 175 if ($this->type !== 'unformatted') { 176 return self::$closingMarks[$this->type]; 177 } 178 179 return $this->getUnformattedSyntax('closing'); 180 } 181 182 /** 183 * Handle the edge case that %% is wrapped in nowiki syntax 184 * 185 * @param string $type 'opening' or 'closing' 186 * 187 * @return string 188 */ 189 protected function getUnformattedSyntax($type) 190 { 191 if (strpos($this->parent->getInnerSyntax(), '%%') === false) { 192 return '%%'; 193 } 194 if ($type === 'opening') { 195 return '<nowiki>'; 196 } 197 return '</nowiki>'; 198 } 199} 200