1<?php 2/** 3 * CClientScript class file. 4 * 5 * @author Qiang Xue <qiang.xue@gmail.com> 6 * @link http://www.yiiframework.com/ 7 * @copyright 2008-2013 Yii Software LLC 8 * @license http://www.yiiframework.com/license/ 9 */ 10 11/** 12 * CClientScript manages JavaScript and CSS stylesheets for views. 13 * 14 * @property string $coreScriptUrl The base URL of all core javascript files. 15 * 16 * @author Qiang Xue <qiang.xue@gmail.com> 17 * @package system.web 18 * @since 1.0 19 */ 20class CClientScript extends CApplicationComponent 21{ 22 /** 23 * The script is rendered in the head section right before the title element. 24 */ 25 const POS_HEAD=0; 26 /** 27 * The script is rendered at the beginning of the body section. 28 */ 29 const POS_BEGIN=1; 30 /** 31 * The script is rendered at the end of the body section. 32 */ 33 const POS_END=2; 34 /** 35 * The script is rendered inside window onload function. 36 */ 37 const POS_LOAD=3; 38 /** 39 * The body script is rendered inside a jQuery ready function. 40 */ 41 const POS_READY=4; 42 43 /** 44 * @var boolean whether JavaScript should be enabled. Defaults to true. 45 */ 46 public $enableJavaScript=true; 47 /** 48 * @var array the mapping between script file names and the corresponding script URLs. 49 * The array keys are script file names (without directory part) and the array values are the corresponding URLs. 50 * If an array value is false, the corresponding script file will not be rendered. 51 * If an array key is '*.js' or '*.css', the corresponding URL will replace all 52 * JavaScript files or CSS files, respectively. 53 * 54 * This property is mainly used to optimize the generated HTML pages 55 * by merging different scripts files into fewer and optimized script files. 56 */ 57 public $scriptMap=array(); 58 /** 59 * @var array list of custom script packages (name=>package spec). 60 * This property keeps a list of named script packages, each of which can contain 61 * a set of CSS and/or JavaScript script files, and their dependent package names. 62 * By calling {@link registerPackage}, one can register a whole package of client 63 * scripts together with their dependent packages and render them in the HTML output. 64 * 65 * The array structure is as follows: 66 * <pre> 67 * array( 68 * 'package-name'=>array( 69 * 'basePath'=>'alias of the directory containing the script files', 70 * 'baseUrl'=>'base URL for the script files', 71 * 'js'=>array(list of js files relative to basePath/baseUrl), 72 * 'css'=>array(list of css files relative to basePath/baseUrl), 73 * 'depends'=>array(list of dependent packages), 74 * ), 75 * ...... 76 * ) 77 * </pre> 78 * 79 * The JS and CSS files listed are relative to 'basePath'. 80 * For example, if 'basePath' is 'application.assets', a script named 'comments.js' 81 * will refer to the file 'protected/assets/comments.js'. 82 * 83 * When a script is being rendered in HTML, it will be prefixed with 'baseUrl'. 84 * For example, if 'baseUrl' is '/assets', the 'comments.js' script will be rendered 85 * using URL '/assets/comments.js'. 86 * 87 * If 'baseUrl' does not start with '/', the relative URL of the application entry 88 * script will be inserted at the beginning. For example, if 'baseUrl' is 'assets' 89 * and the current application runs with the URL 'http://localhost/demo/index.php', 90 * then the 'comments.js' script will be rendered using URL '/demo/assets/comments.js'. 91 * 92 * If 'baseUrl' is not set, the script will be published by {@link CAssetManager} 93 * and the corresponding published URL will be used. 94 * 95 * When calling {@link registerPackage} to register a script package, 96 * this property will be checked first followed by {@link corePackages}. 97 * If a package is found, it will be registered for rendering later on. 98 * 99 * @since 1.1.7 100 */ 101 public $packages=array(); 102 /** 103 * @var array list of core script packages (name=>package spec). 104 * Please refer to {@link packages} for details about package spec. 105 * 106 * By default, the core script packages are specified in 'framework/web/js/packages.php'. 107 * You may configure this property to customize the core script packages. 108 * 109 * When calling {@link registerPackage} to register a script package, 110 * {@link packages} will be checked first followed by this property. 111 * If a package is found, it will be registered for rendering later on. 112 * 113 * @since 1.1.7 114 */ 115 public $corePackages; 116 /** 117 * @var array the registered JavaScript code blocks (position, key => code) 118 */ 119 public $scripts=array(); 120 /** 121 * @var array the registered CSS files (CSS URL=>media type). 122 */ 123 protected $cssFiles=array(); 124 /** 125 * @var array the registered JavaScript files (position, key => URL) 126 */ 127 protected $scriptFiles=array(); 128 /** 129 * @var array the registered head meta tags. Each array element represents an option array 130 * that will be passed as the last parameter of {@link CHtml::metaTag}. 131 * @since 1.1.3 132 */ 133 protected $metaTags=array(); 134 /** 135 * @var array the registered head link tags. Each array element represents an option array 136 * that will be passed as the last parameter of {@link CHtml::linkTag}. 137 * @since 1.1.3 138 */ 139 protected $linkTags=array(); 140 /** 141 * @var array the registered css code blocks (key => array(CSS code, media type)). 142 * @since 1.1.3 143 */ 144 protected $css=array(); 145 /** 146 * @var boolean whether there are any javascript or css to be rendered. 147 * @since 1.1.7 148 */ 149 protected $hasScripts=false; 150 /** 151 * @var array the registered script packages (name => package spec) 152 * @since 1.1.7 153 */ 154 protected $coreScripts=array(); 155 /** 156 * @var integer Where the scripts registered using {@link registerCoreScript} or {@link registerPackage} 157 * will be inserted in the page. This can be one of the CClientScript::POS_* constants. 158 * Defaults to CClientScript::POS_HEAD. 159 * @since 1.1.3 160 */ 161 public $coreScriptPosition=self::POS_HEAD; 162 /** 163 * @var integer Where the scripts registered using {@link registerScriptFile} will be inserted in the page. 164 * This can be one of the CClientScript::POS_* constants. 165 * Defaults to CClientScript::POS_HEAD. 166 * @since 1.1.11 167 */ 168 public $defaultScriptFilePosition=self::POS_HEAD; 169 /** 170 * @var integer Where the scripts registered using {@link registerScript} will be inserted in the page. 171 * This can be one of the CClientScript::POS_* constants. 172 * Defaults to CClientScript::POS_READY. 173 * @since 1.1.11 174 */ 175 public $defaultScriptPosition=self::POS_READY; 176 177 private $_baseUrl; 178 179 /** 180 * Cleans all registered scripts. 181 */ 182 public function reset() 183 { 184 $this->hasScripts=false; 185 $this->coreScripts=array(); 186 $this->cssFiles=array(); 187 $this->css=array(); 188 $this->scriptFiles=array(); 189 $this->scripts=array(); 190 $this->metaTags=array(); 191 $this->linkTags=array(); 192 193 $this->recordCachingAction('clientScript','reset',array()); 194 } 195 196 /** 197 * Renders the registered scripts. 198 * This method is called in {@link CController::render} when it finishes 199 * rendering content. CClientScript thus gets a chance to insert script tags 200 * at <code>head</code> and <code>body</code> sections in the HTML output. 201 * @param string $output the existing output that needs to be inserted with script tags 202 */ 203 public function render(&$output) 204 { 205 if(!$this->hasScripts) 206 return; 207 208 $this->renderCoreScripts(); 209 210 if(!empty($this->scriptMap)) 211 $this->remapScripts(); 212 213 $this->unifyScripts(); 214 215 $this->renderHead($output); 216 if($this->enableJavaScript) 217 { 218 $this->renderBodyBegin($output); 219 $this->renderBodyEnd($output); 220 } 221 } 222 223 /** 224 * Removes duplicated scripts from {@link scriptFiles}. 225 * @since 1.1.5 226 */ 227 protected function unifyScripts() 228 { 229 if(!$this->enableJavaScript) 230 return; 231 $map=array(); 232 if(isset($this->scriptFiles[self::POS_HEAD])) 233 $map=$this->scriptFiles[self::POS_HEAD]; 234 235 if(isset($this->scriptFiles[self::POS_BEGIN])) 236 { 237 foreach($this->scriptFiles[self::POS_BEGIN] as $scriptFile=>$scriptFileValue) 238 { 239 if(isset($map[$scriptFile])) 240 unset($this->scriptFiles[self::POS_BEGIN][$scriptFile]); 241 else 242 $map[$scriptFile]=true; 243 } 244 } 245 246 if(isset($this->scriptFiles[self::POS_END])) 247 { 248 foreach($this->scriptFiles[self::POS_END] as $key=>$scriptFile) 249 { 250 if(isset($map[$key])) 251 unset($this->scriptFiles[self::POS_END][$key]); 252 } 253 } 254 } 255 256 /** 257 * Uses {@link scriptMap} to re-map the registered scripts. 258 */ 259 protected function remapScripts() 260 { 261 $cssFiles=array(); 262 foreach($this->cssFiles as $url=>$media) 263 { 264 $name=basename($url); 265 if(isset($this->scriptMap[$name])) 266 { 267 if($this->scriptMap[$name]!==false) 268 $cssFiles[$this->scriptMap[$name]]=$media; 269 } 270 elseif(isset($this->scriptMap['*.css'])) 271 { 272 if($this->scriptMap['*.css']!==false) 273 $cssFiles[$this->scriptMap['*.css']]=$media; 274 } 275 else 276 $cssFiles[$url]=$media; 277 } 278 $this->cssFiles=$cssFiles; 279 280 $jsFiles=array(); 281 foreach($this->scriptFiles as $position=>$scriptFiles) 282 { 283 $jsFiles[$position]=array(); 284 foreach($scriptFiles as $scriptFile=>$scriptFileValue) 285 { 286 $name=basename($scriptFile); 287 if(isset($this->scriptMap[$name])) 288 { 289 if($this->scriptMap[$name]!==false) 290 $jsFiles[$position][$this->scriptMap[$name]]=$this->scriptMap[$name]; 291 } 292 elseif(isset($this->scriptMap['*.js'])) 293 { 294 if($this->scriptMap['*.js']!==false) 295 $jsFiles[$position][$this->scriptMap['*.js']]=$this->scriptMap['*.js']; 296 } 297 else 298 $jsFiles[$position][$scriptFile]=$scriptFileValue; 299 } 300 } 301 $this->scriptFiles=$jsFiles; 302 } 303 304 /** 305 * Composes script HTML block from the given script values, 306 * attempting to group scripts at single 'script' tag if possible. 307 * @param array $scripts script values to process. 308 * @return string HTML output 309 */ 310 protected function renderScriptBatch(array $scripts) 311 { 312 $html = ''; 313 $scriptBatches = array(); 314 foreach($scripts as $scriptValue) 315 { 316 if(is_array($scriptValue)) 317 { 318 $scriptContent = $scriptValue['content']; 319 unset($scriptValue['content']); 320 $scriptHtmlOptions = $scriptValue; 321 ksort($scriptHtmlOptions); 322 } 323 else 324 { 325 $scriptContent = $scriptValue; 326 $scriptHtmlOptions = array(); 327 } 328 $key=serialize($scriptHtmlOptions); 329 $scriptBatches[$key]['htmlOptions']=$scriptHtmlOptions; 330 $scriptBatches[$key]['scripts'][]=$scriptContent; 331 } 332 foreach($scriptBatches as $scriptBatch) 333 if(!empty($scriptBatch['scripts'])) 334 $html.=CHtml::script(implode("\n",$scriptBatch['scripts']),$scriptBatch['htmlOptions'])."\n"; 335 return $html; 336 } 337 338 /** 339 * Renders the specified core javascript library. 340 */ 341 public function renderCoreScripts() 342 { 343 if($this->coreScripts===null) 344 return; 345 $cssFiles=array(); 346 $jsFiles=array(); 347 foreach($this->coreScripts as $name=>$package) 348 { 349 $baseUrl=$this->getPackageBaseUrl($name); 350 if(!empty($package['js'])) 351 { 352 foreach($package['js'] as $js) 353 $jsFiles[$baseUrl.'/'.$js]=$baseUrl.'/'.$js; 354 } 355 if(!empty($package['css'])) 356 { 357 foreach($package['css'] as $css) 358 $cssFiles[$baseUrl.'/'.$css]=''; 359 } 360 } 361 // merge in place 362 if($cssFiles!==array()) 363 { 364 foreach($this->cssFiles as $cssFile=>$media) 365 $cssFiles[$cssFile]=$media; 366 $this->cssFiles=$cssFiles; 367 } 368 if($jsFiles!==array()) 369 { 370 if(isset($this->scriptFiles[$this->coreScriptPosition])) 371 { 372 foreach($this->scriptFiles[$this->coreScriptPosition] as $url => $value) 373 $jsFiles[$url]=$value; 374 } 375 $this->scriptFiles[$this->coreScriptPosition]=$jsFiles; 376 } 377 } 378 379 /** 380 * Inserts the scripts in the head section. 381 * @param string $output the output to be inserted with scripts. 382 */ 383 public function renderHead(&$output) 384 { 385 $html=''; 386 foreach($this->metaTags as $meta) 387 $html.=CHtml::metaTag($meta['content'],null,null,$meta)."\n"; 388 foreach($this->linkTags as $link) 389 $html.=CHtml::linkTag(null,null,null,null,$link)."\n"; 390 foreach($this->cssFiles as $url=>$media) 391 $html.=CHtml::cssFile($url,$media)."\n"; 392 foreach($this->css as $css) 393 $html.=CHtml::css($css[0],$css[1])."\n"; 394 if($this->enableJavaScript) 395 { 396 if(isset($this->scriptFiles[self::POS_HEAD])) 397 { 398 foreach($this->scriptFiles[self::POS_HEAD] as $scriptFileValueUrl=>$scriptFileValue) 399 { 400 if(is_array($scriptFileValue)) 401 $html.=CHtml::scriptFile($scriptFileValueUrl,$scriptFileValue)."\n"; 402 else 403 $html.=CHtml::scriptFile($scriptFileValueUrl)."\n"; 404 } 405 } 406 407 if(isset($this->scripts[self::POS_HEAD])) 408 $html.=$this->renderScriptBatch($this->scripts[self::POS_HEAD]); 409 } 410 411 if($html!=='') 412 { 413 $count=0; 414 $output=preg_replace('/(<title\b[^>]*>|<\\/head\s*>)/is','<###head###>$1',$output,1,$count); 415 if($count) 416 $output=str_replace('<###head###>',$html,$output); 417 else 418 $output=$html.$output; 419 } 420 } 421 422 /** 423 * Inserts the scripts at the beginning of the body section. 424 * @param string $output the output to be inserted with scripts. 425 */ 426 public function renderBodyBegin(&$output) 427 { 428 $html=''; 429 if(isset($this->scriptFiles[self::POS_BEGIN])) 430 { 431 foreach($this->scriptFiles[self::POS_BEGIN] as $scriptFileUrl=>$scriptFileValue) 432 { 433 if(is_array($scriptFileValue)) 434 $html.=CHtml::scriptFile($scriptFileUrl,$scriptFileValue)."\n"; 435 else 436 $html.=CHtml::scriptFile($scriptFileUrl)."\n"; 437 } 438 } 439 if(isset($this->scripts[self::POS_BEGIN])) 440 $html.=$this->renderScriptBatch($this->scripts[self::POS_BEGIN]); 441 442 if($html!=='') 443 { 444 $count=0; 445 $output=preg_replace('/(<body\b[^>]*>)/is','$1<###begin###>',$output,1,$count); 446 if($count) 447 $output=str_replace('<###begin###>',$html,$output); 448 else 449 $output=$html.$output; 450 } 451 } 452 453 /** 454 * Inserts the scripts at the end of the body section. 455 * @param string $output the output to be inserted with scripts. 456 */ 457 public function renderBodyEnd(&$output) 458 { 459 if(!isset($this->scriptFiles[self::POS_END]) && !isset($this->scripts[self::POS_END]) 460 && !isset($this->scripts[self::POS_READY]) && !isset($this->scripts[self::POS_LOAD])) 461 return; 462 463 $fullPage=0; 464 $output=preg_replace('/(<\\/body\s*>)/is','<###end###>$1',$output,1,$fullPage); 465 $html=''; 466 if(isset($this->scriptFiles[self::POS_END])) 467 { 468 foreach($this->scriptFiles[self::POS_END] as $scriptFileUrl=>$scriptFileValue) 469 { 470 if(is_array($scriptFileValue)) 471 $html.=CHtml::scriptFile($scriptFileUrl,$scriptFileValue)."\n"; 472 else 473 $html.=CHtml::scriptFile($scriptFileUrl)."\n"; 474 } 475 } 476 $scripts=isset($this->scripts[self::POS_END]) ? $this->scripts[self::POS_END] : array(); 477 if(isset($this->scripts[self::POS_READY])) 478 { 479 if($fullPage) 480 $scripts[]="jQuery(function($) {\n".implode("\n",$this->scripts[self::POS_READY])."\n});"; 481 else 482 $scripts[]=implode("\n",$this->scripts[self::POS_READY]); 483 } 484 if(isset($this->scripts[self::POS_LOAD])) 485 { 486 if($fullPage) 487 $scripts[]="jQuery(window).on('load',function() {\n".implode("\n",$this->scripts[self::POS_LOAD])."\n});"; 488 else 489 $scripts[]=implode("\n",$this->scripts[self::POS_LOAD]); 490 } 491 if(!empty($scripts)) 492 $html.=$this->renderScriptBatch($scripts); 493 494 if($fullPage) 495 $output=str_replace('<###end###>',$html,$output); 496 else 497 $output=$output.$html; 498 } 499 500 /** 501 * Returns the base URL of all core javascript files. 502 * If the base URL is not explicitly set, this method will publish the whole directory 503 * 'framework/web/js/source' and return the corresponding URL. 504 * @return string the base URL of all core javascript files 505 */ 506 public function getCoreScriptUrl() 507 { 508 if($this->_baseUrl!==null) 509 return $this->_baseUrl; 510 else 511 return $this->_baseUrl=Yii::app()->getAssetManager()->publish(YII_PATH.'/web/js/source'); 512 } 513 514 /** 515 * Sets the base URL of all core javascript files. 516 * This setter is provided in case when core javascript files are manually published 517 * to a pre-specified location. This may save asset publishing time for large-scale applications. 518 * @param string $value the base URL of all core javascript files. 519 */ 520 public function setCoreScriptUrl($value) 521 { 522 $this->_baseUrl=$value; 523 } 524 525 /** 526 * Returns the base URL for a registered package with the specified name. 527 * If needed, this method may publish the assets of the package and returns the published base URL. 528 * @param string $name the package name 529 * @return string the base URL for the named package. False is returned if the package is not registered yet. 530 * @see registerPackage 531 * @since 1.1.8 532 */ 533 public function getPackageBaseUrl($name) 534 { 535 if(!isset($this->coreScripts[$name])) 536 return false; 537 $package=$this->coreScripts[$name]; 538 if(isset($package['baseUrl'])) 539 { 540 $baseUrl=$package['baseUrl']; 541 if($baseUrl==='' || $baseUrl[0]!=='/' && strpos($baseUrl,'://')===false) 542 $baseUrl=Yii::app()->getRequest()->getBaseUrl().'/'.$baseUrl; 543 $baseUrl=rtrim($baseUrl,'/'); 544 } 545 elseif(isset($package['basePath'])) 546 $baseUrl=Yii::app()->getAssetManager()->publish(Yii::getPathOfAlias($package['basePath'])); 547 else 548 $baseUrl=$this->getCoreScriptUrl(); 549 550 return $this->coreScripts[$name]['baseUrl']=$baseUrl; 551 } 552 553 /** 554 * Checks if package is available. 555 * @param string $name the name of the script package. 556 * @return bool 557 * @since 1.1.18 558 * @see registerPackage 559 */ 560 public function hasPackage($name) 561 { 562 if(isset($this->coreScripts[$name])) 563 return true; 564 if(isset($this->packages[$name])) 565 return true; 566 else 567 { 568 if($this->corePackages===null) 569 $this->corePackages=require(YII_PATH.'/web/js/packages.php'); 570 if(isset($this->corePackages[$name])) 571 return true; 572 } 573 return false; 574 } 575 576 /** 577 * Registers a script package that is listed in {@link packages}. 578 * This method is the same as {@link registerCoreScript}. 579 * @param string $name the name of the script package. 580 * @return static the CClientScript object itself (to support method chaining, available since version 1.1.5). 581 * @since 1.1.7 582 * @see renderCoreScript 583 */ 584 public function registerPackage($name) 585 { 586 return $this->registerCoreScript($name); 587 } 588 589 /** 590 * Registers a script package that is listed in {@link packages}. 591 * @param string $name the name of the script package. 592 * @return static the CClientScript object itself (to support method chaining, available since version 1.1.5). 593 * @see renderCoreScript 594 * @throws CException 595 */ 596 public function registerCoreScript($name) 597 { 598 if(isset($this->coreScripts[$name])) 599 return $this; 600 if(isset($this->packages[$name])) 601 $package=$this->packages[$name]; 602 else 603 { 604 if($this->corePackages===null) 605 $this->corePackages=require(YII_PATH.'/web/js/packages.php'); 606 if(isset($this->corePackages[$name])) 607 $package=$this->corePackages[$name]; 608 } 609 if(isset($package)) 610 { 611 if(!empty($package['depends'])) 612 { 613 foreach($package['depends'] as $p) 614 $this->registerCoreScript($p); 615 } 616 $this->coreScripts[$name]=$package; 617 $this->hasScripts=true; 618 $params=func_get_args(); 619 $this->recordCachingAction('clientScript','registerCoreScript',$params); 620 } 621 elseif(YII_DEBUG) 622 throw new CException('There is no CClientScript package: '.$name); 623 else 624 Yii::log('There is no CClientScript package: '.$name,CLogger::LEVEL_WARNING,'system.web.CClientScript'); 625 626 return $this; 627 } 628 629 /** 630 * Registers a CSS file 631 * @param string $url URL of the CSS file 632 * @param string $media media that the CSS file should be applied to. If empty, it means all media types. 633 * @return static the CClientScript object itself (to support method chaining, available since version 1.1.5). 634 */ 635 public function registerCssFile($url,$media='') 636 { 637 $this->hasScripts=true; 638 $this->cssFiles[$url]=$media; 639 $params=func_get_args(); 640 $this->recordCachingAction('clientScript','registerCssFile',$params); 641 return $this; 642 } 643 644 /** 645 * Registers a piece of CSS code. 646 * @param string $id ID that uniquely identifies this piece of CSS code 647 * @param string $css the CSS code 648 * @param string $media media that the CSS code should be applied to. If empty, it means all media types. 649 * @return static the CClientScript object itself (to support method chaining, available since version 1.1.5). 650 */ 651 public function registerCss($id,$css,$media='') 652 { 653 $this->hasScripts=true; 654 $this->css[$id]=array($css,$media); 655 $params=func_get_args(); 656 $this->recordCachingAction('clientScript','registerCss',$params); 657 return $this; 658 } 659 660 /** 661 * Registers a javascript file. 662 * @param string $url URL of the javascript file 663 * @param integer $position the position of the JavaScript code. Valid values include the following: 664 * <ul> 665 * <li>CClientScript::POS_HEAD : the script is inserted in the head section right before the title element.</li> 666 * <li>CClientScript::POS_BEGIN : the script is inserted at the beginning of the body section.</li> 667 * <li>CClientScript::POS_END : the script is inserted at the end of the body section.</li> 668 * </ul> 669 * @param array $htmlOptions additional HTML attributes 670 * @return static the CClientScript object itself (to support method chaining, available since version 1.1.5). 671 */ 672 public function registerScriptFile($url,$position=null,array $htmlOptions=array()) 673 { 674 $params=func_get_args(); 675 676 if($position===null) 677 $position=$this->defaultScriptFilePosition; 678 $this->hasScripts=true; 679 if(empty($htmlOptions)) 680 $value=$url; 681 else 682 { 683 $value=$htmlOptions; 684 $value['src']=$url; 685 } 686 $this->scriptFiles[$position][$url]=$value; 687 $this->recordCachingAction('clientScript','registerScriptFile',$params); 688 return $this; 689 } 690 691 /** 692 * Registers a piece of javascript code. 693 * @param string $id ID that uniquely identifies this piece of JavaScript code 694 * @param string $script the javascript code 695 * @param integer $position the position of the JavaScript code. Valid values include the following: 696 * <ul> 697 * <li>CClientScript::POS_HEAD : the script is inserted in the head section right before the title element.</li> 698 * <li>CClientScript::POS_BEGIN : the script is inserted at the beginning of the body section.</li> 699 * <li>CClientScript::POS_END : the script is inserted at the end of the body section.</li> 700 * <li>CClientScript::POS_LOAD : the script is inserted in the window.onload() function.</li> 701 * <li>CClientScript::POS_READY : the script is inserted in the jQuery's ready function.</li> 702 * </ul> 703 * @param array $htmlOptions additional HTML attributes 704 * Note: HTML attributes are not allowed for script positions "CClientScript::POS_LOAD" and "CClientScript::POS_READY". 705 * @return static the CClientScript object itself (to support method chaining, available since version 1.1.5). 706 * @throws CException 707 */ 708 public function registerScript($id,$script,$position=null,array $htmlOptions=array()) 709 { 710 $params=func_get_args(); 711 712 if($position===null) 713 $position=$this->defaultScriptPosition; 714 $this->hasScripts=true; 715 if(empty($htmlOptions)) 716 $scriptValue=$script; 717 else 718 { 719 if($position==self::POS_LOAD || $position==self::POS_READY) 720 throw new CException(Yii::t('yii','Script HTML options are not allowed for "CClientScript::POS_LOAD" and "CClientScript::POS_READY".')); 721 $scriptValue=$htmlOptions; 722 $scriptValue['content']=$script; 723 } 724 $this->scripts[$position][$id]=$scriptValue; 725 if($position===self::POS_READY || $position===self::POS_LOAD) 726 $this->registerCoreScript('jquery'); 727 $this->recordCachingAction('clientScript','registerScript',$params); 728 return $this; 729 } 730 731 /** 732 * Registers a meta tag that will be inserted in the head section (right before the title element) of the resulting page. 733 * 734 * <b>Note:</b> 735 * Each call of this method will cause a rendering of new meta tag, even if their attributes are equal. 736 * 737 * <b>Example:</b> 738 * <pre> 739 * $cs->registerMetaTag('example', 'description', null, array('lang' => 'en')); 740 * $cs->registerMetaTag('beispiel', 'description', null, array('lang' => 'de')); 741 * </pre> 742 * @param string $content content attribute of the meta tag 743 * @param string $name name attribute of the meta tag. If null, the attribute will not be generated 744 * @param string $httpEquiv http-equiv attribute of the meta tag. If null, the attribute will not be generated 745 * @param array $options other options in name-value pairs (e.g. 'scheme', 'lang') 746 * @param string $id Optional id of the meta tag to avoid duplicates 747 * @return static the CClientScript object itself (to support method chaining, available since version 1.1.5). 748 */ 749 public function registerMetaTag($content,$name=null,$httpEquiv=null,$options=array(),$id=null) 750 { 751 $params=func_get_args(); 752 753 $this->hasScripts=true; 754 if($name!==null) 755 $options['name']=$name; 756 if($httpEquiv!==null) 757 $options['http-equiv']=$httpEquiv; 758 $options['content']=$content; 759 $this->metaTags[null===$id?count($this->metaTags):$id]=$options; 760 $this->recordCachingAction('clientScript','registerMetaTag',$params); 761 return $this; 762 } 763 764 /** 765 * Registers a link tag that will be inserted in the head section (right before the title element) of the resulting page. 766 * @param string $relation rel attribute of the link tag. If null, the attribute will not be generated. 767 * @param string $type type attribute of the link tag. If null, the attribute will not be generated. 768 * @param string $href href attribute of the link tag. If null, the attribute will not be generated. 769 * @param string $media media attribute of the link tag. If null, the attribute will not be generated. 770 * @param array $options other options in name-value pairs 771 * @return static the CClientScript object itself (to support method chaining, available since version 1.1.5). 772 */ 773 public function registerLinkTag($relation=null,$type=null,$href=null,$media=null,$options=array()) 774 { 775 $params=func_get_args(); 776 777 $this->hasScripts=true; 778 if($relation!==null) 779 $options['rel']=$relation; 780 if($type!==null) 781 $options['type']=$type; 782 if($href!==null) 783 $options['href']=$href; 784 if($media!==null) 785 $options['media']=$media; 786 $this->linkTags[serialize($options)]=$options; 787 $this->recordCachingAction('clientScript','registerLinkTag',$params); 788 return $this; 789 } 790 791 /** 792 * Checks whether the CSS file has been registered. 793 * @param string $url URL of the CSS file 794 * @return boolean whether the CSS file is already registered 795 */ 796 public function isCssFileRegistered($url) 797 { 798 return isset($this->cssFiles[$url]); 799 } 800 801 /** 802 * Checks whether the CSS code has been registered. 803 * @param string $id ID that uniquely identifies the CSS code 804 * @return boolean whether the CSS code is already registered 805 */ 806 public function isCssRegistered($id) 807 { 808 return isset($this->css[$id]); 809 } 810 811 /** 812 * Checks whether the JavaScript file has been registered. 813 * @param string $url URL of the javascript file 814 * @param integer $position the position of the JavaScript code. Valid values include the following: 815 * <ul> 816 * <li>CClientScript::POS_HEAD : the script is inserted in the head section right before the title element.</li> 817 * <li>CClientScript::POS_BEGIN : the script is inserted at the beginning of the body section.</li> 818 * <li>CClientScript::POS_END : the script is inserted at the end of the body section.</li> 819 * </ul> 820 * @return boolean whether the javascript file is already registered 821 */ 822 public function isScriptFileRegistered($url,$position=self::POS_HEAD) 823 { 824 return isset($this->scriptFiles[$position][$url]); 825 } 826 827 /** 828 * Checks whether the JavaScript code has been registered. 829 * @param string $id ID that uniquely identifies the JavaScript code 830 * @param integer $position the position of the JavaScript code. Valid values include the following: 831 * <ul> 832 * <li>CClientScript::POS_HEAD : the script is inserted in the head section right before the title element.</li> 833 * <li>CClientScript::POS_BEGIN : the script is inserted at the beginning of the body section.</li> 834 * <li>CClientScript::POS_END : the script is inserted at the end of the body section.</li> 835 * <li>CClientScript::POS_LOAD : the script is inserted in the window.onload() function.</li> 836 * <li>CClientScript::POS_READY : the script is inserted in the jQuery's ready function.</li> 837 * </ul> 838 * @return boolean whether the javascript code is already registered 839 */ 840 public function isScriptRegistered($id,$position=self::POS_READY) 841 { 842 return isset($this->scripts[$position][$id]); 843 } 844 845 /** 846 * Records a method call when an output cache is in effect. 847 * This is a shortcut to Yii::app()->controller->recordCachingAction. 848 * In case when controller is absent, nothing is recorded. 849 * @param string $context a property name of the controller. It refers to an object 850 * whose method is being called. If empty it means the controller itself. 851 * @param string $method the method name 852 * @param array $params parameters passed to the method 853 * @see COutputCache 854 */ 855 protected function recordCachingAction($context,$method,$params) 856 { 857 if(($controller=Yii::app()->getController())!==null) 858 $controller->recordCachingAction($context,$method,$params); 859 } 860 861 /** 862 * Adds a package to packages list. 863 * 864 * @param string $name the name of the script package. 865 * @param array $definition the definition array of the script package, 866 * @see CClientScript::packages. 867 * @return static the CClientScript object itself (to support method chaining, available since version 1.1.10). 868 * 869 * @since 1.1.9 870 */ 871 public function addPackage($name,$definition) 872 { 873 $this->packages[$name]=$definition; 874 return $this; 875 } 876} 877