Browse Source

store dokuwiki custom code used for migration

David Bernard 9 years ago
parent
commit
010b438899

+ 2 - 2
.gitignore

@@ -9,7 +9,7 @@ target/
 .settings/
 .idea/
 out/
-bin/
+/bin/
 intellij/
 build/
 *.log
@@ -21,4 +21,4 @@ build/
 atlassian-ide-plugin.xml
 index.adoc
 *~
-*.off
+*.off

+ 84 - 0
src/dokuwiki/bin/render.php

@@ -0,0 +1,84 @@
+#!/usr/bin/php
+<?php
+if(!defined('DOKU_INC')) define('DOKU_INC', realpath(dirname(__FILE__).'/../').'/');
+define('NOSESSION', 1);
+require_once(DOKU_INC.'inc/init.php');
+
+
+/**
+ * A simple commandline tool to render some DokuWiki syntax with a given
+ * renderer.
+ *
+ * This may not work for plugins that expect a certain environment to be
+ * set up before rendering, but should work for most or even all standard
+ * DokuWiki markup
+ *
+ * @license GPL2
+ * @author  Andreas Gohr <[email protected]>
+ */
+class RenderCLI extends DokuCLI {
+
+    /**
+     * Register options and arguments on the given $options object
+     *
+     * @param DokuCLI_Options $options
+     * @return void
+     */
+    protected function setup(DokuCLI_Options $options) {
+        $options->setHelp(
+            'A simple commandline tool to render some DokuWiki syntax with a given renderer.'.
+            "\n\n".
+            'This may not work for plugins that expect a certain environment to be '.
+            'set up before rendering, but should work for most or even all standard '.
+            'DokuWiki markup'
+        );
+        $options->registerOption('renderer', 'The renderer mode to use. Defaults to xhtml', 'r', 'mode');
+        $options->registerOption('file', 'The file of the page to renderer.', 'f', 'filepath');
+    }
+
+    /**
+     * Your main program
+     *
+     * Arguments and options have been parsed when this is run
+     *
+     * @param DokuCLI_Options $options
+     * @throws DokuCLI_Exception
+     * @return void
+     */
+    protected function main(DokuCLI_Options $options) {
+        $renderer = $options->getOpt('renderer', 'xhtml');
+
+        if ($options->getOpt('file', '')) {
+          $result = $this->processFile($renderer, realpath($options->getOpt('file', '')));
+        } else {
+          $source = stream_get_contents(STDIN);
+          $result = p_render($renderer, p_get_instructions($source), array());
+        }
+        if(is_null($result)) throw new DokuCLI_Exception("No such renderer $renderer");
+        echo $result;
+    }
+    
+    protected function processFile($renderer, $path) {
+        static $trunclen = null;
+        if(!$trunclen) {
+            global $conf;
+            $trunclen = strlen($conf['datadir'].':');
+        }
+        global $ID;
+        global $INFO;
+        $pagepath = substr($path, $trunclen);
+        $ID = pathID($pagepath);
+        $INFO = pageinfo();
+        //$source = io_readFile($info['filepath']);
+        $rev = '';
+        $file = wikiFN($ID, $rev);
+        //echo $file . " // " . $ID . " // " . $path . " // " . $INFO['filepath'];
+        $result = p_render($renderer, p_get_instructions(io_readWikiPage($file,$id,$rev)), $INFO, $rev);
+        //Render into a file p_get_renderer($mode)
+        return $result;
+    }
+}
+
+// Main
+$cli = new RenderCLI();
+$cli->run();

+ 19 - 0
src/dokuwiki/bin/render_asciidoc.sh

@@ -0,0 +1,19 @@
+#!/bin/bash
+
+cd $(dirname $0)/..
+WIKI=$(pwd)
+export OUTPUT_DIR=$WIKI/../output_asciidoc
+export BIN_DIR=$WIKI/bin
+INPUT_DIR=$WIKI/data/pages
+cd $INPUT_DIR
+echo "dokuwiki: $WIKI"
+echo "bin: $BIN_DIR"
+echo "input: $INPUT_DIR"
+echo "output: $OUTPUT_DIR"
+find . -depth -name "*.txt" -exec sh -c 'mkdir -p $2/$(dirname $1) && $BIN_DIR/render.php -r asciidoc -f "$1" >"$2/${1%.txt}.adoc"' _ {} $OUTPUT_DIR \;
+#FILE="./documentation.txt"
+#echo "---"
+
+#$BIN_DIR/render.php -r asciidoc -f "$FILE" 
+#>"$OUTPUT_DIR/${FILE%.txt}.adoc"
+#cp -R $WIKI/data/media $OUTPUT_DIR/images

