From ee20e7d16637625e900f518b6b46a61bfa30fe6e Mon Sep 17 00:00:00 2001
From: andi <andi@splitbrain.org>
Date: Thu, 19 May 2005 22:10:09 +0200
Subject: [PATCH] first attempt of syntax plugins

The first version of the new plugin system. Syntax plugins only yet. A very simple
example plugin called info (doing nothig useful yet) is included.

Missing Features

  - Doku_Block_Handler needs work (doesn't honur plugins yet)
  - there is no way to specify the order of plugins and other modes yet
  - useful output from the info plugin
  - bug testing and fixing
  - code cleanup
  - documentation

darcs-hash:20050519201009-9977f-f793dbfc6a39d8a9643b610927d93cd3288bdd6b.gz
---
 inc/html.php                |   2 +-
 inc/init.php                |   5 ++
 inc/parser/handler.php      |  19 +++++
 inc/parser/lexer.php        |   7 ++
 inc/parser/parser.php       | 134 +++++++++++++++++++++++++-----------
 inc/parser/xhtml.php        |  10 ++-
 inc/parserutils.php         |  28 ++++++--
 inc/plugins/info/syntax.php |  63 +++++++++++++++++
 inc/plugins/syntax.php      |  66 ++++++++++++++++++
 inc/pluginutils.php         |  62 +++++++++++++++++
 inc/template.php            |   2 +-
 11 files changed, 350 insertions(+), 48 deletions(-)
 create mode 100644 inc/plugins/info/syntax.php
 create mode 100644 inc/plugins/syntax.php
 create mode 100644 inc/pluginutils.php

diff --git a/inc/html.php b/inc/html.php
index c49a2b220..370754c52 100644
--- a/inc/html.php
+++ b/inc/html.php
@@ -364,7 +364,7 @@ function html_search(){
  *
  * @author Andreas Gohr <andi@splitbrain.org>
  */
-function html_locked($ip){
+function html_locked(){
   global $ID;
   global $conf;
   global $lang;
diff --git a/inc/init.php b/inc/init.php
index 150e07d83..af1d1eb9c 100644
--- a/inc/init.php
+++ b/inc/init.php
@@ -10,6 +10,7 @@
   error_reporting(E_ALL ^ E_NOTICE);
 
   //prepare config array()
+  global $conf;
   $conf = array();
 
   // load the config file(s)
@@ -17,12 +18,16 @@
   @include_once(DOKU_INC.'conf/local.php');
 
   //prepare language array
+  global $lang;
   $lang = array();
 
   // define baseURL
   if(!defined('DOKU_BASE')) define('DOKU_BASE',getBaseURL());
   if(!defined('DOKU_URL'))  define('DOKU_URL',getBaseURL(true));
 
+  // define Plugin dir
+  if(!defined('DOKU_PLUGIN'))  define('DOKU_PLUGIN',DOKU_INC.'inc/plugins/');
+
   // define main script
   if(!defined('DOKU_SCRIPT')) define('DOKU_SCRIPT','doku.php');
 
diff --git a/inc/parser/handler.php b/inc/parser/handler.php
index e1ded183a..2379d60ff 100644
--- a/inc/parser/handler.php
+++ b/inc/parser/handler.php
@@ -54,6 +54,25 @@ class Doku_Handler {
         }
         return FALSE;
     }
+
+
+    /**
+     * Special plugin handler
+     *
+     * This handler is called for all modes starting with 'plugin_'.
+     * An additional parameter with the plugin name is passed
+     *
+     * @author Andreas Gohr <andi@splitbrain.org>
+     */
+    function plugin($match, $state, $pos, $pluginname){
+        $data = array($match);
+        $plugin = null;
+        if(plugin_load('syntax',$pluginname,$plugin)){
+            $data = $plugin->handle($match, $state, $pos, $handler);
+        }
+        $this->_addCall('plugin',array($pluginname,$data,$pos),$pos);
+        return TRUE;
+    }
     
     function base($match, $state, $pos) {
         switch ( $state ) {
diff --git a/inc/parser/lexer.php b/inc/parser/lexer.php
index e7961932d..1cacaeed5 100644
--- a/inc/parser/lexer.php
+++ b/inc/parser/lexer.php
@@ -471,6 +471,13 @@ class Doku_Lexer {
 		if (isset($this->_mode_handlers[$handler])) {
 			$handler = $this->_mode_handlers[$handler];
 		}
+    // modes starting with plugin_ are all handled by the same
+    // handler but with an additional parameter
+    if(substr($handler,0,7)=='plugin_'){
+      list($handler,$plugin) = split('_',$handler,2);
+		  return $this->_parser->$handler($content, $is_match, $pos, $plugin);
+    }
+
 		return $this->_parser->$handler($content, $is_match, $pos);
 	}
 	
diff --git a/inc/parser/parser.php b/inc/parser/parser.php
index dd2b72aa0..87a29328c 100644
--- a/inc/parser/parser.php
+++ b/inc/parser/parser.php
@@ -5,6 +5,45 @@ if(!defined('DOKU_INC')) define('DOKU_INC',realpath(dirname(__FILE__).'/../../')
 require_once DOKU_INC . 'inc/parser/lexer.php';
 require_once DOKU_INC . 'inc/parser/handler.php';
 
+
+/**
+ * Define various types of modes used by the parser - they are used to
+ * populate the list of modes another mode accepts
+ */
+global $PARSER_MODES;
+$PARSER_MODES = array(
+    // containers are complex modes that can contain many other modes
+    // hr breaks the principle but they shouldn't be used in tables / lists
+    // so they are put here
+    'container'    => array('listblock','table','quote','hr'),
+
+    // some mode are allowed inside the base mode only
+    'baseonly'     => array('header'),
+
+    // modes for styling text -- footnote behaves similar to styling
+    'formatting'   => array('strong', 'emphasis', 'underline', 'monospace',
+                            'subscript', 'superscript', 'deleted', 'footnote'),
+
+    // modes where the token is simply replaced - they can not contain any
+    // other modes
+    'substition'   => array('acronym','smiley','wordblock','entity',
+                            'camelcaselink', 'internallink','media',
+                            'externallink','linebreak','emaillink',
+                            'windowssharelink','filelink','notoc',
+                            'nocache','multiplyentity','quotes','rss'),
+
+    // modes which have a start and end token but inside which 
+    // no other modes should be applied
+    'protected'    => array('preformatted','code','file','php','html'),
+    
+    // inside this mode no wiki markup should be applied but lineendings
+    // and whitespace isn't preserved
+    'disabled'     => array('unformatted'),
+
+    // used to mark paragraph boundaries
+    'paragraphs'   => array('eol')
+);
+
 //-------------------------------------------------------------------
 
 /**
@@ -101,7 +140,7 @@ class Doku_Parser_Mode {
     var $Lexer;
     
     var $allowedModes = array();
-    
+
     // Called before any calls to connectTo
     function preConnect() {}
     
@@ -120,15 +159,16 @@ class Doku_Parser_Mode {
 class Doku_Parser_Mode_Base extends Doku_Parser_Mode {
     
     function Doku_Parser_Mode_Base() {
+        global $PARSER_MODES;
         
         $this->allowedModes = array_merge (
-                Doku_Parser_BlockContainers(),
-                Doku_Parser_BaseOnly(),
-                Doku_Parser_Paragraphs(),
-                Doku_Parser_Formatting(),
-                Doku_Parser_Substition(),
-                Doku_Parser_Protected(),
-                Doku_Parser_Disabled()
+                $PARSER_MODES['container'],
+                $PARSER_MODES['baseonly'],
+                $PARSER_MODES['paragraphs'],
+                $PARSER_MODES['formatting'],
+                $PARSER_MODES['substition'],
+                $PARSER_MODES['protected'],
+                $PARSER_MODES['disabled']
             );
     }
 }
@@ -137,13 +177,14 @@ class Doku_Parser_Mode_Base extends Doku_Parser_Mode {
 class Doku_Parser_Mode_Footnote extends Doku_Parser_Mode {
     
     function Doku_Parser_Mode_Footnote() {
+        global $PARSER_MODES;
         
         $this->allowedModes = array_merge (
-                Doku_Parser_BlockContainers(),
-                Doku_Parser_Formatting(),
-                Doku_Parser_Substition(),
-                Doku_Parser_Protected(),
-                Doku_Parser_Disabled()
+                $PARSER_MODES['container'],
+                $PARSER_MODES['formatting'],
+                $PARSER_MODES['substition'],
+                $PARSER_MODES['protected'],
+                $PARSER_MODES['disabled']
             );
         
     }
@@ -237,7 +278,6 @@ class Doku_Parser_Mode_HR extends Doku_Parser_Mode {
 
 //-------------------------------------------------------------------
 class Doku_Parser_Mode_Formatting extends Doku_Parser_Mode {
-    
     var $type;
     
     var $formatting = array (
@@ -278,6 +318,7 @@ class Doku_Parser_Mode_Formatting extends Doku_Parser_Mode {
         );
     
     function Doku_Parser_Mode_Formatting($type) {
+        global $PARSER_MODES;
     
         if ( !array_key_exists($type, $this->formatting) ) {
             trigger_error('Invalid formatting type '.$type, E_USER_WARNING);
@@ -285,12 +326,18 @@ class Doku_Parser_Mode_Formatting extends Doku_Parser_Mode {
         
         $this->type = $type;
 
+        // formatting may contain other formatting but not it self
+        $modes = $PARSER_MODES['formatting'];
+        $key = array_search($type, $modes);
+        if ( is_int($key) ) {
+            unset($modes[$key]);
+        }
+
         $this->allowedModes = array_merge (
-                Doku_Parser_Formatting($type),
-                Doku_Parser_Substition(),
-                Doku_Parser_Disabled()
+                $modes,
+                $PARSER_MODES['substition'],
+                $PARSER_MODES['disabled']
             );
-            
     }
     
     function connectTo($mode) {
@@ -321,20 +368,16 @@ class Doku_Parser_Mode_Formatting extends Doku_Parser_Mode {
 class Doku_Parser_Mode_ListBlock extends Doku_Parser_Mode {
 
     function Doku_Parser_Mode_ListBlock() {
+        global $PARSER_MODES;
     
         $this->allowedModes = array_merge (
-                Doku_Parser_Formatting(),
-                Doku_Parser_Substition(),
-                Doku_Parser_Disabled()
+                $PARSER_MODES['formatting'],
+                $PARSER_MODES['substition'],
+                $PARSER_MODES['disabled'],
+                $PARSER_MODES['protected'] #XXX new
             );
 
-        $this->allowedModes[] = 'footnote';
-        $this->allowedModes[] = 'preformatted';
-        $this->allowedModes[] = 'unformatted';
-        $this->allowedModes[] = 'html';
-        $this->allowedModes[] = 'php';
-        $this->allowedModes[] = 'code';
-        $this->allowedModes[] = 'file';
+    //    $this->allowedModes[] = 'footnote';
     }
     
     function connectTo($mode) {
@@ -355,15 +398,17 @@ class Doku_Parser_Mode_ListBlock extends Doku_Parser_Mode {
 class Doku_Parser_Mode_Table extends Doku_Parser_Mode {
     
     function Doku_Parser_Mode_Table() {
+        global $PARSER_MODES;
     
         $this->allowedModes = array_merge (
-                Doku_Parser_Formatting(),
-                Doku_Parser_Substition(),
-                Doku_Parser_Disabled()
+                $PARSER_MODES['formatting'],
+                $PARSER_MODES['substition'],
+                $PARSER_MODES['disabled'],
+                $PARSER_MODES['protected'] #XXX new
             );
-        $this->allowedModes[] = 'footnote';
-        $this->allowedModes[] = 'preformatted';
-        $this->allowedModes[] = 'unformatted';
+        #$this->allowedModes[] = 'footnote';
+        #$this->allowedModes[] = 'preformatted';
+        #$this->allowedModes[] = 'unformatted';
     }
     
     function connectTo($mode) {
@@ -473,15 +518,17 @@ class Doku_Parser_Mode_File extends Doku_Parser_Mode {
 class Doku_Parser_Mode_Quote extends Doku_Parser_Mode {
     
     function Doku_Parser_Mode_Quote() {
+        global $PARSER_MODES;
     
         $this->allowedModes = array_merge (
-                Doku_Parser_Formatting(),
-                Doku_Parser_Substition(),
-                Doku_Parser_Disabled()
+                $PARSER_MODES['formatting'],
+                $PARSER_MODES['substition'],
+                $PARSER_MODES['disabled'],
+                $PARSER_MODES['protected'] #XXX new
             );
-            $this->allowedModes[] = 'footnote';
-            $this->allowedModes[] = 'preformatted';
-            $this->allowedModes[] = 'unformatted';
+            #$this->allowedModes[] = 'footnote';
+            #$this->allowedModes[] = 'preformatted';
+            #$this->allowedModes[] = 'unformatted';
     }
     
     function connectTo($mode) {
@@ -774,9 +821,14 @@ class Doku_Parser_Mode_EmailLink extends Doku_Parser_Mode {
 }
 
 //-------------------------------------------------------------------
+//
+// XXX deprecated - replace by $PARSER_MODES 
+//
 // Help fns to keep mode lists - used to make it easier to populate
 // the list of modes another mode accepts
 
+/*
+
 // Can contain many other modes
 // E.g. a footnote can containing formatting etc.
 function Doku_Parser_BlockContainers() {
@@ -848,6 +900,8 @@ function Doku_Parser_Disabled() {
     );
     return $modes;
 }
+*/
 
+// --------------------------------------------------------------------------
 
 //Setup VIM: ex: et ts=4 enc=utf-8 :
diff --git a/inc/parser/xhtml.php b/inc/parser/xhtml.php
index f9f6be1e6..b58c24435 100644
--- a/inc/parser/xhtml.php
+++ b/inc/parser/xhtml.php
@@ -19,6 +19,7 @@ if ( !defined('DOKU_TAB') ) {
 }
 
 require_once DOKU_INC . 'inc/parser/renderer.php';
+require_once DOKU_INC . 'inc/pluginutils.php';
 
 /**
  * The Renderer 
@@ -41,7 +42,6 @@ class Doku_Renderer_xhtml extends Doku_Renderer {
 
     var $store = '';
 
-
     function document_start() {
     }
     
@@ -57,6 +57,14 @@ class Doku_Renderer_xhtml extends Doku_Renderer {
             $this->doc .= '</div>'.DOKU_LF;
         }
     }
+
+    //handles plugin rendering
+    function plugin($name,$data){
+        $plugin = null;
+        if(plugin_load('syntax',$name,$plugin)){
+            $plugin->render('xhtml',$this,$data);
+        }
+    }
     
     function toc_open() {
         global $lang;
diff --git a/inc/parserutils.php b/inc/parserutils.php
index 802ae8a0d..9c0e4fd9c 100644
--- a/inc/parserutils.php
+++ b/inc/parserutils.php
@@ -11,6 +11,7 @@
 
   require_once(DOKU_INC.'inc/confutils.php');
   require_once(DOKU_INC.'inc/pageutils.php');
+  require_once(DOKU_INC.'inc/pluginutils.php');
 
 /**
  * Returns the parsed Wikitext in XHTML for the given id and revision.
@@ -155,14 +156,26 @@ function p_cached_instructions($file,$cacheonly=false){
 function p_get_instructions($text){
   global $conf;
 
+  //import parser classes and mode definitions
   require_once DOKU_INC . 'inc/parser/parser.php';
-  
+
+  // load syntax plugins
+  $pluginlist = plugin_list('syntax');
+  if(count($pluginlist)){
+    global $PARSER_MODES;
+    $plugins    = array();
+    foreach($pluginlist as $p){
+      plugin_load('syntax',$p,$plugin[$p]);                  //load plugin into $plugin array
+      $PARSER_MODES[$plugin[$p]->getType()][] = "plugin_$p"; //register mode type
+    }
+  }
+ 
   // Create the parser
   $Parser = & new Doku_Parser();
   
   // Add the Handler
   $Parser->Handler = & new Doku_Handler();
-  
+
   // Load all the modes
   $Parser->addMode('listblock',new Doku_Parser_Mode_ListBlock());
   $Parser->addMode('preformatted',new Doku_Parser_Mode_Preformatted()); 
@@ -192,7 +205,7 @@ function p_get_instructions($text){
   
   $Parser->addMode('smiley',new Doku_Parser_Mode_Smiley(array_keys(getSmileys())));
   $Parser->addMode('acronym',new Doku_Parser_Mode_Acronym(array_keys(getAcronyms())));
-  #$Parser->addMode('wordblock',new Doku_Parser_Mode_Wordblock(getBadWords()));
+  #$Parser->addMode('wordblock',new Doku_Parser_Mode_Wordblock($Modes,getBadWords()));
   $Parser->addMode('entity',new Doku_Parser_Mode_Entity(array_keys(getEntities())));
   
   $Parser->addMode('multiplyentity',new Doku_Parser_Mode_MultiplyEntity());
@@ -202,6 +215,11 @@ function p_get_instructions($text){
     $Parser->addMode('camelcaselink',new Doku_Parser_Mode_CamelCaseLink());
   }
 
+  //add plugins FIXME since order is important we, need to find a better way!
+  foreach ( array_keys($plugin) as $p ) {
+    $Parser->addMode("plugin_$p",$plugin[$p]);
+  }
+
   $Parser->addMode('internallink',new Doku_Parser_Mode_InternalLink());
   $Parser->addMode('rss',new Doku_Parser_Mode_RSS());
   $Parser->addMode('media',new Doku_Parser_Mode_Media());
@@ -210,10 +228,10 @@ function p_get_instructions($text){
   $Parser->addMode('windowssharelink',new Doku_Parser_Mode_WindowsShareLink());
   //$Parser->addMode('filelink',new Doku_Parser_Mode_FileLink()); //FIXME ???
   $Parser->addMode('eol',new Doku_Parser_Mode_Eol());
-  
+
   // Do the parsing
   $p    = $Parser->parse($text);
-#  dbg($p);
+//  dbg($p);
   return $p;
 }  
 
diff --git a/inc/plugins/info/syntax.php b/inc/plugins/info/syntax.php
new file mode 100644
index 000000000..4567de685
--- /dev/null
+++ b/inc/plugins/info/syntax.php
@@ -0,0 +1,63 @@
+<?php
+/**
+ * Info Plugin: Displays information about various DokuWiki internals
+ * 
+ * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
+ * @author     Andreas Gohr <andi@splitbrain.org>
+ */
+
+if(!defined('DOKU_INC')) define('DOKU_INC',realpath(dirname(__FILE__).'/../../').'/');
+if(!defined('DOKU_PLUGIN')) define('DOKU_PLUGIN',DOKU_INC.'inc/plugins/');
+require_once(DOKU_PLUGIN.'syntax.php');
+
+/**
+ * All DokuWiki plugins to extend the parser/rendering mechanism
+ * need to inherit from this class
+ */
+class syntax_plugin_info extends DokuWiki_Syntax_Plugin {
+
+    /**
+     * What kind of syntax are we?
+     */
+    function getType(){
+        return 'substition';
+    }
+    
+
+    /**
+     * Connect pattern to lexer
+     */
+    function connectTo($mode) {
+        $this->Lexer->addSpecialPattern('~~INFO:\w+~~',$mode,'plugin_info');
+    }
+
+
+    /**
+     * Handle the match
+     */
+    function handle($match, $state, $pos, &$handler){
+        $match = substr($match,7,-2); //strip ~~INFO: from start and ~~ from end
+        return array(strtolower($match));
+    }
+
+    /**
+     * Create output
+     */
+    function render($mode, &$renderer, $data) {
+        if($mode == 'xhtml'){
+            //handle various info stuff
+            switch ($data[0]){
+                case 'foo': 
+                    $renderer->doc .= "foo is foo";
+                    break;
+                default:
+                    $renderer->doc .= "no info about ".htmlspecialchars($data[0]);
+            }
+            return true;
+        }
+        return false;
+    }
+
+}
+
+//Setup VIM: ex: et ts=4 enc=utf-8 :
diff --git a/inc/plugins/syntax.php b/inc/plugins/syntax.php
new file mode 100644
index 000000000..bb5680cd3
--- /dev/null
+++ b/inc/plugins/syntax.php
@@ -0,0 +1,66 @@
+<?php
+/**
+ * Syntax Plugin Prototype
+ * 
+ * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
+ * @author     Andreas Gohr <andi@splitbrain.org>
+ */
+
+if(!defined('DOKU_INC')) define('DOKU_INC',realpath(dirname(__FILE__).'/../').'/');
+if(!defined('DOKU_PLUGIN')) define('DOKU_PLUGIN',DOKU_INC.'inc/plugins/');
+require_once(DOKU_INC.'inc/parser/parser.php');
+
+/**
+ * All DokuWiki plugins to extend the parser/rendering mechanism
+ * need to inherit from this class
+ */
+class DokuWiki_Syntax_Plugin extends Doku_Parser_Mode {
+
+    /**
+     * Needs to return one of the mode types defined in $PARSER_MODES in parser.php
+     */
+    function getType(){
+        trigger_error('getType() not implemented in '.get_class($this), E_USER_WARNING);
+    }
+
+    /**
+     * Handler to prepare matched data for the rendering process
+     *
+     * Usually you should only need the $match param.
+     *
+     * @param   $match   string    The text matched by the patterns
+     * @param   $state   int       The lexer state for the match
+     * @param   $pos     int       The character position of the matched text
+     * @param   $handler ref       Reference to the Doku_Handler object
+     * @return  array              Return an array with all data you want to use in render
+     */
+    function handle($match, $state, $pos, &$handler){
+        trigger_error('handle() not implemented in '.get_class($this), E_USER_WARNING);
+    }
+
+    /**
+     * Handles the actual output creation.
+     *
+     * The function should always check for the given mode and return false
+     * when a mode isn't supported.
+     *
+     * $renderer contains a reference to the renderer object which is
+     * currently handling the rendering. You need to use it for writing
+     * the output. How this is done depends on the renderer used (specified
+     * by $mode
+     *
+     * The contents of the $data array depends on what the handler() function above
+     * created
+     *
+     * @param   $mode     string   current Rendermode
+     * @param   $renderer ref      reference to the current renderer object
+     * @param   $data     array    data created by handler()
+     * @return  boolean            rendered correctly?
+     */
+    function render($mode, &$renderer, $data) {
+        trigger_error('render() not implemented in '.get_class($this), E_USER_WARNING);
+    }
+
+}
+
+//Setup VIM: ex: et ts=4 enc=utf-8 :
diff --git a/inc/pluginutils.php b/inc/pluginutils.php
new file mode 100644
index 000000000..3be57f2d7
--- /dev/null
+++ b/inc/pluginutils.php
@@ -0,0 +1,62 @@
+<?php
+/**
+ * Utilities for handling plugins
+ * 
+ * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
+ * @author     Andreas Gohr <andi@splitbrain.org>
+ */
+
+/**
+ * Returns a list of available plugins of given type
+ *
+ * @author Andreas Gohr <andi@splitbrain.org>
+ */
+function plugin_list($type){
+  $plugins = array();
+  if ($dh = opendir(DOKU_PLUGIN)) {
+    while (false !== ($file = readdir($dh))) {
+      if ($file == '.' || $file == '..') continue;
+      if (is_file(DOKU_PLUGIN.$file)) continue;
+
+      if (@file_exists(DOKU_PLUGIN.$file.'/'.$type.'.php')){
+        $plugins[] = $file;
+      }
+    }
+    closedir($dh);
+  }
+  return $plugins;
+}
+
+/**
+ * Loads the given plugin and creates an object of it
+ *
+ * @author Andreas Gohr <andi@splitbrain.org>
+ *
+ * @param  $type string 	type of plugin to load
+ * @param  $name string 	name of the plugin to load
+ * @param  $ref  ref      will contain the plugin object
+ * @return boolean        plugin loading successful?
+ */
+function plugin_load($type,$name,&$ref){
+  //we keep all loaded plugins available in global scope for reuse
+  global $DOKU_PLUGINS;
+
+	//plugin already loaded?
+	if($DOKU_PLUGINS[$type][$name] != null){
+		$ref = $DOKU_PLUGINS[$type][$name];
+		return true;
+	}
+
+  //try to load the wanted plugin file
+  if(!@include_once(DOKU_PLUGIN.$name.'/'.$type.'.php')){
+    return false;
+  }
+
+  //construct class and instanciate
+  $class = $type.'_plugin_'.$name;
+  $DOKU_PLUGINS[$type][$name] = new $class;
+  $ref = $DOKU_PLUGINS[$type][$name];
+  return true;
+}
+
+
diff --git a/inc/template.php b/inc/template.php
index 2baa6f77e..0826ba6f8 100644
--- a/inc/template.php
+++ b/inc/template.php
@@ -88,7 +88,7 @@ function tpl_content(){
       html_diff(con($PRE,$TEXT,$SUF),false);
       break;
     case 'locked':
-      html_locked($lockedby);
+      html_locked();
       break;
     case 'login':
       html_login();
-- 
GitLab