Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(541)

Unified Diff: chrome/browser/resources/options2/content_settings_exceptions_area.js

Issue 8895023: Options2: Pull the trigger. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: DIAF. Created 9 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: chrome/browser/resources/options2/content_settings_exceptions_area.js
diff --git a/chrome/browser/resources/options2/content_settings_exceptions_area.js b/chrome/browser/resources/options2/content_settings_exceptions_area.js
new file mode 100644
index 0000000000000000000000000000000000000000..7adde6862095c8c49f505dc3c223b8d19a0ea14e
--- /dev/null
+++ b/chrome/browser/resources/options2/content_settings_exceptions_area.js
@@ -0,0 +1,552 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+cr.define('options.contentSettings', function() {
+ const InlineEditableItemList = options.InlineEditableItemList;
+ const InlineEditableItem = options.InlineEditableItem;
+ const ArrayDataModel = cr.ui.ArrayDataModel;
+
+ /**
+ * Creates a new exceptions list item.
+ * @param {string} contentType The type of the list.
+ * @param {string} mode The browser mode, 'otr' or 'normal'.
+ * @param {boolean} enableAskOption Whether to show an 'ask every time'
+ * option in the select.
+ * @param {Object} exception A dictionary that contains the data of the
+ * exception.
+ * @constructor
+ * @extends {options.InlineEditableItem}
+ */
+ function ExceptionsListItem(contentType, mode, enableAskOption, exception) {
+ var el = cr.doc.createElement('div');
+ el.mode = mode;
+ el.contentType = contentType;
+ el.enableAskOption = enableAskOption;
+ el.dataItem = exception;
+ el.__proto__ = ExceptionsListItem.prototype;
+ el.decorate();
+
+ return el;
+ }
+
+ ExceptionsListItem.prototype = {
+ __proto__: InlineEditableItem.prototype,
+
+ /**
+ * Called when an element is decorated as a list item.
+ */
+ decorate: function() {
+ InlineEditableItem.prototype.decorate.call(this);
+
+ this.isPlaceholder = !this.pattern;
+ var patternCell = this.createEditableTextCell(this.pattern);
+ patternCell.className = 'exception-pattern';
+ patternCell.classList.add('weakrtl');
+ this.contentElement.appendChild(patternCell);
+ if (this.pattern)
+ this.patternLabel = patternCell.querySelector('.static-text');
+ var input = patternCell.querySelector('input');
+
+ // TODO(stuartmorgan): Create an createEditableSelectCell abstracting
+ // this code.
+ // Setting label for display mode. |pattern| will be null for the 'add new
+ // exception' row.
+ if (this.pattern) {
+ var settingLabel = cr.doc.createElement('span');
+ settingLabel.textContent = this.settingForDisplay();
+ settingLabel.className = 'exception-setting';
+ settingLabel.setAttribute('displaymode', 'static');
+ this.contentElement.appendChild(settingLabel);
+ this.settingLabel = settingLabel;
+ }
+
+ // Setting select element for edit mode.
+ var select = cr.doc.createElement('select');
+ var optionAllow = cr.doc.createElement('option');
+ optionAllow.textContent = templateData.allowException;
+ optionAllow.value = 'allow';
+ select.appendChild(optionAllow);
+
+ if (this.enableAskOption) {
+ var optionAsk = cr.doc.createElement('option');
+ optionAsk.textContent = templateData.askException;
+ optionAsk.value = 'ask';
+ select.appendChild(optionAsk);
+ }
+
+ if (this.contentType == 'cookies') {
+ var optionSession = cr.doc.createElement('option');
+ optionSession.textContent = templateData.sessionException;
+ optionSession.value = 'session';
+ select.appendChild(optionSession);
+ }
+
+ if (this.contentType != 'fullscreen') {
+ var optionBlock = cr.doc.createElement('option');
+ optionBlock.textContent = templateData.blockException;
+ optionBlock.value = 'block';
+ select.appendChild(optionBlock);
+ }
+
+ this.contentElement.appendChild(select);
+ select.className = 'exception-setting';
+ if (this.pattern)
+ select.setAttribute('displaymode', 'edit');
+
+ // Used to track whether the URL pattern in the input is valid.
+ // This will be true if the browser process has informed us that the
+ // current text in the input is valid. Changing the text resets this to
+ // false, and getting a response from the browser sets it back to true.
+ // It starts off as false for empty string (new exceptions) or true for
+ // already-existing exceptions (which we assume are valid).
+ this.inputValidityKnown = this.pattern;
+ // This one tracks the actual validity of the pattern in the input. This
+ // starts off as true so as not to annoy the user when he adds a new and
+ // empty input.
+ this.inputIsValid = true;
+
+ this.input = input;
+ this.select = select;
+
+ this.updateEditables();
+
+ // Editing notifications and geolocation is disabled for now.
+ if (this.contentType == 'notifications' ||
+ this.contentType == 'location') {
+ this.editable = false;
+ }
+
+ // If the source of the content setting exception is not the user
+ // preference, then the content settings exception is managed and the user
+ // can't edit it.
+ if (this.dataItem.source &&
+ this.dataItem.source != 'preference') {
+ this.setAttribute('managedby', this.dataItem.source);
+ this.deletable = false;
+ this.editable = false;
+ }
+
+ var listItem = this;
+ // Handle events on the editable nodes.
+ input.oninput = function(event) {
+ listItem.inputValidityKnown = false;
+ chrome.send('checkExceptionPatternValidity',
+ [listItem.contentType, listItem.mode, input.value]);
+ };
+
+ // Listen for edit events.
+ this.addEventListener('canceledit', this.onEditCancelled_);
+ this.addEventListener('commitedit', this.onEditCommitted_);
+ },
+
+ /**
+ * The pattern (e.g., a URL) for the exception.
+ * @type {string}
+ */
+ get pattern() {
+ return this.dataItem['displayPattern'];
+ },
+ set pattern(pattern) {
+ this.dataItem['displayPattern'] = pattern;
+ },
+
+ /**
+ * The setting (allow/block) for the exception.
+ * @type {string}
+ */
+ get setting() {
+ return this.dataItem['setting'];
+ },
+ set setting(setting) {
+ this.dataItem['setting'] = setting;
+ },
+
+ /**
+ * Gets a human-readable setting string.
+ * @type {string}
+ */
+ settingForDisplay: function() {
+ var setting = this.setting;
+ if (setting == 'allow')
+ return templateData.allowException;
+ else if (setting == 'block')
+ return templateData.blockException;
+ else if (setting == 'ask')
+ return templateData.askException;
+ else if (setting == 'session')
+ return templateData.sessionException;
+ },
+
+ /**
+ * Update this list item to reflect whether the input is a valid pattern.
+ * @param {boolean} valid Whether said pattern is valid in the context of
+ * a content exception setting.
+ */
+ setPatternValid: function(valid) {
+ if (valid || !this.input.value)
+ this.input.setCustomValidity('');
+ else
+ this.input.setCustomValidity(' ');
+ this.inputIsValid = valid;
+ this.inputValidityKnown = true;
+ },
+
+ /**
+ * Set the <input> to its original contents. Used when the user quits
+ * editing.
+ */
+ resetInput: function() {
+ this.input.value = this.pattern;
+ },
+
+ /**
+ * Copy the data model values to the editable nodes.
+ */
+ updateEditables: function() {
+ this.resetInput();
+
+ var settingOption =
+ this.select.querySelector('[value=\'' + this.setting + '\']');
+ if (settingOption)
+ settingOption.selected = true;
+ },
+
+ /** @inheritDoc */
+ get currentInputIsValid() {
+ return this.inputValidityKnown && this.inputIsValid;
+ },
+
+ /** @inheritDoc */
+ get hasBeenEdited() {
+ var livePattern = this.input.value;
+ var liveSetting = this.select.value;
+ return livePattern != this.pattern || liveSetting != this.setting;
+ },
+
+ /**
+ * Called when committing an edit.
+ * @param {Event} e The end event.
+ * @private
+ */
+ onEditCommitted_: function(e) {
+ var newPattern = this.input.value;
+ var newSetting = this.select.value;
+
+ this.finishEdit(newPattern, newSetting);
+ },
+
+ /**
+ * Called when cancelling an edit; resets the control states.
+ * @param {Event} e The cancel event.
+ * @private
+ */
+ onEditCancelled_: function() {
+ this.updateEditables();
+ this.setPatternValid(true);
+ },
+
+ /**
+ * Editing is complete; update the model.
+ * @param {string} newPattern The pattern that the user entered.
+ * @param {string} newSetting The setting the user chose.
+ */
+ finishEdit: function(newPattern, newSetting) {
+ this.patternLabel.textContent = newPattern;
+ this.settingLabel.textContent = this.settingForDisplay();
+ var oldPattern = this.pattern;
+ this.pattern = newPattern;
+ this.setting = newSetting;
+
+ // TODO(estade): this will need to be updated if geolocation/notifications
+ // become editable.
+ if (oldPattern != newPattern) {
+ chrome.send('removeException',
+ [this.contentType, this.mode, oldPattern]);
+ }
+
+ chrome.send('setException',
+ [this.contentType, this.mode, newPattern, newSetting]);
+ }
+ };
+
+ /**
+ * Creates a new list item for the Add New Item row, which doesn't represent
+ * an actual entry in the exceptions list but allows the user to add new
+ * exceptions.
+ * @param {string} contentType The type of the list.
+ * @param {string} mode The browser mode, 'otr' or 'normal'.
+ * @param {boolean} enableAskOption Whether to show an 'ask every time'
+ * option in the select.
+ * @constructor
+ * @extends {cr.ui.ExceptionsListItem}
+ */
+ function ExceptionsAddRowListItem(contentType, mode, enableAskOption) {
+ var el = cr.doc.createElement('div');
+ el.mode = mode;
+ el.contentType = contentType;
+ el.enableAskOption = enableAskOption;
+ el.dataItem = [];
+ el.__proto__ = ExceptionsAddRowListItem.prototype;
+ el.decorate();
+
+ return el;
+ }
+
+ ExceptionsAddRowListItem.prototype = {
+ __proto__: ExceptionsListItem.prototype,
+
+ decorate: function() {
+ ExceptionsListItem.prototype.decorate.call(this);
+
+ this.input.placeholder = templateData.addNewExceptionInstructions;
+
+ // Do we always want a default of allow?
+ this.setting = 'allow';
+ },
+
+ /**
+ * Clear the <input> and let the placeholder text show again.
+ */
+ resetInput: function() {
+ this.input.value = '';
+ },
+
+ /** @inheritDoc */
+ get hasBeenEdited() {
+ return this.input.value != '';
+ },
+
+ /**
+ * Editing is complete; update the model. As long as the pattern isn't
+ * empty, we'll just add it.
+ * @param {string} newPattern The pattern that the user entered.
+ * @param {string} newSetting The setting the user chose.
+ */
+ finishEdit: function(newPattern, newSetting) {
+ this.resetInput();
+ chrome.send('setException',
+ [this.contentType, this.mode, newPattern, newSetting]);
+ },
+ };
+
+ /**
+ * Creates a new exceptions list.
+ * @constructor
+ * @extends {cr.ui.List}
+ */
+ var ExceptionsList = cr.ui.define('list');
+
+ ExceptionsList.prototype = {
+ __proto__: InlineEditableItemList.prototype,
+
+ /**
+ * Called when an element is decorated as a list.
+ */
+ decorate: function() {
+ InlineEditableItemList.prototype.decorate.call(this);
+
+ this.classList.add('settings-list');
+
+ for (var parentNode = this.parentNode; parentNode;
+ parentNode = parentNode.parentNode) {
+ if (parentNode.hasAttribute('contentType')) {
+ this.contentType = parentNode.getAttribute('contentType');
+ break;
+ }
+ }
+
+ this.mode = this.getAttribute('mode');
+
+ var exceptionList = this;
+
+ // Whether the exceptions in this list allow an 'Ask every time' option.
+ this.enableAskOption = (this.contentType == 'plugins' &&
+ templateData.enable_click_to_play);
+
+ this.autoExpands = true;
+ this.reset();
+ },
+
+ /**
+ * Creates an item to go in the list.
+ * @param {Object} entry The element from the data model for this row.
+ */
+ createItem: function(entry) {
+ if (entry) {
+ return new ExceptionsListItem(this.contentType,
+ this.mode,
+ this.enableAskOption,
+ entry);
+ } else {
+ var addRowItem = new ExceptionsAddRowListItem(this.contentType,
+ this.mode,
+ this.enableAskOption);
+ addRowItem.deletable = false;
+ return addRowItem;
+ }
+ },
+
+ /**
+ * Sets the exceptions in the js model.
+ * @param {Object} entries A list of dictionaries of values, each dictionary
+ * represents an exception.
+ */
+ setExceptions: function(entries) {
+ var deleteCount = this.dataModel.length;
+
+ if (this.isEditable()) {
+ // We don't want to remove the Add New Exception row.
+ deleteCount = deleteCount - 1;
+ }
+
+ var args = [0, deleteCount];
+ args.push.apply(args, entries);
+ this.dataModel.splice.apply(this.dataModel, args);
+ },
+
+ /**
+ * The browser has finished checking a pattern for validity. Update the
+ * list item to reflect this.
+ * @param {string} pattern The pattern.
+ * @param {bool} valid Whether said pattern is valid in the context of
+ * a content exception setting.
+ */
+ patternValidityCheckComplete: function(pattern, valid) {
+ var listItems = this.items;
+ for (var i = 0; i < listItems.length; i++) {
+ var listItem = listItems[i];
+ // Don't do anything for messages for the item if it is not the intended
+ // recipient, or if the response is stale (i.e. the input value has
+ // changed since we sent the request to analyze it).
+ if (pattern == listItem.input.value)
+ listItem.setPatternValid(valid);
+ }
+ },
+
+ /**
+ * Returns whether the rows are editable in this list.
+ */
+ isEditable: function() {
+ // Editing notifications and geolocation is disabled for now.
+ return !(this.contentType == 'notifications' ||
+ this.contentType == 'location' ||
+ this.contentType == 'fullscreen');
+ },
+
+ /**
+ * Removes all exceptions from the js model.
+ */
+ reset: function() {
+ if (this.isEditable()) {
+ // The null creates the Add New Exception row.
+ this.dataModel = new ArrayDataModel([null]);
+ } else {
+ this.dataModel = new ArrayDataModel([]);
+ }
+ },
+
+ /** @inheritDoc */
+ deleteItemAtIndex: function(index) {
+ var listItem = this.getListItemByIndex(index);
+ if (listItem.undeletable)
+ return;
+
+ var dataItem = listItem.dataItem;
+ var args = [listItem.contentType];
+ if (listItem.contentType == 'location')
+ args.push(dataItem['origin'], dataItem['embeddingOrigin']);
+ else if (listItem.contentType == 'notifications')
+ args.push(dataItem['origin'], dataItem['setting']);
+ else
+ args.push(listItem.mode, listItem.pattern);
+
+ chrome.send('removeException', args);
+ },
+ };
+
+ var OptionsPage = options.OptionsPage;
+
+ /**
+ * Encapsulated handling of content settings list subpage.
+ * @constructor
+ */
+ function ContentSettingsExceptionsArea() {
+ OptionsPage.call(this, 'contentExceptions',
+ templateData.contentSettingsPageTabTitle,
+ 'content-settings-exceptions-area');
+ }
+
+ cr.addSingletonGetter(ContentSettingsExceptionsArea);
+
+ ContentSettingsExceptionsArea.prototype = {
+ __proto__: OptionsPage.prototype,
+
+ initializePage: function() {
+ OptionsPage.prototype.initializePage.call(this);
+
+ var exceptionsLists = this.pageDiv.querySelectorAll('list');
+ for (var i = 0; i < exceptionsLists.length; i++) {
+ options.contentSettings.ExceptionsList.decorate(exceptionsLists[i]);
+ }
+
+ ContentSettingsExceptionsArea.hideOTRLists();
+
+ // If the user types in the URL without a hash, show just cookies.
+ this.showList('cookies');
+ },
+
+ /**
+ * Shows one list and hides all others.
+ * @param {string} type The content type.
+ */
+ showList: function(type) {
+ var header = this.pageDiv.querySelector('h1');
+ header.textContent = templateData[type + '_header'];
+
+ var divs = this.pageDiv.querySelectorAll('div[contentType]');
+ for (var i = 0; i < divs.length; i++) {
+ if (divs[i].getAttribute('contentType') == type)
+ divs[i].hidden = false;
+ else
+ divs[i].hidden = true;
+ }
+ },
+
+ /**
+ * Called after the page has been shown. Show the content type for the
+ * location's hash.
+ */
+ didShowPage: function() {
+ var hash = location.hash;
+ if (hash)
+ this.showList(hash.slice(1));
+ },
+ };
+
+ /**
+ * Called when the last incognito window is closed.
+ */
+ ContentSettingsExceptionsArea.OTRProfileDestroyed = function() {
+ this.hideOTRLists();
+ };
+
+ /**
+ * Clears and hides the incognito exceptions lists.
+ */
+ ContentSettingsExceptionsArea.hideOTRLists = function() {
+ var otrLists = document.querySelectorAll('list[mode=otr]');
+
+ for (var i = 0; i < otrLists.length; i++) {
+ otrLists[i].reset();
+ otrLists[i].parentNode.hidden = true;
+ }
+ };
+
+ return {
+ ExceptionsListItem: ExceptionsListItem,
+ ExceptionsAddRowListItem: ExceptionsAddRowListItem,
+ ExceptionsList: ExceptionsList,
+ ContentSettingsExceptionsArea: ContentSettingsExceptionsArea,
+ };
+});

Powered by Google App Engine
This is Rietveld 408576698