+ 51 - 0
src/dokuwiki/lib/plugins/asciidoc/helper.php

@@ -0,0 +1,51 @@
+<?php
+// must be run within Dokuwiki
+if (!defined('DOKU_INC')) die();
+
+class helper_plugin_asciidoc extends DokuWiki_Plugin {
+
+    /**
+     * Hooks for handling other plugins
+     *
+     * Since we generally outputs xml-ized instructions,
+     * we don't really need the plugins themselves to manage them.
+     *
+     * Feel free to add or modify hooks for plugins below to match your need.
+     */
+    function _asciidoc_extension(&$renderer,$name,$data) {
+        switch ($name) {
+            case 'htmlcomment':
+                list($state, $match) = $data;
+                $renderer->doc .= '<!--';
+                if (HTMLCOMMENT_SAFE) {
+                    $renderer->doc .= $renderer->_xmlEntities($match);
+                } else {
+                    $renderer->doc .= $match;
+                }
+                $renderer->doc .= '-->';
+                return true;
+            case 'info':
+                $renderer->doc .= '<macro name="info" type="'.$data[0].'" />'.DOKU_LF;
+                return true;
+            case 'pageredirect':
+                list($page, $message) = $data;
+                $renderer->doc .= '<macro name="pageredirect" target="'.$page.'" />'.DOKU_LF;
+                return true;
+            case 'plaintext':
+                $renderer->doc .= '<plaintext>';
+                $renderer->doc .= $renderer->_xmlEntities($data);
+                $renderer->doc .= '</plaintext>';
+                return true;
+            case 'tag_tag':
+                foreach ($data as $tag) {
+                    array_push($renderer->keywords, $renderer->_xmlEntities($tag));
+                }
+                return true;
+            case 'tag_topic':
+                list($ns, $tag, $flags) = $data;
+                $renderer->doc .= '<topic namespace="'.$ns.'" tags="'.$tag.'" flags="'.implode(' ',$flags).'" />'.DOKU_LF;
+                return true;
+        }
+        return false;
+    }
+}

+ 7 - 0
src/dokuwiki/lib/plugins/asciidoc/plugin.info.txt

@@ -0,0 +1,7 @@
+base   xml
+author Danny Lin
+email  [email protected]
+date   2015-06-22
+name   xml
+desc   Renders dokuwiki as simple XML output.
+url    http://www.dokuwiki.org/plugin:xml

+ 694 - 0
src/dokuwiki/lib/plugins/asciidoc/renderer.php

