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 }