|
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: HeadStyle.php 20104 2010-01-06 21:26:01Z matthew $ |
|
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 stylesheets |
|
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_HeadStyle extends Zend_View_Helper_Placeholder_Container_Standalone |
|
36 { |
|
37 /** |
|
38 * Registry key for placeholder |
|
39 * @var string |
|
40 */ |
|
41 protected $_regKey = 'Zend_View_Helper_HeadStyle'; |
|
42 |
|
43 /** |
|
44 * Allowed optional attributes |
|
45 * @var array |
|
46 */ |
|
47 protected $_optionalAttributes = array('lang', 'title', 'media', 'dir'); |
|
48 |
|
49 /** |
|
50 * Allowed media types |
|
51 * @var array |
|
52 */ |
|
53 protected $_mediaTypes = array( |
|
54 'all', 'aural', 'braille', 'handheld', 'print', |
|
55 'projection', 'screen', 'tty', 'tv' |
|
56 ); |
|
57 |
|
58 /** |
|
59 * Capture type and/or attributes (used for hinting during capture) |
|
60 * @var string |
|
61 */ |
|
62 protected $_captureAttrs = null; |
|
63 |
|
64 /** |
|
65 * Capture lock |
|
66 * @var bool |
|
67 */ |
|
68 protected $_captureLock; |
|
69 |
|
70 /** |
|
71 * Capture type (append, prepend, set) |
|
72 * @var string |
|
73 */ |
|
74 protected $_captureType; |
|
75 |
|
76 /** |
|
77 * Constructor |
|
78 * |
|
79 * Set separator to PHP_EOL. |
|
80 * |
|
81 * @return void |
|
82 */ |
|
83 public function __construct() |
|
84 { |
|
85 parent::__construct(); |
|
86 $this->setSeparator(PHP_EOL); |
|
87 } |
|
88 |
|
89 /** |
|
90 * Return headStyle object |
|
91 * |
|
92 * Returns headStyle helper object; optionally, allows specifying |
|
93 * |
|
94 * @param string $content Stylesheet contents |
|
95 * @param string $placement Append, prepend, or set |
|
96 * @param string|array $attributes Optional attributes to utilize |
|
97 * @return Zend_View_Helper_HeadStyle |
|
98 */ |
|
99 public function headStyle($content = null, $placement = 'APPEND', $attributes = array()) |
|
100 { |
|
101 if ((null !== $content) && is_string($content)) { |
|
102 switch (strtoupper($placement)) { |
|
103 case 'SET': |
|
104 $action = 'setStyle'; |
|
105 break; |
|
106 case 'PREPEND': |
|
107 $action = 'prependStyle'; |
|
108 break; |
|
109 case 'APPEND': |
|
110 default: |
|
111 $action = 'appendStyle'; |
|
112 break; |
|
113 } |
|
114 $this->$action($content, $attributes); |
|
115 } |
|
116 |
|
117 return $this; |
|
118 } |
|
119 |
|
120 /** |
|
121 * Overload method calls |
|
122 * |
|
123 * Allows the following method calls: |
|
124 * - appendStyle($content, $attributes = array()) |
|
125 * - offsetSetStyle($index, $content, $attributes = array()) |
|
126 * - prependStyle($content, $attributes = array()) |
|
127 * - setStyle($content, $attributes = array()) |
|
128 * |
|
129 * @param string $method |
|
130 * @param array $args |
|
131 * @return void |
|
132 * @throws Zend_View_Exception When no $content provided or invalid method |
|
133 */ |
|
134 public function __call($method, $args) |
|
135 { |
|
136 if (preg_match('/^(?P<action>set|(ap|pre)pend|offsetSet)(Style)$/', $method, $matches)) { |
|
137 $index = null; |
|
138 $argc = count($args); |
|
139 $action = $matches['action']; |
|
140 |
|
141 if ('offsetSet' == $action) { |
|
142 if (0 < $argc) { |
|
143 $index = array_shift($args); |
|
144 --$argc; |
|
145 } |
|
146 } |
|
147 |
|
148 if (1 > $argc) { |
|
149 require_once 'Zend/View/Exception.php'; |
|
150 $e = new Zend_View_Exception(sprintf('Method "%s" requires minimally content for the stylesheet', $method)); |
|
151 $e->setView($this->view); |
|
152 throw $e; |
|
153 } |
|
154 |
|
155 $content = $args[0]; |
|
156 $attrs = array(); |
|
157 if (isset($args[1])) { |
|
158 $attrs = (array) $args[1]; |
|
159 } |
|
160 |
|
161 $item = $this->createData($content, $attrs); |
|
162 |
|
163 if ('offsetSet' == $action) { |
|
164 $this->offsetSet($index, $item); |
|
165 } else { |
|
166 $this->$action($item); |
|
167 } |
|
168 |
|
169 return $this; |
|
170 } |
|
171 |
|
172 return parent::__call($method, $args); |
|
173 } |
|
174 |
|
175 /** |
|
176 * Determine if a value is a valid style tag |
|
177 * |
|
178 * @param mixed $value |
|
179 * @param string $method |
|
180 * @return boolean |
|
181 */ |
|
182 protected function _isValid($value) |
|
183 { |
|
184 if ((!$value instanceof stdClass) |
|
185 || !isset($value->content) |
|
186 || !isset($value->attributes)) |
|
187 { |
|
188 return false; |
|
189 } |
|
190 |
|
191 return true; |
|
192 } |
|
193 |
|
194 /** |
|
195 * Override append to enforce style creation |
|
196 * |
|
197 * @param mixed $value |
|
198 * @return void |
|
199 */ |
|
200 public function append($value) |
|
201 { |
|
202 if (!$this->_isValid($value)) { |
|
203 require_once 'Zend/View/Exception.php'; |
|
204 $e = new Zend_View_Exception('Invalid value passed to append; please use appendStyle()'); |
|
205 $e->setView($this->view); |
|
206 throw $e; |
|
207 } |
|
208 |
|
209 return $this->getContainer()->append($value); |
|
210 } |
|
211 |
|
212 /** |
|
213 * Override offsetSet to enforce style creation |
|
214 * |
|
215 * @param string|int $index |
|
216 * @param mixed $value |
|
217 * @return void |
|
218 */ |
|
219 public function offsetSet($index, $value) |
|
220 { |
|
221 if (!$this->_isValid($value)) { |
|
222 require_once 'Zend/View/Exception.php'; |
|
223 $e = new Zend_View_Exception('Invalid value passed to offsetSet; please use offsetSetStyle()'); |
|
224 $e->setView($this->view); |
|
225 throw $e; |
|
226 } |
|
227 |
|
228 return $this->getContainer()->offsetSet($index, $value); |
|
229 } |
|
230 |
|
231 /** |
|
232 * Override prepend to enforce style creation |
|
233 * |
|
234 * @param mixed $value |
|
235 * @return void |
|
236 */ |
|
237 public function prepend($value) |
|
238 { |
|
239 if (!$this->_isValid($value)) { |
|
240 require_once 'Zend/View/Exception.php'; |
|
241 $e = new Zend_View_Exception('Invalid value passed to prepend; please use prependStyle()'); |
|
242 $e->setView($this->view); |
|
243 throw $e; |
|
244 } |
|
245 |
|
246 return $this->getContainer()->prepend($value); |
|
247 } |
|
248 |
|
249 /** |
|
250 * Override set to enforce style creation |
|
251 * |
|
252 * @param mixed $value |
|
253 * @return void |
|
254 */ |
|
255 public function set($value) |
|
256 { |
|
257 if (!$this->_isValid($value)) { |
|
258 require_once 'Zend/View/Exception.php'; |
|
259 $e = new Zend_View_Exception('Invalid value passed to set; please use setStyle()'); |
|
260 $e->setView($this->view); |
|
261 throw $e; |
|
262 } |
|
263 |
|
264 return $this->getContainer()->set($value); |
|
265 } |
|
266 |
|
267 /** |
|
268 * Start capture action |
|
269 * |
|
270 * @param mixed $captureType |
|
271 * @param string $typeOrAttrs |
|
272 * @return void |
|
273 */ |
|
274 public function captureStart($type = Zend_View_Helper_Placeholder_Container_Abstract::APPEND, $attrs = null) |
|
275 { |
|
276 if ($this->_captureLock) { |
|
277 require_once 'Zend/View/Helper/Placeholder/Container/Exception.php'; |
|
278 $e = new Zend_View_Helper_Placeholder_Container_Exception('Cannot nest headStyle captures'); |
|
279 $e->setView($this->view); |
|
280 throw $e; |
|
281 } |
|
282 |
|
283 $this->_captureLock = true; |
|
284 $this->_captureAttrs = $attrs; |
|
285 $this->_captureType = $type; |
|
286 ob_start(); |
|
287 } |
|
288 |
|
289 /** |
|
290 * End capture action and store |
|
291 * |
|
292 * @return void |
|
293 */ |
|
294 public function captureEnd() |
|
295 { |
|
296 $content = ob_get_clean(); |
|
297 $attrs = $this->_captureAttrs; |
|
298 $this->_captureAttrs = null; |
|
299 $this->_captureLock = false; |
|
300 |
|
301 switch ($this->_captureType) { |
|
302 case Zend_View_Helper_Placeholder_Container_Abstract::SET: |
|
303 $this->setStyle($content, $attrs); |
|
304 break; |
|
305 case Zend_View_Helper_Placeholder_Container_Abstract::PREPEND: |
|
306 $this->prependStyle($content, $attrs); |
|
307 break; |
|
308 case Zend_View_Helper_Placeholder_Container_Abstract::APPEND: |
|
309 default: |
|
310 $this->appendStyle($content, $attrs); |
|
311 break; |
|
312 } |
|
313 } |
|
314 |
|
315 /** |
|
316 * Convert content and attributes into valid style tag |
|
317 * |
|
318 * @param stdClass $item Item to render |
|
319 * @param string $indent Indentation to use |
|
320 * @return string |
|
321 */ |
|
322 public function itemToString(stdClass $item, $indent) |
|
323 { |
|
324 $attrString = ''; |
|
325 if (!empty($item->attributes)) { |
|
326 $enc = 'UTF-8'; |
|
327 if ($this->view instanceof Zend_View_Interface |
|
328 && method_exists($this->view, 'getEncoding') |
|
329 ) { |
|
330 $enc = $this->view->getEncoding(); |
|
331 } |
|
332 foreach ($item->attributes as $key => $value) { |
|
333 if (!in_array($key, $this->_optionalAttributes)) { |
|
334 continue; |
|
335 } |
|
336 if ('media' == $key) { |
|
337 if(false === strpos($value, ',')) { |
|
338 if (!in_array($value, $this->_mediaTypes)) { |
|
339 continue; |
|
340 } |
|
341 } else { |
|
342 $media_types = explode(',', $value); |
|
343 $value = ''; |
|
344 foreach($media_types as $type) { |
|
345 $type = trim($type); |
|
346 if (!in_array($type, $this->_mediaTypes)) { |
|
347 continue; |
|
348 } |
|
349 $value .= $type .','; |
|
350 } |
|
351 $value = substr($value, 0, -1); |
|
352 } |
|
353 } |
|
354 $attrString .= sprintf(' %s="%s"', $key, htmlspecialchars($value, ENT_COMPAT, $enc)); |
|
355 } |
|
356 } |
|
357 |
|
358 $html = '<style type="text/css"' . $attrString . '>' . PHP_EOL |
|
359 . $indent . '<!--' . PHP_EOL . $indent . $item->content . PHP_EOL . $indent . '-->' . PHP_EOL |
|
360 . '</style>'; |
|
361 |
|
362 if (isset($item->attributes['conditional']) |
|
363 && !empty($item->attributes['conditional']) |
|
364 && is_string($item->attributes['conditional'])) |
|
365 { |
|
366 $html = '<!--[if ' . $item->attributes['conditional'] . ']> ' . $html . '<![endif]-->'; |
|
367 } |
|
368 |
|
369 return $html; |
|
370 } |
|
371 |
|
372 /** |
|
373 * Create string representation of placeholder |
|
374 * |
|
375 * @param string|int $indent |
|
376 * @return string |
|
377 */ |
|
378 public function toString($indent = null) |
|
379 { |
|
380 $indent = (null !== $indent) |
|
381 ? $this->getWhitespace($indent) |
|
382 : $this->getIndent(); |
|
383 |
|
384 $items = array(); |
|
385 $this->getContainer()->ksort(); |
|
386 foreach ($this as $item) { |
|
387 if (!$this->_isValid($item)) { |
|
388 continue; |
|
389 } |
|
390 $items[] = $this->itemToString($item, $indent); |
|
391 } |
|
392 |
|
393 $return = $indent . implode($this->getSeparator() . $indent, $items); |
|
394 $return = preg_replace("/(\r\n?|\n)/", '$1' . $indent, $return); |
|
395 return $return; |
|
396 } |
|
397 |
|
398 /** |
|
399 * Create data item for use in stack |
|
400 * |
|
401 * @param string $content |
|
402 * @param array $attributes |
|
403 * @return stdClass |
|
404 */ |
|
405 public function createData($content, array $attributes) |
|
406 { |
|
407 if (!isset($attributes['media'])) { |
|
408 $attributes['media'] = 'screen'; |
|
409 } else if(is_array($attributes['media'])) { |
|
410 $attributes['media'] = implode(',', $attributes['media']); |
|
411 } |
|
412 |
|
413 $data = new stdClass(); |
|
414 $data->content = $content; |
|
415 $data->attributes = $attributes; |
|
416 |
|
417 return $data; |
|
418 } |
|
419 } |