<?php
/**
* @version RC 1.0.3.2 2008-04-24 15:03:43 $
* @package SkyBlueCanvas
* @copyright Copyright (C) 2005 - 2008 Scott Edwin Lewis. All rights reserved.
* @license GNU/GPL, see COPYING.txt
* SkyBlueCanvas is free software. This version may have been modified pursuant
* to the GNU General Public License, and as distributed it includes or
* is derivative of works licensed under the GNU General Public License or
* other free or open source software licenses.
* See COPYING.txt for copyright notices and details.
*/
defined('SKYBLUE') or die(basename(__FILE__));
/**
* Plugin Function Example:
*
* {plugin:my_plugin(const:const_name,var:var_name,literal_str)}
*
* type:name | type:value
*
* str:"my string"
* const:const_name
* var:var_name
* arr:[one,two,three] or [key1=val1,key2=val2]
* class:class.prop
*
* Will support classes. Indicate that a plugin is a class by:
*
* {plugin:my_class.my_func(comma,delimited,args)}
*
* Syntax:
*
* In-line text:
*
* {plugin:func_name(comma,delimited,args)}
*
* HTML:
*
* <!--#plugin func_name(comma,delimited,args) -->
*
*/
define('REGEX_PLUGIN_FUNCTION', "/([a-zA-Z_]+[^\(]*)\(([^\)]*)\)/i");
define('REGEX_INLINE_PLUGIN', "/({plugin:[^}]*})/i");
define('REGEX_COMMENT_PLUGIN', "/(<!--#plugin(.*)-->)/i");
define('TOKEN_ARR_DELIM', ',');
define('TOKEN_ARR_LEFT', '[');
define('TOKEN_ARR_RIGHT', ']');
define('TOKEN_SEQ_POINT', ';');
define('TOKEN_DIVIDER', ':');
define('TOKEN_MEMBER_DIVIDER', '.');
define('TOKEN_INLINE_PLUGIN_LEFT', '{plugin:');
define('TOKEN_INLINE_PLUGIN_RIGHT', '}');
define('TOKEN_COMMENT_PLUGIN_LEFT', '<!--#plugin');
define('TOKEN_COMMENT_PLUGIN_RIGHT', '-->');
define('TOKEN_ASSIGN_OP', '=');
define('PP_CLASS', 'class');
define('PP_FUNCTION', 'func');
global $Core;
$Core->register('OnRenderPage', 'ParseInlinePlugins');
function ParseInlinePlugins($html) {
$PluginParser = new PluginParser($html);
return $PluginParser->get('result');
}
class PluginParser extends SkyBlueObject {
var $classInstances = array();
function PluginParser($text)
{
$this->__construct($text);
}
function __construct($text)
{
$this->result = $this->parseAndReplace($text);
}
function find($text)
{
preg_match_all(REGEX_INLINE_PLUGIN, $text, $tokens1);
preg_match_all(REGEX_COMMENT_PLUGIN, $text, $tokens2);
return array_merge($tokens1[0], $tokens2[0]);
}
function parse($token)
{
preg_match(
REGEX_PLUGIN_FUNCTION,
str_replace(
array(
TOKEN_INLINE_PLUGIN_LEFT,
TOKEN_INLINE_PLUGIN_RIGHT,
TOKEN_COMMENT_PLUGIN_LEFT,
TOKEN_COMMENT_PLUGIN_RIGHT
),
null,
$token
),
$plugins
);
$plugin = null;
if (isset($plugins[1]) && trim($plugins[1] != '')) {
$plugin = $plugins[1];
}
$plugin = $this->_getFunction($plugin);
$class = $plugin[PP_CLASS];
$func = $plugin[PP_FUNCTION];
$call = $func;
if (!empty($class) && class_exists($class)) {
if (!isset($this->classInstances[$class]))
$this->classInstances[$class] = new $class;
$call = array($this->classInstances[$class], $func);
}
$args = array();
if (isset($plugins[2]) && trim($plugins[2]) != '') {
$args = $this->_parse($plugins[2]);
}
return $this->_call($call, $args);
}
function parseAndReplace($text)
{
$tokens = $this->find($text);
for ($i=0; $i<count($tokens); $i++)
{
$replace = $this->parse($tokens[$i]);
if (!empty($replace))
$replace = $this->parseAndReplace($replace);
/**
* r247: Hack to remove enclosing P tag added by WYMeditor to the in-line tokens.
*/
$text = str_replace("<p>{$tokens[$i]}</p>", $replace, $text);
$text = str_replace($tokens[$i], $replace, $text);
}
return $text;
}
function _argval($str)
{
global $Core;
if (!$this->_has($str, TOKEN_DIVIDER) ||
!$this->_has($str, TOKEN_ASSIGN_OP))
{
return $this->_convert($str);
}
list($type, $arg) = $this->_typeAndVal($str);
switch ($type)
{
case 'const':
$val = @constant($arg);
break;
case 'var':
$val = @$$arg;
break;
case 'arr':
$bits = explode(TOKEN_ARR_DELIM, $arg);
for ($i=0; $i<count($bits); $i++)
{
$val[] = $this->_argval($bits[$i]);
}
break;
case 'class':
$val = $this->_parseClassProp($arg);
break;
case 'string':
default:
$val = $arg;
break;
}
return $val;
}
function _typeAndVal($arg)
{
$type = null;
$i=0;
$max = 255;
if (strpos($arg, TOKEN_DIVIDER) !== false)
{
while ($arg{$i} != TOKEN_DIVIDER && $i<$max)
{
$type .= $arg{$i};
$i++;
}
return array($type, substr($arg, $i+1));
}
else if (strpos($arg, TOKEN_ASSIGN_OP) !== false)
{
return $this->_assign($arg);
}
return null;
}
function _assign($arg)
{
$key = null;
if (strpos($arg, TOKEN_ASSIGN_OP) !== false)
{
$i=0;
$max=255;
while ($arg{$i} != TOKEN_ASSIGN_OP && $i<$max)
{
$key .= $arg{$i};
$i++;
}
$val = $this->_convert(substr($arg, $i+1));
return array($key=>$val);
}
}
function _convert($arg, $delim=',')
{
if (strpos($arg, $delim) === false
&& strpos($arg, TOKEN_ASSIGN_OP) === false) {
return $arg;
}
$args = explode($delim, $arg);
$assign = $this->_assign($arg);
if (!empty($assign)) return $assign;
$res = array();
for ($i=0; $i<count($args); $i++)
{
$tmp = trim($args[$i]);
if (strpos($tmp, ':') !== false)
{
list($key, $value) = explode(':', $tmp);
$res[$key] = $value;
}
else
{
$res[$i] = $tmp;
}
}
return $res;
}
function _parseClassProp($str)
{
if (!$this->_has($str, TOKEN_MEMBER_DIVIDER))
{
return null;
}
$bits = explode(TOKEN_MEMBER_DIVIDER, $str);
if (!isset($bits[0]->$bits[1]))
{
if (!class_exists($bits[0]))
{
return null;
}
$class = new $bits[0];
}
return $class->$bits[1];
}
function _parse($str)
{
if (!$this->_has($str, TOKEN_ARR_DELIM))
{
return array($this->_argval($str));
}
$args = array();
$n = 0;
$max = 1000;
while (strlen($str) > 0 && $n < $max)
{
$n++;
$i=0;
$arg = null;
$delim = false;
$inBlock = false;
while (!$delim && strlen($str) && $i < $max)
{
if ($i >= strlen($str)) break;
if ($str{$i} == TOKEN_ARR_LEFT)
{
$inBlock = true;
$delim = false;
}
else if ($str{$i} == TOKEN_ARR_RIGHT)
{
$inBlock = false;
$delim = false;
}
else if ($str{$i} == TOKEN_ARR_DELIM && !$inBlock)
{
$delim = true;
}
if (!$delim && !in_array($str{$i}, array(TOKEN_ARR_LEFT, TOKEN_ARR_RIGHT)))
{
$arg .= $str{$i};
}
$i++;
}
array_push($args, $this->_argval($arg));
$str = trim(substr($str, $i));
}
// global $Core; $Core->Dump($args);
return $args;
}
function _has($haystack, $needle)
{
if (is_array($haystack))
{
return in_array($needle, $haystack);
}
else if (is_string($haystack))
{
return strpos($haystack, $needle) !== false;
}
return false;
}
function _call($call, $args)
{
if (is_callable($call, false))
{
if (count($call) > 1)
{
return $call[0]->$call[1]($args);
}
return $call($args);
}
return null;
}
function _getFunction($plugin)
{
$class = null;
$func = null;
$bits = explode(TOKEN_MEMBER_DIVIDER, $plugin);
if (count($bits) == 1)
{
$func = $bits[0];
}
else
{
$class = $bits[0];
$func = $bits[1];
}
return array(PP_CLASS=>$class, PP_FUNCTION=>$func);
}
function _debug($what)
{
die("<pre>" . print_r($what, true) . "</pre>");
}
};
?>