| Index: chrome/browser/resources/options/content_settings_exceptions_area.js
|
| diff --git a/chrome/browser/resources/options/content_settings_exceptions_area.js b/chrome/browser/resources/options/content_settings_exceptions_area.js
|
| index f727476bee28a9e8e6e33398bf672301979f3b5a..70775599055e4600905fc9228411f3b903eba1ed 100644
|
| --- a/chrome/browser/resources/options/content_settings_exceptions_area.js
|
| +++ b/chrome/browser/resources/options/content_settings_exceptions_area.js
|
| @@ -39,21 +39,27 @@ cr.define('options.contentSettings', function() {
|
| decorate: function() {
|
| ListItem.prototype.decorate.call(this);
|
|
|
| - // Labels for display mode.
|
| - var patternLabel = cr.doc.createElement('span');
|
| - patternLabel.textContent = this.pattern;
|
| - this.appendChild(patternLabel);
|
| -
|
| - var settingLabel = cr.doc.createElement('span');
|
| - settingLabel.textContent = this.settingForDisplay();
|
| - settingLabel.className = 'exceptionSetting';
|
| - this.appendChild(settingLabel);
|
| + // Labels for display mode. |pattern| will be null for the 'add new
|
| + // exception' row.
|
| + if (this.pattern) {
|
| + var patternLabel = cr.doc.createElement('span');
|
| + patternLabel.textContent = this.pattern;
|
| + patternLabel.className = 'exceptionPattern';
|
| + this.appendChild(patternLabel);
|
| + this.patternLabel = patternLabel;
|
| +
|
| + var settingLabel = cr.doc.createElement('span');
|
| + settingLabel.textContent = this.settingForDisplay();
|
| + settingLabel.className = 'exceptionSetting';
|
| + this.appendChild(settingLabel);
|
| + this.settingLabel = settingLabel;
|
| + }
|
|
|
| // Elements for edit mode.
|
| var input = cr.doc.createElement('input');
|
| input.type = 'text';
|
| this.appendChild(input);
|
| - input.className = 'exceptionInput hidden';
|
| + input.className = 'exceptionPattern hidden';
|
|
|
| var select = cr.doc.createElement('select');
|
| var optionAllow = cr.doc.createElement('option');
|
| @@ -93,26 +99,23 @@ cr.define('options.contentSettings', function() {
|
| // empty input.
|
| this.inputIsValid = true;
|
|
|
| - this.patternLabel = patternLabel;
|
| - this.settingLabel = settingLabel;
|
| this.input = input;
|
| this.select = select;
|
| this.optionAllow = optionAllow;
|
| this.optionBlock = optionBlock;
|
|
|
| this.updateEditables();
|
| - if (!this.pattern)
|
| - input.value = templateData.examplePattern;
|
|
|
| var listItem = this;
|
| - this.ondblclick = function(event) {
|
| +
|
| + this.addEventListener('selectedChange', function(event) {
|
| // Editing notifications and geolocation is disabled for now.
|
| if (listItem.contentType == 'notifications' ||
|
| listItem.contentType == 'location')
|
| return;
|
|
|
| - listItem.editing = true;
|
| - };
|
| + listItem.editing = listItem.selected;
|
| + });
|
|
|
| // Handle events on the editable nodes.
|
| input.oninput = function(event) {
|
| @@ -132,32 +135,14 @@ cr.define('options.contentSettings', function() {
|
| case 'U+001B': // Esc
|
| // Reset the inputs.
|
| listItem.updateEditables();
|
| - if (listItem.pattern)
|
| - listItem.maybeSetPatternValid(listItem.pattern, true);
|
| + listItem.setPatternValid(true);
|
| case 'Enter':
|
| - if (listItem.parentNode)
|
| - listItem.parentNode.focus();
|
| + listItem.ownerDocument.activeElement.blur();
|
| }
|
| }
|
|
|
| - function handleBlur(e) {
|
| - // When the blur event happens we do not know who is getting focus so we
|
| - // delay this a bit since we want to know if the other input got focus
|
| - // before deciding if we should exit edit mode.
|
| - var doc = e.target.ownerDocument;
|
| - window.setTimeout(function() {
|
| - var activeElement = doc.activeElement;
|
| - if (!listItem.contains(activeElement)) {
|
| - listItem.editing = false;
|
| - }
|
| - }, 50);
|
| - }
|
| -
|
| input.addEventListener('keydown', handleKeydown);
|
| - input.addEventListener('blur', handleBlur);
|
| -
|
| select.addEventListener('keydown', handleKeydown);
|
| - select.addEventListener('blur', handleBlur);
|
| },
|
|
|
| /**
|
| @@ -199,20 +184,12 @@ cr.define('options.contentSettings', function() {
|
| },
|
|
|
| /**
|
| - * Update this list item to reflect whether the input is a valid pattern
|
| - * if |pattern| matches the text currently in the input.
|
| - * @param {string} pattern The pattern.
|
| + * 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.
|
| */
|
| - maybeSetPatternValid: function(pattern, valid) {
|
| - // Don't do anything for messages where we are 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 != this.input.value)
|
| - return;
|
| -
|
| - if (valid)
|
| + setPatternValid: function(valid) {
|
| + if (valid || !this.input.value)
|
| this.input.setCustomValidity('');
|
| else
|
| this.input.setCustomValidity(' ');
|
| @@ -221,10 +198,18 @@ cr.define('options.contentSettings', function() {
|
| },
|
|
|
| /**
|
| + * 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.input.value = this.pattern;
|
| + this.resetInput();
|
|
|
| if (this.setting == 'allow')
|
| this.optionAllow.selected = true;
|
| @@ -237,6 +222,17 @@ cr.define('options.contentSettings', function() {
|
| },
|
|
|
| /**
|
| + * Fiddle with the display of elements of this list item when the editing
|
| + * mode changes.
|
| + */
|
| + toggleVisibilityForEditing: function() {
|
| + this.patternLabel.classList.toggle('hidden');
|
| + this.settingLabel.classList.toggle('hidden');
|
| + this.input.classList.toggle('hidden');
|
| + this.select.classList.toggle('hidden');
|
| + },
|
| +
|
| + /**
|
| * Whether the user is currently able to edit the list item.
|
| * @type {boolean}
|
| */
|
| @@ -248,54 +244,41 @@ cr.define('options.contentSettings', function() {
|
| if (oldEditing == editing)
|
| return;
|
|
|
| - var listItem = this;
|
| - var pattern = this.pattern;
|
| - var setting = this.setting;
|
| - var patternLabel = this.patternLabel;
|
| - var settingLabel = this.settingLabel;
|
| var input = this.input;
|
| - var select = this.select;
|
| - var optionAllow = this.optionAllow;
|
| - var optionBlock = this.optionBlock;
|
| - var optionSession = this.optionSession;
|
| - var optionAsk = this.optionAsk;
|
| -
|
| - // Just delete this row if it was added via the Add button.
|
| - if (!editing && !pattern && !input.value) {
|
| - var model = listItem.parentNode.dataModel;
|
| - model.splice(model.indexOf(listItem.dataItem), 1);
|
| - return;
|
| - }
|
|
|
| - // Check that we have a valid pattern and if not we do not change the
|
| - // editing mode.
|
| - if (!editing && (!this.inputValidityKnown || !this.inputIsValid)) {
|
| - input.focus();
|
| - input.select();
|
| - return;
|
| - }
|
| -
|
| - patternLabel.classList.toggle('hidden');
|
| - settingLabel.classList.toggle('hidden');
|
| - input.classList.toggle('hidden');
|
| - select.classList.toggle('hidden');
|
| -
|
| - var doc = this.ownerDocument;
|
| - var area = doc.querySelector('div[contentType=' +
|
| - listItem.contentType + '][mode=' + listItem.mode + ']');
|
| - area.enableAddAndEditButtons(!editing);
|
| + this.toggleVisibilityForEditing();
|
|
|
| if (editing) {
|
| this.setAttribute('editing', '');
|
| cr.ui.limitInputWidth(input, this, 20);
|
| - input.focus();
|
| - input.select();
|
| + // When this is called in response to the selectedChange event,
|
| + // the list grabs focus immediately afterwards. Thus we must delay
|
| + // our focus grab.
|
| + window.setTimeout(function() {
|
| + input.focus();
|
| + input.select();
|
| + }, 50);
|
| +
|
| + // TODO(estade): should we insert example text here for the AddNewRow
|
| + // input?
|
| } else {
|
| this.removeAttribute('editing');
|
|
|
| + // Check that we have a valid pattern and if not we do not, abort
|
| + // changes to the exception.
|
| + if (!this.inputValidityKnown || !this.inputIsValid) {
|
| + this.updateEditables();
|
| + this.setPatternValid(true);
|
| + return;
|
| + }
|
| +
|
| var newPattern = input.value;
|
|
|
| var newSetting;
|
| + var optionAllow = this.optionAllow;
|
| + var optionBlock = this.optionBlock;
|
| + var optionSession = this.optionSession;
|
| + var optionAsk = this.optionAsk;
|
| if (optionAllow.selected)
|
| newSetting = 'allow';
|
| else if (optionBlock.selected)
|
| @@ -305,26 +288,103 @@ cr.define('options.contentSettings', function() {
|
| else if (optionAsk && optionAsk.selected)
|
| newSetting = 'ask';
|
|
|
| - // Empty edit - do nothing.
|
| - if (pattern == newPattern && newSetting == this.setting)
|
| - return;
|
| + this.finishEdit(newPattern, newSetting);
|
| + }
|
| + },
|
|
|
| - this.pattern = patternLabel.textContent = newPattern;
|
| - this.setting = newSetting;
|
| - settingLabel.textContent = this.settingForDisplay();
|
| + /**
|
| + * Editing is complete; update the model.
|
| + * @type {string} newPattern The pattern that the user entered.
|
| + * @type {string} newSetting The setting the user chose.
|
| + */
|
| + finishEdit: function(newPattern, newSetting) {
|
| + // Empty edit - do nothing.
|
| + if (newPattern == this.pattern && newSetting == this.setting)
|
| + return;
|
|
|
| - if (pattern != this.pattern) {
|
| - chrome.send('removeExceptions',
|
| - [this.contentType, this.mode, pattern]);
|
| - }
|
| + this.patternLabel.textContent = newPattern;
|
| + this.settingLabel.textContent = this.settingForDisplay();
|
| + var oldPattern = this.pattern;
|
| + this.pattern = newPattern;
|
| + this.setting = newSetting;
|
|
|
| - chrome.send('setException',
|
| - [this.contentType, this.mode, this.pattern, this.setting]);
|
| + if (oldPattern != newPattern) {
|
| + chrome.send('removeExceptions',
|
| + [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('li');
|
| + 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;
|
| + this.input.classList.remove('hidden');
|
| + this.select.classList.remove('hidden');
|
| +
|
| + // 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 = '';
|
| + },
|
| +
|
| + /**
|
| + * No elements show or hide when going into edit mode, so do nothing.
|
| + */
|
| + toggleVisibilityForEditing: function() {
|
| + // No-op.
|
| + },
|
| +
|
| + /**
|
| + * Editing is complete; update the model. As long as the pattern isn't
|
| + * empty, we'll just add it.
|
| + * @type {string} newPattern The pattern that the user entered.
|
| + * @type {string} newSetting The setting the user chose.
|
| + */
|
| + finishEdit: function(newPattern, newSetting) {
|
| + if (newPattern == '')
|
| + return;
|
| +
|
| + chrome.send('setException',
|
| + [this.contentType, this.mode, newPattern, newSetting]);
|
| + },
|
| + };
|
| +
|
| + /**
|
| * Creates a new exceptions list.
|
| * @constructor
|
| * @extends {cr.ui.List}
|
| @@ -340,11 +400,29 @@ cr.define('options.contentSettings', function() {
|
| decorate: function() {
|
| List.prototype.decorate.call(this);
|
|
|
| - this.dataModel = new ArrayDataModel([]);
|
| + this.contentType = this.parentNode.getAttribute('contentType');
|
| + this.mode = this.getAttribute('mode');
|
| +
|
| + var exceptionList = this;
|
| + function handleBlur(e) {
|
| + // When the blur event happens we do not know who is getting focus so we
|
| + // delay this a bit until we know if the new focus node is outside the
|
| + // list.
|
| + var doc = e.target.ownerDocument;
|
| + window.setTimeout(function() {
|
| + var activeElement = doc.activeElement;
|
| + if (!exceptionList.contains(activeElement))
|
| + exceptionList.selectionModel.clear();
|
| + }, 50);
|
| + }
|
| +
|
| + this.addEventListener('blur', handleBlur, true);
|
|
|
| // Whether the exceptions in this list allow an 'Ask every time' option.
|
| this.enableAskOption = (this.contentType == 'plugins' &&
|
| templateData.enable_click_to_play);
|
| +
|
| + this.reset();
|
| },
|
|
|
| /**
|
| @@ -352,10 +430,16 @@ cr.define('options.contentSettings', function() {
|
| * @param {Object} entry The element from the data model for this row.
|
| */
|
| createItem: function(entry) {
|
| - return new ExceptionsListItem(this.contentType,
|
| - this.mode,
|
| - this.enableAskOption,
|
| - entry);
|
| + if (entry) {
|
| + return new ExceptionsListItem(this.contentType,
|
| + this.mode,
|
| + this.enableAskOption,
|
| + entry);
|
| + } else {
|
| + return new ExceptionsAddRowListItem(this.contentType,
|
| + this.mode,
|
| + this.enableAskOption);
|
| + }
|
| },
|
|
|
| /**
|
| @@ -364,16 +448,6 @@ cr.define('options.contentSettings', function() {
|
| */
|
| addException: function(entry) {
|
| this.dataModel.push(entry);
|
| -
|
| - // When an empty row is added, put it into editing mode.
|
| - if (!entry['displayPattern'] && !entry['setting']) {
|
| - var index = this.dataModel.length - 1;
|
| - var sm = this.selectionModel;
|
| - sm.anchorIndex = sm.leadIndex = sm.selectedIndex = index;
|
| - this.scrollIndexIntoView(index);
|
| - var li = this.getListItemByIndex(index);
|
| - li.editing = true;
|
| - }
|
| },
|
|
|
| /**
|
| @@ -384,18 +458,23 @@ cr.define('options.contentSettings', function() {
|
| * a content exception setting.
|
| */
|
| patternValidityCheckComplete: function(pattern, valid) {
|
| - for (var i = 0; i < this.dataModel.length; i++) {
|
| - var listItem = this.getListItemByIndex(i);
|
| - if (listItem)
|
| - listItem.maybeSetPatternValid(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);
|
| }
|
| },
|
|
|
| /**
|
| * Removes all exceptions from the js model.
|
| */
|
| - clear: function() {
|
| - this.dataModel = new ArrayDataModel([]);
|
| + reset: function() {
|
| + // The null creates the Add New Exception row.
|
| + this.dataModel = new ArrayDataModel([null]);
|
| },
|
|
|
| /**
|
| @@ -434,6 +513,7 @@ cr.define('options.contentSettings', function() {
|
|
|
| return {
|
| ExceptionsListItem: ExceptionsListItem,
|
| + ExceptionsAddRowListItem: ExceptionsAddRowListItem,
|
| ExceptionsList: ExceptionsList,
|
| };
|
| });
|
|
|