Mercurial > hg > Members > shoshi > webvirt
comparison cake/libs/view/helpers/js.php @ 0:261e66bd5a0c
hg init
author | Shoshi TAMAKI <shoshi@cr.ie.u-ryukyu.ac.jp> |
---|---|
date | Sun, 24 Jul 2011 21:08:31 +0900 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:261e66bd5a0c |
---|---|
1 <?php | |
2 /** | |
3 * Javascript Generator class file. | |
4 * | |
5 * PHP versions 4 and 5 | |
6 * | |
7 * CakePHP : Rapid Development Framework (http://cakephp.org) | |
8 * Copyright 2006-2010, Cake Software Foundation, Inc. | |
9 * | |
10 * Licensed under The MIT License | |
11 * Redistributions of files must retain the above copyright notice. | |
12 * | |
13 * @copyright Copyright 2006-2010, Cake Software Foundation, Inc. | |
14 * @link http://cakephp.org CakePHP Project | |
15 * @package cake | |
16 * @subpackage cake.cake.libs.view.helpers | |
17 * @since CakePHP v 1.2 | |
18 * @license MIT License (http://www.opensource.org/licenses/mit-license.php) | |
19 */ | |
20 | |
21 /** | |
22 * Javascript Generator helper class for easy use of JavaScript. | |
23 * | |
24 * JsHelper provides an abstract interface for authoring JavaScript with a | |
25 * given client-side library. | |
26 * | |
27 * @package cake | |
28 * @subpackage cake.cake.libs.view.helpers | |
29 */ | |
30 class JsHelper extends AppHelper { | |
31 /** | |
32 * Whether or not you want scripts to be buffered or output. | |
33 * | |
34 * @var boolean | |
35 * @access public | |
36 */ | |
37 var $bufferScripts = true; | |
38 | |
39 /** | |
40 * helpers | |
41 * | |
42 * @var array | |
43 * @access public | |
44 */ | |
45 var $helpers = array('Html', 'Form'); | |
46 | |
47 /** | |
48 * Variables to pass to Javascript. | |
49 * | |
50 * @var array | |
51 * @see JsHelper::set() | |
52 * @access private | |
53 */ | |
54 var $__jsVars = array(); | |
55 | |
56 /** | |
57 * Scripts that are queued for output | |
58 * | |
59 * @var array | |
60 * @see JsHelper::buffer() | |
61 * @access private | |
62 */ | |
63 var $__bufferedScripts = array(); | |
64 | |
65 /** | |
66 * Current Javascript Engine that is being used | |
67 * | |
68 * @var string | |
69 * @access private | |
70 */ | |
71 var $__engineName; | |
72 | |
73 /** | |
74 * The javascript variable created by set() variables. | |
75 * | |
76 * @var string | |
77 * @access public | |
78 */ | |
79 var $setVariable = APP_DIR; | |
80 | |
81 /** | |
82 * Constructor - determines engine helper | |
83 * | |
84 * @param array $settings Settings array contains name of engine helper. | |
85 * @return void | |
86 * @access public | |
87 */ | |
88 function __construct($settings = array()) { | |
89 $className = 'Jquery'; | |
90 if (is_array($settings) && isset($settings[0])) { | |
91 $className = $settings[0]; | |
92 } elseif (is_string($settings)) { | |
93 $className = $settings; | |
94 } | |
95 $engineName = $className; | |
96 list($plugin, $className) = pluginSplit($className); | |
97 | |
98 $this->__engineName = $className . 'Engine'; | |
99 $engineClass = $engineName . 'Engine'; | |
100 $this->helpers[] = $engineClass; | |
101 parent::__construct(); | |
102 } | |
103 | |
104 /** | |
105 * call__ Allows for dispatching of methods to the Engine Helper. | |
106 * methods in the Engines bufferedMethods list will be automatically buffered. | |
107 * You can control buffering with the buffer param as well. By setting the last parameter to | |
108 * any engine method to a boolean you can force or disable buffering. | |
109 * | |
110 * e.g. `$js->get('#foo')->effect('fadeIn', array('speed' => 'slow'), true);` | |
111 * | |
112 * Will force buffering for the effect method. If the method takes an options array you may also add | |
113 * a 'buffer' param to the options array and control buffering there as well. | |
114 * | |
115 * e.g. `$js->get('#foo')->event('click', $functionContents, array('buffer' => true));` | |
116 * | |
117 * The buffer parameter will not be passed onto the EngineHelper. | |
118 * | |
119 * @param string $method Method to be called | |
120 * @param array $params Parameters for the method being called. | |
121 * @return mixed Depends on the return of the dispatched method, or it could be an instance of the EngineHelper | |
122 * @access public | |
123 */ | |
124 function call__($method, $params) { | |
125 if (isset($this->{$this->__engineName}) && method_exists($this->{$this->__engineName}, $method)) { | |
126 $buffer = false; | |
127 if (in_array(strtolower($method), $this->{$this->__engineName}->bufferedMethods)) { | |
128 $buffer = true; | |
129 } | |
130 if (count($params) > 0) { | |
131 $lastParam = $params[count($params) - 1]; | |
132 $hasBufferParam = (is_bool($lastParam) || is_array($lastParam) && isset($lastParam['buffer'])); | |
133 if ($hasBufferParam && is_bool($lastParam)) { | |
134 $buffer = $lastParam; | |
135 unset($params[count($params) - 1]); | |
136 } elseif ($hasBufferParam && is_array($lastParam)) { | |
137 $buffer = $lastParam['buffer']; | |
138 unset($params['buffer']); | |
139 } | |
140 } | |
141 $out = $this->{$this->__engineName}->dispatchMethod($method, $params); | |
142 if ($this->bufferScripts && $buffer && is_string($out)) { | |
143 $this->buffer($out); | |
144 return null; | |
145 } | |
146 if (is_object($out) && is_a($out, 'JsBaseEngineHelper')) { | |
147 return $this; | |
148 } | |
149 return $out; | |
150 } | |
151 if (method_exists($this, $method . '_')) { | |
152 return $this->dispatchMethod($method . '_', $params); | |
153 } | |
154 trigger_error(sprintf(__('JsHelper:: Missing Method %s is undefined', true), $method), E_USER_WARNING); | |
155 } | |
156 | |
157 /** | |
158 * Workaround for Object::Object() existing. Since Object::object exists, it does not | |
159 * fall into call__ and is not passed onto the engine helper. See JsBaseEngineHelper::object() for | |
160 * more information on this method. | |
161 * | |
162 * @param mixed $data Data to convert into JSON | |
163 * @param array $options Options to use for encoding JSON. See JsBaseEngineHelper::object() for more details. | |
164 * @return string encoded JSON | |
165 * @deprecated Remove when support for PHP4 and Object::object are removed. | |
166 * @access public | |
167 */ | |
168 function object($data = array(), $options = array()) { | |
169 return $this->{$this->__engineName}->object($data, $options); | |
170 } | |
171 | |
172 /** | |
173 * Overwrite inherited Helper::value() | |
174 * See JsBaseEngineHelper::value() for more information on this method. | |
175 * | |
176 * @param mixed $val A PHP variable to be converted to JSON | |
177 * @param boolean $quoteStrings If false, leaves string values unquoted | |
178 * @return string a JavaScript-safe/JSON representation of $val | |
179 * @access public | |
180 **/ | |
181 function value($val, $quoteString = true) { | |
182 return $this->{$this->__engineName}->value($val, $quoteString); | |
183 } | |
184 | |
185 /** | |
186 * Writes all Javascript generated so far to a code block or | |
187 * caches them to a file and returns a linked script. If no scripts have been | |
188 * buffered this method will return null. If the request is an XHR(ajax) request | |
189 * onDomReady will be set to false. As the dom is already 'ready'. | |
190 * | |
191 * ### Options | |
192 * | |
193 * - `inline` - Set to true to have scripts output as a script block inline | |
194 * if `cache` is also true, a script link tag will be generated. (default true) | |
195 * - `cache` - Set to true to have scripts cached to a file and linked in (default false) | |
196 * - `clear` - Set to false to prevent script cache from being cleared (default true) | |
197 * - `onDomReady` - wrap cached scripts in domready event (default true) | |
198 * - `safe` - if an inline block is generated should it be wrapped in <![CDATA[ ... ]]> (default true) | |
199 * | |
200 * @param array $options options for the code block | |
201 * @return mixed Completed javascript tag if there are scripts, if there are no buffered | |
202 * scripts null will be returned. | |
203 * @access public | |
204 */ | |
205 function writeBuffer($options = array()) { | |
206 $domReady = isset($this->params['isAjax']) ? !$this->params['isAjax'] : true; | |
207 $defaults = array( | |
208 'onDomReady' => $domReady, 'inline' => true, | |
209 'cache' => false, 'clear' => true, 'safe' => true | |
210 ); | |
211 $options = array_merge($defaults, $options); | |
212 $script = implode("\n", $this->getBuffer($options['clear'])); | |
213 | |
214 if (empty($script)) { | |
215 return null; | |
216 } | |
217 | |
218 if ($options['onDomReady']) { | |
219 $script = $this->{$this->__engineName}->domReady($script); | |
220 } | |
221 $opts = $options; | |
222 unset($opts['onDomReady'], $opts['cache'], $opts['clear']); | |
223 | |
224 if (!$options['cache'] && $options['inline']) { | |
225 return $this->Html->scriptBlock($script, $opts); | |
226 } | |
227 | |
228 if ($options['cache'] && $options['inline']) { | |
229 $filename = md5($script); | |
230 if (!file_exists(JS . $filename . '.js')) { | |
231 cache(str_replace(WWW_ROOT, '', JS) . $filename . '.js', $script, '+999 days', 'public'); | |
232 } | |
233 return $this->Html->script($filename); | |
234 } | |
235 $this->Html->scriptBlock($script, $opts); | |
236 return null; | |
237 } | |
238 | |
239 /** | |
240 * Write a script to the buffered scripts. | |
241 * | |
242 * @param string $script Script string to add to the buffer. | |
243 * @param boolean $top If true the script will be added to the top of the | |
244 * buffered scripts array. If false the bottom. | |
245 * @return void | |
246 * @access public | |
247 */ | |
248 function buffer($script, $top = false) { | |
249 if ($top) { | |
250 array_unshift($this->__bufferedScripts, $script); | |
251 } else { | |
252 $this->__bufferedScripts[] = $script; | |
253 } | |
254 } | |
255 | |
256 /** | |
257 * Get all the buffered scripts | |
258 * | |
259 * @param boolean $clear Whether or not to clear the script caches (default true) | |
260 * @return array Array of scripts added to the request. | |
261 * @access public | |
262 */ | |
263 function getBuffer($clear = true) { | |
264 $this->_createVars(); | |
265 $scripts = $this->__bufferedScripts; | |
266 if ($clear) { | |
267 $this->__bufferedScripts = array(); | |
268 $this->__jsVars = array(); | |
269 } | |
270 return $scripts; | |
271 } | |
272 | |
273 /** | |
274 * Generates the object string for variables passed to javascript. | |
275 * | |
276 * @return string Generated JSON object of all set vars | |
277 * @access protected | |
278 */ | |
279 function _createVars() { | |
280 if (!empty($this->__jsVars)) { | |
281 $setVar = (strpos($this->setVariable, '.')) ? $this->setVariable : 'window.' . $this->setVariable; | |
282 $this->buffer($setVar . ' = ' . $this->object($this->__jsVars) . ';', true); | |
283 } | |
284 } | |
285 | |
286 /** | |
287 * Generate an 'Ajax' link. Uses the selected JS engine to create a link | |
288 * element that is enhanced with Javascript. Options can include | |
289 * both those for HtmlHelper::link() and JsBaseEngine::request(), JsBaseEngine::event(); | |
290 * | |
291 * ### Options | |
292 * | |
293 * - `confirm` - Generate a confirm() dialog before sending the event. | |
294 * - `id` - use a custom id. | |
295 * - `htmlAttributes` - additional non-standard htmlAttributes. Standard attributes are class, id, | |
296 * rel, title, escape, onblur and onfocus. | |
297 * - `buffer` - Disable the buffering and return a script tag in addition to the link. | |
298 * | |
299 * @param string $title Title for the link. | |
300 * @param mixed $url Mixed either a string URL or an cake url array. | |
301 * @param array $options Options for both the HTML element and Js::request() | |
302 * @return string Completed link. If buffering is disabled a script tag will be returned as well. | |
303 * @access public | |
304 */ | |
305 function link($title, $url = null, $options = array()) { | |
306 if (!isset($options['id'])) { | |
307 $options['id'] = 'link-' . intval(mt_rand()); | |
308 } | |
309 list($options, $htmlOptions) = $this->_getHtmlOptions($options); | |
310 $out = $this->Html->link($title, $url, $htmlOptions); | |
311 $this->get('#' . $htmlOptions['id']); | |
312 $requestString = $event = ''; | |
313 if (isset($options['confirm'])) { | |
314 $requestString = $this->confirmReturn($options['confirm']); | |
315 unset($options['confirm']); | |
316 } | |
317 $buffer = isset($options['buffer']) ? $options['buffer'] : null; | |
318 $safe = isset($options['safe']) ? $options['safe'] : true; | |
319 unset($options['buffer'], $options['safe']); | |
320 | |
321 $requestString .= $this->request($url, $options); | |
322 | |
323 if (!empty($requestString)) { | |
324 $event = $this->event('click', $requestString, $options + array('buffer' => $buffer)); | |
325 } | |
326 if (isset($buffer) && !$buffer) { | |
327 $opts = array('safe' => $safe); | |
328 $out .= $this->Html->scriptBlock($event, $opts); | |
329 } | |
330 return $out; | |
331 } | |
332 | |
333 /** | |
334 * Pass variables into Javascript. Allows you to set variables that will be | |
335 * output when the buffer is fetched with `JsHelper::getBuffer()` or `JsHelper::writeBuffer()` | |
336 * The Javascript variable used to output set variables can be controlled with `JsHelper::$setVariable` | |
337 * | |
338 * @param mixed $one Either an array of variables to set, or the name of the variable to set. | |
339 * @param mixed $two If $one is a string, $two is the value for that key. | |
340 * @return void | |
341 * @access public | |
342 */ | |
343 function set($one, $two = null) { | |
344 $data = null; | |
345 if (is_array($one)) { | |
346 if (is_array($two)) { | |
347 $data = array_combine($one, $two); | |
348 } else { | |
349 $data = $one; | |
350 } | |
351 } else { | |
352 $data = array($one => $two); | |
353 } | |
354 if ($data == null) { | |
355 return false; | |
356 } | |
357 $this->__jsVars = array_merge($this->__jsVars, $data); | |
358 } | |
359 | |
360 /** | |
361 * Uses the selected JS engine to create a submit input | |
362 * element that is enhanced with Javascript. Options can include | |
363 * both those for FormHelper::submit() and JsBaseEngine::request(), JsBaseEngine::event(); | |
364 * | |
365 * Forms submitting with this method, cannot send files. Files do not transfer over XmlHttpRequest | |
366 * and require an iframe or flash. | |
367 * | |
368 * ### Options | |
369 * | |
370 * - `url` The url you wish the XHR request to submit to. | |
371 * - `confirm` A string to use for a confirm() message prior to submitting the request. | |
372 * - `method` The method you wish the form to send by, defaults to POST | |
373 * - `buffer` Whether or not you wish the script code to be buffered, defaults to true. | |
374 * - Also see options for JsHelper::request() and JsHelper::event() | |
375 * | |
376 * @param string $title The display text of the submit button. | |
377 * @param array $options Array of options to use. See the options for the above mentioned methods. | |
378 * @return string Completed submit button. | |
379 * @access public | |
380 */ | |
381 function submit($caption = null, $options = array()) { | |
382 if (!isset($options['id'])) { | |
383 $options['id'] = 'submit-' . intval(mt_rand()); | |
384 } | |
385 $formOptions = array('div'); | |
386 list($options, $htmlOptions) = $this->_getHtmlOptions($options, $formOptions); | |
387 $out = $this->Form->submit($caption, $htmlOptions); | |
388 | |
389 $this->get('#' . $htmlOptions['id']); | |
390 | |
391 $options['data'] = $this->serializeForm(array('isForm' => false, 'inline' => true)); | |
392 $requestString = $url = ''; | |
393 if (isset($options['confirm'])) { | |
394 $requestString = $this->confirmReturn($options['confirm']); | |
395 unset($options['confirm']); | |
396 } | |
397 if (isset($options['url'])) { | |
398 $url = $options['url']; | |
399 unset($options['url']); | |
400 } | |
401 if (!isset($options['method'])) { | |
402 $options['method'] = 'post'; | |
403 } | |
404 $options['dataExpression'] = true; | |
405 | |
406 $buffer = isset($options['buffer']) ? $options['buffer'] : null; | |
407 $safe = isset($options['safe']) ? $options['safe'] : true; | |
408 unset($options['buffer'], $options['safe']); | |
409 | |
410 $requestString .= $this->request($url, $options); | |
411 if (!empty($requestString)) { | |
412 $event = $this->event('click', $requestString, $options + array('buffer' => $buffer)); | |
413 } | |
414 if (isset($buffer) && !$buffer) { | |
415 $opts = array('safe' => $safe); | |
416 $out .= $this->Html->scriptBlock($event, $opts); | |
417 } | |
418 return $out; | |
419 } | |
420 | |
421 /** | |
422 * Parse a set of Options and extract the Html options. | |
423 * Extracted Html Options are removed from the $options param. | |
424 * | |
425 * @param array $options Options to filter. | |
426 * @param array $additional Array of additional keys to extract and include in the return options array. | |
427 * @return array Array of js options and Htmloptions | |
428 * @access protected | |
429 */ | |
430 function _getHtmlOptions($options, $additional = array()) { | |
431 $htmlKeys = array_merge( | |
432 array('class', 'id', 'escape', 'onblur', 'onfocus', 'rel', 'title', 'style'), | |
433 $additional | |
434 ); | |
435 $htmlOptions = array(); | |
436 foreach ($htmlKeys as $key) { | |
437 if (isset($options[$key])) { | |
438 $htmlOptions[$key] = $options[$key]; | |
439 } | |
440 unset($options[$key]); | |
441 } | |
442 if (isset($options['htmlAttributes'])) { | |
443 $htmlOptions = array_merge($htmlOptions, $options['htmlAttributes']); | |
444 unset($options['htmlAttributes']); | |
445 } | |
446 return array($options, $htmlOptions); | |
447 } | |
448 } | |
449 | |
450 /** | |
451 * JsEngineBaseClass | |
452 * | |
453 * Abstract Base Class for All JsEngines to extend. Provides generic methods. | |
454 * | |
455 * @package cake.view.helpers | |
456 */ | |
457 class JsBaseEngineHelper extends AppHelper { | |
458 /** | |
459 * Determines whether native JSON extension is used for encoding. Set by object constructor. | |
460 * | |
461 * @var boolean | |
462 * @access public | |
463 */ | |
464 var $useNative = false; | |
465 | |
466 /** | |
467 * The js snippet for the current selection. | |
468 * | |
469 * @var string | |
470 * @access public | |
471 */ | |
472 var $selection; | |
473 | |
474 /** | |
475 * Collection of option maps. Option maps allow other helpers to use generic names for engine | |
476 * callbacks and options. Allowing uniform code access for all engine types. Their use is optional | |
477 * for end user use though. | |
478 * | |
479 * @var array | |
480 * @access protected | |
481 */ | |
482 var $_optionMap = array(); | |
483 | |
484 /** | |
485 * An array of lowercase method names in the Engine that are buffered unless otherwise disabled. | |
486 * This allows specific 'end point' methods to be automatically buffered by the JsHelper. | |
487 * | |
488 * @var array | |
489 * @access public | |
490 */ | |
491 var $bufferedMethods = array('event', 'sortable', 'drag', 'drop', 'slider'); | |
492 | |
493 /** | |
494 * Contains a list of callback names -> default arguments. | |
495 * | |
496 * @var array | |
497 * @access protected | |
498 */ | |
499 var $_callbackArguments = array(); | |
500 | |
501 /** | |
502 * Constructor. | |
503 * | |
504 * @return void | |
505 */ | |
506 function __construct() { | |
507 parent::__construct(); | |
508 $this->useNative = function_exists('json_encode'); | |
509 } | |
510 | |
511 /** | |
512 * Create an `alert()` message in Javascript | |
513 * | |
514 * @param string $message Message you want to alter. | |
515 * @return string completed alert() | |
516 * @access public | |
517 */ | |
518 function alert($message) { | |
519 return 'alert("' . $this->escape($message) . '");'; | |
520 } | |
521 | |
522 /** | |
523 * Redirects to a URL. Creates a window.location modification snippet | |
524 * that can be used to trigger 'redirects' from Javascript. | |
525 * | |
526 * @param mixed $url | |
527 * @param array $options | |
528 * @return string completed redirect in javascript | |
529 * @access public | |
530 */ | |
531 function redirect($url = null) { | |
532 return 'window.location = "' . Router::url($url) . '";'; | |
533 } | |
534 | |
535 /** | |
536 * Create a `confirm()` message | |
537 * | |
538 * @param string $message Message you want confirmed. | |
539 * @return string completed confirm() | |
540 * @access public | |
541 */ | |
542 function confirm($message) { | |
543 return 'confirm("' . $this->escape($message) . '");'; | |
544 } | |
545 | |
546 /** | |
547 * Generate a confirm snippet that returns false from the current | |
548 * function scope. | |
549 * | |
550 * @param string $message Message to use in the confirm dialog. | |
551 * @return string completed confirm with return script | |
552 * @access public | |
553 */ | |
554 function confirmReturn($message) { | |
555 $out = 'var _confirm = ' . $this->confirm($message); | |
556 $out .= "if (!_confirm) {\n\treturn false;\n}"; | |
557 return $out; | |
558 } | |
559 | |
560 /** | |
561 * Create a `prompt()` Javascript function | |
562 * | |
563 * @param string $message Message you want to prompt. | |
564 * @param string $default Default message | |
565 * @return string completed prompt() | |
566 * @access public | |
567 */ | |
568 function prompt($message, $default = '') { | |
569 return 'prompt("' . $this->escape($message) . '", "' . $this->escape($default) . '");'; | |
570 } | |
571 | |
572 /** | |
573 * Generates a JavaScript object in JavaScript Object Notation (JSON) | |
574 * from an array. Will use native JSON encode method if available, and $useNative == true | |
575 * | |
576 * ### Options: | |
577 * | |
578 * - `prefix` - String prepended to the returned data. | |
579 * - `postfix` - String appended to the returned data. | |
580 * | |
581 * @param array $data Data to be converted. | |
582 * @param array $options Set of options, see above. | |
583 * @return string A JSON code block | |
584 * @access public | |
585 */ | |
586 function object($data = array(), $options = array()) { | |
587 $defaultOptions = array( | |
588 'prefix' => '', 'postfix' => '', | |
589 ); | |
590 $options = array_merge($defaultOptions, $options); | |
591 | |
592 if (is_object($data)) { | |
593 $data = get_object_vars($data); | |
594 } | |
595 | |
596 $out = $keys = array(); | |
597 $numeric = true; | |
598 | |
599 if ($this->useNative && function_exists('json_encode')) { | |
600 $rt = json_encode($data); | |
601 } else { | |
602 if (is_null($data)) { | |
603 return 'null'; | |
604 } | |
605 if (is_bool($data)) { | |
606 return $data ? 'true' : 'false'; | |
607 } | |
608 if (is_array($data)) { | |
609 $keys = array_keys($data); | |
610 } | |
611 | |
612 if (!empty($keys)) { | |
613 $numeric = (array_values($keys) === array_keys(array_values($keys))); | |
614 } | |
615 | |
616 foreach ($data as $key => $val) { | |
617 if (is_array($val) || is_object($val)) { | |
618 $val = $this->object($val); | |
619 } else { | |
620 $val = $this->value($val); | |
621 } | |
622 if (!$numeric) { | |
623 $val = '"' . $this->value($key, false) . '":' . $val; | |
624 } | |
625 $out[] = $val; | |
626 } | |
627 | |
628 if (!$numeric) { | |
629 $rt = '{' . join(',', $out) . '}'; | |
630 } else { | |
631 $rt = '[' . join(',', $out) . ']'; | |
632 } | |
633 } | |
634 $rt = $options['prefix'] . $rt . $options['postfix']; | |
635 return $rt; | |
636 } | |
637 | |
638 /** | |
639 * Converts a PHP-native variable of any type to a JSON-equivalent representation | |
640 * | |
641 * @param mixed $val A PHP variable to be converted to JSON | |
642 * @param boolean $quoteStrings If false, leaves string values unquoted | |
643 * @return string a JavaScript-safe/JSON representation of $val | |
644 * @access public | |
645 */ | |
646 function value($val, $quoteString = true) { | |
647 switch (true) { | |
648 case (is_array($val) || is_object($val)): | |
649 $val = $this->object($val); | |
650 break; | |
651 case ($val === null): | |
652 $val = 'null'; | |
653 break; | |
654 case (is_bool($val)): | |
655 $val = ($val === true) ? 'true' : 'false'; | |
656 break; | |
657 case (is_int($val)): | |
658 $val = $val; | |
659 break; | |
660 case (is_float($val)): | |
661 $val = sprintf("%.11f", $val); | |
662 break; | |
663 default: | |
664 $val = $this->escape($val); | |
665 if ($quoteString) { | |
666 $val = '"' . $val . '"'; | |
667 } | |
668 break; | |
669 } | |
670 return $val; | |
671 } | |
672 | |
673 /** | |
674 * Escape a string to be JSON friendly. | |
675 * | |
676 * List of escaped elements: | |
677 * | |
678 * - "\r" => '\n' | |
679 * - "\n" => '\n' | |
680 * - '"' => '\"' | |
681 * | |
682 * @param string $script String that needs to get escaped. | |
683 * @return string Escaped string. | |
684 * @access public | |
685 */ | |
686 function escape($string) { | |
687 App::import('Core', 'Multibyte'); | |
688 return $this->_utf8ToHex($string); | |
689 } | |
690 | |
691 /** | |
692 * Encode a string into JSON. Converts and escapes necessary characters. | |
693 * | |
694 * @param string $string The string that needs to be utf8->hex encoded | |
695 * @return void | |
696 * @access protected | |
697 */ | |
698 function _utf8ToHex($string) { | |
699 $length = strlen($string); | |
700 $return = ''; | |
701 for ($i = 0; $i < $length; ++$i) { | |
702 $ord = ord($string{$i}); | |
703 switch (true) { | |
704 case $ord == 0x08: | |
705 $return .= '\b'; | |
706 break; | |
707 case $ord == 0x09: | |
708 $return .= '\t'; | |
709 break; | |
710 case $ord == 0x0A: | |
711 $return .= '\n'; | |
712 break; | |
713 case $ord == 0x0C: | |
714 $return .= '\f'; | |
715 break; | |
716 case $ord == 0x0D: | |
717 $return .= '\r'; | |
718 break; | |
719 case $ord == 0x22: | |
720 case $ord == 0x2F: | |
721 case $ord == 0x5C: | |
722 $return .= '\\' . $string{$i}; | |
723 break; | |
724 case (($ord >= 0x20) && ($ord <= 0x7F)): | |
725 $return .= $string{$i}; | |
726 break; | |
727 case (($ord & 0xE0) == 0xC0): | |
728 if ($i + 1 >= $length) { | |
729 $i += 1; | |
730 $return .= '?'; | |
731 break; | |
732 } | |
733 $charbits = $string{$i} . $string{$i + 1}; | |
734 $char = Multibyte::utf8($charbits); | |
735 $return .= sprintf('\u%04s', dechex($char[0])); | |
736 $i += 1; | |
737 break; | |
738 case (($ord & 0xF0) == 0xE0): | |
739 if ($i + 2 >= $length) { | |
740 $i += 2; | |
741 $return .= '?'; | |
742 break; | |
743 } | |
744 $charbits = $string{$i} . $string{$i + 1} . $string{$i + 2}; | |
745 $char = Multibyte::utf8($charbits); | |
746 $return .= sprintf('\u%04s', dechex($char[0])); | |
747 $i += 2; | |
748 break; | |
749 case (($ord & 0xF8) == 0xF0): | |
750 if ($i + 3 >= $length) { | |
751 $i += 3; | |
752 $return .= '?'; | |
753 break; | |
754 } | |
755 $charbits = $string{$i} . $string{$i + 1} . $string{$i + 2} . $string{$i + 3}; | |
756 $char = Multibyte::utf8($charbits); | |
757 $return .= sprintf('\u%04s', dechex($char[0])); | |
758 $i += 3; | |
759 break; | |
760 case (($ord & 0xFC) == 0xF8): | |
761 if ($i + 4 >= $length) { | |
762 $i += 4; | |
763 $return .= '?'; | |
764 break; | |
765 } | |
766 $charbits = $string{$i} . $string{$i + 1} . $string{$i + 2} . $string{$i + 3} . $string{$i + 4}; | |
767 $char = Multibyte::utf8($charbits); | |
768 $return .= sprintf('\u%04s', dechex($char[0])); | |
769 $i += 4; | |
770 break; | |
771 case (($ord & 0xFE) == 0xFC): | |
772 if ($i + 5 >= $length) { | |
773 $i += 5; | |
774 $return .= '?'; | |
775 break; | |
776 } | |
777 $charbits = $string{$i} . $string{$i + 1} . $string{$i + 2} . $string{$i + 3} . $string{$i + 4} . $string{$i + 5}; | |
778 $char = Multibyte::utf8($charbits); | |
779 $return .= sprintf('\u%04s', dechex($char[0])); | |
780 $i += 5; | |
781 break; | |
782 } | |
783 } | |
784 return $return; | |
785 } | |
786 | |
787 /** | |
788 * Create javascript selector for a CSS rule | |
789 * | |
790 * @param string $selector The selector that is targeted | |
791 * @return object instance of $this. Allows chained methods. | |
792 * @access public | |
793 */ | |
794 function get($selector) { | |
795 trigger_error(sprintf(__('%s does not have get() implemented', true), get_class($this)), E_USER_WARNING); | |
796 return $this; | |
797 } | |
798 | |
799 /** | |
800 * Add an event to the script cache. Operates on the currently selected elements. | |
801 * | |
802 * ### Options | |
803 * | |
804 * - `wrap` - Whether you want the callback wrapped in an anonymous function. (defaults to true) | |
805 * - `stop` - Whether you want the event to stopped. (defaults to true) | |
806 * | |
807 * @param string $type Type of event to bind to the current dom id | |
808 * @param string $callback The Javascript function you wish to trigger or the function literal | |
809 * @param array $options Options for the event. | |
810 * @return string completed event handler | |
811 * @access public | |
812 */ | |
813 function event($type, $callback, $options = array()) { | |
814 trigger_error(sprintf(__('%s does not have event() implemented', true), get_class($this)), E_USER_WARNING); | |
815 } | |
816 | |
817 /** | |
818 * Create a domReady event. This is a special event in many libraries | |
819 * | |
820 * @param string $functionBody The code to run on domReady | |
821 * @return string completed domReady method | |
822 * @access public | |
823 */ | |
824 function domReady($functionBody) { | |
825 trigger_error(sprintf(__('%s does not have domReady() implemented', true), get_class($this)), E_USER_WARNING); | |
826 } | |
827 | |
828 /** | |
829 * Create an iteration over the current selection result. | |
830 * | |
831 * @param string $callback The function body you wish to apply during the iteration. | |
832 * @return string completed iteration | |
833 */ | |
834 function each($callback) { | |
835 trigger_error(sprintf(__('%s does not have each() implemented', true), get_class($this)), E_USER_WARNING); | |
836 } | |
837 | |
838 /** | |
839 * Trigger an Effect. | |
840 * | |
841 * ### Supported Effects | |
842 * | |
843 * The following effects are supported by all core JsEngines | |
844 * | |
845 * - `show` - reveal an element. | |
846 * - `hide` - hide an element. | |
847 * - `fadeIn` - Fade in an element. | |
848 * - `fadeOut` - Fade out an element. | |
849 * - `slideIn` - Slide an element in. | |
850 * - `slideOut` - Slide an element out. | |
851 * | |
852 * ### Options | |
853 * | |
854 * - `speed` - Speed at which the animation should occur. Accepted values are 'slow', 'fast'. Not all effects use | |
855 * the speed option. | |
856 * | |
857 * @param string $name The name of the effect to trigger. | |
858 * @param array $options Array of options for the effect. | |
859 * @return string completed string with effect. | |
860 * @access public | |
861 */ | |
862 function effect($name, $options) { | |
863 trigger_error(sprintf(__('%s does not have effect() implemented', true), get_class($this)), E_USER_WARNING); | |
864 } | |
865 | |
866 /** | |
867 * Make an XHR request | |
868 * | |
869 * ### Event Options | |
870 * | |
871 * - `complete` - Callback to fire on complete. | |
872 * - `success` - Callback to fire on success. | |
873 * - `before` - Callback to fire on request initialization. | |
874 * - `error` - Callback to fire on request failure. | |
875 * | |
876 * ### Options | |
877 * | |
878 * - `method` - The method to make the request with defaults to GET in more libraries | |
879 * - `async` - Whether or not you want an asynchronous request. | |
880 * - `data` - Additional data to send. | |
881 * - `update` - Dom id to update with the content of the request. | |
882 * - `type` - Data type for response. 'json' and 'html' are supported. Default is html for most libraries. | |
883 * - `evalScripts` - Whether or not <script> tags should be eval'ed. | |
884 * - `dataExpression` - Should the `data` key be treated as a callback. Useful for supplying `$options['data']` as | |
885 * another Javascript expression. | |
886 * | |
887 * @param mixed $url Array or String URL to target with the request. | |
888 * @param array $options Array of options. See above for cross library supported options | |
889 * @return string XHR request. | |
890 * @access public | |
891 */ | |
892 function request($url, $options = array()) { | |
893 trigger_error(sprintf(__('%s does not have request() implemented', true), get_class($this)), E_USER_WARNING); | |
894 } | |
895 | |
896 /** | |
897 * Create a draggable element. Works on the currently selected element. | |
898 * Additional options may be supported by the library implementation. | |
899 * | |
900 * ### Options | |
901 * | |
902 * - `handle` - selector to the handle element. | |
903 * - `snapGrid` - The pixel grid that movement snaps to, an array(x, y) | |
904 * - `container` - The element that acts as a bounding box for the draggable element. | |
905 * | |
906 * ### Event Options | |
907 * | |
908 * - `start` - Event fired when the drag starts | |
909 * - `drag` - Event fired on every step of the drag | |
910 * - `stop` - Event fired when dragging stops (mouse release) | |
911 * | |
912 * @param array $options Options array see above. | |
913 * @return string Completed drag script | |
914 * @access public | |
915 */ | |
916 function drag($options = array()) { | |
917 trigger_error(sprintf(__('%s does not have drag() implemented', true), get_class($this)), E_USER_WARNING); | |
918 } | |
919 | |
920 /** | |
921 * Create a droppable element. Allows for draggable elements to be dropped on it. | |
922 * Additional options may be supported by the library implementation. | |
923 * | |
924 * ### Options | |
925 * | |
926 * - `accept` - Selector for elements this droppable will accept. | |
927 * - `hoverclass` - Class to add to droppable when a draggable is over. | |
928 * | |
929 * ### Event Options | |
930 * | |
931 * - `drop` - Event fired when an element is dropped into the drop zone. | |
932 * - `hover` - Event fired when a drag enters a drop zone. | |
933 * - `leave` - Event fired when a drag is removed from a drop zone without being dropped. | |
934 * | |
935 * @return string Completed drop script | |
936 * @access public | |
937 */ | |
938 function drop($options = array()) { | |
939 trigger_error(sprintf(__('%s does not have drop() implemented', true), get_class($this)), E_USER_WARNING); | |
940 } | |
941 | |
942 /** | |
943 * Create a sortable element. | |
944 * Additional options may be supported by the library implementation. | |
945 * | |
946 * ### Options | |
947 * | |
948 * - `containment` - Container for move action | |
949 * - `handle` - Selector to handle element. Only this element will start sort action. | |
950 * - `revert` - Whether or not to use an effect to move sortable into final position. | |
951 * - `opacity` - Opacity of the placeholder | |
952 * - `distance` - Distance a sortable must be dragged before sorting starts. | |
953 * | |
954 * ### Event Options | |
955 * | |
956 * - `start` - Event fired when sorting starts | |
957 * - `sort` - Event fired during sorting | |
958 * - `complete` - Event fired when sorting completes. | |
959 * | |
960 * @param array $options Array of options for the sortable. See above. | |
961 * @return string Completed sortable script. | |
962 * @access public | |
963 */ | |
964 function sortable() { | |
965 trigger_error(sprintf(__('%s does not have sortable() implemented', true), get_class($this)), E_USER_WARNING); | |
966 } | |
967 | |
968 /** | |
969 * Create a slider UI widget. Comprised of a track and knob. | |
970 * Additional options may be supported by the library implementation. | |
971 * | |
972 * ### Options | |
973 * | |
974 * - `handle` - The id of the element used in sliding. | |
975 * - `direction` - The direction of the slider either 'vertical' or 'horizontal' | |
976 * - `min` - The min value for the slider. | |
977 * - `max` - The max value for the slider. | |
978 * - `step` - The number of steps or ticks the slider will have. | |
979 * - `value` - The initial offset of the slider. | |
980 * | |
981 * ### Events | |
982 * | |
983 * - `change` - Fired when the slider's value is updated | |
984 * - `complete` - Fired when the user stops sliding the handle | |
985 * | |
986 * @return string Completed slider script | |
987 * @access public | |
988 */ | |
989 function slider() { | |
990 trigger_error(sprintf(__('%s does not have slider() implemented', true), get_class($this)), E_USER_WARNING); | |
991 } | |
992 | |
993 /** | |
994 * Serialize the form attached to $selector. | |
995 * Pass `true` for $isForm if the current selection is a form element. | |
996 * Converts the form or the form element attached to the current selection into a string/json object | |
997 * (depending on the library implementation) for use with XHR operations. | |
998 * | |
999 * ### Options | |
1000 * | |
1001 * - `isForm` - is the current selection a form, or an input? (defaults to false) | |
1002 * - `inline` - is the rendered statement going to be used inside another JS statement? (defaults to false) | |
1003 * | |
1004 * @param array $options options for serialization generation. | |
1005 * @return string completed form serialization script | |
1006 * @access public | |
1007 */ | |
1008 function serializeForm() { | |
1009 trigger_error( | |
1010 sprintf(__('%s does not have serializeForm() implemented', true), get_class($this)), E_USER_WARNING | |
1011 ); | |
1012 } | |
1013 | |
1014 /** | |
1015 * Parse an options assoc array into an Javascript object literal. | |
1016 * Similar to object() but treats any non-integer value as a string, | |
1017 * does not include `{ }` | |
1018 * | |
1019 * @param array $options Options to be converted | |
1020 * @param array $safeKeys Keys that should not be escaped. | |
1021 * @return string Parsed JSON options without enclosing { }. | |
1022 * @access protected | |
1023 */ | |
1024 function _parseOptions($options, $safeKeys = array()) { | |
1025 $out = array(); | |
1026 $safeKeys = array_flip($safeKeys); | |
1027 foreach ($options as $key => $value) { | |
1028 if (!is_int($value) && !isset($safeKeys[$key])) { | |
1029 $value = $this->value($value); | |
1030 } | |
1031 $out[] = $key . ':' . $value; | |
1032 } | |
1033 sort($out); | |
1034 return join(', ', $out); | |
1035 } | |
1036 | |
1037 /** | |
1038 * Maps Abstract options to engine specific option names. | |
1039 * If attributes are missing from the map, they are not changed. | |
1040 * | |
1041 * @param string $method Name of method whose options are being worked with. | |
1042 * @param array $options Array of options to map. | |
1043 * @return array Array of mapped options. | |
1044 * @access protected | |
1045 */ | |
1046 function _mapOptions($method, $options) { | |
1047 if (!isset($this->_optionMap[$method])) { | |
1048 return $options; | |
1049 } | |
1050 foreach ($this->_optionMap[$method] as $abstract => $concrete) { | |
1051 if (isset($options[$abstract])) { | |
1052 $options[$concrete] = $options[$abstract]; | |
1053 unset($options[$abstract]); | |
1054 } | |
1055 } | |
1056 return $options; | |
1057 } | |
1058 | |
1059 /** | |
1060 * Prepare callbacks and wrap them with function ([args]) { } as defined in | |
1061 * _callbackArgs array. | |
1062 * | |
1063 * @param string $method Name of the method you are preparing callbacks for. | |
1064 * @param array $options Array of options being parsed | |
1065 * @param string $callbacks Additional Keys that contain callbacks | |
1066 * @return array Array of options with callbacks added. | |
1067 * @access protected | |
1068 */ | |
1069 function _prepareCallbacks($method, $options, $callbacks = array()) { | |
1070 $wrapCallbacks = true; | |
1071 if (isset($options['wrapCallbacks'])) { | |
1072 $wrapCallbacks = $options['wrapCallbacks']; | |
1073 } | |
1074 unset($options['wrapCallbacks']); | |
1075 if (!$wrapCallbacks) { | |
1076 return $options; | |
1077 } | |
1078 $callbackOptions = array(); | |
1079 if (isset($this->_callbackArguments[$method])) { | |
1080 $callbackOptions = $this->_callbackArguments[$method]; | |
1081 } | |
1082 $callbacks = array_unique(array_merge(array_keys($callbackOptions), (array)$callbacks)); | |
1083 | |
1084 foreach ($callbacks as $callback) { | |
1085 if (empty($options[$callback])) { | |
1086 continue; | |
1087 } | |
1088 $args = null; | |
1089 if (!empty($callbackOptions[$callback])) { | |
1090 $args = $callbackOptions[$callback]; | |
1091 } | |
1092 $options[$callback] = 'function (' . $args . ') {' . $options[$callback] . '}'; | |
1093 } | |
1094 return $options; | |
1095 } | |
1096 | |
1097 /** | |
1098 * Conveinence wrapper method for all common option processing steps. | |
1099 * Runs _mapOptions, _prepareCallbacks, and _parseOptions in order. | |
1100 * | |
1101 * @param string $method Name of method processing options for. | |
1102 * @param array $options Array of options to process. | |
1103 * @return string Parsed options string. | |
1104 * @access protected | |
1105 */ | |
1106 function _processOptions($method, $options) { | |
1107 $options = $this->_mapOptions($method, $options); | |
1108 $options = $this->_prepareCallbacks($method, $options); | |
1109 $options = $this->_parseOptions($options, array_keys($this->_callbackArguments[$method])); | |
1110 return $options; | |
1111 } | |
1112 | |
1113 /** | |
1114 * Convert an array of data into a query string | |
1115 * | |
1116 * @param array $parameters Array of parameters to convert to a query string | |
1117 * @return string Querystring fragment | |
1118 * @access protected | |
1119 */ | |
1120 function _toQuerystring($parameters) { | |
1121 $out = ''; | |
1122 $keys = array_keys($parameters); | |
1123 $count = count($parameters); | |
1124 for ($i = 0; $i < $count; $i++) { | |
1125 $out .= $keys[$i] . '=' . $parameters[$keys[$i]]; | |
1126 if ($i < $count - 1) { | |
1127 $out .= '&'; | |
1128 } | |
1129 } | |
1130 return $out; | |
1131 } | |
1132 } |