Home | History | Annotate | Download | only in options
      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', function() {
      6   /** @const */ var Page = cr.ui.pageManager.Page;
      7   /** @const */ var PageManager = cr.ui.pageManager.PageManager;
      8 
      9   // Lookup table to generate the i18n strings.
     10   /** @const */ var permissionsLookup = {
     11     'location': 'location',
     12     'notifications': 'notifications',
     13     'media-stream': 'mediaStream',
     14     'cookies': 'cookies',
     15     'multiple-automatic-downloads': 'multipleAutomaticDownloads',
     16     'images': 'images',
     17     'plugins': 'plugins',
     18     'popups': 'popups',
     19     'javascript': 'javascript'
     20   };
     21 
     22   //////////////////////////////////////////////////////////////////////////////
     23   // ContentSettings class:
     24 
     25   /**
     26    * Encapsulated handling of content settings page.
     27    * @constructor
     28    * @extends {cr.ui.pageManager.Page}
     29    */
     30   function ContentSettings() {
     31     this.activeNavTab = null;
     32     Page.call(this, 'content',
     33               loadTimeData.getString('contentSettingsPageTabTitle'),
     34               'content-settings-page');
     35   }
     36 
     37   cr.addSingletonGetter(ContentSettings);
     38 
     39   ContentSettings.prototype = {
     40     __proto__: Page.prototype,
     41 
     42     /** @override */
     43     initializePage: function() {
     44       Page.prototype.initializePage.call(this);
     45 
     46       var exceptionsButtons =
     47           this.pageDiv.querySelectorAll('.exceptions-list-button');
     48       for (var i = 0; i < exceptionsButtons.length; i++) {
     49         exceptionsButtons[i].onclick = function(event) {
     50           var hash = event.currentTarget.getAttribute('contentType');
     51           PageManager.showPageByName('contentExceptions', true,
     52                                      {hash: '#' + hash});
     53         };
     54       }
     55 
     56       var experimentalExceptionsButtons =
     57           this.pageDiv.querySelectorAll('.website-settings-permission-button');
     58       for (var i = 0; i < experimentalExceptionsButtons.length; i++) {
     59         experimentalExceptionsButtons[i].onclick = function(event) {
     60           var hash = event.currentTarget.getAttribute('contentType');
     61           WebsiteSettingsManager.showWebsiteSettings(hash);
     62         };
     63       }
     64 
     65       var manageHandlersButton = $('manage-handlers-button');
     66       if (manageHandlersButton) {
     67         manageHandlersButton.onclick = function(event) {
     68           PageManager.showPageByName('handlers');
     69         };
     70       }
     71 
     72       if (cr.isChromeOS) {
     73         // Disable some controls for Guest in Chrome OS.
     74         UIAccountTweaks.applyGuestSessionVisibility(document);
     75 
     76         // Disable some controls for Public session in Chrome OS.
     77         UIAccountTweaks.applyPublicSessionVisibility(document);
     78       }
     79 
     80       // Cookies filter page ---------------------------------------------------
     81       $('show-cookies-button').onclick = function(event) {
     82         chrome.send('coreOptionsUserMetricsAction', ['Options_ShowCookies']);
     83         PageManager.showPageByName('cookies');
     84       };
     85 
     86       $('content-settings-overlay-confirm').onclick =
     87           PageManager.closeOverlay.bind(PageManager);
     88 
     89       $('media-pepper-flash-default').hidden = true;
     90       $('media-pepper-flash-exceptions').hidden = true;
     91 
     92       $('media-select-mic').addEventListener('change',
     93           ContentSettings.setDefaultMicrophone_);
     94       $('media-select-camera').addEventListener('change',
     95           ContentSettings.setDefaultCamera_);
     96 
     97       if (loadTimeData.getBoolean('websiteSettingsManagerEnabled')) {
     98         var oldUI =
     99             this.pageDiv.querySelectorAll('.replace-with-website-settings');
    100         for (var i = 0; i < oldUI.length; i++) {
    101           oldUI[i].hidden = true;
    102         }
    103 
    104         var newUI =
    105             this.pageDiv.querySelectorAll('.experimental-website-settings');
    106         for (var i = 0; i < newUI.length; i++) {
    107           newUI[i].hidden = false;
    108         }
    109       }
    110     },
    111   };
    112 
    113   ContentSettings.updateHandlersEnabledRadios = function(enabled) {
    114     var selector = '#content-settings-page input[type=radio][value=' +
    115         (enabled ? 'allow' : 'block') + '].handler-radio';
    116     document.querySelector(selector).checked = true;
    117   };
    118 
    119   /**
    120    * Sets the values for all the content settings radios and labels.
    121    * @param {Object} dict A mapping from radio groups to the checked value for
    122    *     that group.
    123    */
    124   ContentSettings.setContentFilterSettingsValue = function(dict) {
    125     for (var group in dict) {
    126       var settingLabel = $(group + '-default-string');
    127       if (settingLabel) {
    128         var value = dict[group].value;
    129         var valueId =
    130             permissionsLookup[group] + value[0].toUpperCase() + value.slice(1);
    131         settingLabel.textContent = loadTimeData.getString(valueId);
    132       }
    133 
    134       var managedBy = dict[group].managedBy;
    135       var controlledBy = managedBy == 'policy' || managedBy == 'extension' ?
    136           managedBy : null;
    137       document.querySelector('input[type=radio][name=' + group + '][value=' +
    138                              dict[group].value + ']').checked = true;
    139       var radios = document.querySelectorAll('input[type=radio][name=' +
    140                                              group + ']');
    141       for (var i = 0, len = radios.length; i < len; i++) {
    142         radios[i].disabled = (managedBy != 'default');
    143         radios[i].controlledBy = controlledBy;
    144       }
    145       var indicators = document.querySelectorAll(
    146           'span.controlled-setting-indicator[content-setting=' + group + ']');
    147       if (indicators.length == 0)
    148         continue;
    149       // Create a synthetic pref change event decorated as
    150       // CoreOptionsHandler::CreateValueForPref() does.
    151       var event = new Event(group);
    152       event.value = {
    153         value: dict[group].value,
    154         controlledBy: controlledBy,
    155       };
    156       for (var i = 0; i < indicators.length; i++) {
    157         indicators[i].handlePrefChange(event);
    158       }
    159     }
    160   };
    161 
    162   /**
    163    * Updates the labels and indicators for the Media settings. Those require
    164    * special handling because they are backed by multiple prefs and can change
    165    * their scope based on the managed state of the backing prefs.
    166    * @param {{askText: string, blockText: string, cameraDisabled: boolean,
    167    *          micDisabled: boolean, showBubble: boolean, bubbleText: string}}
    168    *     mediaSettings A dictionary containing the following fields:
    169    *     askText The label for the ask radio button.
    170    *     blockText The label for the block radio button.
    171    *     cameraDisabled Whether to disable the camera dropdown.
    172    *     micDisabled Whether to disable the microphone dropdown.
    173    *     showBubble Wether to show the managed icon and bubble for the media
    174    *                label.
    175    *     bubbleText The text to use inside the bubble if it is shown.
    176    */
    177   ContentSettings.updateMediaUI = function(mediaSettings) {
    178     $('media-stream-ask-label').innerHTML =
    179         loadTimeData.getString(mediaSettings.askText);
    180     $('media-stream-block-label').innerHTML =
    181         loadTimeData.getString(mediaSettings.blockText);
    182 
    183     if (mediaSettings.micDisabled)
    184       $('media-select-mic').disabled = true;
    185     if (mediaSettings.cameraDisabled)
    186       $('media-select-camera').disabled = true;
    187 
    188     PageManager.hideBubble();
    189     // Create a synthetic pref change event decorated as
    190     // CoreOptionsHandler::CreateValueForPref() does.
    191     // TODO(arv): It was not clear what event type this should use?
    192     var event = new Event('undefined');
    193     event.value = {};
    194 
    195     if (mediaSettings.showBubble) {
    196       event.value = { controlledBy: 'policy' };
    197       $('media-indicator').setAttribute(
    198           'textpolicy', loadTimeData.getString(mediaSettings.bubbleText));
    199       $('media-indicator').location = cr.ui.ArrowLocation.TOP_START;
    200     }
    201 
    202     $('media-indicator').handlePrefChange(event);
    203   };
    204 
    205   /**
    206    * Initializes an exceptions list.
    207    * @param {string} type The content type that we are setting exceptions for.
    208    * @param {Array} exceptions An array of pairs, where the first element of
    209    *     each pair is the filter string, and the second is the setting
    210    *     (allow/block).
    211    */
    212   ContentSettings.setExceptions = function(type, exceptions) {
    213     this.getExceptionsList(type, 'normal').setExceptions(exceptions);
    214   };
    215 
    216   ContentSettings.setHandlers = function(handlers) {
    217     $('handlers-list').setHandlers(handlers);
    218   };
    219 
    220   ContentSettings.setIgnoredHandlers = function(ignoredHandlers) {
    221     $('ignored-handlers-list').setHandlers(ignoredHandlers);
    222   };
    223 
    224   ContentSettings.setOTRExceptions = function(type, otrExceptions) {
    225     var exceptionsList = this.getExceptionsList(type, 'otr');
    226     // Settings for Guest hides many sections, so check for null first.
    227     if (exceptionsList) {
    228       exceptionsList.parentNode.hidden = false;
    229       exceptionsList.setExceptions(otrExceptions);
    230     }
    231   };
    232 
    233   /**
    234    * @param {string} type The type of exceptions (e.g. "location") to get.
    235    * @param {string} mode The mode of the desired exceptions list (e.g. otr).
    236    * @return {?options.contentSettings.ExceptionsList} The corresponding
    237    *     exceptions list or null.
    238    */
    239   ContentSettings.getExceptionsList = function(type, mode) {
    240     var exceptionsList = document.querySelector(
    241         'div[contentType=' + type + '] list[mode=' + mode + ']');
    242     return !exceptionsList ? null :
    243         assertInstanceof(exceptionsList,
    244                          options.contentSettings.ExceptionsList);
    245   };
    246 
    247   /**
    248    * The browser's response to a request to check the validity of a given URL
    249    * pattern.
    250    * @param {string} type The content type.
    251    * @param {string} mode The browser mode.
    252    * @param {string} pattern The pattern.
    253    * @param {boolean} valid Whether said pattern is valid in the context of
    254    *     a content exception setting.
    255    */
    256   ContentSettings.patternValidityCheckComplete =
    257       function(type, mode, pattern, valid) {
    258     this.getExceptionsList(type, mode).patternValidityCheckComplete(pattern,
    259                                                                     valid);
    260   };
    261 
    262   /**
    263    * Shows/hides the link to the Pepper Flash camera and microphone default
    264    * settings.
    265    * Please note that whether the link is actually showed or not is also
    266    * affected by the style class pepper-flash-settings.
    267    */
    268   ContentSettings.showMediaPepperFlashDefaultLink = function(show) {
    269     $('media-pepper-flash-default').hidden = !show;
    270   };
    271 
    272   /**
    273    * Shows/hides the link to the Pepper Flash camera and microphone
    274    * site-specific settings.
    275    * Please note that whether the link is actually showed or not is also
    276    * affected by the style class pepper-flash-settings.
    277    */
    278   ContentSettings.showMediaPepperFlashExceptionsLink = function(show) {
    279     $('media-pepper-flash-exceptions').hidden = !show;
    280   };
    281 
    282   /**
    283    * Shows/hides the whole Web MIDI settings.
    284    * @param {boolean} show Wether to show the whole Web MIDI settings.
    285    */
    286   ContentSettings.showExperimentalWebMIDISettings = function(show) {
    287     $('experimental-web-midi-settings').hidden = !show;
    288   };
    289 
    290   /**
    291    * Updates the microphone/camera devices menu with the given entries.
    292    * @param {string} type The device type.
    293    * @param {Array} devices List of available devices.
    294    * @param {string} defaultdevice The unique id of the current default device.
    295    */
    296   ContentSettings.updateDevicesMenu = function(type, devices, defaultdevice) {
    297     var deviceSelect = '';
    298     if (type == 'mic') {
    299       deviceSelect = $('media-select-mic');
    300     } else if (type == 'camera') {
    301       deviceSelect = $('media-select-camera');
    302     } else {
    303       console.error('Unknown device type for <device select> UI element: ' +
    304                     type);
    305       return;
    306     }
    307 
    308     deviceSelect.textContent = '';
    309 
    310     var deviceCount = devices.length;
    311     var defaultIndex = -1;
    312     for (var i = 0; i < deviceCount; i++) {
    313       var device = devices[i];
    314       var option = new Option(device.name, device.id);
    315       if (option.value == defaultdevice)
    316         defaultIndex = i;
    317       deviceSelect.appendChild(option);
    318     }
    319     if (defaultIndex >= 0)
    320       deviceSelect.selectedIndex = defaultIndex;
    321   };
    322 
    323   /**
    324    * Enables/disables the protected content exceptions button.
    325    * @param {boolean} enable Whether to enable the button.
    326    */
    327   ContentSettings.enableProtectedContentExceptions = function(enable) {
    328     var exceptionsButton = $('protected-content-exceptions');
    329     if (exceptionsButton)
    330       exceptionsButton.disabled = !enable;
    331   };
    332 
    333   /**
    334    * Set the default microphone device based on the popup selection.
    335    * @private
    336    */
    337   ContentSettings.setDefaultMicrophone_ = function() {
    338     var deviceSelect = $('media-select-mic');
    339     chrome.send('setDefaultCaptureDevice', ['mic', deviceSelect.value]);
    340   };
    341 
    342   /**
    343    * Set the default camera device based on the popup selection.
    344    * @private
    345    */
    346   ContentSettings.setDefaultCamera_ = function() {
    347     var deviceSelect = $('media-select-camera');
    348     chrome.send('setDefaultCaptureDevice', ['camera', deviceSelect.value]);
    349   };
    350 
    351   // Export
    352   return {
    353     ContentSettings: ContentSettings
    354   };
    355 
    356 });
    357