summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorchris <chris@jalakai.co.uk>2006-04-14 21:37:37 +0200
committerchris <chris@jalakai.co.uk>2006-04-14 21:37:37 +0200
commitf65bfee1954d6697e5002f4253d0a7d2d1940eb6 (patch)
tree9dcac5e578987a6aea9a4ea043f25a9b0fabaaa3
parentc4e0e4a153fee5f985668670a91b2cd94a17dd75 (diff)
downloadrpg-f65bfee1954d6697e5002f4253d0a7d2d1940eb6.tar.gz
rpg-f65bfee1954d6697e5002f4253d0a7d2d1940eb6.tar.bz2
action plugins
This patch adds events and a third plugin type, "action" plugins, to DokuWiki. The patch doesn't include any event signalling, that will be added in later patches. Action plugins are loaded before most Dokuwiki processing takes place and at the same time are given the opportunity to register handlers (or hooks) to receive specific dokuwiki events. Other parts of Dokuwiki (e.g. templates and syntax plugins) can also register handlers to receive events. Any part of Dokuwiki can create and signal events, including templates and plugins. This patch also revises the admin plugin class by making it an extension of a new class, DokuWiki_Plugin. The DokuWiki_Plugin_Action class also extends this new class. Further details of events, their signalling and handling, and of action plugins will be added to wiki.splitbrain.org in due course :-) darcs-hash:20060414193737-9b6ab-f23d3d9b93e4c50a3ad97ced03eabc6c0363650b.gz
-rw-r--r--doku.php1
-rw-r--r--inc/events.php162
-rw-r--r--inc/pluginutils.php2
-rw-r--r--lib/plugins/action.php24
-rw-r--r--lib/plugins/admin.php176
-rw-r--r--lib/plugins/base.php190
6 files changed, 380 insertions, 175 deletions
diff --git a/doku.php b/doku.php
index af71e1c65..242d2e6c2 100644
--- a/doku.php
+++ b/doku.php
@@ -11,6 +11,7 @@
if(!defined('DOKU_INC')) define('DOKU_INC',realpath(dirname(__FILE__)).'/');
require_once(DOKU_INC.'inc/init.php');
require_once(DOKU_INC.'inc/common.php');
+ require_once(DOKU_INC.'inc/events.php');
require_once(DOKU_INC.'inc/pageutils.php');
require_once(DOKU_INC.'inc/html.php');
require_once(DOKU_INC.'inc/auth.php');
diff --git a/inc/events.php b/inc/events.php
new file mode 100644
index 000000000..59c1d904d
--- /dev/null
+++ b/inc/events.php
@@ -0,0 +1,162 @@
+<?php
+/**
+ * DokuWiki Events
+ *
+ * @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
+ * @author Christopher Smith <chris@jalakai.co.uk>
+ */
+
+if(!defined('DOKU_INC')) define('DOKU_INC',realpath(dirname(__FILE__).'/../').'/');
+require_once(DOKU_INC.'inc/pluginutils.php');
+class event {
+
+ // public properties
+ var $name = ''; // event name, objects must register against this name to see the event
+ var $data = NULL; // data relevant to the event, no standardised format (YET!)
+ var $result = NULL; // the results of the event action, only relevant in "*_after" advise
+
+ // private properties
+ var $_default = true; // whether or not to carry out the default action associated with the event
+ var $_continue = true; // whether or not to continue propagating the event to other handlers
+ var $_action = NULL; // the function executed to carry out the event
+
+ /**
+ * event constructor
+ */
+ function event($name, &$data, $fn=NULL) {
+
+ $this->name = $name;
+ $this->data =& $data;
+ $this->_action = $fn;
+
+ }
+
+ /**
+ * advise
+ *
+ * advise all registered handlers of this event
+ * any processing based on the event's _default property to be determined by the caller
+ *
+ * @return results of processing the event, usually $this->_default
+ */
+ function advise() {
+ global $EVENT_HANDLER;
+
+ return $EVENT_HANDLER->process_event($this,'');
+ }
+
+ /**
+ * trigger
+ *
+ * advise all registered (<event>_before) handlers that this event is about to take place
+ * carry out the default action using $this->data based on $this->_default, all of which
+ * may have been modified by the event handlers
+ * if the action was carried out, advise all registered (<event>_after) handlers that the
+ * event has taken place
+ *
+ * @return $event->results
+ * the value set by any <event>_before or <event> handlers if the default action is prevented
+ * or the results of the default action (as modified by <event>_after handlers)
+ * or NULL no action took place and no handler modified the value
+ */
+ function trigger() {
+ global $EVENT_HANDLER;
+
+ $EVENT_HANDLER->process_event($this,'before');
+ if ($this->_continue) $EVENT_HANDLER->process_event($this,'');
+
+ if ($this->_default && is_callable($this->_action)) {
+ if (is_array($this->_action)) {
+ list($obj,$method) = $this->_action;
+ $this->result = $obj->$method($this->data);
+ } else {
+ $fn = $this->_action;
+ $this->result = $fn($this->data);
+ }
+
+ $EVENT_HANDLER->process_event($this,'after');
+ }
+
+ return $this->result;
+ }
+
+ /**
+ * stopPropagation
+ *
+ * stop any further processing of the event by event handlers
+ * this function does not prevent the default action taking place
+ */
+ function stopPropagation() { $this->_continue = false; }
+
+ /**
+ * preventDefault
+ *
+ * prevent the default action taking place
+ */
+ function preventDefault() { $this->_default = false; }
+}
+
+class event_handler {
+
+ // public properties: none
+
+ // private properties
+ var $_hooks = array(); // array of events and their registered handlers
+
+ /*
+ * event_handler
+ *
+ * constructor, loads all action plugins and calls their register() method giving them
+ * an opportunity to register any hooks they require
+ */
+ function event_handler() {
+
+ // load action plugins
+ $plugin = NULL;
+ $pluginlist = plugin_list('action');
+
+ foreach ($pluginlist as $plugin_name) {
+ $plugin =& plugin_load('action',$plugin_name);
+
+ if ($plugin !== NULL) $plugin->register($this);
+ }
+ }
+
+ /*
+ * register_hook
+ *
+ * register a hook for an event
+ *
+ * @PARAM $event (string) name used by the event, (incl '_before' or '_after' for triggers)
+ * @PARAM $obj (obj) object in whose scope method is to be executed,
+ * if NULL, method is assumed to be a globally available function
+ * @PARAM $method (function) event handler function
+ * @PARAM $param (mixed) data passed to the event handler
+ */
+ function register_hook($event, &$obj, $method, $param) {
+ $this->_hooks[$event][] = array($obj, $method, $param);
+ }
+
+ function process_event(&$event,$advise='') {
+
+ $evt_name = $event->name . ($advise ? '_'.$advise : '');
+
+ if (!empty($this->_hooks[$evt_name])) {
+ $hook = reset($this->_hooks[$evt_name]);
+ do {
+ list($obj, $method, $param) = $hook;
+ if (is_null($obj)) {
+ $method($param, $event);
+ } else {
+ $obj->$method($param, $event);
+ }
+
+ } while ($event->_continue && $hook = next($this->_hooks[$evt_name]));
+ }
+
+ return $event->_default;
+ }
+}
+
+// create the event handler
+$EVENT_HANDLER = new event_handler();
diff --git a/inc/pluginutils.php b/inc/pluginutils.php
index d9cc848fe..4d3b5cbd6 100644
--- a/inc/pluginutils.php
+++ b/inc/pluginutils.php
@@ -7,7 +7,7 @@
*/
// plugin related constants
-$plugin_types = array('admin','syntax');
+$plugin_types = array('admin','syntax','action');
/**
* Returns a list of available plugins of given type
diff --git a/lib/plugins/action.php b/lib/plugins/action.php
new file mode 100644
index 000000000..05d8735b9
--- /dev/null
+++ b/lib/plugins/action.php
@@ -0,0 +1,24 @@
+<?php
+/**
+ * Admin Plugin Prototype
+ *
+ * @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
+ * @author Christopher Smith <chris@jalakai.co.uk>
+ */
+// must be run within Dokuwiki
+if(!defined('DOKU_INC')) die();
+
+if(!defined('DOKU_PLUGIN')) define('DOKU_PLUGIN',DOKU_INC.'lib/plugins/');
+require_once(DOKU_PLUGIN.'base.php');
+
+/**
+ * All DokuWiki plugins to extend the admin function
+ * need to inherit from this class
+ */
+class DokuWiki_Action_Plugin extends DokuWiki_Plugin {
+
+ function register($controller) {
+ trigger_error('register() not implemented in '.get_class($this), E_USER_WARNING);
+ }
+
+} \ No newline at end of file
diff --git a/lib/plugins/admin.php b/lib/plugins/admin.php
index 7245a73eb..0cf12ad93 100644
--- a/lib/plugins/admin.php
+++ b/lib/plugins/admin.php
@@ -9,32 +9,13 @@
if(!defined('DOKU_INC')) die();
if(!defined('DOKU_PLUGIN')) define('DOKU_PLUGIN',DOKU_INC.'lib/plugins/');
+require_once(DOKU_PLUGIN.'base.php');
/**
* All DokuWiki plugins to extend the admin function
* need to inherit from this class
*/
-class DokuWiki_Admin_Plugin {
-
- var $localised = false; // set to true by setupLocale() after loading language dependent strings
- var $lang = array(); // array to hold language dependent strings, best accessed via ->getLang()
- var $configloaded = false; // set to true by loadConfig() after loading plugin configuration variables
-
- /**
- * General Info
- *
- * Needs to return a associative array with the following values:
- *
- * author - Author of the plugin
- * email - Email address to contact the author
- * date - Last modified date of the plugin in YYYY-MM-DD format
- * name - Name of the plugin
- * desc - Short description of the plugin (Text only)
- * url - Website with more information on the plugin (eg. syntax description)
- */
- function getInfo(){
- trigger_error('getInfo() not implemented in '.get_class($this), E_USER_WARNING);
- }
+class DokuWiki_Admin_Plugin extends DokuWiki_Plugin {
function getMenuText($language) {
$menutext = $this->getLang('menu');
@@ -56,160 +37,7 @@ class DokuWiki_Admin_Plugin {
function html() {
trigger_error('html() not implemented in '.get_class($this), E_USER_WARNING);
}
-
- // private methods (maybe a dokuwiki plugin base class is required for these)
-
- // plugin introspection methods
- // extract from class name, format = <plugin type>_plugin_<name>[_<component name>]
- function getPluginType() { list($t) = explode('_', get_class($this), 2); return $t; }
- function getPluginName() { list($t, $p, $n) = explode('_', get_class($this), 4); return $n; }
- function getPluginComponent() { list($t, $p, $n, $c) = explode('_', get_class($this), 4); return (isset($c)?$c:''); }
-
- // localisation methods
- /**
- * getLang($id)
- * use this function to access plugin language strings
- * to try to minimise unnecessary loading of the strings when the plugin doesn't require them
- * e.g. when info plugin is querying plugins for information about themselves.
- *
- * @param $id id of the string to be retrieved
- * @return string string in appropriate language or english if not available
- */
- function getLang($id) {
- if (!$this->localised) $this->setupLocale();
-
- return (isset($this->lang[$id]) ? $this->lang[$id] : '');
- }
-
- /**
- * locale_xhtml($id)
- *
- * retrieve a language dependent file and pass to xhtml renderer for display
- * plugin equivalent of p_locale_xhtml()
- *
- * @param $id id of language dependent wiki page
- * @return string parsed contents of the wiki page in xhtml format
- */
- function locale_xhtml($id) {
- return p_cached_xhtml($this->localFN($id));
- }
-
- /**
- * localFN($id)
- * prepends appropriate path for a language dependent filename
- * plugin equivalent of localFN()
- */
- function localFN($id) {
- global $conf;
- $plugin = $this->getPluginName();
- $file = DOKU_PLUGIN.$plugin.'/lang/'.$conf['lang'].'/'.$id.'.txt';
- if(!@file_exists($file)){
- //fall back to english
- $file = DOKU_PLUGIN.$plugin.'/lang/en/'.$id.'.txt';
- }
- return $file;
- }
-
- /**
- * setupLocale()
- * reads all the plugins language dependent strings into $this->lang
- * this function is automatically called by getLang()
- */
- function setupLocale() {
- if ($this->localised) return;
-
- global $conf; // definitely don't invoke "global $lang"
- $path = DOKU_PLUGIN.$this->getPluginName().'/lang/';
-
- $lang = array();
-
- // don't include once, in case several plugin components require the same language file
- @include($path.'en/lang.php');
- if ($conf['lang'] != 'en') @include($path.$conf['lang'].'/lang.php');
-
- $this->lang = $lang;
- $this->localised = true;
- }
-
- // configuration methods
- /**
- * getConf($id)
- *
- * use this function to access plugin configuration variables
- */
- function getConf($id){
- global $conf;
- $plugin = $this->getPluginName();
-
- if (!$this->configloaded){
- if ($pconf = $this->loadConfig() !== false){
- foreach ($pconf as $key => $value){
- if (isset($conf['plugin'][$plugin][$key])) continue;
- $conf['plugin'][$plugin][$key] = $value;
- }
- $this->configloaded = true;
- }
- }
-
- return $conf['plugin'][$plugin][$id];
- }
-
- /**
- * loadConfig()
- * reads all plugin configuration variables into $this->conf
- * this function is automatically called by getConf()
- */
- function loadConfig(){
-
- $path = DOKU_PLUGIN.$this->getPluginName().'/conf/';
- $conf = array();
-
- if (!@file_exists($path.'default.php')) return false;
-
- // load default config file
- include($path.'default.php');
-
- return $conf;
- }
-
- // standard functions for outputing email addresses and links
- // use these to avoid having to duplicate code to produce links in line with the installation configuration
- function email($email, $name='', $class='', $more='') {
- if (!$email) return $name;
- $email = obfuscate($email);
- if (!$name) $name = $email;
- $class = "class='".($class ? $class : 'mail')."'";
- return "<a href='mailto:$email' $class title='$email' $more>$name</a>";
- }
-
- function external_link($link, $title='', $class='', $target='', $more='') {
- global $conf;
-
- $link = htmlentities($link);
- if (!$title) $title = $link;
- if (!$target) $target = $conf['target']['extern'];
- if ($conf['relnofollow']) $more .= ' rel="nofollow"';
-
- if ($class) $class = " class='$class'";
- if ($target) $target = " target='$target'";
- if ($more) $more = " ".trim($more);
-
- return "<a href='$link'$class$target$more>$title</a>";
- }
-
- // output text string through the parser, allows dokuwiki markup to be used
- // very ineffecient for small pieces of data - try not to use
- function render($text, $format='xhtml') {
- return p_render($format, p_get_instructions($text),$info);
- }
-
- // deprecated functions
- function plugin_localFN($id) { return $this->localFN($id); }
- function plugin_locale_xhtml($id) { return $this->locale_xhtml($id); }
- function plugin_email($e, $n='', $c='', $m='') { return $this->email($e, $n, $c, $m); }
- function plugin_link($l, $t='', $c='', $to='', $m='') { return $this->external_link($l, $t, $c, $to, $m); }
- function plugin_render($t, $f='xhtml') { return $this->render($t, $f); }
}
//Setup VIM: ex: et ts=4 enc=utf-8 : \ No newline at end of file
diff --git a/lib/plugins/base.php b/lib/plugins/base.php
new file mode 100644
index 000000000..7f27942aa
--- /dev/null
+++ b/lib/plugins/base.php
@@ -0,0 +1,190 @@
+<?php
+/**
+ * Admin Plugin Prototype
+ *
+ * @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
+ * @author Christopher Smith <chris@jalakai.co.uk>
+ */
+// must be run within Dokuwiki
+if(!defined('DOKU_INC')) die();
+
+if(!defined('DOKU_PLUGIN')) define('DOKU_PLUGIN',DOKU_INC.'lib/plugins/');
+
+/**
+ * All DokuWiki plugins to extend the admin function
+ * need to inherit from this class
+ */
+class DokuWiki_Plugin {
+
+ var $localised = false; // set to true by setupLocale() after loading language dependent strings
+ var $lang = array(); // array to hold language dependent strings, best accessed via ->getLang()
+ var $configloaded = false; // set to true by loadConfig() after loading plugin configuration variables
+
+ /**
+ * General Info
+ *
+ * Needs to return a associative array with the following values:
+ *
+ * author - Author of the plugin
+ * email - Email address to contact the author
+ * date - Last modified date of the plugin in YYYY-MM-DD format
+ * name - Name of the plugin
+ * desc - Short description of the plugin (Text only)
+ * url - Website with more information on the plugin (eg. syntax description)
+ */
+ function getInfo(){
+ trigger_error('getInfo() not implemented in '.get_class($this), E_USER_WARNING);
+ }
+
+ // plugin introspection methods
+ // extract from class name, format = <plugin type>_plugin_<name>[_<component name>]
+ function getPluginType() { list($t) = explode('_', get_class($this), 2); return $t; }
+ function getPluginName() { list($t, $p, $n) = explode('_', get_class($this), 4); return $n; }
+ function getPluginComponent() { list($t, $p, $n, $c) = explode('_', get_class($this), 4); return (isset($c)?$c:''); }
+
+ // localisation methods
+ /**
+ * getLang($id)
+ * use this function to access plugin language strings
+ * to try to minimise unnecessary loading of the strings when the plugin doesn't require them
+ * e.g. when info plugin is querying plugins for information about themselves.
+ *
+ * @param $id id of the string to be retrieved
+ * @return string string in appropriate language or english if not available
+ */
+ function getLang($id) {
+ if (!$this->localised) $this->setupLocale();
+
+ return (isset($this->lang[$id]) ? $this->lang[$id] : '');
+ }
+
+ /**
+ * locale_xhtml($id)
+ *
+ * retrieve a language dependent file and pass to xhtml renderer for display
+ * plugin equivalent of p_locale_xhtml()
+ *
+ * @param $id id of language dependent wiki page
+ * @return string parsed contents of the wiki page in xhtml format
+ */
+ function locale_xhtml($id) {
+ return p_cached_xhtml($this->localFN($id));
+ }
+
+ /**
+ * localFN($id)
+ * prepends appropriate path for a language dependent filename
+ * plugin equivalent of localFN()
+ */
+ function localFN($id) {
+ global $conf;
+ $plugin = $this->getPluginName();
+ $file = DOKU_PLUGIN.$plugin.'/lang/'.$conf['lang'].'/'.$id.'.txt';
+ if(!@file_exists($file)){
+ //fall back to english
+ $file = DOKU_PLUGIN.$plugin.'/lang/en/'.$id.'.txt';
+ }
+ return $file;
+ }
+
+ /**
+ * setupLocale()
+ * reads all the plugins language dependent strings into $this->lang
+ * this function is automatically called by getLang()
+ */
+ function setupLocale() {
+ if ($this->localised) return;
+
+ global $conf; // definitely don't invoke "global $lang"
+ $path = DOKU_PLUGIN.$this->getPluginName().'/lang/';
+
+ $lang = array();
+
+ // don't include once, in case several plugin components require the same language file
+ @include($path.'en/lang.php');
+ if ($conf['lang'] != 'en') @include($path.$conf['lang'].'/lang.php');
+
+ $this->lang = $lang;
+ $this->localised = true;
+ }
+
+ // configuration methods
+ /**
+ * getConf($id)
+ *
+ * use this function to access plugin configuration variables
+ */
+ function getConf($id){
+ global $conf;
+
+ $plugin = $this->getPluginName();
+
+ if (!$this->configloaded){
+ if ($pconf = $this->loadConfig() !== false){
+ foreach ($pconf as $key => $value){
+ if (isset($conf['plugin'][$plugin][$key])) continue;
+ $conf['plugin'][$plugin][$key] = $value;
+ }
+ $this->configloaded = true;
+ }
+ }
+
+ return $conf['plugin'][$plugin][$id];
+ }
+
+ /**
+ * loadConfig()
+ * reads all plugin configuration variables into $this->conf
+ * this function is automatically called by getConf()
+ */
+ function loadConfig(){
+
+ $path = DOKU_PLUGIN.$this->getPluginName().'/conf/';
+ $conf = array();
+
+ if (!@file_exists($path.'default.php')) return false;
+
+ // load default config file
+ include($path.'default.php');
+
+ return $conf;
+ }
+
+ // standard functions for outputing email addresses and links
+ // use these to avoid having to duplicate code to produce links in line with the installation configuration
+ function email($email, $name='', $class='', $more='') {
+ if (!$email) return $name;
+ $email = obfuscate($email);
+ if (!$name) $name = $email;
+ $class = "class='".($class ? $class : 'mail')."'";
+ return "<a href='mailto:$email' $class title='$email' $more>$name</a>";
+ }
+
+ function external_link($link, $title='', $class='', $target='', $more='') {
+ global $conf;
+
+ $link = htmlentities($link);
+ if (!$title) $title = $link;
+ if (!$target) $target = $conf['target']['extern'];
+ if ($conf['relnofollow']) $more .= ' rel="nofollow"';
+
+ if ($class) $class = " class='$class'";
+ if ($target) $target = " target='$target'";
+ if ($more) $more = " ".trim($more);
+
+ return "<a href='$link'$class$target$more>$title</a>";
+ }
+
+ // output text string through the parser, allows dokuwiki markup to be used
+ // very ineffecient for small pieces of data - try not to use
+ function render($text, $format='xhtml') {
+ return p_render($format, p_get_instructions($text),$info);
+ }
+
+ // deprecated functions
+ function plugin_localFN($id) { return $this->localFN($id); }
+ function plugin_locale_xhtml($id) { return $this->locale_xhtml($id); }
+ function plugin_email($e, $n='', $c='', $m='') { return $this->email($e, $n, $c, $m); }
+ function plugin_link($l, $t='', $c='', $to='', $m='') { return $this->external_link($l, $t, $c, $to, $m); }
+ function plugin_render($t, $f='xhtml') { return $this->render($t, $f); }
+} \ No newline at end of file