1// Copyright (c) 2012 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5/**
6 * Takes the |pluginsData| input argument which represents data about the
7 * currently installed/running plugins and populates the html jstemplate with
8 * that data. It expects an object structure like the above.
9 * @param {Object} pluginsData Detailed info about installed plugins. Same
10 *     expected format as returnPluginsData().
11 */
12function renderTemplate(pluginsData) {
13  // This is the javascript code that processes the template:
14  var input = new JsEvalContext(pluginsData);
15  var output = $('pluginTemplate');
16  jstProcess(input, output);
17}
18
19/**
20 * Asks the C++ PluginsDOMHandler to get details about the installed plugins and
21 * return detailed data about the configuration. The PluginsDOMHandler should
22 * reply to returnPluginsData() (below).
23 */
24function requestPluginsData() {
25  chrome.send('requestPluginsData');
26  chrome.send('getShowDetails');
27}
28
29function loadShowDetailsFromPrefs(show_details) {
30  tmiModeExpanded = show_details;
31  $('collapse').style.display =
32      show_details ? 'inline' : 'none';
33  $('expand').style.display =
34      show_details ? 'none' : 'inline';
35
36  document.body.className = show_details ? 'show-in-tmi-mode' : 'hide-tmi-mode';
37}
38
39/**
40 * Called by the web_ui_ to re-populate the page with data representing the
41 * current state of installed plugins.
42 * @param {Object} pluginsData Detailed info about installed plugins. The
43 *     template expects each plugin's format to match the following structure to
44 *     correctly populate the page:
45 *   {
46 *     plugins: [
47 *       {
48 *         name: 'Group Name',
49 *         description: 'description',
50 *         version: 'version',
51 *         update_url: 'http://update/',
52 *         critical: true,
53 *         enabled: true,
54 *         identifier: 'plugin-name',
55 *         plugin_files: [
56 *           {
57 *             path: '/blahblah/blahblah/MyCrappyPlugin.plugin',
58 *             name: 'MyCrappyPlugin',
59 *             version: '1.2.3',
60 *             description: 'My crappy plugin',
61 *             mimeTypes: [
62 *               { description: 'Foo Media',
63 *                 fileExtensions: ['foo'],
64 *                 mimeType: 'application/x-my-foo' },
65 *               { description: 'Bar Stuff',
66 *                 fileExtensions: ['bar', 'baz'],
67 *                 mimeType: 'application/my-bar' }
68 *             ],
69 *             enabledMode: 'enabledByUser'
70 *           },
71 *           {
72 *             path: '/tmp/MyFirst.plugin',
73 *             name: 'MyFirstPlugin',
74 *             version: '3.14r15926',
75 *             description: 'My first plugin',
76 *             mimeTypes: [
77 *               { description: 'New Guy Media',
78 *                 fileExtensions: ['mfp'],
79 *                 mimeType: 'application/x-my-first' }
80 *             ],
81 *             enabledMode: 'enabledByPolicy'
82 *           },
83 *           {
84 *             path: '/foobar/baz/YourGreatPlugin.plugin',
85 *             name: 'YourGreatPlugin',
86 *             version: '4.5',
87 *             description: 'Your great plugin',
88 *             mimeTypes: [
89 *               { description: 'Baz Stuff',
90 *                 fileExtensions: ['baz'],
91 *                 mimeType: 'application/x-your-baz' }
92 *             ],
93 *             enabledMode: 'disabledByUser'
94 *           },
95 *           {
96 *             path: '/foobiz/bar/HisGreatPlugin.plugin',
97 *             name: 'HisGreatPlugin',
98 *             version: '1.2',
99 *             description: 'His great plugin',
100 *             mimeTypes: [
101 *               { description: 'More baz Stuff',
102 *                 fileExtensions: ['bor'],
103 *                 mimeType: 'application/x-his-bor' }
104 *             ],
105 *             enabledMode: 'disabledByPolicy'
106 *           }
107 *         ]
108 *       }
109 *     ]
110 *   }
111 */
112function returnPluginsData(pluginsData) {
113  var bodyContainer = $('body-container');
114  var body = document.body;
115
116  // Set all page content to be visible so we can measure heights.
117  bodyContainer.style.visibility = 'hidden';
118  body.className = '';
119  var slidables = document.getElementsByClassName('show-in-tmi-mode');
120  for (var i = 0; i < slidables.length; i++)
121    slidables[i].style.height = 'auto';
122
123  renderTemplate(pluginsData);
124
125  // Add handlers to dynamically created HTML elements.
126  var links = document.getElementsByClassName('disable-plugin-link');
127  for (var i = 0; i < links.length; i++) {
128    links[i].onclick = function() {
129      handleEnablePlugin(this, false, false);
130      return false;
131    };
132  }
133  links = document.getElementsByClassName('enable-plugin-link');
134  for (var i = 0; i < links.length; i++) {
135    links[i].onclick = function() {
136      handleEnablePlugin(this, true, false);
137      return false;
138    };
139  }
140  links = document.getElementsByClassName('disable-group-link');
141  for (var i = 0; i < links.length; i++) {
142    links[i].onclick = function() {
143      handleEnablePlugin(this, false, true);
144      return false;
145    };
146  }
147  links = document.getElementsByClassName('enable-group-link');
148  for (var i = 0; i < links.length; i++) {
149    links[i].onclick = function() {
150      handleEnablePlugin(this, true, true);
151      return false;
152    };
153  }
154  var checkboxes = document.getElementsByClassName('always-allow');
155  for (var i = 0; i < checkboxes.length; i++) {
156    checkboxes[i].onclick = function() {
157      handleSetPluginAlwaysAllowed(this);
158    };
159  }
160
161  if (cr.isChromeOS) {
162    // Disable some controls for Guest in ChromeOS.
163    uiAccountTweaks.UIAccountTweaks.applyGuestSessionVisibility(document);
164    // Disable some controls for Public session in ChromeOS.
165    uiAccountTweaks.UIAccountTweaks.applyPublicSessionVisibility(document);
166  }
167
168  // Make sure the left column (with "Description:", "Location:", etc.) is the
169  // same size for all plugins.
170  var labels = document.getElementsByClassName('plugin-details-label');
171  var maxLabelWidth = 0;
172  for (var i = 0; i < labels.length; i++)
173    labels[i].style.width = 'auto';
174  for (var i = 0; i < labels.length; i++)
175    maxLabelWidth = Math.max(maxLabelWidth, labels[i].offsetWidth);
176  for (var i = 0; i < labels.length; i++)
177    labels[i].style.width = maxLabelWidth + 'px';
178
179  // Explicitly set the height for each element that wants to be "slid" in and
180  // out when the tmiModeExpanded is toggled.
181  var slidables = document.getElementsByClassName('show-in-tmi-mode');
182  for (var i = 0; i < slidables.length; i++)
183    slidables[i].style.height = slidables[i].offsetHeight + 'px';
184
185  // Reset visibility of page based on the current tmi mode.
186  $('collapse').style.display =
187     tmiModeExpanded ? 'inline' : 'none';
188  $('expand').style.display =
189     tmiModeExpanded ? 'none' : 'inline';
190  bodyContainer.style.visibility = 'visible';
191  body.className = tmiModeExpanded ?
192     'show-tmi-mode-initial' : 'hide-tmi-mode-initial';
193}
194
195/**
196 * Handles a 'enable' or 'disable' button getting clicked.
197 * @param {HTMLElement} node The HTML element for the plugin being changed.
198 * @param {boolean} enable Whether to enable or disable the plugin.
199 * @param {boolean} isGroup True if we're enabling/disabling a plugin group,
200 *     rather than a single plugin.
201 */
202function handleEnablePlugin(node, enable, isGroup) {
203  // Tell the C++ PluginsDOMHandler to enable/disable the plugin.
204  chrome.send('enablePlugin', [String(node.path), String(enable),
205              String(isGroup)]);
206}
207
208// Keeps track of whether details have been made visible (expanded) or not.
209var tmiModeExpanded = false;
210
211/*
212 * Toggles visibility of details.
213 */
214function toggleTmiMode() {
215  tmiModeExpanded = !tmiModeExpanded;
216
217  $('collapse').style.display =
218      tmiModeExpanded ? 'inline' : 'none';
219  $('expand').style.display =
220      tmiModeExpanded ? 'none' : 'inline';
221
222  document.body.className =
223      tmiModeExpanded ? 'show-tmi-mode' : 'hide-tmi-mode';
224
225  chrome.send('saveShowDetailsToPrefs', [String(tmiModeExpanded)]);
226}
227
228function handleSetPluginAlwaysAllowed(el) {
229  chrome.send('setPluginAlwaysAllowed', [el.identifier, el.checked]);
230}
231
232/**
233 * @param {Object} plugin An object containing the information about a plugin.
234 *     See returnPluginsData() for the format of this object.
235 * @return {boolean} Whether the plugin's version should be displayed.
236 */
237function shouldDisplayPluginVersion(plugin) {
238  return !!plugin.version && plugin.version != '0';
239}
240
241/**
242 * @param {Object} plugin An object containing the information about a plugin.
243 *     See returnPluginsData() for the format of this object.
244 * @return {boolean} Whether the plugin's description should be displayed.
245 */
246function shouldDisplayPluginDescription(plugin) {
247  // Only display the description if it's not blank and if it's not just the
248  // name, version, or combination thereof.
249  return plugin.description &&
250         plugin.description != plugin.name &&
251         plugin.description != plugin.version &&
252         plugin.description != 'Version ' + plugin.version &&
253         plugin.description != plugin.name + ' ' + plugin.version;
254}
255
256/**
257 * @param {Object} plugin An object containing the information about a plugin.
258 *     See returnPluginsData() for the format of this object.
259 * @return {boolean} Whether the plugin is enabled.
260 */
261function isPluginEnabled(plugin) {
262  return plugin.enabledMode == 'enabledByUser' ||
263         plugin.enabledMode == 'enabledByPolicy';
264}
265
266// Unfortunately, we don't have notifications for plugin (list) status changes
267// (yet), so in the meanwhile just update regularly.
268setInterval(requestPluginsData, 30000);
269
270// Get data and have it displayed upon loading.
271document.addEventListener('DOMContentLoaded', requestPluginsData);
272
273// Add handlers to static HTML elements.
274$('collapse').onclick = toggleTmiMode;
275$('expand').onclick = toggleTmiMode;
276$('details-link').onclick = toggleTmiMode;
277