summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDries Buytaert <dries@buytaert.net>2010-10-21 19:31:39 +0000
committerDries Buytaert <dries@buytaert.net>2010-10-21 19:31:39 +0000
commit3cbd47d1458b9914d0ede84fd31d4ecc0c8e684b (patch)
tree5818038bc57b05fdcfa8b23fbf43e69f148f5f8b
parent2a0e32644822d34416f4633b4c6fc8674870e6d8 (diff)
downloadbrdo-3cbd47d1458b9914d0ede84fd31d4ecc0c8e684b.tar.gz
brdo-3cbd47d1458b9914d0ede84fd31d4ecc0c8e684b.tar.bz2
- Patch #647228 by sun, katbailey, Rob Loach: links are needlessly unable to fully participate in D7 AJAX framework features.
-rw-r--r--includes/ajax.inc51
-rw-r--r--includes/common.inc42
-rw-r--r--includes/theme.inc2
-rw-r--r--misc/ajax.js33
-rw-r--r--modules/block/block.test4
-rw-r--r--modules/simpletest/tests/ajax.test8
-rw-r--r--modules/simpletest/tests/ajax_test.module21
7 files changed, 131 insertions, 30 deletions
diff --git a/includes/ajax.inc b/includes/ajax.inc
index 0ec7859aa..2fd7f6941 100644
--- a/includes/ajax.inc
+++ b/includes/ajax.inc
@@ -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;
}
diff --git a/includes/common.inc b/includes/common.inc
index b15dccd2f..62c5d22eb 100644
--- a/includes/common.inc
+++ b/includes/common.inc
@@ -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;
}
/**
diff --git a/includes/theme.inc b/includes/theme.inc
index 4bf80d855..6c7a779d9 100644
--- a/includes/theme.inc
+++ b/includes/theme.inc
@@ -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');
}
diff --git a/misc/ajax.js b/misc/ajax.js
index 773986ae3..570e2aaed 100644
--- a/misc/ajax.js
+++ b/misc/ajax.js
@@ -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);
}
diff --git a/modules/block/block.test b/modules/block/block.test
index 4c92eb582..c3d02f34c 100644
--- a/modules/block/block.test
+++ b/modules/block/block.test
@@ -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();
diff --git a/modules/simpletest/tests/ajax.test b/modules/simpletest/tests/ajax.test
index 961188bc5..2788d4f90 100644
--- a/modules/simpletest/tests/ajax.test
+++ b/modules/simpletest/tests/ajax.test
@@ -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');
}
/**
diff --git a/modules/simpletest/tests/ajax_test.module b/modules/simpletest/tests/ajax_test.module
index cc8e6e8fe..70f87f512 100644
--- a/modules/simpletest/tests/ajax_test.module
+++ b/modules/simpletest/tests/ajax_test.module
@@ -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;
+}
+