diff --git a/core/modules/simpletest/lib/Drupal/simpletest/WebTestBase.php b/core/modules/simpletest/lib/Drupal/simpletest/WebTestBase.php
index 00ba41a..fc8c49c 100644
--- a/core/modules/simpletest/lib/Drupal/simpletest/WebTestBase.php
+++ b/core/modules/simpletest/lib/Drupal/simpletest/WebTestBase.php
@@ -1493,11 +1493,9 @@ protected function drupalPostForm($path, $edit, $submit, array $options = array(
/**
* Executes an Ajax form submission.
*
- * This executes a POST as ajax.js does. It uses the returned JSON data, an
- * array of commands, to update $this->content using equivalent DOM
- * manipulation as is used by ajax.js. It also returns the array of commands.
- * It does not apply custom AJAX commands though, because emulation is only
- * implemented for the AJAX commands that ship with Drupal core.
+ * This executes a POST as ajax.js does. The returned JSON data is used to
+ * update $this->content via drupalProcessAjaxResponse(). It also returns
+ * the array of AJAX commands received.
*
* @param $path
* Location of the form containing the Ajax enabled element to test. Can be
@@ -1532,6 +1530,7 @@ protected function drupalPostForm($path, $edit, $submit, array $options = array(
* An array of Ajax commands.
*
* @see drupalPostForm()
+ * @see drupalProcessAjaxResponse()
* @see ajax.js
*/
protected function drupalPostAjaxForm($path, $edit, $triggering_element, $ajax_path = NULL, array $options = array(), array $headers = array(), $form_html_id = NULL, $ajax_settings = NULL) {
@@ -1540,8 +1539,6 @@ protected function drupalPostAjaxForm($path, $edit, $triggering_element, $ajax_p
if (isset($path)) {
$this->drupalGet($path, $options);
}
- $content = $this->content;
- $drupal_settings = $this->drupalSettings;
$headers[] = 'Accept: application/vnd.drupal-ajax';
@@ -1558,7 +1555,7 @@ protected function drupalPostAjaxForm($path, $edit, $triggering_element, $ajax_p
}
$element = $this->xpath($xpath);
$element_id = (string) $element[0]['id'];
- $ajax_settings = $drupal_settings['ajax'][$element_id];
+ $ajax_settings = $this->drupalSettings['ajax'][$element_id];
}
// Add extra information to the POST data as ajax.js does.
@@ -1590,95 +1587,123 @@ protected function drupalPostAjaxForm($path, $edit, $triggering_element, $ajax_p
// Change the page content by applying the returned commands.
if (!empty($ajax_settings) && !empty($return)) {
- // ajax.js applies some defaults to the settings object, so do the same
- // for what's used by this function.
- $ajax_settings += array(
- 'method' => 'replaceWith',
- );
- // DOM can load HTML soup. But, HTML soup can throw warnings, suppress
- // them.
- $dom = new DOMDocument();
- @$dom->loadHTML($content);
- // XPath allows for finding wrapper nodes better than DOM does.
- $xpath = new DOMXPath($dom);
- foreach ($return as $command) {
- switch ($command['command']) {
- case 'settings':
- $drupal_settings = drupal_merge_js_settings(array($drupal_settings, $command['settings']));
- break;
+ $this->drupalProcessAjaxResponse($return, $ajax_settings);
+ }
- case 'insert':
- $wrapperNode = NULL;
- // When a command doesn't specify a selector, use the
- // #ajax['wrapper'] which is always an HTML ID.
- if (!isset($command['selector'])) {
- $wrapperNode = $xpath->query('//*[@id="' . $ajax_settings['wrapper'] . '"]')->item(0);
- }
- // @todo Ajax commands can target any jQuery selector, but these are
- // hard to fully emulate with XPath. For now, just handle 'head'
- // and 'body', since these are used by ajax_render().
- elseif (in_array($command['selector'], array('head', 'body'))) {
- $wrapperNode = $xpath->query('//' . $command['selector'])->item(0);
- }
- if ($wrapperNode) {
- // ajax.js adds an enclosing DIV to work around a Safari bug.
- $newDom = new DOMDocument();
- @$newDom->loadHTML('
' . $command['data'] . '
');
- $newNode = $dom->importNode($newDom->documentElement->firstChild->firstChild, TRUE);
- $method = isset($command['method']) ? $command['method'] : $ajax_settings['method'];
- // The "method" is a jQuery DOM manipulation function. Emulate
- // each one using PHP's DOMNode API.
- switch ($method) {
- case 'replaceWith':
- $wrapperNode->parentNode->replaceChild($newNode, $wrapperNode);
- break;
- case 'append':
- $wrapperNode->appendChild($newNode);
- break;
- case 'prepend':
- // If no firstChild, insertBefore() falls back to
- // appendChild().
- $wrapperNode->insertBefore($newNode, $wrapperNode->firstChild);
- break;
- case 'before':
- $wrapperNode->parentNode->insertBefore($newNode, $wrapperNode);
- break;
- case 'after':
- // If no nextSibling, insertBefore() falls back to
- // appendChild().
- $wrapperNode->parentNode->insertBefore($newNode, $wrapperNode->nextSibling);
- break;
- case 'html':
- foreach ($wrapperNode->childNodes as $childNode) {
- $wrapperNode->removeChild($childNode);
- }
- $wrapperNode->appendChild($newNode);
- break;
- }
+ return $return;
+ }
+
+ /**
+ * Processes an AJAX response into current content.
+ *
+ * This processes the AJAX response as ajax.js does. It uses the response's
+ * JSON data, and an array of commands, to update $this->content using
+ * equivalent DOM manipulation as is used by ajax.js.
+ * It does not apply custom AJAX commands though, because emulation is only
+ * implemented for the AJAX commands that ship with Drupal core.
+ *
+ * @param array $ajax_response
+ * An array of AJAX commands.
+ * @param array $ajax_settings
+ * An array of Ajax settings which will be used to process the response.
+ * @param array $drupal_settings
+ * (optional) An array of settings to update the value of drupalSettings
+ * for the currently-loaded page.
+ *
+ * @see drupalPostAjaxForm()
+ * @see ajax.js
+ */
+ protected function drupalProcessAjaxResponse(array $ajax_response, array $ajax_settings, array $drupal_settings = array()) {
+
+ $content = $this->content;
+
+ // ajax.js applies some defaults to the settings object, so do the same
+ // for what's used by this function.
+ $ajax_settings += array(
+ 'method' => 'replaceWith',
+ );
+ // DOM can load HTML soup. But, HTML soup can throw warnings, suppress
+ // them.
+ $dom = new DOMDocument();
+ @$dom->loadHTML($content);
+ // XPath allows for finding wrapper nodes better than DOM does.
+ $xpath = new DOMXPath($dom);
+ foreach ($ajax_response as $command) {
+ switch ($command['command']) {
+ case 'settings':
+ $drupal_settings = drupal_merge_js_settings(array($drupal_settings, $command['settings']));
+ break;
+
+ case 'insert':
+ $wrapperNode = NULL;
+ // When a command doesn't specify a selector, use the
+ // #ajax['wrapper'] which is always an HTML ID.
+ if (!isset($command['selector'])) {
+ $wrapperNode = $xpath->query('//*[@id="' . $ajax_settings['wrapper'] . '"]')->item(0);
+ }
+ // @todo Ajax commands can target any jQuery selector, but these are
+ // hard to fully emulate with XPath. For now, just handle 'head'
+ // and 'body', since these are used by ajax_render().
+ elseif (in_array($command['selector'], array('head', 'body'))) {
+ $wrapperNode = $xpath->query('//' . $command['selector'])->item(0);
+ }
+ if ($wrapperNode) {
+ // ajax.js adds an enclosing DIV to work around a Safari bug.
+ $newDom = new DOMDocument();
+ @$newDom->loadHTML('' . $command['data'] . '
');
+ $newNode = $dom->importNode($newDom->documentElement->firstChild->firstChild, TRUE);
+ $method = isset($command['method']) ? $command['method'] : $ajax_settings['method'];
+ // The "method" is a jQuery DOM manipulation function. Emulate
+ // each one using PHP's DOMNode API.
+ switch ($method) {
+ case 'replaceWith':
+ $wrapperNode->parentNode->replaceChild($newNode, $wrapperNode);
+ break;
+ case 'append':
+ $wrapperNode->appendChild($newNode);
+ break;
+ case 'prepend':
+ // If no firstChild, insertBefore() falls back to
+ // appendChild().
+ $wrapperNode->insertBefore($newNode, $wrapperNode->firstChild);
+ break;
+ case 'before':
+ $wrapperNode->parentNode->insertBefore($newNode, $wrapperNode);
+ break;
+ case 'after':
+ // If no nextSibling, insertBefore() falls back to
+ // appendChild().
+ $wrapperNode->parentNode->insertBefore($newNode, $wrapperNode->nextSibling);
+ break;
+ case 'html':
+ foreach ($wrapperNode->childNodes as $childNode) {
+ $wrapperNode->removeChild($childNode);
+ }
+ $wrapperNode->appendChild($newNode);
+ break;
}
- break;
+ }
+ break;
- // @todo Add suitable implementations for these commands in order to
- // have full test coverage of what ajax.js can do.
- case 'remove':
- break;
- case 'changed':
- break;
- case 'css':
- break;
- case 'data':
- break;
- case 'restripe':
- break;
- case 'add_css':
- break;
- }
+ // @todo Add suitable implementations for these commands in order to
+ // have full test coverage of what ajax.js can do.
+ case 'remove':
+ break;
+ case 'changed':
+ break;
+ case 'css':
+ break;
+ case 'data':
+ break;
+ case 'restripe':
+ break;
+ case 'add_css':
+ break;
}
- $content = $dom->saveHTML();
}
+ $content = $dom->saveHTML();
$this->drupalSetContent($content);
$this->drupalSetSettings($drupal_settings);
- return $return;
}
/**