CClientScript.php 28 KB

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