jump to navigation

Cajax Component v2 May 7, 2006

Posted by rossoft in CakePHP.
trackback

First, some examples

<?php
echo $cajax->replace_html('div.mone','Changed by class.Hello world!<br/>Trying things');
echo $cajax->replace_html(array('#mas2','#otro'),'Changed by id');
echo $cajax->effect(array('#mas2','#otro'),'BlindDown',array('duration'=>1));
echo $cajax->effect('#hola','Highlight');
echo $cajax->effect('#mas2','Puff',array('duration'=>1));
//this will call the url "/pruebas/cajax_call" through ajax. it doesn't have the parameter array('update'=>'somediv'), then it will update a special hidden div created by cajax (useful if cajax_call only prints some javascript code like $cajax->replace_html(…)
echo $cajax->periodical_remote('/pruebas/cajax_call',2);
echo $cajax->toggle(array('#xxxx','.haa')); //two toggles for same element
echo $cajax->toggle('#xxxx');
echo $cajax->delay($cajax->toggle('#xxxx',false),10);

//Creation of proxy object
$mas3=$cajax->e(array('#mas3','#mas4'));
echo $mas3->effect('Fade',array('duration'=>2));

echo $cajax->delay(
//Passing proxy object to for_each
$cajax->for_each($mas3,'alert(_elem.innerHTML);',false)
,5);

echo $cajax->delay(
$cajax->e('.haa2')->effect('Appear',array(),false) //through proxy object
,8);

echo $cajax->delay(
$cajax->e('.haa2')->replace('<p>HI!</p>',false) //through proxy object
,15);

echo $mas3->for_each('_elem.innerHTML+="With for_each"');

 echo $cajax->e('#mas5')->replace_request_action('/sms/enviar');
 
 echo $cajax->e('#otro')->add_classname('x1');
        echo $cajax->e('#mas5')->replace_render_element('pruebas/cajax_test',array('var1'=>'testing'));
        echo $cajax->e('#otro')->remove_classname('x1');

?>

Installation.
1. You need OutputComponent, HeadHelper from this blog
2. dollar_e.js from http://ajaxian.com/archives/dollar-e-a-documentcreateelement-wrapper
3. Prototype >= 1.4.0
4. Copy the following to /app/controller/components/cajax.php

