Home | History | Annotate | Download | only in toolbox
      1 // Copyright 2014 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 WebInspector.OverridesUI = {}
      6 
      7 /**
      8  * @param {!Document} document
      9  * @param {!function(!function(string))=} titleProvider
     10  * @return {!Element}
     11  */
     12 WebInspector.OverridesUI.createDeviceSelect = function(document, titleProvider)
     13 {
     14     var p = document.createElement("p");
     15 
     16     var deviceSelectElement = p.createChild("select");
     17     deviceSelectElement.addEventListener("change", deviceSelected, false);
     18 
     19     var saveButton = p.createChild("button");
     20     saveButton.textContent = WebInspector.UIString("Save as");
     21     saveButton.addEventListener("click", saveClicked, false);
     22 
     23     var removeButton = p.createChild("button");
     24     removeButton.textContent = WebInspector.UIString("Remove");
     25     removeButton.addEventListener("click", removeClicked, false);
     26 
     27     // This has to be object, not boolean, otherwise its value doesn't update properly.
     28     var emulatedSettingChangedMuted = { muted: false };
     29     WebInspector.overridesSupport.settings.emulateResolution.addChangeListener(emulatedSettingChanged);
     30     WebInspector.overridesSupport.settings.deviceWidth.addChangeListener(emulatedSettingChanged);
     31     WebInspector.overridesSupport.settings.deviceHeight.addChangeListener(emulatedSettingChanged);
     32     WebInspector.overridesSupport.settings.deviceScaleFactor.addChangeListener(emulatedSettingChanged);
     33     WebInspector.overridesSupport.settings.emulateMobile.addChangeListener(emulatedSettingChanged);
     34     WebInspector.overridesSupport.settings.emulateTouch.addChangeListener(emulatedSettingChanged);
     35     WebInspector.overridesSupport.settings.userAgent.addChangeListener(emulatedSettingChanged);
     36 
     37     WebInspector.overridesSupport.settings.customDevicePresets.addChangeListener(customPresetsChanged);
     38     customPresetsChanged();
     39 
     40     function deviceSelected()
     41     {
     42         updateButtons();
     43 
     44         if (deviceSelectElement.selectedIndex === 0)
     45             return;
     46 
     47         var option = deviceSelectElement.options[deviceSelectElement.selectedIndex];
     48         emulatedSettingChangedMuted.muted = true;
     49         WebInspector.overridesSupport.emulateDevice(option.device);
     50         emulatedSettingChangedMuted.muted = false;
     51     }
     52 
     53     function emulatedSettingChanged()
     54     {
     55         if (emulatedSettingChangedMuted.muted)
     56             return;
     57 
     58         var index = 0;
     59         for (var i = 1; i < deviceSelectElement.options.length; ++i) {
     60             var option = deviceSelectElement.options[i];
     61             if (WebInspector.overridesSupport.isEmulatingDevice(option.device)) {
     62                 index = i;
     63                 break;
     64             }
     65         }
     66         deviceSelectElement.selectedIndex = index;
     67         updateButtons();
     68     }
     69 
     70     function updateButtons()
     71     {
     72         var index = deviceSelectElement.selectedIndex;
     73         var custom = deviceSelectElement.options[index].custom;
     74         saveButton.disabled = !!index || !titleProvider;
     75         removeButton.disabled = !custom;
     76     }
     77 
     78     function customPresetsChanged()
     79     {
     80         deviceSelectElement.removeChildren();
     81 
     82         var selectDeviceOption = new Option(WebInspector.UIString("<Select model>"), WebInspector.UIString("<Select model>"));
     83         selectDeviceOption.device = {title: WebInspector.UIString("<Select model>"), width: 0, height: 0, deviceScaleFactor: 0, userAgent: "", touch: false, mobile: false};
     84         selectDeviceOption.disabled = true;
     85         deviceSelectElement.appendChild(selectDeviceOption);
     86 
     87         addGroup(WebInspector.UIString("Custom"), WebInspector.overridesSupport.settings.customDevicePresets.get(), true);
     88         addGroup(WebInspector.UIString("Devices"), WebInspector.OverridesUI._phones.concat(WebInspector.OverridesUI._tablets));
     89         addGroup(WebInspector.UIString("Notebooks"), WebInspector.OverridesUI._notebooks);
     90 
     91         /**
     92          * @param {string} name
     93          * @param {!Array.<!WebInspector.OverridesSupport.Device>} devices
     94          * @param {boolean=} custom
     95          */
     96         function addGroup(name, devices, custom)
     97         {
     98             if (!devices.length)
     99                 return;
    100             devices = devices.slice();
    101             devices.sort(compareDevices);
    102             var groupElement = deviceSelectElement.createChild("optgroup");
    103             groupElement.label = name;
    104             for (var i = 0; i < devices.length; ++i) {
    105                 var option = new Option(devices[i].title, devices[i].title);
    106                 option.device = devices[i];
    107                 option.custom = custom;
    108                 groupElement.appendChild(option);
    109             }
    110         }
    111 
    112         /**
    113          * @param {!WebInspector.OverridesSupport.Device} device1
    114          * @param {!WebInspector.OverridesSupport.Device} device2
    115          * @return {number}
    116          */
    117         function compareDevices(device1, device2)
    118         {
    119             return device1.title < device2.title ? -1 : (device1.title > device2.title ? 1 : 0);
    120         }
    121 
    122         emulatedSettingChanged();
    123     }
    124 
    125     function saveClicked()
    126     {
    127         titleProvider(saveDevicePreset);
    128     }
    129 
    130     /**
    131      * @param {string} title
    132      */
    133     function saveDevicePreset(title)
    134     {
    135         if (!title)
    136             return;
    137         var device = WebInspector.overridesSupport.deviceFromCurrentSettings();
    138         device.title = title;
    139         var presets = WebInspector.overridesSupport.settings.customDevicePresets.get();
    140         presets.push(device);
    141         WebInspector.overridesSupport.settings.customDevicePresets.set(presets);
    142     }
    143 
    144     function removeClicked()
    145     {
    146         var presets = WebInspector.overridesSupport.settings.customDevicePresets.get();
    147         var option = deviceSelectElement.options[deviceSelectElement.selectedIndex];
    148         var device = option.device;
    149         presets.remove(device);
    150         WebInspector.overridesSupport.settings.customDevicePresets.set(presets);
    151     }
    152 
    153     return p;
    154 }
    155 
    156 /**
    157  * @param {!Document} document
    158  * @return {!Element}
    159  */
    160 WebInspector.OverridesUI.createNetworkConditionsSelect = function(document)
    161 {
    162     var networkConditionsSetting = WebInspector.overridesSupport.settings.networkConditions;
    163     var conditionsSelectElement = document.createElement("select");
    164     var presets = WebInspector.OverridesUI._networkConditionsPresets;
    165     for (var i = 0; i < presets.length; ++i) {
    166         var preset = presets[i];
    167         var throughput = preset.throughput | 0;
    168         var latency = preset.latency | 0;
    169         var isThrottling = (throughput > 0) || latency;
    170         if (!isThrottling) {
    171             conditionsSelectElement.add(new Option(preset.title, preset.id));
    172         } else {
    173             var throughputText = (throughput < 1024) ? WebInspector.UIString("%d Kbps", throughput) : WebInspector.UIString("%d Mbps", (throughput / 1024) | 0);
    174             var title = WebInspector.UIString("%s (%s %dms RTT)", preset.title, throughputText, latency);
    175             var option = new Option(title, preset.id);
    176             option.title = WebInspector.UIString("Maximum download throughput: %s.\r\nMinimum round-trip time: %dms.", throughputText, latency);
    177             conditionsSelectElement.add(option);
    178         }
    179     }
    180 
    181     settingChanged();
    182     networkConditionsSetting.addChangeListener(settingChanged);
    183     conditionsSelectElement.addEventListener("change", presetSelected, false);
    184 
    185     function presetSelected()
    186     {
    187         var selectedOption = conditionsSelectElement.options[conditionsSelectElement.selectedIndex];
    188         conditionsSelectElement.title = selectedOption.title;
    189         var presetId = selectedOption.value;
    190         var preset = presets[presets.length - 1];
    191         for (var i = 0; i < presets.length; ++i) {
    192             if (presets[i].id === presetId) {
    193                 preset = presets[i];
    194                 break;
    195             }
    196         }
    197         var kbps = 1024 / 8;
    198         networkConditionsSetting.removeChangeListener(settingChanged);
    199         networkConditionsSetting.set({throughput: preset.throughput * kbps, latency: preset.latency});
    200         networkConditionsSetting.addChangeListener(settingChanged);
    201     }
    202 
    203     function settingChanged()
    204     {
    205         var conditions = networkConditionsSetting.get();
    206         var presetIndex = presets.length - 1;
    207         var kbps = 1024 / 8;
    208         for (var i = 0; i < presets.length; ++i) {
    209             if (presets[i].throughput === conditions.throughput / kbps && presets[i].latency === conditions.latency) {
    210                 presetIndex = i;
    211                 break;
    212             }
    213         }
    214         conditionsSelectElement.selectedIndex = presetIndex;
    215         conditionsSelectElement.title = conditionsSelectElement.options[presetIndex].title;
    216     }
    217 
    218     return conditionsSelectElement;
    219 }
    220 
    221 /**
    222  * @param {!Document} document
    223  * @return {{select: !Element, input: !Element}}
    224  */
    225 WebInspector.OverridesUI.createUserAgentSelectAndInput = function(document)
    226 {
    227     var userAgentSetting = WebInspector.overridesSupport.settings.userAgent;
    228     const noOverride = {title: WebInspector.UIString("No override"), value: ""};
    229     const customOverride = {title: WebInspector.UIString("Other"), value: "Other"};
    230     var userAgents = [noOverride].concat(WebInspector.OverridesUI._userAgents).concat([customOverride]);
    231 
    232     var userAgentSelectElement = document.createElement("select");
    233     for (var i = 0; i < userAgents.length; ++i)
    234         userAgentSelectElement.add(new Option(userAgents[i].title, userAgents[i].value));
    235     userAgentSelectElement.selectedIndex = 0;
    236 
    237     var otherUserAgentElement = document.createElement("input");
    238     otherUserAgentElement.type = "text";
    239     otherUserAgentElement.value = userAgentSetting.get();
    240     otherUserAgentElement.title = userAgentSetting.get();
    241 
    242     settingChanged();
    243     userAgentSetting.addChangeListener(settingChanged);
    244     userAgentSelectElement.addEventListener("change", userAgentSelected, false);
    245 
    246     otherUserAgentElement.addEventListener("dblclick", textDoubleClicked, true);
    247     otherUserAgentElement.addEventListener("blur", textChanged, false);
    248     otherUserAgentElement.addEventListener("keydown", textKeyDown, false);
    249 
    250     function userAgentSelected()
    251     {
    252         var value = userAgentSelectElement.options[userAgentSelectElement.selectedIndex].value;
    253         if (value !== customOverride.value) {
    254             userAgentSetting.removeChangeListener(settingChanged);
    255             userAgentSetting.set(value);
    256             userAgentSetting.addChangeListener(settingChanged);
    257             otherUserAgentElement.value = value;
    258             otherUserAgentElement.title = value;
    259             otherUserAgentElement.readOnly = true;
    260         } else {
    261             otherUserAgentElement.readOnly = false;
    262             otherUserAgentElement.focus();
    263         }
    264     }
    265 
    266     function settingChanged()
    267     {
    268         var value = userAgentSetting.get();
    269         var options = userAgentSelectElement.options;
    270         var selectionRestored = false;
    271         for (var i = 0; i < options.length; ++i) {
    272             if (options[i].value === value) {
    273                 userAgentSelectElement.selectedIndex = i;
    274                 selectionRestored = true;
    275                 break;
    276             }
    277         }
    278 
    279         otherUserAgentElement.readOnly = selectionRestored;
    280         if (!selectionRestored)
    281             userAgentSelectElement.selectedIndex = options.length - 1;
    282 
    283         if (otherUserAgentElement.value !== value) {
    284             otherUserAgentElement.value = value;
    285             otherUserAgentElement.title = value;
    286         }
    287     }
    288 
    289     function textKeyDown(event)
    290     {
    291         if (isEnterKey(event))
    292             textChanged();
    293     }
    294 
    295     function textDoubleClicked()
    296     {
    297         userAgentSelectElement.selectedIndex = userAgents.length - 1;
    298         userAgentSelected();
    299     }
    300 
    301     function textChanged()
    302     {
    303         if (userAgentSetting.get() !== otherUserAgentElement.value)
    304             userAgentSetting.set(otherUserAgentElement.value);
    305     }
    306 
    307     return { select: userAgentSelectElement, input: otherUserAgentElement };
    308 }
    309 
    310 /** @type {!Array.<!WebInspector.OverridesSupport.Device>} */
    311 WebInspector.OverridesUI._phones = [
    312     {title: "Apple iPhone 3GS", width: 320, height: 480, deviceScaleFactor: 1, userAgent: "Mozilla/5.0 (iPhone; U; CPU iPhone OS 4_2_1 like Mac OS X; en-us) AppleWebKit/533.17.9 (KHTML, like Gecko) Version/5.0.2 Mobile/8C148 Safari/6533.18.5", touch: true, mobile: true},
    313     {title: "Apple iPhone 4", width: 320, height: 480, deviceScaleFactor: 2, userAgent: "Mozilla/5.0 (iPhone; U; CPU iPhone OS 4_2_1 like Mac OS X; en-us) AppleWebKit/533.17.9 (KHTML, like Gecko) Version/5.0.2 Mobile/8C148 Safari/6533.18.5", touch: true, mobile: true},
    314     {title: "Apple iPhone 5", width: 320, height: 568, deviceScaleFactor: 2, userAgent: "Mozilla/5.0 (iPhone; CPU iPhone OS 7_0 like Mac OS X; en-us) AppleWebKit/537.51.1 (KHTML, like Gecko) Version/7.0 Mobile/11A465 Safari/9537.53", touch: true, mobile: true},
    315     {title: "Apple iPhone 6", width: 375, height: 667, deviceScaleFactor: 2, userAgent: "Mozilla/5.0 (iPhone; CPU iPhone OS 8_0 like Mac OS X) AppleWebKit/600.1.3 (KHTML, like Gecko) Version/8.0 Mobile/12A4345d Safari/600.1.4", touch: true, mobile: true},
    316     {title: "Apple iPhone 6 Plus", width: 414, height: 736, deviceScaleFactor: 3, userAgent: "Mozilla/5.0 (iPhone; CPU iPhone OS 8_0 like Mac OS X) AppleWebKit/600.1.3 (KHTML, like Gecko) Version/8.0 Mobile/12A4345d Safari/600.1.4", touch: true, mobile: true},
    317     {title: "BlackBerry Z10", width: 384, height: 640, deviceScaleFactor: 2, userAgent: "Mozilla/5.0 (BB10; Touch) AppleWebKit/537.10+ (KHTML, like Gecko) Version/10.0.9.2372 Mobile Safari/537.10+", touch: true, mobile: true},
    318     {title: "BlackBerry Z30", width: 360, height: 640, deviceScaleFactor: 2, userAgent: "Mozilla/5.0 (BB10; Touch) AppleWebKit/537.10+ (KHTML, like Gecko) Version/10.0.9.2372 Mobile Safari/537.10+", touch: true, mobile: true},
    319     {title: "Google Nexus 4", width: 384, height: 640, deviceScaleFactor: 2, userAgent: "Mozilla/5.0 (Linux; Android 4.2.1; en-us; Nexus 4 Build/JOP40D) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.166 Mobile Safari/535.19", touch: true, mobile: true},
    320     {title: "Google Nexus 5", width: 360, height: 640, deviceScaleFactor: 3, userAgent: "Mozilla/5.0 (Linux; Android 4.2.1; en-us; Nexus 5 Build/JOP40D) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.166 Mobile Safari/535.19", touch: true, mobile: true},
    321     {title: "Google Nexus S", width: 320, height: 533, deviceScaleFactor: 1.5, userAgent: "Mozilla/5.0 (Linux; U; Android 2.3.4; en-us; Nexus S Build/GRJ22) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1", touch: true, mobile: true},
    322     {title: "HTC Evo, Touch HD, Desire HD, Desire", width: 320, height: 533, deviceScaleFactor: 1.5, userAgent: "Mozilla/5.0 (Linux; U; Android 2.2; en-us; Sprint APA9292KT Build/FRF91) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1", touch: true, mobile: true},
    323     {title: "HTC One X, EVO LTE", width: 360, height: 640, deviceScaleFactor: 2, userAgent: "Mozilla/5.0 (Linux; Android 4.0.3; HTC One X Build/IML74K) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.133 Mobile Safari/535.19", touch: true, mobile: true},
    324     {title: "HTC Sensation, Evo 3D", width: 360, height: 640, deviceScaleFactor: 1.5, userAgent: "Mozilla/5.0 (Linux; U; Android 4.0.3; en-us; HTC Sensation Build/IML74K) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30", touch: true, mobile: true},
    325     {title: "LG Optimus 2X, Optimus 3D, Optimus Black", width: 320, height: 533, deviceScaleFactor: 1.5, userAgent: "Mozilla/5.0 (Linux; U; Android 2.2; en-us; LG-P990/V08c Build/FRG83) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1 MMS/LG-Android-MMS-V1.0/1.2", touch: true, mobile: true},
    326     {title: "LG Optimus G", width: 384, height: 640, deviceScaleFactor: 2, userAgent: "Mozilla/5.0 (Linux; Android 4.0; LG-E975 Build/IMM76L) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.166 Mobile Safari/535.19", touch: true, mobile: true},
    327     {title: "LG Optimus LTE, Optimus 4X HD", width: 424, height: 753, deviceScaleFactor: 1.7, userAgent: "Mozilla/5.0 (Linux; U; Android 2.3; en-us; LG-P930 Build/GRJ90) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1", touch: true, mobile: true},
    328     {title: "LG Optimus One", width: 213, height: 320, deviceScaleFactor: 1.5, userAgent: "Mozilla/5.0 (Linux; U; Android 2.2.1; en-us; LG-MS690 Build/FRG83) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1", touch: true, mobile: true},
    329     {title: "Motorola Defy, Droid, Droid X, Milestone", width: 320, height: 569, deviceScaleFactor: 1.5, userAgent: "Mozilla/5.0 (Linux; U; Android 2.0; en-us; Milestone Build/ SHOLS_U2_01.03.1) AppleWebKit/530.17 (KHTML, like Gecko) Version/4.0 Mobile Safari/530.17", touch: true, mobile: true},
    330     {title: "Motorola Droid 3, Droid 4, Droid Razr, Atrix 4G, Atrix 2", width: 540, height: 960, deviceScaleFactor: 1, userAgent: "Mozilla/5.0 (Linux; U; Android 2.2; en-us; Droid Build/FRG22D) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1", touch: true, mobile: true},
    331     {title: "Motorola Droid Razr HD", width: 720, height: 1280, deviceScaleFactor: 1, userAgent: "Mozilla/5.0 (Linux; U; Android 2.3; en-us; DROID RAZR 4G Build/6.5.1-73_DHD-11_M1-29) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1", touch: true, mobile: true},
    332     {title: "Nokia C5, C6, C7, N97, N8, X7", width: 360, height: 640, deviceScaleFactor: 1, userAgent: "NokiaN97/21.1.107 (SymbianOS/9.4; Series60/5.0 Mozilla/5.0; Profile/MIDP-2.1 Configuration/CLDC-1.1) AppleWebkit/525 (KHTML, like Gecko) BrowserNG/7.1.4", touch: true, mobile: true},
    333     {title: "Nokia Lumia 7X0, Lumia 8XX, Lumia 900, N800, N810, N900", width: 320, height: 533, deviceScaleFactor: 1.5, userAgent: "Mozilla/5.0 (compatible; MSIE 10.0; Windows Phone 8.0; Trident/6.0; IEMobile/10.0; ARM; Touch; NOKIA; Lumia 820)", touch: true, mobile: true},
    334     {title: "Samsung Galaxy Note 3", width: 360, height: 640, deviceScaleFactor: 3, userAgent: "Mozilla/5.0 (Linux; U; Android 4.3; en-us; SM-N900T Build/JSS15J) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30", touch: true, mobile: true},
    335     {title: "Samsung Galaxy Note II", width: 360, height: 640, deviceScaleFactor: 2, userAgent: "Mozilla/5.0 (Linux; U; Android 4.1; en-us; GT-N7100 Build/JRO03C) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30", touch: true, mobile: true},
    336     {title: "Samsung Galaxy Note", width: 400, height: 640, deviceScaleFactor: 2, userAgent: "Mozilla/5.0 (Linux; U; Android 2.3; en-us; SAMSUNG-SGH-I717 Build/GINGERBREAD) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1", touch: true, mobile: true},
    337     {title: "Samsung Galaxy S III, Galaxy Nexus", width: 360, height: 640, deviceScaleFactor: 2, userAgent: "Mozilla/5.0 (Linux; U; Android 4.0; en-us; GT-I9300 Build/IMM76D) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30", touch: true, mobile: true},
    338     {title: "Samsung Galaxy S, S II, W", width: 320, height: 533, deviceScaleFactor: 1.5, userAgent: "Mozilla/5.0 (Linux; U; Android 2.1; en-us; GT-I9000 Build/ECLAIR) AppleWebKit/525.10+ (KHTML, like Gecko) Version/3.0.4 Mobile Safari/523.12.2", touch: true, mobile: true},
    339     {title: "Samsung Galaxy S4", width: 360, height: 640, deviceScaleFactor: 3, userAgent: "Mozilla/5.0 (Linux; Android 4.2.2; GT-I9505 Build/JDQ39) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.59 Mobile Safari/537.36", touch: true, mobile: true},
    340     {title: "Sony Xperia S, Ion", width: 360, height: 640, deviceScaleFactor: 2, userAgent: "Mozilla/5.0 (Linux; U; Android 4.0; en-us; LT28at Build/6.1.C.1.111) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30", touch: true, mobile: true},
    341     {title: "Sony Xperia Sola, U", width: 480, height: 854, deviceScaleFactor: 1, userAgent: "Mozilla/5.0 (Linux; U; Android 2.3; en-us; SonyEricssonST25i Build/6.0.B.1.564) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1", touch: true, mobile: true},
    342     {title: "Sony Xperia Z, Z1", width: 360, height: 640, deviceScaleFactor: 3, userAgent: "Mozilla/5.0 (Linux; U; Android 4.2; en-us; SonyC6903 Build/14.1.G.1.518) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30", touch: true, mobile: true}
    343 ];
    344 
    345 /** @type {!Array.<!WebInspector.OverridesSupport.Device>} */
    346 WebInspector.OverridesUI._tablets = [
    347     {title: "Amazon Kindle Fire HDX 7", width: 1920, height: 1200, deviceScaleFactor: 2, userAgent: "Mozilla/5.0 (Linux; U; en-us; KFTHWI Build/JDQ39) AppleWebKit/535.19 (KHTML, like Gecko) Silk/3.13 Safari/535.19 Silk-Accelerated=true", touch: true, mobile: true},
    348     {title: "Amazon Kindle Fire HDX 8.9", width: 2560, height: 1600, deviceScaleFactor: 2, userAgent: "Mozilla/5.0 (Linux; U; en-us; KFAPWI Build/JDQ39) AppleWebKit/535.19 (KHTML, like Gecko) Silk/3.13 Safari/535.19 Silk-Accelerated=true", touch: true, mobile: true},
    349     {title: "Amazon Kindle Fire (First Generation)", width: 1024, height: 600, deviceScaleFactor: 1, userAgent: "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_3; en-us; Silk/1.0.141.16-Gen4_11004310) AppleWebkit/533.16 (KHTML, like Gecko) Version/5.0 Safari/533.16 Silk-Accelerated=true", touch: true, mobile: true},
    350     {title: "Apple iPad 1 / 2 / iPad Mini", width: 1024, height: 768, deviceScaleFactor: 1, userAgent: "Mozilla/5.0 (iPad; CPU OS 4_3_5 like Mac OS X; en-us) AppleWebKit/533.17.9 (KHTML, like Gecko) Version/5.0.2 Mobile/8L1 Safari/6533.18.5", touch: true, mobile: true},
    351     {title: "Apple iPad 3 / 4", width: 1024, height: 768, deviceScaleFactor: 2, userAgent: "Mozilla/5.0 (iPad; CPU OS 7_0 like Mac OS X) AppleWebKit/537.51.1 (KHTML, like Gecko) Version/7.0 Mobile/11A465 Safari/9537.53", touch: true, mobile: true},
    352     {title: "BlackBerry PlayBook", width: 1024, height: 600, deviceScaleFactor: 1, userAgent: "Mozilla/5.0 (PlayBook; U; RIM Tablet OS 2.1.0; en-US) AppleWebKit/536.2+ (KHTML like Gecko) Version/7.2.1.0 Safari/536.2+", touch: true, mobile: true},
    353     {title: "Google Nexus 10", width: 1280, height: 800, deviceScaleFactor: 2, userAgent: "Mozilla/5.0 (Linux; Android 4.3; Nexus 10 Build/JSS15Q) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/29.0.1547.72 Safari/537.36", touch: true, mobile: true},
    354     {title: "Google Nexus 7 2", width: 960, height: 600, deviceScaleFactor: 2, userAgent: "Mozilla/5.0 (Linux; Android 4.3; Nexus 7 Build/JSS15Q) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/29.0.1547.72 Safari/537.36", touch: true, mobile: true},
    355     {title: "Google Nexus 7", width: 966, height: 604, deviceScaleFactor: 1.325, userAgent: "Mozilla/5.0 (Linux; Android 4.3; Nexus 7 Build/JSS15Q) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/29.0.1547.72 Safari/537.36", touch: true, mobile: true},
    356     {title: "Motorola Xoom, Xyboard", width: 1280, height: 800, deviceScaleFactor: 1, userAgent: "Mozilla/5.0 (Linux; U; Android 3.0; en-us; Xoom Build/HRI39) AppleWebKit/525.10 (KHTML, like Gecko) Version/3.0.4 Mobile Safari/523.12.2", touch: true, mobile: true},
    357     {title: "Samsung Galaxy Tab 7.7, 8.9, 10.1", width: 1280, height: 800, deviceScaleFactor: 1, userAgent: "Mozilla/5.0 (Linux; U; Android 2.2; en-us; SCH-I800 Build/FROYO) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1", touch: true, mobile: true},
    358     {title: "Samsung Galaxy Tab", width: 1024, height: 600, deviceScaleFactor: 1, userAgent: "Mozilla/5.0 (Linux; U; Android 2.2; en-us; SCH-I800 Build/FROYO) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1", touch: true, mobile: true}
    359 ];
    360 
    361 /** @type {!Array.<!WebInspector.OverridesSupport.Device>} */
    362 WebInspector.OverridesUI._notebooks = [
    363     {title: "Notebook with touch", width: 1280, height: 950, deviceScaleFactor: 1, userAgent: "", touch: true, mobile: false},
    364     {title: "Notebook with HiDPI screen", width: 1440, height: 900, deviceScaleFactor: 2, userAgent: "", touch: false, mobile: false},
    365     {title: "Generic notebook", width: 1280, height: 800, deviceScaleFactor: 1, userAgent: "", touch: false, mobile: false}
    366 ];
    367 
    368 /** @type {!Array.<!WebInspector.OverridesSupport.NetworkConditionsPreset>} */
    369 WebInspector.OverridesUI._networkConditionsPresets = [
    370     {id: "offline", title: "Offline", throughput: 0, latency: 0},
    371     {id: "gprs", title: "GPRS", throughput: 50, latency: 500},
    372     {id: "edge", title: "EDGE", throughput: 250, latency: 300},
    373     {id: "3g", title: "3G", throughput: 750, latency: 100},
    374     {id: "dsl", title: "DSL", throughput: 2 * 1024, latency: 5},
    375     {id: "wifi", title: "WiFi", throughput: 30 * 1024, latency: 2},
    376     {id: "online", title: "No throttling", throughput: WebInspector.OverridesSupport.NetworkThroughputUnlimitedValue, latency: 0}
    377 ];
    378 
    379 /** @type {!Array.<{title: string, value: string}>} */
    380 WebInspector.OverridesUI._userAgents = [
    381     {title: "Android 4.0.2 \u2014 Galaxy Nexus", value: "Mozilla/5.0 (Linux; U; Android 4.0.2; en-us; Galaxy Nexus Build/ICL53F) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30"},
    382     {title: "Android 2.3 \u2014 Nexus S", value: "Mozilla/5.0 (Linux; U; Android 2.3.6; en-us; Nexus S Build/GRK39F) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1"},
    383     {title: "BlackBerry \u2014 BB10", value: "Mozilla/5.0 (BB10; Touch) AppleWebKit/537.1+ (KHTML, like Gecko) Version/10.0.0.1337 Mobile Safari/537.1+"},
    384     {title: "BlackBerry \u2014 PlayBook 2.1", value: "Mozilla/5.0 (PlayBook; U; RIM Tablet OS 2.1.0; en-US) AppleWebKit/536.2+ (KHTML, like Gecko) Version/7.2.1.0 Safari/536.2+"},
    385     {title: "BlackBerry \u2014 9900", value: "Mozilla/5.0 (BlackBerry; U; BlackBerry 9900; en-US) AppleWebKit/534.11+ (KHTML, like Gecko) Version/7.0.0.187 Mobile Safari/534.11+"},
    386     {title: "Chrome 31 \u2014 Mac", value: "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.63 Safari/537.36"},
    387     {title: "Chrome 31 \u2014 Windows", value: "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.16 Safari/537.36"},
    388     {title: "Chrome \u2014 Android Tablet", value: "Mozilla/5.0 (Linux; Android 4.1.2; Nexus 7 Build/JZ054K) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.166 Safari/535.19"},
    389     {title: "Chrome \u2014 Android Mobile", value: "Mozilla/5.0 (Linux; Android 4.0.4; Galaxy Nexus Build/IMM76B) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.133 Mobile Safari/535.19"},
    390     {title: "Chrome \u2014 iPad", value: "Mozilla/5.0 (iPad; CPU OS 7_0 like Mac OS X) AppleWebKit/537.51.1 (KHTML, like Gecko) CriOS/30.0.1599.12 Mobile/11A465 Safari/8536.25"},
    391     {title: "Chrome \u2014 iPhone", value: "Mozilla/5.0 (iPhone; CPU iPhone OS 7_0_2 like Mac OS X) AppleWebKit/537.51.1 (KHTML, like Gecko) CriOS/30.0.1599.12 Mobile/11A501 Safari/8536.25"},
    392     {title: "Firefox 14 \u2014 Android Mobile", value: "Mozilla/5.0 (Android; Mobile; rv:14.0) Gecko/14.0 Firefox/14.0"},
    393     {title: "Firefox 14 \u2014 Android Tablet", value: "Mozilla/5.0 (Android; Tablet; rv:14.0) Gecko/14.0 Firefox/14.0"},
    394     {title: "Firefox 4 \u2014 Mac", value: "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:2.0.1) Gecko/20100101 Firefox/4.0.1"},
    395     {title: "Firefox 4 \u2014 Windows", value: "Mozilla/5.0 (Windows NT 6.1; rv:2.0.1) Gecko/20100101 Firefox/4.0.1"},
    396     {title: "Firefox 7 \u2014 Mac", value: "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:7.0.1) Gecko/20100101 Firefox/7.0.1"},
    397     {title: "Firefox 7 \u2014 Windows", value: "Mozilla/5.0 (Windows NT 6.1; Intel Mac OS X 10.6; rv:7.0.1) Gecko/20100101 Firefox/7.0.1"},
    398     {title: "Internet Explorer 10", value: "Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; Trident/6.0)"},
    399     {title: "Internet Explorer 7", value: "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0)"},
    400     {title: "Internet Explorer 8", value: "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.0; Trident/4.0)"},
    401     {title: "Internet Explorer 9", value: "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0)"},
    402     {title: "iPad \u2014 iOS 8", value: "Mozilla/5.0 (iPad; CPU OS 8_0 like Mac OS X) AppleWebKit/600.1.3 (KHTML, like Gecko) Version/8.0 Mobile/12A4345d Safari/600.1.4"},
    403     {title: "iPad \u2014 iOS 7", value: "Mozilla/5.0 (iPad; CPU OS 7_0_2 like Mac OS X) AppleWebKit/537.51.1 (KHTML, like Gecko) Version/7.0 Mobile/11A501 Safari/9537.53"},
    404     {title: "iPad \u2014 iOS 6", value: "Mozilla/5.0 (iPad; CPU OS 6_0 like Mac OS X) AppleWebKit/536.26 (KHTML, like Gecko) Version/6.0 Mobile/10A5376e Safari/8536.25"},
    405     {title: "iPhone \u2014 iOS 8", value: "Mozilla/5.0 (iPhone; CPU iPhone OS 8_0 like Mac OS X) AppleWebKit/600.1.3 (KHTML, like Gecko) Version/8.0 Mobile/12A4345d Safari/600.1.4"},
    406     {title: "iPhone \u2014 iOS 7", value: "Mozilla/5.0 (iPhone; CPU iPhone OS 7_0_2 like Mac OS X) AppleWebKit/537.51.1 (KHTML, like Gecko) Version/7.0 Mobile/11A4449d Safari/9537.53"},
    407     {title: "iPhone \u2014 iOS 6", value: "Mozilla/5.0 (iPhone; CPU iPhone OS 6_0 like Mac OS X) AppleWebKit/536.26 (KHTML, like Gecko) Version/6.0 Mobile/10A5376e Safari/8536.25"},
    408     {title: "MeeGo \u2014 Nokia N9", value: "Mozilla/5.0 (MeeGo; NokiaN9) AppleWebKit/534.13 (KHTML, like Gecko) NokiaBrowser/8.5.0 Mobile Safari/534.13"},
    409     {title: "Opera 18 \u2014 Mac", value: "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.63 Safari/537.36 OPR/18.0.1284.68"},
    410     {title: "Opera 18 \u2014 Windows", value: "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.63 Safari/537.36 OPR/18.0.1284.68"},
    411     {title: "Opera 12 \u2014 Mac", value: "Opera/9.80 (Macintosh; Intel Mac OS X 10.9.1) Presto/2.12.388 Version/12.16"},
    412     {title: "Opera 12 \u2014 Windows", value: "Opera/9.80 (Windows NT 6.1) Presto/2.12.388 Version/12.16"},
    413     {title: "Silk \u2014 Kindle Fire (Desktop view)", value: "Mozilla/5.0 (Linux; U; en-us; KFTHWI Build/JDQ39) AppleWebKit/535.19 (KHTML, like Gecko) Silk/3.13 Safari/535.19 Silk-Accelerated=true"},
    414     {title: "Silk \u2014 Kindle Fire (Mobile view)", value: "Mozilla/5.0 (Linux; U; Android 4.2.2; en-us; KFTHWI Build/JDQ39) AppleWebKit/535.19 (KHTML, like Gecko) Silk/3.13 Mobile Safari/535.19 Silk-Accelerated=true"}
    415 ];