PageRenderTime 197ms CodeModel.GetById 73ms app.highlight 12ms RepoModel.GetById 109ms app.codeStats 0ms

/atk4/lib/jQuery/Chain.php

https://github.com/mahimarathore/mahi
PHP | 245 lines | 207 code | 3 blank | 35 comment | 6 complexity | 5dbb95a9008b7fa430b840204cfa6d0e MD5 | raw file
  1<?php
  2/***********************************************************
  3  jQuery chain proxy. Returned by view->js(). Calls to this
  4  class will be converted into jQuery calls.
  5
  6  Feel free to call _XX functions in this class
  7
  8  Reference:
  9  http://agiletoolkit.org/doc/ref
 10
 11==ATK4===================================================
 12   This file is part of Agile Toolkit 4
 13    http://agiletoolkit.org/
 14
 15   (c) 2008-2013 Agile Toolkit Limited <info@agiletoolkit.org>
 16   Distributed under Affero General Public License v3 and
 17   commercial license.
 18
 19   See LICENSE or LICENSE_COM for more information
 20=====================================================ATK4=*/
 21/*
 22   This class represents sequentall calls to one jQuery object
 23 */
 24class jQuery_Chain extends AbstractModel {
 25    public $str='';
 26    public $prepend='';
 27    public $selector=null;
 28    public $enclose=false;
 29    public $preventDefault=false;
 30    public $base='';
 31    function __call($name,$arguments){
 32        if($arguments){
 33            $a2=$this->_flattern_objects($arguments,true);
 34            $this->str.=".$name(".$a2.")";
 35        }else{
 36            $this->str.=".$name()";
 37        }
 38        return $this;
 39    }
 40    /* convert reserved words or used methods into js calls, such as "execute" */
 41    function _fn($name,$arguments=array()){
 42        // Wrapper for functons which use reserved words
 43        return $this->__call($name,$arguments);
 44    }
 45    /* converting this object into string will produce JavaScript code */
 46    function __toString(){
 47        return $this->_render();
 48    }
 49
 50    /* Some methods shouldn't be special! */
 51    function each(){
 52        return $this->__call('each',func_get_args());
 53    }
 54
 55    /* Chain binds to parent object by default. Use this to use other selector $('selector') */
 56    function _selector($selector=null){
 57        $this->selector=$selector;
 58        return $this;
 59    }
 60    /* Use this to bind chain to document $(document)... */
 61    function _selectorDocument(){
 62        $this->selector='__atk_selector_document';
 63        return $this;
 64    }
 65    /* Use this to bind chain to window $(window)... */
 66    function _selectorWindow(){
 67        $this->selector='__atk_selector_window';
 68        return $this;
 69    }
 70    /* Use this to bind chain to "this" $(this)... */
 71    function _selectorThis(){
 72        $this->selector='__atk_selector_this';
 73        return $this;
 74    }
 75    /* Use this to bind chain to "region" $(region). Region is defined by ATK when reloading */
 76    function _selectorRegion(){
 77        $this->selector='__atk_selector_region';
 78        return $this;
 79    }
 80    /* Execute more JavaScript code before chain. Avoid using. */
 81    function _prepend($code){
 82        if(is_array($code)){
 83            $code=join(';',$code);
 84        }
 85        $this->prepend=$code.';'.$this->prepend;
 86        return $this;
 87    }
 88    function debug(){
 89        $this->debug=true;
 90        return $this;
 91    }
 92    /* Send chain in response to form submit, button click or ajaxec() function for AJAX control output */
 93    function execute(){
 94        if(isset($_POST['ajax_submit']) || $_SERVER['HTTP_X_REQUESTED_WITH']=='XMLHttpRequest'){
 95            //if($this->api->jquery)$this->api->jquery->getJS($this->owner);
 96
 97            $x=$this->api->template->get('document_ready');
 98            if(is_array($x))$x=join('',$x);
 99            echo $this->_render();
100            $this->api->hook('post-js-execute');
101            exit;
102        }else return $this;
103    }
104    /* [private] used by custom json_encoding */
105    function _safe_js_string($str) {
106        $l=strlen($str);
107        $ret="";
108        for($i=0;$i<$l;++$i) {
109            switch($str[$i]) {
110                case "\r": $ret.="\\r"; break;
111                case "\n": $ret.="\\n"; break;
112                case "\"":     case "'":     case "<": case ">":  case "&":  case "\\":
113                           $ret.='\x'.dechex( ord($str[$i] ) );
114                           break;
115                default:
116                           $ret.=$str[$i];
117                           break;
118            }
119        }
120        return $ret;
121    }
122    /* [private] custom json_encoding. called on function arguments. */
123    protected function _flattern_objects($arg,$return_comma_list=false){
124        /*
125         * This function is very similar to json_encode, however it will traverse array
126         * before encoding in search of objects based on AbstractObject. Those would
127         * be replaced with their json representation if function exists, otherwise
128         * with string representation
129         */
130        if(is_object($arg)){
131            if($arg instanceof jQuery_Chain){
132                $r=$arg->_render();
133                if(substr($r,-1)==';')$r=substr($r,0,-1);
134                return $r;
135            }elseif($arg instanceof AbstractView){
136                return "'#".str_replace('/','_',$arg->name)."'";
137            }else{
138                return "'".$this->_safe_js_string((string)$arg)."'";    // indirectly call toString();
139            }
140        }elseif(is_array($arg)){
141            $a2=array();
142            // is array associative? (hash)
143            $assoc=$arg!=array_values($arg);
144
145            foreach($arg as $key=>$value){
146                $value=$this->_flattern_objects($value);
147                $key=$this->_flattern_objects($key);
148                if(!$assoc || $return_comma_list){
149                    $a2[]=$value;
150                }else{
151                    $a2[]=$key.':'.$value;
152                }
153            }
154            if($return_comma_list){
155                $s=join(',',$a2);
156            }elseif($assoc){
157                $s='{'.join(',',$a2).'}';
158            }else{
159                $s='['.join(',',$a2).']';
160            }
161        }elseif(is_string($arg)){
162            $s="'".$this->_safe_js_string($arg)."'";
163        }elseif(is_bool($arg)){
164            $s=json_encode($arg);
165        }elseif(is_numeric($arg)){
166            $s=json_encode($arg);
167        }elseif(is_null($arg)){
168            $s=json_encode($arg);
169        }else{
170            throw $this->exception('Unable to encode value for jQuery Chain - unknown type')
171                ->addMoreInfo('arg',$arg);
172        }
173        return $s;
174    }
175    /* Calls real redirect (from univ), but accepts page name. Use url() for 1st argument manually anyway. */
176    function redirect($page=null,$arg=null){
177        $url=$this->api->url($page,$arg);
178        return $this->_fn('redirect',array($url));
179    }
180    /* Reload object. You can bind this to custom event and trigger it if object is not directly accessible. */
181    function reload($arguments=array(),$fn=null,$url=null){
182        if($fn)$fn->_enclose();
183        $id=$this->owner;
184        if(!$url)$url=$this->api->url(null,array('cut_object'=>$id->name));
185        return $this->_fn('atk4_reload',array($url,$arguments,$fn));
186    }
187    /* Chain will not be called but will return callable function instead. */
188    function _enclose($fn=null,$preventDefault=false){
189        // builds structure $('obj').$fn(function(){ $('obj').XX; });
190        if($fn===null)$fn=true;
191        $this->enclose=$fn;
192        $this->preventDefault=$preventDefault;
193        return $this;
194    }
195    function _render(){
196        $ret='';
197        $ret.=$this->prepend;
198        if($this->selector===false){
199            $ret.="$";
200        }elseif($this->selector==='__atk_selector_this'){
201            $ret.="$(this)";
202        }elseif($this->selector==='__atk_selector_document'){
203            $ret.="$(document)";
204        }elseif($this->selector==='__atk_selector_window'){
205            $ret.="$(window)";
206        }elseif($this->selector==='__atk_selector_region'){
207            $ret.="$(region)";
208        }else{
209            if($this->str)$ret.="$('".($this->selector?$this->selector:'#'.str_replace('/','_',$this->owner->name))."')";
210        }
211        $ret.=$this->str;
212        if($this->enclose===true){
213            if($this->preventDefault){
214                $ret="function(ev){ev.preventDefault();ev.stopPropagation(); ".$ret." }";
215            }else{
216                $ret="function(){ ".$ret." }";
217            }
218        }elseif($this->enclose){
219            $ret="$('".($this->selector?$this->selector:'#'.$this->owner->name)."')".
220                ".bind('".$this->enclose."',function(ev){ ev.preventDefault();ev.stopPropagation(); ".$ret." })";
221        }
222        if(@$this->debug){
223            echo "<font color='blue'>".htmlspecialchars($ret).";</font><br/>";
224            $this->debug=false;
225        }
226        return $ret;
227    }
228    /* Returns HTML for a link with text $text. When clicked will execute this chain. */
229    function getLink($text){
230        return '<a href="javascript:void(0)" onclick="'.$this->getString().'">'.$text.'</a>';
231    }
232    function getString(){
233        return $this->_render();
234    }
235    /* Specify requirement for stylesheet. Will load dynamically. */
236    function _css($file){
237        $this->api->jquery->addStylesheet($file);
238        return $this;
239    }
240    /* Specify requirement for extra javascript include. Will load dynamically. */
241    function _load($file){
242        $this->api->jquery->addInclude($file);
243        return $this;
244    }
245}