[New Plugin] jQuery4CMSimple

Third Party Plugins to CMSimple - how to install, use and create plugins

Moderator: Tata

cmb
Posts: 13273
Joined: Tue Jun 21, 2011 11:04 am
Location: Mü-Sa, RLP, DE
Contact:

Re: [New Plugin] jQuery4CMSimple

Post by cmb » Thu Sep 01, 2011 10:46 am

Hello Holger,

I've just came across an issue with the jQuery4CMSimple documentation. The example code given in section "How to use" doesn't work. It mandatory to declare $plugin_cf as global, when jquery.inc.php is included from within a function. Typically this will be the case, as the plugin developer needs access the configuration, but perhaps it should be documented explicitly.

Christoph
Christoph M. Becker – Plugins for CMSimple_XH

Holger
Site Admin
Posts: 3101
Joined: Mon May 19, 2008 7:10 pm
Location: Hessen, Germany
Contact:

Re: [New Plugin] jQuery4CMSimple

Post by Holger » Thu Sep 01, 2011 11:40 am

Hello Christoph,
cmb wrote:The example code given in section "How to use" doesn't work.
Hmm, for me it's working...

That's the code we're speaking from:

Code: Select all

<?php

function myplugin(){
    global $pth; //be sure CMSimple variables are accessible in your function

    $jqerror = '';
    if(!file_exists($pth['folder']['plugins'].'jquery/jquery.inc.php')){
        $jqerror = '<div class="cmsimplecore_warning">'.
                   '<b>Ups!</b>'.tag('br').
                   'Plugin '.ucfirst(basename(dirname(__FILE__))).
                   ' requires jQuery4CMSimple - Plugin!'.tag('br').
                   'Please download and install jQuery4CMSimple'.tag('br').
                   'from <a href='.
                   '"http://cmsimple-xh.com/wiki/doku.php/plugins:jquery4cmsimple">'.
                   ' www.cmsimple-xh.com/wiki</a>.'.
                   '</div>';
        //drop the rest of the plugin-code
        return($jqerror);
    } else {
    //load include-file from jQuery-plugin
    //always use "include_once"!
    include_once($pth['folder']['plugins'].'jquery/jquery.inc.php'); 

    //include jQuery to the <head>
    include_jQuery();

    //include jQuery UI to the <head>, if you use it in your plugin
    include_jQueryUI();

    //....
    //your other code ...
    //....
    
    }
}

?>
cmb wrote:It mandatory to declare $plugin_cf as global, when jquery.inc.php is included from within a function.
Where?
The example code only needs $pth array from CMSimple.

If a developer needs other globals he should know which ones, or am I totally wrong here?

KR
Holger

cmb
Posts: 13273
Joined: Tue Jun 21, 2011 11:04 am
Location: Mü-Sa, RLP, DE
Contact:

Re: [New Plugin] jQuery4CMSimple

Post by cmb » Thu Sep 01, 2011 11:48 am

Hello Holger,

the problem is with jquery.inc.php. It includes jquery/config/config.php to have access to $plugin_cf['jquery']. That's indeed important, because it's needed in include_jQuery() and declared there as global. But if a developer includes jquery.inc.php from within a function, jquery/config/config.php will be included in the functions scope, and so the global declaration in include_jQuery() fails!

That means that

Code: Select all

<script type="text/javascript" src="./plugins/jquery/lib/jquery"></script>
will be included to the <head>. Note the missing jquery-1.6.1-min.js!

Christoph
Christoph M. Becker – Plugins for CMSimple_XH

Holger
Site Admin
Posts: 3101
Joined: Mon May 19, 2008 7:10 pm
Location: Hessen, Germany
Contact:

Re: [New Plugin] jQuery4CMSimple

Post by Holger » Thu Sep 01, 2011 7:29 pm

Hi Christoph!
cmb wrote:Hello Holger,

the problem is with jquery.inc.php. It includes jquery/config/config.php to have access to $plugin_cf['jquery']. That's indeed important, because it's needed in include_jQuery() and declared there as global.
Sorry but you're wrong here. The only reason why I've added

Code: Select all

//load plugin-configuration
require($pth['folder']['plugins'].'jquery/config/config.php'); 
to the include - file is for further/advanced usage (e.g. to make it available in code that runs before the pluginloader is called).
You can comment out this line and everything will work.
Function include_jQuery() can of course access $plugin_cf because that array was made accessible with

Code: Select all

