Processing page output on the fly

Sometimes it would be useful to process the output of the formatting engine before displaying it to visitors. This will allow actions to automatically reformat text in particular ways. For instance, all camelcase links could be uncamelized while still maintaining the underlying code on the page. It would also be nice if we could apply certain actions across the entire site. This is exactly what this code allows us to do.

The first step is deciding whether or not we want to process the entire page, including the header and the footer, or just the body content. The current incarnation is working at the level of the body content, but it can be easily extended to include the header and footer output as well.

Once we know what we're dealing with, we can find where it's coming into the wiki display process. The Run() method is handy for figuring this type of stuff out. In the case of the formatted body content, we find that it's loaded up by the page/show handler. So we have to open that up and replace the line that prints $this->page['body'] with the following code:

        // display page
        $global_actions = $this->LoadSingle('SELECT body FROM ' . $this->config['table_prefix'] . 'pages WHERE tag = \'GlobalActions\' AND latest = \'Y\'');
        $regex = "/\{\{(onpageload.*?)\}\}/s";
        if (preg_match($regex, $this->page['body'] . (isset($global_actions['body']) ? $global_actions['body'] : ''), $matches))
            $onload_actions = $matches[1];
            $this->page['body'] = preg_replace($regex, '', $this->page['body']);
        if ($this->config['allow_page_load_actions'] && $onload_actions)
            echo $this->Action($onload_actions);
            echo $this->Format($this->page['body'], 'wakka');

As you can see, the new process only comes into the picture if the user has set the 'allow_page_load_actions' config variable to true.

The next thing we need to do is create a file called "onpageload.php" and save it in the actions directory. Here's the code:

if ($this->tag == 'GlobalActions') return;

if (!function_exists('_onpageload'))
    function _onpageload(&$wikka, $actions)
        foreach ($actions as $name => $parameters)
            if (!in_array($name, array('wikka_vars', 'runtime', 'onpageload')))
                $this->page['body'] = $wikka->Action($name . ' ' . preg_replace("/(.+):'(.*)'/U", '$1="$2"', $parameters));

if (isset($vars['runtime']) && $vars['runtime'] == 'before') _onpageload($this, $vars);
$this->page['body'] = $this->Format($this->page['body'], 'wakka');
if ((isset($vars['runtime']) && $vars['runtime'] != 'before') || empty($vars['runtime'])) _onpageload($this, $vars);
echo $this->page['body'];

Apparently the first line is required to prevent a hard-to-follow tail chasing event of some sort. It's much too late to figure this out tonight, though. Hence, the simple return. It works for now, but is that good enough? Not if it turns out that every action we want to use in the GlobalActions page must add this line up top! So if you spot the bug, please let me know!

Some examples

{{onpageload uncamel=""}}

This will run the uncamel action with no parameters after the page formatter has been applied.

{{onpageload runtime="before" uncamel=""}}

The same as above, only this time it will be applied before the formatter runs.

{{onpageload runtime="before" customaction1="param1:'value1' param2:'value2'" customaction2=""}}

Executes two actions before processing the page data. The first takes two parameters (it hasn't really been tested, but should work in theory).

One final note, if you would like to apply an action sitewide then you have to create a page called GlobalActions and put the onpageload event there.



There are 7 comments on this page. [Show comments]
Valid XHTML :: Valid CSS: :: Powered by WikkaWiki