Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(105)

Side by Side Diff: chrome/browser/resources/extensions/update_node.js

Issue 893453002: Stop rebuilding all elements in chrome://extensions to preserve focus on refresh (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: DO NOT COMMIT - Diff Changes Created 5 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // TODO(hcarmona): Remove this temporary file.
2
3 /**
4 * Updates an HTML element for the extension metadata given in |extension|.
5 * @param {ExtensionData} extension A dictionary of extension metadata.
6 * @param {Element} node The node that is being updated.
7 * @private
8 */
9 updateNode_: function(extension, node) {
10 node.classList.toggle('inactive-extension',
11 !extension.enabled || extension.terminated);
12
13 node.classList.toggle('policy-controlled', extension.managedInstall);
14
15 node.classList.toggle('may-not-remove',
16 extension.dependentExtensions.length > 0 ||
17 extension.recommendedInstall);
18
19 node.classList.toggle('may-not-modify',
20 extension.managedInstall ||
21 extension.dependentExtensions.length > 0 ||
22 extension.suspiciousInstall ||
23 extension.corruptInstall ||
24 extension.updateRequiredByPolicy);
25
26 node.classList.toggle('extension-highlight',
27 node.id == this.getIdQueryParam_());
not at google - send to devlin 2015/02/03 17:41:18 What was wrong with the old class setup code?
hcarmona 2015/02/03 19:26:10 This code will toggle the classes because the node
not at google - send to devlin 2015/02/03 19:33:40 Yes I think that would be preferable, at least for
hcarmona 2015/02/04 23:38:59 Done.
28
29 var item = node.querySelector('.extension-list-item');
30 // Prevent the image cache of extension icon by using the reloaded
31 // timestamp as a query string. The timestamp is recorded when the user
32 // clicks the 'Reload' link. http://crbug.com/159302.
33 if (extensionReloadedTimestamp[extension.id]) {
34 item.style.backgroundImage =
35 'url(' + extension.icon + '?' +
36 extensionReloadedTimestamp[extension.id] + ')';
37 } else {
38 item.style.backgroundImage = 'url(' + extension.icon + ')';
39 }
40
41 var title = node.querySelector('.extension-title');
42 title.textContent = extension.name;
43
44 var version = node.querySelector('.extension-version');
45 version.textContent = extension.version;
46
47 var locationText = node.querySelector('.location-text');
48 locationText.textContent = extension.locationText;
49
50 var blacklistText = node.querySelector('.blacklist-text');
51 blacklistText.textContent = extension.blacklistText;
52
53 var description = document.createElement('span');
54 description.textContent = extension.description;
55 var descriptionHolder = node.querySelector('.extension-description');
56 descriptionHolder.textContent = '';
57 descriptionHolder.appendChild(description);
58
59 // The 'Show Browser Action' button.
60 var showButton = node.querySelector('.show-button');
61 this.toggleEventListener_(showButton, extension.enable_show_button,
not at google - send to devlin 2015/02/03 17:41:18 Any reason why you need to toggle these listeners?
hcarmona 2015/02/03 19:26:10 Previous logic only adds listeners when they're go
not at google - send to devlin 2015/02/03 19:33:40 Maybe Dan can comment on that, but I feel the comp
Dan Beam 2015/02/03 19:35:06 i think unless there's a metrics-driven or anecdot
hcarmona 2015/02/04 23:38:59 Page feels snappier (compared to stable) when togg
62 'click', showButton.showButtonHandler);
63 showButton.hidden = !extension.enable_show_button;
64
65 // The 'allow in incognito' checkbox.
66 node.querySelector('.incognito-control').hidden =
67 !this.data_.incognitoAvailable;
68 var incognito = node.querySelector('.incognito-control input');
69 incognito.disabled = !extension.incognitoCanBeEnabled;
70 incognito.checked = extension.enabledIncognito;
71 this.toggleEventListener_(incognito, !incognito.disabled,
72 'change', incognito.changeHandler);
73 var butterBar = node.querySelector('.butter-bar');
74 butterBar.hidden = !butterBarVisibility[extension.id];
75
76 // The 'collect errors' checkbox. This should only be visible if the
77 // error console is enabled - we can detect this by the existence of the
78 // |errorCollectionEnabled| property.
79 node.querySelector('.error-collection-control').hidden =
80 !extension.wantsErrorCollection;
81 var errorCollection =
82 node.querySelector('.error-collection-control input');
83 errorCollection.checked = extension.wantsErrorCollection &&
84 extension.errorCollectionEnabled;
85 this.toggleEventListener_(errorCollection, extension.wantsErrorCollection,
86 'change', errorCollection.changeHandler);
87
88 // The 'allow on all urls' checkbox. This should only be visible if
89 // active script restrictions are enabled. If they are not enabled, no
90 // extensions should want all urls.
91 var allUrls = node.querySelector('.all-urls-control');
92 this.toggleEventListener_(allUrls, extension.wantsAllUrls,
93 'click', allUrls.clickHandler);
94 allUrls.querySelector('input').checked = extension.wantsAllUrls &&
95 extension.allowAllUrls;
96 allUrls.hidden = !extension.wantsAllUrls;
97
98 // The 'allow file:// access' checkbox.
99 var fileAccess = node.querySelector('.file-access-control');
100 this.toggleEventListener_(fileAccess, extension.wantsFileAccess,
101 'click', fileAccess.clickHandler);
102 fileAccess.querySelector('input').checked = extension.wantsFileAccess &&
103 extension.allowFileAccess;
104 fileAccess.hidden = !extension.wantsFileAccess;
105
106 // The 'Options' button or link, depending on its behaviour.
107 var optionsEnabled = extension.enabled && extension.optionsUrl;
108
109 var optionsLink = node.querySelector('.options-link');
110 var optionsLinkEnabled = optionsEnabled && extension.optionsOpenInTab;
111 this.addEventListener(optionsLink, optionsLinkEnabled,
112 'click', optionsLink.clickHandler);
113 optionsLink.hidden = !optionsLinkEnabled;
114
115 var optionsButton = options = node.querySelector('.options-button');
116 var optionsButtonEnabled = optionsEnabled && !extension.optionsOpenInTab;
117 this.addEventListener(optionsButton, optionsButtonEnabled,
118 'click', optionsButton.clickHandler);
119 optionsButton.hidden = !optionsButtonEnabled;
120
121 // The 'View in Web Store/View Web Site' link.
122 var siteLinkEnabled = extension.homepageUrl &&
123 !extension.enableExtensionInfoDialog;
124 var siteLink = node.querySelector('.site-link');
125 siteLink.href = extension.homepageUrl;
126 siteLink.textContent = loadTimeData.getString(
127 extension.homepageProvided ? 'extensionSettingsVisitWebsite' :
128 'extensionSettingsVisitWebStore');
129 siteLink.hidden = !siteLinkEnabled;
130
131 // The 'Reload' link.
132 var reload = node.querySelector('.reload-link');
133 this.toggleEventListener_(reload, extension.allow_reload,
134 'click', reload.clickHandler);
135 reload.hidden = !extension.allow_reload;
136
137 var canLaunch = extension.allow_reload && extension.is_platform_app;
138 // The 'Launch' link.
139 var launch = node.querySelector('.launch-link');
140 this.toggleEventListener_(launch, canLaunch,
141 'click', launch.clickHandler);
142 launch.hidden = !canLaunch;
143
144 // The 'Reload' terminated link.
145 var isTerminated = extension.terminated;
146 var terminatedReload = node.querySelector('.terminated-reload-link');
147 this.toggleEventListener_(terminatedReload, isTerminated,
148 'click', terminatedReload.clickHandler);
149 terminatedReload.hidden = !isTerminated;
150
151 // The 'Repair' corrupted link.
152 var canRepair = !isTerminated && extension.corruptInstall &&
153 extension.isFromStore;
154 var repair = node.querySelector('.corrupted-repair-button');
155 this.toggleEventListener_(repair, canRepair,
156 'click', repair.clickHandler);
157 repair.hidden = !canRepair;
158
159 // The 'Enabled' checkbox.
160 var isOK = !isTerminated && !canRepair;
161 var enable = node.querySelector('.enable-checkbox');
162 enable.hidden = !isOK;
163 var enableCheckboxDisabled = extension.managedInstall ||
164 extension.suspiciousInstall ||
165 extension.corruptInstall ||
166 extension.updateRequiredByPolicy ||
167 extension.dependentExtensions.length > 0;
168 enable.querySelector('input').disabled = enableCheckboxDisabled;
169 this.toggleEventListener_(enable, isOK && !enableCheckboxDisabled,
170 'click', enable.clickHandler);
171
172 enable.querySelector('input').checked = isOK && extension.enabled;
173
174 // Button for extensions controlled by policy.
175 var controlNode = node.querySelector('.enable-controls');
176 if (extension.managedInstall &&
177 !controlNode.querySelector('.controlled-extension-indicator')) {
178 var indicator = new cr.ui.ControlledIndicator();
179 indicator.classList.add('controlled-extension-indicator');
180 indicator.setAttribute('controlled-by', 'policy');
181 indicator.setAttribute('textpolicy', extension.policyText || '');
182 controlNode.appendChild(indicator);
183 } else if (!extension.managedInstall) {
184 var indicator = controlNode.querySelector(
185 '.controlled-extension-indicator');
186 if (indicator)
187 controlNode.removeChild(indicator);
188 }
189
190 // Developer mode ////////////////////////////////////////////////////////
191
192 // First we have the id.
193 var idLabel = node.querySelector('.extension-id');
194 idLabel.textContent = ' ' + extension.id;
195
196 // Then the path, if provided by unpacked extension.
197 var loadPath = node.querySelector('.load-path');
198 loadPath.hidden = !extension.isUnpacked;
199 var pathLink = loadPath.querySelector('a:nth-of-type(1)');
200 pathLink.textContent = ' ' + extension.prettifiedPath;
201 this.toggleEventListener_(pathLink, extension.isUnpacked,
202 'click', pathLink.clickHandler);
203
204 // Then the 'managed, cannot uninstall/disable' message.
205 var isRequired = extension.managedInstall || extension.recommendedInstall;
206 node.querySelector('.managed-message').hidden = !isRequired;
207
208 // Then the 'This isn't from the webstore, looks suspicious' message.
209 var isSuspicious = !isRequired && extension.suspiciousInstall;
210 node.querySelector('.suspicious-install-message').hidden = !isSuspicious;
211
212 // Then the 'This is a corrupt extension' message.
213 var isCorrupt = !isRequired && extension.corruptInstall;
214 node.querySelector('.corrupt-install-message').hidden = !isCorrupt;
215
216 // Then the 'An update required by enterprise policy' message. Note that
217 // a force-installed extension might be disabled due to being outdated
218 // as well.
219 node.querySelector('.update-required-message').hidden =
220 !extension.updateRequiredByPolicy;
221 // We would like to hide managed installed message since this
222 // extension is disabled.
223 node.querySelector('.managed-message').hidden =
224 extension.updateRequiredByPolicy;
225
226 // The 'following extensions depend on this extension' list.
227 var hasDependents = extension.dependentExtensions.length > 0;
228 node.classList.toggle('developer-extras', hasDependents);
229 var dependentMessage =
230 node.querySelector('.dependent-extensions-message');
231 dependentMessage.hidden = !hasDependents;
232 var dependentList = dependentMessage.querySelector('ul');
233 dependentList.textContent = '';
234 var dependentTemplate = $('template-collection').querySelector(
235 '.dependent-list-item');
236 extension.dependentExtensions.forEach(function(elem) {
237 var depNode = dependentTemplate.cloneNode(true);
238 depNode.querySelector('.dep-extension-title').textContent = elem.name;
239 depNode.querySelector('.dep-extension-id').textContent = elem.id;
240 dependentList.appendChild(depNode);
241 });
242
243 // The active views.
244 var hasActiveViews = extension.views.length > 0;
245 var activeViews = node.querySelector('.active-views');
246 activeViews.hidden = !hasActiveViews;
247
248 var link = activeViews.querySelector('a');
249
250 // Link needs to be an only child before the list is updated.
251 while (link.nextElementSibling)
252 activeViews.removeChild(link.nextElementSibling);
253
254 // Link needs to be cleaned up if it was used before.
255 link.textContent = '';
256 if (link.clickHandler)
257 link.removeEventListener('click', link.clickHandler);
258
259 if (hasActiveViews) {
260 extension.views.forEach(function(view, i) {
261 var displayName = view.generatedBackgroundPage ?
262 loadTimeData.getString('backgroundPage') : view.path;
263 var label = displayName +
264 (view.incognito ?
265 ' ' + loadTimeData.getString('viewIncognito') : '') +
266 (view.renderProcessId == -1 ?
267 ' ' + loadTimeData.getString('viewInactive') : '');
268 link.textContent = label;
269 link.clickHandler = function(e) {
270 // TODO(estade): remove conversion to string?
271 chrome.send('extensionSettingsInspect', [
272 String(extension.id),
273 String(view.renderProcessId),
274 String(view.renderViewId),
275 view.incognito
276 ]);
277 };
278 link.addEventListener('click', link.clickHandler);
279
280 if (i < extension.views.length - 1) {
281 link = link.cloneNode(true);
282 activeViews.appendChild(link);
283 }
284 });
285 }
286
287 // The extension warnings (describing runtime issues).
288 var warningPanel = node.querySelector('.extension-warnings');
289 warningPanel.hidden = !extension.warnings;
290 var warningList = warningPanel.querySelector('ul');
291 warningList.textContent = '';
292 if (extension.warnings) {
293 extension.warnings.forEach(function(warning) {
294 warningList.appendChild(document.createElement('li')).innerText =
295 warning;
296 });
297 }
298
299 // If the ErrorConsole is enabled, we should have manifest and/or runtime
300 // errors. Otherwise, we may have install warnings. We should not have
301 // both ErrorConsole errors and install warnings.
302 // Errors.
303 this.updateErrors_(node.querySelector('.manifest-errors'),
304 extension.manifestErrors);
305 this.updateErrors_(node.querySelector('.runtime-errors'),
306 extension.runtimeErrors);
307 // Install warnings.
308 var installWarningPanel = node.querySelector('.install-warnings');
309 installWarningPanel.hidden = !extension.installWarnings;
310 var installWarningList = installWarningPanel.querySelector('ul');
311 installWarningList.textContent = '';
312 if (extension.installWarnings) {
313 extension.installWarnings.forEach(function(warning) {
314 var li = document.createElement('li');
315 li.innerText = warning.message;
316 installWarningList.appendChild(li);
317 });
318 }
319
320 if (location.hash.substr(1) == extension.id) {
321 // Scroll beneath the fixed header so that the extension is not
322 // obscured.
323 var topScroll = node.offsetTop - $('page-header').offsetHeight;
324 var pad = parseInt(window.getComputedStyle(node, null).marginTop, 10);
325 if (!isNaN(pad))
326 topScroll -= pad / 2;
327 setScrollTopForDocument(document, topScroll);
328 }
329 },
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698