Mark::sort()   A
last analyzed

Complexity

Conditions 6
Paths 7

Size

Total Lines 23
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

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