Seditio Source
Root |
./othercms/b2evolution_7.2.3/plugins/test_plugin/_test.plugin.php
<?php
/**
 * This file implements the TEST plugin.
 *
 * For the most recent and complete Plugin API documentation
 * see {@link Plugin} in ../inc/plugins/_plugin.class.php.
 *
 * This file is part of the evoCore framework - {@link http://evocore.net/}
 * See also {@link https://github.com/b2evolution/b2evolution}.
 *
 * @license GNU GPL v2 - {@link http://b2evolution.net/about/gnu-gpl-license}
 *
 * @copyright (c)2003-2020 by Francois Planque - {@link http://fplanque.com/}
 * Parts of this file are copyright (c)2004-2006 by Daniel HAHLER - {@link http://thequod.de/contact}.
 *
 * @package plugins
 */
if( !defined('EVO_MAIN_INIT') ) die( 'Please, do not access this page directly.' );


/**
 * TEST Plugin
 *
 * This plugin responds to virtually all possible plugin events :P
 *
 * @package plugins
 */
class test_plugin extends Plugin
{
   
/**
     * Variables below MUST be overriden by plugin implementations,
     * either in the subclass declaration or in the subclass constructor.
     */
   
var $name = 'Test';
    var
$code = 'evo_TEST';
    var
$priority = 50;
    var
$version = '7.2.3';
    var
$author = 'The b2evo Group';
    var
$help_url = '';  // empty URL defaults to manual wiki

    /*
     * These variables MAY be overriden.
     */
   
var $number_of_installs = 1;
    var
$group = 'rendering';


   
/**
     * Init
     *
     * This gets called after a plugin has been registered/instantiated.
     */
   
function PluginInit( & $params )
    {
       
$this->short_desc = T_('Test plugin');
       
$this->long_desc = T_('This plugin responds to virtually all possible plugin events :P');

       
// Trigger plugin settings instantiation (for testing).
       
if( $params['is_installed'] )
        {
           
$this->Settings->get('foo');
        }
    }


   
/**
     * Define the GLOBAL settings of the plugin here. These can then be edited in the backoffice in System > Plugins.
     *
     * @see Plugin::GetDefaultSettings()
     * @param array Associative array of parameters (since v1.9).
     *    'for_editing': true, if the settings get queried for editing;
     *                   false, if they get queried for instantiating {@link Plugin::$Settings}.
     * @return array see {@link Plugin::GetDefaultSettings()}.
     * The array to be returned should define the names of the settings as keys (max length is 30 chars)
     * and assign an array with the following keys to them (only 'label' is required):
     */
   
function GetDefaultSettings( & $params )
    {
       
$r = array(
           
'click_me' => array(
               
'label' => 'Click me!',
               
'defaultvalue' => '1',
               
'type' => 'checkbox',
            ),
           
'input_me' => array(
               
'label' => 'How are you?',
               
'defaultvalue' => '',
               
'note' => 'Welcome to b2evolution',
            ),
           
'number' => array(
               
'label' => 'Number',
               
'defaultvalue' => '8',
               
'note' => '1-9',
               
'valid_range' => array( 'min'=>1, 'max'=>9 ),
            ),
           
'my_select' => array(
               
'label' => 'Selector',
               
'id' => $this->classname.'_my_select_id',
               
'class' => $this->classname.'_my_select_class',
               
'onchange' => 'document.getElementById("'.$this->classname.'_a_disabled_one").disabled = ( this.value == "sun" );',
               
'defaultvalue' => 'one',
               
'type' => 'select',
               
'options' => array( 'sun' => 'Sunday', 'mon' => 'Monday' ),
               
'note' => 'This combo is connected with the next field',
            ),
           
'a_disabled_one' => array(
               
'label' => 'This one is disabled',
               
'id' => $this->classname.'_a_disabled_one',
               
'type' => 'checkbox',
               
'defaultvalue' => '1',
               
'disabled' => true, // this can be useful if you detect that something cannot be changed. You probably want to add a 'note' then, too.
               
'note' => 'Change the above select input to "Monday" to enable it.',
            ),
           
'select_multiple' => array(
               
'label' => $this->T_( 'Multiple select' ),
               
'type' => 'select',
               
'multiple' => true,
               
'allow_none' => true,
               
'options' => array( 'sci' => $this->T_( 'Scissors' ), 'pap' => $this->T_( 'Paper' ), 'sto' => $this->T_( 'Stone') ),
               
'defaultvalue' => array( 'sci', 'sto' ),
               
'note' => $this->T_( 'This is a free style Multiple Select. You can choose zero or one or more items' )
            ),
           
/*
             * note: The $this->T_( string )function tanslates the string.
             * However since it inherits from the class Plugin you will need
             * to provide the translation on a per plugin basis. In other
             * words: this will not be translated through B2evolution.
             */
           
'blog' => array(
               
'label' => 'A blog',
               
'type' => 'select_blog',  // TODO: does not scale with 500 blogs
               
'allow_none' => true,
            ),
           
'blogs' => array(
               
'label' => 'A set of blogs',
               
'type' => 'select_blog',    // TODO: BROKEN + does not scale with 500 blogs
               
'multiple' => true,
               
'allow_none' => true,
            ),
           
'single_user' => array(
               
'label' => 'A single user',
               
'type' => 'select_user',
               
'users_limit' => 5,
               
'allow_none' => true,
               
'defaultvalue' => 0,
               
'note' => 'Allows chosing none or one user'
           
),
           
'sets' => array(
               
'label' => 'Multiple users',
               
'type' => 'select_user',
               
'users_limit' => 10,
               
'min_count' => 0,
               
'max_count' => 3,
               
'multiple' => 'true',
               
'allow_none' => true,
               
'note' => 'Allows none or one or more than one user (up to three in this example)',
               
'entries' => array(
                   
'user' => array(
                       
'label' => 'A user',
                       
'type' => 'select_user',        // TODO: does not scale with 500 users
                       
'allow_none' => true,
                    ),
                ),
            ),
           
'maxlen' => array(
               
'label' => 'Max',
               
'type' => 'textarea',
               
'maxlength' => 10,
               
'note' => 'Maximum length is 10 here.',
            ),
           
'plug_color' => array(
               
'label' => 'Plugin color',
               
'type' => 'color',
               
'note' => 'Click on the field to display a color selector.',
               
'defaultvalue' => '#F60',
            ),
        );

        if(
$params['for_editing'] )
        {
// we're asked for the settings for editing:
           
if( $this->Settings->get('my_select') == 'mon' )
            {
               
$r['a_disabled_one']['disabled'] = false;
            }
        }

        return
$r;
    }


   
/**
     * Define here default custom settings that are to be made available
     *     in the backoffice for collections, private messages and newsletters.
     *
     * @param array Associative array of parameters.
     * @return array See {@link Plugin::get_custom_setting_definitions()}.
     */
   
function get_custom_setting_definitions( & $params )
    {
        return array(
           
'custom' => array(
                   
'label' => 'Custom setting',
                   
'note' => 'Custom plugin setting for collections, private messages and newsletters.',
                   
'defaultvalue' => 'Custom value',
                ),
           
'custom_color' => array(
                   
'label' => 'Custom color',
                   
'type' => 'color',
                   
'note' => 'Click on the field to display a color selector.',
                   
'defaultvalue' => '#033',
                ),
        );
    }


   
/**
     * 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_comment_rendering' => 'stealth',
               
'default_post_rendering' => 'opt-out'
           
)
        );

       
$r = array_merge( parent::get_coll_setting_definitions( $default_params ),
                array(
                   
'coll_custom' => array(
                           
'label' => 'Collection setting',
                           
'note' => 'Custom plugin setting ONLY for collections.',
                           
'defaultvalue' => 'Collection value',
                        ),
                   
'coll_color' => array(
                           
'label' => 'Collection color',
                           
'type' => 'color',
                           
'note' => 'Click on the field to display a color selector.',
                           
'defaultvalue' => '#0C9',
                        ),
                )
            );

        return
$r;
    }


   
/**
     * Define here default message settings that are to be made available in the backoffice.
     *
     * @param array Associative array of parameters.
     * @return array See {@link Plugin::GetDefaultSettings()}.
     */
   
function get_msg_setting_definitions( & $params )
    {
       
// set params to allow rendering for messages by default
       
$default_params = array_merge( $params, array( 'default_msg_rendering' => 'stealth' ) );

       
$r = array_merge( parent::get_msg_setting_definitions( $default_params ),
                array(
                   
'custom_msg' => array(
                           
'label' => 'Message setting',
                           
'note' => 'Custom plugin setting ONLY for messages.',
                           
'defaultvalue' => 'Message value',
                        ),
                   
'msg_color' => array(
                           
'label' => 'Message color',
                           
'type' => 'color',
                           
'note' => 'Click on the field to display a color selector.',
                           
'defaultvalue' => '#393',
                        ),
                )
            );

        return
$r;
    }


   
/**
     * Define here default email settings that are to be made available in the backoffice.
     *
     * @param array Associative array of parameters.
     * @return array See {@link Plugin::GetDefaultSettings()}.
     */
   
function get_email_setting_definitions( & $params )
    {
       
// set params to allow rendering for emails by default:
       
$default_params = array_merge( $params, array( 'default_email_rendering' => 'stealth' ) );

       
$r = array_merge( parent::get_email_setting_definitions( $default_params ),
                array(
                   
'custom_email' => array(
                           
'label' => 'Email setting',
                           
'note' => 'Custom plugin setting ONLY for emails.',
                           
'defaultvalue' => 'Email value',
                        ),
                   
'email_color' => array(
                           
'label' => 'Email color',
                           
'type' => 'color',
                           
'note' => 'Click on the field to display a color selector.',
                           
'defaultvalue' => '#DDF',
                        ),
                )
            );

        return
$r;
    }


   
/**
     * Define here default shared settings that are to be made available in the backoffice.
     *
     * @param array Associative array of parameters.
     * @return array See {@link Plugin::GetDefaultSettings()}.
     */
   
function get_shared_setting_definitions( & $params )
    {
       
// set params to allow rendering for shared container widgets by default:
       
$default_params = array_merge( $params, array( 'default_shared_rendering' => 'stealth' ) );

       
$r = array_merge( parent::get_shared_setting_definitions( $default_params ),
                array(
                   
'custom_shared' => array(
                           
'label' => 'Shared setting',
                           
'note' => 'Custom plugin setting ONLY for shared container widgets.',
                           
'defaultvalue' => 'Shared value',
                        ),
                   
'shared_color' => array(
                           
'label' => 'Shared color',
                           
'type' => 'color',
                           
'note' => 'Click on the field to display a color selector.',
                           
'defaultvalue' => '#DDF',
                        ),
                )
            );

        return
$r;
    }


   
/**
     * Get definitions for widget specific editable params
     *
     * @see Plugin::GetDefaultSettings()
     * @param array Local params like 'for_editing' => true
     * @return array
     */
   
function get_widget_param_definitions( $params )
    {
       
$r = array(
           
'title' => array(
                   
'label' => T_('Block title'),
                   
'note' => T_('Title to display in your skin.'),
                   
'size' => 60,
                   
'defaultvalue' => 'Test plugin widget',
            ),
           
'widget_color' => array(
               
'label' => 'Widget color',
               
'type' => 'color',
               
'note' => 'Click on the field to display a color selector.',
               
'defaultvalue' => '#F66',
            ),
        );
        return
$r;
    }


   
/**
     * Get keys for block/widget caching
     *
     * Maybe be overriden by some widgets, depending on what THEY depend on..
     *
     * @param integer Widget ID
     * @return array of keys this widget depends on
     */
   
function get_widget_cache_keys( $widget_ID = 0 )
    {
        global
$Blog;

        return array(
               
'wi_ID'        => $widget_ID, // Have the widget settings changed ?
               
'set_coll_ID'  => $Blog->ID, // Have the settings of the blog changed ? (ex: new skin)
               
'cont_coll_ID' => empty( $this->disp_params['blog_ID'] ) ? $Blog->ID : $this->disp_params['blog_ID'], // Has the content of the displayed blog changed ?
           
);
    }


   
/**
     * Define the PER-USER settings of the plugin here. These can then be edited by each user.
     *
     * You can access them in the plugin through the member object
     * {@link $UserSettings}, e.g.:
     * <code>$this->UserSettings->get( 'my_param' );</code>
     *
     * This method behaves exactly like {@link Plugin::GetDefaultSettings()},
     * except that it defines user specific settings instead of global settings.
     *
     * @todo 3.0 fp> 1) This is not an event: RENAME to lowercase (in b2evo 3.0)
     * @todo 3.0 fp> 2) This defines more than Default values ::  confusing name
     * @todo name tentative get_user_param_definitions()
     *
     * @see Plugin::GetDefaultUserSettings()
     * @param array Associative array of parameters.
     *    'for_editing': true, if the settings get queried for editing;
     *                   false, if they get queried for instantiating {@link Plugin::$UserSettings}.
     * @return array See {@link Plugin::GetDefaultSettings()}.
     */
   
function GetDefaultUserSettings( & $params )
    {
        return array(
               
'echo_random' => array(
                   
'label' => 'Echo a random number in AdminBeginPayload event',
                   
'type' => 'checkbox',
                   
'defaultvalue' => '0',
                ),
               
'deactivate' => array(
                   
'label' => 'Deactivate',
                   
'type' => 'checkbox',
                   
'defaultvalue' => '0',
                ),
            );
    }


   
/**
     * Get the list of dependencies that the plugin has.
     *
     * This gets checked on install or uninstall of a plugin.
     *
     * There are two <b>classes</b> of dependencies:
     *  - 'recommends': This is just a recommendation. If it cannot get fulfilled
     *                  there will just be a note added on install.
     *  - 'requires': A plugin cannot be installed if the dependencies cannot get
     *                fulfilled. Also, a plugin cannot get uninstalled, if another
     *                plugin depends on it.
     *
     * Each <b>class</b> of dependency can have the following types:
     *  - 'events_by_one': A list of eventlists that have to be provided by a single plugin,
     *                     e.g., <code>array( array('RequestCaptcha', 'ValidateCaptcha') )</code>
     *                     to look for a plugin that provides both events.
     *  - 'plugins':
     *    A list of plugins, either just the plugin's classname or an array with
     *    classname and minimum version of the plugin (see {@link Plugin::$version}).
     *    E.g.: <code>array( 'test_plugin', '1' )</code> to require at least version "1"
     *          of the test plugin.
     *  - 'app_min': Minimum application (b2evo) version, e.g. "1.9".
     *               This way you can make sure that the hooks you need are implemented
     *               in the core.
     *               (Available since b2evo 1.8.3. To make it work before 1.8.2 use
     *               "api_min" and check for array(1, 2) (API version of 1.9)).
     *  - 'api_min': You can require a specific minimum version of the Plugins API here.
     *               If it's just a number, only the major version is checked against.
     *               To check also for the minor version, you have to give an array:
     *               array( major, minor ).
     *               Obsolete since 1.9! Used API versions: 1.1 (b2evo 1.8.1) and 1.2 (b2evo 1.9).
     *
     * @see Plugin::GetDependencies()
     * @return array
     */
   
function GetDependencies()
    {
        return array(
               
'recommends' => array(
                   
'events_by_one' => array( array('Foo', 'Bar'), array('FooBar', 'BarFoo') ), // a plugin that provides "Foo" and "Bar", and one (may be the same) that provides "FooBar" and "BarFoo"
                   
'events' => array( 'some_event', 'some_other_event' ),
                   
'plugins' => array( array( 'some_plugin', '1' ) ), // at least version 1 of some_plugin
               
),

               
'requires' => array(
                   
// Same syntax as with the 'recommends' class above, but would prevent the plugin from being installed.
               
),
            );
    }


   
/**
     * This method should return your DB schema, consisting of a list of CREATE TABLE
     * queries.
     *
     * The DB gets changed accordingly on installing or enabling your Plugin.
     *
     * If you want to change your DB layout in a new version of your Plugin, simply
     * adjust the queries here and increase {@link Plugin::$version}, because this will
     * request to check the current DB layout against the one you require.
     *
     * For restrictions see {@link db_delta()}.
     *
     * @see Plugin::GetDbLayout()
     */
   
function GetDbLayout()
    {
        global
$DB;

        return array(
               
'CREATE TABLE '.$this->get_sql_table( 'test_table_name' ).' (
                    test_ID   INT UNSIGNED NOT NULL AUTO_INCREMENT,
                    test_name VARCHAR( 255 ) COLLATE utf8mb4_unicode_ci NOT NULL,
                    PRIMARY KEY( test_ID )
                ) ENGINE = innodb DEFAULT CHARSET = '
.$DB->get_connection_charset()
            );
    }


   
