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: */
20: class 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: * Registers a script package that is listed in {@link packages}.
555: * This method is the same as {@link registerCoreScript}.
556: * @param string $name the name of the script package.
557: * @return static the CClientScript object itself (to support method chaining, available since version 1.1.5).
558: * @since 1.1.7
559: * @see renderCoreScript
560: */
561: public function registerPackage($name)
562: {
563: return $this->registerCoreScript($name);
564: }
565:
566: /**
567: * Registers a script package that is listed in {@link packages}.
568: * @param string $name the name of the script package.
569: * @return static the CClientScript object itself (to support method chaining, available since version 1.1.5).
570: * @see renderCoreScript
571: */
572: public function registerCoreScript($name)
573: {
574: if(isset($this->coreScripts[$name]))
575: return $this;
576: if(isset($this->packages[$name]))
577: $package=$this->packages[$name];
578: else
579: {
580: if($this->corePackages===null) {
581: $this->corePackages=require(YII_PATH.'/web/js/packages.php');
582: $this->corePackages = array_merge( $this->corePackages,
583: require('protected/data/packages.php')
584: );
585: }
586: if(isset($this->corePackages[$name]))
587: $package=$this->corePackages[$name];
588: }
589: if(isset($package))
590: {
591: if(!empty($package['depends']))
592: {
593: foreach($package['depends'] as $p)
594: $this->registerCoreScript($p);
595: }
596: $this->coreScripts[$name]=$package;
597: $this->hasScripts=true;
598: $params=func_get_args();
599: $this->recordCachingAction('clientScript','registerCoreScript',$params);
600: }
601: elseif(YII_DEBUG)
602: throw new CException('There is no CClientScript package: '.$name);
603: else
604: Yii::log('There is no CClientScript package: '.$name,CLogger::LEVEL_WARNING,'system.web.CClientScript');
605:
606: return $this;
607: }
608:
609: /**
610: * Registers a CSS file
611: * @param string $url URL of the CSS file
612: * @param string $media media that the CSS file should be applied to. If empty, it means all media types.
613: * @return static the CClientScript object itself (to support method chaining, available since version 1.1.5).
614: */
615: public function registerCssFile($url,$media='')
616: {
617: $this->hasScripts=true;
618: $this->cssFiles[$url]=$media;
619: $params=func_get_args();
620: $this->recordCachingAction('clientScript','registerCssFile',$params);
621: return $this;
622: }
623:
624: /**
625: * Registers a piece of CSS code.
626: * @param string $id ID that uniquely identifies this piece of CSS code
627: * @param string $css the CSS code
628: * @param string $media media that the CSS code should be applied to. If empty, it means all media types.
629: * @return static the CClientScript object itself (to support method chaining, available since version 1.1.5).
630: */
631: public function registerCss($id,$css,$media='')
632: {
633: $this->hasScripts=true;
634: $this->css[$id]=array($css,$media);
635: $params=func_get_args();
636: $this->recordCachingAction('clientScript','registerCss',$params);
637: return $this;
638: }
639:
640: /**
641: * Registers a javascript file.
642: * @param string $url URL of the javascript file
643: * @param integer $position the position of the JavaScript code. Valid values include the following:
644: * <ul>
645: * <li>CClientScript::POS_HEAD : the script is inserted in the head section right before the title element.</li>
646: * <li>CClientScript::POS_BEGIN : the script is inserted at the beginning of the body section.</li>
647: * <li>CClientScript::POS_END : the script is inserted at the end of the body section.</li>
648: * </ul>
649: * @param array $htmlOptions additional HTML attributes
650: * @return static the CClientScript object itself (to support method chaining, available since version 1.1.5).
651: */
652: public function registerScriptFile($url,$position=null,array $htmlOptions=array())
653: {
654: if($position===null)
655: $position=$this->defaultScriptFilePosition;
656: $this->hasScripts=true;
657: if(empty($htmlOptions))
658: $value=$url;
659: else
660: {
661: $value=$htmlOptions;
662: $value['src']=$url;
663: }
664: $this->scriptFiles[$position][$url]=$value;
665: $params=func_get_args();
666: $this->recordCachingAction('clientScript','registerScriptFile',$params);
667: return $this;
668: }
669:
670: /**
671: * Registers a piece of javascript code.
672: * @param string $id ID that uniquely identifies this piece of JavaScript code
673: * @param string $script the javascript code
674: * @param integer $position the position of the JavaScript code. Valid values include the following:
675: * <ul>
676: * <li>CClientScript::POS_HEAD : the script is inserted in the head section right before the title element.</li>
677: * <li>CClientScript::POS_BEGIN : the script is inserted at the beginning of the body section.</li>
678: * <li>CClientScript::POS_END : the script is inserted at the end of the body section.</li>
679: * <li>CClientScript::POS_LOAD : the script is inserted in the window.onload() function.</li>
680: * <li>CClientScript::POS_READY : the script is inserted in the jQuery's ready function.</li>
681: * </ul>
682: * @param array $htmlOptions additional HTML attributes
683: * Note: HTML attributes are not allowed for script positions "CClientScript::POS_LOAD" and "CClientScript::POS_READY".
684: * @return static the CClientScript object itself (to support method chaining, available since version 1.1.5).
685: */
686: public function registerScript($id,$script,$position=null,array $htmlOptions=array())
687: {
688: if($position===null)
689: $position=$this->defaultScriptPosition;
690: $this->hasScripts=true;
691: if(empty($htmlOptions))
692: $scriptValue=$script;
693: else
694: {
695: if($position==self::POS_LOAD || $position==self::POS_READY)
696: throw new CException(Yii::t('yii','Script HTML options are not allowed for "CClientScript::POS_LOAD" and "CClientScript::POS_READY".'));
697: $scriptValue=$htmlOptions;
698: $scriptValue['content']=$script;
699: }
700: $this->scripts[$position][$id]=$scriptValue;
701: if($position===self::POS_READY || $position===self::POS_LOAD)
702: $this->registerCoreScript('jquery');
703: $params=func_get_args();
704: $this->recordCachingAction('clientScript','registerScript',$params);
705: return $this;
706: }
707:
708: /**
709: * Registers a meta tag that will be inserted in the head section (right before the title element) of the resulting page.
710: *
711: * <b>Note:</b>
712: * Each call of this method will cause a rendering of new meta tag, even if their attributes are equal.
713: *
714: * <b>Example:</b>
715: * <pre>
716: * $cs->registerMetaTag('example', 'description', null, array('lang' => 'en'));
717: * $cs->registerMetaTag('beispiel', 'description', null, array('lang' => 'de'));
718: * </pre>
719: * @param string $content content attribute of the meta tag
720: * @param string $name name attribute of the meta tag. If null, the attribute will not be generated
721: * @param string $httpEquiv http-equiv attribute of the meta tag. If null, the attribute will not be generated
722: * @param array $options other options in name-value pairs (e.g. 'scheme', 'lang')
723: * @param string $id Optional id of the meta tag to avoid duplicates
724: * @return static the CClientScript object itself (to support method chaining, available since version 1.1.5).
725: */
726: public function registerMetaTag($content,$name=null,$httpEquiv=null,$options=array(),$id=null)
727: {
728: $this->hasScripts=true;
729: if($name!==null)
730: $options['name']=$name;
731: if($httpEquiv!==null)
732: $options['http-equiv']=$httpEquiv;
733: $options['content']=$content;
734: $this->metaTags[null===$id?count($this->metaTags):$id]=$options;
735: $params=func_get_args();
736: $this->recordCachingAction('clientScript','registerMetaTag',$params);
737: return $this;
738: }
739:
740: /**
741: * Registers a link tag that will be inserted in the head section (right before the title element) of the resulting page.
742: * @param string $relation rel attribute of the link tag. If null, the attribute will not be generated.
743: * @param string $type type attribute of the link tag. If null, the attribute will not be generated.
744: * @param string $href href attribute of the link tag. If null, the attribute will not be generated.
745: * @param string $media media attribute of the link tag. If null, the attribute will not be generated.
746: * @param array $options other options in name-value pairs
747: * @return static the CClientScript object itself (to support method chaining, available since version 1.1.5).
748: */
749: public function registerLinkTag($relation=null,$type=null,$href=null,$media=null,$options=array())
750: {
751: $this->hasScripts=true;
752: if($relation!==null)
753: $options['rel']=$relation;
754: if($type!==null)
755: $options['type']=$type;
756: if($href!==null)
757: $options['href']=$href;
758: if($media!==null)
759: $options['media']=$media;
760: $this->linkTags[serialize($options)]=$options;
761: $params=func_get_args();
762: $this->recordCachingAction('clientScript','registerLinkTag',$params);
763: return $this;
764: }
765:
766: /**
767: * Checks whether the CSS file has been registered.
768: * @param string $url URL of the CSS file
769: * @return boolean whether the CSS file is already registered
770: */
771: public function isCssFileRegistered($url)
772: {
773: return isset($this->cssFiles[$url]);
774: }
775:
776: /**
777: * Checks whether the CSS code has been registered.
778: * @param string $id ID that uniquely identifies the CSS code
779: * @return boolean whether the CSS code is already registered
780: */
781: public function isCssRegistered($id)
782: {
783: return isset($this->css[$id]);
784: }
785:
786: /**
787: * Checks whether the JavaScript file has been registered.
788: * @param string $url URL of the javascript file
789: * @param integer $position the position of the JavaScript code. Valid values include the following:
790: * <ul>
791: * <li>CClientScript::POS_HEAD : the script is inserted in the head section right before the title element.</li>
792: * <li>CClientScript::POS_BEGIN : the script is inserted at the beginning of the body section.</li>
793: * <li>CClientScript::POS_END : the script is inserted at the end of the body section.</li>
794: * </ul>
795: * @return boolean whether the javascript file is already registered
796: */
797: public function isScriptFileRegistered($url,$position=self::POS_HEAD)
798: {
799: return isset($this->scriptFiles[$position][$url]);
800: }
801:
802: /**
803: * Checks whether the JavaScript code has been registered.
804: * @param string $id ID that uniquely identifies the JavaScript code
805: * @param integer $position the position of the JavaScript code. Valid values include the following:
806: * <ul>
807: * <li>CClientScript::POS_HEAD : the script is inserted in the head section right before the title element.</li>
808: * <li>CClientScript::POS_BEGIN : the script is inserted at the beginning of the body section.</li>
809: * <li>CClientScript::POS_END : the script is inserted at the end of the body section.</li>
810: * <li>CClientScript::POS_LOAD : the script is inserted in the window.onload() function.</li>
811: * <li>CClientScript::POS_READY : the script is inserted in the jQuery's ready function.</li>
812: * </ul>
813: * @return boolean whether the javascript code is already registered
814: */
815: public function isScriptRegistered($id,$position=self::POS_READY)
816: {
817: return isset($this->scripts[$position][$id]);
818: }
819:
820: /**
821: * Records a method call when an output cache is in effect.
822: * This is a shortcut to Yii::app()->controller->recordCachingAction.
823: * In case when controller is absent, nothing is recorded.
824: * @param string $context a property name of the controller. It refers to an object
825: * whose method is being called. If empty it means the controller itself.
826: * @param string $method the method name
827: * @param array $params parameters passed to the method
828: * @see COutputCache
829: */
830: protected function recordCachingAction($context,$method,$params)
831: {
832: if(($controller=Yii::app()->getController())!==null)
833: $controller->recordCachingAction($context,$method,$params);
834: }
835:
836: /**
837: * Adds a package to packages list.
838: *
839: * @param string $name the name of the script package.
840: * @param array $definition the definition array of the script package,
841: * @see CClientScript::packages.
842: * @return static the CClientScript object itself (to support method chaining, available since version 1.1.10).
843: *
844: * @since 1.1.9
845: */
846: public function addPackage($name,$definition)
847: {
848: $this->packages[$name]=$definition;
849: return $this;
850: }
851: }
852: