<!DOCTYPE HTML> <html i18n-values="dir:textdirection;"> <head> <meta charset="utf-8"> <title i18n-content="pluginsTitle"></title> <style> body { margin: 10px; min-width: 47em; } a { color: blue; font-size: 103%; } div#header { margin-bottom: 1.05em; /* 67px is the height of the header's background image. */ min-height: 67px; overflow: hidden; padding-bottom: 20px; -webkit-padding-start: 0; padding-top: 20px; position: relative; box-sizing: border-box; } #header h1 { background: url('../../app/theme/extensions_section.png') 0px 20px no-repeat; display: inline; margin: 0; padding-bottom: 43px; padding-left: 75px; padding-top: 40px; } html[dir=rtl] #header h1 { background: url('../../app/theme/extensions_section.png') right no-repeat; padding-right: 95px; padding-left: 0; } h1 { font-size: 156%; font-weight: bold; padding: 0; margin: 0; } div.content { font-size: 88%; margin-top: 5px; } .section-header { background: #ebeff9; border-top: 1px solid #b5c7de; font-size: 99%; padding-bottom: 2px; -webkit-padding-start: 5px; padding-top: 3px; width: 100%; } .section-header > table tr td:first-child { width: 100%; } .section-header > table { width: 100%; } .section-header-title { font-weight: bold; } .vbox-container { display: -webkit-box; -webkit-box-orient: vertical; } .wbox { display: -webkit-box; -webkit-box-align: stretch; -webkit-box-flex: 1; } #top { -webkit-padding-end: 5px; } .showInTmiMode { overflow: hidden; } body.hideTmiModeInitial .showInTmiMode { height: 0 !important; opacity: 0; } body.hideTmiMode .showInTmiMode { height: 0 !important; opacity: 0; -webkit-transition: all .1s ease-out; } body.showTmiModeInitial .showInTmiMode { opacity: 1; } body.showTmiMode .showInTmiMode { opacity: 1; -webkit-transition: all .1s ease-in; } .wbox-tmi-mode { -webkit-box-align: stretch; -webkit-box-flex: 1; } .tmi-mode-image { margin-top: 2px; padding-left: 5px; padding-right: 5px; } .tmi-mode-link { margin-right: 3px; white-space: nowrap; } .tmi-mode-link a { font-size: 97%; } .tmi-mode { background: #f4f6fc; border-bottom: 1px solid #edeff5; font-size: 89%; padding-bottom: 0.8em; -webkit-padding-start: 10px; padding-top: 0.8em; width: 100%; } .plugin-disabled > td { background-color: #f0f0f0; color: #a0a0a0; padding-bottom: 4px; padding-top: 5px; } .plugin-enabled > td { padding-bottom: 4px; padding-top: 5px; } .plugin-file-disabled { background-color: #f0f0f0; color: #a0a0a0; padding-top: 5px; padding-bottom: 5px; } .plugin-file-enabled { padding-top: 5px; padding-bottom: 5px; } .plugin { border-bottom: 1px solid #cdcdcd; } .critical { color: red; } /* Indent the text related to each plug-in. */ .plugin-text { -webkit-padding-start: 5px; } .plugin-name { font-weight: bold; } .no-plugins { margin: 6em 0 0; text-align: center; font-size: 1.2em; } /* Use tables for layout, so eliminate extra spacing. */ .plugin-details table { -webkit-border-horizontal-spacing: 0; -webkit-border-vertical-spacing: 0; } .plugin-details { -webkit-padding-start: 1em; } /* Separate the inital line, Description, Location, and MIME Types lines. */ .plugin-details > div { padding-top: 0.1em } /* Align rows of tables along the top. */ .plugin-details tr { vertical-align: top; } /* Separate columns by 1em for the most part. */ .plugin-details td+td { -webkit-padding-start: 1em; } /* Make the MIME Types tables smaller. */ .plugin-details .mime-types { font-size: 95%; } /* Separate the header from the contents in each MIME Types table. */ .plugin-details .mime-types .header td { padding-bottom: 0.1em; border-bottom: 1px solid; } /* Separate the columns for tables used for horizontal listings only a bit. */ .hlisting td+td { -webkit-padding-start: 0.4em; } /* Match the indentation of .plugin-text. */ .plugin-actions { -webkit-padding-start: 5px; margin-top: 0.2em; margin-bottom: 0.2em; } button { font-size: 104%; } </style> <script> /** * This variable structure is here to document the structure that the template * expects to correctly populate the page. */ var pluginDataFormat = { 'plugins': [ { 'name': 'Group Name', 'description': 'description', 'version': 'version', 'update_url': 'http://update/', 'critical': true, 'enabled': true, 'plugin_files': [ { 'path': '/blahblah/blahblah/MyCrappyPlugin.plugin', 'name': 'MyCrappyPlugin', 'version': '1.2.3', 'description': 'My crappy plugin', 'mimeTypes': [ { 'description': 'Foo Media', 'fileExtensions': [ 'foo' ], 'mimeType': 'application/x-my-foo' }, { 'description': 'Bar Stuff', 'fileExtensions': [ 'bar','baz' ], 'mimeType': 'application/my-bar' } ], 'enabledMode': 'enabledByUser' }, { 'path': '/tmp/MyFirst.plugin', 'name': 'MyFirstPlugin', 'version': '3.14r15926', 'description': 'My first plugin', 'mimeTypes': [ { 'description': 'New Guy Media', 'fileExtensions': [ 'mfp' ], 'mimeType': 'application/x-my-first' } ], 'enabledMode': 'enabledByPolicy' }, { 'path': '/foobar/baz/YourGreatPlugin.plugin', 'name': 'YourGreatPlugin', 'version': '4.5', 'description': 'Your great plugin', 'mimeTypes': [ { 'description': 'Baz Stuff', 'fileExtensions': [ 'baz' ], 'mimeType': 'application/x-your-baz' } ], 'enabledMode': 'disabledByUser' }, { 'path': '/foobiz/bar/HisGreatPlugin.plugin', 'name': 'HisGreatPlugin', 'version': '1.2', 'description': 'His great plugin', 'mimeTypes': [ { 'description': 'More baz Stuff', 'fileExtensions': [ 'bor' ], 'mimeType': 'application/x-his-bor' } ], 'enabledMode': 'disabledByPolicy' } ] } ] }; /** * Takes the |pluginsData| input argument which represents data about the * currently installed/running plugins and populates the html jstemplate with * that data. It expects an object structure like the above. * @param {Object} pluginsData Detailed info about installed plugins */ function renderTemplate(pluginsData) { // This is the javascript code that processes the template: var input = new JsEvalContext(pluginsData); var output = document.getElementById('pluginTemplate'); jstProcess(input, output); } /** * Asks the C++ PluginsDOMHandler to get details about the installed plugins and * return detailed data about the configuration. The PluginsDOMHandler should * reply to returnPluginsData() (below). */ function requestPluginsData() { chrome.send('requestPluginsData', []); chrome.send('getShowDetails', []); } function loadShowDetailsFromPrefs(show_details) { tmiModeExpanded = show_details; document.getElementById('collapse').style.display = show_details ? 'inline' : 'none'; document.getElementById('expand').style.display = show_details ? 'none' : 'inline'; document.body.className = show_details ? 'showTmiMode' : 'hideTmiMode'; } /** * Asks the C++ PluginsDOMHandler to show the terms of service (about:terms). */ function showTermsOfService() { chrome.send('showTermsOfService', []); } /** * Called by the web_ui_ to re-populate the page with data representing the * current state of installed plugins. */ function returnPluginsData(pluginsData){ var bodyContainer = document.getElementById('body-container'); var body = document.body; // Set all page content to be visible so we can measure heights. bodyContainer.style.visibility = 'hidden'; body.className = ''; var slidables = document.getElementsByClassName('showInTmiMode'); for (var i = 0; i < slidables.length; i++) slidables[i].style.height = 'auto'; renderTemplate(pluginsData); // Make sure the left column (with "Description:", "Location:", etc.) is the // same size for all plugins. var labels = document.getElementsByClassName('plugin-details-label'); var maxLabelWidth = 0; for (var i = 0; i < labels.length; i++) labels[i].style.width = 'auto'; for (var i = 0; i < labels.length; i++) maxLabelWidth = Math.max(maxLabelWidth, labels[i].offsetWidth); for (var i = 0; i < labels.length; i++) labels[i].style.width = maxLabelWidth + 'px'; // Explicitly set the height for each element that wants to be "slid" in and // out when the tmiModeExpanded is toggled. var slidables = document.getElementsByClassName('showInTmiMode'); for (var i = 0; i < slidables.length; i++) slidables[i].style.height = slidables[i].offsetHeight + 'px'; // Reset visibility of page based on the current tmi mode. document.getElementById('collapse').style.display = tmiModeExpanded ? 'inline' : 'none'; document.getElementById('expand').style.display = tmiModeExpanded ? 'none' : 'inline'; bodyContainer.style.visibility = 'visible'; body.className = tmiModeExpanded ? 'showTmiModeInitial' : 'hideTmiModeInitial'; } /** * Handles a 'enable' or 'disable' button getting clicked. */ function handleEnablePlugin(node, enable, isGroup) { // Tell the C++ PluginsDOMHandler to enable/disable the plugin. chrome.send('enablePlugin', [String(node.path), String(enable), String(isGroup)]); } // Keeps track of whether details have been made visible (expanded) or not. var tmiModeExpanded = false; /* * Toggles visibility of details. */ function toggleTmiMode() { tmiModeExpanded = !tmiModeExpanded; document.getElementById('collapse').style.display = tmiModeExpanded ? 'inline' : 'none'; document.getElementById('expand').style.display = tmiModeExpanded ? 'none' : 'inline'; document.body.className = tmiModeExpanded ? 'showTmiMode' : 'hideTmiMode'; chrome.send('saveShowDetailsToPrefs', [String(tmiModeExpanded)]); } /** * Determines whether a plugin's version should be displayed. */ function shouldDisplayPluginVersion(plugin) { return !!plugin.version && plugin.version != '0'; } /** * Determines whether a plugin's description should be displayed. */ function shouldDisplayPluginDescription(plugin) { // Only display the description if it's not blank and if it's not just the // name, version, or combination thereof. return plugin.description && plugin.description != plugin.name && plugin.description != plugin.version && plugin.description != 'Version ' + plugin.version && plugin.description != plugin.name + ' ' + plugin.version; } /** * Determines whether a plugin is enabled or not. */ function isPluginEnabled(plugin) { return plugin.enabledMode == 'enabledByUser' || plugin.enabledMode == 'enabledByPolicy'; } // Unfortunately, we don't have notifications for plugin (list) status changes // (yet), so in the meanwhile just update regularly. setInterval(requestPluginsData, 30000); // Get data and have it displayed upon loading. document.addEventListener('DOMContentLoaded', requestPluginsData); </script> </head> <body i18n-values=".style.fontFamily:fontfamily;.style.fontSize:fontsize"> <div id="body-container" style="visibility:hidden"> <div id="header"><h1 i18n-content="pluginsTitle">TITLE</h1></div> <div id="pluginTemplate"> <div id="container" class="vbox-container"> <div id="top" class="wbox"> <div class="section-header"> <table cellpadding="0" cellspacing="0"><tr valign="center"> <td> <span class="section-header-title" i18n-content="pluginsTitle" >TITLE</span> <span class="section-header-title" jsdisplay="plugins.length > 0">(<span jscontent="plugins.length"></span>)</span> </td> <td width="18"> <img id="collapse" class="tmi-mode-image" style="display:none" onclick="toggleTmiMode();" src="shared/images/minus.png"> <img id="expand" class="tmi-mode-image" onclick="toggleTmiMode();" src="shared/images/plus.png"> </td> <td> <div class="tmi-mode-link"> <a onclick="toggleTmiMode();" style="cursor: default" i18n-content="pluginsDetailsModeLink">DETAILS</a> </div> </td> </tr></table> </div> </div> </div> <div class="content"> <div class="plugin-name no-plugins" jsdisplay="plugins.length === 0"> <div i18n-content="noPlugins">NO_PLUGINS_ARE_INSTALLED</div> </div> <div jsdisplay="plugins.length > 0"> <div class="plugin" jsselect="plugins"> <table width="100%" cellpadding="2" cellspacing="0"> <tr jsvalues= ".className:isPluginEnabled($this) ? 'plugin-enabled' : 'plugin-disabled'"> <td valign="top"> <div class="plugin-text"> <div> <span class="plugin-name" dir="ltr" jscontent="name">NAME</span> <span jsdisplay="plugin_files.length > 1" jscontent="'(' + plugin_files.length +' files)'">(x)</span> <span jsdisplay="shouldDisplayPluginVersion($this)"> - <span i18n-content="pluginVersion">VERSION</span> <span jsvalues=".className:critical? 'critical': ''" dir="ltr" jscontent="version">x.x.x.x</span> </span> <a jsdisplay="critical" jsvalues=".href:update_url" i18n-content="pluginDownload">DOWNLOAD UPDATE</a> <span jsdisplay="enabledMode == 'disabledByUser'" i18n-content="pluginDisabled">(DISABLED)</span> <span jsdisplay="enabledMode == 'disabledByPolicy'" i18n-content="pluginDisabledByPolicy">(DISABLED_BY_POLICY)</span> <span jsdisplay="enabledMode == 'enabledByPolicy'" i18n-content="pluginEnabledByPolicy">(ENABLED_BY_POLICY)</span> <div jsdisplay="shouldDisplayPluginDescription($this)"> <span dir="ltr" jsvalues=".innerHTML:description"> </div> </div> <div jsselect="plugin_files" class="plugin-details"> <div class="showInTmiMode"> <div jsvalues= ".className:isPluginEnabled($this) ? 'plugin-file-enabled' : 'plugin-file-disabled'"> <div><table><tr> <td class="plugin-details-label" i18n-content="pluginName">NAME:</td> <td><span dir="ltr" jscontent="name">NAME</span></td> </tr></table></div> <div><table> <tr jsdisplay="shouldDisplayPluginDescription($this)"> <td class="plugin-details-label" i18n-content="pluginDescription">DESCRIPTION:</td> <td> <span dir="ltr" jsvalues=".innerHTML:description"> </td> </tr> </table></div> <div><table><tr> <td class="plugin-details-label" i18n-content="pluginVersion">VERSION:</td> <td><span dir="ltr" jscontent="version">x.x.x.x</span></td> </tr></table></div> <div><table><tr> <td class="plugin-details-label" i18n-content="pluginPath">PATH:</td> <td><span dir="ltr" jscontent="path"></span></td> </tr></table></div> <div><table><tr> <td class="plugin-details-label"> </td> <td> <span jsdisplay="enabledMode == 'disabledByUser'" i18n-content="pluginDisabled">(DISABLED)</span> <span jsdisplay="enabledMode == 'disabledByPolicy'" i18n-content="pluginDisabledByPolicy">(DISABLED_BY_POLICY)</span> <span jsdisplay="enabledMode == 'enabledByPolicy'" i18n-content="pluginEnabledByPolicy">(ENABLED_BY_POLICY)</span> <span> <a jsvalues=".path:path" jsdisplay="enabledMode == 'enabledByUser'" onclick="handleEnablePlugin(this, false, false)" href="javascript:void(0);" i18n-content="disable" >DISABLE</a> <a jsvalues=".path:path" jsdisplay="enabledMode == 'disabledByUser'" onclick="handleEnablePlugin(this, true, false)" href="javascript:void(0);" i18n-content="enable" >ENABLE</a> <span jsdisplay="enabledMode == 'enabledByPolicy'" i18n-content="pluginCannotBeDisabledDueToPolicy" >CANNOT_DISABLE</span> <span jsdisplay="enabledMode == 'disabledByPolicy'" i18n-content="pluginCannotBeEnabledDueToPolicy" >CANNOT_ENABLE</span> </span> </td> </tr></table></div> <table><tr jsdisplay="mimeTypes.length > 0"> <td class="plugin-details-label" i18n-content="pluginMimeTypes">MIME_TYPES:</td> <td><table width="100%" class="mime-types"> <tr class="header"> <td i18n-content="pluginMimeTypesMimeType" >MIME type</td> <td i18n-content="pluginMimeTypesDescription" >DESCRIPTION</td> <td i18n-content="pluginMimeTypesFileExtensions" >FILE_EXTENSIONS</td> </tr> <tr jsselect="mimeTypes"> <td><span dir="ltr" jscontent="mimeType"></span></td> <td><span dir="ltr" jsvalues=".innerHTML:description"></span></td> <td><table jsdisplay="fileExtensions.length > 0" class="hlisting"> <tr><td jsselect="fileExtensions"> <span dir="ltr" jscontent="'.' + $this"> </td></tr> </table></td> </tr> </table></td> </tr></table> </div> </div> </div> </div> <div class="plugin-actions"> <span> <a jsvalues=".path:name" jsdisplay="enabledMode == 'enabledByUser'" onclick="handleEnablePlugin(this, false, true)" href="javascript:void(0);" i18n-content="disable" >DISABLE</a> <a jsvalues=".path:name" jsdisplay="enabledMode == 'disabledByUser'" onclick="handleEnablePlugin(this, true, true)" href="javascript:void(0);" i18n-content="enable" >ENABLE</a> <span jsdisplay="enabledMode == 'enabledByPolicy'" i18n-content="pluginCannotBeDisabledDueToPolicy" >CANNOT_DISABLE</span> <span jsdisplay="enabledMode == 'disabledByPolicy'" i18n-content="pluginCannotBeEnabledDueToPolicy" >CANNOT_ENABLE</span> </span> </div> </td> </tr> </table> </div> </div> </div> </div> </div> </body> </html>