<?php
/**
* This file implements the Wacko plugin for b2evolution
*
* Wacko style formatting
*
* b2evolution - {@link http://b2evolution.net/}
* Released under GNU GPL License - {@link http://b2evolution.net/about/gnu-gpl-license}
* @copyright (c)2003-2020 by Francois Planque - {@link http://fplanque.com/}
*
* @package plugins
* @ignore
*/
if( !defined('EVO_MAIN_INIT') ) die( 'Please, do not access this page directly.' );
/**
* @package plugins
*/
class wacko_plugin extends Plugin
{
var $code = 'b2evWcko';
var $name = 'Wacko formatting';
var $priority = 30;
var $version = '7.2.3';
var $group = 'rendering';
var $short_desc;
var $long_desc;
var $help_topic = 'wacko-plugin';
var $number_of_installs = 1;
/**
* Init
*/
function PluginInit( & $params )
{
$this->short_desc = T_('Wacko style formatting');
$this->long_desc = T_('Accepted formats:<br />
== h2 ==<br />
=== h3 ===<br />
==== h4 ====<br />
===== h5 =====<br />
====== h6 ======<br />
--- (horizontal rule)<br />
%%%codeblock%%%<br />');
}
/**
* Define here default collection/blog settings that are to be made available in the backoffice.
*
* @param array Associative array of parameters.
* @return array See {@link Plugin::get_coll_setting_definitions()}.
*/
function get_coll_setting_definitions( & $params )
{
$default_params = array_merge( $params, array( 'default_post_rendering' => 'opt-in' ) );
return parent::get_coll_setting_definitions( $default_params );
}
/**
* Perform rendering
*
* @param array Associative array of parameters
* 'data': the data (by reference). You probably want to modify this.
* 'format': see {@link format_to_output()}. Only 'htmlbody' and 'entityencoded' will arrive here.
* @return boolean true if we can render something for the required output format
*/
function RenderItemAsHtml( & $params )
{
$content = & $params['data'];
// Search array:
$search = array(
'#( ^ | [\s\S] ) ====== (.+?) ====== #x',
'#( ^ | [\s\S] ) ===== (.+?) ===== #x',
'#( ^ | [\s\S] ) ==== (.+?) ==== #x',
'#( ^ | [\s\S] ) === (.+?) === #x',
'#( ^ | [\s\S] ) == (.+?) == #x',
'#^ \s* --- \s* $#xm', // multiline start/stop checking
);
// HTML replace array:
$replace = array(
'$1<h6>$2</h6>',
'$1<h5>$2</h5>',
'$1<h4>$2</h4>',
'$1<h3>$2</h3>',
'$1<h2>$2</h2>',
'<hr />',
);
$content = replace_outside_code_and_short_tags( $search, $replace, $content );
// Find bullet lists
if( stristr( $content, '<code' ) !== false || stristr( $content, '<pre' ) !== false || strstr( $content, '`' ) !== false )
{ // Call replace_content() on everything outside code/pre:
$content = callback_on_non_matching_blocks( $content,
'~(`|<(code|pre)[^>]*>).*?(\1|</\2>)~is',
array( $this, 'find_bullet_lists' ) );
}
else
{ // No code/pre blocks, replace on the whole thing
$content = $this->find_bullet_lists( $content );
}
return true;
}
/**
* Find bullet lists
*
* @param string Content
* @return string Content
*/
function find_bullet_lists( $content )
{
// Find and parse the code blocks to html view
$content = $this->escape_codeblock( $content );
$lines = explode( "\n", $content );
$lines_count = count( $lines );
$lists = array();
$current_depth = 0;
$content = '';
foreach( $lines as $l => $line )
{
if( ! preg_match( '#^ /s $#xm', $line ) )
{ // If not blank line
$matches = array();
if( preg_match( '#^(( )+)\*(.*)$#m', $line, $matches ) )
{ // We have a list item
$req_depth = strlen( $matches[1] ) / 2;
while( $current_depth < $req_depth )
{ // We must indent
$content .= "<ul>\n";
array_push( $lists, 'ul' );
$current_depth++;
}
while( $current_depth > $req_depth )
{ // We must close lists
$content .= '</'.array_pop( $lists ).">\n";
$current_depth--;
}
$content .= $matches[1].'<li>'.$matches[3]."</li>\n";
continue;
}
if( preg_match( '#^(( )+)([0-9]+)(.*)$#m', $line, $matches ) )
{ // We have an ordered list item
$req_depth = strlen( $matches[1] ) / 2;
while( $current_depth < $req_depth )
{ // We must indent
$content .= '<ol start="'.$matches[3].'">'."\n";
array_push( $lists, 'ol' );
$current_depth++;
}
while( $current_depth > $req_depth )
{ // We must close lists
$content .= '</'.array_pop( $lists ).">\n";
$current_depth--;
}
$content .= $matches[1].'<li>'.$matches[4]."</li>\n";
continue;
}
// Normal line.
if( $current_depth )
{ // We must go back to 0
$content .= '</'.implode( ">\n</", $lists ).">\n";
$lists = array();
$current_depth = 0;
}
$content .= $line;
if( $l < $lines_count - 1 )
{ // Don't append a newline at the end, because it will create an unnecessary newline that didn't exist in source content
$content .= "\n";
}
}
}
if( $current_depth )
{ // We must go back to 0
$content .= '</'.implode( ">\n</", $lists ).">\n";
}
return $content;
}
/**
* Parse code blocks to html view
*
* @param string Content
* @param string
*/
function escape_codeblock( $content )
{
$search = '/ %%%
( \s*? \n )? # Eat optional blank line after %%%
(.+?)
( \n \s*? )? # Eat optional blank line before %%%
%%%
/sx'; // %%%escaped codeblock%%%
return preg_replace_callback( $search, array( $this, 'escape_codeblock_callback' ), $content );
}
/**
* Callback function for code block parsing
*
* @param array Result of preg_replace function, @see $this->escape_codeblock()
* @return string
*/
function escape_codeblock_callback( $match )
{
return '<div class="codeblock"><pre><code>'
.htmlspecialchars( stripslashes( $match[2] ), ENT_NOQUOTES )
.'</code></pre></div>';
}
}
?>