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.
6 * @fileoverview Defines a list of plug-ins that shows for each plug-in a list
7 * of content setting rules.
10 cr.define('pluginSettings.ui', function() {
11 const List = cr.ui.List;
12 const ListItem = cr.ui.ListItem;
13 const ListSingleSelectionModel = cr.ui.ListSingleSelectionModel;
16 * CSS classes used by this class.
29 PLUGIN_LIST: 'plugin-list',
32 * Set on a plug-in list entry to show details about the plug-in.
34 PLUGIN_SHOW_DETAILS: 'plugin-show-details',
39 PLUGIN_NAME: 'plugin-name',
42 * The number of rules set for a plug-in.
44 NUM_RULES: 'num-rules',
47 * The element containing details about a plug-in.
49 PLUGIN_DETAILS: 'plugin-details',
52 * The element containing the column headers for the list of rules.
54 COLUMN_HEADERS: 'column-headers',
57 * The header for the pattern column.
59 PATTERN_COLUMN_HEADER: 'pattern-column-header',
62 * The header for the setting column.
64 SETTING_COLUMN_HEADER: 'setting-column-header',
68 * Returns the item's height, like offsetHeight but such that it works better
69 * when the page is zoomed. See the similar calculation in @{code cr.ui.List}.
70 * This version also accounts for the animation done in this file.
71 * @param {!Element} item The item to get the height of.
72 * @return {number} The height of the item, calculated with zooming in mind.
74 function getItemHeight(item) {
75 var height = item.style.height;
76 // Use the fixed animation target height if set, in case the element is
77 // currently being animated and we'd get an intermediate height below.
78 if (height && height.substr(-2) == 'px') {
79 return parseInt(height.substr(0, height.length - 2));
81 return item.getBoundingClientRect().height;
85 * Creates a new plug-in list item element.
86 * @param {!PluginList} list The plug-in list containing this item.
87 * @param {!Object} info Information about the plug-in.
89 * @extends {cr.ui.ListItem}
91 function PluginListItem(list, info) {
92 var el = cr.doc.createElement('li');
95 * The plug-in list containing this item.
102 * Information about the plug-in.
108 el.__proto__ = PluginListItem.prototype;
113 PluginListItem.prototype = {
114 __proto__: ListItem.prototype,
117 * The element containing details about the plug-in. This is only null in
119 * @type {?HTMLDivElement}
122 detailsElement_: null,
125 * Initializes the element.
127 decorate: function() {
128 ListItem.prototype.decorate.call(this);
130 var info = this.info_;
132 var contentElement = this.ownerDocument.createElement('div');
134 var titleEl = this.ownerDocument.createElement('div');
135 var nameEl = this.ownerDocument.createElement('span');
136 nameEl.className = CSSClass.PLUGIN_NAME;
137 nameEl.textContent = info.description;
138 nameEl.title = info.description;
139 titleEl.appendChild(nameEl);
140 this.numRulesEl_ = this.ownerDocument.createElement('span');
141 this.numRulesEl_.className = CSSClass.NUM_RULES;
142 titleEl.appendChild(this.numRulesEl_);
143 contentElement.appendChild(titleEl);
145 this.detailsElement_ = this.ownerDocument.createElement('div');
146 this.detailsElement_.classList.add(CSSClass.PLUGIN_DETAILS);
147 this.detailsElement_.classList.add(CSSClass.HIDDEN);
149 var columnHeadersEl = this.ownerDocument.createElement('div');
150 columnHeadersEl.className = CSSClass.COLUMN_HEADERS;
151 var patternColumnEl = this.ownerDocument.createElement('div');
152 patternColumnEl.textContent =
153 chrome.i18n.getMessage('patternColumnHeader');
154 patternColumnEl.className = CSSClass.PATTERN_COLUMN_HEADER;
155 var settingColumnEl = this.ownerDocument.createElement('div');
156 settingColumnEl.textContent =
157 chrome.i18n.getMessage('settingColumnHeader');
158 settingColumnEl.className = CSSClass.SETTING_COLUMN_HEADER;
159 columnHeadersEl.appendChild(patternColumnEl);
160 columnHeadersEl.appendChild(settingColumnEl);
161 this.detailsElement_.appendChild(columnHeadersEl);
162 contentElement.appendChild(this.detailsElement_);
164 this.appendChild(contentElement);
166 var settings = new pluginSettings.Settings(this.info_.id);
167 this.updateRulesCount_(settings);
168 settings.addEventListener(
170 this.updateRulesCount_.bind(this, settings));
172 // Create the rule list asynchronously, to make sure that it is already
173 // fully integrated in the DOM tree.
174 window.setTimeout(this.loadRules_.bind(this, settings), 0);
178 * Create the list of content setting rules applying to this plug-in.
179 * @param {!pluginSettings.Settings} The settings object storing the content
183 loadRules_: function(settings) {
184 var rulesEl = this.ownerDocument.createElement('list');
185 this.detailsElement_.appendChild(rulesEl);
187 pluginSettings.ui.RuleList.decorate(rulesEl);
188 rulesEl.setPluginSettings(settings);
192 * Called when the list of rules changes to update the rule count shown when
193 * the list is not expanded.
194 * @param {!pluginSettings.Settings} The settings object storing the content
198 updateRulesCount_: function(settings) {
199 this.numRulesEl_.textContent = '(' + settings.getAll().length + ' rules)';
203 * Whether this item is expanded or not.
208 * Whether this item is expanded or not.
212 return this.expanded_;
214 set expanded(expanded) {
215 if (this.expanded_ == expanded) {
218 this.expanded_ = expanded;
220 var oldExpanded = this.list_.expandItem;
221 this.list_.expandItem = this;
222 this.detailsElement_.classList.remove(CSSClass.HIDDEN);
224 oldExpanded.expanded = false;
226 this.classList.add(CSSClass.PLUGIN_SHOW_DETAILS);
228 if (this.list_.expandItem == this) {
229 this.list_.leadItemHeight = 0;
230 this.list_.expandItem = null;
232 this.style.height = '';
233 this.detailsElement_.classList.add(CSSClass.HIDDEN);
234 this.classList.remove(CSSClass.PLUGIN_SHOW_DETAILS);
240 * Creates a new plug-in list.
242 * @extends {cr.ui.List}
244 var PluginList = cr.ui.define('list');
246 PluginList.prototype = {
247 __proto__: List.prototype,
250 * Initializes the element.
252 decorate: function() {
253 List.prototype.decorate.call(this);
254 this.classList.add(CSSClass.PLUGIN_LIST);
255 var sm = new ListSingleSelectionModel();
256 sm.addEventListener('change', this.handleSelectionChange_.bind(this));
257 this.selectionModel = sm;
258 this.autoExpands = true;
262 * Creates a new plug-in list item.
263 * @param {!Object} info Information about the plug-in.
265 createItem: function(info) {
266 return new PluginListItem(this, info);
270 * Called when the selection changes.
271 * @param {!Event} ce The change event.
274 handleSelectionChange_: function(ce) {
275 ce.changes.forEach(function(change) {
276 var listItem = this.getListItemByIndex(change.index);
278 if (!change.selected) {
279 // TODO(bsmith) explain window timeout (from cookies_list.js)
280 window.setTimeout(function() {
281 if (!listItem.selected || !listItem.lead) {
282 listItem.expanded = false;
285 } else if (listItem.lead) {
286 listItem.expanded = true;
294 PluginList: PluginList,
295 PluginListItem: PluginListItem,