Commit 3cbd47d1 authored by Dries's avatar Dries

- Patch #647228 by sun, katbailey, Rob Loach: links are needlessly unable to...

- Patch #647228 by sun, katbailey, Rob Loach: links are needlessly unable to fully participate in D7 AJAX framework features.
parent 2a0e3264
......@@ -515,7 +515,26 @@ function ajax_footer() {
}
/**
* Add AJAX information about a form element to the page to communicate with JavaScript.
* Form element process callback to handle #ajax.
*
* @param $element
* An associative array containing the properties of the element.
*
* @return
* The processed element.
*
* @see ajax_pre_render_element()
*/
function ajax_process_form($element, &$form_state) {
$element = ajax_pre_render_element($element);
if (!empty($element['#ajax_processed'])) {
$form_state['cache'] = TRUE;
}
return $element;
}
/**
* Add AJAX information about an element to the page to communicate with JavaScript.
*
* If #ajax['path'] is set on an element, this additional JavaScript is added
* to the page header to attach the AJAX behaviors. See ajax.js for more
......@@ -526,15 +545,22 @@ function ajax_footer() {
* Properties used:
* - #ajax['event']
* - #ajax['path']
* - #ajax['options']
* - #ajax['wrapper']
* - #ajax['parameters']
* - #ajax['effect']
*
* @return
* None. Additional code is added to the header of the page using
* drupal_add_js().
* The processed element with the necessary JavaScript attached to it.
*/
function ajax_process_form($element, &$form_state) {
function ajax_pre_render_element($element) {
// Skip already processed elements.
if (isset($element['#ajax_processed'])) {
return $element;
}
// Initialize #ajax_processed, so we do not process this element again.
$element['#ajax_processed'] = FALSE;
// Nothing to do if there is neither a callback nor a path.
if (!(isset($element['#ajax']['callback']) || isset($element['#ajax']['path']))) {
return $element;
......@@ -567,6 +593,10 @@ function ajax_process_form($element, &$form_state) {
$element['#ajax']['event'] = 'change';
break;
case 'link':
$element['#ajax']['event'] = 'click';
break;
default:
return $element;
}
......@@ -581,6 +611,8 @@ function ajax_process_form($element, &$form_state) {
// Assign default settings.
$settings += array(
'path' => 'system/ajax',
'options' => array(),
'selector' => '#' . $element['#id'],
'effect' => 'none',
'speed' => 'none',
......@@ -593,9 +625,9 @@ function ajax_process_form($element, &$form_state) {
$settings['method'] = 'replaceWith';
}
// Change path to url.
$settings['url'] = isset($settings['path']) ? url($settings['path']) : url('system/ajax');
unset($settings['path']);
// Change path to URL.
$settings['url'] = url($settings['path'], $settings['options']);
unset($settings['path'], $settings['options']);
// Add special data to $settings['submit'] so that when this element
// triggers an AJAX submission, Drupal's form processing can determine which
......@@ -614,7 +646,7 @@ function ajax_process_form($element, &$form_state) {
}
unset($settings['trigger_as']);
}
else {
elseif (isset($element['#name'])) {
// Most of the time, elements can submit as themselves, in which case the
// 'trigger_as' key isn't needed, and the element's name is used.
$settings['submit']['_triggering_element_name'] = $element['#name'];
......@@ -645,7 +677,8 @@ function ajax_process_form($element, &$form_state) {
'data' => array('ajax' => array($element['#id'] => $settings)),
);
$form_state['cache'] = TRUE;
// Indicate that AJAX processing was successful.
$element['#ajax_processed'] = TRUE;
}
return $element;
}
......
......@@ -5206,10 +5206,44 @@ function drupal_pre_render_conditional_comments($elements) {
* @return
* The passed in elements containing a rendered link in '#markup'.
*/
function drupal_pre_render_link($elements) {
$options = isset($elements['#options']) ? $elements['#options'] : array();
$elements['#markup'] = l($elements['#title'], $elements['#href'], $options);
return $elements;
function drupal_pre_render_link($element) {
// By default, link options to pass to l() are normally set in #options.
$element += array('#options' => array());
// However, within the scope of renderable elements, #attributes is a valid
// way to specify attributes, too. Take them into account, but do not override
// attributes from #options.
if (isset($element['#attributes'])) {
$element['#options'] += array('attributes' => array());
$element['#options']['attributes'] += $element['#attributes'];
}
// This #pre_render callback can be invoked from inside or outside of a Form
// API context, and depending on that, a HTML ID may be already set in
// different locations. #options should have precedence over Form API's #id.
// #attributes have been taken over into #options above already.
if (isset($element['#options']['attributes']['id'])) {
$element['#id'] = $element['#options']['attributes']['id'];
}
elseif (isset($element['#id'])) {
$element['#options']['attributes']['id'] = $element['#id'];
}
// Conditionally invoke ajax_pre_render_element(), if #ajax is set.
if (isset($element['#ajax']) && !isset($element['#ajax_processed'])) {
// If no HTML ID was found above, automatically create one.
if (!isset($element['#id'])) {
$element['#id'] = $element['#options']['attributes']['id'] = drupal_html_id('ajax-link');
}
// If #ajax['path] was not specified, use the href as AJAX request URL.
if (!isset($element['#ajax']['path'])) {
$element['#ajax']['path'] = $element['#href'];
$element['#ajax']['options'] = $element['#options'];
}
$element = ajax_pre_render_element($element);
}
$element['#markup'] = l($element['#title'], $element['#href'], $element['#options']);
return $element;
}
/**
......
......@@ -108,7 +108,7 @@ function drupal_theme_initialize() {
// @see ajax_base_page_theme()
$setting['ajaxPageState'] = array(
'theme' => $theme_key,
'themeToken' => drupal_get_token($theme_key),
'theme_token' => drupal_get_token($theme_key),
);
drupal_add_js($setting, 'setting');
}
......
......@@ -176,6 +176,7 @@ Drupal.ajax = function (base, element, element_settings) {
ajax.form.ajaxSubmit(ajax.options);
}
else {
ajax.beforeSerialize(ajax.element, ajax.options);
$.ajax(ajax.options);
}
}
......@@ -216,31 +217,35 @@ Drupal.ajax.prototype.beforeSerialize = function (element, options) {
var settings = this.settings || Drupal.settings;
Drupal.detachBehaviors(this.form, settings, 'serialize');
}
};
/**
* Handler for the form redirection submission.
*/
Drupal.ajax.prototype.beforeSubmit = function (form_values, element, options) {
// Disable the element that received the change.
$(this.element).addClass('progress-disabled').attr('disabled', true);
// Prevent duplicate HTML ids in the returned markup.
// @see drupal_html_id()
options.data['ajax_html_ids[]'] = [];
$('[id]').each(function () {
form_values.push({ name: 'ajax_html_ids[]', value: this.id });
options.data['ajax_html_ids[]'].push(this.id);
});
// Allow Drupal to return new JavaScript and CSS files to load without
// returning the ones already loaded.
form_values.push({ name: 'ajax_page_state[theme]', value: Drupal.settings.ajaxPageState.theme });
form_values.push({ name: 'ajax_page_state[theme_token]', value: Drupal.settings.ajaxPageState.themeToken });
// @see ajax_base_page_theme()
// @see drupal_get_css()
// @see drupal_get_js()
options.data['ajax_page_state[theme]'] = Drupal.settings.ajaxPageState.theme;
options.data['ajax_page_state[theme_token]'] = Drupal.settings.ajaxPageState.theme_token;
for (var key in Drupal.settings.ajaxPageState.css) {
form_values.push({ name: 'ajax_page_state[css][' + key + ']', value: 1 });
options.data['ajax_page_state[css][' + key + ']'] = 1;
}
for (var key in Drupal.settings.ajaxPageState.js) {
form_values.push({ name: 'ajax_page_state[js][' + key + ']', value: 1 });
options.data['ajax_page_state[js][' + key + ']'] = 1;
}
};
/**
* Handler for the form redirection submission.
*/
Drupal.ajax.prototype.beforeSubmit = function (form_values, element, options) {
// Disable the element that received the change.
$(this.element).addClass('progress-disabled').attr('disabled', true);
// Insert progressbar or throbber.
if (this.progress.type == 'bar') {
......@@ -279,7 +284,7 @@ Drupal.ajax.prototype.success = function (response, status) {
Drupal.freezeHeight();
for (i in response) {
for (var i in response) {
if (response[i]['command'] && this.commands[response[i]['command']]) {
this.commands[response[i]['command']](this, response[i], status);
}
......
......@@ -87,8 +87,8 @@ class BlockTestCase extends DrupalWebTestCase {
// Verify presence of configure and delete links for custom block.
$this->drupalGet('admin/structure/block');
$this->assertRaw(l(t('configure'), 'admin/structure/block/manage/block/' . $bid . '/configure'), t('Custom block configure link found.'));
$this->assertRaw(l(t('delete'), 'admin/structure/block/manage/block/' . $bid . '/delete'), t('Custom block delete link found.'));
$this->assertLinkByHref('admin/structure/block/manage/block/' . $bid . '/configure', 0, t('Custom block configure link found.'));
$this->assertLinkByHref('admin/structure/block/manage/block/' . $bid . '/delete', 0, t('Custom block delete link found.'));
// Set visibility only for authenticated users, to verify delete functionality.
$edit = array();
......
......@@ -59,6 +59,8 @@ class AJAXTestCase extends DrupalWebTestCase {
* Tests primary AJAX framework functions.
*/
class AJAXFrameworkTestCase extends AJAXTestCase {
protected $profile = 'testing';
public static function getInfo() {
return array(
'name' => 'AJAX framework',
......@@ -84,6 +86,12 @@ class AJAXFrameworkTestCase extends AJAXTestCase {
'settings' => array('basePath' => base_path(), 'ajax' => 'test'),
);
$this->assertCommand($commands, $expected, t('ajax_render() loads settings added with drupal_add_js().'));
// Verify that AJAX settings are loaded for #type 'link'.
$this->drupalGet('ajax-test/link');
$settings = $this->drupalGetSettings();
$this->assertEqual($settings['ajax']['ajax-link']['url'], url('filter/tips'));
$this->assertEqual($settings['ajax']['ajax-link']['wrapper'], 'block-system-main');
}
/**
......
......@@ -24,6 +24,11 @@ function ajax_test_menu() {
'access callback' => TRUE,
'type' => MENU_CALLBACK,
);
$items['ajax-test/link'] = array(
'title' => 'AJAX Link',
'page callback' => 'ajax_test_link',
'access callback' => TRUE,
);
return $items;
}
......@@ -49,3 +54,19 @@ function ajax_test_error() {
}
return array('#type' => 'ajax', '#error' => $message);
}
/**
* Menu callback; Renders a #type link with #ajax.
*/
function ajax_test_link() {
$build['link'] = array(
'#type' => 'link',
'#title' => 'Show help',
'#href' => 'filter/tips',
'#ajax' => array(
'wrapper' => 'block-system-main',
),
);
return $build;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment