File indexing completed on 2024-12-22 05:37:13
0001 <?php 0002 /** 0003 * Zend Framework 0004 * 0005 * LICENSE 0006 * 0007 * This source file is subject to the new BSD license that is bundled 0008 * with this package in the file LICENSE.txt. 0009 * It is also available through the world-wide-web at this URL: 0010 * http://framework.zend.com/license/new-bsd 0011 * If you did not receive a copy of the license and are unable to 0012 * obtain it through the world-wide-web, please send an email 0013 * to license@zend.com so we can send you a copy immediately. 0014 * 0015 * @category Zend 0016 * @package Zend_View 0017 * @subpackage Helper 0018 * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) 0019 * @version $Id$ 0020 * @license http://framework.zend.com/license/new-bsd New BSD License 0021 */ 0022 0023 /** Zend_View_Helper_Placeholder_Container_Standalone */ 0024 // require_once 'Zend/View/Helper/Placeholder/Container/Standalone.php'; 0025 0026 /** 0027 * Helper for setting and retrieving script elements for HTML head section 0028 * 0029 * @uses Zend_View_Helper_Placeholder_Container_Standalone 0030 * @package Zend_View 0031 * @subpackage Helper 0032 * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) 0033 * @license http://framework.zend.com/license/new-bsd New BSD License 0034 * @method $this appendFile($src, $type = 'text/javascript', array $attrs = array()) 0035 * @method $this appendScript($script, $type = 'text/javascript', array $attrs = array()) 0036 * @method $this offsetSetFile($index, $src, $type = 'text/javascript', array $attrs = array()) 0037 * @method $this offsetSetScript($index, $script, $type = 'text/javascript', array $attrs = array()) 0038 * @method $this prependFile($src, $type = 'text/javascript', array $attrs = array()) 0039 * @method $this prependScript($script, $type = 'text/javascript', array $attrs = array()) 0040 * @method $this setFile($src, $type = 'text/javascript', array $attrs = array()) 0041 * @method $this setScript($script, $type = 'text/javascript', array $attrs = array()) 0042 */ 0043 class Zend_View_Helper_HeadScript extends Zend_View_Helper_Placeholder_Container_Standalone 0044 { 0045 /**#@+ 0046 * Script type contants 0047 * @const string 0048 */ 0049 const FILE = 'FILE'; 0050 const SCRIPT = 'SCRIPT'; 0051 /**#@-*/ 0052 0053 /** 0054 * Registry key for placeholder 0055 * @var string 0056 */ 0057 protected $_regKey = 'Zend_View_Helper_HeadScript'; 0058 0059 /** 0060 * Are arbitrary attributes allowed? 0061 * @var bool 0062 */ 0063 protected $_arbitraryAttributes = false; 0064 0065 /**#@+ 0066 * Capture type and/or attributes (used for hinting during capture) 0067 * @var string 0068 */ 0069 protected $_captureLock; 0070 protected $_captureScriptType = null; 0071 protected $_captureScriptAttrs = null; 0072 protected $_captureType; 0073 /**#@-*/ 0074 0075 /** 0076 * Optional allowed attributes for script tag 0077 * @var array 0078 */ 0079 protected $_optionalAttributes = array( 0080 'charset', 'defer', 'language', 'src' 0081 ); 0082 0083 /** 0084 * Required attributes for script tag 0085 * @var string 0086 */ 0087 protected $_requiredAttributes = array('type'); 0088 0089 /** 0090 * Whether or not to format scripts using CDATA; used only if doctype 0091 * helper is not accessible 0092 * @var bool 0093 */ 0094 public $useCdata = false; 0095 0096 /** 0097 * Constructor 0098 * 0099 * Set separator to PHP_EOL. 0100 * 0101 * @return void 0102 */ 0103 public function __construct() 0104 { 0105 parent::__construct(); 0106 $this->setSeparator(PHP_EOL); 0107 } 0108 0109 /** 0110 * Return headScript object 0111 * 0112 * Returns headScript helper object; optionally, allows specifying a script 0113 * or script file to include. 0114 * 0115 * @param string $mode Script or file 0116 * @param string $spec Script/url 0117 * @param string $placement Append, prepend, or set 0118 * @param array $attrs Array of script attributes 0119 * @param string $type Script type and/or array of script attributes 0120 * @return Zend_View_Helper_HeadScript 0121 */ 0122 public function headScript($mode = Zend_View_Helper_HeadScript::FILE, $spec = null, $placement = 'APPEND', array $attrs = array(), $type = 'text/javascript') 0123 { 0124 if ((null !== $spec) && is_string($spec)) { 0125 $action = ucfirst(strtolower($mode)); 0126 $placement = strtolower($placement); 0127 switch ($placement) { 0128 case 'set': 0129 case 'prepend': 0130 case 'append': 0131 $action = $placement . $action; 0132 break; 0133 default: 0134 $action = 'append' . $action; 0135 break; 0136 } 0137 $this->$action($spec, $type, $attrs); 0138 } 0139 0140 return $this; 0141 } 0142 0143 /** 0144 * Start capture action 0145 * 0146 * @param mixed $captureType 0147 * @param string $typeOrAttrs 0148 * @return void 0149 */ 0150 public function captureStart($captureType = Zend_View_Helper_Placeholder_Container_Abstract::APPEND, $type = 'text/javascript', $attrs = array()) 0151 { 0152 if ($this->_captureLock) { 0153 // require_once 'Zend/View/Helper/Placeholder/Container/Exception.php'; 0154 $e = new Zend_View_Helper_Placeholder_Container_Exception('Cannot nest headScript captures'); 0155 $e->setView($this->view); 0156 throw $e; 0157 } 0158 0159 $this->_captureLock = true; 0160 $this->_captureType = $captureType; 0161 $this->_captureScriptType = $type; 0162 $this->_captureScriptAttrs = $attrs; 0163 ob_start(); 0164 } 0165 0166 /** 0167 * End capture action and store 0168 * 0169 * @return void 0170 */ 0171 public function captureEnd() 0172 { 0173 $content = ob_get_clean(); 0174 $type = $this->_captureScriptType; 0175 $attrs = $this->_captureScriptAttrs; 0176 $this->_captureScriptType = null; 0177 $this->_captureScriptAttrs = null; 0178 $this->_captureLock = false; 0179 0180 switch ($this->_captureType) { 0181 case Zend_View_Helper_Placeholder_Container_Abstract::SET: 0182 case Zend_View_Helper_Placeholder_Container_Abstract::PREPEND: 0183 case Zend_View_Helper_Placeholder_Container_Abstract::APPEND: 0184 $action = strtolower($this->_captureType) . 'Script'; 0185 break; 0186 default: 0187 $action = 'appendScript'; 0188 break; 0189 } 0190 $this->$action($content, $type, $attrs); 0191 } 0192 0193 /** 0194 * Overload method access 0195 * 0196 * Allows the following method calls: 0197 * - appendFile($src, $type = 'text/javascript', $attrs = array()) 0198 * - offsetSetFile($index, $src, $type = 'text/javascript', $attrs = array()) 0199 * - prependFile($src, $type = 'text/javascript', $attrs = array()) 0200 * - setFile($src, $type = 'text/javascript', $attrs = array()) 0201 * - appendScript($script, $type = 'text/javascript', $attrs = array()) 0202 * - offsetSetScript($index, $src, $type = 'text/javascript', $attrs = array()) 0203 * - prependScript($script, $type = 'text/javascript', $attrs = array()) 0204 * - setScript($script, $type = 'text/javascript', $attrs = array()) 0205 * 0206 * @param string $method 0207 * @param array $args 0208 * @return Zend_View_Helper_HeadScript 0209 * @throws Zend_View_Exception if too few arguments or invalid method 0210 */ 0211 public function __call($method, $args) 0212 { 0213 if (preg_match('/^(?P<action>set|(ap|pre)pend|offsetSet)(?P<mode>File|Script)$/', $method, $matches)) { 0214 if (1 > count($args)) { 0215 // require_once 'Zend/View/Exception.php'; 0216 $e = new Zend_View_Exception(sprintf('Method "%s" requires at least one argument', $method)); 0217 $e->setView($this->view); 0218 throw $e; 0219 } 0220 0221 $action = $matches['action']; 0222 $mode = strtolower($matches['mode']); 0223 $type = 'text/javascript'; 0224 $attrs = array(); 0225 0226 if ('offsetSet' == $action) { 0227 $index = array_shift($args); 0228 if (1 > count($args)) { 0229 // require_once 'Zend/View/Exception.php'; 0230 $e = new Zend_View_Exception(sprintf('Method "%s" requires at least two arguments, an index and source', $method)); 0231 $e->setView($this->view); 0232 throw $e; 0233 } 0234 } 0235 0236 $content = $args[0]; 0237 0238 if (isset($args[1])) { 0239 $type = (string) $args[1]; 0240 } 0241 if (isset($args[2])) { 0242 $attrs = (array) $args[2]; 0243 } 0244 0245 switch ($mode) { 0246 case 'script': 0247 $item = $this->createData($type, $attrs, $content); 0248 if ('offsetSet' == $action) { 0249 $this->offsetSet($index, $item); 0250 } else { 0251 $this->$action($item); 0252 } 0253 break; 0254 case 'file': 0255 default: 0256 if (!$this->_isDuplicate($content) || $action=='set') { 0257 $attrs['src'] = $content; 0258 $item = $this->createData($type, $attrs); 0259 if ('offsetSet' == $action) { 0260 $this->offsetSet($index, $item); 0261 } else { 0262 $this->$action($item); 0263 } 0264 } 0265 break; 0266 } 0267 0268 return $this; 0269 } 0270 0271 return parent::__call($method, $args); 0272 } 0273 0274 /** 0275 * Is the file specified a duplicate? 0276 * 0277 * @param string $file 0278 * @return bool 0279 */ 0280 protected function _isDuplicate($file) 0281 { 0282 foreach ($this->getContainer() as $item) { 0283 if (($item->source === null) 0284 && array_key_exists('src', $item->attributes) 0285 && ($file == $item->attributes['src'])) 0286 { 0287 return true; 0288 } 0289 } 0290 return false; 0291 } 0292 0293 /** 0294 * Is the script provided valid? 0295 * 0296 * @param mixed $value 0297 * @param string $method 0298 * @return bool 0299 */ 0300 protected function _isValid($value) 0301 { 0302 if ((!$value instanceof stdClass) 0303 || !isset($value->type) 0304 || (!isset($value->source) && !isset($value->attributes))) 0305 { 0306 return false; 0307 } 0308 0309 return true; 0310 } 0311 0312 /** 0313 * Override append 0314 * 0315 * @param string $value 0316 * @return void 0317 */ 0318 public function append($value) 0319 { 0320 if (!$this->_isValid($value)) { 0321 // require_once 'Zend/View/Exception.php'; 0322 $e = new Zend_View_Exception('Invalid argument passed to append(); please use one of the helper methods, appendScript() or appendFile()'); 0323 $e->setView($this->view); 0324 throw $e; 0325 } 0326 0327 return $this->getContainer()->append($value); 0328 } 0329 0330 /** 0331 * Override prepend 0332 * 0333 * @param string $value 0334 * @return void 0335 */ 0336 public function prepend($value) 0337 { 0338 if (!$this->_isValid($value)) { 0339 // require_once 'Zend/View/Exception.php'; 0340 $e = new Zend_View_Exception('Invalid argument passed to prepend(); please use one of the helper methods, prependScript() or prependFile()'); 0341 $e->setView($this->view); 0342 throw $e; 0343 } 0344 0345 return $this->getContainer()->prepend($value); 0346 } 0347 0348 /** 0349 * Override set 0350 * 0351 * @param string $value 0352 * @return void 0353 */ 0354 public function set($value) 0355 { 0356 if (!$this->_isValid($value)) { 0357 // require_once 'Zend/View/Exception.php'; 0358 $e = new Zend_View_Exception('Invalid argument passed to set(); please use one of the helper methods, setScript() or setFile()'); 0359 $e->setView($this->view); 0360 throw $e; 0361 } 0362 0363 return $this->getContainer()->set($value); 0364 } 0365 0366 /** 0367 * Override offsetSet 0368 * 0369 * @param string|int $index 0370 * @param mixed $value 0371 * @return void 0372 */ 0373 public function offsetSet($index, $value) 0374 { 0375 if (!$this->_isValid($value)) { 0376 // require_once 'Zend/View/Exception.php'; 0377 $e = new Zend_View_Exception('Invalid argument passed to offsetSet(); please use one of the helper methods, offsetSetScript() or offsetSetFile()'); 0378 $e->setView($this->view); 0379 throw $e; 0380 } 0381 0382 return $this->getContainer()->offsetSet($index, $value); 0383 } 0384 0385 /** 0386 * Set flag indicating if arbitrary attributes are allowed 0387 * 0388 * @param bool $flag 0389 * @return Zend_View_Helper_HeadScript 0390 */ 0391 public function setAllowArbitraryAttributes($flag) 0392 { 0393 $this->_arbitraryAttributes = (bool) $flag; 0394 return $this; 0395 } 0396 0397 /** 0398 * Are arbitrary attributes allowed? 0399 * 0400 * @return bool 0401 */ 0402 public function arbitraryAttributesAllowed() 0403 { 0404 return $this->_arbitraryAttributes; 0405 } 0406 0407 /** 0408 * Create script HTML 0409 * 0410 * @param string $type 0411 * @param array $attributes 0412 * @param string $content 0413 * @param string|int $indent 0414 * @return string 0415 */ 0416 public function itemToString($item, $indent, $escapeStart, $escapeEnd) 0417 { 0418 $attrString = ''; 0419 if (!empty($item->attributes)) { 0420 foreach ($item->attributes as $key => $value) { 0421 if ((!$this->arbitraryAttributesAllowed() && !in_array($key, $this->_optionalAttributes)) 0422 || in_array($key, array('conditional', 'noescape'))) 0423 { 0424 continue; 0425 } 0426 if ('defer' == $key) { 0427 $value = 'defer'; 0428 } 0429 $attrString .= sprintf(' %s="%s"', $key, ($this->_autoEscape) ? $this->_escape($value) : $value); 0430 } 0431 } 0432 0433 $addScriptEscape = !(isset($item->attributes['noescape']) && filter_var($item->attributes['noescape'], FILTER_VALIDATE_BOOLEAN)); 0434 0435 $type = ($this->_autoEscape) ? $this->_escape($item->type) : $item->type; 0436 $html = '<script type="' . $type . '"' . $attrString . '>'; 0437 if (!empty($item->source)) { 0438 $html .= PHP_EOL ; 0439 0440 if ($addScriptEscape) { 0441 $html .= $indent . ' ' . $escapeStart . PHP_EOL; 0442 } 0443 0444 $html .= $indent . ' ' . $item->source; 0445 0446 if ($addScriptEscape) { 0447 $html .= $indent . ' ' . $escapeEnd . PHP_EOL; 0448 } 0449 0450 $html .= $indent; 0451 } 0452 $html .= '</script>'; 0453 0454 if (isset($item->attributes['conditional']) 0455 && !empty($item->attributes['conditional']) 0456 && is_string($item->attributes['conditional'])) 0457 { 0458 // inner wrap with comment end and start if !IE 0459 if (str_replace(' ', '', $item->attributes['conditional']) === '!IE') { 0460 $html = '<!-->' . $html . '<!--'; 0461 } 0462 $html = $indent . '<!--[if ' . $item->attributes['conditional'] . ']>' . $html . '<![endif]-->'; 0463 } else { 0464 $html = $indent . $html; 0465 } 0466 0467 return $html; 0468 } 0469 0470 /** 0471 * Retrieve string representation 0472 * 0473 * @param string|int $indent 0474 * @return string 0475 */ 0476 public function toString($indent = null) 0477 { 0478 $indent = (null !== $indent) 0479 ? $this->getWhitespace($indent) 0480 : $this->getIndent(); 0481 0482 if ($this->view) { 0483 $useCdata = $this->view->doctype()->isXhtml() ? true : false; 0484 } else { 0485 $useCdata = $this->useCdata ? true : false; 0486 } 0487 $escapeStart = ($useCdata) ? '//<![CDATA[' : '//<!--'; 0488 $escapeEnd = ($useCdata) ? '//]]>' : '//-->'; 0489 0490 $items = array(); 0491 $this->getContainer()->ksort(); 0492 foreach ($this as $item) { 0493 if (!$this->_isValid($item)) { 0494 continue; 0495 } 0496 0497 $items[] = $this->itemToString($item, $indent, $escapeStart, $escapeEnd); 0498 } 0499 0500 $return = implode($this->getSeparator(), $items); 0501 return $return; 0502 } 0503 0504 /** 0505 * Create data item containing all necessary components of script 0506 * 0507 * @param string $type 0508 * @param array $attributes 0509 * @param string $content 0510 * @return stdClass 0511 */ 0512 public function createData($type, array $attributes, $content = null) 0513 { 0514 $data = new stdClass(); 0515 $data->type = $type; 0516 $data->attributes = $attributes; 0517 $data->source = $content; 0518 return $data; 0519 } 0520 }