1<?php 2 3namespace dokuwiki\plugin\prosemirror\schema; 4 5/** 6 * Class Node 7 * 8 * @package dokuwiki\plugin\prosemirror\schema 9 * @link http://prosemirror.net/ref.html#model.Node 10 */ 11class Node implements \JsonSerializable 12{ 13 /** @var string The type of node that this is */ 14 protected $type; 15 16 /** @var Node[] holding the node's children */ 17 protected $content = []; 18 19 /** @var string For text nodes, this contains the node's text content. */ 20 protected $text; 21 22 /** @var Mark[] The marks (things like whether it is emphasized or part of a link) associated with this node */ 23 protected $marks = []; 24 25 /** @var array list of attributes */ 26 protected $attrs = []; 27 28 /** 29 * Node constructor. 30 * 31 * @param string $type 32 */ 33 public function __construct($type) 34 { 35 $this->type = $type; 36 if ($type == 'text') { 37 $this->setText(''); 38 } 39 } 40 41 /** 42 * @param Node $child 43 */ 44 public function addChild(Node $child) 45 { 46 if ($this->type == 'text') { 47 throw new \RuntimeException('TextNodes may not have children'); 48 } 49 $this->content[] = $child; 50 } 51 52 /** 53 * @param Mark $mark 54 */ 55 public function addMark(Mark $mark) 56 { 57 $this->marks[] = $mark; 58 } 59 60 /** 61 * @return string 62 */ 63 public function getType() 64 { 65 return $this->type; 66 } 67 68 /** 69 * @return string 70 */ 71 public function getText() 72 { 73 return $this->text; 74 } 75 76 /** 77 * @param string $text 78 */ 79 public function setText($text) 80 { 81 if ($this->type != 'text') { 82 throw new \RuntimeException('Non-TextNodes may not have text'); 83 } 84 $this->text = $text; 85 } 86 87 /** 88 * @param string $key Attribute key to get or set 89 * @param null $value Attribute value to set, null to get 90 * 91 * @return $this|mixed Either the wanted value or the Node itself 92 */ 93 public function attr($key, $value = null) 94 { 95 if (is_null($value)) { 96 if (isset($this->attrs[$key])) { 97 return $this->attrs[$key]; 98 } else { 99 return null; 100 } 101 } 102 103 $this->attrs[$key] = $value; 104 return $this; 105 } 106 107 /** 108 * Specify data which should be serialized to JSON 109 * 110 * @link http://php.net/manual/en/jsonserializable.jsonserialize.php 111 * @return mixed data which can be serialized by <b>json_encode</b>, 112 * which is a value of any type other than a resource. 113 * @since 5.4.0 114 */ 115 public function jsonSerialize() 116 { 117 $json = [ 118 'type' => $this->type, 119 ]; 120 if ($this->type == 'text') { 121 $json['text'] = $this->text; 122 } elseif ($this->content) { 123 $json['content'] = $this->content; 124 } 125 126 if ($this->marks) { 127 $json['marks'] = $this->marks; 128 } 129 if ($this->attrs) { 130 $json['attrs'] = $this->attrs; 131 } 132 133 return $json; 134 } 135 136 /** 137 * Check if any child nodes have been added to this node 138 * 139 * @return bool 140 */ 141 public function hasContent() 142 { 143 return $this->content !== []; 144 } 145 146 /** 147 * Trim all whitespace from the beginning of this node's content 148 * 149 * If this is a text-node then this node's text is left-trimmed 150 * 151 * If the first node in the content is afterwards only an empty string, then it is removed 152 * 153 * @return void 154 */ 155 public function trimContentLeft() 156 { 157 if ($this->hasContent()) { 158 $this->content[0]->trimContentLeft(); 159 if ($this->content[0]->getText() === '') { 160 array_shift($this->content); 161 } 162 return; 163 } 164 if ($this->text !== null) { 165 $this->text = ltrim($this->text); 166 } 167 } 168 169 /** 170 * Trim all whitespace from the end of this node's content 171 * 172 * If this is a text-node then this node's text is right-trimmed 173 * 174 * If the last node in the content is afterwards only an empty string, then it is removed 175 * 176 * @return void 177 */ 178 public function trimContentRight() 179 { 180 if ($this->hasContent()) { 181 $contentLength = count($this->content) - 1; 182 $this->content[$contentLength]->trimContentRight(); 183 if ($this->content[$contentLength]->getText() === '') { 184 array_pop($this->content); 185 } 186 return; 187 } 188 if ($this->text !== null) { 189 $this->text = rtrim($this->text); 190 } 191 } 192} 193