<?php
/**
 *
 * Cajax component
 * Some wrapper functions for prototype + scriptaculous
 * Requires Prototype >= 1.4.0
 *
 * @author      RosSoft
 * @version     0.21
 * @license         MIT
 *
 * @link http://api.rubyonrails.org/classes/ActionView/Helpers/PrototypeHelper/JavaScriptGenerator/GeneratorMethods.html
 * @link http://prototype.conio.net/
 * @link http://ajaxian.com/archives/dollar-e-a-documentcreateelement-wrapper
 *
 * In the API, a css selector can be a string or an array
 * of strings. The format of the string is a prototype css
 * selection.
 * Examples:
 * $css='.cl'   All the elements with class 'cl'
 * $css='#someid'   Element with id 'someid'
 * $css=array('#someid','.cl') All elements with class 'cl' union element with id 'someid'
 * $css='p.cl'  All the <p class="cl"> elements  
 */
 
     /**
      * The DOM ID of a hidden DIV that will
      * be created automatically. Useful when needed a div
      * for flushing javascript code on it.
      */
    define('CAJAX_CONTAINER','cajax_container');    
    class CajaxComponent extends Object
    {
        var $components=array    (
                                    'Output',
                                    'RequestHandler',
                                  );        
        var $helpers=    array    (    'Head',
                                    'Javascript',
                                    'Ajax',
                                );

        /**
         * If true, then all the calls will be attached to
         * an onload function
         */        
        var $enclose_onload=false;
       
        /**
         * Enable enclosing in <script> tags.
         * For enclosing, $enclose_enable and the parameter
         * $enclose of a call must be true both
         */
        var $enclose_enable=true;

       
        function startup(&$controller)
        {
               $this->controller =& $controller;
                          
            $this->_init_helpers();
            $this->Head->register_js('dollar_e');
           
            if (! $this->RequestHandler->isAjax())
            {    
                $this->Head->register_jsblock(                    
                    $this->on_load(
                            $this->new_element('document.body','div',CAJAX_CONTAINER,array(),false)
                            .
                            $this->e('#' . CAJAX_CONTAINER)->hide(false)
                            ,false)
                    );
            }                                    
            // For accessing the component from views (like helpers)
            $this->controller->set('cajax',$this);
        }
       
        /**
         * Creates instances of the helpers used
         */
        function _init_helpers()
        {
            $this->Output->startup($this->controller);
            foreach ($this->helpers as $h)
            {
                $this->{$h}=& $this->Output->returnHelper($h);        
            }
        }

        /**
         * Creates a new DOM element        
         * @param string $tag Type of tag (a,div,span…)
         * @param string $id DOM ID of the element
         * @param array $attr Attributes of the element
         * @param boolean $enclose Enclose the result in <SCRIPT> tags
         * @return string Javscript code
         */
        function new_element($parent,$tag,$id,$attr=array(),$enclose=true)
        {
            $element=array_merge(array('tag'=>$tag,'id'=>$id),$attr);
            $element=$this->Javascript->object($element);
            $js=$parent . '.appendChild($E(' . $element. '));';            
            return $this->_enclose($js,$enclose);
        }

        /**
         * Enclose or not the javascript code
         * @param string $jscode Javascript to be [not] enclosed
         * @param boolean $enclose
         * @return string
         */        
        function _enclose($jscode,$enclose)
        {
            if ($this->enclose_enable && $enclose)
            {
                if ($this->enclose_onload)
                {
                    $jscode=$this->on_load($jscode,false);
                }
                return $this->Javascript->codeBlock($jscode) . "\n";
            }
            else
            {
                return $jscode . "\n"; 
            }
        }
       
        /**
         * Replaces the inner HTML code of some objects
         * @param mixed $css CSS selector of the objects
         * @param string $content The content to be set
         * @param boolean $enclose
         * @return string
         */        
        function replace_html($css,$content,$enclose=true)
        {            
            $js= 'Element.update(_elem,unescape("' . $this->_js_string($content) . '"));';                        
            return $this->for_each($css,$js,$enclose);
           
        }
       
        /**
         * Replaces the inner HTML code of some objects with an element
         * @param mixed $css CSS selector of the objects
         * @param string $element The name of the element
         * @param string $params The params of the element
         * @param boolean $enclose
         * @return string
         */        
        function replace_render_element($css,$element,$params=array(),$enclose=true)
        {
            $content=$this->Output->returnElement($element,$params);
            return $this->replace_html($css,$content,$enclose);            
        }

        /**
         * Replaces the inner HTML code of some objects with a requestAction
         * @param mixed $css CSS selector of the objects
         * @param string $url RequestAction url
         * @param string $params Extra params to RequestAction
         * @param boolean $enclose
         * @return string
         *        
         */        
        function replace_request_action($css,$url,$params=array(),$enclose=true)
        {
            $params['return']=true;
            $content=$this->requestAction($url,$params);
            return $this->replace_html($css,$content,$enclose);        
        }        
       
        /**
         * Replaces the outer HTML code of some objects (replaces the entire object)
         * @param mixed $css CSS selector of the objects
         * @param string $content HTML tag and content to be set        
         * @param boolean $enclose
         * @return string
         */        
        function replace($css,$content,$enclose=true)
        {            
            $js= 'Element.replace(_elem,unescape("' . $this->_js_string($content) . '"));';            
            return $this->for_each($css,$js,$enclose);
        }
       

        /**
         * Returns a reference to javascripts elements
         * @param mixed $css CSS selector / array of selectors
         * @return string Javascript reference
         */        
        function _ref($css)
        {
            if (is_object($css) && strcasecmp(get_class($css),'CajaxProxy')==0)
            {
                /* The parameter is an instance of a cajax proxy
                    get real css selector from it */
                return $css->ref();
            }
            else
            {
                $js="$$('";
                if (is_array($css))
                {
                    $js.=implode("','",$css);
                }
                else
                {
                    $js.=$css;
                }
                $js.="')";        
                return $js;
            }
        }
       
        /**
         * Returns an javascript proxy object to the css selection
         * @param string $css CSS selection
         * @return object Proxy to the object
         */        
        function e($css)
        {
            return new CajaxProxy($this,$css); 
        }
       
        /**
         * Executes the effect to some elements that matches css selection
         * @param mixed $css CSS selection
         * @param string $effect The scriptaculous effect (Fade,Appear,…)   
         * @param boolean $enclose
         * @return string
         *
         * @link http://wiki.script.aculo.us/scriptaculous/show/CombinationEffectsDemo
         */                
        function effect($css,$effect,$params=array(),$enclose=true)
        {            
            $params=$this->Javascript->object($params);
            return $this->for_each($css,"new Effect.$effect(_elem,$params)",$enclose);        
        }

        /**
         * Executes the jscode for each element that matches
         * the css selection. The jscode is executed for each
         * element, the element is referenced by the variable '_elem'
         * @param mixed $css CSS selection
         * @param string $jscode The javascript code using _elem variable 
         * @param boolean $enclose
         * @return string
         */                
        function for_each($css,$jscode,$enclose=true)
        {
            $ref=$this->_ref($css);
            $js="$ref.each(function(_elem) { $jscode });";
            return $this->_enclose($js,$enclose);                        
        }
       
        /**
         * Safe javascript string.
         * Must be decoded with the js function 'unescape'
         * @param string PHP String
         * @return string Javascript-safe string.
         */
        function _js_string($string)
        {
            return rawurlencode(utf8_decode($string));            
        }

        /**
         * Attach an event to an element.
         *
         * @param mixed $css CSS selector to the element to be observed
         * @param string $event event to observe
         * @param string $jscode function to call
         * @param boolean $enclose
         * @return string
         */        
        function event($css, $event, $jscode,$enclose=true)
        {
            $js_event= "Event.observe(_elem, \"$event\", function(event){ $jscode }, false);";
            return $this->for_each($css,$js_event,$enclose);            
        }
       
        /**
         * Attaches an onload function
         * @param string $jscode Javascript code to be executed
         * @paran boolean $enclose
         * @return string
         */
        function on_load($jscode,$enclose=true)
        {
            //Not works with $this->event (I don't know a css selector for window)
            $js= "Event.observe(window, \"load\", function(){ $jscode }, false);";
            return $this->_enclose($js,$enclose);
        }    

        /**
         * Hides an element or an array of elements by css selector
         * @param mixed $css CSS selector
         * @return string
         */
        function hide($css,$enclose=true)
        {
            return $this->for_each($css,"Element.hide(_elem)",$enclose);
        }
       
        /**
         * Shows an element or an array of elements by css selector
         * @param mixed $css CSS Selector
         * @param boolean $enclose
         * @return string
         */
        function show($css,$enclose=true)
        {
            return $this->for_each($css,"Element.show(_elem)",$enclose);
        }
       
        /**
         * Removes an element or an array of elements by css selector
         * @param mixed $css Selector
         * @param boolean $enclose
         * @return string
         */
        function remove($css,$enclose=true)
        {
            return $this->for_each($css,"Element.remove(_elem)",$enclose);
        }            

        /**
         * Toggles the visibility of an element or an array of elements
         * @param mixed $id DOM ID of the object (or array of ids)
         * @param boolean $enclose
         * @return string
         */
        function toggle($css,$enclose=true)
        {
            return $this->for_each($css,"Element.toggle(_elem)",$enclose);        
        }
       
        /**
         * Javascript redirection to the given location
         * @param string $url
         * @param boolean $enclose
         * @return string
         */
        function redirect_to($url,$enclose=true)
        {
            $js="window.location.href='$url'";
            return $this->_enclose($url,$enclose);                    
        }
        /**
         * Periodically calls some javascript code
         * @param string $jscode Javascript to be called
         * @param integer $freq Seconds
         * @return string
         */        
        function periodical($jscode,$freq=10,$enclose=true)
        {            
            $js="new PeriodicalExecuter(function() { $jscode }, $freq)";
            return $this->_enclose($js,$enclose);            
        }
       
        /**
         * Periodically calls a remote url (useful for updating a div)
         * @param string $url Cakeway /controller/action
         * @param integer $freq Frequency in seconds
         * @param array $options @see AjaxHelper
         * @param boolean $enclose
         * @return string 
         */
        function periodical_remote($url,$freq=10,$options=array(),$enclose=true)
        {
            $options['url']=$url;
            if (!isset($options['update']))
            {
                $options['update']=CAJAX_CONTAINER;
            }            
            $js=$this->remote_function($options,false);
            return $this->periodical($js,$freq,$enclose);
        }
       
        /**
         * Calls a remote ajax function
         * @param array $options @see AjaxHelper
         * @param boolean $enclose
         * @retur string
         */        
        function remote_function($options=array(),$enclose=true)
        {
            $js=$this->Ajax->remoteFunction($options);
            return $this->_enclose($js,$enclose);
        }

        /**
         * Executes the jscode after the delay
         * @param string $jscode Javascript to be executed
         * @param integer $delay Delay time in seconds
         * @param boolean $enclose
         * @return string
         *
         */        
        function delay($jscode,$delay,$enclose=true)
        {
            $js="setTimeout(function() {\n$jscode\n}," . ($delay * 1000) . ');';
            return $this->_enclose($js,$enclose);
        }

        /**
         * Converts an array of args to a js-array of args
         * @param array $args
         * @return string
         */        
        function _call_args($args)
        {
            $arr=array();
            foreach ($args as $i)
            {
                $arr[]=$this->_object($i);    
            }            
            return implode(",",$arr);
        }           

        /**
         * Calls a js function with the given array of params
         * @param string $function Name of the function
         * @param array $args Array of params
         * @param boolean $enclose
         * @return string
         */        
        function call($function,$args,$enclose=true)
        {
            $js="$function(" . $this->_call_args($args). ")";
            return $this->_enclose($js,$enclose);
        }
       
        /**
         * Shows an alert box
         * @param string $message Message to be shown
         * @param boolean $enclose
         * @return string
         */        
        function alert($message,$enclose=true)
        {            
            return $this->call('alert',array($message),$enclose);
        }

        /**        
         * Returns a the js-string of a php variable
         * @param mixed $var
         * @return string
         */
        function _object($var)
        {
            if (is_object($var) && get_class($var)=='CajaxProxy')
            {
                return $var->js_object();
            }                     
            else if (is_array($var))
            {
                return $this->Javascript->object($var);
            }
            else
            {
                $var=$this->_js_string($var);
                return "'$var'";
            }            
        }        
       
        /**
         * Assigns a value to a js variable
         * @param string $variable name of the variable
         * @param string $value
         * @param boolean $enclose
         * @return string
         */
        function assign($variable,$value,$enclose=true)
        {
            $js="$variable=" . $this->_object($value);
            return $this->_enclose($js);
        }
       
        /**
         * Adds a CSS class to an element or an array of elements by css selector
         * @param string $css Selector
         * @param string $classname Class to be added
         * @param boolean $enclose
         * @return string
         * 
         */        
        function add_classname($css,$classname,$enclose=true)
        {
            return $this->for_each($css,"Element.addClassName(_elem,'$classname');",$enclose);
        }

        /**
         * Removes a CSS class to an element or an array of elements by css selector
         * @param string $css Selector
         * @param string $classname Class to be removed
         * @param boolean $enclose
         * @return string
         * 
         */        
        function remove_classname($css,$classname,$enclose=true)
        {
            return $this->for_each($css,"Element.removeClassName(_elem,'$classname');",$enclose);
        }                
       
                   
    }    
    
    ////////////////////////////////////////////////////////////
    /**
     * After creating an instance of it through
     * $obj=$cajax->e(css_selection),
     * you can call $obj->hide(), $obj->effect('Appear') ,etc.
     */        
    
    class CajaxProxy extends Object
    {
        /** css selector */
        var $_css;
       
        /**        
         * Reference to the Cajax instance
         */
        var $Cajax;        
        function ref()
        {
            return $this->Cajax->_ref($this->_css);
        }
       
        function add_classname($classname,$enclose=true)
        {
            return $this->Cajax->add_classname($this->_css,$classname,$enclose);
        }
       
        function remove_classname($classname,$enclose=true)
        {
            return $this->Cajax->remove_classname($this->_css,$classname,$enclose);
        }    

        /**
         * Constructor
         * @param object $Cajax Instance of CajaxComponent
         * @param string $css CSS Selector
         */        
        function __construct(&$Cajax,$css)
        {
            $this->Cajax =& $Cajax;
            $this->_css=$css;
        }    
       
        /**
         * Shows the object(s)
         * @param boolean $enclose
         *
         */
        function show($enclose=true)
        {            
            return $this->Cajax->show($this->_css,$enclose);
        }
       
        /**
         * Toggles the object(s)
         * @param boolean $enclose
         *
         */
        function toggle($enclose=true)
        {            
            return $this->Cajax->toggle($this->_css,$enclose);
        }    
           

        /**
         * Hides the object(s)
         * @param boolean $enclose
         *
         */
        function hide($enclose=true)
        {            
            return $this->Cajax->hide($this->_css,$enclose);
        }
       
       
        /**
         * Removes the object(s)
         * @param boolean $enclose
         *
         */
        function remove($enclose=true)
        {            
            return $this->Cajax->remove($this->_css,$enclose);
        }            

        /**        
         * Does an scriptaculous effect
         * @param string $effect Name of effect
         * @param array $params Array of parameters to the effect
         * @param boolean $enclose
         * @link http://wiki.script.aculo.us/scriptaculous/show/CombinationEffectsDemo
         */
        function effect($effect,$params=array(),$enclose=true)
        {
            return $this->Cajax->effect($this->_css,$effect,$params,$enclose);
        }
       
        /**
         * Replaces the HTML code
         * @param string $content The content to be set
         * @param boolean $enclose
         * @return string
         */

        function replace_html($content,$enclose=true)
        {
            return $this->Cajax->replace_html($this->_css,$content,$enclose);
        }
       
        /**
         * Attach an event to an element.
         *
         * @param string $event event to observe
         * @param string $jscode function to call
         * @param boolean $enclose
         * @return string
         */        
        function event($event, $jscode,$enclose=true)
        {
            return $this->Cajax->event($this->_css,$event,$jscode,$enclose);
        }

        /**
         * Executes the jscode for each element that matches
         * the css selection. The jscode is executed for each
         * element, the element is referenced by the variable '_elem'
         * @param string $jscode The javascript code using _elem variable 
         * @param boolean $enclose
         * @return string
         */                
        function for_each($jscode,$enclose=true)
        {
            return $this->Cajax->for_each($this->_css,$jscode,$enclose);            
        }
       
        /**
         * Replaces the outer HTML code of the objects (replaces the entire object)
         * @param string $content HTML tag and content to be set
         * @param boolean $enclose
         * @return string
         */        
        function replace($content,$enclose=true)
        {
            return $this->Cajax->replace($this->_css,$content,$enclose);
        }
       
        /**
         * Replaces the inner HTML code of some objects with an element
         * @param string $element The name of the element
         * @param string $params The params of the element
         * @param boolean $enclose
         * @return string
         */        
        function replace_render_element($element,$params=array(),$enclose=true)
        {
            return $this->Cajax->replace_render_element($this->_css,$element,$params,$enclose);
        }

        /**
         * Replaces the inner HTML code of some objects with a requestAction
         * @param string $url RequestAction url
         * @param string $params Extra params to RequestAction
         * @param boolean $enclose
         * @return string
         *        
         */        
        function replace_request_action($url,$params=array(),$enclose=true)
        {
            return $this->Cajax->replace_request_action($this->_css,$url,$params,$enclose);
        }        
                       
    }        
