options: fix content settings exceptions dialog regression.

Stupid natural numbers.

BUG=367636
[email protected]

Review URL: https://codereview.chromium.org/264713008

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@267975 0039d316-1c4b-4281-b951-d872f2087c98
diff --git a/chrome/browser/resources/options/content_settings.js b/chrome/browser/resources/options/content_settings.js
index 12b85af..357b9eb8 100644
--- a/chrome/browser/resources/options/content_settings.js
+++ b/chrome/browser/resources/options/content_settings.js
@@ -115,8 +115,9 @@
         value: dict[group].value,
         controlledBy: controlledBy,
       };
-      for (var i = 0; i < indicators.length; i++)
+      for (var i = 0; i < indicators.length; i++) {
         indicators[i].handlePrefChange(event);
+      }
     }
   };
 
@@ -164,31 +165,36 @@
   /**
    * Initializes an exceptions list.
    * @param {string} type The content type that we are setting exceptions for.
-   * @param {Array} list An array of pairs, where the first element of each pair
-   *     is the filter string, and the second is the setting (allow/block).
+   * @param {Array} exceptions An array of pairs, where the first element of
+   *     each pair is the filter string, and the second is the setting
+   *     (allow/block).
    */
-  ContentSettings.setExceptions = function(type, list) {
-    var exceptionsList =
-        document.querySelector('div[contentType=' + type + ']' +
-                               ' list[mode=normal]');
-    exceptionsList.setExceptions(list);
+  ContentSettings.setExceptions = function(type, exceptions) {
+    this.getExceptionsList(type, 'normal').setExceptions(exceptions);
   };
 
-  ContentSettings.setHandlers = function(list) {
-    $('handlers-list').setHandlers(list);
+  ContentSettings.setHandlers = function(handlers) {
+    $('handlers-list').setHandlers(handlers);
   };
 
-  ContentSettings.setIgnoredHandlers = function(list) {
-    $('ignored-handlers-list').setHandlers(list);
+  ContentSettings.setIgnoredHandlers = function(ignoredHandlers) {
+    $('ignored-handlers-list').setHandlers(ignoredHandlers);
   };
 
-  ContentSettings.setOTRExceptions = function(type, list) {
-    var exceptionsList =
-        document.querySelector('div[contentType=' + type + ']' +
-                               ' list[mode=otr]');
-
+  ContentSettings.setOTRExceptions = function(type, otrExceptions) {
+    var exceptionsList = this.getExceptionsList(type, 'otr');
     exceptionsList.parentNode.hidden = false;
-    exceptionsList.setExceptions(list);
+    exceptionsList.setExceptions(otrExceptions);
+  };
+
+  /**
+   * @param {string} type The type of exceptions (e.g. "location") to get.
+   * @param {string} mode The mode of the desired exceptions list (e.g. otr).
+   * @return {?ExceptionsList} The corresponding exceptions list or null.
+   */
+  ContentSettings.getExceptionsList = function(type, mode) {
+    return document.querySelector(
+        'div[contentType=' + type + '] list[mode=' + mode + ']');
   };
 
   /**
@@ -202,10 +208,8 @@
    */
   ContentSettings.patternValidityCheckComplete =
       function(type, mode, pattern, valid) {
-    var exceptionsList =
-        document.querySelector('div[contentType=' + type + '] ' +
-                               'list[mode=' + mode + ']');
-    exceptionsList.patternValidityCheckComplete(pattern, valid);
+    this.getExceptionsList(type, mode).patternValidityCheckComplete(pattern,
+                                                                    valid);
   };
 
   /**
@@ -216,7 +220,7 @@
    */
   ContentSettings.showMediaPepperFlashDefaultLink = function(show) {
     $('media-pepper-flash-default').hidden = !show;
-  }
+  };
 
   /**
    * Shows/hides the link to the Pepper Flash camera and microphone
@@ -226,7 +230,7 @@
    */
   ContentSettings.showMediaPepperFlashExceptionsLink = function(show) {
     $('media-pepper-flash-exceptions').hidden = !show;
-  }
+  };
 
   /**
    * Shows/hides the whole Web MIDI settings.
@@ -234,7 +238,7 @@
    */
   ContentSettings.showExperimentalWebMIDISettings = function(show) {
     $('experimental-web-midi-settings').hidden = !show;
-  }
+  };
 
   /**
    * Updates the microphone/camera devices menu with the given entries.
@@ -275,10 +279,9 @@
    */
   ContentSettings.enableProtectedContentExceptions = function(enable) {
     var exceptionsButton = $('protected-content-exceptions');
-    if (exceptionsButton) {
+    if (exceptionsButton)
       exceptionsButton.disabled = !enable;
-    }
-  }
+  };
 
   /**
    * Set the default microphone device based on the popup selection.
diff --git a/chrome/browser/resources/options/handler_options.js b/chrome/browser/resources/options/handler_options.js
index 894e13f7..0918e0f 100644
--- a/chrome/browser/resources/options/handler_options.js
+++ b/chrome/browser/resources/options/handler_options.js
@@ -27,7 +27,7 @@
 
     /**
      * The handlers list.
-     * @type {DeletableItemList}
+     * @type {options.HandlersList}
      * @private
      */
     handlersList_: null,