global $plugin_cf; 
at the top of the function.
So it's available in include_jQuery() function, but not in the parent function myplugin(); ;) .

It's the same with $hjs and the new declared $jQueryPlugins array from function include_jQueryPlugin():
it's accessible within that function but not outside until you not make it accessible with "global" in e.g. your plugin-function.
cmb wrote:That means that

Code: Select all

<script type="text/javascript" src="./plugins/jquery/lib/jquery"></script>
will be included to the <head>. Note the missing jquery-1.6.1-min.js!
And this is IMO impossible too, if we say you're right, because the functions from the jQuery4CMSimple-Plugin are writing to $hjs, which isn't available in myplugin() too.

I've checked that more than one time, because I thought the same way like you.
So I've made again a little demo with three plugins.
Plug0 is only a index.php with the code from the documentation.
Plug1 is the same in a function plug1()
Plug2 is a copy of Plug1.

Here's a sample code of Plug1:

Code: Select all

<?php

function plug1(){
    global $pth; //be sure CMSimple variables are accessible in your function

    $jqerror ='';
    if(!file_exists($pth['folder']['plugins'].'jquery/jquery.inc.php')){
        $jqerror = '<div class="cmsimplecore_warning">'.
                   '<b>Ups!</b>'.tag('br').
                   'Plugin '.ucfirst(basename(dirname(__FILE__))).
                   ' requires jQuery4CMSimple - Plugin!'.tag('br').
                   'Please download and install jQuery4CMSimple'.tag('br').
                   'from <a href='.
                   '"http://cmsimple-xh.com/wiki/doku.php/plugins:jquery4cmsimple">'.
                   ' www.cmsimple-xh.com/wiki</a>.'.
                   '</div>';
        //drop the rest of the plugin-code
        return($jqerror);
    } else {
    //load inculde-file from jQuery-plugin
    //always use "include_once"!
    include_once($pth['folder']['plugins'].'jquery/jquery.inc.php'); 

    //include jQuery to the <head>
    include_jQuery();

    //include jQuery UI to the <head>, if you use it in your plugin
    include_jQueryUI();
    
    //include other jQuery plugins
    echo "<br>Plug1: <br>";
    include_jQueryPlugin('test1',$pth['folder']['plugins'].'plug1/libs/test1.js');

    //....
    //your other code ...
    //....
    
    }
}

?>
To show the contents of $jQueryPlugins, I've added a var_dump() to function include_jQueryPlugin():

Code: Select all

function include_jQueryPlugin($name='', $path='') {
    global $hjs, $jQueryPlugins;
    
    if(!isset($jQueryPlugins)) {
        $jQueryPlugins = array();
    }
    
    if(defined('JQUERY')) {
        if($name != '') {
            if(!file_exists($path)) {
                e('missing', 'file', $path);
                return;
            }
            $name = strtolower($name);
            if (!in_array($name, $jQueryPlugins)) {
                $hjs .= "\n".'<script type="text/javascript" src="'.$path.'"></script>';
                $jQueryPlugins[] .= $name;
                var_dump($jQueryPlugins);
            }
        }
    }
}
 
BTW: here's a little typo in the code: "$jQueryPlugins[] .= $name;" should be "$jQueryPlugins[] = $name;" but it works with the dot too

See it in action altogether here with preCall:
http://holgerirmler.de/jqtest/?jQuery-Tests
and here with classic CMSimple-Scripting:
http://holgerirmler.de/jqtest/?jQuery-Tests2

Have a look at the source to see that everything is ok.
I've checked that with CMSimple 3.3 and the pluginloader from the wiki with success too.

KR
Holger

cmb
Posts: 13273
Joined: Tue Jun 21, 2011 11:04 am
Location: Mü-Sa, RLP, DE
Contact:

Re: [New Plugin] jQuery4CMSimple

Post by cmb » Thu Sep 01, 2011 7:57 pm

Hello Holger,

thanks for your comprehensive answer. :) I have to check all the details later. But this afternoon I had the problem, that the filename of the jquery.js was not included to the <head> because bca included jquery.inc.php from a funtion without declaring $plugin_cf global. So, what happened:

1. his plugin (HandheldXH) was called first by the plugin loader (before the jquery plugin)
2. in index.php it globally included handheld.inc.php und called handheld()
3. handheld() included jquery.inc.php
4. jquery.inc.php required it's config.php globally (and defined some functions), so $plugin_cf got a local variable of handheld() :!:
5. handheld() called include_jQuery()
6. include_jQuery() declared $plugin_cf as global, but that was not read by the pluginloader, nor was it introduced to the global namespace by jquery.inc.php
7. include_jQuery() added the path to jquery.js to the head using global $plugin_cf['jquery']['file_core'], which was empty() at that time :(

Everything worked fine, after I declared $plugin_cf global in handheld(), because when (6) happens now, $plugin_cf is a global.

You might try HandheldXHbeta2 for yourself. Just put JS debugging on, and watch the HTML source. ;)

Christoph

PS: I've just checked your demo. Indeed that works, because $jQueryPlugins is always in the global namespace by declaration in include_jQueryPlugin. (BTW: the typo .= might trigger a notice). But the problem is with include/require:
php.net wrote: When a file is included, the code it contains inherits the variable scope of the line on which the include occurs.
...
If the include occurs inside a function within the calling file, then all of the code contained in the called file will behave as though it had been defined inside that function. So, it will follow the variable scope of that function.
PPS: I was just confused, because I'd included jquery.inc.php in Advancedform_XH from within a function without having $plugin_cf declared globally -- but it worked! But after I thought about it, I found, that it's no problem, if this inclusion is triggered by a plugin-call. The only problem is, when a plugin includes jquery.inc.php directly when it's included by the plugin loader, before the jquery plugin was included, and if the inclusion happens within a function without declaring $plugin_cf as global. This is indeed a very rare occasion ;)
Christoph M. Becker – Plugins for CMSimple_XH

Holger
Site Admin
Posts: 3101
Joined: Mon May 19, 2008 7:10 pm
Location: Hessen, Germany
Contact:

Re: [New Plugin] jQuery4CMSimple

Post by Holger » Thu Sep 01, 2011 8:42 pm

Hi Christoph,

now I've checked that Handheld-Plugin.
It's written in the "new coding style" to keep the index.php small....

And there is the problem:
jquery.inc.php is "the include" of the included handheld.inc.php which is included from handheld-index.php... and finally from the pluginloader.
Ok in this case (the include from the included include :roll: ) it is clear that $plugin_cf can't be available when it's not made accessible by the parent include.
If a author writes a code with such deep include-levels he should be familiar with the way how "globals" work.

Ok I can't see that huge parse-time-advantage by putting the whole plugin - functionality into an include-file, but when it's a "must be", I'll suggest to include
all the stuff at the same level in index.php of the plugin - to make the authors (and our) live easier ;) :
Handheld-Plugin - index.php:

Code: Select all

<?php
/**
 * Handheld CMSimple
 *
 * @author Brett Allen
 * @version 0.2 - 20-08-2011
  **/
/* utf8-marker = äöüß */

if($plugin_cf['handheld']['enable'] == "1"){
    //do some error-check if jQuery-plugin is available here
    include_once($pth['folder']['plugins'].'jquery/jquery.inc.php'); 
    //include jQuery to the <head>
    include_jQuery();
    include_once($pth['folder']['plugins'].'handheld/handheld.inc.php');
    handheld();
    include_handheld();
    
    $dest=$plugin_cf['handheld']['destination'];
    
    $hjs .= <<<SCRIPT
<script type="text/javascript">
/* <![CDATA[ */
if(jQuery.browser.mobile){window.location.replace('$dest');}
(jQuery);
/* ]]> */
</script>
SCRIPT;
}
?>
(tested and working)

So keep the include-levels as short as possible to prevent a mess with not accessible variables.

KR
Holger

Holger
Site Admin
Posts: 3101
Joined: Mon May 19, 2008 7:10 pm
Location: Hessen, Germany
Contact:

Re: [New Plugin] jQuery4CMSimple

Post by Holger » Thu Sep 01, 2011 9:05 pm

cmb wrote:The only problem is, when a plugin includes jquery.inc.php directly when it's included by the plugin loader, before the jquery plugin was included, and if the inclusion happens within a function without declaring $plugin_cf as global.
Sorry, again:
no!
Even in this case (see the demo with Plug0, which prints his output on every page) jquery.inc.php finds it's cf-array because of the declared require of it's config.php.
And, because it's done as "require", it will complete die with a blank page, when $pth - array isn't available too.
So a developer will notice that early ;) .
cmb wrote:(BTW: the typo .= might trigger a notice)
Hehe, I was wondering about that: it doesn't (in the demo is XHdebugmode on with level 6). So I think it's allowed :lol: and I'll add the names on right side of the array anyway ;) .

The problem with the handheld-plugin is the included included include - as written in your quote from php.net.