/**
     * This method gets asked when plugins get installed and allows you to return a list
     * of extra events, which your plugin triggers itself (e.g. through
     * {@link $Plugins->trigger_event()}).
     *
     * NOTE: PLEASE use a distinct prefix for the event name, e.g. "$this->classname".
     *
     * NOTE: The length of event names is limited to 40 chars.
     *
     * NOTE: Please comment the params and the return value here with the list
     *       that you return. Only informal as comment, but makes it easier for
     *       others.
     *
     * @see Plugin::GetExtraEvents()
     * @return NULL|array "event_name" => "description"
     */
   
function GetExtraEvents()
    {
        return array(
               
// Gets "min" and "max" as params and should return a random number in between:
               
'test_plugin_get_random' => 'TEST event that returns a random number.',
            );
    }


   
/**
     * Gets provided as plugin event (and gets also used internally for demonstration).
     *
     * @param array Associative array of parameters
     *              'min': mininum number
     *              'max': maxinum number
     * @return integer
     */
   
function test_plugin_get_random( & $params )
    {
        return
rand( $params['min'], $params['max'] );
    }


   
/**
     * Return list of custom disp types handled by this plugin
     *
     * @see Plugin::GetHandledDispModes()
     * @return array list of disp modes handled by this plugin
     */
   
function GetHandledDispModes()
    {
        return array(
               
'disp_test', // display our test disp
           
);
    }


   
/**
     * Display our custom disp mode(s)
     *
     * @see Plugin::HandleDispMode()
     * @param mixed array $params
     *    disp > display mode requested
     * @return did we display?
     */
   
function HandleDispMode( $params )
    {
        echo
'<p>This is the test plugin handling the ['.$params['disp'].'] disp mode.</p>';
    }


   
/**
     * Override this method to define methods/functions that you want to make accessible
     * through /htsrv/call_plugin.php, which allows you to call those methods by HTTP request.
     *
     * This is useful for things like AJAX or displaying an IFRAME element, where the content
     * should get provided by the plugin itself.
     *
     * E.g., the image captcha plugin uses this method to serve a generated image.
     *
     * NOTE: the Plugin's method must be prefixed with "htsrv_", but in this list (and the URL) it
     *       is not. E.g., to have a method "disp_image" that should be callable through this method
     *       return <code>array('disp_image')</code> here and implement it as
     *       <code>function htsrv_disp_image( $params )</code> in your plugin.
     *       This is used to distinguish those methods from others, but keep URLs nice.
     *
     * @see Plugin::GetHtsrvMethods()
     * @return array
     */
   
function GetHtsrvMethods()
    {
        return array(
'test_action' );
    }

   
/**
     * AJAX callback to test action.
     *
     * @param array Params
     */
   