?>

Advertisements

Comments»

1. Naonak - May 9, 2006

Hello Ros-soft,

I don’t understand why you create a component instead of an helper.

Can you explain me, please ?

2. rossoft - May 9, 2006

It’s a helper-component. You can access it from views.
In it’s heart it is a helper. But making it a component I’ve access to startup() where I create a hidden div through HeadHelper. Also it needs access to requesthandler component.

Maybe it can be a helper but then you must add one line to each function

3. sosa - May 10, 2006

If you put this in a package with a sample, I’m sold.
I really need something like this, I was doing something, but this looks better.

4. rossoft - May 11, 2006

I will package it to cakeforge

5. rossoft - May 11, 2006

Now it’s packaged in http://cakeforge.org/snippet/detail.php?type=package&id=13

Also all the files and an example can be found at
http://www.ros-soft.net/otros/cakephp_blog/cajax_test.tgz

Uncompress in the root dir of a new cake installation then go to the browser http://your_cake_location/cajax_test/

6. Franck - July 12, 2006

Very nice to use, I would like to make an helper for some particular function, but what should I declare if I want to use the $cajax in my own helper ?
Thanks

7. Leslie Freeman - February 2, 2007

Hello,
I just started using your CJS component and I’m super stoked on it. Everything has been working great except that I can’t figure out how to use callbacks. I was trying to do something like this:

