| Index: chrome/browser/resources/extensions/update_node.js
|
| diff --git a/chrome/browser/resources/extensions/update_node.js b/chrome/browser/resources/extensions/update_node.js
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..62cad04630e2c22c59174caac070995e443debee
|
| --- /dev/null
|
| +++ b/chrome/browser/resources/extensions/update_node.js
|
| @@ -0,0 +1,289 @@
|
| +// TODO(hcarmona): Remove this temporary file.
|
| +
|
| + /**
|
| + * Updates an HTML element for the extension metadata given in |extension|.
|
| + * @param {ExtensionData} extension A dictionary of extension metadata.
|
| + * @param {Element} node The node that is being updated.
|
| + * @private
|
| + */
|
| + updateNode_: function(extension, node) {
|
| + node.classList.toggle('inactive-extension',
|
| + !extension.enabled || extension.terminated);
|
| +
|
| + var toRemove = ['policy-controlled', 'may-not-modify', 'may-not-remove'];
|
| + node.classList.remove.apply(node.classList, toRemove);
|
| + var classes = [];
|
| + if (extension.managedInstall) {
|
| + classes.push('policy-controlled', 'may-not-modify');
|
| + } else if (extension.dependentExtensions.length > 0) {
|
| + classes.push('may-not-remove', 'may-not-modify');
|
| + } else if (extension.recommendedInstall) {
|
| + classes.push('may-not-remove');
|
| + } else if (extension.suspiciousInstall ||
|
| + extension.corruptInstall ||
|
| + extension.updateRequiredByPolicy) {
|
| + classes.push('may-not-modify');
|
| + }
|
| + node.classList.add.apply(node.classList, classes);
|
| +
|
| + node.classList.toggle('extension-highlight',
|
| + node.id == this.getIdQueryParam_());
|
| +
|
| + var item = node.querySelector('.extension-list-item');
|
| + // Prevent the image cache of extension icon by using the reloaded
|
| + // timestamp as a query string. The timestamp is recorded when the user
|
| + // clicks the 'Reload' link. http://crbug.com/159302.
|
| + if (extensionReloadedTimestamp[extension.id]) {
|
| + item.style.backgroundImage =
|
| + 'url(' + extension.icon + '?' +
|
| + extensionReloadedTimestamp[extension.id] + ')';
|
| + } else {
|
| + item.style.backgroundImage = 'url(' + extension.icon + ')';
|
| + }
|
| +
|
| + this.setTextContent_(node, '.extension-title', extension.name);
|
| + this.setTextContent_(node, '.extension-version', extension.version);
|
| + this.setTextContent_(node, '.location-text', extension.locationText);
|
| + this.setTextContent_(node, '.blacklist-text', extension.blacklistText);
|
| + this.setTextContent_(node, '.extension-description',
|
| + extension.description);
|
| +
|
| + // The 'Show Browser Action' button.
|
| + this.updateElement_(node, '.show-button', extension.enable_show_button);
|
| +
|
| + // The 'allow in incognito' checkbox.
|
| + this.updateElement_(node, '.incognito-control',
|
| + this.data_.incognitoAvailable, function(item) {
|
| + var incognito = item.querySelector('input');
|
| + incognito.disabled = !extension.incognitoCanBeEnabled;
|
| + incognito.checked = extension.enabledIncognito;
|
| + });
|
| +
|
| + // Only show the butterbar once.
|
| + butterBarVisibility[extension.id] = butterBarVisibility[extension.id] &&
|
| + extension.enabledIncognito;
|
| + this.updateElement_(node, '.butter-bar',
|
| + butterBarVisibility[extension.id]);
|
| +
|
| + // The 'collect errors' checkbox. This should only be visible if the
|
| + // error console is enabled - we can detect this by the existence of the
|
| + // |errorCollectionEnabled| property.
|
| + this.updateElement_(node, '.error-collection-control',
|
| + extension.wantsErrorCollection, function(item) {
|
| + item.querySelector('input').checked = extension.errorCollectionEnabled;
|
| + });
|
| +
|
| + // The 'allow on all urls' checkbox. This should only be visible if
|
| + // active script restrictions are enabled. If they are not enabled, no
|
| + // extensions should want all urls.
|
| + this.updateElement_(node, '.all-urls-control', extension.wantsAllUrls,
|
| + function(item) {
|
| + item.querySelector('input').checked = extension.allowAllUrls;
|
| + });
|
| +
|
| + // The 'allow file:// access' checkbox.
|
| + this.updateElement_(node, '.file-access-control',
|
| + extension.wantsFileAccess, function(item) {
|
| + item.querySelector('input').checked = extension.allowFileAccess;
|
| + });
|
| +
|
| + // The 'Options' button or link, depending on its behaviour.
|
| + var optionsEnabled = extension.enabled && extension.optionsUrl;
|
| + this.updateElement_(node, '.options-link', optionsEnabled &&
|
| + extension.optionsOpenInTab);
|
| + this.updateElement_(node, '.options-button', optionsEnabled &&
|
| + !extension.optionsOpenInTab);
|
| +
|
| + // The 'View in Web Store/View Web Site' link.
|
| + var siteLinkEnabled = extension.homepageUrl &&
|
| + !extension.enableExtensionInfoDialog;
|
| + this.updateElement_(node, '.site-link', siteLinkEnabled, function(item) {
|
| + item.href = extension.homepageUrl;
|
| + item.textContent = loadTimeData.getString(
|
| + extension.homepageProvided ? 'extensionSettingsVisitWebsite' :
|
| + 'extensionSettingsVisitWebStore');
|
| + });
|
| +
|
| + // The 'Reload' link.
|
| + this.updateElement_(node, '.reload-link', extension.allow_reload);
|
| +
|
| + // The 'Launch' link.
|
| + this.updateElement_(node, '.launch-link', extension.allow_reload &&
|
| + extension.is_platform_app);
|
| +
|
| + // The 'Reload' terminated link.
|
| + var isTerminated = extension.terminated;
|
| + this.updateElement_(node, '.terminated-reload-link', isTerminated);
|
| +
|
| + // The 'Repair' corrupted link.
|
| + var canRepair = !isTerminated && extension.corruptInstall &&
|
| + extension.isFromStore;
|
| + this.updateElement_(node, '.corrupted-repair-button', canRepair);
|
| +
|
| + // The 'Enabled' checkbox.
|
| + var isOK = !isTerminated && !canRepair;
|
| + this.updateElement_(node, '.enable-checkbox', isOK, function(item) {
|
| + var enableCheckboxDisabled = extension.managedInstall ||
|
| + extension.suspiciousInstall ||
|
| + extension.corruptInstall ||
|
| + extension.updateRequiredByPolicy ||
|
| + extension.dependentExtensions.length > 0;
|
| + item.querySelector('input').disabled = enableCheckboxDisabled;
|
| + item.querySelector('input').checked = isOK && extension.enabled;
|
| + });
|
| +
|
| + // Button for extensions controlled by policy.
|
| + var controlNode = node.querySelector('.enable-controls');
|
| + if (extension.managedInstall &&
|
| + !controlNode.querySelector('.controlled-extension-indicator')) {
|
| + var indicator = new cr.ui.ControlledIndicator();
|
| + indicator.classList.add('controlled-extension-indicator');
|
| + indicator.setAttribute('controlled-by', 'policy');
|
| + indicator.setAttribute('textpolicy', extension.policyText || '');
|
| + controlNode.appendChild(indicator);
|
| + } else if (!extension.managedInstall) {
|
| + var indicator = controlNode.querySelector(
|
| + '.controlled-extension-indicator');
|
| + if (indicator)
|
| + controlNode.removeChild(indicator);
|
| + }
|
| +
|
| + // Developer mode ////////////////////////////////////////////////////////
|
| +
|
| + // First we have the id.
|
| + var idLabel = node.querySelector('.extension-id');
|
| + idLabel.textContent = ' ' + extension.id;
|
| +
|
| + // Then the path, if provided by unpacked extension.
|
| + this.updateElement_(node, '.load-path', extension.isUnpacked, function() {
|
| + item.querySelector('a:nth-of-type(1)').textContent =
|
| + ' ' + extension.prettifiedPath;
|
| + });
|
| +
|
| + // Then the 'managed, cannot uninstall/disable' message.
|
| + var isRequired = extension.managedInstall || extension.recommendedInstall;
|
| + this.updateElement_(node, '.managed-message', isRequired);
|
| +
|
| + // Then the 'This isn't from the webstore, looks suspicious' message.
|
| + this.updateElement_(node, '.suspicious-install-message', !isRequired &&
|
| + extension.suspiciousInstall);
|
| +
|
| + // Then the 'This is a corrupt extension' message.
|
| + this.updateElement_(node, '.corrupt-install-message', !isRequired &&
|
| + extension.corruptInstall);
|
| +
|
| + // Then the 'An update required by enterprise policy' message. Note that
|
| + // a force-installed extension might be disabled due to being outdated
|
| + // as well.
|
| + this.updateElement_(node, '.update-required-message',
|
| + extension.updateRequiredByPolicy);
|
| + // We would like to hide managed installed message since this
|
| + // extension is disabled.
|
| + this.updateElement_(node, '.managed-message',
|
| + !extension.updateRequiredByPolicy);
|
| +
|
| + // The 'following extensions depend on this extension' list.
|
| + var hasDependents = extension.dependentExtensions.length > 0;
|
| + node.classList.toggle('developer-extras', hasDependents);
|
| + this.updateElement_(node, '.dependent-extensions-message', hasDependents,
|
| + function(item) {
|
| + var dependentList = item.querySelector('ul');
|
| + dependentList.textContent = '';
|
| + var dependentTemplate = $('template-collection').querySelector(
|
| + '.dependent-list-item');
|
| + extension.dependentExtensions.forEach(function(elem) {
|
| + var depNode = dependentTemplate.cloneNode(true);
|
| + depNode.querySelector('.dep-extension-title').textContent =
|
| + elem.name;
|
| + depNode.querySelector('.dep-extension-id').textContent = elem.id;
|
| + dependentList.appendChild(depNode);
|
| + });
|
| + });
|
| +
|
| + // The active views.
|
| + this.updateElement_(node, '.active-views', extension.views.length > 0,
|
| + function(item) {
|
| + var link = item.querySelector('a');
|
| +
|
| + // Link needs to be an only child before the list is updated.
|
| + while (link.nextElementSibling)
|
| + item.removeChild(link.nextElementSibling);
|
| +
|
| + // Link needs to be cleaned up if it was used before.
|
| + link.textContent = '';
|
| + if (link.clickHandler)
|
| + link.removeEventListener('click', link.clickHandler);
|
| +
|
| + extension.views.forEach(function(view, i) {
|
| + var displayName = view.generatedBackgroundPage ?
|
| + loadTimeData.getString('backgroundPage') : view.path;
|
| + var label = displayName +
|
| + (view.incognito ?
|
| + ' ' + loadTimeData.getString('viewIncognito') : '') +
|
| + (view.renderProcessId == -1 ?
|
| + ' ' + loadTimeData.getString('viewInactive') : '');
|
| + link.textContent = label;
|
| + link.clickHandler = function(e) {
|
| + // TODO(estade): remove conversion to string?
|
| + chrome.send('extensionSettingsInspect', [
|
| + String(extension.id),
|
| + String(view.renderProcessId),
|
| + String(view.renderViewId),
|
| + view.incognito
|
| + ]);
|
| + };
|
| + link.addEventListener('click', link.clickHandler);
|
| +
|
| + if (i < extension.views.length - 1) {
|
| + link = link.cloneNode(true);
|
| + item.appendChild(link);
|
| + }
|
| + });
|
| + });
|
| +
|
| + // The extension warnings (describing runtime issues).
|
| + this.updateElement_(node, '.extension-warnings', extension.warnings,
|
| + function(item) {
|
| + var warningList = item.querySelector('ul');
|
| + warningList.textContent = '';
|
| + if (extension.warnings) {
|
| + extension.warnings.forEach(function(warning) {
|
| + var li = document.createElement('li');
|
| + warningList.appendChild(li).innerText = warning;
|
| + });
|
| + }
|
| + });
|
| +
|
| + // If the ErrorConsole is enabled, we should have manifest and/or runtime
|
| + // errors. Otherwise, we may have install warnings. We should not have
|
| + // both ErrorConsole errors and install warnings.
|
| + // Errors.
|
| + this.updateErrors_(node.querySelector('.manifest-errors'),
|
| + extension.manifestErrors);
|
| + this.updateErrors_(node.querySelector('.runtime-errors'),
|
| + extension.runtimeErrors);
|
| +
|
| + // Install warnings.
|
| + this.updateElement_(node, '.install-warnings', extension.installWarnings,
|
| + function(item) {
|
| + var installWarningList = installWarningPanel.querySelector('ul');
|
| + installWarningList.textContent = '';
|
| + if (extension.installWarnings) {
|
| + extension.installWarnings.forEach(function(warning) {
|
| + var li = document.createElement('li');
|
| + li.innerText = warning.message;
|
| + installWarningList.appendChild(li);
|
| + });
|
| + }
|
| + });
|
| +
|
| + if (location.hash.substr(1) == extension.id) {
|
| + // Scroll beneath the fixed header so that the extension is not
|
| + // obscured.
|
| + var topScroll = node.offsetTop - $('page-header').offsetHeight;
|
| + var pad = parseInt(window.getComputedStyle(node, null).marginTop, 10);
|
| + if (!isNaN(pad))
|
| + topScroll -= pad / 2;
|
| + setScrollTopForDocument(document, topScroll);
|
| + }
|
| + },
|
|
|