diff --git a/cake/libs/view/helpers/ajax.php b/cake/libs/view/helpers/ajax.php index 481501eb0..9ad289261 100644 --- a/cake/libs/view/helpers/ajax.php +++ b/cake/libs/view/helpers/ajax.php @@ -58,49 +58,78 @@ class AjaxHelper extends AppHelper { * * @var array */ - var $callbacks = array('complete', 'create', 'exception', 'failure', 'interactive', 'loading', 'loaded', 'success', 'uninitialized'); + var $callbacks = array( + 'complete', 'create', 'exception', 'failure', 'interactive', 'loading', + 'loaded', 'success', 'uninitialized' + ); /** * Names of AJAX options. * * @var array */ - var $ajaxOptions = array('after', 'asynchronous', 'before', 'confirm', 'condition', 'contentType', 'encoding', 'evalScripts', 'failure', 'fallback', 'form', 'indicator', 'insertion', 'interactive', 'loaded', 'loading', 'method', 'onCreate', 'onComplete', 'onException', 'onFailure', 'onInteractive', 'onLoaded', 'onLoading', 'onSuccess', 'onUninitialized', 'parameters', 'position', 'postBody', 'requestHeaders', 'success', 'type', 'update', 'with'); + var $ajaxOptions = array( + 'after', 'asynchronous', 'before', 'confirm', 'condition', 'contentType', 'encoding', + 'evalScripts', 'failure', 'fallback', 'form', 'indicator', 'insertion', 'interactive', + 'loaded', 'loading', 'method', 'onCreate', 'onComplete', 'onException', 'onFailure', + 'onInteractive', 'onLoaded', 'onLoading', 'onSuccess', 'onUninitialized', 'parameters', + 'position', 'postBody', 'requestHeaders', 'success', 'type', 'update', 'with' + ); /** * Options for draggable. * * @var array */ - var $dragOptions = array('handle', 'revert', 'snap', 'zindex', 'constraint', 'change', 'ghosting', 'starteffect', 'reverteffect', 'endeffect'); + var $dragOptions = array( + 'handle', 'revert', 'snap', 'zindex', 'constraint', 'change', 'ghosting', + 'starteffect', 'reverteffect', 'endeffect' + ); /** * Options for droppable. * * @var array */ - var $dropOptions = array('accept', 'containment', 'greedy', 'hoverclass', 'onHover', 'onDrop', 'overlap'); + var $dropOptions = array( + 'accept', 'containment', 'greedy', 'hoverclass', 'onHover', 'onDrop', 'overlap' + ); /** * Options for sortable. * * @var array */ - var $sortOptions = array('constraint', 'containment', 'dropOnEmpty', 'ghosting', 'handle', 'hoverclass', 'onUpdate', 'onChange', 'only', 'overlap', 'scroll', 'scrollSensitivity', 'scrollSpeed', 'tag', 'tree', 'treeTag', 'update'); + var $sortOptions = array( + 'constraint', 'containment', 'dropOnEmpty', 'ghosting', 'handle', 'hoverclass', 'onUpdate', + 'onChange', 'only', 'overlap', 'scroll', 'scrollSensitivity', 'scrollSpeed', 'tag', 'tree', + 'treeTag', 'update' + ); /** * Options for slider. * * @var array */ - var $sliderOptions = array('alignX', 'alignY', 'axis', 'disabled', 'handleDisabled', 'handleImage', 'increment', 'maximum', 'minimum', 'onChange', 'onSlide', 'range', 'sliderValue', 'values'); + var $sliderOptions = array( + 'alignX', 'alignY', 'axis', 'disabled', 'handleDisabled', 'handleImage', 'increment', + 'maximum', 'minimum', 'onChange', 'onSlide', 'range', 'sliderValue', 'values' + ); /** * Options for in-place editor. * * @var array */ - var $editorOptions = array('okText', 'cancelText', 'savingText', 'formId', 'externalControl', 'rows', 'cols', 'size', 'highlightcolor', 'highlightendcolor', 'savingClassName', 'formClassName', 'loadTextURL', 'loadingText', 'callback', 'ajaxOptions', 'clickToEditText', 'collection', 'okButton', 'cancelLink', 'submitOnBlur'); + var $editorOptions = array( + 'okText', 'cancelText', 'savingText', 'formId', 'externalControl', 'rows', 'cols', 'size', + 'highlightcolor', 'highlightendcolor', 'savingClassName', 'formClassName', 'loadTextURL', + 'loadingText', 'callback', 'ajaxOptions', 'clickToEditText', 'collection', 'okButton', + 'cancelLink', 'submitOnBlur' + ); /** * Options for auto-complete editor. * * @var array */ - var $autoCompleteOptions = array('afterUpdateElement', 'callback', 'frequency', 'indicator', 'minChars', 'onShow', 'onHide', 'parameters', 'paramName', 'tokens', 'updateElement'); + var $autoCompleteOptions = array( + 'afterUpdateElement', 'callback', 'frequency', 'indicator', 'minChars', 'onShow', 'onHide', + 'parameters', 'paramName', 'tokens', 'updateElement' + ); /** * Output buffer for Ajax update content * @@ -187,11 +216,13 @@ class AjaxHelper extends AppHelper { if (empty($options['fallback']) || !isset($options['fallback'])) { $options['fallback'] = $href; } - $htmlOptions = array_merge(array('id' => 'link' . intval(mt_rand()), 'onclick' => ''), $htmlOptions); + $htmlDefaults = array('id' => 'link' . intval(mt_rand()), 'onclick' => ''); + $htmlOptions = array_merge($htmlDefaults, $htmlOptions); $htmlOptions['onclick'] .= ' event.returnValue = false; return false;'; $return = $this->Html->link($title, $href, $htmlOptions, null, $escapeTitle); - $script = $this->Javascript->event("'{$htmlOptions['id']}'", "click", $this->remoteFunction($options)); + $callback = $this->remoteFunction($options); + $script = $this->Javascript->event("'{$htmlOptions['id']}'", "click", $callback); if (is_string($script)) { $return .= $script; @@ -248,30 +279,40 @@ class AjaxHelper extends AppHelper { /** * Periodically call remote url via AJAX. * - * Periodically calls the specified url (options[url]) every options[frequency] seconds (default is 10). - * Usually used to update a specified div (options[update]) with the results of the remote call. - * The options for specifying the target with url and defining callbacks is the same as linkToRemote. + * Periodically calls the specified url (options[url]) every options[frequency] + * seconds (default is 10). Usually used to update a specified div (options[update]) with + * the results of the remote call. The options for specifying the target with url and defining + * callbacks is the same as AjaxHelper::link(). * * @param array $options Callback options * @return string Javascript code + * @see AjaxHelper::link() */ function remoteTimer($options = null) { $frequency = (isset($options['frequency'])) ? $options['frequency'] : 10; - $code = "new PeriodicalExecuter(function() {" . $this->remoteFunction($options) . "}, $frequency)"; + $callback = $this->remoteFunction($options); + $code = "new PeriodicalExecuter(function() {{$callback}}, $frequency)"; return $this->Javascript->codeBlock($code); } /** * Returns form tag that will submit using Ajax. * * Returns a form tag that will submit using XMLHttpRequest in the background instead of the regular - * reloading POST arrangement. Even though it's using Javascript to serialize the form elements, the form submission - * will work just like a regular submission as viewed by the receiving side (all elements available in params). - * The options for defining callbacks is the same as link(). + * reloading POST arrangement. Even though it's using Javascript to serialize the form elements, + * the form submission will work just like a regular submission as viewed by the receiving side + * (all elements available in params). The options for defining callbacks is the same + * as AjaxHelper::link(). * - * @param array $params Form target + * @param mixed $params Either a string identifying the form target, or an array of method + * parameters, including: + * - 'params' => Acts as the form target + * - 'type' => 'post' or 'get' + * - 'options' => An array containing all HTML and script options used to + * generate the form tag and Ajax request. * @param array $type How form data is posted: 'get' or 'post' * @param array $options Callback/HTML options * @return string JavaScript/HTML code + * @see AjaxHelper::link() */ function form($params = null, $type = 'post', $options = array()) { $model = false; @@ -283,25 +324,33 @@ class AjaxHelper extends AppHelper { $options['url'] = array('action' => $params); } - $htmlOptions = array_merge(array( - 'id' => 'form' . intval(mt_rand()), 'onsubmit' => "event.returnValue = false; return false;", - 'type' => $type), - $this->__getHtmlOptions($options, array('model', 'with')) + $htmlDefaults = array( + 'id' => 'form' . intval(mt_rand()), + 'onsubmit' => "event.returnValue = false; return false;", + 'type' => $type ); + $htmlOptions = $this->__getHtmlOptions($options, array('model', 'with')); + $htmlOptions = array_merge($htmlDefaults, $htmlOptions); - $options = array_merge(array('model' => $model,'with' => "Form.serialize('{$htmlOptions['id']}')"), $options); - return $this->Form->create($options['model'], $htmlOptions) - . $this->Javascript->event("'" . $htmlOptions['id']. "'", 'submit', $this->remoteFunction($options)); + $defaults = array('model' => $model, 'with' => "Form.serialize('{$htmlOptions['id']}')"); + $options = array_merge($defaults, $options); + $callback = $this->remoteFunction($options); + + $form = $this->Form->create($options['model'], $htmlOptions); + $script = $this->Javascript->event("'" . $htmlOptions['id']. "'", 'submit', $callback); + return $form . $script; } /** * Returns a button input tag that will submit using Ajax * - * Returns a button input tag that will submit form using XMLHttpRequest in the background instead of regular - * reloading POST arrangement. options argument is the same as in form_remote_tag + * Returns a button input tag that will submit form using XMLHttpRequest in the background instead + * of regular reloading POST arrangement. options argument is the same as + * in AjaxHelper::form(). * * @param string $title Input button title * @param array $options Callback options * @return string Ajaxed input button + * @see AjaxHelper::form() */ function submit($title = 'Submit', $options = array()) { $htmlOptions = $this->__getHtmlOptions($options); @@ -315,8 +364,11 @@ class AjaxHelper extends AppHelper { } $htmlOptions['onclick'] = "event.returnValue = false; return false;"; - return $this->Form->submit($title, $htmlOptions) - . $this->Javascript->event('"' . $htmlOptions['id'] . '"', 'click', $this->remoteFunction($options)); + $callback = $this->remoteFunction($options); + + $form = $this->Form->submit($title, $htmlOptions); + $script = $this->Javascript->event('"' . $htmlOptions['id'] . '"', 'click', $callback); + return $form . $script; } /** * Observe field and call ajax on change. @@ -354,7 +406,9 @@ class AjaxHelper extends AppHelper { if (!isset($options['frequency']) || intval($options['frequency']) == 0) { $observer = 'EventObserver'; } - return $this->Javascript->codeBlock($this->_buildObserver('Form.Element.' . $observer, $field, $options)); + return $this->Javascript->codeBlock( + $this->_buildObserver('Form.Element.' . $observer, $field, $options) + ); } /** * Observe entire form and call ajax on change. @@ -376,7 +430,9 @@ class AjaxHelper extends AppHelper { if (!isset($options['frequency']) || intval($options['frequency']) == 0) { $observer = 'EventObserver'; } - return $this->Javascript->codeBlock($this->_buildObserver('Form.' . $observer, $form, $options)); + return $this->Javascript->codeBlock( + $this->_buildObserver('Form.' . $observer, $form, $options) + ); } /** * Create a text field with Autocomplete. @@ -402,7 +458,11 @@ class AjaxHelper extends AppHelper { $options['id'] = Inflector::camelize(str_replace(".", "_", $field)); } - $divOptions = array('id' => $options['id'] . "_autoComplete", 'class' => isset($options['class']) ? $options['class'] : 'auto_complete'); + $divOptions = array( + 'id' => $options['id'] . "_autoComplete", + 'class' => isset($options['class']) ? $options['class'] : 'auto_complete' + ); + if (isset($options['div_id'])) { $divOptions['id'] = $options['div_id']; unset($options['div_id']); @@ -426,11 +486,13 @@ class AjaxHelper extends AppHelper { $options = $this->_optionsToString($options, array('paramName', 'indicator')); $options = $this->_buildOptions($options, $this->autoCompleteOptions); - return $this->Form->text($field, $htmlOptions) . "\n" . - $this->Html->div(null, '', $divOptions) . "\n" . - $this->Javascript->codeBlock("{$var}new Ajax.Autocompleter('" . $htmlOptions['id'] - . "', '" . $divOptions['id'] . "', '" . $this->Html->url($url) . "', " . - $options . ");"); + + $text = $this->Form->text($field, $htmlOptions); + $div = $this->Html->div(null, '', $divOptions); + $script = "{$var}new Ajax.Autocompleter('{$htmlOptions['id']}', '{$divOptions['id']}', '"; + $script .= $this->Html->url($url) . "', {$options});"; + + return "{$text}\n{$div}\n" . $this->Javascript->codeBlock($script); } /** * Creates an Ajax-updateable DIV element @@ -492,7 +554,9 @@ class AjaxHelper extends AppHelper { $var = 'var ' . $options['var'] . ' = '; unset($options['var']); } - $options = $this->_buildOptions($this->_optionsToString($options, array('handle', 'constraint')), $this->dragOptions); + $options = $this->_buildOptions( + $this->_optionsToString($options, array('handle', 'constraint')), $this->dragOptions + ); return $this->Javascript->codeBlock("{$var}new Draggable('$id', " .$options . ");"); } /** @@ -510,7 +574,9 @@ class AjaxHelper extends AppHelper { } else if (isset($options['accept'])) { $options['accept'] = $this->Javascript->object($options['accept']); } - $options = $this->_buildOptions($this->_optionsToString($options, $optionsString), $this->dropOptions); + $options = $this->_buildOptions( + $this->_optionsToString($options, $optionsString), $this->dropOptions + ); return $this->Javascript->codeBlock("Droppables.add('{$id}', {$options});"); } /** @@ -526,14 +592,20 @@ class AjaxHelper extends AppHelper { * @return string JavaScript block to create a droppable element */ function dropRemote($id, $options = array(), $ajaxOptions = array()) { - $options['onDrop'] = "function(element, droppable, event) {" . $this->remoteFunction($ajaxOptions) . "}"; + $callback = $this->remoteFunction($ajaxOptions); + $options['onDrop'] = "function(element, droppable, event) {{$callback}}"; $optionsString = array('overlap', 'hoverclass'); + if (!isset($options['accept']) || !is_array($options['accept'])) { $optionsString[] = 'accept'; } else if (isset($options['accept'])) { $options['accept'] = $this->Javascript->object($options['accept']); } - $options = $this->_buildOptions($this->_optionsToString($options, $optionsString), $this->dropOptions); + + $options = $this->_buildOptions( + $this->_optionsToString($options, $optionsString), + $this->dropOptions + ); return $this->Javascript->codeBlock("Droppables.add('{$id}', {$options});"); } /** @@ -552,12 +624,15 @@ class AjaxHelper extends AppHelper { $var = 'var ' . $id . ' = '; } - $options = $this->_optionsToString($options, array('axis', 'handleImage', 'handleDisabled')); + $options = $this->_optionsToString($options, array( + 'axis', 'handleImage', 'handleDisabled' + )); $callbacks = array('change', 'slide'); foreach ($callbacks as $callback) { if (isset($options[$callback])) { - $options['on' . ucfirst($callback)] = 'function(value) {' . $options[$callback] . '}'; + $call = $options[$callback]; + $options['on' . ucfirst($callback)] = "function(value) {{$call}}"; unset($options[$callback]); } } @@ -567,7 +642,8 @@ class AjaxHelper extends AppHelper { } $options = $this->_buildOptions($options, $this->sliderOptions); - return $this->Javascript->codeBlock("{$var}new Control.Slider('$id', '$trackId', $options);"); + $script = "{$var}new Control.Slider('$id', '$trackId', $options);"; + return $this->Javascript->codeBlock($script); } /** * Makes an Ajax In Place editor control. @@ -603,9 +679,14 @@ class AjaxHelper extends AppHelper { unset($options['var']); } - $options = $this->_optionsToString($options, array('okText', 'cancelText', 'savingText', 'formId', 'externalControl', 'highlightcolor', 'highlightendcolor', 'savingClassName', 'formClassName', 'loadTextURL', 'loadingText', 'clickToEditText', 'okButton', 'cancelLink')); + $options = $this->_optionsToString($options, array( + 'okText', 'cancelText', 'savingText', 'formId', 'externalControl', 'highlightcolor', + 'highlightendcolor', 'savingClassName', 'formClassName', 'loadTextURL', 'loadingText', + 'clickToEditText', 'okButton', 'cancelLink' + )); $options = $this->_buildOptions($options, $this->editorOptions); - return $this->Javascript->codeBlock("{$var}new Ajax.{$type}('{$id}', '{$url}', {$options});"); + $script = "{$var}new Ajax.{$type}('{$id}', '{$url}', {$options});"; + return $this->Javascript->codeBlock($script); } /** * Makes a list or group of floated objects sortable. @@ -627,8 +708,17 @@ class AjaxHelper extends AppHelper { $block = $options['block']; unset($options['block']); } - $strings = array('tag', 'constraint', 'only', 'handle', 'hoverclass', 'tree', 'treeTag', 'update', 'overlap'); - if (isset($options['scroll']) && $options['scroll'] != 'window' && strpos($options['scroll'], '$(') !== 0) { + $strings = array( + 'tag', 'constraint', 'only', 'handle', 'hoverclass', 'tree', + 'treeTag', 'update', 'overlap' + ); + $scrollIsObject = ( + isset($options['scroll']) && + $options['scroll'] != 'window' && + strpos($options['scroll'], '$(') !== 0 + ); + + if ($scrollIsObject) { $strings[] = 'scroll'; } @@ -636,6 +726,7 @@ class AjaxHelper extends AppHelper { $options = array_merge($options, $this->_buildCallbacks($options)); $options = $this->_buildOptions($options, $this->sortOptions); $result = "Sortable.create('$id', $options);"; + if (!$block) { return $result; } @@ -650,7 +741,9 @@ class AjaxHelper extends AppHelper { function __optionsForAjax($options) { if (isset($options['indicator'])) { if (isset($options['loading'])) { - if (!empty($options['loading']) && substr(trim($options['loading']), -1, 1) != ';') { + $loading = $options['loading']; + + if (!empty($loading) && substr(trim($loading), -1, 1) != ';') { $options['loading'] .= '; '; } $options['loading'] .= "Element.show('{$options['indicator']}');"; @@ -658,7 +751,9 @@ class AjaxHelper extends AppHelper { $options['loading'] = "Element.show('{$options['indicator']}');"; } if (isset($options['complete'])) { - if (!empty($options['complete']) && substr(trim($options['complete']), -1, 1) != ';') { + $complete = $options['complete']; + + if (!empty($complete) && substr(trim($complete), -1, 1) != ';') { $options['complete'] .= '; '; } $options['complete'] .= "Element.hide('{$options['indicator']}');"; @@ -672,8 +767,13 @@ class AjaxHelper extends AppHelper { array('asynchronous' => 'true', 'evalScripts' => 'true'), $this->_buildCallbacks($options) ); - $options = $this->_optionsToString($options, array('contentType', 'encoding', 'fallback', 'method', 'postBody', 'update', 'url')); - $jsOptions = array_merge($jsOptions, array_intersect_key($options, array_flip(array('contentType', 'encoding', 'method', 'postBody')))); + + $options = $this->_optionsToString($options, array( + 'contentType', 'encoding', 'fallback', 'method', 'postBody', 'update', 'url' + )); + $jsOptions = array_merge($jsOptions, array_intersect_key($options, array_flip(array( + 'contentType', 'encoding', 'method', 'postBody' + )))); foreach ($options as $key => $value) { switch ($key) { @@ -684,7 +784,8 @@ class AjaxHelper extends AppHelper { $jsOptions['evalScripts'] = ($value) ? 'true' : 'false'; break; case 'position': - $jsOptions['insertion'] = "Insertion." . Inflector::camelize($options['position']); + $pos = Inflector::camelize($options['position']); + $jsOptions['insertion'] = "Insertion.{$pos}"; break; case 'with': $jsOptions['parameters'] = $options['with']; @@ -766,10 +867,10 @@ class AjaxHelper extends AppHelper { } $callback = $this->remoteFunction($options); - $javascript = "new $klass('$name', "; - $javascript .= (!isset($options['frequency']) || intval($options['frequency']) == 0 ? '' : $options['frequency'] . ', ' ) . "function(element, value) {"; - $javascript .= "$callback})"; - return $javascript; + $hasFrequency = !(!isset($options['frequency']) || intval($options['frequency']) == 0); + $frequency = $hasFrequency ? $options['frequency'] . ', ' : ''; + + return "new $klass('$name', {$frequency}function(element, value) {{$callback}})"; } /** * Return Javascript text for callbacks. @@ -800,7 +901,14 @@ class AjaxHelper extends AppHelper { break; } if (isset($options['bind'])) { - if ((is_array($options['bind']) && in_array($callback, $options['bind'])) || (is_string($options['bind']) && strpos($options['bind'], $callback) !== false)) { + $bind = $options['bind']; + + $hasBinding = ( + (is_array($bind) && in_array($callback, $bind)) || + (is_string($bind) && strpos($bind, $callback) !== false) + ); + + if ($hasBinding) { $callbacks[$name] .= ".bind(this)"; } } @@ -818,7 +926,12 @@ class AjaxHelper extends AppHelper { */ function _optionsToString($options, $stringOpts = array()) { foreach ($stringOpts as $option) { - if (isset($options[$option]) && !empty($options[$option]) && is_string($options[$option]) && $options[$option][0] != "'") { + $hasOption = ( + isset($options[$option]) && !empty($options[$option]) && + is_string($options[$option]) && $options[$option][0] != "'" + ); + + if ($hasOption) { if ($options[$option] === true || $options[$option] === 'true') { $options[$option] = 'true'; } elseif ($options[$option] === false || $options[$option] === 'false') { @@ -853,7 +966,9 @@ class AjaxHelper extends AppHelper { } } $out = 'var __ajaxUpdater__ = {' . join(", \n", $data) . '};' . "\n"; - $out .= 'for (n in __ajaxUpdater__) { if (typeof __ajaxUpdater__[n] == "string" && $(n)) Element.update($(n), unescape(decodeURIComponent(__ajaxUpdater__[n]))); }'; + $out .= 'for (n in __ajaxUpdater__) { if (typeof __ajaxUpdater__[n] == "string"'; + $out .= ' && $(n)) Element.update($(n), unescape(decodeURIComponent('; + $out .= '__ajaxUpdater__[n]))); }'; e($this->Javascript->codeBlock($out, false)); } $scripts = $this->Javascript->getCache(); @@ -866,4 +981,5 @@ class AjaxHelper extends AppHelper { } } } + ?> \ No newline at end of file