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