getResponse()->addJavascript($path, 'first'); /** * Add a jQuery Plugin on the head DOM after the jQuery call * * Examples: * * * tom@punkave.com: corrected path /*/ function jq_add_plugin($options = array()) { // tom@punkave.com: with a singular name (jq_add_plugin), this function // really should accept a non-array argument if (!is_array($options)) { $options = array($options); } foreach ( $options as $o ) { sfContext::getInstance ()->getResponse ()->addJavascript (sfConfig::get('sf_jquery_web_dir', '/sfJqueryReloadedPlugin') . "/js/plugins/$o"); } } /** * Periodically calls the specified url ('url') every 'frequency' seconds (default is 10). * Usually used to update a specified div ('update') with the results of the remote call. * The options for specifying the target with 'url' and defining callbacks is the same as 'link_to_remote()'. */ function jq_periodically_call_remote($options = array()) { $frequency = isset($options['frequency']) ? $options['frequency'] : 10; // every ten seconds by default $code = 'setInterval(function() {'.jq_remote_function($options).'}, '.($frequency * 1000).')'; return javascript_tag($code); } /** * Returns an html button to a remote action defined by 'url' (using the * 'url_for()' format) that's called in the background using XMLHttpRequest. * * See link_to_remote() for details. * */ function jq_button_to_remote($name, $options = array(), $html_options = array()) { return jq_button_to_function($name, jq_remote_function($options), $html_options); } /** * Returns a link to a remote action defined by 'url' * (using the 'url_for()' format) that's called in the background using * XMLHttpRequest. The result of that request can then be inserted into a * DOM object whose id can be specified with 'update'. * Usually, the result would be a partial prepared by the controller with * either 'render_partial()'. * * Examples: * 'posts', * 'url' => 'destroy?id='.$post.id, * )) ?> * 'emails', * 'url' => '@list_emails', * )) ?> * * You can also specify a hash for 'update' to allow for * easy redirection of output to an other DOM element if a server-side error occurs: * * Example: * array('success' => 'posts', 'failure' => 'error'), * 'url' => 'destroy?id='.$post.id, * )) ?> * * Optionally, you can use the 'position' parameter to influence * how the target DOM element is updated. It must be one of * 'before', 'top', 'bottom', or 'after'. * * By default, these remote requests are processed asynchronous during * which various JavaScript callbacks can be triggered (for progress indicators and * the likes). All callbacks get access to the 'request' object, * which holds the underlying XMLHttpRequest. * * To access the server response, use 'request.responseText', to * find out the HTTP status, use 'request.status'. * * If you are using JSON, you can access it via the 'data' parameter * * Example: * '@undo?n='.$word_counter, * 'complete' => 'undoRequestCompleted(request)' * )) ?> * * The callbacks that may be specified are (in order): * * 'loading' Called when the remote document is being * loaded with data by the browser. * 'loaded' Called when the browser has finished loading * the remote document. * 'interactive' Called when the user can interact with the * remote document, even though it has not * finished loading. * 'success' Called when the XMLHttpRequest is completed, * and the HTTP status code is in the 2XX range. * 'failure' Called when the XMLHttpRequest is completed, * and the HTTP status code is not in the 2XX * range. * 'complete' Called when the XMLHttpRequest is complete * (fires after success/failure if they are present)., * * You can further refine 'success' and 'failure' by adding additional * callbacks for specific status codes: * * Example: * '@rule', * '404' => "alert('Not found...? Wrong URL...?')", * 'failure' => "alert('HTTP Error ' + request.status + '!')", * )) ?> * * A status code callback overrides the success/failure handlers if present. * * If you for some reason or another need synchronous processing (that'll * block the browser while the request is happening), you can specify * 'type' => 'synchronous'. * * You can customize further browser side call logic by passing * in JavaScript code snippets via some optional parameters. In * their order of use these are: * * 'confirm' Adds confirmation dialog. * 'condition' Perform remote request conditionally * by this expression. Use this to * describe browser-side conditions when * request should not be initiated. * 'before' Called before request is initiated. * 'after' Called immediately after request was * initiated and before 'loading'. * 'submit' Specifies the DOM element ID that's used * as the parent of the form elements. By * default this is the current form, but * it could just as well be the ID of a * table row or any other DOM element. */ function jq_link_to_remote($name, $options = array(), $html_options = array()) { return jq_link_to_function($name, jq_remote_function($options), $html_options); } /** * Returns a Javascript function (or expression) that will update a DOM element '$element_id' * according to the '$options' passed. * * Possible '$options' are: * 'content' The content to use for updating. Can be left out if using block, see example. * 'action' Valid options are 'update' (assumed by default), 'empty', 'remove' * 'position' If the 'action' is 'update', you can optionally specify one of the following positions: * 'before', 'top', 'bottom', 'after'. * * Example: * 'bottom', * 'content' => "

New product!

", * )) * ) ?> */ function jq_update_element_function($element_id, $options = array()) { $content = escape_javascript(isset($options['content']) ? $options['content'] : ''); $value = isset($options['action']) ? $options['action'] : 'update'; switch ($value) { case 'update': $updateMethod = _update_method(isset($options['position']) ? $options['position'] : ''); $javascript_function = "jQuery('#$element_id').$updateMethod('$content')"; break; case 'empty': $javascript_function = "jQuery('#$element_id').empty()"; break; case 'remove': $javascript_function = "jQuery('#$element_id').remove()"; break; default: throw new sfException('Invalid action, choose one of update, remove, empty'); } $javascript_function .= ";\n"; return (isset($options['binding']) ? $javascript_function.$options['binding'] : $javascript_function); } /** * Returns the javascript needed for a remote function. * Takes the same arguments as 'link_to_remote()'. * * Example: * */ function jq_remote_function($options) { // Defining elements to update if (isset($options['update']) && is_array($options['update'])) { // On success, update the element with returned data if (isset($options['update']['success'])) $update_success = "#".$options['update']['success']; // On failure, execute a client-side function if (isset($options['update']['failure'])) $update_failure = $options['update']['failure']; } else if (isset($options['update'])) $update_success = "#".$options['update']; // Update method $updateMethod = _update_method(isset($options['position']) ? $options['position'] : ''); // Callbacks if (isset($options['loading'])) $callback_loading = $options['loading']; if (isset($options['complete'])) $callback_complete = $options['complete']; if (isset($options['success'])) $callback_success = $options['success']; $execute = 'false'; if ((isset($options['script'])) && ($options['script'] == '1')) $execute = 'true'; // Data Type if (isset($options['dataType'])) { $dataType = $options['dataType']; } elseif ($execute) { $dataType = 'html'; } else { $dataType = 'text'; } // POST or GET ? $method = 'POST'; if ((isset($options['method'])) && (strtoupper($options['method']) == 'GET')) $method = $options['method']; // async or sync, async is default if ((isset($options['type'])) && ($options['type'] == 'synchronous')) $type = 'false'; // Is it a form submitting if (isset($options['form'])) $formData = 'jQuery(this).serialize()'; elseif (isset($options['submit'])) $formData = '{\'#'.$options['submit'].'\'}.serialize()'; // boutell and JoeZ99: 'with' should not be quoted, it's not useful // that way, see the Symfony documentation for the original remote_function elseif (isset($options['with'])) $formData = $options['with']; // build the function $function = "jQuery.ajax({"; $function .= 'type:\''.$method.'\''; $function .= ',dataType:\'' . $dataType . '\''; if (isset($type)) $function .= ',async:'.$type; if (isset($formData)) $function .= ',data:'.$formData; if (isset($update_success) and !isset($callback_success)) $function .= ',success:function(data, textStatus){jQuery(\''.$update_success.'\').'.$updateMethod.'(data);}'; if (isset($update_failure)) $function .= ',error:function(XMLHttpRequest, textStatus, errorThrown){'.$update_failure.'}'; if (isset($callback_loading)) $function .= ',beforeSend:function(XMLHttpRequest){'.$callback_loading.'}'; if (isset($callback_complete)) $function .= ',complete:function(XMLHttpRequest, textStatus){'.$callback_complete.'}'; if (isset($callback_success)) $function .= ',success:function(data, textStatus){'.$callback_success.'}'; $function .= ',url:\''.url_for($options['url']).'\''; $function .= '})'; if (isset($options['before'])) { $function = $options['before'].'; '.$function; } if (isset($options['after'])) { $function = $function.'; '.$options['after']; } if (isset($options['condition'])) { $function = 'if ('.$options['condition'].') { '.$function.'; }'; } if (isset($options['confirm'])) { $function = "if (confirm('".escape_javascript($options['confirm'])."')) { $function; }"; if (isset($options['cancel'])) { $function = $function.' else { '.$options['cancel'].' }'; } } return $function; } /** * 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 specifying the target with 'url' and defining callbacks are the same as 'link_to_remote()'. * * A "fall-through" target for browsers that don't do JavaScript can be specified * with the 'action'/'method' options on '$options_html' * * Example: * '@tag_add', * 'update' => 'question_tags', * 'loading' => "Element.show('indicator'); \$('tag').value = ''", * 'complete' => "Element.hide('indicator');".visual_effect('highlight', 'question_tags'), * )) ?> * * The hash passed as a second argument is equivalent to the options (2nd) argument in the form_tag() helper. * * By default the fall-through action is the same as the one specified in the 'url' * (and the default method is 'post'). */ function jq_form_remote_tag($options = array(), $options_html = array()) { $options = _parse_attributes($options); $options_html = _parse_attributes($options_html); $options['form'] = true; $options_html['onsubmit'] = jq_remote_function($options).'; return false;'; $options_html['action'] = isset($options_html['action']) ? $options_html['action'] : url_for($options['url']); $options_html['method'] = isset($options_html['method']) ? $options_html['method'] : 'post'; return tag('form', $options_html, true); } /** * Returns a JavaScript snippet to be used on the AJAX callbacks for starting * visual effects. * * * Visual effect support 3 optionnal options : callback, speed, opacity. Not all effect does support all options. * * List of effects (options that supported by this effect) * Effects: * - hide(speed, callback) * - show(speed, callback) * - slideDown(speed, callback) * - slideUp(speed, callback) * - slideToggle(speed, callback) * - fadeIn(speed, callback) * - fadeOut(speed, callback) * - fadeTo(speed, opacity, callback) * - toggle * * * * Example of effect that support speed + callback: * 'posts', * 'url' => '@reload', * 'complete => visual_effect('fade', '#posts', array('speed' => 'slow', 'callback' => 'function(){$("post_content").css("background", "yellow")}' )), * )) ?> * * Speed support 4 arguments : 'fast', 'normal', 'slow', number_in_miliseconds * * * * Example of effect that support speed + opacity + callback: * 'posts', * 'url' => '@reload', * 'complete => visual_effect('fadeTo', '#posts', array('speed' => 'slow', 'opacity' => '0.33', 'callback' => 'function(){$("post_content").css("background", "yellow")}' )), * )) ?> * * Opacity must be between 0 and 1, if none are specify or not between 0 and 1m, it assumes 0.5(default value) * * * * Element is optional so if you dont specify it assumes current element * Example * 'posts', * 'url' => '@reload', * 'complete => visual_effect('hide'), * )) ?> * * This would hide the form when request is completed * * * * Fore more information check the jquery doc * http://http://docs.jquery.com/Effects. */ function jq_visual_effect($effect, $element_id = false, $js_options = array()) { //format slide /fade effect name correctly. if(preg_match("/^(slide|fade)/i", $effect, $matches)) { $count = strtolower($matches[1]) == 'fade'? 3 : 4; $effect = preg_replace("/(^|_|-)+(.)/e", '', $effect); //remove non alpha char $effect = preg_replace('/\ +/', '', $effect); //remove space $effect = trim(strtolower($matches[1]).ucfirst(strtolower(substr($effect, $count)))); } else { $effect = trim(strtolower($effect)); } $element = $element_id ? "'$element_id'" : 'this'; //Building speed $speed = isset($js_options['speed'])? is_numeric($js_options['speed'] )?$js_options['speed'] : "'". $js_options['speed'] ."'": "'normal'"; //Building opacty $opacity = isset($js_options['opacity']) && is_numeric($js_options['opacity'] )?$js_options['opacity'] >= 0 && $js_options['opacity'] <= 1?$js_options['opacity'] :0.5:0.5; //Building callback $callback = isset($js_options['callback']) ? ", ". $js_options['callback'] :null; if(in_array($effect, array('hide', 'show','slideDown', 'slideUp', 'slideToggle', 'fadeIn', 'fadeOut'))) { return sprintf("jQuery(%s).%s(%s %s );", $element, $effect, $speed, $callback); } elseif($effect == "fadeTo") { return sprintf("jQuery(%s).%s(%s, %s %s);", $element, $effect, $speed, $opacity, $callback); } else { return sprintf("jQuery(%s).%s();", $element, $effect); } } /** * Returns a button input tag that will submit form using XMLHttpRequest in the background instead of regular * reloading POST arrangement. The '$options' argument is the same as in 'form_remote_tag()'. */ function jq_submit_to_remote($name, $value, $options = array(), $options_html = array()) { $options = _parse_attributes($options); $options_html = _parse_attributes($options_html); if (!isset($options['with'])) { $options['with'] = 'jQuery(this.form.elements).serialize()'; } $options_html['type'] = 'button'; $options_html['onclick'] = jq_remote_function($options).'; return false;'; $options_html['name'] = $name; $options_html['value'] = $value; return tag('input', $options_html, false); } /** * Returns a image submit tag that will submit form using XMLHttpRequest in the background instead of regular * reloading POST arrangement. The '$options' argument is the same as in 'form_remote_tag()'. */ function jq_submit_image_to_remote($name, $source, $options = array(), $options_html = array()) { $options = _parse_attributes($options); $options_html = _parse_attributes($options_html); if (!isset($options['with'])) { $options['with'] = 'jQuery(this.form.elements).serialize()'; } $options_html['type'] = 'image'; $options_html['onclick'] = jq_remote_function($options).' return false;'; $options_html['name'] = $name; $options_html['src'] = image_path($source); if (!isset($options_html['alt'])) { $path_pos = strrpos($source, '/'); $dot_pos = strrpos($source, '.'); $begin = $path_pos ? $path_pos + 1 : 0; $nb_str = ($dot_pos ? $dot_pos : strlen($source)) - $begin; $options_html['alt'] = ucfirst(substr($source, $begin, $nb_str)); } return tag('input', $options_html, false); } /** * Makes the elements matching the jQuery selector '$selector' * sortable by drag-and-drop and makes an AJAX call whenever the sort order * has changed. By default, the action called gets the serialized sortable * element as parameters. * * Example: * '@order', * )) ?> * * In the example, the action gets a 'foo' array parameter * containing the values of the ids of elements the sortable consists * of, in the current order. * * Additional options can be passed in the $options associative array * and will be sent to jquery as parameters. For example: * 'handle' => 'span' specifies that span elements within the * sortable element are the element the user actually clicks on * (although entire first-generation child elements of the * sortable element get reordered as a result). * * Added by tom@punkave.com. */ function jq_sortable_element($selector, $options = array()) { // We need ui.sortable for this trick jq_add_plugin(sfConfig::get('jquery_sortable', 'jquery-ui-sortable-1.6rc6.min.js')); $options = _parse_attributes($options); $url = json_encode(url_for($options['url'])); unset($options['url']); $jsonOptions = ''; foreach ($options as $key => $val) { $jsonOptions .= ", $key: " . json_encode($val); } $result = << * @param string name value of input field * @param string default value for input field * @param array input tag options. (size, autocomplete, etc...) * @param array completion options. (use_style, etc...) * * Example: * echo jq_input_auto_complete_tag('q','', 'search/index',array( * 'size' => 15),array( * 'use_style' => false, * 'scrollHeight' => 480, * 'scroll' => false, * 'highlight' => false, * ) ) ?> * * @return string input field tag, div for completion results, and * auto complete javascript tags */ function jq_input_auto_complete_tag($name, $value, $url, $tag_options = array(), $completion_options = array()) { // We need ui.autocomplete for this trick jq_add_plugin(sfConfig::get('jquery_autocomplete','jquery.autocomplete-1.0.2.min.js')); $tag_options = _convert_options($tag_options); $comp_options = _convert_options($completion_options); // Convert to JSON parameters $jsonOptions = ''; foreach ($comp_options as $key => $val) { if ($jsonOptions!='') { $jsonOptions .= ', '; } switch($key) { case 'formatItem': case 'formatResult': $jsonOptions .= "$key: " . $val; break; default: $jsonOptions .= "$key: " . json_encode($val); break; } } // Get Stylesheet $context = sfContext::getInstance(); $response = $context->getResponse(); $comp_options = _convert_options($completion_options); if (isset($comp_options['use_style']) && $comp_options['use_style'] == true) { $response->addStylesheet(sfConfig::get('sf_jquery_web_dir').'/css/JqueryAutocomplete'); } // Get Id from name attribute $tag_options['id'] = get_id_from_name(isset($tag_options['id']) ? $tag_options['id'] : $name); // Add input form $javascript = tag('input', array_merge(array('type' => 'text', 'name' => $name, 'value' => $value), _convert_options($tag_options))); // Calc JQuery Javascript code $autocomplete_script = sprintf('$("#%s").autocomplete("%s",{ %s });',$name,$url,$jsonOptions); $javascript .= javascript_tag($autocomplete_script); return $javascript; } function _update_method($position) { // Updating method $updateMethod = 'html'; switch ($position) { case 'before':$updateMethod='before';break; case 'after':$updateMethod='after';break; case 'top':$updateMethod='prepend';break; case 'bottom':$updateMethod='append';break; } return $updateMethod; } /*** This is a wrapper for the JavascriptHelper function ***/ function jq_link_to_function($name, $function, $html_options= array()) { return link_to_function($name, $function, $html_options); } /*** This is a wrapper for the JavascriptHelper function ***/ function jq_button_to_function($name, $function, $html_options = array()) { return button_to_function($name, $function, $html_options); } /*** This is a wrapper for the JavascriptHelper function ***/ function jq_javascript_tag($content = null) { return javascript_tag($content); } /*** This is a wrapper for the JavascriptHelper function ***/ function jq_javascript_cdata_section($content) { return javascript_cdata_section($content); } /*** This is a wrapper for the JavascriptHelper function ***/ function jq_if_javascript() { return if_javascript(); } /*** This is a wrapper for the JavascriptHelper function ***/ function jq_end_javascript_tag() { return end_javascript_tag(); }