Home | History | Annotate | Download | only in resources
      1 <!DOCTYPE HTML>
      2 <html i18n-values="dir:textdirection;">
      3 <head>
      4 <meta charset="utf-8">
      5 <title i18n-content="title"></title>
      6 <style>
      7 body {
      8   margin: 10px;
      9   min-width: 47em;
     10 }
     11 
     12 a {
     13   color: blue;
     14   font-size: 103%;
     15 }
     16 
     17 div#header {
     18   margin-bottom: 1.05em;
     19   /* 67px is the height of the header's background image. */
     20   min-height: 67px;
     21   overflow: hidden;
     22   padding-bottom: 20px;
     23   -webkit-padding-start: 0;
     24   padding-top: 20px;
     25   position: relative;
     26   box-sizing: border-box;
     27 }
     28 
     29 #header h1 {
     30   background: url('../../app/theme/extensions_section.png') 0px 20px no-repeat;
     31   display: inline;
     32   margin: 0;
     33   padding-bottom: 43px;
     34   padding-left: 75px;
     35   padding-top: 40px;
     36 }
     37 
     38 html[dir=rtl] #header h1 {
     39   background: url('../../app/theme/extensions_section.png') right no-repeat;
     40   padding-right: 95px;
     41   padding-left: 0;
     42 }
     43 
     44 h1 {
     45   font-size: 156%;
     46   font-weight: bold;
     47   padding: 0;
     48   margin: 0;
     49 }
     50 
     51 div.content {
     52   font-size: 88%;
     53   margin-top: 5px;
     54 }
     55 
     56 .section-header {
     57   background: #ebeff9;
     58   border-top: 1px solid #b5c7de;
     59   font-size: 99%;
     60   padding-bottom: 2px;
     61   -webkit-padding-start: 5px;
     62   padding-top: 3px;
     63   width: 100%;
     64 }
     65 
     66 .section-header-title {
     67   font-weight: bold;
     68 }
     69 
     70 .vbox-container {
     71   display: -webkit-box;
     72   -webkit-box-orient: vertical;
     73 }
     74 
     75 .wbox {
     76   display: -webkit-box;
     77   -webkit-box-align: stretch;
     78   -webkit-box-flex: 1;
     79 }
     80 
     81 .showInDevMode {
     82   overflow: hidden;
     83 }
     84 
     85 body.hideDevModeInitial .showInDevMode {
     86   height: 0 !important;
     87   opacity: 0;
     88 }
     89 
     90 body.hideDevMode .showInDevMode {
     91   height: 0 !important;
     92   opacity: 0;
     93   -webkit-transition: all .1s ease-out;
     94 }
     95 
     96 body.showDevModeInitial .showInDevMode {
     97   opacity: 1;
     98 }
     99 
    100 body.showDevMode .showInDevMode {
    101   opacity: 1;
    102   -webkit-transition: all .1s ease-in;
    103 }
    104 
    105 .wbox-dev-mode {
    106   -webkit-box-align: stretch;
    107   -webkit-box-flex: 1;
    108 }
    109 
    110 .developer-mode-image {
    111   margin-top: 2px;
    112 }
    113 
    114 .developer-mode-link {
    115   margin-right: 3px;
    116   white-space: nowrap;
    117 }
    118 
    119 .developer-mode-link a {
    120   font-size: 97%;
    121 }
    122 
    123 .developer-mode {
    124   background: #f4f6fc;
    125   border-bottom: 1px solid #edeff5;
    126   font-size: 89%;
    127   padding-bottom: 0.8em;
    128   -webkit-padding-start: 10px;
    129   padding-top: 0.8em;
    130   width: 100%;
    131 }
    132 
    133 .extension_disabled td {
    134   background-color: #f0f0f0;
    135   color: #a0a0a0;
    136   padding-bottom: 4px;
    137   padding-top: 5px;
    138 }
    139 
    140 .extension_enabled td {
    141   padding-bottom: 4px;
    142   padding-top: 5px;
    143 }
    144 
    145 .extension {
    146   border-bottom: 1px solid #cdcdcd;
    147 }
    148 
    149 .extension-name {
    150   font-weight: bold;
    151 }
    152 
    153 .no-extensions {
    154   margin: 6em 0 0;
    155   text-align: center;
    156   font-size: 1.2em;
    157 }
    158 
    159 #try-gallery {
    160   margin-top: 1em;
    161   font-weight: normal;
    162 }
    163 
    164 #get-moar-extensions {
    165   margin-top: 1em;
    166   text-align: right;
    167   font-weight: bold;
    168 }
    169 
    170 html[dir=rtl] #get-moar-extensions {
    171    text-align: left;
    172 }
    173 
    174 .extension-description {
    175   margin-top: 0.4em;
    176 }
    177 
    178 .extension-details {
    179   margin-top: 0.5em;
    180 }
    181 
    182 .extension-actions {
    183 }
    184 
    185 .extension-actions-div {
    186   margin-top: 0.4em;
    187 }
    188 
    189 .extension-actions input {
    190   margin: 0 3px 0 10px;
    191   vertical-align: text-bottom;
    192 }
    193 
    194 .extension-views {
    195   margin: 0 0 0;
    196   margin-left: 2ex;
    197   padding: 0;
    198   list-style-type: none;
    199 }
    200 
    201 html[dir=rtl] .extension-views {
    202   margin: 0 2ex 0 0;
    203 }
    204 
    205 button {
    206   font-size: 104%;
    207 }
    208 
    209 #dialogBackground, #dialogBackground div {
    210   display: -webkit-box;
    211   -webkit-box-align: center;
    212 }
    213 
    214 #dialog input[type=button] {
    215   font-size: 12px;
    216   height: 25px;
    217   width: 100px;
    218 }
    219 
    220 #dialog input[type=text] {
    221   font-size: 12px;
    222   font-family: Helvetica, Arial, sans-serif;
    223   width: 220px;
    224 }
    225 
    226 #dialogBackground {
    227   background-color: rgba(0, 0, 0, .2);
    228   display: none;
    229   height: 100%;
    230   left: 0;
    231   position: fixed;
    232   top: 0;
    233   width: 100%;
    234   z-index: 1;
    235   -webkit-box-orient: vertical;
    236   -webkit-user-select: none;
    237 }
    238 
    239 html[dir=rtl] #dialogBackground {
    240   right: 0;
    241   left: auto;
    242 }
    243 
    244 #dialogHBackground {
    245   height: 100%;
    246   -webkit-box-orient: horizontal;
    247 }
    248 
    249 
    250 #dialog {
    251   background-color: #5296DE;
    252   border: 1px solid #3A75BD;
    253   border-radius: 6px 6px;
    254   font-size: 12px;
    255   width: 520px;
    256   -webkit-box-orient: vertical;
    257 }
    258 
    259 html[dir=rtl] #dialog {
    260   font-size: 13px;
    261 }
    262 
    263 #dialogHeader {
    264   background-color: rgba(0,0,0,0);
    265   color: white;
    266   margin: 4px;
    267   width: 100%;
    268 }
    269 
    270 html[dir=rtl] #dialogHeader {
    271   margin-left: -20px;
    272 }
    273 
    274 #dialogBody {
    275   background-color: rgb(240, 240, 240);
    276   border: 1px solid #3A75BD;
    277   border-bottom-left-radius: 4px 4px;
    278   border-bottom-right-radius: 4px 4px;
    279   margin: 0px 2px 2px 2px;
    280   -webkit-box-orient: vertical;
    281 }
    282 
    283 #dialogContentHeader {
    284   margin: 16px;
    285 }
    286 
    287 .dialogBrowseRow {
    288   -webkit-margin-start: -24px;
    289   width: 100%;
    290   -webkit-box-orient: horizontal;
    291   -webkit-box-pack: end;
    292 }
    293 
    294 .dialogBrowseRow>* {
    295   margin: 2px
    296 }
    297 
    298 #dialogContentFooter {
    299   margin-bottom: 6px;
    300   -webkit-margin-start: -12px;
    301   margin-top: 20px;
    302 }
    303 
    304 .inspectPopupNote {
    305   color: grey;
    306 }
    307 
    308 .incognitoWarning {
    309   margin: 0.75em 0;
    310   display: none;
    311   opacity: 0;
    312   -webkit-transition: opacity .2s ease-out;
    313 }
    314 
    315 .incognitoWarning .yellow {
    316   background:#fff299;
    317   padding:2px 5px;
    318   border-radius:3px;
    319 }
    320 </style>
    321 <script>
    322 /**
    323  * This variable structure is here to document the structure that the template
    324  * expects to correctly populate the page.
    325  */
    326 var extensionDataFormat = {
    327   'developerMode': false,
    328   'extensions': [
    329     {
    330       'id': '0000000000000000000000000000000000000000',
    331       'name': 'Google Chrome',
    332       'description': 'Extension long format description',
    333       'version': '1.0.231',
    334       'mayDisable': 'true',
    335       'enabled': 'true',
    336       'terminated': 'false',
    337       'enabledIncognito': 'false',
    338       'wantsFileAccess': 'false',
    339       'allowFileAccess': 'false',
    340       'allow_reload': true,
    341       'is_hosted_app': false,
    342       'order': 1,
    343       'options_url': 'options.html',
    344       'enable_show_button': false,
    345       'icon': 'relative-path-to-icon.png',
    346       // TODO(aa): It would be nice to also render what type of view each one
    347       // is, like 'toolstrip', 'background', etc. Eventually, if we can also
    348       // debug and inspect content scripts, maybe we don't need to list the
    349       // components, just the views.
    350       'views': [
    351         {
    352           'path': 'toolstrip.html',
    353           'renderViewId': 1,
    354           'renderProcessId': 1,
    355           'incognito': false
    356         },
    357         {
    358           'path': 'background.html',
    359           'renderViewId': 2,
    360           'renderProcessId': 1,
    361           'incognito': false
    362         }
    363       ]
    364     },
    365     {
    366       'id': '0000000000000000000000000000000000000001',
    367       'name': 'RSS Subscriber',
    368       'description': 'Extension long format description',
    369       'version': '1.0.231',
    370       'mayDisable': 'true',
    371       'enabled': 'true',
    372       'terminated': 'false',
    373       'enabledIncognito': 'false',
    374       'wantsFileAccess': 'false',
    375       'allowFileAccess': 'false',
    376       'allow_reload': false,
    377       'is_hosted_app': false,
    378       'order': 2,
    379       'icon': '',
    380       "hasPopupAction": false
    381     }
    382   ]
    383 };
    384 
    385 // Keeps track of whether the developer mode subsection has been made visible
    386 // (expanded) or not.
    387 var devModeExpanded = false;
    388 
    389 /**
    390  * Toggles the devModeExpanded, and notifies the c++ WebUI to toggle the
    391  * extensions.ui.developer_mode which saved in the preferences.
    392  */
    393 function toggleDevModeExpanded() {
    394   devModeExpanded = !devModeExpanded;
    395   chrome.send('toggleDeveloperMode', []);
    396 }
    397 
    398 /**
    399  * Takes the |extensionsData| input argument which represents data about the
    400  * currently installed/running extensions and populates the html jstemplate with
    401  * that data. It expects an object structure like the above.
    402  * @param {Object} extensionsData Detailed info about installed extensions
    403  */
    404 function renderTemplate(extensionsData) {
    405   // Sort by order specified in the data or (if equal) then sort by
    406   // extension name (case-insensitive).
    407   extensionsData.extensions.sort(function(a, b) {
    408     if (a.order == b.order) {
    409       a = a.name.toLowerCase();
    410       b = b.name.toLowerCase();
    411       return a < b ? -1 : (a > b ? 1 : 0);
    412     } else {
    413       return a.order < b.order ? -1 : 1;
    414     }
    415   });
    416 
    417   // This is the javascript code that processes the template:
    418   var input = new JsEvalContext(extensionsData);
    419   var output = document.getElementById('extensionTemplate');
    420   jstProcess(input, output);
    421 }
    422 
    423 /**
    424  * Asks the C++ ExtensionDOMHandler to get details about the installed
    425  * extensions and return detailed data about the configuration. The
    426  * ExtensionDOMHandler should reply to returnExtensionsData() (below).
    427  */
    428 function requestExtensionsData() {
    429   chrome.send('requestExtensionsData', []);
    430 }
    431 
    432 // Used for observing function of the backend datasource for this page by
    433 // tests.
    434 var webui_responded_ = false;
    435 
    436 // Used to only do some work the first time we render.
    437 var rendered_once_ = false;
    438 
    439 /**
    440  * Called by the web_ui_ to re-populate the page with data representing
    441  * the current state of installed extensions.
    442  */
    443 function returnExtensionsData(extensionsData){
    444   webui_responded_ = true;
    445   devModeExpanded = extensionsData.developerMode;
    446 
    447   var bodyContainer = document.getElementById('body-container');
    448   var body = document.body;
    449 
    450   // Set all page content to be visible so we can measure heights.
    451   bodyContainer.style.visibility = 'hidden';
    452   body.className = '';
    453   var slidables = document.getElementsByClassName('showInDevMode');
    454   for (var i = 0; i < slidables.length; i++)
    455     slidables[i].style.height = 'auto';
    456 
    457   renderTemplate(extensionsData);
    458 
    459   // Explicitly set the height for each element that wants to be 'slid' in and
    460   // out when the devModeExpanded is toggled.
    461   var slidables = document.getElementsByClassName('showInDevMode');
    462   for (var i = 0; i < slidables.length; i++)
    463     slidables[i].style.height = slidables[i].offsetHeight + 'px';
    464 
    465   // Hide all the incognito warnings that are attached to the wrong extension
    466   // ID, which can happen when an extension is added or removed.
    467   var warnings = document.getElementsByClassName('incognitoWarning');
    468   for (var i = 0; i < warnings.length; i++) {
    469     var extension = warnings[i];
    470     while (extension.className != "extension")
    471       extension = extension.parentNode;
    472 
    473     if (extension.extensionId != warnings[i].attachedExtensionId) {
    474       warnings[i].style.display = "none";
    475       warnings[i].style.opacity = "0";
    476     }
    477   }
    478 
    479   // Reset visibility of page based on the current dev mode.
    480   document.getElementById('collapse').style.display =
    481      devModeExpanded ? 'inline' : 'none';
    482   document.getElementById('expand').style.display =
    483      devModeExpanded ? 'none' : 'inline';
    484   bodyContainer.style.visibility = 'visible';
    485   body.className = devModeExpanded ?
    486      'showDevModeInitial' : 'hideDevModeInitial';
    487 
    488   if (rendered_once_)
    489     return;
    490 
    491   // Blech, JSTemplate always inserts the strings as text, which is usually a
    492   // feature, but in this case it contains HTML that we want to be rendered.
    493   var elm = document.getElementById('try-gallery');
    494   if (elm)
    495     elm.innerHTML = elm.textContent;
    496 
    497   elm = document.getElementById('get-moar-extensions');
    498   if (elm)
    499     elm.innerHTML = elm.textContent;
    500 
    501   rendered_once_ = true;
    502 }
    503 
    504 /**
    505  * Tell the C++ ExtensionDOMHandler to inspect the page detailed in |viewData|.
    506  */
    507 function sendInspectMessage(viewData) {
    508   // TODO(aa): This is ghetto, but WebUIBindings doesn't support sending
    509   // anything other than arrays of strings, and this is all going to get
    510   // replaced with V8 extensions soon anyway.
    511   chrome.send('inspect', [
    512     String(viewData.renderProcessId), String(viewData.renderViewId)
    513   ]);
    514 }
    515 
    516 /**
    517  * Handles a 'reload' link getting clicked.
    518  */
    519 function handleReloadExtension(node) {
    520   // Tell the C++ ExtensionDOMHandler to reload the extension.
    521   chrome.send('reload', [node.extensionId]);
    522 }
    523 
    524 /**
    525  * Handles a 'enable' or 'disable' link getting clicked.
    526  */
    527 function handleEnableExtension(node, enable) {
    528   // Tell the C++ ExtensionDOMHandler to reload the extension.
    529   chrome.send('enable', [node.extensionId, String(enable)]);
    530   requestExtensionsData();
    531 }
    532 
    533 /**
    534  * Handles the 'enableIncognito' checkbox getting changed.
    535  */
    536 function handleToggleExtensionIncognito(node) {
    537   var warning = node;
    538 
    539   while (warning.className != "extension")
    540     warning = warning.parentNode;
    541 
    542   warning = warning.getElementsByClassName("incognitoWarning")[0];
    543   if (!node.checked) {
    544     warning.style.display = "none";
    545     warning.style.opacity = "0";
    546   } else {
    547     warning.attachedExtensionId = node.extensionId;
    548     warning.style.display = "block";
    549 
    550     // Must set the opacity later. Otherwise, the fact that the display is
    551     // changing causes the animation to not happen.
    552     window.setTimeout(function() {
    553       warning.style.opacity = "1";
    554     }, 0);
    555   }
    556 
    557   chrome.send('enableIncognito', [node.extensionId, String(node.checked)]);
    558 }
    559 
    560 /**
    561  * Handles the 'allowFileAccess' checkbox getting changed.
    562  */
    563 function handleToggleAllowFileAccess(node) {
    564   chrome.send('allowFileAccess', [node.extensionId, String(node.checked)]);
    565 }
    566 
    567 /**
    568  * Handles an 'uninstall' link getting clicked.
    569  */
    570 function handleUninstallExtension(node) {
    571   chrome.send('uninstall', [node.extensionId]);
    572 }
    573 
    574 /**
    575  * Handles an 'options' link getting clicked.
    576  */
    577 function handleOptions(node) {
    578   chrome.send('options', [node.extensionId]);
    579 }
    580 
    581 /**
    582 * Handles a 'show button' link getting clicked.
    583 */
    584 function handleShowButton(node) {
    585   chrome.send('showButton', [node.extensionId]);
    586 }
    587 
    588 /**
    589 * Utility function which asks the C++ to show a platform-specific file select
    590 * dialog, and fire |callback| with the |filePath| that resulted. |selectType|
    591 * can be either 'file' or 'folder'. |operation| can be 'load', 'packRoot',
    592 * or 'pem' which are signals to the C++ to do some operation-specific
    593 * configuration.
    594 */
    595 function showFileDialog(selectType, operation, callback) {
    596   handleFilePathSelected = function(filePath) {
    597     callback(filePath);
    598     handleFilePathSelected = function() {};
    599   };
    600 
    601   chrome.send('selectFilePath', [selectType, operation]);
    602 }
    603 
    604 /**
    605  * Handles the "Load extension..." button being pressed.
    606  */
    607 function loadExtension() {
    608   showFileDialog('folder', 'load', function(filePath) {
    609     chrome.send('load', [String(filePath)]);
    610   });
    611 }
    612 
    613 /**
    614  * Handles the "Pack extension..." button being pressed.
    615  */
    616 function packExtension() {
    617   var extensionPath = document.getElementById('extensionPathText').value;
    618   var privateKeyPath = document.getElementById('privateKeyPath').value;
    619   chrome.send('pack', [extensionPath, privateKeyPath]);
    620 }
    621 
    622 /**
    623  * Shows to modal HTML pack dialog.
    624  */
    625 function showPackDialog() {
    626   document.getElementById('dialogBackground').style.display = '-webkit-box';
    627 }
    628 
    629 /**
    630  * Hides the pack dialog.
    631  */
    632 function hidePackDialog() {
    633   document.getElementById('dialogBackground').style.display = 'none'
    634 }
    635 
    636 /*
    637  * Toggles visibility of the developer mode.
    638  */
    639 function toggleDeveloperMode() {
    640   toggleDevModeExpanded();
    641 
    642   document.getElementById('collapse').style.display =
    643       devModeExpanded ? 'inline' : 'none';
    644   document.getElementById('expand').style.display =
    645       devModeExpanded ? 'none' : 'inline';
    646 
    647   document.body.className =
    648       devModeExpanded ? 'showDevMode' : 'hideDevMode';
    649 }
    650 
    651 /**
    652  * Pop up a select dialog to capture the extension path.
    653  */
    654 function selectExtensionPath() {
    655   showFileDialog('folder', 'packRoot', function(filePath) {
    656     document.getElementById('extensionPathText').value = filePath;
    657   });
    658 }
    659 
    660 /**
    661  * Pop up a select dialog to capture the private key path.
    662  */
    663 function selectPrivateKeyPath() {
    664   showFileDialog('file', 'pem', function(filePath) {
    665     document.getElementById('privateKeyPath').value = filePath;
    666   });
    667 }
    668 
    669 /**
    670  * Handles the "Update extensions now" button being pressed.
    671  */
    672 function autoUpdate() {
    673   chrome.send('autoupdate', []);
    674 }
    675 
    676 document.addEventListener('DOMContentLoaded', requestExtensionsData);
    677 
    678 </script>
    679 </head>
    680 <body i18n-values=".style.fontFamily:fontfamily;.style.fontSize:fontsize">
    681   <div id="dialogBackground">
    682     <div id="dialogHBackground">
    683       <div id="dialog">
    684         <div id="dialogHeader" i18n-content="packDialogTitle">
    685           PACK EXTENSION
    686         </div>
    687         <div id="dialogBody">
    688           <div id="dialogContentHeader" i18n-content="packDialogHeading">
    689             HEADING
    690           </div>
    691           <div class="dialogBrowseRow">
    692             <div i18n-content="rootDirectoryLabel">
    693               ROOT_DIR
    694             </div>
    695             <div>
    696               <input type="text" id="extensionPathText">
    697             </div>
    698             <div>
    699               <input type="button" value="BROWSE"
    700                      i18n-values="value:packDialogBrowse"
    701                      onclick="selectExtensionPath();">
    702             </div>
    703           </div>
    704           <div class="dialogBrowseRow">
    705             <div i18n-content="privateKeyLabel">
    706               PRIVATE_KEY
    707             </div>
    708             <div>
    709               <input type="text" id="privateKeyPath">
    710             </div>
    711             <div>
    712               <input type="button" value="BROWSE"
    713                      i18n-values="value:packDialogBrowse"
    714                      onclick="selectPrivateKeyPath();">
    715             </div>
    716           </div>
    717           <div class="dialogBrowseRow" id="dialogContentFooter">
    718             <div>
    719               <input type="button" value="OK"
    720                   i18n-values="value:okButton" onclick="packExtension();">
    721             </div>
    722             <div>
    723               <input type="button" value="CANCEL"
    724                   i18n-values="value:cancelButton" onclick="hidePackDialog();">
    725             </div>
    726           </div>
    727         </div>
    728       </div>
    729     </div>
    730   </div>
    731 
    732   <div id="body-container" style="visibility:hidden">
    733 
    734     <div id="header"><h1 i18n-content="title">TITLE</h1></div>
    735 
    736     <div id="extensionTemplate">
    737 
    738       <div id="container" class="vbox-container">
    739       <div id="top" class="wbox" style="padding-right: 5px">
    740 
    741         <div class="section-header">
    742           <table cellpadding="0" cellspacing="0" width="100%">
    743           <tr valign="center">
    744             <td>
    745               <span class="section-header-title" i18n-content="title"
    746                 >TITLE</span>
    747               <span class="section-header-title"
    748                     jsdisplay="extensions.length > 0">(<span
    749                     jscontent="extensions.length"></span>)</span>
    750             </td>
    751             <td width="18" padding="">
    752               <img id="collapse" class="developer-mode-image"
    753                    style="display:none" onclick="toggleDeveloperMode();"
    754                    src="shared/images/minus.png">
    755               <img id="expand" class="developer-mode-image"
    756                    onclick="toggleDeveloperMode();" src="shared/images/plus.png">
    757             </td>
    758             <td width="50" align="right">
    759               <div class="developer-mode-link">
    760                 <a onclick="toggleDeveloperMode();" style="cursor: default"
    761                    i18n-content="devModeLink">DEVMODE</a>
    762               </div>
    763             </td>
    764           </tr>
    765           </table>
    766         </div>
    767 
    768       </div>
    769       <div id="developer_tools" class="wbox-dev-mode showInDevMode">
    770         <div class="developer-mode">
    771           <span i18n-content="devModePrefix">DEVELOPER_MODE:</span>
    772           <button onclick="loadExtension()"
    773                   i18n-content="loadUnpackedButton">LOAD</button>
    774           <button onclick="showPackDialog()"
    775                   i18n-content="packButton">PACK</button>
    776           <button onclick="autoUpdate()"
    777                   i18n-content="updateButton">UPDATE</button>
    778         </div>
    779       </div>
    780       </div>
    781 
    782       <div class="content">
    783         <div class="extension-name no-extensions" jsdisplay="extensions.length === 0">
    784           <div i18n-content="noExtensions">NO_EXTENSIONS_ARE_INSTALLED</div>
    785           <div i18n-content="suggestGallery" id="try-gallery">TRY_GALLERY</div>
    786         </div>
    787 
    788         <div jsdisplay="extensions.length > 0">
    789         <div class="extension" jsselect="extensions" jsvalues=".extensionId:id">
    790           <table width="100%" cellpadding="2" cellspacing="0">
    791           <tr jsvalues=".className:enabled ? 'extension_enabled' : 'extension_disabled'">
    792           <td width="62" height="50" align="center" valign="top">
    793             <span jsdisplay="icon"><img jsvalues=".src:icon" width="48"
    794                 height="48">
    795           </td>
    796           <td valign="top">
    797             <div>
    798               <a jsdisplay="homepageUrl.length > 0"
    799                  jsvalues=".href:homepageUrl">
    800               <span class="extension-name"
    801                     jscontent="name">EXTENSION NAME</span></a>
    802               <span class="extension-name"
    803                     jsdisplay="homepageUrl.length == 0"
    804                     jscontent="name">EXTENSION NAME</span>
    805               - <span i18n-content="extensionVersion">VERSION</span>
    806               <span jscontent="version">x.x.x.x</span>
    807               <span jsdisplay="!enabled && !terminated"
    808                     i18n-content="extensionDisabled">(DISABLED)</span>
    809               <span jsdisplay="terminated"
    810                     i18n-content="extensionCrashed">(CRASHED)</span>
    811               <span jsdisplay="isUnpacked"
    812                     i18n-content="inDevelopment">(IN DEVELOPMENT)</span>
    813             </div>
    814 
    815             <div class="extension-description" jscontent="description"></div>
    816             <div class="showInDevMode">
    817               <div class="extension-details">
    818                 <span i18n-content="extensionId">ID_LABEL: </span>
    819                 <span jscontent="id"></span>
    820               </div>
    821               <div class="extension-details" jsdisplay="path">
    822                 <span i18n-content="extensionPath">PATH_LABEL: </span>
    823                 <span jscontent="path"></span>
    824               </div>
    825               <div class="extension-details">
    826                 <span jsdisplay="views.length > 0 || hasPopupAction" i18n-content="inspectViews">
    827                   INSPECT ACTIVE VIEWS:
    828                 </span>
    829                 <ul class="extension-views">
    830                   <li jsselect="views">
    831                     <span jsvalues=".extensionView:$this">
    832                       <a jsvalues=".extensionView:$this" href="#"
    833                          onclick="sendInspectMessage(this.extensionView); return false;">
    834                         <span jscontent="path"></span></a>
    835                       <span jsdisplay="incognito"
    836                             i18n-content="viewIncognito">(INCOGNITO)</span>
    837                     </span>
    838                   </li>
    839                   <li i18n-content="inspectPopupsInstructions"
    840                       class="inspectPopupNote" jsdisplay="hasPopupAction">
    841                     INSPECT POPUP INSRUCTIONS
    842                   </li>
    843                 </ul>
    844               </div>
    845             </div>
    846             <div class="extension-actions-div">
    847               <span class="extension-actions">
    848                 <a
    849                   jsvalues=".extensionId:id"
    850                   jsdisplay="(enabled && allow_reload) || terminated"
    851                   onclick="handleReloadExtension(this)"
    852                   href="javascript:void 0;"
    853                   i18n-content="reload"
    854                   >RELOAD</a>
    855                 <span jsdisplay="enabled && allow_reload">-</span>
    856                 <a
    857                   jsvalues=".extensionId:id"
    858                   jsdisplay="enabled && mayDisable"
    859                   onclick="handleEnableExtension(this, false)"
    860                   href="javascript:void 0;"
    861                   i18n-content="disable"
    862                   >DISABLE</a>
    863                 <a
    864                   jsvalues=".extensionId:id"
    865                   jsdisplay="!enabled && !terminated"
    866                   onclick="handleEnableExtension(this, true)"
    867                   href="javascript:void 0;"
    868                   i18n-content="enable"
    869                   >ENABLE</a>
    870                 <span jsdisplay="mayDisable">-</span>
    871                 <a
    872                   jsvalues=".extensionId:id"
    873                   jsdisplay="mayDisable"
    874                   onclick="handleUninstallExtension(this)"
    875                   href="javascript:void 0;"
    876                   i18n-content="uninstall"
    877                   >UNINSTALL</a>
    878                 <span jsdisplay="options_url && enabled">-</span>
    879                 <a
    880                   jsdisplay="options_url && enabled"
    881                   jsvalues=".extensionId:id"
    882                   onclick="handleOptions(this)"
    883                   href="javascript:void 0;"
    884                   i18n-content="options"
    885                   >OPTIONS</a>
    886                 <span jsdisplay="enable_show_button && enabled">-</span>
    887                 <a
    888                   jsdisplay="enable_show_button && enabled"
    889                   jsvalues=".extensionId:id"
    890                   onclick="handleShowButton(this)"
    891                   href="javascript:void 0;"
    892                   i18n-content="showButton"
    893                   >SHOW_BUTTON</a>
    894                 <label jsdisplay="enabled && !is_hosted_app">
    895                 <input type="checkbox"
    896                   jsvalues=".extensionId:id;.enabled:enabled"
    897                   jsdisplay="enabled"
    898                   jseval="this.checked = enabledIncognito"
    899                   onchange="handleToggleExtensionIncognito(this)">
    900                 <span i18n-content="enableIncognito">ALLOW THIS EXTENSION TO RUN IN INCOGNITO</span></label>
    901                 <label jsdisplay="enabled && wantsFileAccess">
    902                 <input type="checkbox"
    903                   jsvalues=".extensionId:id;.enabled:enabled;.wantsFileAccess:wantsFileAccess"
    904                   jsdisplay="enabled && wantsFileAccess"
    905                   jseval="this.checked = allowFileAccess"
    906                   onchange="handleToggleAllowFileAccess(this)">
    907                 <span i18n-content="allowFileAccess">ALLOW THIS EXTENSION ACCESS TO FILE URLS</span></label>
    908                 <span jsdisplay="!mayDisable">-</span>
    909                 <span jsdisplay="!mayDisable"
    910                   i18n-content="policyControlled">THIS EXTENSION CAN NOT BE DISABLED OR UNINSTALLED BY USER</span>
    911               </span>
    912             </div>
    913             <div class="incognitoWarning">
    914               <span class="yellow" i18n-values=".innerHTML:incognitoWarning">WARNING - CHROME CANNOT PREVENT THIS EXTENSION FROM RECORDING YOUR BROWSING HISTORY</span>
    915             </div>
    916           </td>
    917           </tr>
    918           </table>
    919         </div>
    920         </div>
    921 
    922         <div id="get-moar-extensions" jsdisplay="extensions.length > 0"
    923             i18n-content="getMoreExtensions"></div>
    924       </div>
    925     </div>
    926   </div>
    927   </body>
    928 </html>
    929