| OLD | NEW |
| (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 var toRemove = ['policy-controlled', 'may-not-modify', 'may-not-remove']; |
| 14 node.classList.remove.apply(node.classList, toRemove); |
| 15 var classes = []; |
| 16 if (extension.managedInstall) { |
| 17 classes.push('policy-controlled', 'may-not-modify'); |
| 18 } else if (extension.dependentExtensions.length > 0) { |
| 19 classes.push('may-not-remove', 'may-not-modify'); |
| 20 } else if (extension.recommendedInstall) { |
| 21 classes.push('may-not-remove'); |
| 22 } else if (extension.suspiciousInstall || |
| 23 extension.corruptInstall || |
| 24 extension.updateRequiredByPolicy) { |
| 25 classes.push('may-not-modify'); |
| 26 } |
| 27 node.classList.add.apply(node.classList, classes); |
| 28 |
| 29 node.classList.toggle('extension-highlight', |
| 30 node.id == this.getIdQueryParam_()); |
| 31 |
| 32 var item = node.querySelector('.extension-list-item'); |
| 33 // Prevent the image cache of extension icon by using the reloaded |
| 34 // timestamp as a query string. The timestamp is recorded when the user |
| 35 // clicks the 'Reload' link. http://crbug.com/159302. |
| 36 if (extensionReloadedTimestamp[extension.id]) { |
| 37 item.style.backgroundImage = |
| 38 'url(' + extension.icon + '?' + |
| 39 extensionReloadedTimestamp[extension.id] + ')'; |
| 40 } else { |
| 41 item.style.backgroundImage = 'url(' + extension.icon + ')'; |
| 42 } |
| 43 |
| 44 this.setTextContent_(node, '.extension-title', extension.name); |
| 45 this.setTextContent_(node, '.extension-version', extension.version); |
| 46 this.setTextContent_(node, '.location-text', extension.locationText); |
| 47 this.setTextContent_(node, '.blacklist-text', extension.blacklistText); |
| 48 this.setTextContent_(node, '.extension-description', |
| 49 extension.description); |
| 50 |
| 51 // The 'Show Browser Action' button. |
| 52 this.updateElement_(node, '.show-button', extension.enable_show_button); |
| 53 |
| 54 // The 'allow in incognito' checkbox. |
| 55 this.updateElement_(node, '.incognito-control', |
| 56 this.data_.incognitoAvailable, function(item) { |
| 57 var incognito = item.querySelector('input'); |
| 58 incognito.disabled = !extension.incognitoCanBeEnabled; |
| 59 incognito.checked = extension.enabledIncognito; |
| 60 }); |
| 61 |
| 62 // Only show the butterbar once. |
| 63 butterBarVisibility[extension.id] = butterBarVisibility[extension.id] && |
| 64 extension.enabledIncognito; |
| 65 this.updateElement_(node, '.butter-bar', |
| 66 butterBarVisibility[extension.id]); |
| 67 |
| 68 // The 'collect errors' checkbox. This should only be visible if the |
| 69 // error console is enabled - we can detect this by the existence of the |
| 70 // |errorCollectionEnabled| property. |
| 71 this.updateElement_(node, '.error-collection-control', |
| 72 extension.wantsErrorCollection, function(item) { |
| 73 item.querySelector('input').checked = extension.errorCollectionEnabled; |
| 74 }); |
| 75 |
| 76 // The 'allow on all urls' checkbox. This should only be visible if |
| 77 // active script restrictions are enabled. If they are not enabled, no |
| 78 // extensions should want all urls. |
| 79 this.updateElement_(node, '.all-urls-control', extension.wantsAllUrls, |
| 80 function(item) { |
| 81 item.querySelector('input').checked = extension.allowAllUrls; |
| 82 }); |
| 83 |
| 84 // The 'allow file:// access' checkbox. |
| 85 this.updateElement_(node, '.file-access-control', |
| 86 extension.wantsFileAccess, function(item) { |
| 87 item.querySelector('input').checked = extension.allowFileAccess; |
| 88 }); |
| 89 |
| 90 // The 'Options' button or link, depending on its behaviour. |
| 91 var optionsEnabled = extension.enabled && extension.optionsUrl; |
| 92 this.updateElement_(node, '.options-link', optionsEnabled && |
| 93 extension.optionsOpenInTab); |
| 94 this.updateElement_(node, '.options-button', optionsEnabled && |
| 95 !extension.optionsOpenInTab); |
| 96 |
| 97 // The 'View in Web Store/View Web Site' link. |
| 98 var siteLinkEnabled = extension.homepageUrl && |
| 99 !extension.enableExtensionInfoDialog; |
| 100 this.updateElement_(node, '.site-link', siteLinkEnabled, function(item) { |
| 101 item.href = extension.homepageUrl; |
| 102 item.textContent = loadTimeData.getString( |
| 103 extension.homepageProvided ? 'extensionSettingsVisitWebsite' : |
| 104 'extensionSettingsVisitWebStore'); |
| 105 }); |
| 106 |
| 107 // The 'Reload' link. |
| 108 this.updateElement_(node, '.reload-link', extension.allow_reload); |
| 109 |
| 110 // The 'Launch' link. |
| 111 this.updateElement_(node, '.launch-link', extension.allow_reload && |
| 112 extension.is_platform_app); |
| 113 |
| 114 // The 'Reload' terminated link. |
| 115 var isTerminated = extension.terminated; |
| 116 this.updateElement_(node, '.terminated-reload-link', isTerminated); |
| 117 |
| 118 // The 'Repair' corrupted link. |
| 119 var canRepair = !isTerminated && extension.corruptInstall && |
| 120 extension.isFromStore; |
| 121 this.updateElement_(node, '.corrupted-repair-button', canRepair); |
| 122 |
| 123 // The 'Enabled' checkbox. |
| 124 var isOK = !isTerminated && !canRepair; |
| 125 this.updateElement_(node, '.enable-checkbox', isOK, function(item) { |
| 126 var enableCheckboxDisabled = extension.managedInstall || |
| 127 extension.suspiciousInstall || |
| 128 extension.corruptInstall || |
| 129 extension.updateRequiredByPolicy || |
| 130 extension.dependentExtensions.length > 0; |
| 131 item.querySelector('input').disabled = enableCheckboxDisabled; |
| 132 item.querySelector('input').checked = isOK && extension.enabled; |
| 133 }); |
| 134 |
| 135 // Button for extensions controlled by policy. |
| 136 var controlNode = node.querySelector('.enable-controls'); |
| 137 if (extension.managedInstall && |
| 138 !controlNode.querySelector('.controlled-extension-indicator')) { |
| 139 var indicator = new cr.ui.ControlledIndicator(); |
| 140 indicator.classList.add('controlled-extension-indicator'); |
| 141 indicator.setAttribute('controlled-by', 'policy'); |
| 142 indicator.setAttribute('textpolicy', extension.policyText || ''); |
| 143 controlNode.appendChild(indicator); |
| 144 } else if (!extension.managedInstall) { |
| 145 var indicator = controlNode.querySelector( |
| 146 '.controlled-extension-indicator'); |
| 147 if (indicator) |
| 148 controlNode.removeChild(indicator); |
| 149 } |
| 150 |
| 151 // Developer mode //////////////////////////////////////////////////////// |
| 152 |
| 153 // First we have the id. |
| 154 var idLabel = node.querySelector('.extension-id'); |
| 155 idLabel.textContent = ' ' + extension.id; |
| 156 |
| 157 // Then the path, if provided by unpacked extension. |
| 158 this.updateElement_(node, '.load-path', extension.isUnpacked, function() { |
| 159 item.querySelector('a:nth-of-type(1)').textContent = |
| 160 ' ' + extension.prettifiedPath; |
| 161 }); |
| 162 |
| 163 // Then the 'managed, cannot uninstall/disable' message. |
| 164 var isRequired = extension.managedInstall || extension.recommendedInstall; |
| 165 this.updateElement_(node, '.managed-message', isRequired); |
| 166 |
| 167 // Then the 'This isn't from the webstore, looks suspicious' message. |
| 168 this.updateElement_(node, '.suspicious-install-message', !isRequired && |
| 169 extension.suspiciousInstall); |
| 170 |
| 171 // Then the 'This is a corrupt extension' message. |
| 172 this.updateElement_(node, '.corrupt-install-message', !isRequired && |
| 173 extension.corruptInstall); |
| 174 |
| 175 // Then the 'An update required by enterprise policy' message. Note that |
| 176 // a force-installed extension might be disabled due to being outdated |
| 177 // as well. |
| 178 this.updateElement_(node, '.update-required-message', |
| 179 extension.updateRequiredByPolicy); |
| 180 // We would like to hide managed installed message since this |
| 181 // extension is disabled. |
| 182 this.updateElement_(node, '.managed-message', |
| 183 !extension.updateRequiredByPolicy); |
| 184 |
| 185 // The 'following extensions depend on this extension' list. |
| 186 var hasDependents = extension.dependentExtensions.length > 0; |
| 187 node.classList.toggle('developer-extras', hasDependents); |
| 188 this.updateElement_(node, '.dependent-extensions-message', hasDependents, |
| 189 function(item) { |
| 190 var dependentList = item.querySelector('ul'); |
| 191 dependentList.textContent = ''; |
| 192 var dependentTemplate = $('template-collection').querySelector( |
| 193 '.dependent-list-item'); |
| 194 extension.dependentExtensions.forEach(function(elem) { |
| 195 var depNode = dependentTemplate.cloneNode(true); |
| 196 depNode.querySelector('.dep-extension-title').textContent = |
| 197 elem.name; |
| 198 depNode.querySelector('.dep-extension-id').textContent = elem.id; |
| 199 dependentList.appendChild(depNode); |
| 200 }); |
| 201 }); |
| 202 |
| 203 // The active views. |
| 204 this.updateElement_(node, '.active-views', extension.views.length > 0, |
| 205 function(item) { |
| 206 var link = item.querySelector('a'); |
| 207 |
| 208 // Link needs to be an only child before the list is updated. |
| 209 while (link.nextElementSibling) |
| 210 item.removeChild(link.nextElementSibling); |
| 211 |
| 212 // Link needs to be cleaned up if it was used before. |
| 213 link.textContent = ''; |
| 214 if (link.clickHandler) |
| 215 link.removeEventListener('click', link.clickHandler); |
| 216 |
| 217 extension.views.forEach(function(view, i) { |
| 218 var displayName = view.generatedBackgroundPage ? |
| 219 loadTimeData.getString('backgroundPage') : view.path; |
| 220 var label = displayName + |
| 221 (view.incognito ? |
| 222 ' ' + loadTimeData.getString('viewIncognito') : '') + |
| 223 (view.renderProcessId == -1 ? |
| 224 ' ' + loadTimeData.getString('viewInactive') : ''); |
| 225 link.textContent = label; |
| 226 link.clickHandler = function(e) { |
| 227 // TODO(estade): remove conversion to string? |
| 228 chrome.send('extensionSettingsInspect', [ |
| 229 String(extension.id), |
| 230 String(view.renderProcessId), |
| 231 String(view.renderViewId), |
| 232 view.incognito |
| 233 ]); |
| 234 }; |
| 235 link.addEventListener('click', link.clickHandler); |
| 236 |
| 237 if (i < extension.views.length - 1) { |
| 238 link = link.cloneNode(true); |
| 239 item.appendChild(link); |
| 240 } |
| 241 }); |
| 242 }); |
| 243 |
| 244 // The extension warnings (describing runtime issues). |
| 245 this.updateElement_(node, '.extension-warnings', extension.warnings, |
| 246 function(item) { |
| 247 var warningList = item.querySelector('ul'); |
| 248 warningList.textContent = ''; |
| 249 if (extension.warnings) { |
| 250 extension.warnings.forEach(function(warning) { |
| 251 var li = document.createElement('li'); |
| 252 warningList.appendChild(li).innerText = warning; |
| 253 }); |
| 254 } |
| 255 }); |
| 256 |
| 257 // If the ErrorConsole is enabled, we should have manifest and/or runtime |
| 258 // errors. Otherwise, we may have install warnings. We should not have |
| 259 // both ErrorConsole errors and install warnings. |
| 260 // Errors. |
| 261 this.updateErrors_(node.querySelector('.manifest-errors'), |
| 262 extension.manifestErrors); |
| 263 this.updateErrors_(node.querySelector('.runtime-errors'), |
| 264 extension.runtimeErrors); |
| 265 |
| 266 // Install warnings. |
| 267 this.updateElement_(node, '.install-warnings', extension.installWarnings, |
| 268 function(item) { |
| 269 var installWarningList = installWarningPanel.querySelector('ul'); |
| 270 installWarningList.textContent = ''; |
| 271 if (extension.installWarnings) { |
| 272 extension.installWarnings.forEach(function(warning) { |
| 273 var li = document.createElement('li'); |
| 274 li.innerText = warning.message; |
| 275 installWarningList.appendChild(li); |
| 276 }); |
| 277 } |
| 278 }); |
| 279 |
| 280 if (location.hash.substr(1) == extension.id) { |
| 281 // Scroll beneath the fixed header so that the extension is not |
| 282 // obscured. |
| 283 var topScroll = node.offsetTop - $('page-header').offsetHeight; |
| 284 var pad = parseInt(window.getComputedStyle(node, null).marginTop, 10); |
| 285 if (!isNaN(pad)) |
| 286 topScroll -= pad / 2; |
| 287 setScrollTopForDocument(document, topScroll); |
| 288 } |
| 289 }, |
| OLD | NEW |