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

Side by Side Diff: chrome/browser/resources/options2/content_settings_exceptions_area.js

Issue 10809005: Options: Rename chrome/browser/resources/options2 -> chrome/browser/resources/options. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Fix. Created 8 years, 4 months 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 unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 cr.define('options.contentSettings', function() {
6 /** @const */ var InlineEditableItemList = options.InlineEditableItemList;
7 /** @const */ var InlineEditableItem = options.InlineEditableItem;
8 /** @const */ var ArrayDataModel = cr.ui.ArrayDataModel;
9
10 /**
11 * Creates a new exceptions list item.
12 *
13 * @param {string} contentType The type of the list.
14 * @param {string} mode The browser mode, 'otr' or 'normal'.
15 * @param {boolean} enableAskOption Whether to show an 'ask every time'
16 * option in the select.
17 * @param {Object} exception A dictionary that contains the data of the
18 * exception.
19 * @constructor
20 * @extends {options.InlineEditableItem}
21 */
22 function ExceptionsListItem(contentType, mode, enableAskOption, exception) {
23 var el = cr.doc.createElement('div');
24 el.mode = mode;
25 el.contentType = contentType;
26 el.enableAskOption = enableAskOption;
27 el.dataItem = exception;
28 el.__proto__ = ExceptionsListItem.prototype;
29 el.decorate();
30
31 return el;
32 }
33
34 ExceptionsListItem.prototype = {
35 __proto__: InlineEditableItem.prototype,
36
37 /**
38 * Called when an element is decorated as a list item.
39 */
40 decorate: function() {
41 InlineEditableItem.prototype.decorate.call(this);
42
43 this.isPlaceholder = !this.pattern;
44 var patternCell = this.createEditableTextCell(this.pattern);
45 patternCell.className = 'exception-pattern';
46 patternCell.classList.add('weakrtl');
47 this.contentElement.appendChild(patternCell);
48 if (this.pattern)
49 this.patternLabel = patternCell.querySelector('.static-text');
50 var input = patternCell.querySelector('input');
51
52 // TODO(stuartmorgan): Create an createEditableSelectCell abstracting
53 // this code.
54 // Setting label for display mode. |pattern| will be null for the 'add new
55 // exception' row.
56 if (this.pattern) {
57 var settingLabel = cr.doc.createElement('span');
58 settingLabel.textContent = this.settingForDisplay();
59 settingLabel.className = 'exception-setting';
60 settingLabel.setAttribute('displaymode', 'static');
61 this.contentElement.appendChild(settingLabel);
62 this.settingLabel = settingLabel;
63 }
64
65 // Setting select element for edit mode.
66 var select = cr.doc.createElement('select');
67 var optionAllow = cr.doc.createElement('option');
68 optionAllow.textContent = loadTimeData.getString('allowException');
69 optionAllow.value = 'allow';
70 select.appendChild(optionAllow);
71
72 if (this.enableAskOption) {
73 var optionAsk = cr.doc.createElement('option');
74 optionAsk.textContent = loadTimeData.getString('askException');
75 optionAsk.value = 'ask';
76 select.appendChild(optionAsk);
77 }
78
79 if (this.contentType == 'cookies') {
80 var optionSession = cr.doc.createElement('option');
81 optionSession.textContent = loadTimeData.getString('sessionException');
82 optionSession.value = 'session';
83 select.appendChild(optionSession);
84 }
85
86 if (this.contentType != 'fullscreen') {
87 var optionBlock = cr.doc.createElement('option');
88 optionBlock.textContent = loadTimeData.getString('blockException');
89 optionBlock.value = 'block';
90 select.appendChild(optionBlock);
91 }
92
93 this.contentElement.appendChild(select);
94 select.className = 'exception-setting';
95 if (this.pattern)
96 select.setAttribute('displaymode', 'edit');
97
98 // Used to track whether the URL pattern in the input is valid.
99 // This will be true if the browser process has informed us that the
100 // current text in the input is valid. Changing the text resets this to
101 // false, and getting a response from the browser sets it back to true.
102 // It starts off as false for empty string (new exceptions) or true for
103 // already-existing exceptions (which we assume are valid).
104 this.inputValidityKnown = this.pattern;
105 // This one tracks the actual validity of the pattern in the input. This
106 // starts off as true so as not to annoy the user when he adds a new and
107 // empty input.
108 this.inputIsValid = true;
109
110 this.input = input;
111 this.select = select;
112
113 this.updateEditables();
114
115 // Editing notifications, geolocation and media-stream is disabled for
116 // now.
117 if (this.contentType == 'notifications' ||
118 this.contentType == 'location' ||
119 this.contentType == 'media-stream') {
120 this.editable = false;
121 }
122
123 // If the source of the content setting exception is not the user
124 // preference, then the content settings exception is managed and the user
125 // can't edit it.
126 if (this.dataItem.source &&
127 this.dataItem.source != 'preference') {
128 this.setAttribute('managedby', this.dataItem.source);
129 this.deletable = false;
130 this.editable = false;
131 }
132
133 // If the exception comes from a hosted app, display the name and the
134 // icon of the app.
135 if (this.dataItem.source == 'HostedApp') {
136 this.title =
137 loadTimeData.getString('set_by') + ' ' + this.dataItem.appName;
138 var button = this.querySelector('.row-delete-button');
139 // Use the host app's favicon (16px, match bigger size).
140 // See c/b/ui/webui/extensions/extension_icon_source.h
141 // for a description of the chrome://extension-icon URL.
142 button.style.backgroundImage =
143 'url(\'chrome://extension-icon/' + this.dataItem.appId + '/16/1\')';
144 }
145
146 var listItem = this;
147 // Handle events on the editable nodes.
148 input.oninput = function(event) {
149 listItem.inputValidityKnown = false;
150 chrome.send('checkExceptionPatternValidity',
151 [listItem.contentType, listItem.mode, input.value]);
152 };
153
154 // Listen for edit events.
155 this.addEventListener('canceledit', this.onEditCancelled_);
156 this.addEventListener('commitedit', this.onEditCommitted_);
157 },
158
159 /**
160 * The pattern (e.g., a URL) for the exception.
161 *
162 * @type {string}
163 */
164 get pattern() {
165 return this.dataItem['displayPattern'];
166 },
167 set pattern(pattern) {
168 this.dataItem['displayPattern'] = pattern;
169 },
170
171 /**
172 * The setting (allow/block) for the exception.
173 *
174 * @type {string}
175 */
176 get setting() {
177 return this.dataItem['setting'];
178 },
179 set setting(setting) {
180 this.dataItem['setting'] = setting;
181 },
182
183 /**
184 * Gets a human-readable setting string.
185 *
186 * @type {string}
187 */
188 settingForDisplay: function() {
189 var setting = this.setting;
190 if (setting == 'allow')
191 return loadTimeData.getString('allowException');
192 else if (setting == 'block')
193 return loadTimeData.getString('blockException');
194 else if (setting == 'ask')
195 return loadTimeData.getString('askException');
196 else if (setting == 'session')
197 return loadTimeData.getString('sessionException');
198 },
199
200 /**
201 * Update this list item to reflect whether the input is a valid pattern.
202 *
203 * @param {boolean} valid Whether said pattern is valid in the context of a
204 * content exception setting.
205 */
206 setPatternValid: function(valid) {
207 if (valid || !this.input.value)
208 this.input.setCustomValidity('');
209 else
210 this.input.setCustomValidity(' ');
211 this.inputIsValid = valid;
212 this.inputValidityKnown = true;
213 },
214
215 /**
216 * Set the <input> to its original contents. Used when the user quits
217 * editing.
218 */
219 resetInput: function() {
220 this.input.value = this.pattern;
221 },
222
223 /**
224 * Copy the data model values to the editable nodes.
225 */
226 updateEditables: function() {
227 this.resetInput();
228
229 var settingOption =
230 this.select.querySelector('[value=\'' + this.setting + '\']');
231 if (settingOption)
232 settingOption.selected = true;
233 },
234
235 /** @inheritDoc */
236 get currentInputIsValid() {
237 return this.inputValidityKnown && this.inputIsValid;
238 },
239
240 /** @inheritDoc */
241 get hasBeenEdited() {
242 var livePattern = this.input.value;
243 var liveSetting = this.select.value;
244 return livePattern != this.pattern || liveSetting != this.setting;
245 },
246
247 /**
248 * Called when committing an edit.
249 *
250 * @param {Event} e The end event.
251 * @private
252 */
253 onEditCommitted_: function(e) {
254 var newPattern = this.input.value;
255 var newSetting = this.select.value;
256
257 this.finishEdit(newPattern, newSetting);
258 },
259
260 /**
261 * Called when cancelling an edit; resets the control states.
262 *
263 * @param {Event} e The cancel event.
264 * @private
265 */
266 onEditCancelled_: function() {
267 this.updateEditables();
268 this.setPatternValid(true);
269 },
270
271 /**
272 * Editing is complete; update the model.
273 *
274 * @param {string} newPattern The pattern that the user entered.
275 * @param {string} newSetting The setting the user chose.
276 */
277 finishEdit: function(newPattern, newSetting) {
278 this.patternLabel.textContent = newPattern;
279 this.settingLabel.textContent = this.settingForDisplay();
280 var oldPattern = this.pattern;
281 this.pattern = newPattern;
282 this.setting = newSetting;
283
284 // TODO(estade): this will need to be updated if geolocation/notifications
285 // become editable.
286 if (oldPattern != newPattern) {
287 chrome.send('removeException',
288 [this.contentType, this.mode, oldPattern]);
289 }
290
291 chrome.send('setException',
292 [this.contentType, this.mode, newPattern, newSetting]);
293 }
294 };
295
296 /**
297 * Creates a new list item for the Add New Item row, which doesn't represent
298 * an actual entry in the exceptions list but allows the user to add new
299 * exceptions.
300 *
301 * @param {string} contentType The type of the list.
302 * @param {string} mode The browser mode, 'otr' or 'normal'.
303 * @param {boolean} enableAskOption Whether to show an 'ask every time' option
304 * in the select.
305 * @constructor
306 * @extends {cr.ui.ExceptionsListItem}
307 */
308 function ExceptionsAddRowListItem(contentType, mode, enableAskOption) {
309 var el = cr.doc.createElement('div');
310 el.mode = mode;
311 el.contentType = contentType;
312 el.enableAskOption = enableAskOption;
313 el.dataItem = [];
314 el.__proto__ = ExceptionsAddRowListItem.prototype;
315 el.decorate();
316
317 return el;
318 }
319
320 ExceptionsAddRowListItem.prototype = {
321 __proto__: ExceptionsListItem.prototype,
322
323 decorate: function() {
324 ExceptionsListItem.prototype.decorate.call(this);
325
326 this.input.placeholder =
327 loadTimeData.getString('addNewExceptionInstructions');
328
329 // Do we always want a default of allow?
330 this.setting = 'allow';
331 },
332
333 /**
334 * Clear the <input> and let the placeholder text show again.
335 */
336 resetInput: function() {
337 this.input.value = '';
338 },
339
340 /** @inheritDoc */
341 get hasBeenEdited() {
342 return this.input.value != '';
343 },
344
345 /**
346 * Editing is complete; update the model. As long as the pattern isn't
347 * empty, we'll just add it.
348 *
349 * @param {string} newPattern The pattern that the user entered.
350 * @param {string} newSetting The setting the user chose.
351 */
352 finishEdit: function(newPattern, newSetting) {
353 this.resetInput();
354 chrome.send('setException',
355 [this.contentType, this.mode, newPattern, newSetting]);
356 },
357 };
358
359 /**
360 * Creates a new exceptions list.
361 *
362 * @constructor
363 * @extends {cr.ui.List}
364 */
365 var ExceptionsList = cr.ui.define('list');
366
367 ExceptionsList.prototype = {
368 __proto__: InlineEditableItemList.prototype,
369
370 /**
371 * Called when an element is decorated as a list.
372 */
373 decorate: function() {
374 InlineEditableItemList.prototype.decorate.call(this);
375
376 this.classList.add('settings-list');
377
378 for (var parentNode = this.parentNode; parentNode;
379 parentNode = parentNode.parentNode) {
380 if (parentNode.hasAttribute('contentType')) {
381 this.contentType = parentNode.getAttribute('contentType');
382 break;
383 }
384 }
385
386 this.mode = this.getAttribute('mode');
387
388 var exceptionList = this;
389
390 // Whether the exceptions in this list allow an 'Ask every time' option.
391 this.enableAskOption = this.contentType == 'plugins' ||
392 this.contentType == 'pepper-flash-cameramic';
393
394 this.autoExpands = true;
395 this.reset();
396 },
397
398 /**
399 * Creates an item to go in the list.
400 *
401 * @param {Object} entry The element from the data model for this row.
402 */
403 createItem: function(entry) {
404 if (entry) {
405 return new ExceptionsListItem(this.contentType,
406 this.mode,
407 this.enableAskOption,
408 entry);
409 } else {
410 var addRowItem = new ExceptionsAddRowListItem(this.contentType,
411 this.mode,
412 this.enableAskOption);
413 addRowItem.deletable = false;
414 return addRowItem;
415 }
416 },
417
418 /**
419 * Sets the exceptions in the js model.
420 *
421 * @param {Object} entries A list of dictionaries of values, each dictionary
422 * represents an exception.
423 */
424 setExceptions: function(entries) {
425 var deleteCount = this.dataModel.length;
426
427 if (this.isEditable()) {
428 // We don't want to remove the Add New Exception row.
429 deleteCount = deleteCount - 1;
430 }
431
432 var args = [0, deleteCount];
433 args.push.apply(args, entries);
434 this.dataModel.splice.apply(this.dataModel, args);
435 },
436
437 /**
438 * The browser has finished checking a pattern for validity. Update the list
439 * item to reflect this.
440 *
441 * @param {string} pattern The pattern.
442 * @param {bool} valid Whether said pattern is valid in the context of a
443 * content exception setting.
444 */
445 patternValidityCheckComplete: function(pattern, valid) {
446 var listItems = this.items;
447 for (var i = 0; i < listItems.length; i++) {
448 var listItem = listItems[i];
449 // Don't do anything for messages for the item if it is not the intended
450 // recipient, or if the response is stale (i.e. the input value has
451 // changed since we sent the request to analyze it).
452 if (pattern == listItem.input.value)
453 listItem.setPatternValid(valid);
454 }
455 },
456
457 /**
458 * Returns whether the rows are editable in this list.
459 */
460 isEditable: function() {
461 // Exceptions of the following lists are not editable for now.
462 return !(this.contentType == 'notifications' ||
463 this.contentType == 'location' ||
464 this.contentType == 'fullscreen' ||
465 this.contentType == 'media-stream');
466 },
467
468 /**
469 * Removes all exceptions from the js model.
470 */
471 reset: function() {
472 if (this.isEditable()) {
473 // The null creates the Add New Exception row.
474 this.dataModel = new ArrayDataModel([null]);
475 } else {
476 this.dataModel = new ArrayDataModel([]);
477 }
478 },
479
480 /** @inheritDoc */
481 deleteItemAtIndex: function(index) {
482 var listItem = this.getListItemByIndex(index);
483 if (listItem.undeletable)
484 return;
485
486 var dataItem = listItem.dataItem;
487 var args = [listItem.contentType];
488 if (listItem.contentType == 'location')
489 args.push(dataItem['origin'], dataItem['embeddingOrigin']);
490 else if (listItem.contentType == 'notifications')
491 args.push(dataItem['origin'], dataItem['setting']);
492 else
493 args.push(listItem.mode, listItem.pattern);
494
495 chrome.send('removeException', args);
496 },
497 };
498
499 var OptionsPage = options.OptionsPage;
500
501 /**
502 * Encapsulated handling of content settings list subpage.
503 *
504 * @constructor
505 */
506 function ContentSettingsExceptionsArea() {
507 OptionsPage.call(this, 'contentExceptions',
508 loadTimeData.getString('contentSettingsPageTabTitle'),
509 'content-settings-exceptions-area');
510 }
511
512 cr.addSingletonGetter(ContentSettingsExceptionsArea);
513
514 ContentSettingsExceptionsArea.prototype = {
515 __proto__: OptionsPage.prototype,
516
517 initializePage: function() {
518 OptionsPage.prototype.initializePage.call(this);
519
520 var exceptionsLists = this.pageDiv.querySelectorAll('list');
521 for (var i = 0; i < exceptionsLists.length; i++) {
522 options.contentSettings.ExceptionsList.decorate(exceptionsLists[i]);
523 }
524
525 ContentSettingsExceptionsArea.hideOTRLists(false);
526
527 // If the user types in the URL without a hash, show just cookies.
528 this.showList('cookies');
529
530 $('content-settings-exceptions-overlay-confirm').onclick =
531 OptionsPage.closeOverlay.bind(OptionsPage);
532 },
533
534 /**
535 * Shows one list and hides all others.
536 *
537 * @param {string} type The content type.
538 */
539 showList: function(type) {
540 var header = this.pageDiv.querySelector('h1');
541 header.textContent = loadTimeData.getString(type + '_header');
542
543 var divs = this.pageDiv.querySelectorAll('div[contentType]');
544 for (var i = 0; i < divs.length; i++) {
545 if (divs[i].getAttribute('contentType') == type)
546 divs[i].hidden = false;
547 else
548 divs[i].hidden = true;
549 }
550 },
551
552 /**
553 * Called after the page has been shown. Show the content type for the
554 * location's hash.
555 */
556 didShowPage: function() {
557 var hash = location.hash;
558 if (hash)
559 this.showList(hash.slice(1));
560 },
561 };
562
563 /**
564 * Called when the last incognito window is closed.
565 */
566 ContentSettingsExceptionsArea.OTRProfileDestroyed = function() {
567 this.hideOTRLists(true);
568 };
569
570 /**
571 * Hides the incognito exceptions lists and optionally clears them as well.
572 * @param {boolean} clear Whether to clear the lists.
573 */
574 ContentSettingsExceptionsArea.hideOTRLists = function(clear) {
575 var otrLists = document.querySelectorAll('list[mode=otr]');
576
577 for (var i = 0; i < otrLists.length; i++) {
578 otrLists[i].parentNode.hidden = true;
579 if (clear)
580 otrLists[i].reset();
581 }
582 };
583
584 return {
585 ExceptionsListItem: ExceptionsListItem,
586 ExceptionsAddRowListItem: ExceptionsAddRowListItem,
587 ExceptionsList: ExceptionsList,
588 ContentSettingsExceptionsArea: ContentSettingsExceptionsArea,
589 };
590 });
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698