diff --git a/chrome/browser/resources/options/handler_options_list.js b/chrome/browser/resources/options/handler_options_list.js
index 5572a55..fef1740d 100644
--- a/chrome/browser/resources/options/handler_options_list.js
+++ b/chrome/browser/resources/options/handler_options_list.js
@@ -6,7 +6,6 @@
   /** @const */ var ArrayDataModel = cr.ui.ArrayDataModel;
   /** @const */ var List = cr.ui.List;
   /** @const */ var ListItem = cr.ui.ListItem;
-  /** @const */ var HandlerOptions = options.HandlerOptions;
   /** @const */ var DeletableItem = options.DeletableItem;
   /** @const */ var DeletableItemList = options.DeletableItemList;
 
@@ -168,7 +167,6 @@
     decorate: function() {
       ListItem.prototype.decorate.call(this);
 
-      var self = this;
       var delegate = {
         removeHandler: function(index, handler) {
           chrome.send('removeHandler', [handler]);
diff --git a/chrome/browser/ui/webui/options/content_settings_exception_area_browsertest.js b/chrome/browser/ui/webui/options/content_settings_exception_area_browsertest.js
index 93da9c6..f9fc3df 100644
--- a/chrome/browser/ui/webui/options/content_settings_exception_area_browsertest.js
+++ b/chrome/browser/ui/webui/options/content_settings_exception_area_browsertest.js
@@ -12,9 +12,7 @@
 ContentSettingsExceptionAreaWebUITest.prototype = {
   __proto__: testing.Test.prototype,
 
-  /**
-   * Browse to the content settings exception area.
-   */
+  /** @override */
   browsePreload: 'chrome://settings-frame/contentExceptions',
 };
 
@@ -27,7 +25,63 @@
 GEN('#endif  // defined(OS_CHROMEOS)');
 // Test opening the content settings exception area has correct location.
 TEST_F('ContentSettingsExceptionAreaWebUITest',
-       'MAYBE_testOpenContentSettingsExceptionArea',
-       function() {
-         assertEquals(this.browsePreload, document.location.href);
-       });
+       'MAYBE_testOpenContentSettingsExceptionArea', function() {
+  assertEquals(this.browsePreload, document.location.href);
+});
+
+/**
+ * A class to asynchronously test the content settings exception area dialog.
+ * @extends {testing.Test}
+ * @constructor
+ */
+function ContentSettingsExceptionsAreaAsyncWebUITest() {}
+
+ContentSettingsExceptionsAreaAsyncWebUITest.prototype = {
+  __proto__: testing.Test.prototype,
+
+  /** @override */
+  browsePreload: 'chrome://settings-frame/contentExceptions',
+
+  /** @override */
+  isAsync: true,
+};
+
+// Adds and removes a location content setting exception.
+TEST_F('ContentSettingsExceptionsAreaAsyncWebUITest',
+       'testAddRemoveLocationExceptions', function() {
+  assertEquals(this.browsePreload, document.location.href);
+
+  /** @const */ var origin = 'http://google.com:80';
+  /** @const */ var setExceptions = ContentSettings.setExceptions;
+
+  var list = ContentSettings.getExceptionsList('cookies', 'normal');
+  assertEquals(1, list.items.length);
+
+  var setExceptionsCounter = 0;
+  var setExceptionsCallback = function() {
+    setExceptionsCounter++;
+    if (setExceptionsCounter == 1) {
+      // The first item is now the exception (edit items are always last).
+      expectEquals('block', list.dataModel.item(0).setting);
+      expectEquals(origin, list.dataModel.item(0).origin);
+
+      // Delete the item and verify it worked.
+      list.deleteItemAtIndex(0);
+    } else if (setExceptionsCounter == 2) {
+      // Verify the item was deleted, restore the original method, and finish.
+      expectEquals(1, list.items.length);
+      ContentSettings.setExceptions = setExceptions;
+      testDone();
+    }
+  };
+
+  // NOTE: if this test doesn't succeed, |ContentSettings.setExceptions| may not
+  // be restored to its original method. I know no easy way to fix this.
+  ContentSettings.setExceptions = function() {
+    setExceptions.apply(ContentSettings, arguments);
+    setExceptionsCallback();
+  };
+
+  // Add an item to the location exception area to start the test.
+  list.items[0].finishEdit(origin, 'block');
+});
diff --git a/chrome/browser/ui/webui/options/content_settings_handler.cc b/chrome/browser/ui/webui/options/content_settings_handler.cc
index b672cbd3..f7da58e2 100644
--- a/chrome/browser/ui/webui/options/content_settings_handler.cc
+++ b/chrome/browser/ui/webui/options/content_settings_handler.cc
@@ -1209,9 +1209,9 @@
   rv = args->GetString(2, &pattern);
   DCHECK(rv);
 
-  // The third argument to this handler is optional.
+  // The fourth argument to this handler is optional.
   std::string secondary_pattern;
-  if (args->GetSize() == 3U) {
+  if (args->GetSize() >= 4U) {
     rv = args->GetString(3, &secondary_pattern);
     DCHECK(rv);
   }