xref: /plugin/strata/types/wiki.php (revision 8147e7f0f3a9cfca132ca1e79e615abe3149787f)
15153720fSfkaag71<?php
25153720fSfkaag71/**
35153720fSfkaag71 * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
45153720fSfkaag71 * @author     Brend Wanders <b.wanders@utwente.nl>
55153720fSfkaag71 */
65153720fSfkaag71// must be run within Dokuwiki
75153720fSfkaag71if(!defined('DOKU_INC')) die('Meh.');
85153720fSfkaag71
95153720fSfkaag71use dokuwiki\Parsing\Parser;
105153720fSfkaag71use dokuwiki\Parsing\Handler\Block;
11*8147e7f0SFKaaguse dokuwiki\Extension\Event;
125153720fSfkaag71
135153720fSfkaag71/**
145153720fSfkaag71 * The 'render as wiki text' type.
155153720fSfkaag71 */
165153720fSfkaag71class plugin_strata_type_wiki extends plugin_strata_type {
175153720fSfkaag71    function normalize($value, $hint) {
185153720fSfkaag71        $ins = $this->_instructions($value);
195153720fSfkaag71
205153720fSfkaag71        $value = "\n".str_replace("\r\n","\n",$value)."\n";
215153720fSfkaag71
225153720fSfkaag71        for($i=count($ins)-1;$i>=0;$i--) {
235153720fSfkaag71            switch($ins[$i][0]) {
245153720fSfkaag71                case 'internallink':
255153720fSfkaag71                    $replacement = $this->_normalize_internallink($ins[$i][1]);
265153720fSfkaag71                    break;
275153720fSfkaag71                case 'locallink':
285153720fSfkaag71                    $replacement = $this->_normalize_locallink($ins[$i][1]);
295153720fSfkaag71                    break;
305153720fSfkaag71                case 'internalmedia':
315153720fSfkaag71                    $replacement = $this->_normalize_media($ins[$i][1]);
325153720fSfkaag71                    break;
335153720fSfkaag71                case 'externallink':
345153720fSfkaag71                    $replacement = $this->_linkSyntax($ins[$i][1], $ins[$i][1][0]);
355153720fSfkaag71                    break;
365153720fSfkaag71                default:
375153720fSfkaag71                    continue 2;
385153720fSfkaag71            }
395153720fSfkaag71
405153720fSfkaag71            $value = substr_replace($value, $replacement, $ins[$i][2], $ins[$i+1][2] - $ins[$i][2]);
415153720fSfkaag71        }
425153720fSfkaag71
435153720fSfkaag71        // strip off only the inserted newlines
445153720fSfkaag71        return substr($value,1,-1);
455153720fSfkaag71    }
465153720fSfkaag71
475153720fSfkaag71    /**
485153720fSfkaag71     * Normalizes an internal link.
495153720fSfkaag71     */
505153720fSfkaag71    function _normalize_internallink($instruction) {
515153720fSfkaag71        global $ID;
525153720fSfkaag71
535153720fSfkaag71        // split off query string
545153720fSfkaag71        $parts = explode('?', $instruction[0] ,2);
555153720fSfkaag71
565153720fSfkaag71        $id = $parts[0];
575153720fSfkaag71
585153720fSfkaag71		list($id,$hash) = explode('#', $id, 2);
595153720fSfkaag71        // normalize selflink
605153720fSfkaag71        if($id === '') {
615153720fSfkaag71            $id = $ID;
625153720fSfkaag71        }
635153720fSfkaag71
645153720fSfkaag71        // actually resolve the page
655153720fSfkaag71        resolve_pageid(getNS($ID), $id, $exists);
665153720fSfkaag71        // make the resolved pageid absolute, so it does not re-resolve to something else later on
675153720fSfkaag71        $id = ':'.$id;
685153720fSfkaag71
695153720fSfkaag71        // render the link
705153720fSfkaag71        return $this->_linkSyntax($instruction, $id.'#'.$hash);
715153720fSfkaag71    }
725153720fSfkaag71
735153720fSfkaag71    /**
745153720fSfkaag71     * Normalizes a local link.
755153720fSfkaag71     */
765153720fSfkaag71    function _normalize_locallink($instruction) {
775153720fSfkaag71        global $ID;
785153720fSfkaag71
795153720fSfkaag71        // simply prefix the current page
805153720fSfkaag71        return $this->_linkSyntax($instruction, $ID.'#'.$instruction[0]);
815153720fSfkaag71    }
825153720fSfkaag71
835153720fSfkaag71    /**
845153720fSfkaag71     * Normalizes a media array.
855153720fSfkaag71     */
865153720fSfkaag71    function _normalize_media($instruction) {
875153720fSfkaag71        global $ID;
885153720fSfkaag71
895153720fSfkaag71        // construct media structure based on input
905153720fSfkaag71        if(isset($instruction['type'])) {
915153720fSfkaag71            $media = $instruction;
925153720fSfkaag71        } else {
935153720fSfkaag71            list($src, $title, $align, $width, $height, $cache, $linking) = $instruction;
945153720fSfkaag71            $media = compact('src','title','align','width','height');
955153720fSfkaag71            $media['type']= 'internalmedia';
965153720fSfkaag71        }
975153720fSfkaag71
985153720fSfkaag71        // normalize internal media links
995153720fSfkaag71        if($media['type'] == 'internalmedia') {
1005153720fSfkaag71            list($src,$hash) = explode('#',$media['src'],2);
1015153720fSfkaag71            resolve_mediaid(getNS($ID),$src, $exists);
1025153720fSfkaag71            if($hash) $src.='#'.$hash;
1035153720fSfkaag71            $media['src'] = ':'.$src;
1045153720fSfkaag71        }
1055153720fSfkaag71
1065153720fSfkaag71        // render the media structure
1075153720fSfkaag71        return $this->_mediaSyntax($media);
1085153720fSfkaag71    }
1095153720fSfkaag71
1105153720fSfkaag71    /**
1115153720fSfkaag71     * Renders the media syntax.
1125153720fSfkaag71     */
1135153720fSfkaag71    function _mediaSyntax($media) {
1145153720fSfkaag71        // the source
1155153720fSfkaag71        $src = $media['src'];
1165153720fSfkaag71
1175153720fSfkaag71        // the resizing part
1185153720fSfkaag71        if(isset($media['width'])) {
1195153720fSfkaag71            $size = '?'.$media['width'];
1205153720fSfkaag71            if(isset($media['height'])) {
1215153720fSfkaag71                $size .= 'x'.$media['height'];
1225153720fSfkaag71            }
1235153720fSfkaag71        } else {
1245153720fSfkaag71            $size = '';
1255153720fSfkaag71        }
1265153720fSfkaag71
1275153720fSfkaag71        // the title part
1285153720fSfkaag71        if(isset($media['title'])) {
1295153720fSfkaag71            $title = '|'.$media['title'];
1305153720fSfkaag71        } else {
1315153720fSfkaag71            $title = '';
1325153720fSfkaag71        }
1335153720fSfkaag71
1345153720fSfkaag71        // the alignment parts
1355153720fSfkaag71        if(isset($media['align'])) {
1365153720fSfkaag71            switch($media['align']) {
1375153720fSfkaag71            case 'left':
1385153720fSfkaag71                $al = ''; $ar = ' '; break;
1395153720fSfkaag71            case 'right':
1405153720fSfkaag71                $al = ' '; $ar = ''; break;
1415153720fSfkaag71            case 'center':
1425153720fSfkaag71                $al = ' '; $ar = ' '; break;
1435153720fSfkaag71            }
1445153720fSfkaag71        }
1455153720fSfkaag71
1465153720fSfkaag71        // construct the syntax
1475153720fSfkaag71        return '{{'.$al.$src.$size.$ar.$title.'}}';
1485153720fSfkaag71    }
1495153720fSfkaag71
1505153720fSfkaag71    /**
1515153720fSfkaag71     * Renders the link syntax, invoking media normalization
1525153720fSfkaag71     * if required.
1535153720fSfkaag71     */
1545153720fSfkaag71    function _linkSyntax($instruction, $newLink) {
1555153720fSfkaag71        // fetch params from old link
1565153720fSfkaag71        $parts = explode('?', $instruction[0],2);
1575153720fSfkaag71        if(count($parts) === 2) {
1585153720fSfkaag71            $params = '?'.$parts[1];
1595153720fSfkaag71        } else {
1605153720fSfkaag71            $params = '';
1615153720fSfkaag71        }
1625153720fSfkaag71
1635153720fSfkaag71        // determine title
1645153720fSfkaag71        $title = '';
1655153720fSfkaag71        if(isset($instruction[1])) {
1665153720fSfkaag71            if(is_array($instruction[1])) {
1675153720fSfkaag71                if($instruction[1]['type'] == 'internalmedia') {
1685153720fSfkaag71                    $title='|'.$this->_normalize_media($instruction[1]);
1695153720fSfkaag71                } else {
1705153720fSfkaag71                    $title='|'.$this->_mediaSyntax($instruction[1]);
1715153720fSfkaag71                }
1725153720fSfkaag71            } else {
1735153720fSfkaag71                $title = '|'.$instruction[1];
1745153720fSfkaag71            }
1755153720fSfkaag71        }
1765153720fSfkaag71
1775153720fSfkaag71        // construct a new link string
1785153720fSfkaag71        return '[['.$newLink.$params.$title.']]';
1795153720fSfkaag71
1805153720fSfkaag71    }
1815153720fSfkaag71
1825153720fSfkaag71    function render($mode, &$R, &$T, $value, $hint) {
1835153720fSfkaag71        // though this breaks backlink functionality, we really do not want
1845153720fSfkaag71        // metadata renders of included pieces of wiki.
1855153720fSfkaag71        if($mode == 'xhtml' || $mode == 'odt') {
1865153720fSfkaag71            $instructions = $this->_instructions($value);
1875153720fSfkaag71            $instructions = array_slice($instructions, 2, -2);
1885153720fSfkaag71
1895153720fSfkaag71            // last-minute fix of newline in front of content
1905153720fSfkaag71            if(!empty($instructions[0][0]) && $instructions[0][0]=='cdata') {
1915153720fSfkaag71                $instructions[0][1][0] = ltrim($instructions[0][1][0]);
1925153720fSfkaag71            }
1935153720fSfkaag71
1945153720fSfkaag71            // actual render of content
1955153720fSfkaag71            $R->nest($instructions);
1965153720fSfkaag71        }
1975153720fSfkaag71    }
1985153720fSfkaag71
1995153720fSfkaag71    function getInfo() {
2005153720fSfkaag71        return array(
2015153720fSfkaag71            'desc'=>'Allows the use of dokuwiki syntax; only non-block syntax is allowed (only links, formatting, etc.; no tables, headers, and other large stuff). The hint is ignored.',
2025153720fSfkaag71            'tags'=>array()
2035153720fSfkaag71        );
2045153720fSfkaag71    }
2055153720fSfkaag71
2065153720fSfkaag71    function _instructions($text) {
2075153720fSfkaag71        // determine all parser modes that are allowable as inline modes
2085153720fSfkaag71        // (i.e., those that are allowed inside a table cell, minus those
2095153720fSfkaag71        // that have a paragraph type other than 'normal')
2105153720fSfkaag71
2115153720fSfkaag71        // determine all modes allowed inside a table cell or list item
2125153720fSfkaag71
2135153720fSfkaag71        // import parser classes and mode definitions to make the $PARSER_MODES global available to us
2145153720fSfkaag71        require_once(DOKU_INC . 'inc/parser/parser.php');
2155153720fSfkaag71        global $PARSER_MODES;
2165153720fSfkaag71        $allowedModes = array_merge(
2175153720fSfkaag71            $PARSER_MODES['formatting'],
2185153720fSfkaag71            $PARSER_MODES['substition'],
2195153720fSfkaag71            $PARSER_MODES['disabled'],
2205153720fSfkaag71            $PARSER_MODES['protected']
2215153720fSfkaag71        );
2225153720fSfkaag71
2235153720fSfkaag71        // determine all modes that are not allowed either due to paragraph
2245153720fSfkaag71        // handling, or because they're blacklisted as they don't make sense.
2255153720fSfkaag71        $blockHandler = new Block();
2265153720fSfkaag71        $disallowedModes = array_merge(
2275153720fSfkaag71            // inlined from Block::blockOpen due to being protected:
2285153720fSfkaag71            array(
2295153720fSfkaag71                'header',
2305153720fSfkaag71                'listu_open','listo_open','listitem_open','listcontent_open',
2315153720fSfkaag71                'table_open','tablerow_open','tablecell_open','tableheader_open','tablethead_open',
2325153720fSfkaag71                'quote_open',
2335153720fSfkaag71                'code','file','hr','preformatted','rss',
2345153720fSfkaag71                'htmlblock','phpblock',
2355153720fSfkaag71                'footnote_open',
2365153720fSfkaag71            ),
2375153720fSfkaag71            // inlined from Block::stackOpen due to being protected:
2385153720fSfkaag71            array(
2395153720fSfkaag71                'section_open',
2405153720fSfkaag71            ),
2415153720fSfkaag71            array('notoc', 'nocache')
2425153720fSfkaag71        );
2435153720fSfkaag71
2445153720fSfkaag71        $allowedModes = array_diff($allowedModes, $disallowedModes);
2455153720fSfkaag71
2465153720fSfkaag71        $parser = new Parser(new Doku_Handler());
2475153720fSfkaag71
2485153720fSfkaag71        foreach(p_get_parsermodes() as $mode) {
2495153720fSfkaag71            if(!in_array($mode['mode'], $allowedModes)) continue;
2505153720fSfkaag71            $parser->addMode($mode['mode'], $mode['obj']);
2515153720fSfkaag71        }
2525153720fSfkaag71
253*8147e7f0SFKaag        Event::createAndTrigger('PARSER_WIKITEXT_PREPROCESS', $text);
2545153720fSfkaag71        $p = $parser->parse($text);
2555153720fSfkaag71        return $p;
2565153720fSfkaag71    }
2575153720fSfkaag71}
258