* @license GPL 2 (http://www.gnu.org/licenses/gpl.html) * @package action */ if (!defined('DOKU_INC')) die(); // the plugin must be run within Dokuwiki require_once "method.php"; // common methods used by PyCode plugin /** * This class defines all the methods used by the PyCode plugin to interact * with the DokuWiki's events. * * It extends DokuWiki's basic action defined in lib/plugins/action.php. * * @package action_pycode */ class action_plugin_pycode extends DokuWiki_Action_Plugin { /** * Constructor method for class suitable for any initialization. */ public function __construct() { $this->mpp = new method_pycode_plugin; } /** * Here are registered the event handlers */ public function register(Doku_Event_Handler $controller) { $controller->register_hook("ACTION_ACT_PREPROCESS", "BEFORE", $this, "update_code", array ()); $controller->register_hook("INDEXER_PAGE_ADD", "BEFORE", $this, "add_code", array()); $controller->register_hook("DOKUWIKI_DONE", "BEFORE", $this, "update_log", array ()); $controller->register_hook("TOOLBAR_DEFINE", "AFTER", $this, "insert_button", array ()); } /** * It substitutes, in the local copy of , only the pice of code which * the user wants to update. * * After that it's necessary to refresh the page, but, since it's used * the function header() to reload the page it's important to call this * method before any actual output is sent. * So it's necessary to use ACTION_ACT_PREPROCESS. * * In DokuWiki, instead of use $_POST, is strongly recommended to access * to it using its input classes: * $_POST["foo"]; becomes $INPUT->post->str("foo"); * * @param (obj) $event the event object * @param (arr) $param data passed when this handler was registered */ public function update_code(Doku_Event $event, $param) { global $INPUT; if ($INPUT->post->str("submit") == "Ok") { $loc_url = $INPUT->post->str("url"); $code_new = unserialize(base64_decode($INPUT->post->str("new"))); $ln_s = $INPUT->post->str("start"); $ln_e = $INPUT->post->str("end"); list($code_all_old, $flag, $name, $subname) = $this->mpp->_get_code($loc_url); $ls = $ln_s - 1; $le = $ln_e - 1; $ln = $le - $ls + 1; array_splice($code_all_old, $ls, $ln, $code_new); $this->mpp->_save_code($loc_url, $code_all_old); $uri = rtrim(DOKU_URL, "/") . $_SERVER['REQUEST_URI']; header("Location: " . $uri); exit; } } /** * It adds the code to the page which has to be indexed. * * Since the code is embedded and not write whitin the page, normally, * it is not parsed by the search engine. * So it's necessary to append the code to the page. * * @param (obj) $event the event object * @param (arr) $param data passed when this handler was registered */ public function add_code(Doku_Event $event, $param) { $log = DOKU_PLUGIN . "pycode/tmp/logfile"; $log = json_decode(file_get_contents($log), true); foreach ($log as $page => $files) { $page = substr($page, 0, -4); // remove extension .txt $page = str_replace("/", ":", $page); if ($event->data["page"] == $page) { $event->data["body"] = p_cached_output(wikiFN($page)); } } } /** * It records in a logfile all (s) embedded in each wiki page. * * For each wiki page are listed all the (s) embedded (same is * listed only one time) so that one of them is no longer used, the relative * local copy can be safely deleted. * * During the creation of a wiki page, the list of (s) is saved in a * temporary logfile.tmp. * When the page is created, logfile.tmp is used to update a permanent * logfile. * Same in the same wiki page are listed only once. * * This function have to be called after the wiki page is created, * so it's necessary to use an event like DOKUWIKI_DONE. * * @param (obj) $event the event object * @param (arr) $param data passed when this handler was registered */ public function update_log(Doku_Event $event, $param) { global $ACT; global $INFO; $wiki = str_replace(DOKU_INC . "data/pages/", "", $INFO["filepath"]); $tmp = DOKU_PLUGIN . "pycode/tmp/"; $log_old = DOKU_PLUGIN . "pycode/tmp/logfile"; $log_new = DOKU_PLUGIN . "pycode/tmp/logfile.tmp"; if ($ACT == "show") { if (file_exists($log_old) == true) { // recover data stored in the logfile so we have sth. like this: // array { // ["1"] => array { // [0] => "1", // [1] => "2" // } // } $log_old = json_decode(file_get_contents($log_old), true); if (file_exists($log_new) == true) { // recover data stored in the temporary logfile $log_new = json_decode(file_get_contents($log_new), true); if (array_key_exists($wiki, $log_old) == false) { // all (s) added to this wiki page are new $log_old[$wiki] = array(); foreach ($log_new[$wiki] as $file) { array_push($log_old[$wiki], $file); } } else { // look for new (s) not present among old (s) $add = array_diff($log_new[$wiki], $log_old[$wiki]); // add new entry (s) in the logfile foreach ($add as $file_add) { array_push($log_old[$wiki], $file_add); } // look for old (s) not present among new (s) $del = array_diff($log_old[$wiki], $log_new[$wiki]); // check among all wiki pages if these (s) deleted were // the last ones and, if so, remove them from the logfile // and the relatives (s) foreach ($del as $key => $file_del) { $i = 0; foreach ($log_old as $page => $files) { if ($wiki == $page) { continue; } if (array_search($file_del, $files) !== false) { $i = 1; // is still embedded in another wiki page } } if ($i == 0) { unlink(DOKU_PLUGIN . "pycode/tmp/" . $file_del); unset($log_old[$wiki][$key]); $log_old[$wiki] = array_values($log_old[$wiki]); // reindex } } } } else { // all (s) deleted from this wiki page are old $del = $log_old[$wiki]; if (empty($del) == false) { foreach ($del as $key => $file_del) { unlink(DOKU_PLUGIN . "pycode/tmp/" . $file_del); } unset($log_old[$wiki]); } } if (count($log_old) == 0) { unlink(DOKU_PLUGIN . "pycode/tmp/logfile"); } else { // now the array for logfile is update and ready to be written $str = json_encode($log_old); file_put_contents(DOKU_PLUGIN . "pycode/tmp/logfile", $str); } } elseif (file_exists($log_old) == false and file_exists($log_new) == true) { rename($log_new, $log_old); } if (file_exists($tmp) == true) { // remove empty directories $tree_dir = $this->mpp->_get_tree_dir(DOKU_PLUGIN . "pycode/tmp/"); $this->mpp->_remove_empty_dir($tree_dir); // destroy temporary logfile if (file_exists(DOKU_PLUGIN . "pycode/tmp/logfile.tmp") == true) { unlink(DOKU_PLUGIN . "pycode/tmp/logfile.tmp"); } } } } /** * It inserts the PyCode's buttons in the toolbar. * * @param (obj) $event the event object * @param (arr) $param data passed when this handler was registered */ public function insert_button(Doku_Event $event, $param) { $btns = $this->getConf("btns"); if ($btns == 1){ $event->data[] = array ( 'type' => "PyCode", 'title' => "PyCode Plugin", 'icon' => "../../plugins/pycode/images/picker.png" ); } } }