@@ -0,0 +1,694 @@
+<?php
+/**
+ * DokuWiki Plugin xml
+ *
+ * @author   Patrick Bueker <[email protected]>
+ * @author   Danny Lin <[email protected]>
+ * @license  GPLv2 or later (http://www.gnu.org/licenses/gpl.html)
+ *
+ */
+
+// must be run within Dokuwiki
+if(!defined('DOKU_INC')) die();
+
+if (!defined('DOKU_LF')) define('DOKU_LF', "\n");
+if (!defined('DOKU_TAB')) define('DOKU_TAB', "\t");
+require_once DOKU_INC . 'inc/parser/renderer.php';
+
+class renderer_plugin_asciidoc extends Doku_Renderer {
+
+    function __construct() {
+        $this->reset();
+    }
+
+    /**
+     * Allows renderer to be used again. Clean out any per-use values.
+     */
+    function reset() {
+        $this->info = array(
+            'cache' => true, // may the rendered result cached?
+            'toc'   => false, // render the TOC?
+        );
+        $this->precedinglevel = array();
+        $this->sectionlevel = 1;
+        $this->helper         = &plugin_load('helper','asciidoc');
+        $this->keywords = array();
+        $this->doctitle = '';
+        $this->doc            = '';
+        $this->tagStack       = array();
+        $this->listKindStack      = array();
+        $this->quoteStack      = array();
+        $this->relfileprefix = '';
+
+        $this->smiley_to_emoticon = array(
+          '>:(' => 'angry', '>:-(' => 'angry',
+          ':")' => 'blush', ':-")' => 'blush',
+          '</3' => 'broken_heart', '<\\3' => 'broken_heart',
+          ':/' => 'confused', ':-/' => 'confused', ':-\\' => 'confused', ':-\\' => 'confused',// twemoji shows question
+          ":'(" => 'cry', ":'-(" => 'cry', ':,(' => 'cry', ':,-(' => 'cry',
+          ':(' => 'frowning', ':-(' => 'frowning',
+          '<3' => 'heart',
+          ']:(' => 'imp', ']:-(' => 'imp',
+          'o:)' => 'innocent', 'O:)' => 'innocent', 'o:-)' => 'innocent', 'O:-)' => 'innocent', '0:)' => 'innocent', '0:-)' => 'innocent',
+          ":')" => 'joy', ":'-)" => 'joy', ':,)' => 'joy', ':,-)' => 'joy', ":'D" => 'joy', ":'-D" => 'joy', ':,D' => 'joy', ':,-D' => 'joy',
+          ':*' => 'kissing', ':-*' => 'kissing',
+          'x-)'=> 'laughing', 'X-)'=> 'laughing',
+          ':|' => 'neutral_face', ':-|' => 'neutral_face',
+          ':o' => 'open_mouth', ':-o' => 'open_mouth', ':O' => 'open_mouth', ':-O' => 'open_mouth',
+          ':@' => 'rage', ':-@' => 'rage',
+          ':D' => 'smile', ':-D'  => 'smile',
+          ':)' => 'smiley', ':-)' => 'smiley',
+          ']:)' => 'smiling_imp', ']:-)' => 'smiling_imp',
+          ":,'(" => 'sob', ":,'-(" => 'sob', ';(' => 'sob', ';-(' => 'sob',
+          ':P' => 'stuck_out_tongue', ':-P' => 'stuck_out_tongue',
+          '8-)' => 'sunglasses', 'B-)' => 'sunglasses',
+          ',:(' => 'sweat', ',:-(' => 'sweat',
+          ',:)' => 'sweat_smile', ',:-)'  => 'sweat_smile',
+          ':s' => 'unamused', ':-S' => 'unamused', ':z' => 'unamused', ':-Z' => 'unamused', ':$' => 'unamused', ':-$' => 'unamused',
+          ';)' => 'wink', ';-)' => 'wink'
+        );
+    }
+
+    /**
+     * Returns the format produced by this renderer.
+     *
+     * @return string
+     */
+    function getFormat(){return 'asciidoc';}
+
+    /**
+     * handle plugin rendering
+     */
+    function plugin($name,$data){
+        $plugin =& plugin_load('syntax',$name);
+        if ($plugin == null) return;
+        if ($this->helper->_asciidoc_extension($this,$name,$data)) return;
+        $plugin->render($this->getFormat(),$this,$data);
+    }
+
+    function document_start() {
+        global $conf;
+        global $ID;
+        global $INFO;
+        //TODO add title, author, revision, ...
+        // store the content type headers in metadata
+        // prepare date and path
+        $fn = $INFO['filepath'];
+        $fn = str_replace(fullpath($conf['datadir']).'/', '', $fn);
+        $fn = str_replace('.txt', '.adoc', $fn);
+        $fn = utf8_decodeFN($fn);
+
+        $this->doc = '';
+        $this->relfileprefix = str_repeat("../", substr_count ( $ID , ':'));
+
+        $headers = array(
+            'Content-Type' => 'text/asciidoc; charset=utf-8;',
+            'Content-Disposition' => 'attachment; filename="'.$fn.'";',
+        );
+        p_set_metadata($ID,array('format' => array('asciidoc' => $headers) ));
+    }
+
+    function document_end() {
+      global $ID;
+      global $INFO;
+      //TODO add title, author, revision, ...
+      if (empty($this->doctitle)) {
+        $this->doctitle = $this->_simpleTitle($ID);
+      }
+      $top = '';
+      $top .= '= ' . $this->doctitle .DOKU_LF;
+      $top .= ':author: ' . $INFO['editor'] .DOKU_LF;
+      $top .= ':revnumber: ' . $INFO['rev'] .DOKU_LF;
+      $top .= ':revdate: ' . dformat($INFO['lastmod']) .DOKU_LF;
+      if (!empty($this->keywords)) {
+          $top .= ':keywords: ' . implode(', ', $this->keywords) . DOKU_LF;
+      }
+      if (!empty($this->relfileprefix)){
+        $top .= ':relfileprefix: ' . $this->relfileprefix . DOKU_LF;
+        $top .= ':imagesdir: ' . rtrim($this->relfileprefix, '/') . DOKU_LF;
+      }
+      //:relfileprefix: ../
+      $top .= 'ifdef::env-github,env-browser[:outfilesuffix: .adoc]'  . DOKU_LF;
+      $top .= DOKU_LF;
+      $this->doc = $top . $this->doc;
+    }
+
+    function header($text, $level, $pos) {
+      //echo "header :" . $level . " // " . $this->sectionlevel . "\n";
+        if (!$text) return; //skip empty headlines
+        if ($level == 1 && empty($this->doctitle)) {
+            $this->doctitle = $text;
+        } else {
+            $this->doc .= DOKU_LF . DOKU_LF . str_repeat("=", $level) . ' ' . $text. DOKU_LF;
+        }
+    }
+
+    function section_open($level) {
+        array_push($this->precedinglevel,$level);
+        $this->sectionlevel = $this->sectionlevel + 1;
+    }
+
+    function section_close() {
+      $this->sectionlevel = $this->sectionlevel - 1;
+    }
+
+    function nocache() {
+        $this->info['cache'] = false;
+        $this->doc .= '<macro name="nocache" />'.DOKU_LF;
+    }
+
+    function notoc() {
+        $this->info['toc'] = false;
+        $this->doc .= '<macro name="notoc" />'.DOKU_LF;
+    }
+
+    function cdata($text) {
+        $this->doc .= $this->_xmlEntities($text);
+    }
+
+    function p_open() {
+        $this->doc .= DOKU_LF;
+        $this->_openTag($this, 'p_close', array());
+    }
+
+    function p_close() {
+        $this->_closeTags($this, __FUNCTION__);
+        $this->doc .= DOKU_LF.DOKU_LF;
+    }
+
+    function linebreak() {
+        $this->doc .= '+'.DOKU_LF;
+    }
+
+    function hr() {
+        $this->doc .= "'''".DOKU_LF;
+    }
+
+    function strong_open() {
+        $this->doc .= '*';
+        $this->_openTag($this, 'strong_close', array());
+    }
+
+    function strong_close() {
+        $this->_closeTags($this, __FUNCTION__);
+        $this->doc .= '*';
+    }
+
+    function emphasis_open() {
+        $this->doc .= '_';
+        $this->_openTag($this, 'emphasis_close', array());
+    }
+
+    function emphasis_close() {
+        $this->_closeTags($this, __FUNCTION__);
+        $this->doc .= '_';
+    }
+
+    function underline_open() {
+        $this->doc .= '+++<u>';
+        $this->_openTag($this, 'underline_close', array());
+    }
+
+    function underline_close() {
+        $this->_closeTags($this, __FUNCTION__);
+        $this->doc .= '</u>+++';
+    }
+
+    function monospace_open() {
+        $this->doc .= '`';
+        $this->_openTag($this, 'monospace_close', array());
+    }
+
+    function monospace_close() {
+        $this->_closeTags($this, __FUNCTION__);
+        $this->doc .= '`';
+    }
+
+    function subscript_open() {
+        $this->doc .= '~';
+        $this->_openTag($this, 'subscript_close', array());
+    }
+
+    function subscript_close() {
+        $this->_closeTags($this, __FUNCTION__);
+        $this->doc .= '~';
+    }
+
+    function superscript_open() {
+        $this->doc .= '^';
+        $this->_openTag($this, 'superscript_close', array());
+    }
+
+    function superscript_close() {
+        $this->_closeTags($this, __FUNCTION__);
+        $this->doc .= '^';
+    }
+
+    function deleted_open() {
+        $this->doc .= '+++<strike>';
+        $this->_openTag($this, 'deleted_close', array());
+    }
+
+    function deleted_close() {
+        $this->_closeTags($this, __FUNCTION__);
+        $this->doc .= '</strike>+++';
+    }
+
+    function footnote_open() {
+        $this->doc .= 'footnote:[';
+        $this->_openTag($this, 'footnote_close', array());
+    }
+
+    function footnote_close() {
+        $this->_closeTags($this, __FUNCTION__);
+        $this->doc .= ']';
+    }
+
+    function listu_open() {
+        array_unshift($this->listKindStack, "*");
+        $this->_openTag($this, 'listu_close', array());
+    }
+
+    function listu_close() {
+        $this->_closeTags($this, __FUNCTION__);
+        $this->doc .= DOKU_LF;
+        array_shift($this->listKindStack);
+    }
+
+    function listo_open() {
+        array_unshift($this->listKindStack, ".");
+        $this->_openTag($this, 'listo_close', array());
+    }
+
+    function listo_close() {
+        $this->_closeTags($this, __FUNCTION__);
+        $this->doc .= DOKU_LF;
+        array_shift($this->listKindStack);
+    }
+
+    function listitem_open($level) {
+        //$this->doc .= DOKU_TAB.'<listitem level="' . $level . '">';
+        $this->doc .= DOKU_LF.str_repeat($this->listKindStack[0], $level) . ' ';
+        $this->_openTag($this, 'listitem_close', array());
+    }
+
+    function listitem_close() {
+        $this->_closeTags($this, __FUNCTION__);
+        //$this->doc .= DOKU_LF;
+    }
+
+    function listcontent_open() {
+        //$this->doc .= '<listcontent>';
+        $this->_openTag($this, 'listcontent_close', array());
+    }
+
+    function listcontent_close() {
+        $this->_closeTags($this, __FUNCTION__);
+        //$this->doc .= '</listcontent>';
+    }
+
+    function unformatted($text) {
+        $this->doc .= '+++';
+        $this->doc .= $this->_xmlEntities($text);
+        $this->doc .= '+++';
+    }
+
+    function php($text) {
+        $this->doc .= '<php>';
+        $this->doc .= $this->_xmlEntities($text);
+        $this->doc .= '</php>';
+    }
+
+    function phpblock($text) {
+        $this->doc .= '<phpblock>';
+        $this->doc .= $this->_xmlEntities($text);
+        $this->doc .= '</phpblock>'.DOKU_LF;
+    }
+
+    function html($text) {
+        $this->doc .= '<html>';
+        $this->doc .= $this->_xmlEntities($text);
+        $this->doc .= '</html>';
+    }
+
+    function htmlblock($text) {
+        $this->doc .= '<htmlblock>';
+        $this->doc .= $this->_xmlEntities($text);
+        $this->doc .= '</htmlblock>'.DOKU_LF;
+    }
+
+    function preformatted($text) {
+      $this->doc .= DOKU_LF.'....'.DOKU_LF;
+      $this->doc .= $text;
+      $this->doc .= DOKU_LF.'....'.DOKU_LF;
+    }
+
+    function quote_open() {
+        $this->doc .= '[quote]'.DOKU_LF.'____'.DOKU_LF;
+        $this->_openTag($this, 'quote_close', array());
+    }
+
+    function quote_close() {
+        $this->_closeTags($this, __FUNCTION__);
+        $this->doc .= DOKU_LF.'____'.DOKU_LF;
+    }
+
+    function code($text, $lang = null, $file = null) {
+      $this->doc .= DOKU_LF.'[source';
+      if ($lang != null) $this->doc .= ',' . $lang;
+      $this->doc .= ']'.DOKU_LF;
+      if ($file != null) $this->doc .= '.' . $file;
+      $this->doc .= DOKU_LF.'----'.DOKU_LF;
+      $this->doc .= $text;
+      $this->doc .= DOKU_LF.'----'.DOKU_LF;
+    }
+
+    function file($text, $lang = null, $file = null) {
+      $this->code($text, $lang, $file);
+        // $this->doc .= '<file lang="' . $lang . '" file="' . $file . '">';
+        // $this->doc .= $this->_xmlEntities($text);
+        // $this->doc .= '</file>'.DOKU_LF;
+    }
+
+    function acronym($acronym) {
+      // not supported by asciidoc 1.5 (maybe in 1.7) => use footnote as workaround)
+      $this->doc .= '+++<abbr title="'. $this->_xmlEntities($this->acronyms[$acronym]) .'">' . $this->_xmlEntities($acronym) . '</abbr>+++';
+    }
+
+    function smiley($smiley) {
+        $this->doc .= 'emoji:' . $this->smiley_to_emoticon[$smiley];
+    }
+
+    function entity($entity) {
+        $this->doc .= $this->_xmlEntities($this->entities[$entity]);
+    }
+
+    /**
+     * Multiply entities are of the form: 640x480 where $x=640 and $y=480
+     *
+     * @param string $x The left hand operand
+     * @param string $y The rigth hand operand
+     */
+    function multiplyentity($x, $y) {
+        // $this->doc .= '<multiplyentity>';
+        // $this->doc .= '<x>'.$this->_xmlEntities($x).'</x>';
+        // $this->doc .= '<y>'.$this->_xmlEntities($y).'</y>';
+        // $this->doc .= '</multiplyentity>';
+        $this->doc .= $this->_xmlEntities($x).'x'.$this->_xmlEntities($y);
+    }
+
+    function singlequoteopening() {
+        global $lang;
+        $this->doc .= $lang['singlequoteopening'];
+        $this->_openTag($this, 'singlequoteclosing', array());
+    }
+
+    function singlequoteclosing() {
+        $this->_closeTags($this, __FUNCTION__);
+        $this->doc .= $lang['singlequoteclosing'];
+    }
+
+    function apostrophe() {
+        global $lang;
+        $this->doc .= $lang['apostrophe'];
+    }
+
+    function doublequoteopening() {
+        global $lang;
+        $this->doc .= $lang['doublequoteopening'];
+        $this->_openTag($this, 'doublequoteclosing', array());
+    }
+
+    function doublequoteclosing() {
+        $this->_closeTags($this, __FUNCTION__);
+        $this->doc .= $lang['doublequoteclosing'];
+    }
+
+    /**
+     * Links in CamelCase format.
+     *
+     * @param string $link Link text
+     */
+    function camelcaselink($link) {
+        $this->internallink($link, $link, 'camelcase');
+    }
+
+    function locallink($hash, $name = null) {
+        $this->doc .= '<<' .$hash . ',' . $this->_getLinkTitle($name, $hash, $isImage) .'>>';
+    }
+
+    /**
+     * Links of the form 'wiki:syntax', where $title is either a string or (for
+     * media links) an array.
+     *
+     * @param string $link The link text
+     * @param mixed $title Title text (array for media links)
+     * @param string $type overwrite the type (for camelcaselink)
+     */
+    function internallink($link, $title = null, $type='internal') {
+        global $ID;
+        $id = $link;
+        $name = $title;
+        list($id, $hash) = explode('#', $id, 2);
+        list($id, $search) = explode('?', $id, 2);
+        if ($id === '') $id = $ID;
+        $default = $this->_simpleTitle($id);
+        resolve_pageid(getNS($ID), $id, $exists);
+        $name = $this->_getLinkTitle($name, $default, $isImage, $id, 'content');
+        $path = str_replace(':', '/', $id);
+        //$this->doc .= '<link type="'.$type.'" link="'.$this->_xmlEntities($link).'" id="'.$id.'" search="'.$this->_xmlEntities($search).'" hash="'.$this->_xmlEntities($hash).'">';
+        //$this->doc .= $name;
+        //$this->doc .= '</link>';
+        $this->doc .= '<<'. $path . '#' . $hash .','. $name .'>>';
+    }
+
+    /**
+     * Full URL links with scheme. $title could be an array, for media links.
+     *
+     * @param string $link The link text
+     * @param mixed $title Title text (array for media links)
+     */
+    function externallink($link, $title = null) {
+        $this->doc .= 'link:' . $link  .'['. $this->_getLinkTitle($title, $link, $isImage) . ']';
+    }
+
+    /**
+     * @param string $link the original link - probably not much use
+     * @param string $title
+     * @param string $wikiName an indentifier for the wiki
+     * @param string $wikiUri the URL fragment to append to some known URL
+     */
+    function interwikilink($link, $title = null, $wikiName, $wikiUri) {
+        $name = $this->_getLinkTitle($title, $wikiUri, $isImage);
+        $url = $this->_resolveInterWiki($wikiName, $wikiUri);
+        //$this->doc .= '<link type="interwiki" link="'.$this->_xmlEntities($link).'" href="'.$url.'">';
+        //$this->doc .= $name;
+        //$this->doc .= '</link>';
+        $this->doc .= 'link:' . $url  .'['. $name . ']';
+    }
+
+    /**
+     * Link to a Windows share, $title could be an array (media)
+     *
+     * @param string $link
+     * @param mixed $title
+     */
+    function windowssharelink($link, $title = null) {
+        $name = $this->_getLinkTitle($title, $link, $isImage);
+        //$url = str_replace('\\','/',$link);
+        //$url = 'file:///'.$url;
+        $this->doc .= 'link:' . $link  .'['. $name . ']';
+    }
+
+    function emaillink($address, $name = null) {
+        $name = $this->_getLinkTitle($name, '', $isImage);
+        $url = $address;
+        $url = obfuscate($url);
+        $url   = 'mailto:'.$url;
+        $this->doc .= $url . '['. $name . ']';
+    }
+
+    /**
+     * Render media that is internal to the wiki.
+     *
+     * @param string $src
+     * @param string $title
+     * @param string $align
+     * @param string $width
+     * @param string $height
+     * @param string $cache
+     * @param string $linking
+     */
+    function internalmedia ($src, $title=null, $align=null, $width=null, $height=null, $cache=null, $linking=null) {
+        $this->doc .= $this->_media('internalmedia', $src, $title, $align, $width, $height, $cache, $linking);
+    }
+
+    /**
+     * Render media that is external to the wiki.
+     *
+     * @param string $src
+     * @param string $title
+     * @param string $align
+     * @param string $width
+     * @param string $height
+     * @param string $cache
+     * @param string $linking
+     */
+    function externalmedia ($src, $title=null, $align=null, $width=null, $height=null, $cache=null, $linking=null) {
+        $this->doc .= $this->_media('externalmedia', $src, $title, $align, $width, $height, $cache, $linking);
+    }
+
+    function table_open($maxcols = null, $numrows = null){
+        //$this->doc .= '<table maxcols="' . $maxcols . '" numrows="' . $numrows . '">'.DOKU_LF;
+        $this->doc .= '[cols="'. $maxcols . '", options="header"]' . DOKU_LF . '|===' . DOKU_LF;
+        $this->_openTag($this, 'table_close', array());
+    }
+
+    function table_close(){
+        $this->_closeTags($this, __FUNCTION__);
+        $this->doc .= DOKU_LF. '|===' . DOKU_LF;
+    }
+
+    function tablerow_open(){
+        $this->doc .= DOKU_LF;
+        $this->_openTag($this, 'tablerow_close', array());
+    }
+
+    function tablerow_close(){
+        $this->_closeTags($this, __FUNCTION__);
+        //$this->doc .= '</tablerow>'.DOKU_LF;
+    }
+
+    function tableheader_open($colspan = 1, $align = null, $rowspan = 1){
+      $this->tablecell_open($colspan, $align, $rowspan);
+      // TODO
+        // $this->doc .= '<tableheader';
+        // if ($colspan>1) $this->doc .= ' colspan="' . $colspan . '"';
+        // if ($rowspan>1) $this->doc .= ' rowspan="' . $rowspan . '"';
+        // if ($align) $this->doc .= ' align="' . $align . '"';
+        // $this->doc .= '>';
+        // $this->_openTag($this, 'tableheader_close', array());
+    }
+
+    function tableheader_close(){
+      $this->tablecell_close();
+        // $this->_closeTags($this, __FUNCTION__);
+        // $this->doc .= '</tableheader>';
+    }
+
+    function tablecell_open($colspan = 1, $align = null, $rowspan = 1) {
+      if ($rowspan > 1) $this->doc .= '.' . $rowspan . '+';
+      if ($colspan > 1) $this->doc .= $colspan . '+';
+      if ($align == "left") $this->doc .= '<';
+      if ($align == "center") $this->doc .= '^';
+      if ($align == "right") $this->doc .= '>';
+      $this->doc .= 'a|'; //always enable asciidoc content
+      $this->_openTag($this, 'tablecell_close', array());
+    }
+
+    function tablecell_close(){
+        $this->_closeTags($this, __FUNCTION__);
+        $this->doc .= DOKU_LF;
+    }
+
+    /**
+     * Private functions for internal handling
+     */
+    function _xmlEntities($text){
+        return htmlspecialchars($text,ENT_COMPAT,'UTF-8');
+    }
+
+    /**
+     * Render media elements.
+     * @see Doku_Renderer_xhtml::internalmedia()
+     *
+     * @param string $type Either 'internalmedia' or 'externalmedia'
+     * @param string $src
+     * @param string $title
+     * @param string $align
+     * @param string $width
+     * @param string $height
+     * @param string $cache
+     * @param string $linking
+     */
+    function _media($type, $src, $title=null, $align=null, $width=null, $height=null, $cache=null, $linking = null) {
+        global $ID;
+        $link = $src;
+        list($src, $hash) = explode('#', $src, 2);
+        if ($type == 'internalmedia') {
+            resolve_mediaid(getNS($ID), $src, $exists);
+        }
+        $name = $title ? $this->_xmlEntities($title) : $this->_xmlEntities(utf8_basename(noNS($src)));
+        if ($type == 'internalmedia') {
+        //     $src = ' id="'.$this->_xmlEntities($src).'" hash="'.$this->_xmlEntities($hash).'"';
+            $url = str_replace(':', '/', $src);
+        } else {
+            $url = $src;
+        }
+        
+        //$out = 'image:' . $url. '['. $name . ',with="'. $width .'",height="'. $height . '",align="' . $align . '", link="'. $linking .'"]';
+        if (stripos($url, '.mp4') !== false || stripos($url, '.webm') !== false || stripos($url, '.ogv') !== false) {
+          $out = DOKU_LF.'video::' . $url . '[]'.DOKU_LF;
+        } else {
+          if (empty($align)) {
+            $out = 'image:' . $url. '['. $name . ',with="'. $width .'",height="'. $height . '"]';
+          } else {
+            $out = DOKU_LF.'image::' . $url. '['. $name . ',with="'. $width .'",height="'. $height . '",align="' . $align .'"]'.DOKU_LF;
+          }
+        }
+        //$out .= '<media type="'.$type.'" link="'.$this->_xmlEntities($link).'"'.($src).' align="'.$align.'" width="'.$width.'" height="'.$height.'" cache="'.$cache.'" linking="'.$linking.'">';
+        return $out;
+    }
+
+    function _getLinkTitle($title, $default, & $isImage, $id=null, $linktype='content'){
+        $isImage = false;
+        if ( is_array($title) ) {
+            $isImage = true;
+            return $this->_imageTitle($title);
+        } elseif ( is_null($title) || trim($title)=='') {
+            if (useHeading($linktype) && $id) {
+                $heading = p_get_first_heading($id);
+                if ($heading) {
+                    return $this->_xmlEntities($heading);
+                }
+            }
+            return $this->_xmlEntities($default);
+        } else {
+            return $this->_xmlEntities($title);
+        }
+    }
+
+    function _imageTitle($img) {
+        global $ID;
+
+        // some fixes on $img['src']
+        // see internalmedia() and externalmedia()
+        list($img['src'], $hash) = explode('#', $img['src'], 2);
+        if ($img['type'] == 'internalmedia') {
+            resolve_mediaid(getNS($ID), $img['src'], $exists);
+        }
+
+        return $this->_media($img['type'],
+                              $img['src'],
+                              $img['title'],
+                              $img['align'],
+                              $img['width'],
+                              $img['height'],
+                              $img['cache']);
+    }
+    
+    function _openTag($class, $func, $data=null) {
+        $this->tagStack[] = array($class, $func, $data);
+    }
+
+    function _closeTags($class=null, $func=null) {
+        if ($this->tagClosing==true) return;  // skip nested calls
+        $this->tagClosing = true;
+        while(count($this->tagStack)>0) {
+            list($lastclass, $lastfunc, $lastdata) = array_pop($this->tagStack);
+            if (!($lastclass===$class && $lastfunc==$func)) call_user_func_array( array($lastclass, $lastfunc), $lastdata );
+            else break;
+        }
+        $this->tagClosing = false;
+    }
+}