views:

2897

answers:

7

Is there a way to check if jQuery is loaded using PHP?

I have two different plugins in Joomla that load the jQuery JS, but when it is included more than once it does not work correctly.

To explain the process a bit more: Joomla offers an ability to intercept the HTML source before it is rendered, essentially working on the source code itself.

This is using the function:

onPrepareContent(&$row, &$params, $limitstart)

$row is the HTML content of the page that can be parsed.

I was thinking that maybe a preg_match could work but don't have very much experience with it.

+2  A: 

PHP is processed long before jQuery is loaded. The server processes the output that is sent to the client computer where it's loaded, along with jQuery. You should load the jQuery library into your site's template rather than in each module.

Jonathan Sampson
As much as that sounds great in theory, it does not work in the aspect of extending the functionality of a Joomla website that does not already have jQuery included in the template
privateace
+1  A: 

Should first make the check in javascript. for example:

window.onload = function()
{
   if (typeof(window.jQuery)=="undefined")
      alert('jQuery no load');
   else
      alert('jQuery Ok');
}

then, you could send a message by ajax to the server.

andres descalzo
A: 

Unless Joomla provides a way of telling you which scripts it is including? (Zend Framework has such a list)

jeef3
+1  A: 

That's not possible. PHP is server-side, while Javascript (the language JQuery is written in) is client-side. PHP code inherently has to run before the text that includes the Javascript even be sent to the user and attempted to be loaded.

Your best bet is to not include jQuery more than once. You could do this by replacing all of your includes with something like:

<script type='text/javascript'>
    if($) { } // test to see if the jQuery function is defined
    else document.write("<script type='text/javascript' src='jquery.js'></script>");
</script>

Admittedly this is a bit of a hack, and there might be a better way.

EDIT: After a bit of thought: this may not even work because of the asynchronicity of loading the jQuery library from the server. It seems like the best way to do this would be with an onload event handler attached to the script include, but the DOM doesn't support that.

EDIT 2: Okay, now I think that your best bet would be to simply include it once in the page using only one script tag per-page. You could do this by adding it to a global header of some sort and then removing it everywhere else. Then, no matter what, don't include it again. This might mean that you load it on some pages that don't need it, but due to cache on modern browsers it shouldn't be a problem.

Imagist
+1  A: 

I'm assuming you're using Joomla1.0?

Joomla buffers content using the PHP output buffer. ie: ob_start().

You can get the contents using: ob_get_contents();

Thus you can have a regular expression that checks for JQuery. Something like:

$jquery_loaded = preg_match("/<script.*?src=[\"']jquery[^\"']\"/i", ob_get_contents());

should be good enough. (I haven't tested that).

Using ob_get_contents() may not work in situations since the PHP output buffer can be nested. You can start as many buffers within buffers.

For Joomla1.5, you can get the buffer via the API which ensures you're always getting Joomla output.

$Document =& JFactory::getDocument();
$buffer = $Document->getBuffer();

Whether Joomla1.0 or 1.5 you have to note that Joomla can add to the buffer at any point before it renders the output (calls ob_flush() or equivalent). Thus your check for JQuery has to take into account that JQuery can be loaded after the check.

Note that Joomla buffer is created not only for HTML, but can be CSS, JavaScript, XML, JSON etc. So you might want to check for HTML before doing your JQuery tests. You can also test for the admin panel.

$mainframe =& JFactory::getApplication();
$doctype    = $document->getType();

     // deactivate for backend
     if ($mainframe->isAdmin() || $doctype != 'html') {
      return false;
     }


For reference here is an example system plugin that partly does the things you want. It is a compatibility plugin for MooTools1.2.

<?php
/**
 * MooTools1.2 w/ 1.1 compat for AjaxChat
 * @copyright www.fijiwebdesign.com
 * @author [email protected]
 * @license http://www.gnu.org/copyleft/gpl.html GNU/GPL
 */

// included only
defined( '_JEXEC' ) or die( 'Direct Access to this location is not allowed!' );

jimport( 'joomla.plugin.plugin' );

/**
 * Joomla PHP Speedy Integration
 *
 * @author [email protected]
 */
class  plgSystemAjaxchat extends JPlugin
{
    /**
     * Constructor
     *
     * For php4 compatability we must not use the __constructor as a constructor for plugins
     * because func_get_args ( void ) returns a copy of all passed arguments NOT references.
     * This causes problems with cross-referencing necessary for the observer design pattern.
     *
     * @access protected
     * @param object $subject The object to observe
     * @param  array  $config  An array that holds the plugin configuration
     * @since 1.0
     */
    function plgSystemAjaxchat(& $subject, $config)
    {
     parent::__construct($subject, $config);

     $mainframe =& JFactory::getApplication();
     $document =& JFactory::getDocument();
     $doctype = $document->getType();

     // deactivate for backend
     if ($mainframe->isAdmin()) {
      return false;
     }

     // add mootools 1.2
     if ( $doctype == 'html' ) {
      $document->addScript('components/com_ajaxchat/js/mootools-1.2-core.js');
      $document->addScript('components/com_ajaxchat/js/mootools-1.2-more.js');
      $document->addScript('components/com_ajaxchat/js/mootools-1.2-core-compat.js');
      $document->addScript('components/com_ajaxchat/js/mootools-1.2-more-compat.js');
     }

    }

    /**
     * After Templte output is in buffer
     */
    function onAfterRender() {

     $mainframe =& JFactory::getApplication();
     $document =& JFactory::getDocument();
     $doctype = $document->getType();

     // deactivate for backend
     if ($mainframe->isAdmin()) {
      return false;
     }

     // Only render for HTML output
     if ( $doctype !== 'html' ) { 
      return; 
     }

     // get the output buffer
     $body = JResponse::getBody();

     // remove mootools if not needed
     if (stristr($body, 'mootools.js') || stristr($body, 'mootools-uncompressed.js')) {
      $body = preg_replace("/<script.*?mootools(-uncompressed)?\.js.*?<\/script>/i", '', $body);
     } else {
      $body = preg_replace("/<script.*?mootools-1\.2\-.*?\.js.*?<\/script>[\s\t\r\n]*/i", "\n", $body);
     }

     JResponse::setBody($body);
    }

}

?>
bucabay
+1  A: 

You might want to try using the JDocument object to get the headers, search for jQuery, then reset as necessary. The getHeadData() and setHeadData() methods should help you from there. You can get the current JDocument object with this code:

$document =& JFactory::getDocument();

You might also want to look at this response to a similar question: http://stackoverflow.com/questions/1329981/joomla-jquery-modules-conflicting/1333301#1333301

In that one, you're actually stripping out the redundant jQuery loads.

jlleblanc
+3  A: 

Better yet, you can verify it w/ Javascript and then add it to the head if missing.

   if (typeof jQuery == 'undefined') { 
   var head = document.getElementsByTagName("head")[0];
   script = document.createElement('script');
   script.id = 'jQuery';
   script.type = 'text/javascript';
   script.src = 'js/jquery.js';
   head.appendChild(script);

}

Renfro