KR
Holger

cmb
Posts: 13273
Joined: Tue Jun 21, 2011 11:04 am
Location: Mü-Sa, RLP, DE
Contact:

Re: [New Plugin] jQuery4CMSimple

Post by cmb » Thu Sep 01, 2011 9:22 pm

Hello Holger,

thanks for having a further look at this issue and at HandheldXH. Well, you're absolutely right, that it's the best not to nest includes too deeply. IMO HandheldXH doesn't need another include file at all, because index.php would be small enough to not cause any noticeable overhead. But that's not the problem.

I've just written a plugin called "A". Just one file: index.php:

Code: Select all

<?php

function myplugin(){
    global $pth; //be sure CMSimple variables are accessible in your function

    $jqerror = '';
    if(!file_exists($pth['folder']['plugins'].'jquery/jquery.inc.php')){
        $jqerror = '<div class="cmsimplecore_warning">'.
                   '<b>Ups!</b>'.tag('br').
                   'Plugin '.ucfirst(basename(dirname(__FILE__))).
                   ' requires jQuery4CMSimple - Plugin!'.tag('br').
                   'Please download and install jQuery4CMSimple'.tag('br').
                   'from <a href='.
                   '"http://cmsimple-xh.com/wiki/doku.php/plugins:jquery4cmsimple">'.
                   ' www.cmsimple-xh.com/wiki</a>.'.
                   '</div>';
        //drop the rest of the plugin-code
        return($jqerror);
    } else {
    //load include-file from jQuery-plugin
    //always use "include_once"!
    include_once($pth['folder']['plugins'].'jquery/jquery.inc.php'); 

    //include jQuery to the <head>
    include_jQuery();

    //include jQuery UI to the <head>, if you use it in your plugin
    include_jQueryUI();

    //....
    //your other code ...
    //....
    
    }
}

myplugin();

?>
That's exactly the code from the documentation, with the call to myplugin() inserted globally. No deep nesting. After installing it, if I look at the HTML source code of a page of my CMSimple installation, it shows:

Code: Select all

<script type="text/javascript" src="./plugins/jquery/lib/jquery/"></script> 
Note the missing filename of jquery.js. Everything will be fine, if either the plugin would be included by the pluginloader after the jquery plugin, or I've added global $plugin_cf.

If the line

Code: Select all

require($pth['folder']['plugins'].'jquery/config/config.php');
 
would be missing from jquery.inc.php any plugin that directly calls include_jQuery() (instead of calling it through a plugin call/CMSimple script), will fail, if that plugin will be included before the jQuery plugin. This is due to the pluginloaders strategy to include all files of a plugin (index, admin, config, etc) instead of first including the configs of all plugins, and then the rest of the plugin files.

Christoph
Christoph M. Becker – Plugins for CMSimple_XH

cmb
Posts: 13273
Joined: Tue Jun 21, 2011 11:04 am
Location: Mü-Sa, RLP, DE
Contact:

Re: [New Plugin] jQuery4CMSimple

Post by cmb » Thu Sep 01, 2011 9:25 pm

Hello Holger,
Holger wrote: Even in this case (see the demo with Plug0, which prints his output on every page) jquery.inc.php finds it's cf-array because of the declared require of it's config.php.
Yes, you're right. jquery.inc.php will find it's $plugin_cf. But when it's included from within a function, $plugin_cf will be local to that function. So it will not be seen by include_jQuery().

Christoph
Christoph M. Becker – Plugins for CMSimple_XH

Holger
Site Admin
Posts: 3101
Joined: Mon May 19, 2008 7:10 pm
Location: Hessen, Germany
Contact:

Re: [New Plugin] jQuery4CMSimple

Post by Holger » Thu Sep 01, 2011 9:53 pm

Hmm, now I can't follow you :? :
cmb wrote:I'd included jquery.inc.php in Advancedform_XH from within a function without having $plugin_cf declared globally -- but it worked!
and
cmb wrote:when it's included from within a function, $plugin_cf will be local to that function. So it will not be seen by include_jQuery().
I think there's a general misunderstanding on how "global" works or between what "global" is doing or not doing (= the superglobals in PHP)...
The code

Code: Select all

function foo() {
    global $bar;
} 
will make $bar from the instance outside this function accessible inside function foo() and not the other way.

Holger

PS: again, IMO it's better to make things not more complicated than they are.
Where is the advantage to include jquery.inc.php inside another include and not in the plugins index.php?

Post Reply