1<?php 2/** 3 * jQuery Engine Helper for JsHelper 4 * 5 * Provides jQuery specific JavaScript for JsHelper. 6 * 7 * Implements the JsHelper interface for jQuery. All $options arrays 8 * support all options found in the JsHelper, as well as those in the jQuery 9 * documentation. 10 * 11 * CakePHP(tm) : Rapid Development Framework (https://cakephp.org) 12 * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) 13 * 14 * Licensed under The MIT License 15 * For full copyright and license information, please see the LICENSE.txt 16 * Redistributions of files must retain the above copyright notice. 17 * 18 * @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) 19 * @link https://cakephp.org CakePHP(tm) Project 20 * @package Cake.View.Helper 21 * @since CakePHP(tm) v 1.3 22 * @license https://opensource.org/licenses/mit-license.php MIT License 23 */ 24 25App::uses('AppHelper', 'View/Helper'); 26App::uses('JsBaseEngineHelper', 'View/Helper'); 27 28/** 29 * jQuery Engine Helper for JsHelper 30 * 31 * Provides jQuery specific JavaScript for JsHelper. 32 * 33 * Implements the JsHelper interface for jQuery. All $options arrays 34 * support all options found in the JsHelper, as well as those in the jQuery 35 * documentation. 36 * 37 * @package Cake.View.Helper 38 */ 39class JqueryEngineHelper extends JsBaseEngineHelper { 40 41/** 42 * Option mappings for jQuery 43 * 44 * @var array 45 */ 46 protected $_optionMap = array( 47 'request' => array( 48 'type' => 'dataType', 49 'before' => 'beforeSend', 50 'method' => 'type', 51 ), 52 'sortable' => array( 53 'complete' => 'stop', 54 ), 55 'drag' => array( 56 'snapGrid' => 'grid', 57 'container' => 'containment', 58 ), 59 'drop' => array( 60 'leave' => 'out', 61 'hover' => 'over' 62 ), 63 'slider' => array( 64 'complete' => 'stop', 65 'direction' => 'orientation' 66 ) 67 ); 68 69/** 70 * Callback arguments lists 71 * 72 * @var string 73 */ 74 protected $_callbackArguments = array( 75 'slider' => array( 76 'start' => 'event, ui', 77 'slide' => 'event, ui', 78 'change' => 'event, ui', 79 'stop' => 'event, ui' 80 ), 81 'sortable' => array( 82 'start' => 'event, ui', 83 'sort' => 'event, ui', 84 'change' => 'event, ui', 85 'beforeStop' => 'event, ui', 86 'stop' => 'event, ui', 87 'update' => 'event, ui', 88 'receive' => 'event, ui', 89 'remove' => 'event, ui', 90 'over' => 'event, ui', 91 'out' => 'event, ui', 92 'activate' => 'event, ui', 93 'deactivate' => 'event, ui' 94 ), 95 'drag' => array( 96 'start' => 'event, ui', 97 'drag' => 'event, ui', 98 'stop' => 'event, ui', 99 ), 100 'drop' => array( 101 'activate' => 'event, ui', 102 'deactivate' => 'event, ui', 103 'over' => 'event, ui', 104 'out' => 'event, ui', 105 'drop' => 'event, ui' 106 ), 107 'request' => array( 108 'beforeSend' => 'XMLHttpRequest', 109 'error' => 'XMLHttpRequest, textStatus, errorThrown', 110 'success' => 'data, textStatus', 111 'complete' => 'XMLHttpRequest, textStatus', 112 'xhr' => '' 113 ) 114 ); 115 116/** 117 * The variable name of the jQuery Object, useful 118 * when jQuery is put into noConflict() mode. 119 * 120 * @var string 121 */ 122 public $jQueryObject = '$'; 123 124/** 125 * Helper function to wrap repetitive simple method templating. 126 * 127 * @param string $method The method name being generated. 128 * @param string $template The method template 129 * @param array $options Array of options for method 130 * @param array $extraSafeKeys Extra safe keys 131 * @return string Composed method string 132 */ 133 protected function _methodTemplate($method, $template, $options, $extraSafeKeys = array()) { 134 $options = $this->_mapOptions($method, $options); 135 $options = $this->_prepareCallbacks($method, $options); 136 $callbacks = array_keys($this->_callbackArguments[$method]); 137 if (!empty($extraSafeKeys)) { 138 $callbacks = array_merge($callbacks, $extraSafeKeys); 139 } 140 $options = $this->_parseOptions($options, $callbacks); 141 return sprintf($template, $this->selection, $options); 142 } 143 144/** 145 * Create javascript selector for a CSS rule 146 * 147 * @param string $selector The selector that is targeted 148 * @return self 149 */ 150 public function get($selector) { 151 if ($selector === 'window' || $selector === 'document') { 152 $this->selection = $this->jQueryObject . '(' . $selector . ')'; 153 } else { 154 $this->selection = $this->jQueryObject . '("' . $selector . '")'; 155 } 156 return $this; 157 } 158 159/** 160 * Add an event to the script cache. Operates on the currently selected elements. 161 * 162 * ### Options 163 * 164 * - 'wrap' - Whether you want the callback wrapped in an anonymous function. (defaults true) 165 * - 'stop' - Whether you want the event to stopped. (defaults true) 166 * 167 * @param string $type Type of event to bind to the current dom id 168 * @param string $callback The JavaScript function you wish to trigger or the function literal 169 * @param array $options Options for the event. 170 * @return string completed event handler 171 */ 172 public function event($type, $callback, $options = array()) { 173 $defaults = array('wrap' => true, 'stop' => true); 174 $options += $defaults; 175 176 $function = 'function (event) {%s}'; 177 if ($options['wrap'] && $options['stop']) { 178 $callback .= "\nreturn false;"; 179 } 180 if ($options['wrap']) { 181 $callback = sprintf($function, $callback); 182 } 183 return sprintf('%s.bind("%s", %s);', $this->selection, $type, $callback); 184 } 185 186/** 187 * Create a domReady event. For jQuery. This method does not 188 * bind a 'traditional event' as `$(document).bind('ready', fn)` 189 * Works in an entirely different fashion than `$(document).ready()` 190 * The first will not run the function when eval()'d as part of a response 191 * The second will. Because of the way that ajax pagination is done 192 * `$().ready()` is used. 193 * 194 * @param string $functionBody The code to run on domReady 195 * @return string completed domReady method 196 */ 197 public function domReady($functionBody) { 198 return $this->jQueryObject . '(document).ready(function () {' . $functionBody . '});'; 199 } 200 201/** 202 * Create an iteration over the current selection result. 203 * 204 * @param string $callback The function body you wish to apply during the iteration. 205 * @return string completed iteration 206 */ 207 public function each($callback) { 208 return $this->selection . '.each(function () {' . $callback . '});'; 209 } 210 211/** 212 * Trigger an Effect. 213 * 214 * @param string $name The name of the effect to trigger. 215 * @param array $options Array of options for the effect. 216 * @return string completed string with effect. 217 * @see JsBaseEngineHelper::effect() 218 */ 219 public function effect($name, $options = array()) { 220 $speed = null; 221 if (isset($options['speed']) && in_array($options['speed'], array('fast', 'slow'))) { 222 $speed = $this->value($options['speed']); 223 } 224 $effect = ''; 225 switch ($name) { 226 case 'slideIn': 227 case 'slideOut': 228 $name = ($name === 'slideIn') ? 'slideDown' : 'slideUp'; 229 case 'hide': 230 case 'show': 231 case 'fadeIn': 232 case 'fadeOut': 233 case 'slideDown': 234 case 'slideUp': 235 $effect = ".$name($speed);"; 236 break; 237 } 238 return $this->selection . $effect; 239 } 240 241/** 242 * Create an $.ajax() call. 243 * 244 * If the 'update' key is set, success callback will be overridden. 245 * 246 * @param string|array $url URL 247 * @param array $options See JsHelper::request() for options. 248 * @return string The completed ajax call. 249 * @see JsBaseEngineHelper::request() for options list. 250 */ 251 public function request($url, $options = array()) { 252 $url = html_entity_decode($this->url($url), ENT_COMPAT, Configure::read('App.encoding')); 253 $options = $this->_mapOptions('request', $options); 254 if (isset($options['data']) && is_array($options['data'])) { 255 $options['data'] = $this->_toQuerystring($options['data']); 256 } 257 $options['url'] = $url; 258 if (isset($options['update'])) { 259 $wrapCallbacks = isset($options['wrapCallbacks']) ? $options['wrapCallbacks'] : true; 260 $success = ''; 261 if (isset($options['success']) && !empty($options['success'])) { 262 $success .= $options['success']; 263 } 264 $success .= $this->jQueryObject . '("' . $options['update'] . '").html(data);'; 265 if (!$wrapCallbacks) { 266 $success = 'function (data, textStatus) {' . $success . '}'; 267 } 268 $options['dataType'] = 'html'; 269 $options['success'] = $success; 270 unset($options['update']); 271 } 272 $callbacks = array('success', 'error', 'beforeSend', 'complete', 'xhr'); 273 if (!empty($options['dataExpression'])) { 274 $callbacks[] = 'data'; 275 unset($options['dataExpression']); 276 } 277 $options = $this->_prepareCallbacks('request', $options); 278 $options = $this->_parseOptions($options, $callbacks); 279 return $this->jQueryObject . '.ajax({' . $options . '});'; 280 } 281 282/** 283 * Create a sortable element. 284 * 285 * Requires both Ui.Core and Ui.Sortables to be loaded. 286 * 287 * @param array $options Array of options for the sortable. 288 * @return string Completed sortable script. 289 * @see JsBaseEngineHelper::sortable() for options list. 290 */ 291 public function sortable($options = array()) { 292 $template = '%s.sortable({%s});'; 293 return $this->_methodTemplate('sortable', $template, $options); 294 } 295 296/** 297 * Create a Draggable element 298 * 299 * Requires both Ui.Core and Ui.Draggable to be loaded. 300 * 301 * @param array $options Array of options for the draggable element. 302 * @return string Completed Draggable script. 303 * @see JsBaseEngineHelper::drag() for options list. 304 */ 305 public function drag($options = array()) { 306 $template = '%s.draggable({%s});'; 307 return $this->_methodTemplate('drag', $template, $options); 308 } 309 310/** 311 * Create a Droppable element 312 * 313 * Requires both Ui.Core and Ui.Droppable to be loaded. 314 * 315 * @param array $options Array of options for the droppable element. 316 * @return string Completed Droppable script. 317 * @see JsBaseEngineHelper::drop() for options list. 318 */ 319 public function drop($options = array()) { 320 $template = '%s.droppable({%s});'; 321 return $this->_methodTemplate('drop', $template, $options); 322 } 323 324/** 325 * Create a Slider element 326 * 327 * Requires both Ui.Core and Ui.Slider to be loaded. 328 * 329 * @param array $options Array of options for the droppable element. 330 * @return string Completed Slider script. 331 * @see JsBaseEngineHelper::slider() for options list. 332 */ 333 public function slider($options = array()) { 334 $callbacks = array('start', 'change', 'slide', 'stop'); 335 $template = '%s.slider({%s});'; 336 return $this->_methodTemplate('slider', $template, $options, $callbacks); 337 } 338 339/** 340 * Serialize a form attached to $selector. If the current selection is not an input or 341 * form, errors will be created in the JavaScript. 342 * 343 * @param array $options Options for the serialization 344 * @return string completed form serialization script. 345 * @see JsBaseEngineHelper::serializeForm() for option list. 346 */ 347 public function serializeForm($options = array()) { 348 $options += array('isForm' => false, 'inline' => false); 349 $selector = $this->selection; 350 if (!$options['isForm']) { 351 $selector = $this->selection . '.closest("form")'; 352 } 353 $method = '.serialize()'; 354 if (!$options['inline']) { 355 $method .= ';'; 356 } 357 return $selector . $method; 358 } 359 360} 361