From df50f455c79ed4f9f1773295eb305b3d0e85c745 Mon Sep 17 00:00:00 2001
From: Bob Vincent <bobvin@pillars.net>
Date: Mon, 17 Oct 2011 19:52:07 -0400
Subject: [PATCH] Issue #93854 by moonray, becw, Dave Reid, pounard,
 das-peter, Steven Jones, c960657, ericduran, pillarsdotnet:
 Allow autocompletion to contain slashes.

---
 misc/autocomplete.js             |    5 +++--
 modules/taxonomy/taxonomy.module |   13 ++++++++++++-
 modules/taxonomy/taxonomy.test   |   35 +++++++++++++++++++++++++++++++++++
 3 files changed, 50 insertions(+), 3 deletions(-)

diff --git a/misc/autocomplete.js b/misc/autocomplete.js
index 5e85be44fc5f372e1d4a6ccc4cef2454e3be7376..f91d58e0118a6a2e7adf1b14c90b9aa91240624f 100644
--- a/misc/autocomplete.js
+++ b/misc/autocomplete.js
@@ -287,10 +287,11 @@ Drupal.ACDB.prototype.search = function (searchString) {
   this.timer = setTimeout(function () {
     db.owner.setStatus('begin');
 
-    // Ajax GET request for autocompletion.
+    // Ajax GET request for autocompletion. We use Drupal.encodePath instead of
+    // encodeURIComponent to allow autocomplete search terms to contain slashes.
     $.ajax({
       type: 'GET',
-      url: db.uri + '/' + encodeURIComponent(searchString),
+      url: db.uri + '/' + Drupal.encodePath(searchString),
       dataType: 'json',
       success: function (matches) {
         if (typeof matches.status == 'undefined' || matches.status != 0) {
diff --git a/modules/taxonomy/taxonomy.module b/modules/taxonomy/taxonomy.module
index 7921b797cce5150e60562c2f8474bcf30e67be84..0e66cab45f9dc4468a7726d25eb0eae630ecf6d8 100644
--- a/modules/taxonomy/taxonomy.module
+++ b/modules/taxonomy/taxonomy.module
@@ -312,13 +312,24 @@ function taxonomy_menu() {
     'type' => MENU_CALLBACK,
     'file' => 'taxonomy.pages.inc',
   );
-  $items['taxonomy/autocomplete'] = array(
+  // This matches the vocabulary name without any search text.
+  $items['taxonomy/autocomplete/%'] = array(
     'title' => 'Autocomplete taxonomy',
     'page callback' => 'taxonomy_autocomplete',
     'access arguments' => array('access content'),
     'type' => MENU_CALLBACK,
     'file' => 'taxonomy.pages.inc',
   );
+  // We append /%menu_tail so the search text may contain slashes.
+  $items['taxonomy/autocomplete/%/%menu_tail'] = array(
+    'title' => 'Autocomplete taxonomy',
+    'page callback' => 'taxonomy_autocomplete',
+    'page arguments' => array(2, 3),
+    'access arguments' => array('access content'),
+    'type' => MENU_CALLBACK,
+    'file' => 'taxonomy.pages.inc',
+    'load arguments' => array('%map', '%index'),
+  );
 
   $items['admin/structure/taxonomy/%taxonomy_vocabulary_machine_name'] = array(
     'title callback' => 'taxonomy_admin_vocabulary_title_callback',
diff --git a/modules/taxonomy/taxonomy.test b/modules/taxonomy/taxonomy.test
index 9a89b9c98ff63924d7d592c7408efe70cdb756d4..b34aa9d260152114417608e0a3fc3b3c1079b06e 100644
--- a/modules/taxonomy/taxonomy.test
+++ b/modules/taxonomy/taxonomy.test
@@ -641,6 +641,41 @@ class TaxonomyTermTestCase extends TaxonomyWebTestCase {
   }
 
   /**
+   * Test term autocompletion edge cases with slashes in the names.
+   */
+  function testTermAutocompletion() {
+    // Add a term with a slash in the name.
+    $first_term = $this->createTerm($this->vocabulary);
+    $first_term->name = '10/16/2011';
+    taxonomy_term_save($first_term);
+    // Add another term that differs after the slash character.
+    $second_term = $this->createTerm($this->vocabulary);
+    $second_term->name = '10/17/2011';
+    taxonomy_term_save($second_term);
+
+    // Try to autocomplete a term name that matches both terms.
+    // We should get both term in a json encoded string.
+    $input = '10/';
+    $path = 'taxonomy/autocomplete/taxonomy_';
+    $path .= $this->vocabulary->machine_name . '/' . $input;
+    // The result order is not guaranteed, so check each term separately.
+    $url = url($path, array('absolute' => TRUE));
+    $result = drupal_http_request($url);
+    $data = drupal_json_decode($result->data);
+    $this->assertEqual($data[$first_term->name], check_plain($first_term->name), t('Autocomplete returned the first matching term'));
+    $this->assertEqual($data[$second_term->name], check_plain($second_term->name), t('Autocomplete returned the second matching term'));
+
+    // Try to autocomplete a term name that matches 1st term.
+    // We should only get the first term in a json encoded string.
+    $input = '10/16';
+    $url = 'taxonomy/autocomplete/taxonomy_';
+    $url .= $this->vocabulary->machine_name . '/' . $input;
+    $this->drupalGet($url);
+    $target = array($first_term->name => check_plain($first_term->name));
+    $this->assertRaw(drupal_json_encode($target), t('Autocomplete returns only the expected matching term.'));
+  }
+
+  /**
    * Save, edit and delete a term using the user interface.
    */
   function testTermInterface() {
-- 
1.7.5.4