function htsrv_test_action( $params )
    {
        global
$DB;

       
// To call this action use URL which is generated by code:
        // $htsrv_plugin_url = $this->get_htsrv_url( 'test_action', array( 'param_1' => 'value_1' ) );

       
if( empty( $params['param_1'] ) )
        {    
// Nothing to do:
           
return;
        }

       
$param2 = param( 'param2', 'string' );

       
$DB->query( 'INSERT INTO '.$this->get_sql_table( 'test_table_name' ).'
            ( test_name ) VALUES ( '
.$DB->quote( 'param_1 = '.$params['param_1'].'; param2 = '.$param2 ).' ) ' );
    }


   
/**
     * This method gets asked for a list of cronjobs that the plugin
     * provides.
     * If a user installs a cron job out of this list, the
     * {@link Plugin::ExecCronJob()} of the plugin gets called.
     *
     * @see Plugin::GetCronJobs()
     * @return array Array of arrays with keys "name", "ctrl" and "params".
     *               "name" gets used for display. "ctrl" (string) and
     *               "params" (array) get passed to the
     *               {@link Plugin::ExecCronJob()} method when the cronjob
     *               gets executed.
     */
   
function GetCronJobs( & $params )
    {
        return array(
                array(
                   
'name' => 'TEST plugin - cron job',
                   
'ctrl' => 'test_job',
                   
'params' => array( 'param' => 1 ),
                ),
            );
    }


   
/**
     * Execute/handle a cron job, which has been scheduled by the admin out
     * of the list that the Plugin provides (see {@link GetCronJobs()}).
     *
     * @see Plugin::ExecCronJob()
     * @param array Associative array of parameters
     *   - 'ctrl': The "ctrl" name as defined in {@link GetCronJobs()}
     *   - 'params': The "params" value as defined in {@link GetCronJobs()},
     *               plus "ctsk_ID" which holds the cron task ID.
     * @return array with keys "code" (integer, 1 is ok), "message" (gets logged)
     */
   
function ExecCronJob( & $params )
    {
        if(
$params['ctrl'] == 'test_job' )
        {
            return array(
'code' => 1, 'message' => 'Test successful.' );
        }
    }

   
// }}}


    /*
     * Event handlers. These are meant to be implemented by your plugin. {{{
     */

    // Admin/backoffice events (without events specific to Items or Comments): {{{


    /**
     * Event handler: Gets invoked in /toolbar.inc.php after the menu structure is built.
     *
     * @see Plugin::AdminAfterEvobarInit()
     */
   
function AdminAfterEvobarInit()
    {
       
// The following is a tiny bit hackish and should probably be abstracted a bit, but just a little bit
        // The idea is too let plugins hook pretty much anywhere into the menu structure, including Left AND Right menus.

       
global $topleft_Menu;
       
$topleft_Menu->add_menu_entries( 'tools', array(
               
'urls_sep' => array(
                       
'separator' => true,
                    ),
               
'urls' => array(
                       
'text' => 'Test plugin&hellip;',
                       
'href' => $this->get_tools_tab_url(),
                    ),
            ) );
    }


   
/**
     * Event handler: Gets invoked in /evoadm.php for every backoffice page after
     *                the menu structure is built. You could use the {@link $AdminUI} object
     *                to modify it.
     *
     * This is the hook to register menu entries. See {@link register_menu_entry()}.
     *
     * @see Plugin::AdminAfterMenuInit()
     */
   
function AdminAfterMenuInit()
    {
       
$this->register_menu_entry( 'Test tab' );
    }


   
/**
     * Event handler: Called when ending the admin html head section.
     *
     * @see Plugin::AdminEndHtmlHead()
     * @param array Associative array of parameters
     * @return boolean did we do something?
     */
   
function AdminEndHtmlHead( & $params )
    {
        echo
'<!-- This comment was added by the TEST plugin event "AdminEndHtmlHead" with function "echo" -->';

       
add_headline( '<!-- This comment was added by the TEST plugin event "AdminEndHtmlHead" with function "add_headline"-->' );

       
add_js_headline( 'console.log( "This JavaScript log was added by the TEST plugin event \'AdminEndHtmlHead\' with function \'add_js_headline\'" )' );

       
add_css_headline( '/* This CSS was added by the TEST plugin event \'AdminEndHtmlHead\' with function "add_css_headline" */' );

        return
true;
    }


   
/**
     * Event handler: Called right after displaying the admin page footer.
     *
     * @see Plugin::AdminAfterPageFooter()
     * @param array Associative array of parameters
     * @return boolean did we do something?
     */
   
function AdminAfterPageFooter( & $params )
    {
        echo
'<p class="footer">This is the TEST plugin responding to the AdminAfterPageFooter event!</p>';

        return
true;
    }


   
/**
     * Event handler: Called when displaying editor buttons (in back-office).
     *
     * This method, if implemented, should output the buttons (probably as html INPUT elements)
     * and return true, if button(s) have been displayed.
     *
     * You should provide an unique html ID with each button.
     *
     * @see Plugin::AdminDisplayEditorButton()
     * @param array Associative array of parameters.
     *   - 'target_type': either 'Comment' or 'Item' or 'EmailCampaign'.
     *   - 'edit_layout': "inskin", "expert", etc. (users, hackers, plugins, etc. may create their own layouts in addition to these)
     *                    NOTE: Please respect the "inskin" mode, which should display only the most simple things!
     * @return boolean did we display a button?
     */
   
function AdminDisplayEditorButton( & $params )
    {
       
?>
       <input type="button" value="TEST" onclick="alert('Hi! This is the TEST plugin (AdminDisplayEditorButton)!');" class="btn btn-default" />
        <?php
       
return true;
    }


   
/**
     * Event handler: Called when displaying editor buttons (in front-office).
     *
     * This method, if implemented, should output the buttons (probably as html INPUT elements)
     * and return true, if button(s) have been displayed.
     *
     * You should provide an unique html ID with each button.
     *
     * @see Plugin::DisplayEditorButton()
     * @param array Associative array of parameters.
     *   - 'target_type': either 'Comment' or 'Item'.
     *   - 'edit_layout': "inskin", "expert", etc. (users, hackers, plugins, etc. may create their own layouts in addition to these)
     *                    NOTE: Please respect the "inskin" mode, which should display only the most simple things!
     * @return boolean did we display a button?
     */
   
function DisplayEditorButton( & $params )
    {
       
?>
       <input type="button" value="TEST" onclick="alert('Hi! This is the TEST plugin (DisplayEditorButton)!');" class="btn btn-default" />
        <?php
       
return true;
    }


   
/**
     * Event handler: Called when displaying editor toolbars on post/item form.
     *
     * This is for post/item edit forms only. Comments, PMs and emails use different events.
     *
     * @see Plugin::AdminDisplayToolbar()
     * @param array Associative array of parameters
     *   - 'edit_layout': "inskin", "expert", etc. (users, hackers, plugins, etc. may create their own layouts in addition to these)
     *                    NOTE: Please respect the "inskin" mode, which should display only the most simple things!
     * @return boolean did we display a toolbar?
     */
   
function AdminDisplayToolbar( & $params )
    {
        echo
$this->get_template( 'toolbar_before', array( '$toolbar_class$' => $this->code.'_toolbar' ) );

        echo
$this->get_template( 'toolbar_title_before' );
        echo
'TEST toolbar for Item:';
        echo
$this->get_template( 'toolbar_title_after' );

        echo
$this->get_template( 'toolbar_group_before' );
        echo
'<input type="button" class="'.$this->get_template( 'toolbar_button_class' ).'" value="TEST 1" onclick="alert(\'TEST 1\')" />';
        echo
'<input type="button" class="'.$this->get_template( 'toolbar_button_class' ).'" value="TEST 2" onclick="alert(\'TEST 2\')" />';
        echo
$this->get_template( 'toolbar_group_after' );

        echo
$this->get_template( 'toolbar_group_before' );
        echo
'<input type="button" class="'.$this->get_template( 'toolbar_button_class' ).'" value="TEST 3" onclick="alert(\'TEST 3 from second group\')" />';
        echo
$this->get_template( 'toolbar_group_after' );

        echo
$this->get_template( 'toolbar_after' );

        return
true;
    }


   
/**
     * Event handler: Called when handling actions for the "Tools" menu.
     *
     * Use {@link msg()} to add messages for the user.
     *
     * @see Plugin::AdminToolAction()
     */
   
function AdminToolAction()
    {
       
$this->msg( 'Hello, This is the AdminToolAction for the TEST plugin.' );
    }


   
/**
     * Event handler: Called when displaying the block in the "Tools" menu.
     *
     * @see Plugin::AdminToolPayload()
     * @return boolean did we display something?
     */
   
function AdminToolPayload()
    {
        echo
'Hello, This is the AdminToolPayload for the TEST plugin.';

        return
true;
    }


   
/**
     * Event handler: Method that gets invoked when our tab is selected.
     *
     * You should catch (your own) params (using {@link param()}) here and do actions
     * (but no output!).
     *
     * Use {@link msg()} to add messages for the user.
     *
     * @see Plugin::AdminTabAction()
     */
   
function AdminTabAction()
    {
        global
$Plugins;

       
$this->text_from_AdminTabAction = '<p>This is text from AdminTabAction for the TEST plugin.</p>'
           
.'<p>Here is a random number: '
           
.$Plugins->get_trigger_event_first_return('test_plugin_get_random', array( 'min'=>-1000, 'max'=>1000 )).'</p>';

        if(
$this->param_text = param( $this->get_class_id('text') ) )
        {
           
$this->text_from_AdminTabAction .= '<p>You have said: '.$this->param_text.'</p>';
        }
    }


   
/**
     * Event handler: Gets invoked when our tab is selected and should get displayed.
     *
     * Do your output here.
     *
     * @see Plugin::AdminTabPayload()
     * @return boolean did we display something?
     */
   
function AdminTabPayload()
    {
        echo
'Hello, this is the AdminTabPayload for the TEST plugin.';

        echo
$this->text_from_AdminTabAction;

       
// TODO: this is tedious.. should either be a global function (get_admin_Form()) or a plugin helper..
       
$Form = new Form();
       
$Form->begin_form();

       
$Form->add_crumb( 'plugin_test' );
       
$Form->hidden_ctrl(); // needed to pass the "ctrl=tools" param
       
$Form->hiddens_by_key( get_memorized() ); // needed to pass all other memorized params, especially "tab"

       
$Form->text_input( $this->get_class_id().'_text', $this->param_text, '20', 'Text' );

       
$Form->button_input(); // default "submit" button

       
$Form->end_form();

        return
true;
    }


   
/**
     * Event handler: Gets invoked before the main payload in the backoffice.
     *
     * @see Plugin::AdminBeginPayload()
     */
   
function AdminBeginPayload()
    {
        global
$Plugins;

        echo
'<div class="panelblock center">TEST plugin: AdminBeginPayload event.</div>';

        if(
$this->UserSettings->get('echo_random') )
        {
            echo
'<div class="panelblock center">TEST plugin: A random number requested by user setting: '
                   
.$Plugins->get_trigger_event_first_return('test_plugin_get_random', array( 'min'=>0, 'max'=>1000 ) ).'</div>';
        }
    }


   
/**
     * Event handler: Called at the beginning  of the "Edit wdiget" form on back-office.
     *
     * @param array Associative array of parameters
     *   - 'Form': the {@link Form} object (by reference)
     *   - 'ComponentWidget': the Widget which gets edited (by reference)
     * @return boolean did we display something?
     */
   
function WidgetBeginSettingsForm( & $params )
    {
       
$params['Form']->begin_fieldset( 'TEST plugin', array( 'id' => 'WidgetBeginSettingsForm' ) );
       
$params['Form']->info_field( 'TEST plugin', 'This is the TEST plugin responding to the WidgetBeginSettingsForm event for widget #'.$params['ComponentWidget']->ID.'.' );
       
$params['Form']->end_fieldset( 'Foo' );

        return
true;
    }


   
/**
     * Event handler: Called at the end  of the "Edit wdiget" form on back-office.
     *
     * @param array Associative array of parameters
     *   - 'Form': the {@link Form} object (by reference)
     *   - 'ComponentWidget': the Widget which gets edited (by reference)
     * @return boolean did we display something?
     */
   
function WidgetEndSettingsForm( & $params )
    {
       
$params['Form']->begin_fieldset( 'TEST plugin', array( 'id' => 'WidgetEndSettingsForm' ) );
       
$params['Form']->info_field( 'TEST plugin', 'This is the TEST plugin responding to the WidgetEndSettingsForm event for widget #'.$params['ComponentWidget']->ID.'.' );
       
$params['Form']->end_fieldset( 'Foo' );

        return
true;
    }

   
// }}}


    // Skin/Blog events: {{{

    /**
     * Event handler: Called before a blog gets displayed (in _blog_main.inc.php).
     *
     * @see Plugin::BeforeBlogDisplay()
     */
   
function BeforeBlogDisplay( & $params )
    {
       
$this->msg( 'This is the TEST plugin responding to the BeforeBlogDisplay event.' );
    }


   
/**
     * Event handler: Gets invoked when an action request was called which should be blocked in specific cases
     *
     * Blocakble actions: comment post, user login/registration, email send/validation, account activation
     *
     * @see Plugin::BeforeBlockableAction()
     */
   
function BeforeBlockableAction()
    {
       
$this->msg( 'This is the TEST plugin responding to the BeforeBlockableAction event.' );
    }


   
/**
     * Event handler: Called when a MainList object gets created.
     *
     * Note: you must create your own MainList object here, set filters and query the database, see init_MainList() for detailes.
     *
     * @see Plugin::InitMainList()
     * @param array Associative array of parameters
     *   - 'MainList': The "MainList" object (by reference).
     *   - 'limit': The number of posts to display
     * @return boolean True if you've created your own MainList object and queried the database, false otherwise.
     */
   
function InitMainList( & $params )
    {
        global
$Blog;
        global
$preview, $disp;
        global
$postIDlist, $postIDarray, $cat_array;

       
$params['MainList'] = new ItemList2( $Blog, $Blog->get_timestamp_min(), $Blog->get_timestamp_max(), $params['limit'] ); // COPY (FUNC)

       
if( ! $preview )
        {
            if(
$disp == 'page' )
            {    
// Get pages:
               
$params['MainList']->set_default_filters( array(
                       
'itemtype_usage' => 'page', // pages
                   
) );
            }

            if(
$disp == 'search' && param('s', 'string') )
            {    
// Here we allow b2evolution to search in posts and in pages
               
$this->msg( 'TEST plugin: InitMainList() method allows us to search in both posts and pages.', 'note' );

               
$params['MainList']->set_default_filters( array(
                       
'itemtype_usage' => 'post,page'
                   
) );
            }

           
$params['MainList']->load_from_Request( false );

           
// Save aggregate setting
           
$saved_aggregate_state = $Blog->get_setting( 'aggregate_coll_IDs' );

            if(
$disp == 'posts' && !empty($params['MainList']->filters['tags']) )
            {    
// If the MainList if filtered by tag we search for posts in all public blogs
               
if( !empty($params['MainList']->filters['tags']) )
                {    
// All public blogs
                   
$BlogCache = & get_BlogCache();
                   
$Blog->set_setting( 'aggregate_coll_IDs', implode( ',', $BlogCache->load_public() ) );

                   
$this->msg( 'TEST plugin: InitMainList() method allows us to display tagged posts from all public blogs.', 'note' );
                }
            }

           
// Run the query:
           
$params['MainList']->query();

           
// Restore aggregate setting to its original value
           
$Blog->set_setting( 'aggregate_coll_IDs', $saved_aggregate_state );

           
// Old style globals for category.funcs:
           
$postIDlist = $params['MainList']->get_page_ID_list();
           
$postIDarray = $params['MainList']->get_page_ID_array();
        }
        else
        {    
// We want to preview a single post, we are going to fake a lot of things...
           
$params['MainList']->preview_from_request();

           
// Legacy for the category display
           
$cat_array = array();
        }

        return
true; // This is required!
   
}


   
/**
     * Event handler: Called at the beginning of the skin's HTML HEAD section.
     *
     * Use this to add any HTML HEAD lines (like CSS styles or links to resource files (CSS, JavaScript, ..)).
     *
     * @see Plugin::SkinBeginHtmlHead()
     * @param array Associative array of parameters
     */
   
function SkinBeginHtmlHead( & $params )
    {
       
require_js_defer( '#jquery#', 'blog' );
    }


   
/**
     * Event handler: Called at the end of the skin's HTML HEAD section.
     *
     * Use this to add any HTML HEAD lines (like CSS styles or links to resource files (CSS, JavaScript, ..)).
     *
     * @param array Associative array of parameters
     */
   
function SkinEndHtmlHead( & $params )
    {
        echo
'<script>
            jQuery( document ).ready( function()
            {
                jQuery( "#plugin_test_htsrv_action_'
.$this->ID.'" ).click( function()
                {
                    jQuery.ajax( {
                        url: "'
.$this->get_htsrv_url( 'test_action', array( 'param_1' => 'value_1' ), '&', true ).'",
                        data: "param2=value2",
                        success: function( result )
                        {
                            alert( "New record has been inserted to DB table \"'
.$this->get_sql_table( 'test_table_name' ).'\"" );
                        }
                    } );
                    return false;
                } );
            } );
        </script>'
;
    }


   
/**
     * Event handler: Called at the beginning of the skin's HTML BODY section.
     *
     * Use this to add any HTML snippet at the beginning of the generated page.
     *
     * @param array Associative array of parameters
     */
   
function SkinBeginHtmlBody( & $params )
    {
        echo
'TEST plugin: SkinBeginHtmlBody event.';
    }


   
/**
     * Event handler: Called at the end of the skin's HTML BODY section.
     *
     * Use this to add any HTML snippet at the end of the generated page.
     *
     * @see Plugin::SkinBeginHtmlHead()
     * @param array Associative array of parameters
     */
   
function SkinEndHtmlBody( & $params )
    {
        echo
'TEST plugin: SkinEndHtmlBody event.';
    }


   
/**
     * Event handler: Gets called before skin wrapper.
     *
     * Use this to add any HTML code before skin wrapper and after evo toolbar.
     *
     * @see Plugin::BeforeSkinWrapper()
     * @param array Associative array of parameters
     */
   
function BeforeSkinWrapper( & $params )
    {
        echo
'<p>TEST plugin: BeforeSkinWrapper event.</p>';

        echo
'<p><a href="#" id="plugin_test_htsrv_action_'.$this->ID.'">Click here</a> to test htsrv plugin action and see a result in DB table <code>'.$this->get_sql_table( 'test_table_name' ).'</code>.</p>';
    }

   
/**
     * Called when a plugin gets called by its {@link $code}.
     *
     * If you provide this event, b2evolution will assume your plugin
     * provides a widget and list it in the "Available widgets" list.
     *
     * @see Plugins::SkinTag()
     * @param array The array passed to {@link Plugins::call_by_code()}.
     */
   
function SkinTag( & $params )
    {
        echo
$params['block_start'];

        echo
$params['block_title_start'];
        echo
$params['title'];
        echo
$params['block_title_end'];

        echo
$params['block_body_start'];

        echo
'Test plugin widget content';

        echo
$params['block_body_end'];

        echo
$params['block_end'];

        return
true;
    }

   
/**
     * Event handler: Gets asked about a list of skin names that the plugin handles.
     *
     * If one of the skins returned gets called through the "skin=X" URL param, the
     * {@link Plugin::DisplaySkin()} method of your plugin gets called.
     *
     * @see Plugins::GetProvidedSkins()
     * @return array
     */
   
function GetProvidedSkins()
    {
        return array(
'bootstrap_blog_skin' );
    }


   
/**
     * Event handler: Display a skin. Use {@link Plugin::GetProvidedSkins()} to return
     * a list of names that you register.
     *
     * @see Plugins::DisplaySkin()
     * @param array Associative array of parameters
     *   - 'skin': name of skin to be displayed (from the list of {@link Plugin::GetProvidedSkins()}).
     *             If your Plugin only registers one skin, you can ignore it.
     */
   
function DisplaySkin( & $params )
    {
        if(
$params['skin'] == 'bootstrap_blog_skin' )
        {
            global
$skins_path, $app_version, $disp, $ads_current_skin_path, $disp_handlers, $disp_handler, $Skin, $Blog, $Item;

           
$ads_current_skin_path = $skins_path.$params['skin'].'/';

           
$disp_handler = $ads_current_skin_path.'index.main.php';

            require
$disp_handler;
        }
    }

   
// }}}


    // (Un)Install / (De)Activate events: {{{

    /**
     * Event handler: Called before the plugin is going to be installed.
     *
     * This is the hook to create any DB tables or the like.
     *
     * If you just want to add a note, use {@link Plugin::msg()} (and return true).
     *
     * @see Plugin::BeforeInstall()
     * @return true|string True, if the plugin can be enabled/activated,
     *                     a string with an error/note otherwise.
     */
   
function BeforeInstall()
    {
       
$this->msg( 'TEST plugin: BeforeInstall event.' );
        return
true;
    }


   
/**
     * Event handler: Called after the plugin has been installed.
     *
     * @see Plugin::AfterInstall()
     */
   
function AfterInstall()
    {
       
$this->msg( 'TEST plugin sucessfully installed. All the hard work we did was adding this message in the AfterInstall event.. ;)' );
    }


   
/**
     * Event handler: Called before the plugin is going to be un-installed.
     *
     * This is the hook to remove any files or the like - tables with canonical names
     * (see {@link Plugin::get_sql_table()}, are handled internally.
     *
     * See {@link BeforeUninstallPayload()} for the corresponding payload handler, which you
     * can request to invoke by returning NULL here.
     *
     * Note: this method gets called again, if the uninstallation has to be confirmed,
     *       either because you've requested a call to {@link BeforeUninstallPayload()}
     *       or there are tables to be dropped (what the admin user has to confirm).
     *
     * @see Plugin::BeforeUninstall()
     * @param array Associative array of parameters.
     *              'unattended': true if Uninstall is unattended (e.g., the /install action "deletedb" uses it).
     *                            This should cleanup everything without confirmation!
     * @return boolean|NULL
     *         true when it's ok to uninstall,
     *         false on failure (the plugin won't get uninstalled then).
     *               You should add the reason for it through {@link Plugin::msg()}.
     *         NULL requests to execute the {@link BeforeUninstallPayload()} method.
     */
   
function BeforeUninstall( & $params )
    {
       
$this->msg( 'TEST plugin sucessfully un-installed. All the hard work we did was adding this message.. ;)' );
        return
true;
    }


   
/**
     * Event handler: Gets invoked to display the payload before uninstalling the plugin.
     *
     * You have to request a call to this during the plugin uninstall procedure by
     * returning NULL in {@link BeforeUninstall()}.
     *
     * @see Plugin::BeforeUninstallPayload()
     * @param array Associative array of parameters.
     *              'Form': The {@link Form} that asks the user for confirmation (by reference).
     *                      If your plugin uses canonical table names (see {@link Plugin::get_sql_table()}),
     *                      there will be already a list of those tables included in it.
     *                      Do not end the form, just add own inputs or hidden keys to it.
     */
   
function BeforeUninstallPayload( & $params )
    {
        echo
'TEST plugin: BeforeUninstallPayload event.';
    }


   
/**
     * Event handler: Called when the admin tries to enable the plugin, changes
     * its configuration/settings and after installation.
     *
     * Use this, if your plugin needs configuration before it can be used.
     *
     * @see Plugin::BeforeEnable()
     * @return true|string True, if the plugin can be enabled/activated,
     *                     a string with an error/note otherwise.
     */
   
function BeforeEnable()
    {
       
$this->msg( 'TEST plugin: BeforeEnable event.' );
        return
true;  // default is to allow Activation
   
}


   
/**
     * Event handler: Your plugin gets notified here, just before it gets
     * disabled.
     *
     * You cannot prevent this, but only clean up stuff, if you have to.
     *
     * @see Plugin::BeforeDisable()
     */
   
function BeforeDisable()
    {
       
$this->msg( 'TEST plugin: BeforeDisable event.' );
    }


   
/**
     * Event handler: Called when we detect a version change (in {@link Plugins::register()}).
     *
     * Use this for your upgrade needs.
     *
     * @see Plugin::PluginVersionChanged()
     * @param array Associative array of parameters.
     *              'old_version': The old version of your plugin as stored in DB.
     *              'db_row': an array with the columns of the plugin DB entry (in T_plugins).
     *                        The key 'plug_version' is the same as the 'old_version' key.
     * @return boolean If this method returns false, the Plugin's status gets changed to "needs_config" and
     *                 it gets unregistered for the current request.
     */
   
function PluginVersionChanged( & $params )
    {
       
$this->msg( 'TEST plugin: BeforeDisable event.' );
        return
true;
    }

   
// }}}


    // Blog events: {{{

    /**
     * Event handler: called at the end of {@link Blog::dbinsert() inserting
     * a blog into the database}, which means it has been created.
     *
     * @see Plugin::AfterCollectionInsert()
     * @param array Associative array of parameters
     *   - 'Blog': the related Blog (by reference)
     */
   
function AfterCollectionInsert( & $params )
    {
       
$this->msg( 'This is the TEST plugin responding to the AfterCollectionInsert event.' );
    }


   
/**
     * Event handler: called at the end of {@link Blog::dbupdate() updating
     * a blog in the database}.
     *
     * @see Plugin::AfterCollectionUpdate()
     * @param array Associative array of parameters
     *   - 'Blog': the related Blog (by reference)
     */
   
function AfterCollectionUpdate( & $params )
    {
       
$this->msg( 'This is the TEST plugin responding to the AfterCollectionUpdate event.' );
    }


   
/**
     * Event handler: called at the end of {@link Blog::dbdelete() deleting
     * a blog from the database}.
     *
     * @see Plugin::AfterCollectionDelete()
     * @param array Associative array of parameters
     *   - 'Blog': the related Blog (by reference)
     */
   
function AfterCollectionDelete( & $params )
    {
       
$this->msg( 'This is the TEST plugin responding to the AfterCollectionDelete event.' );
    }


   
/**
     * Event handler: Defines blog kinds, their names and description.
     * Define blog settings in {@link Plugin::InitCollectionKinds()} method of your plugin.
     *
     * Note: You can change default blog kinds $params['kinds'] (which get passed by reference).
     *
     * @see Plugin::GetCollectionKinds()
     * @param array Associative array of parameters
     *   - 'kinds': dafault blog kinds (by reference)
     * @retun: array
     */
   
function GetCollectionKinds( & $params )
    {
       
$params['kinds'] = array_merge( $params['kinds'], array(
               
'test_kind' => array(
                   
'name' => 'Just another collection type',
                   
'desc' => 'This is the TEST plugin handling the GetCollectionKinds event.',
                ),
               
'std' => array( // override standard blog settings
                   
'name' => 'Non-standard blog',
                   
'desc' => 'Description is changed by TEST plugin.',
                ),
            ) );

        return
$params['kinds'];
    }


   
/**
     * Event handler: Defines blog settings by its kind. Use {@link get_collection_kinds()} to return
     * an array of available blog kinds and their names.
     * Define new blog kinds in {@link Plugin::GetCollectionKinds()} method of your plugin.
     *
     * Note: You have to change $params['Blog'] (which gets passed by reference).
     *
     * @see Plugin::InitCollectionKinds()
     * @param array Associative array of parameters
     *   - 'Blog': created Blog (by reference)
     *   - 'kind': the kind of created blog (by reference)
     */
   
function InitCollectionKinds( & $params )
    {
       
// Load blog functions
       
load_funcs( 'collections/model/_blog.funcs.php' );

       
// Get all available blog kinds
       
$kinds = get_collection_kinds();

        switch(
$params['kind'] )
        {
            case
'std': // override standard blog settings
               
$params['Blog']->set( 'name', $kinds[$params['kind']]['name'] );
                break;

            case
'test_kind':
               
$params['Blog']->set( 'name', $kinds[$params['kind']]['name'] );
               
$params['Blog']->set( 'shortname', 'Test blog' );
                break;
        }
    }

   
// }}}


    // Item events: {{{

    /**
     * Event handler: Called when rendering item/post contents as HTML. (CACHED)
     *
     * The rendered content will be *cached* and the cached content will be reused on subsequent displays.
     * Use {@link DisplayItemAsHtml()} instead if you want to do rendering at display time.
     *
      * Note: You have to change $params['data'] (which gets passed by reference).
     *
     * @see Plugin::DisplayItemAsHtml()
     * @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.
     *   - 'Item': the {@link Item} object which gets rendered.
     *   - 'view_type': What part of a post are we displaying: 'teaser', 'extension' or 'full'
     * @return boolean Have we changed something?
     */
   
function RenderItemAsHtml( & $params )
    {
       
$params['data'] = 'TEST['.$params['data'].']TEST - RenderItemAsHtml()';

        return
true;
    }


   
/**
     * Event handler: Called when rendering item/post contents as XML.
     *
     * Should this plugin apply to XML?
     * It should actually only apply when:
     * - it generates some content that is visible without HTML tags
     * - it removes some dirty markup when generating the tags (which will get stripped afterwards)
     * Note: htmlentityencoded is not considered as XML here.
     *
     * Note: You have to change $params['data'] (which gets passed by reference).
     *
     * @see Plugin::RenderItemAsXml()
     * @param array Associative array of parameters
     *   - 'data': the data (by reference). You probably want to modify this.
     *   - 'format': see {@link format_to_output()}. Only 'xml' will arrive here.
     *   - 'Item': the {@link Item} object which gets rendered.
     *   - 'view_type': What part of a post are we displaying: 'teaser', 'extension' or 'full'
     * @return boolean Have we changed something?
     */
   
function RenderItemAsXml( & $params )
    {
       
$params['data'] = 'TEST['.$params['data'].']TEST - RenderItemAsXml()';

        return
true;
    }


   
/**
     * Event handler: Called when rendering item/post contents other than XML or HTML.
     *
     * Note: return value is ignored. You have to change $params['data'].
     *
     * @see Plugin::RenderItemAsText()
     * @param array Associative array of parameters
     *   - 'data': the data (by reference). You probably want to modify this.
     *   - 'format': see {@link format_to_output()}. Only 'text' will arrive here.
     *   - 'Item': the {@link Item} object which gets rendered.
     *   - 'view_type': What part of a post are we displaying: 'teaser', 'extension' or 'full'
     * @return boolean Have we changed something?
     */
   
function RenderItemAsText( & $params )
    {
       
$params['data'] = 'TEST['.$params['data'].']TEST - RenderItemAsText()';

        return
true;
    }


   
/**
     * Event handler: Called when displaying an item/post's content as HTML.
     *
     * This is different from {@link RenderItemAsHtml()}, because it gets called
     * on every display (while rendering gets cached).
     *
     * @see Plugin::DisplayItemAsHtml()
     * @param array Associative array of parameters
     *   - 'data': the data (by reference). You probably want to modify this.
     *   - 'format': see {@link format_to_output()}.
     *   - 'Item': The {@link Item} that gets displayed (by reference).
     *   - 'preview': Is this only a preview?
     *   - 'dispmore': Does this include the "more" text (if available), which means "full post"?
     *   - 'view_type': What part of a post are we displaying: 'teaser', 'extension' or 'full'
     * @return boolean Have we changed something?
     */
   
function DisplayItemAsHtml( & $params )
    {
       
$params['data'] = $params['data']."\n<br />-- test_plugin::DisplayItemAsHtml()";

        return
true;
    }


   
/**
     * Event handler: Called when displaying an item/post's content as XML.
     *
     * This is different from {@link RenderItemAsXml()}, because it gets called
     * on every display (while rendering gets cached).
     *
     * @see Plugin::DisplayItemAsXml()
     * @param array Associative array of parameters
     *   - 'data': the data (by reference). You probably want to modify this.
     *   - 'format': see {@link format_to_output()}.
     *   - 'Item': The {@link Item} that gets displayed (by reference).
     *   - 'preview': Is this only a preview?
     *   - 'dispmore': Does this include the "more" text (if available), which means "full post"?
     *   - 'view_type': What part of a post are we displaying: 'teaser', 'extension' or 'full'
     * @return boolean Have we changed something?
     */
   
function DisplayItemAsXml( & $params )
    {
       
$params['data'] = $params['data']."\n<br />-- test_plugin::DisplayItemAsXml()";

        return
true;
    }


   
/**
     * Event handler: Called when displaying an item/post's content as text.
     *
     * This is different from {@link RenderItemAsText()}, because it gets called
     * on every display (while rendering gets cached).
     *
     * @see Plugin::DisplayItemAsText()
     * @param array Associative array of parameters
     *   - 'data': the data (by reference). You probably want to modify this.
     *   - 'format': see {@link format_to_output()}. Only 'text' will arrive here.
     *   - 'Item': The {@link Item} that gets displayed (by reference).
     *   - 'preview': Is this only a preview?
     *   - 'dispmore': Does this include the "more" text (if available), which means "full post"?
     *   - 'view_type': What part of a post are we displaying: 'teaser', 'extension' or 'full'
     * @return boolean Have we changed something?
     */
   
function DisplayItemAsText( & $params )
    {
       
$params['data'] = $params['data']."\n<br />-- test_plugin::DisplayItemAsText()";

        return
true;
    }


   
/**
     * Event handler: called at the beginning of {@link Item::dbupdate() updating
     * an item/post in the database}.
     *
     * Use this to manipulate the {@link Item}, e.g. adding a renderer code
     * through {@link Item::add_renderer()}.
     *
     * @see Plugin::PrependItemUpdateTransact()
     * @param array Associative array of parameters
     *   - 'Item': the related Item (by reference)
     */
   
function PrependItemUpdateTransact( & $params )
    {
       
$this->msg( 'This is the TEST plugin responding to the PrependItemUpdateTransact event.' );
    }


   
/**
     * Event handler: called at the end of {@link Item::dbupdate() updating
     * an item/post in the database}.
     *
     * @see Plugin::AfterItemUpdate()
     * @param array Associative array of parameters
     *   - 'Item': the related Item (by reference)
     *   - 'dbchanges': array with DB changes; a copy of {@link Item::dbchanges()},
     *                  before they got applied (since 1.9)
     */
   
function AfterItemUpdate( & $params )
    {
       
$this->msg( 'This is the TEST plugin responding to the AfterItemUpdate event.' );
    }


   
/**
     * Event handler: called at the beginning of {@link Item::dbinsert() inserting
     * an item/post in the database}.
     *
     * Use this to manipulate the {@link Item}, e.g. adding a renderer code
     * through {@link Item::add_renderer()}.
     *
     * @see Plugin::PrependItemInsertTransact()
     * @param array Associative array of parameters
     *   - 'Item': the related Item (by reference)
     */
   
function PrependItemInsertTransact( & $params )
    {
       
$this->msg( 'This is the TEST plugin responding to the PrependItemInsertTransact event.' );
    }


   
/**
     * Event handler: called at the end of {@link Item::dbinsert() inserting
     * a item/post into the database}, which means it has been created.
     *
     * @see Plugin::AfterItemInsert()
     * @param array Associative array of parameters
     *   - 'Item': the related Item (by reference)
     *   - 'dbchanges': array with DB changes; a copy of {@link Item::dbchanges()},
     *                  before they got applied (since 1.9)
     */
   
function AfterItemInsert( & $params )
    {
       
$this->msg( 'This is the TEST plugin responding to the AfterItemInsert event.' );
    }


   
/**
     * Event handler: called at the end of {@link Item::dbdelete() deleting
     * an item/post from the database}.
     *
     * @see Plugin::AfterItemDelete()
     * @param array Associative array of parameters
     *   - 'Item': the related Item (by reference)
     */
   
function AfterItemDelete( & $params )
    {
       
$this->msg( 'This is the TEST plugin responding to the AfterItemDelete event.' );
    }


   
/**
     * Event handler: called when instantiating an Item for preview.
     *
     * @see Plugin::AppendItemPreviewTransact()
     * @param array Associative array of parameters
     *   - 'Item': the related Item (by reference)
     */
   
function AppendItemPreviewTransact( & $params )
    {
       
$this->msg( 'This is the TEST plugin responding to the AppendItemPreviewTransact event.' );
    }


   
/**
     * Event handler: Called at the end of the "Edit item" form.
     *
     * @see Plugin::AdminDisplayItemFormFieldset()
     * @param array Associative array of parameters
     *   - 'Form': the {@link Form} object (by reference)
     *   - 'Item': the Item which gets edited (by reference)
     *   - 'edit_layout': "inskin", "expert", etc. (users, hackers, plugins, etc. may create their own layouts in addition to these)
     *                    NOTE: Please respect the "inskin" mode, which should display only the most simple things!
     * @return boolean did we display something?
     */
   
function AdminDisplayItemFormFieldset( & $params )
    {
       
$params['Form']->begin_fieldset( 'TEST plugin' );
       
$params['Form']->info_field( 'TEST plugin', 'This is the TEST plugin responding to the AdminDisplayItemFormFieldset event.' );
       
$params['Form']->end_fieldset( 'Foo' );

        return
true;
    }


   
/**
     * Event handler: Called at the end of the "Edit item" form in front-office.
     *
     * @see Plugin::DisplayItemFormFieldset()
     * @param array Associative array of parameters
     *   - 'Form': the {@link Form} object (by reference)
     *   - 'Item': the Item which gets edited (by reference)
     *   - 'edit_layout': "inskin", "expert", etc. (users, hackers, plugins, etc. may create their own layouts in addition to these)
     *                    NOTE: Please respect the "inskin" mode, which should display only the most simple things!
     * @return boolean did we display something?
     */
   
function DisplayItemFormFieldset( & $params )
    {
       
$params['Form']->begin_fieldset( 'TEST plugin' );
       
$params['Form']->info_field( 'TEST plugin', 'This is the TEST plugin responding to the DisplayItemFormFieldset event.' );
       
$params['Form']->end_fieldset( 'Foo' );

        return
true;
    }


   
/**
     * Event handler: Called before an item gets deleted (in the backoffice).
     *
     * You could {@link Plugin::msg() add a message} of
     * category "error" here, to prevent the comment from being deleted.
     *
     * @see Plugin::AdminBeforeItemEditDelete()
     * @since 2.0
     * @param array Associative array of parameters
     *              'Item': the Item which gets created (by reference)
     */
   
function AdminBeforeItemEditDelete( & $params )
    {
       
$this->msg( 'This is the TEST plugin responding to the AdminBeforeItemEditDelete event.' );
    }


   
/**
     * Event handler: Called before a new item gets created (in the backoffice).
     *
     * You could {@link Plugin::msg() add a message} of
     * category "error" here, to prevent the comment from being inserted.
     *
     * @see Plugin::AdminBeforeItemEditCreate()
     * @param array Associative array of parameters
     *              'Item': the Item which gets created (by reference)
     */
   
function AdminBeforeItemEditCreate( & $params )
    {
       
$this->msg( 'This is the TEST plugin responding to the AdminBeforeItemEditCreate event.' );
    }


   
/**
     * Event handler: Called before an existing item gets updated (in the backoffice).
     *
     * You could {@link Plugin::msg() add a message} of
     * category "error" here, to prevent the comment from being inserted.
     *
     * @see Plugin::AdminBeforeItemEditUpdate()
     * @param array Associative array of parameters
     *              'Item': the Item which gets updated (by reference)
     */
   
function AdminBeforeItemEditUpdate( & $params )
    {
       
$this->msg( 'This is the TEST plugin responding to the AdminBeforeItemEditUpdate event.' );
    }


   
/**
     * Event handler: the plugin gets asked if an item can receive feedback/comments.
     *
     * @see Plugin::ItemCanComment()
     * @param array Associative array of parameters
     *              'Item': the Item
     * @return boolean|string
     *   true, if the Item can receive feedback
     *   false/string, if the Item cannot receive feedback. If you return a string
     *                 this gets displayed as an error/explanation.
     *   NULL, if you do not want to say "yes" or "no".
     */
   
function ItemCanComment( & $params )
    {
    }


   
/**
     * Event handler: send a ping about a new item.
     *
     * @see Plugin::ItemSendPing()
     * @param array Associative array of parameters
     *        'Item': the Item (by reference)
     *        'xmlrpcresp': Set this to the {@link xmlrpcresp} object, if the plugin
     *                      uses XMLRPC.
     *        'display': Should results get displayed? (normally you should not need
     *                   to care about this, especially if you can set 'xmlrpcresp')
     * @return boolean Was the ping successful?
     */
   
function ItemSendPing( & $params )
    {
       
$this->msg( 'This is the TEST plugin responding to the ItemSendPing event.' );
    }


   
/**
     * Event handler: called to display the URL that accepts trackbacks for
     *                an item.
     *
     * @see Plugin::DisplayTrackbackAddr()
     * @param array Associative array of parameters
     *   - 'Item': the {@link Item} object (by reference)
     *   - 'template': the template to display the URL (%url%)
     */
   
function DisplayTrackbackAddr( & $params )
    {
        echo
str_replace( '%url%', 'TEST plugin DisplayTrackbackAddr', $params['template'] );
    }


   
/**
     * Event handler: Does your Plugin want to apply as a renderer for the item?
     *
     * NOTE: this is especially useful for lazy Plugins, which would look
     *       at the content and decide, if they apply.
     *
     * @see Plugin::DisplayTrackbackAddr()
     * @param array Associative array of parameters
     *   - 'Item': the {@link Item} object (by reference)
     * @return boolean|NULL If true, the Plugin gets added as a renderer, false
     *         removes it as a renderer (if existing) and NULL does not change the
     *         renderer setting regarding your Plugin.
     */
   
function ItemApplyAsRenderer( & $params )
    {
        return
true;
    }

   
// }}}


    // Feedback (Comment/Trackback) events: {{{

    /**
     * Event handler: Called when displaying editor toolbars on comment form.
     *
     * @see Plugin::DisplayCommentToolbar()
     * @param array Associative array of parameters
     * @return boolean did we display a toolbar?
     */
   
function DisplayCommentToolbar( & $params )
    {
        echo
$this->get_template( 'toolbar_before', array( '$toolbar_class$' => $this->code.'_toolbar' ) );

        echo
$this->get_template( 'toolbar_title_before' );
        echo
'TEST toolbar for Comment:';
        echo
$this->get_template( 'toolbar_title_after' );

        echo
$this->get_template( 'toolbar_group_before' );
        echo
'<input type="button" class="'.$this->get_template( 'toolbar_button_class' ).'" value="TEST 1" onclick="alert(\'TEST 1\')" />';
        echo
'<input type="button" class="'.$this->get_template( 'toolbar_button_class' ).'" value="TEST 2" onclick="alert(\'TEST 2\')" />';
        echo
$this->get_template( 'toolbar_group_after' );

        echo
$this->get_template( 'toolbar_group_before' );
        echo
'<input type="button" class="'.$this->get_template( 'toolbar_button_class' ).'" value="TEST 3" onclick="alert(\'TEST 3 from second group\')" />';
        echo
$this->get_template( 'toolbar_group_after' );

        echo
$this->get_template( 'toolbar_after' );

        return
true;
    }


   
/**
     * Event handler: Called at the end of the "Edit comment" form on back-office.
     *
     * @see Plugin::AdminDisplayCommentFormFieldset()
     * @param array Associative array of parameters
     *   - 'Form': the {@link Form} object (by reference)
     *   - 'Comment': the Comment which gets edited (by reference)
     *   - 'edit_layout': only NULL currently, as there's only one layout
     * @return boolean did we display something?
     */
   
function AdminDisplayCommentFormFieldset( & $params )
    {
       
$params['Form']->begin_fieldset( 'TEST plugin' );
       
$params['Form']->info_field( 'TEST plugin', 'This is the TEST plugin responding to the AdminDisplayCommentFormFieldset event.' );
       
$params['Form']->end_fieldset( 'Foo' );

        return
true;
    }


   
/**
     * Event handler: Called at the end of the front-office comment form.
     *
     * You might want to use this to inject antispam payload to use in
     * in {@link GetSpamKarmaForComment()} or modify the Comment according
     * to it in {@link BeforeCommentFormInsert()}.
     *
     * @see Plugin::DisplayCommentFormFieldset()
     * @param array Associative array of parameters
     *   - 'Form': the comment form generating object
     *   - 'Item': the Item for which the comment is meant
     */
   
function DisplayCommentFormFieldset( & $params )
    {
       
$params['Form']->begin_fieldset( 'TEST plugin' );
       
$params['Form']->info_field( 'TEST plugin', 'This is the TEST plugin responding to the DisplayCommentFormFieldset event.' );
       
$params['Form']->end_fieldset( 'Foo' );
        return
true;
    }


   
/**
     * Event handler: Called in the submit button section of the
     * front-office comment form.
     *
     * @see Plugin::DisplayCommentFormButton()
     * @param array Associative array of parameters
     *   - 'Form': the comment form generating object
     *   - 'Item': the Item for which the comment is meant
     */
   
function DisplayCommentFormButton( & $params )
    {
       
?>
       <input type="button" value="TEST" onclick="alert('Hi! This is the TEST plugin (DisplayCommentFormButton)!');" class="btn btn-default" />
        <?php
   
}


   
/**
     * Event handler: Called before at the beginning, if a comment form gets sent (and received).
     *
     * Use this to filter input, e.g. the OpenID uses this to provide alternate authentication.
     *
     * If you need to delegate to another service (what OpenID does), you need to remember all
     * these params (use array_keys($params)) and restore them when coming back.
     * Only comment_item_ID is required at the beginning of comment_post.php (where this hook)
     * is located (and has to be passed via GET/POST) - all other params can get stored in a
     * local session and restored when coming back (this is recommended.)
     *
     * @see Plugin::CommentFormSent()
     * @since 1.10.0
     * @see Plugin::DisplayCommentFormFieldset()
     * @param array Associative array of parameters
     *   - 'comment_item_ID': ID of the item the comment is for
     *   - 'comment': the comment text (by reference)
     *   - 'original_comment': the original, unfiltered comment text - you should not modify it here,
     *      this is meant e.g. for the OpenID plugin to re-inject it after redirection (by reference)
     *   - 'action': "save" or "preview" (by reference)
     *   - 'User': {@link User}, if logged in or null (by reference)
     *   - 'anon_name': Name of the anonymous commenter (by reference)
     *   - 'anon_email': E-Mail of the anonymous commenter (by reference)
     *   - 'anon_url': URL of the anonymous commenter (by reference)
     *   - 'anon_allow_msgform': "Allow msgform" preference of the anonymous commenter (by reference)
     *   - 'anon_cookies': "Remember me" preference of the anonymous commenter (by reference)
     *   - 'redirect_to': URL where to redirect to in the end of comment posting (by reference)
     *   - 'crumb_comment': Crumb expected for the comment (see {@link Session::assert_received_crumb()})
     *     (by reference).
     */
   
function CommentFormSent( & $params )
    {
       
$this->msg( 'This is the TEST plugin responding to the CommentFormSent event.' );
    }


   
/**
     * Event handler: Called before a comment gets inserted through the public comment
     *                form.
     *
     * Use this, to validate a comment: you could {@link Plugin::msg() add a message} of
     * category "error" here, to prevent the comment from being inserted.
     *
     * @see Plugin::BeforeCommentFormInsert()
     * @param array Associative array of parameters
     *   - 'Comment': the Comment (by reference)
     *   - 'original_comment': this is the unstripped and unformated posted comment
     *   - 'action': "save" or "preview" (by reference) (since 1.10)
     *   - 'is_preview': is this a request for previewing the comment? (boolean)
     */
   
function BeforeCommentFormInsert( & $params )
    {
       
$this->msg( 'This is the TEST plugin responding to the BeforeCommentFormInsert event.' );
    }


   
/**
     * Event handler: Called when a comment form has been processed and the comment
     *                got inserted into DB.
     *
     * @see Plugin::AfterCommentFormInsert()
     * @param array Associative array of parameters
     *   - 'Comment': the Comment (by reference)
     *   - 'original_comment': this is the unstripped and unformated posted comment
     */
   
function AfterCommentFormInsert( & $params )
    {
       
$this->msg( 'This is the TEST plugin responding to the AfterCommentFormInsert event.' );
    }


   
/**
     * Event handler: Called to ask the plugin for the spam karma of a comment/trackback.
     *
     * This gets called just before the comment gets stored.
     *
     * @see Plugin::GetSpamKarmaForComment()
     * @param array Associative array of parameters
     *   - 'Comment': the {@link Comment} object (by reference)
     *   - The following values are interesting if you want to provide skipping of a test:
     *     - 'cur_karma': current karma value (cur_karma_abs/cur_karma_divider or NULL)
     *     - 'cur_karma_abs': current karma absolute value or NULL (if no Plugin returned karma before)
     *     - 'cur_karma_divider': current divider (sum of weights)
     *     - 'cur_count_plugins': number of Plugins that have already been asked
     * @return integer|NULL Spam probability (-100 - 100).
     *                -100 means "absolutely no spam", 100 means "absolutely spam".
     *                Only if you return a numeric value, it gets considered (e.g., "", NULL or false get ignored).
     */
   
function GetSpamKarmaForComment( & $params )
    {
       
$count = preg_match_all( '~(https?|ftp)://~i', $params['Comment']->content, $matches );

        if(
$count > 5 )
        {    
// If comment has more 5 urls decide this comment is spam:
           
return 100;
        }

       
// Not spam comment:
       
return -100;
    }


   
/**
     * Event handler: called at the end of {@link Comment::dbupdate() updating
     * a comment in the database}.
     *
     * @see Plugin::AfterCommentUpdate()
     * @param array Associative array of parameters
     *   - 'Comment': the related Comment (by reference)
     *   - 'dbchanges': array with DB changes; a copy of {@link Comment::dbchanges()},
     *                  before they got applied (since 1.9)
     */
   
function AfterCommentUpdate( & $params )
    {
       
$this->msg( 'This is the TEST plugin responding to the AfterCommentUpdate event.' );
    }


   
/**
     * Event handler: called at the end of {@link Comment::dbinsert() inserting
     * a comment into the database}, which means it has been created.
     *
     * @see Plugin::AfterCommentInsert()
     * @param array Associative array of parameters
     *   - 'Comment': the related Comment (by reference)
     *   - 'dbchanges': array with DB changes; a copy of {@link Comment::dbchanges()},
     *                  before they got applied (since 1.9)
     */
   
function AfterCommentInsert( & $params )
    {
       
$this->msg( 'This is the TEST plugin responding to the AfterCommentInsert event.' );
    }


   
/**
     * Event handler: called at the end of {@link Comment::dbdelete() deleting
     * a comment from the database}.
     *
     * @see Plugin::AfterCommentDelete()
     * @param array Associative array of parameters
     *   - 'Comment': the related Comment (by reference)
     */
   
function AfterCommentDelete( & $params )
    {
       
$this->msg( 'This is the TEST plugin responding to the AfterCommentDelete event.' );
    }


   
/**
     * Event handler: called before a trackback gets recorded.
     *
     * Use this, to validate a trackback: you could {@link Plugin::msg() add a message} of
     * category "error" here, to prevent the trackback from being accepted.
     *
     * @see Plugin::BeforeTrackbackInsert()
     * @param array Associative array of parameters
     *   - 'Comment': the trackback (which is a {@link Comment} object with "trackback" type) (by reference)
     *        The trackback-params get mapped like this:
     *        - "blog_name" => "author"
     *        - "url" => "author_url"
     *        - "title"/"excerpt" => "comment"
     *
     */
   
function BeforeTrackbackInsert( & $params )
    {
       
$this->msg( 'This is the TEST plugin responding to the BeforeTrackbackInsert event.' );
    }

   
/**
     * Event handler: Gets called after a trackback has been recorded.
     *
     * @see Plugin::AfterTrackbackInsert()
     * @param array Associative array of parameters
     *   - 'Comment': the trackback (which is a {@link Comment} object with "trackback" type) (by reference)
     *        The trackback-params get mapped like this:
     *        - "blog_name" => "author"
     *        - "url" => "author_url"
     *        - "title"/"excerpt" => "comment"
     */
   
function AfterTrackbackInsert( & $params )
    {
       
$this->msg( 'This is the TEST plugin responding to the AfterTrackbackInsert event.' );
    }

   
/**
     * Event handler: called to filter the comment's anonymous author name
     *
     * @see Plugin::FilterCommentAuthor()
     * @param array Associative array of parameters
     *   - 'data': the name of the author/blog (by reference)
     *   - 'Comment': the {@link Comment} object
     */
   
function FilterCommentAuthor( & $params )
    {
       
$params['data'] = $params['data'].' TEST plugin FilterCommentAuthor()';
    }


   
/**
     * Event handler: called to filter the comment's author URL.
     * This may be either the URL only or a full link (A tag).
     *
     * @see Plugin::FilterCommentAuthorUrl()
     * @param array Associative array of parameters
     *   - 'data': the URL of the author/blog (by reference)
     *   - 'makelink': true, if the "data" contains a link (HTML A tag)
     *   - 'Comment': the {@link Comment} object
     */
   
function FilterCommentAuthorUrl( & $params )
    {
       
$params['data'] = $params['data'].' TEST plugin FilterCommentAuthorUrl()';
    }


   
/**
     * Event handler: called to filter the comment's content
     *
     * @see Plugin::FilterCommentContent()
     * @param array Associative array of parameters
     *   - 'data': the name of the author/blog (by reference)
     *   - 'Comment': the {@link Comment} object
     */
   
function FilterCommentContent( & $params )
    {
       
parent::FilterCommentContent( $params );
    }

   
// }}}


    // Message form events: {{{

    /**
     * Event handler: Called when displaying editor toolbars for message.
     *
     * @see Plugin::DisplayMessageToolbar()
     * @param array Associative array of parameters
     * @return boolean did we display a toolbar?
     */
   
function DisplayMessageToolbar( & $params )
    {
        echo
$this->get_template( 'toolbar_before', array( '$toolbar_class$' => $this->code.'_toolbar' ) );

        echo
$this->get_template( 'toolbar_title_before' );
        echo
'TEST toolbar for Message:';
        echo
$this->get_template( 'toolbar_title_after' );

        echo
$this->get_template( 'toolbar_group_before' );
        echo
'<input type="button" class="'.$this->get_template( 'toolbar_button_class' ).'" value="TEST 1" onclick="alert(\'TEST 1\')" />';
        echo
'<input type="button" class="'.$this->get_template( 'toolbar_button_class' ).'" value="TEST 2" onclick="alert(\'TEST 2\')" />';
        echo
$this->get_template( 'toolbar_group_after' );

        echo
$this->get_template( 'toolbar_group_before' );
        echo
'<input type="button" class="'.$this->get_template( 'toolbar_button_class' ).'" value="TEST 3" onclick="alert(\'TEST 3 from second group\')" />';
        echo
$this->get_template( 'toolbar_group_after' );

        echo
$this->get_template( 'toolbar_after' );

        return
true;
    }


   
/**
     * Event handler: Called at the end of the front-office message form, which
     * allows to send an email to a user/commentator.
     *
     * You might want to use this to inject antispam payload to use in
     * in {@link MessageFormSent()}.
     *
     * @see Plugin::DisplayMessageFormFieldset()
     * @param array Associative array of parameters
     *   - 'Form': the comment form generating object
     *   - 'recipient_ID': ID of the user (if any)
     *   - 'item_ID': ID of the item where the user clicked the msgform icon (if any)
     *   - 'comment_ID': ID of the comment where the user clicked the msgform icon (if any)
     */
   
function DisplayMessageFormFieldset( & $params )
    {
       
$params['Form']->begin_fieldset( 'TEST plugin' );
       
$params['Form']->info_field( 'TEST plugin', 'This is the TEST plugin responding to the DisplayMessageFormFieldset event.' );
       
$params['Form']->end_fieldset( 'Foo' );

        return
true;
    }


   
/**
     * Event handler: Called in the submit button section of the
     * front-office message form.
     *
     * @see Plugin::DisplayMessageFormButton()
     * @param array Associative array of parameters
     *   - 'Form': the comment form generating object
     *   - 'recipient_ID': ID of the user (if any)
     *   - 'item_ID': ID of the item where the user clicked the msgform icon (if any)
     *   - 'comment_ID': ID of the comment where the user clicked the msgform icon (if any)
     */
   
function DisplayMessageFormButton( & $params )
    {
       
?>
       <input type="button" value="TEST" onclick="alert('Hi! This is the TEST plugin (DisplayMessageFormButton)!');" class="btn btn-default" />
        <?php
   
}


   
/**
     * Event handler: Called before at the beginning, if a message of thread form gets sent (and received).
     *
     * Use this to filter input
     *
     * @see Plugin::MessageThreadFormSent()
     * @param array Associative array of parameters
     *   - 'content': the message text (by reference)
     */
   
function MessageThreadFormSent( & $params )
    {
       
$this->msg( 'This is the TEST plugin responding to the MessageThreadFormSent event.' );
    }


   
/**
     * Event handler: Called when a message form has been submitted.
     *
     * Add messages of category "error" to prevent the message from being sent.
     *
     * You can also alter the "message" or "message_footer" that gets sent here.
     *
     * @see Plugin::MessageFormSent()
     * @param array Associative array of parameters
     *   - 'recipient_ID': ID of the user (if any)
     *   - 'item_ID': ID of the item where the user clicked the msgform icon (if any)
     *   - 'comment_ID': ID of the comment where the user clicked the msgform icon (if any)
     *   - 'sender_name': The name of the sender (by reference) (since 1.10.0)
     *   - 'sender_email': The email address of the sender (by reference) (since 1.10.0)
     *   - 'subject': The subject of the message to be sent (by reference) (since 1.10.0)
     *   - 'message': The message to be sent (by reference)
     *   - 'Blog': The blog, depending on the context (may be null) (by reference) (since 1.10.0)
     */
   
function MessageFormSent( & $params )
    {
       
$this->msg( 'This is the TEST plugin responding to the MessageFormSent event.' );
    }


   
/**
     * Event handler: Called after a message has been sent through the public email form.
     *
     * This is meant to cleanup generated data.
     *
     * @see Plugin::MessageFormSent()
     * @param array Associative array of parameters
     *   - 'success_message' (bool): true if the message has been sent, false otherwise
     */
   
function MessageFormSentCleanup( & $params )
    {
       
$this->msg( 'This is the TEST plugin responding to the MessageFormSentCleanup event.' );
    }


   
/**
     * Event handler: called to filter the message's content
     *
     * @see Plugin::FilterMsgContent()
     * @param array Associative array of parameters
     *   - 'data': the name of the author/blog (by reference)
     *   - 'Message': the {@link Comment} object
     */
   
function FilterMsgContent( & $params )
    {
       
parent::FilterMsgContent( $params );
    }

   
/**
     * Event handler: Called when rendering message contents as HTML. (CACHED)
     *
     * The rendered content will be *cached* and the cached content will be reused on subsequent displays.
     *
     * Note: You have to change $params['data'] (which gets passed by reference).
     *
     * @see Plugin::RenderMessageAsHtml()
     * @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.
     *   - 'Item': the {@link Item} object which gets rendered.
     *   - 'view_type': What part of a post are we displaying: 'teaser', 'extension' or 'full'
     * @return boolean Have we changed something?
     */
   
function RenderMessageAsHtml( & $params )
    {
       
// Use this render by default temporarily
       
return $this->RenderItemAsHtml( $params );
    }

   
// }}}


    // Email form events: {{{

    /**
     * Event handler: Called when displaying editor toolbars for email.
     *
     * @see Plugin::DisplayEmailToolbar()
     * @param array Associative array of parameters
     * @return boolean did we display a toolbar?
     */
   
function DisplayEmailToolbar( & $params )
    {
        echo
$this->get_template( 'toolbar_before', array( '$toolbar_class$' => $this->code.'_toolbar' ) );

        echo
$this->get_template( 'toolbar_title_before' );
        echo
'TEST toolbar for Email Campaign:';
        echo
$this->get_template( 'toolbar_title_after' );

        echo
$this->get_template( 'toolbar_group_before' );
        echo
'<input type="button" class="'.$this->get_template( 'toolbar_button_class' ).'" value="TEST 1" onclick="alert(\'TEST 1\')" />';
        echo
'<input type="button" class="'.$this->get_template( 'toolbar_button_class' ).'" value="TEST 2" onclick="alert(\'TEST 2\')" />';
        echo
$this->get_template( 'toolbar_group_after' );

        echo
$this->get_template( 'toolbar_group_before' );
        echo
'<input type="button" class="'.$this->get_template( 'toolbar_button_class' ).'" value="TEST 3" onclick="alert(\'TEST 3 from second group\')" />';
        echo
$this->get_template( 'toolbar_group_after' );

        echo
$this->get_template( 'toolbar_after' );

        return
true;
    }


   
/**
     * Event handler: Called before at the beginning, if an email form gets sent (and received).
     *
     * Use this to filter input
     *
     * @see Plugin::EmailFormSent()
     * @param array Associative array of parameters
     *   - 'content': the message text (by reference)
     */
   
function EmailFormSent( & $params )
    {
       
$this->msg( 'This is the TEST plugin responding to the EmailFormSent event.' );
    }


   
/**
     * Event handler: called to filter the email's content
     *
     * @see Plugin::FilterEmailContent()
     * @param array Associative array of parameters
     *   - 'EmailCampaign': the {@link EmailCampaign} object
     */
   
function FilterEmailContent( & $params )
    {
       
parent::FilterEmailContent( $params );
    }

   
/**
     * Event handler: Called when rendering email contents as HTML. (CACHED)
     *
     * The rendered content will be *cached* and the cached content will be reused on subsequent displays.
     *
     * Note: You have to change $params['data'] (which gets passed by reference).
     *
     * @see Plugin::RenderEmailAsHtml()
     * @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.
     *   - 'EmailCampaign': the {@link Item} object which gets rendered.
     * @return boolean Have we changed something?
     */
   
function RenderEmailAsHtml( & $params )
    {
       
// Use this render by default temporarily
       
return $this->RenderItemAsHtml( $params );
    }

   
// }}}


    // Caching events: {{{


    /**
     * Event handler: called to cache page content (get cached content or request caching).
     *
     * This method must build a unique key for the requested page (including cookie/session info) and
     * start an output buffer, to get the content to cache.
     *
     * Note, that there are special occassions when this event does not get called, because we want
     * really fresh content always:
     *  - we're generating static pages
     *  - there gets a "dynamic object", such as "Messages" or "core.preview_Comment" transported in the session
     *
     * @see Plugin::CachePageContent()
     * @param array Associative array of parameters
     *   - 'data': this must get set to the page content on cache hit
     * @return boolean True if we handled the request (either returned caching data or started buffering),
     *                 false if we do not want to cache this page.
     */
   
function CachePageContent( & $params )
    {
    }


   
/**
     * Event handler: gets asked for if we are generating cached content.
     *
     * This is useful to not generate a list of online users or the like.
     *
     * @see Plugin::CacheIsCollectingContent()
     * @return boolean
     */
   
function CacheIsCollectingContent()
    {
       
// Uncomment a line below if this plugin is collecting a content in cache currently:
        // return true;
   
}


   
/**
     * This gets called before an image thumbnail gets created.
     *
     * This is useful to post-process the thumbnail image (add a watermark or change colors).
     *
     * @see Plugin::BeforeThumbCreate()
     * @param array Associative array of parameters
     *   - 'File': the related File (by reference)
     *   - 'imh': image resource (by reference)
     *   - 'size': size name (by reference)
     *   - 'mimetype': mimetype of thumbnail (by reference)
     *   - 'quality': JPEG image quality [0-100] (by reference)
     *   - 'root_type': file root type 'user', 'group', 'collection' etc. (by reference)
     *   - 'root_type_ID': ID of user, group or collection (by reference)
     */
   
function BeforeThumbCreate( & $params )
    {
       
$this->msg( 'This is the TEST plugin responding to the BeforeThumbCreate event.' );
    }

   
// }}}


    // PluginSettings {{{
    /**
     * Event handler: Called before displaying or setting a plugin's setting in the backoffice.
     *
     * @see PluginSettingsValidateSet()
     * @param array Associative array of parameters
     *   - 'name': name of the setting
     *   - 'value': value of the setting (by reference)
     *   - 'meta': meta data of the setting (as given in {@link GetDefaultSettings()})
     *   - 'action': 'display' or 'set'
     * @return string|NULL Return a string with an error to prevent the setting from being set
     *                     and/or a message added to the settings field.
     */
   
function PluginSettingsValidateSet( & $params )
    {
        if(
$params['name'] == 'input_me' )
        {
            if(
$params['value'] != 'fine' && $params['value'] != 'bad' )
            {
                return
'Answer can be either "fine" or "bad".';
            }
        }
    }


   
/**
     * Event handler: Called as action just before updating the {@link Plugin::$Settings plugin's settings}.
     *
     * The "regular" settings from {@link GetDefaultSettings()} have been set into
     * {@link Plugin::$Settings}, but get saved into DB after this method has been called.
     *
     * Use this to catch custom input fields from {@link PluginSettingsEditDisplayAfter()} or
     * add notes/errors through {@link Plugin::msg()}.
     *
     * If you want to modify plugin events (see {@link Plugin::enable_event()} and
     * {@link Plugin::disable_event()}), you should use {@link Plugin::BeforeEnable()}, because Plugin
     * events get saved (according to the edit settings screen) after this event.
     *
     * @see PluginSettingsUpdateAction()
     * @return false|NULL Return false to prevent the settings from being updated to DB.
     */
   
function PluginSettingsUpdateAction()
    {
       
$this->msg( 'This is the TEST plugin responding to the PluginSettingsUpdateAction event.' );
    }


   
/**
     * Event handler: Called as action before displaying the "Edit plugin" form,
     * which includes the display of the {@link Plugin::$Settings plugin's settings}.
     *
     * You may want to use this to check existing settings or display notes about
     * something.
     *
     * @see PluginSettingsEditAction()
     */
   
function PluginSettingsEditAction()
    {
       
$this->msg( 'This is the TEST plugin responding to the PluginSettingsEditAction event.' );
    }


   
/**
     * Event handler: Called after the form to edit the {@link Plugin::$Settings} has been
     * displayed.
     *
     * Use this to add custom input fields (and catch them in {@link PluginSettingsUpdateAction()})
     * or display custom output (e.g. a test link).
     *
     * @see PluginSettingsEditDisplayAfter()
     * @param array Associative array of parameters
     *   - 'Form': the {@link Form}, where an fieldset has been opened already (by reference)
     */
   
function PluginSettingsEditDisplayAfter( & $params )
    {
       
$this->msg( 'This is the TEST plugin responding to the PluginSettingsEditDisplayAfter event.' );
    }

   
// }}}


    // PluginUserSettings {{{
    /**
     * Event handler: Called before displaying or setting a plugin's user setting in the backoffice.
     *
     * @see PluginUserSettingsValidateSet()
     * @param array Associative array of parameters
     *   - 'name': name of the setting
     *   - 'value': value of the setting (by reference)
     *   - 'meta': meta data of the setting (as given in {@link GetDefaultUserSettings()})
     *   - 'User': the {@link User} for which the setting is
     *   - 'action': 'display' or 'set'
     * @return string|NULL Return a string with an error to prevent the setting from being set
     *                     and/or a message added to the settings field.
     */
   
function PluginUserSettingsValidateSet( & $params )
    {
        if(
$params['name'] == 'deactivate' )
        {
            if(
$params['value'] == 0 )
            {
                return
'Plaese enable setting "Deactivate" of Test plugin.';
            }
        }
    }


   
/**
     * Event handler: Called as action just before updating the {@link Plugin::$UserSettings plugin's user settings}.
     *
     * The "regular" settings from {@link GetDefaultUserSettings()} have been set into
     * {@link Plugin::$UserSettings}, but get saved into DB after this method has been called.
     *
     * Use this to catch custom input fields from {@link PluginUserSettingsEditDisplayAfter()} or
     * add notes/errors through {@link Plugin::msg()}.
     *
     * @see Plugin::PluginUserSettingsUpdateAction()
     * @param array Associative array of parameters
     *   - 'User': the {@link User} for which the settings get updated
     *   - 'action': "save", "reset"
     * @return false|NULL Return false to prevent the settings from being updated to DB.
     */
   
function PluginUserSettingsUpdateAction( & $params )
    {
        if(
$this->UserSettings->get('echo_random') )
        {
           
$this->msg( 'TEST plugin: Random numbers have been disabled.' );
        }
        else
        {
           
$this->msg( 'TEST plugin: Random numbers have been enabled.' );
        }

        return
true;
    }


   
/**
     * Event handler: Called as action before displaying the "Edit user" form,
     * which includes the display of the {@link Plugin::$UserSettings plugin's user settings}.
     *
     * You may want to use this to check existing settings or display notes about
     * something.
     *
     * @see PluginUserSettingsEditAction()
     * @param array Associative array of parameters
     *   - 'User': the {@link User} for which the settings are being displayed/edited
     */
   
function PluginUserSettingsEditAction( & $params )
    {
       
$this->msg( 'This is the TEST plugin responding to the PluginUserSettingsEditAction event.' );
    }


   
/**
     * Event handler: Called after the form to edit the {@link Plugin::$UserSettings} has been
     * displayed.
     *
     * Use this to add custom input fields (and catch them in {@link PluginUserSettingsUpdateAction()})
     * or display custom output (e.g. a test link).
     *
     * @see PluginUserSettingsEditDisplayAfter()
     * @param array Associative array of parameters
     *   - 'Form': the {@link Form}, where an fieldset has been opened already (by reference)
     *   - 'User': the {@link User} whose settings get displayed for editing (since 1.10.0)
     */
   
function PluginUserSettingsEditDisplayAfter( & $params )
    {
       
$this->msg( 'This is the TEST plugin responding to the PluginUserSettingsEditDisplayAfter event.' );
    }

   
// }}}

    // PluginCollSettings {{{
    /**
     * Event handler: Called as action just before updating plugin's collection/blog settings.
     *
     * Use this to add notes/errors through {@link Plugin::msg()} or to process saved settings.
     *
     * @see PluginCollSettingsUpdateAction()
     */
   
function PluginCollSettingsUpdateAction()
    {
       
$this->msg( 'This is the TEST plugin responding to the PluginCollSettingsUpdateAction event.' );
    }

   
// }}}

    // PluginMsgSettings {{{
    /**
     * Event handler: Called as action just before updating plugin's messages settings.
     *
     * Use this to add notes/errors through {@link Plugin::msg()} or to process saved settings.
     *
     * @see PluginMsgSettingsUpdateAction()
     */
   
function PluginMsgSettingsUpdateAction()
    {
       
$this->msg( 'This is the TEST plugin responding to the PluginMsgSettingsUpdateAction event.' );
    }

   
// }}}

    // PluginEmailSettings {{{
    /**
     * Event handler: Called as action just before updating plugin's email campaign settings.
     *
     * Use this to add notes/errors through {@link Plugin::msg()} or to process saved settings.
     *
     * @see PluginEmailSettingsUpdateAction()
     */
   
function PluginEmailSettingsUpdateAction()
    {
       
$this->msg( 'This is the TEST plugin responding to the PluginEmailSettingsUpdateAction event.' );
    }

   
// }}}


    // User related events, including registration and login (procedure): {{{

    /**
     * Event handler: Called at the end of the login procedure, if the
     *                user is anonymous ({@link $current_User current User} NOT set).
     *
     * Use this for example to read some cookie and define further handling of
     * this visitor or force them to login, by {@link Plugin::msg() adding a message}
     * of class "login_error", which will trigger the login screen.
     * asimo> There is no message with "login_error" class anymore,
     * there is a $login_error global variable
     *
     * @see Plugin::AfterLoginAnonymousUser()
     */
   
function AfterLoginAnonymousUser( & $params )
    {
       
$this->msg( 'This is the TEST plugin responding to the AfterLoginAnonymousUser event.' );
    }


   
/**
     * Event handler: Called at the end of the login procedure, if the
     *                {@link $current_User current User} is set and the
     *                user is therefor registered.
     *
     * Use this for example to re-act on specific {@link Plugin::$UserSettings user settings},
     * e.g., call {@link Plugin::forget_events()} to de-activate the plugin for
     * the current request.
     *
     * You can also {@link Plugin::msg() add a message} of class "login_error"
     * to prevent the user from accessing the site and triggering
     * the login screen.
     * asimo> There is no message with "login_error" class anymore,
     * there is a $login_error global variable
     *
     * @see Plugin::AfterLoginRegisteredUser()
     */
   
function AfterLoginRegisteredUser( & $params )
    {
       
$this->msg( 'This is the TEST plugin responding to the AfterLoginRegisteredUser event.' );
    }


   
/**
     * Event handler: Called when a new user has registered, at the end of the
     *                DB transaction that created this user.
     *
     * If you want to modify the about-to-be-created user (if the transaction gets
     * committed), you'll have to call {@link User::dbupdate()} on it, because he
     * got already inserted (but the transaction is not yet committed).
     *
     * Note: if you want to re-act on a new user,
     * use {@link Plugin::AfterUserRegistration()} instead!
     *
     * @see Plugin::AppendUserRegistrTransact()
     * @param array Associative array of parameters
     *   - 'User': the {@link User user object} (as reference).
     * @return boolean false if the whole transaction should get rolled back (the user does not get created).
     */
   
function AppendUserRegistrTransact( & $params )
    {
       
$this->msg( 'This is the TEST plugin responding to the AppendUserRegistrTransact event.' );

        return
true;
    }


   
/**
     * Event handler: Called when a new user has registered and got created.
     *
     * Note: if you want to modify a new user,
     * use {@link Plugin::AppendUserRegistrTransact()} instead!
     *
     * @see Plugin::AfterUserRegistration()
     * @param array Associative array of parameters
     *   - 'User': the {@link User user object} (as reference).
     */
   
function AfterUserRegistration( & $params )
    {
       
$this->msg( 'This is the TEST plugin responding to the AfterUserRegistration event.' );
    }


   
/**
     * Event handler: Called at the begining of the "Register as new user" form.
     *
     * You might want to use this to inject antispam payload to use
     * in {@link Plugin::RegisterFormSent()}.
     *
     * @see Plugin::DisplayRegisterFormBefore()
     * @param array Associative array of parameters
     *   - 'Form': the comment form generating object (by reference)
     *   - 'inskin': boolean true if the form is displayed in skin
     */
   
function DisplayRegisterFormBefore( & $params )
    {
       
$this->msg( 'This is the TEST plugin responding to the DisplayRegisterFormBefore event.' );
    }


   
/**
     * Event handler: Called at the end of the "Register as new user" form.
     *
     * You might want to use this to inject antispam payload to use
     * in {@link Plugin::RegisterFormSent()}.
     *
     * @see Plugin::DisplayRegisterFormFieldset()
     * @param array Associative array of parameters
     *   - 'Form': the comment form generating object (by reference)
     *   - 'inskin': boolean true if the form is displayed in skin
     */
   
function DisplayRegisterFormFieldset( & $params )
    {
       
$params['Form']->begin_fieldset( 'TEST plugin' );
       
$params['Form']->info_field( 'TEST plugin', 'This is the TEST plugin responding to the DisplayRegisterFormFieldset event.' );
       
$params['Form']->end_fieldset( 'Foo' );

        return
true;
    }


   
/**
     * Event handler: Called when a "Register as new user" form has been submitted.
     *
     * You can cancel the registration process by {@link Plugin::msg() adding a message}
     * of type "error".
     *
     * @see Plugin::RegisterFormSent()
     * @param array Associative array of parameters
     *   - 'login': Login name (by reference) (since 1.10.0)
     *   - 'email': E-Mail value (by reference) (since 1.10.0)
     *   - 'locale': Locale value (by reference) (since 1.10.0)
     *   - 'pass1': Password (by reference) (since 1.10.0)
     *   - 'pass2': Confirmed password (by reference) (since 1.10.0)
     */
   
function RegisterFormSent( & $params )
    {
       
$this->msg( 'This is the TEST plugin responding to the RegisterFormSent event.' );
    }


   
/**
     * Event handler: Called at the end of the "Login" form.
     *
     * You might want to use this to inject payload to use
     * in {@link LoginAttempt()}.
     *
     * @see Plugin::DisplayLoginFormFieldset()
     * @param array Associative array of parameters
     *   - 'Form': the comment form generating object (by reference)
     */
   
function DisplayLoginFormFieldset( & $params )
    {
       
$params['Form']->info_field( 'TEST plugin', 'This is the TEST plugin hooking the DisplayLoginFormFieldset event.' );
    }


   
/**
     * Event handler: called when a user attemps to login.
     *
     * You can prevent the user from logging in by {@link Plugin::msg() adding a message}
     * of type "login_error".
     *
     * Otherwise, this hook is meant to authenticate a user against some
     * external database (e.g. LDAP) and generate a new user.
     *
     * To check, if a user already exists in b2evo with that login/password, you might
     * want to use <code>user_pass_ok( $login, $pass_md5, true )</code>.
     *
     * NOTE: if 'pass_hashed' is not empty, you won't receive the password in clear-type. It
     *       has been hashed using client-side Javascript.
     *       SHA1( MD5($params['pass']).$params['pass_salt'] ) should result in $params['pass_hashed']!
     *       If you need the raw password, see {@link LoginAttemptNeedsRawPassword()}.
     *
     * @see Plugin::LoginAttempt()
     * @param array Associative array of parameters
     *   - 'login': user's login (by reference since 1.10.0)
     *   - 'pass': user's password (by reference since 1.10.0)
     *   - 'pass_md5': user's md5 password (by reference since 1.10.0)
     *   - 'pass_salt': the salt used in "pass_hashed" (by reference)
     *   - 'pass_hashed': if non-empty this is the users passwords hashed. See note above. (by reference)
     *   - 'pass_ok': is the password ok for 'login'? (by reference) (since 1.10.0)
     */
   
function LoginAttempt( & $params )
    {
       
$this->msg( 'This is the TEST plugin responding to the LoginAttempt event.', 'note' );
    }


   
/**
     * Event handler: your Plugin should return true here, if it needs a raw (un-hashed)
     * password for the {@link Plugin::LoginAttempt()} event. If any Plugin returns true
     * for this event, client-side hashing of the password is not used.
     * NOTE: this causes passwords to travel un-encrypted, unless SSL/HTTPS get used.
     *
     * @see Plugin::LoginAttemptNeedsRawPassword()
     * @return boolean True, if you need the raw password.
     */
   
function LoginAttemptNeedsRawPassword()
    {
        return
false;
    }


   
/**
     * Event handler: called when a user logs out.
     *
     * This is meant to cleanup data, e.g. if you use the
     * {@link Plugin::AlternateAuthentication()} hook.
     *
     * @see Plugin::Logout()
     * @param array Associative array of parameters
     *   - 'User': the user object
     */
   
function Logout( $params )
    {
       
$this->msg( 'This is the TEST plugin responding to the Logout event.' );
    }


   
/**
     * Event handler: Called at the end of the "Validate user account" form, which gets
     *                invoked if newusers_mustvalidate is enabled and the user has not
     *                been validated yet.
     *
     * The corresponding action event is {@link Plugin::ValidateAccountFormSent()}.
     *
     * @see Plugin::DisplayValidateAccountFormFieldset()
     * @param array Associative array of parameters
     *   - 'Form': the comment form generating object (by reference)
     */
   
function DisplayValidateAccountFormFieldset( & $params )
    {
       
$params['Form']->info( 'TEST plugin', 'This is the TEST plugin responding to the ValidateAccountFormSent event.' );
    }


   
/**
     * Event handler: Called when a "Validate user account" form has been submitted.
     *
     * You can cancel the registration process by {@link Plugin::msg() adding a message}
     * of type "error".
     *
     * @see Plugin::ValidateAccountFormSent()
     */
   
function ValidateAccountFormSent( & $params )
    {
       
$this->msg( 'This is the TEST plugin responding to the ValidateAccountFormSent event.' );
    }


   
/**
     * Event handler: Called at the end of the "User profile" form.
     *
     * The corresponding action event is {@link Plugin::ProfileFormSent()}.
     *
     * @see Plugin::DisplayProfileFormFieldset()
     * @param array Associative array of parameters
     *   - 'Form': the user profile form generating object (by reference)
     *   - 'User': the edited user object (by reference)
     *   - 'edit_layout':
     *            "public" - public front-office user profile form (info only),
     *            "private" - private front-office user profile form (editable),
     *   - 'is_admin_page': (boolean) indicates whether we are in front-office or backoffice
     */
   
function DisplayProfileFormFieldset( & $params )
    {
        if(
$params['edit_layout'] == 'public' )
        {
// Do nothing in public mode
           
return false;
        }

       
$params['Form']->info( 'TEST plugin', 'This is the TEST plugin responding to the DisplayProfileFormFieldset event.' );
    }


   
/**
     * Event handler: Called before at the beginning, if a profile form gets sent (and received).
     *
     * Use this to filter input
     *
     * @see Plugin::ProfileFormSent()
     * @param array Associative array of parameters
     *   - 'User': edited {@link User} object (by reference)
     *   - 'newuser_firstname': firstname (by reference)
     *   - 'newuser_lastname': lastname (by reference)
     *   - 'newuser_nickname': nickname (by reference)
     *   - 'newuser_locale': locale (by reference)
     *   - 'newuser_url': URL (by reference)
     *   - 'newuser_email': email (by reference)
     *   - 'newuser_allow_msgform': "message form" status (by reference)
     *   - 'newuser_notify': "notifications" status (by reference)
     *   - 'newuser_showonline': "show online" status (by reference)
     *   - 'newuser_gender': gender (by reference)
     *   - 'pass1': pass1 (by reference)
     *   - 'pass2': pass2 (by reference)
     */
   
function ProfileFormSent( & $params )
    {
       
$this->msg( 'This is the TEST plugin responding to the ProfileFormSent event.' );
    }


   
/**
     * Event handler: called at the end of the login process, if the user did not try to
     *                login (by sending "login" and "pwd"), the session has no user attached
     *                or only "login" is given.
     *
     * This hook is meant to automagically login/authenticate an user by his/her IP address,
     * special cookie, etc..
     *
     * If you can authenticate the user, you'll have to attach him to the {@link $Session},
     * either through {@link Session::set_user_ID()} or {@link Session::set_User()}.
     *
     * @see Plugin::AlternateAuthentication()
     * @return boolean True, if the user has been authentificated (set in $Session)
     */
   
function AlternateAuthentication( & $params )
    {
        if(
0 ) // you should only enable it for test purposes, because it automagically logs every user in as "demouser"!
       
{
            global
$Session, $Messages;

           
$UserCache = & get_UserCache();
            if(
$demo_User = & $UserCache->get_by_login('demouser') )
            {
// demouser exists:
               
$Session->set_User( $demo_User );
               
$Messages->add( 'Logged in as demouser.', 'success' );
                return
true;
            }
        }
    }


   
/**
     * Event handler: called at the end of {@link User::dbupdate() updating
     * an user account in the database}, which means that it has been changed.
     *
     * @see Plugin::AfterUserUpdate()
     * @since 1.8.1
     * @param array Associative array of parameters
     *   - 'User': the related User (by reference)
     */
   
function AfterUserUpdate( & $params )
    {
       
$this->msg( 'This is the TEST plugin responding to the AfterUserUpdate event.' );
    }


   
/**
     * Event handler: called at the end of {@link User::dbinsert() inserting
     * an user account into the database}, which means it has been created.
     *
     * @see Plugin::AfterUserInsert()
     * @since 1.8.1
     * @param array Associative array of parameters
     *   - 'User': the related User (by reference)
     */
   
function AfterUserInsert( & $params )
    {
       
$this->msg( 'This is the TEST plugin responding to the AfterUserInsert event.' );
    }


   
/**
     * Event handler: called at the end of {@link User::dbdelete() deleting
     * an user from the database}.
     *
     * @see Plugin::AfterUserDelete()
     * @since 1.8.1
     * @param array Associative array of parameters
     *   - 'User': the related User (by reference)
     */
   
function AfterUserDelete( & $params )
    {
       
$this->msg( 'This is the TEST plugin responding to the AfterUserDelete event.' );
    }

   
// }}}


    // General events: {{{

    /**
     * Event handler: Return data to display captcha html code
     *
     * @param array Associative array of parameters:
     *   - 'Form':          Form object
     *   - 'form_type':     Form type
     *   - 'form_position': Current form position where this event is called
     *   - 'captcha_info':  Default captcha info text(can be changed by this plugin)
     *   - 'captcha_template_question': Default HTML template for question text = '<span class="evo_captcha_question">$captcha_question$</span><br>'
     *   - 'captcha_template_answer':   Default HTML template for answer field = '<span class="evo_captcha_answer">$captcha_answer$</span><br>'
     * @return array Associative array of parameters:
     *   - 'captcha_position': Captcha position where current plugin must be displayed for the requested form type
     *   - 'captcha_html':     Captcha html code
     *   - 'captcha_info':     Captcha info text
     */
   
function RequestCaptcha( & $params )
    {
        if( ! isset(
$params['form_type'] ) || $params['form_type'] != 'comment' )
        {    
// Apply captcha only for comment form:
           
return false;
        }

       
// Get current or new question:
       
$question = $this->get_captcha_question();

        if( empty(
$question ) )
        {    
// No question detected:
           
return false;
        }

       
// Question text:
       
$captcha_html = str_replace( '$captcha_question$', $question['question'], $params['captcha_template_question'] );
       
// Answer input field:
       
$captcha_field_params = array(
               
'type'     => 'text',
               
'name'     => 'captcha_'.$this->code.'_'.$this->ID.'_answer',
               
'value'    => param( 'captcha_'.$this->code.'_'.$this->ID.'_answer', 'string', '' ),
               
'size'     => 10,
               
'required' => true,
               
'class'    => 'form_text_input form-control',
            );
       
$Form = & $params['Form'];
       
$captcha_html .= str_replace( '$captcha_answer$', $Form->get_input_element( $captcha_field_params ), $params['captcha_template_answer'] );

        return array(
               
'captcha_position' => 'before_submit_button',
               
'captcha_html'     => $captcha_html,
               
'captcha_info'     => $params['captcha_info'],
            );
    }


   
/**
     * Event handler: general event to validate a captcha which payload was added
     * through {@link RequestCaptcha()}.
     *
     * NOTE: if the action is verified/completed in total, you HAVE to cleanup its data
     *       and is not vulnerable against multiple usage of the same captcha!
     *
     * @param array Associative array of parameters
     * @return boolean true if the catcha could be validated
     */
   
function ValidateCaptcha( & $params )
    {
        if( ! empty(
$params['is_preview'] ) || ! isset( $params['form_type'] ) || $params['form_type'] != 'comment' )
        {    
// We should not apply captcha to the requested form:
           
return true;
        }

       
$posted_answer = utf8_strtolower( param( 'captcha_'.$this->code.'_'.$this->ID.'_answer', 'string', '' ) );

        if( empty(
$posted_answer ) )
        {
           
$this->debug_log( 'captcha_'.$this->code.'_'.$this->ID.'_answer' );
           
param_error( 'captcha_'.$this->code.'_'.$this->ID.'_answer', 'Please enter TEST captcha answer.' );
            if(
$comment_Item = & $params['Comment']->get_Item() )
            {
               
syslog_insert( 'Comment TEST captcha answer is not entered', 'warning', 'item', $comment_Item->ID, 'plugin', $this->ID );
            }
            return
false;
        }

       
// Get current question:
       
$current_question = $this->get_captcha_question();

        if(
$posted_answer != utf8_strtolower( $current_question['answer'] ) )
        {    
// Wrong answer:
           
$this->debug_log( 'Posted ('.$posted_answer.') and answer "test" do not match!' );
           
param_error( 'captcha_'.$this->code.'_'.$this->ID.'_answer', 'The entered TEST answer is incorrect.' );
            if(
$comment_Item = & $params['Comment']->get_Item() )
            {
               
syslog_insert( 'Comment TEST captcha answer is incorrect', 'warning', 'item', $comment_Item->ID, 'plugin', $this->ID );
            }
            return
false;
        }

       
// If answer is correct:
        //   We should clean the question ID that was assigned for current session and IP address
        //   It gives to assign new question on the next captcha event
       
global $Session;
       
$Session->delete( 'captcha_'.$this->code.'_'.$this->ID );

        return
true;
    }


   
/**
     * Event handler: called at the end of {@link DataObject::dbinsert() inserting an object in the database}.
     *
     * @see Plugin::AfterObjectInsert()
     * @param array Associative array of parameters
     *   - 'Object': the related Object (by reference)
     *   - 'type': class name of deleted Object (Chapter, File, Blog, Link, Comment, Slug etc.) (by reference)
     */
   
function AfterObjectInsert( & $params )
    {
       
$this->msg( sprintf('This is the TEST plugin responding to the AfterObjectInsert event. You have just created new [%s]', $params['type']), 'note' );
    }


   
/**
     * Event handler: called at the end of {@link DataObject::dbupdate() updating an object in the database}.
     *
     * @see Plugin::AfterObjectUpdate()
     * @param array Associative array of parameters
     *   - 'Object': the related Object (by reference)
     *   - 'type': class name of deleted Object (Chapter, File, Blog, Link, Comment, Slug etc.) (by reference)
     */
   
function AfterObjectUpdate( & $params )
    {
       
$this->msg( sprintf('This is the TEST plugin responding to the AfterObjectUpdate event. You have just changed a [%s]', $params['type']), 'note' );
    }


   
/**
     * Event handler: called at the end of {@link DataObject::dbdelete() deleting an object from the database}.
     *
     * @see Plugin::AfterObjectDelete()
     * @param array Associative array of parameters
     *   - 'Object': the related Object (by reference)
     *   - 'type': class name of deleted Object (Chapter, File, Blog, Link, Comment, Slug etc.) (by reference)
     */
   
function AfterObjectDelete( & $params )
    {
       
$this->msg( sprintf('This is the TEST plugin responding to the AfterObjectDelete event. You have just deleted a [%s]', $params['type']), 'note' );
    }
   
// }}}


    /**
     * Event handler: Called when an IP address gets displayed, typically in a protected
     * area or for a privileged user, e.g. in the backoffice statistics menu.
     *
     * @see Plugin::FilterIpAddress()
     * @param array Associative array of parameters
     *   - 'data': the data (by reference). You probably want to modify this.
     *   - 'format': see {@link format_to_output()}.
     * @return boolean Have we changed something?
     */
   
function FilterIpAddress( & $params )
    {
       
$params['data'] = '[[IP:'.$params['data'].' (TEST plugin)]]';

        return
true;
    }


   
/**
     * Event handler: Called after initializing plugins, DB, Settings, Hit, .. but
     * quite early.
     *
     * This is meant to be a good point for Antispam plugins to cancel the request.
     *
     * @see Plugin::SessionLoaded()
     */
   
function SessionLoaded()
    {
       
$this->msg( 'This is the TEST plugin responding to the SessionLoaded event.' );
    }


   
/**
     * Event handler: Called right after initializing plugins. This is the earliest event you can use.
     *
     * This is meant to be a good point for doing early processing and cancelling the request.
     * Note that at this point DB charset is not set, Session and Hit aren't initialized
     *
     * @see Plugin::AfterPluginsInit()
     */
   
function AfterPluginsInit()
    {
       
$this->msg( 'This is the TEST plugin responding to the AfterPluginsInit event.' );
    }


   
/**
     * Event handler: Called at the end of _main.inc.php. This is the the latest event called before blog initialization.
     *
     * This is meant to be a good point for doing processing that don't require a blog to be initialized.
     *
     * @see Plugin::AfterMainInit()
     */
   
function AfterMainInit()
    {
       
$this->msg( 'This is the TEST plugin responding to the AfterMainInit event.' );
    }


   
/**
     * Event handler: Called before pruning sessions. The plugin can prevent deletion
     * of particular sessions, by returning their IDs.
     *
     * Note: There can be hundreds of thousands of sessions about to be deleted.
     * Any plugin making use of this may have serious performance/memory issues.
     *
     * fp> TODO: maybe we should pass the prune cut off date instead.
     * What's a use case for this?
     *
     * @see Plugin::BeforeSessionsDelete()
     * @param array Associative array of parameters
     *   - 'IDs': list of session IDs that are about to get deleted (WARNING: potentially huge)
     * @return array List of IDs that should not get deleted
     */
   
function BeforeSessionsDelete( & $params )
    {
       
$this->debug_log('BeforeSessionsDelete: Could have prevented the deletion of all sessions older than ' ).date('Y-m-d H:i:s', $params['cutoff_timestamp' ] );
        return array();
    }


   
/**
     * Event handler: Called when a hit gets logged, but before it gets recorded.
     *
     * @see Plugin::AppendHitLog()
     * @param array Associative array of parameters
     *   - 'Hit': The "Hit" object (by reference).
     *
     * @return boolean True if you've handled the recording of the hit, false otherwise.
     */
   
function AppendHitLog( & $params )
    {
       
$this->msg( 'This is the TEST plugin responding to the AppendHitLog event.' );

       
// Do nothing by default:
       
return false;
    }


   
/**
     * Event handler: Called before an uploaded file gets saved on server.
     *
     * @see Plugin::AfterFileUpload()
     * @param array Associative array of parameters
     *   - 'File': The "File" object (by reference).
     *   - 'name': file name (by reference).
     *   - 'type': file mimetype (by reference).
     *   - 'tmp_name': file location (by reference).
     *   - 'size': file size in bytes  (by reference).
     *
     * @return boolean 'false' to abort file upload, otherwise return 'true'
     */
   
function AfterFileUpload( & $params )
    {
       
$this->msg( 'This is the TEST plugin responding to the AfterFileUpload event.' );
        return array();
// Do nothing by default:
   
}


   
/**
     * This method should return a string that used as suffix
     *   for the field 'From Country' on the user profile page in the BackOffice
     *
     * @see Plugin::GetUserFromCountrySuffix()
     * @param array Associative array of parameters
     *   - 'User': the related User (by reference)
     * @return string Field suffix
     */
   
function GetUserFromCountrySuffix( & $params )
    {
        return
'Test plugin event "GetUserFromCountrySuffix"';
    }


   
/**
     * This method initializes an array that used as additional columns
     *   for the results table in the BackOffice
     *
     * @see Plugin::GetAdditionalColumnsTable()
     * @param array Associative array of parameters
     *   'table'   - Special name that used to know what plugin must use current table
     *   'column'  - DB field which contains IP address
     *   'Results' - Object
     */
   
function GetAdditionalColumnsTable( & $params  )
    {
       
$params = array_merge( array(
               
'table'   => '', // sessions, activity, ipranges
               
'column'  => '', // sess_ipaddress, comment_author_IP, aipr_IPv4start, hit_remote_addr
               
'Results' => NULL, // object Results
           
), $params );

        if(
is_null( $params['Results'] ) || !is_object( $params['Results'] ) )
        {    
// Results must be object
           
return;
        }

        if(
in_array( $params['table'], array( 'sessions', 'activity', 'ipranges', 'top_ips' ) ) )
        {    
// Display column only for required tables by Test plugin:
           
$column = array(
               
'th' => 'TEST Column',
               
'td' => 'TEST Value',
            );
           
$params['Results']->cols[] = $column;
        }
    }


   
////////// Custom plugin methods - START //////////


    /**
     * Assign config questions
     *
     * @return array Questions array
     */
   
function get_captcha_questions()
    {
        return array(
               
'1' => array( 'question' => 'Question 1?', 'answer' => 'Answer 1' ),
               
'2' => array( 'question' => 'Question 2?', 'answer' => 'Answer 2' ),
            );
    }

   
/**
     * Get question for current session
     *
     * @return array Question data from plugin config
     */
   
function get_captcha_question()
    {
        global
$Session;

       
$question = NULL;

       
// Get question ID from Session:
       
$this->question_ID = $Session->get( 'captcha_'.$this->code.'_'.$this->ID );

        if( empty(
$this->question_ID ) )
        {    
// Assign new random question for current Session:
           
$question = $this->get_new_captcha_question();
        }

        if( empty(
$question ) && ! empty( $this->question_ID ) )
        {    
// Get question data:
           
$questions = $this->get_captcha_questions();
            if( isset(
$questions[ $this->question_ID ] ) )
            {
               
$question = $questions[ $this->question_ID ];
            }

            if( empty(
$question ) )
            {    
// Assign random question if previous question doesn't exist in config:
                // This case may happens when admin changed the questions but user has the old question ID in the session
               
$question = $this->get_new_captcha_question();
            }
        }

        return
$question;
    }


   
/**
     * Assign new random question for current session
     *
     * @return array Question data with keys 'question' and 'answer'
     */
   
function get_new_captcha_question()
    {
        global
$Session;

       
$questions = $this->get_captcha_questions();

       
// Get random question:
       
$this->question_index = rand( 1, count( $questions ) );

       
// Save the assigned question index in the session:
       
$Session->set( 'captcha_'.$this->code.'_'.$this->ID, $this->question_index );
       
$Session->dbsave();

        return
$questions[ $this->question_index ];
    }


   
////////// Custom plugin methods - END //////////
}

?>