View.php 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724
  1. <?php
  2. /**
  3. * @link https://www.yiiframework.com/
  4. * @copyright Copyright (c) 2008 Yii Software LLC
  5. * @license https://www.yiiframework.com/license/
  6. */
  7. namespace yii\web;
  8. use Yii;
  9. use yii\base\InvalidConfigException;
  10. use yii\helpers\ArrayHelper;
  11. use yii\helpers\Html;
  12. use yii\helpers\Url;
  13. /**
  14. * View represents a view object in the MVC pattern.
  15. *
  16. * View provides a set of methods (e.g. [[render()]]) for rendering purpose.
  17. *
  18. * View is configured as an application component in [[\yii\base\Application]] by default.
  19. * You can access that instance via `Yii::$app->view`.
  20. *
  21. * You can modify its configuration by adding an array to your application config under `components`
  22. * as it is shown in the following example:
  23. *
  24. * ```php
  25. * 'view' => [
  26. * 'theme' => 'app\themes\MyTheme',
  27. * 'renderers' => [
  28. * // you may add Smarty or Twig renderer here
  29. * ]
  30. * // ...
  31. * ]
  32. * ```
  33. *
  34. * For more details and usage information on View, see the [guide article on views](guide:structure-views).
  35. *
  36. * @property \yii\web\AssetManager $assetManager The asset manager. Defaults to the "assetManager" application
  37. * component.
  38. *
  39. * @author Qiang Xue <qiang.xue@gmail.com>
  40. * @since 2.0
  41. *
  42. * @phpstan-type RegisterJsFileOptions array{
  43. * depends?: class-string[],
  44. * position?: int,
  45. * appendTimestamp?: boolean
  46. * }
  47. *
  48. * @psalm-type RegisterJsFileOptions = array{
  49. * depends?: class-string[],
  50. * position?: int,
  51. * appendTimestamp?: boolean
  52. * }
  53. *
  54. * @phpstan-type RegisterCssFileOptions array{
  55. * depends?: class-string[],
  56. * appendTimestamp?: boolean
  57. * }
  58. *
  59. * @psalm-type RegisterCssFileOptions = array{
  60. * depends?: class-string[],
  61. * appendTimestamp?: boolean
  62. * }
  63. */
  64. class View extends \yii\base\View
  65. {
  66. /**
  67. * @event Event an event that is triggered by [[beginBody()]].
  68. */
  69. const EVENT_BEGIN_BODY = 'beginBody';
  70. /**
  71. * @event Event an event that is triggered by [[endBody()]].
  72. */
  73. const EVENT_END_BODY = 'endBody';
  74. /**
  75. * The location of registered JavaScript code block or files.
  76. * This means the location is in the head section.
  77. */
  78. const POS_HEAD = 1;
  79. /**
  80. * The location of registered JavaScript code block or files.
  81. * This means the location is at the beginning of the body section.
  82. */
  83. const POS_BEGIN = 2;
  84. /**
  85. * The location of registered JavaScript code block or files.
  86. * This means the location is at the end of the body section.
  87. */
  88. const POS_END = 3;
  89. /**
  90. * The location of registered JavaScript code block.
  91. * This means the JavaScript code block will be enclosed within `jQuery(document).ready()`.
  92. */
  93. const POS_READY = 4;
  94. /**
  95. * The location of registered JavaScript code block.
  96. * This means the JavaScript code block will be enclosed within `jQuery(window).load()`.
  97. */
  98. const POS_LOAD = 5;
  99. /**
  100. * This is internally used as the placeholder for receiving the content registered for the head section.
  101. */
  102. const PH_HEAD = '<![CDATA[YII-BLOCK-HEAD]]>';
  103. /**
  104. * This is internally used as the placeholder for receiving the content registered for the beginning of the body section.
  105. */
  106. const PH_BODY_BEGIN = '<![CDATA[YII-BLOCK-BODY-BEGIN]]>';
  107. /**
  108. * This is internally used as the placeholder for receiving the content registered for the end of the body section.
  109. */
  110. const PH_BODY_END = '<![CDATA[YII-BLOCK-BODY-END]]>';
  111. /**
  112. * @var AssetBundle[] list of the registered asset bundles. The keys are the bundle names, and the values
  113. * are the registered [[AssetBundle]] objects.
  114. * @see registerAssetBundle()
  115. */
  116. public $assetBundles = [];
  117. /**
  118. * @var string the page title
  119. */
  120. public $title;
  121. /**
  122. * @var array the registered meta tags.
  123. * @see registerMetaTag()
  124. */
  125. public $metaTags = [];
  126. /**
  127. * @var array the registered link tags.
  128. * @see registerLinkTag()
  129. */
  130. public $linkTags = [];
  131. /**
  132. * @var array the registered CSS code blocks.
  133. * @see registerCss()
  134. */
  135. public $css = [];
  136. /**
  137. * @var array the registered CSS files.
  138. * @see registerCssFile()
  139. */
  140. public $cssFiles = [];
  141. /**
  142. * @since 2.0.53
  143. * @var array the style tag options.
  144. */
  145. public $styleOptions = [];
  146. /**
  147. * @var array the registered JS code blocks
  148. * @see registerJs()
  149. */
  150. public $js = [];
  151. /**
  152. * @var array the registered JS files.
  153. * @see registerJsFile()
  154. */
  155. public $jsFiles = [];
  156. /**
  157. * @since 2.0.50
  158. * @var array the script tag options.
  159. */
  160. public $scriptOptions = [];
  161. private $_assetManager;
  162. /**
  163. * Whether [[endPage()]] has been called and all files have been registered
  164. * @var bool
  165. * @since 2.0.44
  166. */
  167. protected $isPageEnded = false;
  168. /**
  169. * Marks the position of an HTML head section.
  170. */
  171. public function head()
  172. {
  173. echo self::PH_HEAD;
  174. }
  175. /**
  176. * Marks the beginning of an HTML body section.
  177. */
  178. public function beginBody()
  179. {
  180. echo self::PH_BODY_BEGIN;
  181. $this->trigger(self::EVENT_BEGIN_BODY);
  182. }
  183. /**
  184. * Marks the ending of an HTML body section.
  185. */
  186. public function endBody()
  187. {
  188. $this->trigger(self::EVENT_END_BODY);
  189. echo self::PH_BODY_END;
  190. foreach (array_keys($this->assetBundles) as $bundle) {
  191. $this->registerAssetFiles($bundle);
  192. }
  193. }
  194. /**
  195. * Marks the ending of an HTML page.
  196. * @param bool $ajaxMode whether the view is rendering in AJAX mode.
  197. * If true, the JS scripts registered at [[POS_READY]] and [[POS_LOAD]] positions
  198. * will be rendered at the end of the view like normal scripts.
  199. */
  200. public function endPage($ajaxMode = false)
  201. {
  202. $this->trigger(self::EVENT_END_PAGE);
  203. $this->isPageEnded = true;
  204. $content = ob_get_clean();
  205. echo strtr($content, [
  206. self::PH_HEAD => $this->renderHeadHtml(),
  207. self::PH_BODY_BEGIN => $this->renderBodyBeginHtml(),
  208. self::PH_BODY_END => $this->renderBodyEndHtml($ajaxMode),
  209. ]);
  210. $this->clear();
  211. }
  212. /**
  213. * Renders a view in response to an AJAX request.
  214. *
  215. * This method is similar to [[render()]] except that it will surround the view being rendered
  216. * with the calls of [[beginPage()]], [[head()]], [[beginBody()]], [[endBody()]] and [[endPage()]].
  217. * By doing so, the method is able to inject into the rendering result with JS/CSS scripts and files
  218. * that are registered with the view.
  219. *
  220. * @param string $view the view name. Please refer to [[render()]] on how to specify this parameter.
  221. * @param array $params the parameters (name-value pairs) that will be extracted and made available in the view file.
  222. * @param object|null $context the context that the view should use for rendering the view. If null,
  223. * existing [[context]] will be used.
  224. * @return string the rendering result
  225. * @see render()
  226. */
  227. public function renderAjax($view, $params = [], $context = null)
  228. {
  229. $viewFile = $this->findViewFile($view, $context);
  230. ob_start();
  231. ob_implicit_flush(false);
  232. $this->beginPage();
  233. $this->head();
  234. $this->beginBody();
  235. echo $this->renderFile($viewFile, $params, $context);
  236. $this->endBody();
  237. $this->endPage(true);
  238. return ob_get_clean();
  239. }
  240. /**
  241. * Registers the asset manager being used by this view object.
  242. * @return \yii\web\AssetManager the asset manager. Defaults to the "assetManager" application component.
  243. */
  244. public function getAssetManager()
  245. {
  246. return $this->_assetManager ?: Yii::$app->getAssetManager();
  247. }
  248. /**
  249. * Sets the asset manager.
  250. * @param \yii\web\AssetManager $value the asset manager
  251. */
  252. public function setAssetManager($value)
  253. {
  254. $this->_assetManager = $value;
  255. }
  256. /**
  257. * Clears up the registered meta tags, link tags, css/js scripts and files.
  258. */
  259. public function clear()
  260. {
  261. $this->metaTags = [];
  262. $this->linkTags = [];
  263. $this->css = [];
  264. $this->cssFiles = [];
  265. $this->js = [];
  266. $this->jsFiles = [];
  267. $this->assetBundles = [];
  268. }
  269. /**
  270. * Registers all files provided by an asset bundle including depending bundles files.
  271. * Removes a bundle from [[assetBundles]] once files are registered.
  272. * @param string $name name of the bundle to register
  273. */
  274. protected function registerAssetFiles($name)
  275. {
  276. if (!isset($this->assetBundles[$name])) {
  277. return;
  278. }
  279. $bundle = $this->assetBundles[$name];
  280. if ($bundle) {
  281. foreach ($bundle->depends as $dep) {
  282. $this->registerAssetFiles($dep);
  283. }
  284. $bundle->registerAssetFiles($this);
  285. }
  286. unset($this->assetBundles[$name]);
  287. }
  288. /**
  289. * Registers the named asset bundle.
  290. * All dependent asset bundles will be registered.
  291. * @param string $name the class name of the asset bundle (without the leading backslash)
  292. * @param int|null $position if set, this forces a minimum position for javascript files.
  293. * This will adjust depending assets javascript file position or fail if requirement can not be met.
  294. * If this is null, asset bundles position settings will not be changed.
  295. * See [[registerJsFile]] for more details on javascript position.
  296. * @return AssetBundle the registered asset bundle instance
  297. * @throws InvalidConfigException if the asset bundle does not exist or a circular dependency is detected
  298. */
  299. public function registerAssetBundle($name, $position = null)
  300. {
  301. if (!isset($this->assetBundles[$name])) {
  302. $am = $this->getAssetManager();
  303. $bundle = $am->getBundle($name);
  304. $this->assetBundles[$name] = false;
  305. // register dependencies
  306. $pos = isset($bundle->jsOptions['position']) ? $bundle->jsOptions['position'] : null;
  307. foreach ($bundle->depends as $dep) {
  308. $this->registerAssetBundle($dep, $pos);
  309. }
  310. $this->assetBundles[$name] = $bundle;
  311. } elseif ($this->assetBundles[$name] === false) {
  312. throw new InvalidConfigException("A circular dependency is detected for bundle '$name'.");
  313. } else {
  314. $bundle = $this->assetBundles[$name];
  315. }
  316. if ($position !== null) {
  317. $pos = isset($bundle->jsOptions['position']) ? $bundle->jsOptions['position'] : null;
  318. if ($pos === null) {
  319. $bundle->jsOptions['position'] = $pos = $position;
  320. } elseif ($pos > $position) {
  321. throw new InvalidConfigException("An asset bundle that depends on '$name' has a higher javascript file position configured than '$name'.");
  322. }
  323. // update position for all dependencies
  324. foreach ($bundle->depends as $dep) {
  325. $this->registerAssetBundle($dep, $pos);
  326. }
  327. }
  328. return $bundle;
  329. }
  330. /**
  331. * Registers a meta tag.
  332. *
  333. * For example, a description meta tag can be added like the following:
  334. *
  335. * ```php
  336. * $view->registerMetaTag([
  337. * 'name' => 'description',
  338. * 'content' => 'This website is about funny raccoons.'
  339. * ]);
  340. * ```
  341. *
  342. * will result in the meta tag `<meta name="description" content="This website is about funny raccoons.">`.
  343. *
  344. * @param array $options the HTML attributes for the meta tag.
  345. * @param string|null $key the key that identifies the meta tag. If two meta tags are registered
  346. * with the same key, the latter will overwrite the former. If this is null, the new meta tag
  347. * will be appended to the existing ones.
  348. */
  349. public function registerMetaTag($options, $key = null)
  350. {
  351. if ($key === null) {
  352. $this->metaTags[] = Html::tag('meta', '', $options);
  353. } else {
  354. $this->metaTags[$key] = Html::tag('meta', '', $options);
  355. }
  356. }
  357. /**
  358. * Registers CSRF meta tags.
  359. * They are rendered dynamically to retrieve a new CSRF token for each request.
  360. *
  361. * ```php
  362. * $view->registerCsrfMetaTags();
  363. * ```
  364. *
  365. * The above code will result in `<meta name="csrf-param" content="[yii\web\Request::$csrfParam]">`
  366. * and `<meta name="csrf-token" content="tTNpWKpdy-bx8ZmIq9R72...K1y8IP3XGkzZA==">` added to the page.
  367. *
  368. * Note: Hidden CSRF input of ActiveForm will be automatically refreshed by calling `window.yii.refreshCsrfToken()`
  369. * from `yii.js`.
  370. *
  371. * @since 2.0.13
  372. */
  373. public function registerCsrfMetaTags()
  374. {
  375. $this->metaTags['csrf_meta_tags'] = $this->renderDynamic('return yii\helpers\Html::csrfMetaTags();');
  376. }
  377. /**
  378. * Registers a link tag.
  379. *
  380. * For example, a link tag for a custom [favicon](https://www.w3.org/2005/10/howto-favicon)
  381. * can be added like the following:
  382. *
  383. * ```php
  384. * $view->registerLinkTag(['rel' => 'icon', 'type' => 'image/png', 'href' => '/myicon.png']);
  385. * ```
  386. *
  387. * which will result in the following HTML: `<link rel="icon" type="image/png" href="/myicon.png">`.
  388. *
  389. * **Note:** To register link tags for CSS stylesheets, use [[registerCssFile()]] instead, which
  390. * has more options for this kind of link tag.
  391. *
  392. * @param array $options the HTML attributes for the link tag.
  393. * @param string|null $key the key that identifies the link tag. If two link tags are registered
  394. * with the same key, the latter will overwrite the former. If this is null, the new link tag
  395. * will be appended to the existing ones.
  396. */
  397. public function registerLinkTag($options, $key = null)
  398. {
  399. if ($key === null) {
  400. $this->linkTags[] = Html::tag('link', '', $options);
  401. } else {
  402. $this->linkTags[$key] = Html::tag('link', '', $options);
  403. }
  404. }
  405. /**
  406. * Registers a CSS code block.
  407. * @param string $css the content of the CSS code block to be registered
  408. * @param array $options the HTML attributes for the `<style>`-tag.
  409. * @param string|null $key the key that identifies the CSS code block. If null, it will use
  410. * $css as the key. If two CSS code blocks are registered with the same key, the latter
  411. * will overwrite the former.
  412. */
  413. public function registerCss($css, $options = [], $key = null)
  414. {
  415. $key = $key ?: md5($css);
  416. $this->css[$key] = Html::style($css, $options);
  417. }
  418. /**
  419. * Registers a CSS file.
  420. *
  421. * This method should be used for simple registration of CSS files. If you want to use features of
  422. * [[AssetManager]] like appending timestamps to the URL and file publishing options, use [[AssetBundle]]
  423. * and [[registerAssetBundle()]] instead.
  424. *
  425. * @param string $url the CSS file to be registered.
  426. * @param array $options the HTML attributes for the link tag. Please refer to [[Html::cssFile()]] for
  427. * the supported options. The following options are specially handled and are not treated as HTML attributes:
  428. *
  429. * - `depends`: array, specifies the names of the asset bundles that this CSS file depends on.
  430. * - `appendTimestamp`: bool whether to append a timestamp to the URL.
  431. *
  432. * @param string|null $key the key that identifies the CSS script file. If null, it will use
  433. * $url as the key. If two CSS files are registered with the same key, the latter
  434. * will overwrite the former.
  435. * @throws InvalidConfigException
  436. *
  437. * @phpstan-param RegisterCssFileOptions $options
  438. * @psalm-param RegisterCssFileOptions $options
  439. */
  440. public function registerCssFile($url, $options = [], $key = null)
  441. {
  442. $this->registerFile('css', $url, $options, $key);
  443. }
  444. /**
  445. * Registers a JS code block.
  446. * @param string $js the JS code block to be registered
  447. * @param int $position the position at which the JS script tag should be inserted
  448. * in a page. The possible values are:
  449. *
  450. * - [[POS_HEAD]]: in the head section
  451. * - [[POS_BEGIN]]: at the beginning of the body section
  452. * - [[POS_END]]: at the end of the body section
  453. * - [[POS_LOAD]]: enclosed within jQuery(window).load().
  454. * Note that by using this position, the method will automatically register the jQuery js file.
  455. * - [[POS_READY]]: enclosed within jQuery(document).ready(). This is the default value.
  456. * Note that by using this position, the method will automatically register the jQuery js file.
  457. *
  458. * @param string|null $key the key that identifies the JS code block. If null, it will use
  459. * $js as the key. If two JS code blocks are registered with the same key, the latter
  460. * will overwrite the former.
  461. */
  462. public function registerJs($js, $position = self::POS_READY, $key = null)
  463. {
  464. $key = $key ?: md5($js);
  465. $this->js[$position][$key] = $js;
  466. if ($position === self::POS_READY || $position === self::POS_LOAD) {
  467. JqueryAsset::register($this);
  468. }
  469. }
  470. /**
  471. * Registers a JS or CSS file.
  472. *
  473. * @param string $url the JS file to be registered.
  474. * @param string $type type (js or css) of the file.
  475. * @param array $options the HTML attributes for the script tag. The following options are specially handled
  476. * and are not treated as HTML attributes:
  477. *
  478. * - `depends`: array, specifies the names of the asset bundles that this CSS file depends on.
  479. * - `appendTimestamp`: bool whether to append a timestamp to the URL.
  480. *
  481. * @param string|null $key the key that identifies the JS script file. If null, it will use
  482. * $url as the key. If two JS files are registered with the same key at the same position, the latter
  483. * will overwrite the former. Note that position option takes precedence, thus files registered with the same key,
  484. * but different position option will not override each other.
  485. * @throws InvalidConfigException
  486. */
  487. private function registerFile($type, $url, $options = [], $key = null)
  488. {
  489. $url = Yii::getAlias($url);
  490. $key = $key ?: $url;
  491. $depends = ArrayHelper::remove($options, 'depends', []);
  492. $originalOptions = $options;
  493. $position = ArrayHelper::remove($options, 'position', self::POS_END);
  494. try {
  495. $assetManagerAppendTimestamp = $this->getAssetManager()->appendTimestamp;
  496. } catch (InvalidConfigException $e) {
  497. $depends = null; // the AssetManager is not available
  498. $assetManagerAppendTimestamp = false;
  499. }
  500. $appendTimestamp = ArrayHelper::remove($options, 'appendTimestamp', $assetManagerAppendTimestamp);
  501. if ($this->isPageEnded) {
  502. Yii::warning('You\'re trying to register a file after View::endPage() has been called.');
  503. }
  504. if (empty($depends)) {
  505. // register directly without AssetManager
  506. if ($appendTimestamp && Url::isRelative($url)) {
  507. $prefix = Yii::getAlias('@web');
  508. $prefixLength = strlen($prefix);
  509. $trimmedUrl = ltrim((substr($url, 0, $prefixLength) === $prefix) ? substr($url, $prefixLength) : $url, '/');
  510. $timestamp = @filemtime(Yii::getAlias('@webroot/' . $trimmedUrl, false));
  511. if ($timestamp > 0) {
  512. $url = $timestamp ? "$url?v=$timestamp" : $url;
  513. }
  514. }
  515. if ($type === 'js') {
  516. $this->jsFiles[$position][$key] = Html::jsFile($url, $options);
  517. } else {
  518. $this->cssFiles[$key] = Html::cssFile($url, $options);
  519. }
  520. } else {
  521. $this->getAssetManager()->bundles[$key] = Yii::createObject([
  522. 'class' => AssetBundle::className(),
  523. 'baseUrl' => '',
  524. 'basePath' => '@webroot',
  525. (string)$type => [ArrayHelper::merge([!Url::isRelative($url) ? $url : ltrim($url, '/')], $originalOptions)],
  526. "{$type}Options" => $options,
  527. 'depends' => (array)$depends,
  528. ]);
  529. $this->registerAssetBundle($key);
  530. }
  531. }
  532. /**
  533. * Registers a JS file.
  534. *
  535. * This method should be used for simple registration of JS files. If you want to use features of
  536. * [[AssetManager]] like appending timestamps to the URL and file publishing options, use [[AssetBundle]]
  537. * and [[registerAssetBundle()]] instead.
  538. *
  539. * @param string $url the JS file to be registered.
  540. * @param array $options the HTML attributes for the script tag. The following options are specially handled
  541. * and are not treated as HTML attributes:
  542. *
  543. * - `depends`: array, specifies the names of the asset bundles that this JS file depends on.
  544. * - `position`: specifies where the JS script tag should be inserted in a page. The possible values are:
  545. * * [[POS_HEAD]]: in the head section
  546. * * [[POS_BEGIN]]: at the beginning of the body section
  547. * * [[POS_END]]: at the end of the body section. This is the default value.
  548. * - `appendTimestamp`: bool whether to append a timestamp to the URL.
  549. *
  550. * Please refer to [[Html::jsFile()]] for other supported options.
  551. *
  552. * @param string|null $key the key that identifies the JS script file. If null, it will use
  553. * $url as the key. If two JS files are registered with the same key at the same position, the latter
  554. * will overwrite the former. Note that position option takes precedence, thus files registered with the same key,
  555. * but different position option will not override each other.
  556. * @throws InvalidConfigException
  557. *
  558. * @phpstan-param RegisterJsFileOptions $options
  559. * @psalm-param RegisterJsFileOptions $options
  560. */
  561. public function registerJsFile($url, $options = [], $key = null)
  562. {
  563. $this->registerFile('js', $url, $options, $key);
  564. }
  565. /**
  566. * Registers a JS code block defining a variable. The name of variable will be
  567. * used as key, preventing duplicated variable names.
  568. *
  569. * @param string $name Name of the variable
  570. * @param array|string $value Value of the variable
  571. * @param int $position the position in a page at which the JavaScript variable should be inserted.
  572. * The possible values are:
  573. *
  574. * - [[POS_HEAD]]: in the head section. This is the default value.
  575. * - [[POS_BEGIN]]: at the beginning of the body section.
  576. * - [[POS_END]]: at the end of the body section.
  577. * - [[POS_LOAD]]: enclosed within jQuery(window).load().
  578. * Note that by using this position, the method will automatically register the jQuery js file.
  579. * - [[POS_READY]]: enclosed within jQuery(document).ready().
  580. * Note that by using this position, the method will automatically register the jQuery js file.
  581. *
  582. * @since 2.0.14
  583. */
  584. public function registerJsVar($name, $value, $position = self::POS_HEAD)
  585. {
  586. $js = sprintf('var %s = %s;', $name, \yii\helpers\Json::htmlEncode($value));
  587. $this->registerJs($js, $position, $name);
  588. }
  589. /**
  590. * Renders the content to be inserted in the head section.
  591. * The content is rendered using the registered meta tags, link tags, CSS/JS code blocks and files.
  592. * @return string the rendered content
  593. */
  594. protected function renderHeadHtml()
  595. {
  596. $lines = [];
  597. if (!empty($this->metaTags)) {
  598. $lines[] = implode("\n", $this->metaTags);
  599. }
  600. if (!empty($this->linkTags)) {
  601. $lines[] = implode("\n", $this->linkTags);
  602. }
  603. if (!empty($this->cssFiles)) {
  604. $lines[] = implode("\n", $this->cssFiles);
  605. }
  606. if (!empty($this->css)) {
  607. $lines[] = implode("\n", $this->css);
  608. }
  609. if (!empty($this->jsFiles[self::POS_HEAD])) {
  610. $lines[] = implode("\n", $this->jsFiles[self::POS_HEAD]);
  611. }
  612. if (!empty($this->js[self::POS_HEAD])) {
  613. $lines[] = Html::script(implode("\n", $this->js[self::POS_HEAD]));
  614. }
  615. return empty($lines) ? '' : implode("\n", $lines);
  616. }
  617. /**
  618. * Renders the content to be inserted at the beginning of the body section.
  619. * The content is rendered using the registered JS code blocks and files.
  620. * @return string the rendered content
  621. */
  622. protected function renderBodyBeginHtml()
  623. {
  624. $lines = [];
  625. if (!empty($this->jsFiles[self::POS_BEGIN])) {
  626. $lines[] = implode("\n", $this->jsFiles[self::POS_BEGIN]);
  627. }
  628. if (!empty($this->js[self::POS_BEGIN])) {
  629. $lines[] = Html::script(implode("\n", $this->js[self::POS_BEGIN]));
  630. }
  631. return empty($lines) ? '' : implode("\n", $lines);
  632. }
  633. /**
  634. * Renders the content to be inserted at the end of the body section.
  635. * The content is rendered using the registered JS code blocks and files.
  636. * @param bool $ajaxMode whether the view is rendering in AJAX mode.
  637. * If true, the JS scripts registered at [[POS_READY]] and [[POS_LOAD]] positions
  638. * will be rendered at the end of the view like normal scripts.
  639. * @return string the rendered content
  640. */
  641. protected function renderBodyEndHtml($ajaxMode)
  642. {
  643. $lines = [];
  644. if (!empty($this->jsFiles[self::POS_END])) {
  645. $lines[] = implode("\n", $this->jsFiles[self::POS_END]);
  646. }
  647. if ($ajaxMode) {
  648. $scripts = [];
  649. if (!empty($this->js[self::POS_END])) {
  650. $scripts[] = implode("\n", $this->js[self::POS_END]);
  651. }
  652. if (!empty($this->js[self::POS_READY])) {
  653. $scripts[] = implode("\n", $this->js[self::POS_READY]);
  654. }
  655. if (!empty($this->js[self::POS_LOAD])) {
  656. $scripts[] = implode("\n", $this->js[self::POS_LOAD]);
  657. }
  658. if (!empty($scripts)) {
  659. $lines[] = Html::script(implode("\n", $scripts));
  660. }
  661. } else {
  662. if (!empty($this->js[self::POS_END])) {
  663. $lines[] = Html::script(implode("\n", $this->js[self::POS_END]));
  664. }
  665. if (!empty($this->js[self::POS_READY])) {
  666. $js = "jQuery(function ($) {\n" . implode("\n", $this->js[self::POS_READY]) . "\n});";
  667. $lines[] = Html::script($js);
  668. }
  669. if (!empty($this->js[self::POS_LOAD])) {
  670. $js = "jQuery(window).on('load', function () {\n" . implode("\n", $this->js[self::POS_LOAD]) . "\n});";
  671. $lines[] = Html::script($js);
  672. }
  673. }
  674. return empty($lines) ? '' : implode("\n", $lines);
  675. }
  676. }