extensions_ui.html revision ddb351dbec246cf1fab5ec20d2d5520909041de1
1<!DOCTYPE HTML>
2<html i18n-values="dir:textdirection;">
3<head>
4<meta charset="utf-8">
5<title i18n-content="title"></title>
6<style>
7body {
8  margin: 10px;
9  min-width: 47em;
10}
11
12a {
13  color: blue;
14  font-size: 103%;
15}
16
17div#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
38html[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
44h1 {
45  font-size: 156%;
46  font-weight: bold;
47  padding: 0;
48  margin: 0;
49}
50
51div.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
85body.hideDevModeInitial .showInDevMode {
86  height: 0 !important;
87  opacity: 0;
88}
89
90body.hideDevMode .showInDevMode {
91  height: 0 !important;
92  opacity: 0;
93  -webkit-transition: all .1s ease-out;
94}
95
96body.showDevModeInitial .showInDevMode {
97  opacity: 1;
98}
99
100body.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
170html[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
201html[dir=rtl] .extension-views {
202  margin: 0 2ex 0 0;
203}
204
205button {
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
239html[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
259html[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
270html[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 */
326var 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.
387var 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 */
393function 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 */
404function 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 */
428function requestExtensionsData() {
429  chrome.send('requestExtensionsData', []);
430}
431
432// Used for observing function of the backend datasource for this page by
433// tests.
434var webui_responded_ = false;
435
436// Used to only do some work the first time we render.
437var 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 */
443function 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 */
507function 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 */
519function 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 */
527function 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 */
536function 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 */
563function handleToggleAllowFileAccess(node) {
564  chrome.send('allowFileAccess', [node.extensionId, String(node.checked)]);
565}
566
567/**
568 * Handles an 'uninstall' link getting clicked.
569 */
570function handleUninstallExtension(node) {
571  chrome.send('uninstall', [node.extensionId]);
572}
573
574/**
575 * Handles an 'options' link getting clicked.
576 */
577function handleOptions(node) {
578  chrome.send('options', [node.extensionId]);
579}
580
581/**
582* Handles a 'show button' link getting clicked.
583*/
584function 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*/
595function 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 */
607function 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 */
616function 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 */
625function showPackDialog() {
626  document.getElementById('dialogBackground').style.display = '-webkit-box';
627}
628
629/**
630 * Hides the pack dialog.
631 */
632function hidePackDialog() {
633  document.getElementById('dialogBackground').style.display = 'none'
634}
635
636/*
637 * Toggles visibility of the developer mode.
638 */
639function 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 */
654function 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 */
663function 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 */
672function autoUpdate() {
673  chrome.send('autoupdate', []);
674}
675
676document.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