PageRenderTime 50ms CodeModel.GetById 22ms RepoModel.GetById 1ms app.codeStats 0ms

/library/Zend/View/Helper/HeadScript.php

https://bitbucket.org/dbaltas/zend-framework-1.x-on-git
PHP | 508 lines | 274 code | 51 blank | 183 comment | 50 complexity | 29e4f19de671fe70ba028b8dc523c7a5 MD5 | raw file
Possible License(s): BSD-3-Clause, LGPL-2.0, MIT
  1. <?php
  2. /**
  3. * Zend Framework
  4. *
  5. * LICENSE
  6. *
  7. * This source file is subject to the new BSD license that is bundled
  8. * with this package in the file LICENSE.txt.
  9. * It is also available through the world-wide-web at this URL:
  10. * http://framework.zend.com/license/new-bsd
  11. * If you did not receive a copy of the license and are unable to
  12. * obtain it through the world-wide-web, please send an email
  13. * to license@zend.com so we can send you a copy immediately.
  14. *
  15. * @category Zend
  16. * @package Zend_View
  17. * @subpackage Helper
  18. * @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
  19. * @version $Id: HeadScript.php 24960 2012-06-15 14:09:34Z adamlundrigan $
  20. * @license http://framework.zend.com/license/new-bsd New BSD License
  21. */
  22. /** Zend_View_Helper_Placeholder_Container_Standalone */
  23. require_once 'Zend/View/Helper/Placeholder/Container/Standalone.php';
  24. /**
  25. * Helper for setting and retrieving script elements for HTML head section
  26. *
  27. * @uses Zend_View_Helper_Placeholder_Container_Standalone
  28. * @package Zend_View
  29. * @subpackage Helper
  30. * @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
  31. * @license http://framework.zend.com/license/new-bsd New BSD License
  32. */
  33. class Zend_View_Helper_HeadScript extends Zend_View_Helper_Placeholder_Container_Standalone
  34. {
  35. /**#@+
  36. * Script type contants
  37. * @const string
  38. */
  39. const FILE = 'FILE';
  40. const SCRIPT = 'SCRIPT';
  41. /**#@-*/
  42. /**
  43. * Registry key for placeholder
  44. * @var string
  45. */
  46. protected $_regKey = 'Zend_View_Helper_HeadScript';
  47. /**
  48. * Are arbitrary attributes allowed?
  49. * @var bool
  50. */
  51. protected $_arbitraryAttributes = false;
  52. /**#@+
  53. * Capture type and/or attributes (used for hinting during capture)
  54. * @var string
  55. */
  56. protected $_captureLock;
  57. protected $_captureScriptType = null;
  58. protected $_captureScriptAttrs = null;
  59. protected $_captureType;
  60. /**#@-*/
  61. /**
  62. * Optional allowed attributes for script tag
  63. * @var array
  64. */
  65. protected $_optionalAttributes = array(
  66. 'charset', 'defer', 'language', 'src'
  67. );
  68. /**
  69. * Required attributes for script tag
  70. * @var string
  71. */
  72. protected $_requiredAttributes = array('type');
  73. /**
  74. * Whether or not to format scripts using CDATA; used only if doctype
  75. * helper is not accessible
  76. * @var bool
  77. */
  78. public $useCdata = false;
  79. /**
  80. * Constructor
  81. *
  82. * Set separator to PHP_EOL.
  83. *
  84. * @return void
  85. */
  86. public function __construct()
  87. {
  88. parent::__construct();
  89. $this->setSeparator(PHP_EOL);
  90. }
  91. /**
  92. * Return headScript object
  93. *
  94. * Returns headScript helper object; optionally, allows specifying a script
  95. * or script file to include.
  96. *
  97. * @param string $mode Script or file
  98. * @param string $spec Script/url
  99. * @param string $placement Append, prepend, or set
  100. * @param array $attrs Array of script attributes
  101. * @param string $type Script type and/or array of script attributes
  102. * @return Zend_View_Helper_HeadScript
  103. */
  104. public function headScript($mode = Zend_View_Helper_HeadScript::FILE, $spec = null, $placement = 'APPEND', array $attrs = array(), $type = 'text/javascript')
  105. {
  106. if ((null !== $spec) && is_string($spec)) {
  107. $action = ucfirst(strtolower($mode));
  108. $placement = strtolower($placement);
  109. switch ($placement) {
  110. case 'set':
  111. case 'prepend':
  112. case 'append':
  113. $action = $placement . $action;
  114. break;
  115. default:
  116. $action = 'append' . $action;
  117. break;
  118. }
  119. $this->$action($spec, $type, $attrs);
  120. }
  121. return $this;
  122. }
  123. /**
  124. * Start capture action
  125. *
  126. * @param mixed $captureType
  127. * @param string $typeOrAttrs
  128. * @return void
  129. */
  130. public function captureStart($captureType = Zend_View_Helper_Placeholder_Container_Abstract::APPEND, $type = 'text/javascript', $attrs = array())
  131. {
  132. if ($this->_captureLock) {
  133. require_once 'Zend/View/Helper/Placeholder/Container/Exception.php';
  134. $e = new Zend_View_Helper_Placeholder_Container_Exception('Cannot nest headScript captures');
  135. $e->setView($this->view);
  136. throw $e;
  137. }
  138. $this->_captureLock = true;
  139. $this->_captureType = $captureType;
  140. $this->_captureScriptType = $type;
  141. $this->_captureScriptAttrs = $attrs;
  142. ob_start();
  143. }
  144. /**
  145. * End capture action and store
  146. *
  147. * @return void
  148. */
  149. public function captureEnd()
  150. {
  151. $content = ob_get_clean();
  152. $type = $this->_captureScriptType;
  153. $attrs = $this->_captureScriptAttrs;
  154. $this->_captureScriptType = null;
  155. $this->_captureScriptAttrs = null;
  156. $this->_captureLock = false;
  157. switch ($this->_captureType) {
  158. case Zend_View_Helper_Placeholder_Container_Abstract::SET:
  159. case Zend_View_Helper_Placeholder_Container_Abstract::PREPEND:
  160. case Zend_View_Helper_Placeholder_Container_Abstract::APPEND:
  161. $action = strtolower($this->_captureType) . 'Script';
  162. break;
  163. default:
  164. $action = 'appendScript';
  165. break;
  166. }
  167. $this->$action($content, $type, $attrs);
  168. }
  169. /**
  170. * Overload method access
  171. *
  172. * Allows the following method calls:
  173. * - appendFile($src, $type = 'text/javascript', $attrs = array())
  174. * - offsetSetFile($index, $src, $type = 'text/javascript', $attrs = array())
  175. * - prependFile($src, $type = 'text/javascript', $attrs = array())
  176. * - setFile($src, $type = 'text/javascript', $attrs = array())
  177. * - appendScript($script, $type = 'text/javascript', $attrs = array())
  178. * - offsetSetScript($index, $src, $type = 'text/javascript', $attrs = array())
  179. * - prependScript($script, $type = 'text/javascript', $attrs = array())
  180. * - setScript($script, $type = 'text/javascript', $attrs = array())
  181. *
  182. * @param string $method
  183. * @param array $args
  184. * @return Zend_View_Helper_HeadScript
  185. * @throws Zend_View_Exception if too few arguments or invalid method
  186. */
  187. public function __call($method, $args)
  188. {
  189. if (preg_match('/^(?P<action>set|(ap|pre)pend|offsetSet)(?P<mode>File|Script)$/', $method, $matches)) {
  190. if (1 > count($args)) {
  191. require_once 'Zend/View/Exception.php';
  192. $e = new Zend_View_Exception(sprintf('Method "%s" requires at least one argument', $method));
  193. $e->setView($this->view);
  194. throw $e;
  195. }
  196. $action = $matches['action'];
  197. $mode = strtolower($matches['mode']);
  198. $type = 'text/javascript';
  199. $attrs = array();
  200. if ('offsetSet' == $action) {
  201. $index = array_shift($args);
  202. if (1 > count($args)) {
  203. require_once 'Zend/View/Exception.php';
  204. $e = new Zend_View_Exception(sprintf('Method "%s" requires at least two arguments, an index and source', $method));
  205. $e->setView($this->view);
  206. throw $e;
  207. }
  208. }
  209. $content = $args[0];
  210. if (isset($args[1])) {
  211. $type = (string) $args[1];
  212. }
  213. if (isset($args[2])) {
  214. $attrs = (array) $args[2];
  215. }
  216. switch ($mode) {
  217. case 'script':
  218. $item = $this->createData($type, $attrs, $content);
  219. if ('offsetSet' == $action) {
  220. $this->offsetSet($index, $item);
  221. } else {
  222. $this->$action($item);
  223. }
  224. break;
  225. case 'file':
  226. default:
  227. if (!$this->_isDuplicate($content) || $action=='set') {
  228. $attrs['src'] = $content;
  229. $item = $this->createData($type, $attrs);
  230. if ('offsetSet' == $action) {
  231. $this->offsetSet($index, $item);
  232. } else {
  233. $this->$action($item);
  234. }
  235. }
  236. break;
  237. }
  238. return $this;
  239. }
  240. return parent::__call($method, $args);
  241. }
  242. /**
  243. * Is the file specified a duplicate?
  244. *
  245. * @param string $file
  246. * @return bool
  247. */
  248. protected function _isDuplicate($file)
  249. {
  250. foreach ($this->getContainer() as $item) {
  251. if (($item->source === null)
  252. && array_key_exists('src', $item->attributes)
  253. && ($file == $item->attributes['src']))
  254. {
  255. return true;
  256. }
  257. }
  258. return false;
  259. }
  260. /**
  261. * Is the script provided valid?
  262. *
  263. * @param mixed $value
  264. * @param string $method
  265. * @return bool
  266. */
  267. protected function _isValid($value)
  268. {
  269. if ((!$value instanceof stdClass)
  270. || !isset($value->type)
  271. || (!isset($value->source) && !isset($value->attributes)))
  272. {
  273. return false;
  274. }
  275. return true;
  276. }
  277. /**
  278. * Override append
  279. *
  280. * @param string $value
  281. * @return void
  282. */
  283. public function append($value)
  284. {
  285. if (!$this->_isValid($value)) {
  286. require_once 'Zend/View/Exception.php';
  287. $e = new Zend_View_Exception('Invalid argument passed to append(); please use one of the helper methods, appendScript() or appendFile()');
  288. $e->setView($this->view);
  289. throw $e;
  290. }
  291. return $this->getContainer()->append($value);
  292. }
  293. /**
  294. * Override prepend
  295. *
  296. * @param string $value
  297. * @return void
  298. */
  299. public function prepend($value)
  300. {
  301. if (!$this->_isValid($value)) {
  302. require_once 'Zend/View/Exception.php';
  303. $e = new Zend_View_Exception('Invalid argument passed to prepend(); please use one of the helper methods, prependScript() or prependFile()');
  304. $e->setView($this->view);
  305. throw $e;
  306. }
  307. return $this->getContainer()->prepend($value);
  308. }
  309. /**
  310. * Override set
  311. *
  312. * @param string $value
  313. * @return void
  314. */
  315. public function set($value)
  316. {
  317. if (!$this->_isValid($value)) {
  318. require_once 'Zend/View/Exception.php';
  319. $e = new Zend_View_Exception('Invalid argument passed to set(); please use one of the helper methods, setScript() or setFile()');
  320. $e->setView($this->view);
  321. throw $e;
  322. }
  323. return $this->getContainer()->set($value);
  324. }
  325. /**
  326. * Override offsetSet
  327. *
  328. * @param string|int $index
  329. * @param mixed $value
  330. * @return void
  331. */
  332. public function offsetSet($index, $value)
  333. {
  334. if (!$this->_isValid($value)) {
  335. require_once 'Zend/View/Exception.php';
  336. $e = new Zend_View_Exception('Invalid argument passed to offsetSet(); please use one of the helper methods, offsetSetScript() or offsetSetFile()');
  337. $e->setView($this->view);
  338. throw $e;
  339. }
  340. return $this->getContainer()->offsetSet($index, $value);
  341. }
  342. /**
  343. * Set flag indicating if arbitrary attributes are allowed
  344. *
  345. * @param bool $flag
  346. * @return Zend_View_Helper_HeadScript
  347. */
  348. public function setAllowArbitraryAttributes($flag)
  349. {
  350. $this->_arbitraryAttributes = (bool) $flag;
  351. return $this;
  352. }
  353. /**
  354. * Are arbitrary attributes allowed?
  355. *
  356. * @return bool
  357. */
  358. public function arbitraryAttributesAllowed()
  359. {
  360. return $this->_arbitraryAttributes;
  361. }
  362. /**
  363. * Create script HTML
  364. *
  365. * @param string $type
  366. * @param array $attributes
  367. * @param string $content
  368. * @param string|int $indent
  369. * @return string
  370. */
  371. public function itemToString($item, $indent, $escapeStart, $escapeEnd)
  372. {
  373. $attrString = '';
  374. if (!empty($item->attributes)) {
  375. foreach ($item->attributes as $key => $value) {
  376. if ((!$this->arbitraryAttributesAllowed() && !in_array($key, $this->_optionalAttributes))
  377. || in_array($key, array('conditional', 'noescape')))
  378. {
  379. continue;
  380. }
  381. if ('defer' == $key) {
  382. $value = 'defer';
  383. }
  384. $attrString .= sprintf(' %s="%s"', $key, ($this->_autoEscape) ? $this->_escape($value) : $value);
  385. }
  386. }
  387. $addScriptEscape = !(isset($item->attributes['noescape']) && filter_var($item->attributes['noescape'], FILTER_VALIDATE_BOOLEAN));
  388. $type = ($this->_autoEscape) ? $this->_escape($item->type) : $item->type;
  389. $html = '<script type="' . $type . '"' . $attrString . '>';
  390. if (!empty($item->source)) {
  391. $html .= PHP_EOL ;
  392. if ($addScriptEscape) {
  393. $html .= $indent . ' ' . $escapeStart . PHP_EOL;
  394. }
  395. $html .= $indent . ' ' . $item->source;
  396. if ($addScriptEscape) {
  397. $html .= $indent . ' ' . $escapeEnd . PHP_EOL;
  398. }
  399. $html .= $indent;
  400. }
  401. $html .= '</script>';
  402. if (isset($item->attributes['conditional'])
  403. && !empty($item->attributes['conditional'])
  404. && is_string($item->attributes['conditional']))
  405. {
  406. $html = $indent . '<!--[if ' . $item->attributes['conditional'] . ']> ' . $html . '<![endif]-->';
  407. } else {
  408. $html = $indent . $html;
  409. }
  410. return $html;
  411. }
  412. /**
  413. * Retrieve string representation
  414. *
  415. * @param string|int $indent
  416. * @return string
  417. */
  418. public function toString($indent = null)
  419. {
  420. $indent = (null !== $indent)
  421. ? $this->getWhitespace($indent)
  422. : $this->getIndent();
  423. if ($this->view) {
  424. $useCdata = $this->view->doctype()->isXhtml() ? true : false;
  425. } else {
  426. $useCdata = $this->useCdata ? true : false;
  427. }
  428. $escapeStart = ($useCdata) ? '//<![CDATA[' : '//<!--';
  429. $escapeEnd = ($useCdata) ? '//]]>' : '//-->';
  430. $items = array();
  431. $this->getContainer()->ksort();
  432. foreach ($this as $item) {
  433. if (!$this->_isValid($item)) {
  434. continue;
  435. }
  436. $items[] = $this->itemToString($item, $indent, $escapeStart, $escapeEnd);
  437. }
  438. $return = implode($this->getSeparator(), $items);
  439. return $return;
  440. }
  441. /**
  442. * Create data item containing all necessary components of script
  443. *
  444. * @param string $type
  445. * @param array $attributes
  446. * @param string $content
  447. * @return stdClass
  448. */
  449. public function createData($type, array $attributes, $content = null)
  450. {
  451. $data = new stdClass();
  452. $data->type = $type;
  453. $data->attributes = $attributes;
  454. $data->source = $content;
  455. return $data;
  456. }
  457. }