echo $page->effect(‘#new_gallery_form’,’BlindUp’, array(‘duration’=>0.3, ‘afterFinish’ => “function() { alert(‘I am done’); }”));

The BlindUp is working, but the afterFinish function doesn’t seem to get called. Any ideas?

Thanks again for all the great work!

8. rossoft - February 3, 2007

@Leslie:
Thanks for your interesest in CJS.
The problem is that in JSON the afterFind value is quoted, and then it isn’t eval’ed correctly.
This new function effect doesn’t quote the afterFind value (I don’t know what version of CakePHP and PageHelper are you using, maybe you’ve to do some extra changess).

/**
* Executes the effect to some elements that matches css selection
* @param mixed $css CSS selection
* @param string $effect The scriptaculous effect (Fade,Appear,…)
* @param array $params Extra parameters for the effect
* @param boolean $enclose
* @return string
*
* @link http://wiki.script.aculo.us/scriptaculous/show/CombinationEffectsDemo
*/
function effect($css,$effect,$params=array(),$enclose=true)
{
$not_quoted=array(‘afterFinish’);
$params=$this->Javascript->object($params,false,”,”,$not_quoted,false);
$effect=Inflector::camelize($effect);
return $this->for_each($css,”new Effect.$effect(_elem,$params)”,$enclose);
}

Bye!

9. 3D animation - April 16, 2013

I like the helpful information you provide in your articles.
I will bookmark your weblog and check again here frequently.
I am quite certain I will learn many new stuff right here!
Best of luck for the next!

10. donald trump - June 11, 2013

Hey there! Quick question that’s entirely off topic. Do you know how to make your site mobile friendly? My weblog looks weird when viewing from my apple iphone. I’m trying to find
a theme or plugin that might be able to correct this
issue. If you have any suggestions, please share. Appreciate it!

11. business flights to new zealand deals - September 30, 2013

Having read this I thought it was really informative.
I appreciate you taking the time and effort to put this content together.
I once again find myself personally spending a lot of time both reading and commenting.
But so what, it was still worth it!


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: