1<?php
2
3namespace dokuwiki\plugin\prosemirror\parser;
4
5use dokuwiki\Extension\Event;
6use dokuwiki\plugin\prosemirror\ProsemirrorException;
7
8abstract class Node implements NodeInterface
9{
10    private static $nodeclass = [
11        'text' => TextNode::class,
12        'paragraph' => ParagraphNode::class,
13        'list_paragraph' => ParagraphNode::class,
14        'bullet_list' => ListNode::class,
15        'ordered_list' => ListNode::class,
16        'heading' => HeadingNode::class,
17        'preformatted' => PreformattedNode::class,
18        'code_block' => CodeBlockNode::class,
19        'blockquote' => QuoteNode::class,
20        'image' => ImageNode::class,
21        'hard_break' => HardBreakNode::class,
22        'horizontal_rule' => HruleNode::class,
23        'footnote' => FootnoteNode::class,
24        'smiley' => SmileyNode::class,
25        'table' => TableNode::class,
26        'table_row' => TableRowNode::class,
27        'table_cell' => TableCellNode::class,
28        'table_header' => TableCellNode::class,
29        'rss' => RSSNode::class,
30        'dwplugin_inline' => PluginNode::class,
31        'dwplugin_block' => PluginNode::class,
32    ];
33
34    private static $linkClasses = [
35        'interwikilink' => InterwikiLinkNode::class,
36        'internallink' => InternalLinkNode::class,
37        'emaillink' => EmailLinkNode::class,
38        'externallink' => ExternalLinkNode::class,
39        'windowssharelink' => WindowsShareLinkNode::class,
40        'other' => ExternalLinkNode::class,
41    ];
42
43    /**
44     * Get a Node instance of the correct type
45     *
46     * @param array     $node
47     * @param Node      $parent
48     * @param Node|null $previous
49     *
50     * @return Node
51     */
52    public static function getSubNode($node, Node $parent, Node $previous = null)
53    {
54        try {
55            if ($node['type'] === 'link') {
56                $linkType = $node['attrs']['data-type'];
57                return new self::$linkClasses[$linkType]($node, $parent, $previous);
58            }
59
60            if (isset(self::$nodeclass[$node['type']])) {
61                return new self::$nodeclass[$node['type']]($node, $parent, $previous);
62            }
63            $eventData = [
64                'node' => $node,
65                'parent' => $parent,
66                'previous' => $previous,
67                'newNode' => null,
68            ];
69            $event = new Event('PROSEMIRROR_PARSE_UNKNOWN', $eventData);
70            if ($event->advise_before() || !is_a($eventData['newNode'], self::class)) {
71                $exception = new ProsemirrorException('Invalid node type received: ' . $node['type'], 0);
72                $exception->addExtraData('nodeData', $node);
73                $exception->addExtraData('parentNodeType', get_class($parent));
74
75                throw $exception;
76            }
77            return $eventData['newNode'];
78        } catch (\Error $e) {
79            $exception = new ProsemirrorException(
80                'FIXME: better message for general error! Invalid node type received: ' . $node['type'],
81                0,
82                $e
83            );
84            $exception->addExtraData('nodeData', $node);
85            $exception->addExtraData('parentNodeType', get_class($parent));
86
87            throw $exception;
88        }
89    }
90
91    /**
92     * Get the node's representation as DokuWiki Syntax
93     *
94     * @return string
95     */
96    abstract public function toSyntax();
97}
98