home *** CD-ROM | disk | FTP | other *** search
Text File | 2013-04-03 | 45.7 KB | 1,383 lines |
- // Copyright (c) 2012 The Chromium Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
-
- // Copyright (c) 2012 The Chromium Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
-
- /**
- * @fileoverview A collection of utility methods for UberPage and its contained
- * pages.
- */
-
- cr.define('uber', function() {
-
- /**
- * Fixed position header elements on the page to be shifted by handleScroll.
- * @type {NodeList}
- */
- var headerElements;
-
- /**
- * This should be called by uber content pages when DOM content has loaded.
- */
- function onContentFrameLoaded() {
- headerElements = document.getElementsByTagName('header');
- document.addEventListener('scroll', handleScroll);
-
- // Trigger the scroll handler to tell the navigation if our page started
- // with some scroll (happens when you use tab restore).
- handleScroll();
-
- window.addEventListener('message', handleWindowMessage);
- }
-
- /**
- * Handles scroll events on the document. This adjusts the position of all
- * headers and updates the parent frame when the page is scrolled.
- * @private
- */
- function handleScroll() {
- var offset = document.body.scrollLeft * -1;
- for (var i = 0; i < headerElements.length; i++)
- headerElements[i].style.webkitTransform = 'translateX(' + offset + 'px)';
-
- invokeMethodOnParent('adjustToScroll', document.body.scrollLeft);
- };
-
- /**
- * Handles 'message' events on window.
- * @param {Event} e The message event.
- */
- function handleWindowMessage(e) {
- if (e.data.method === 'frameSelected')
- handleFrameSelected();
- else if (e.data.method === 'mouseWheel')
- handleMouseWheel(e.data.params);
- }
-
- /**
- * This is called when a user selects this frame via the navigation bar
- * frame (and is triggered via postMessage() from the uber page).
- * @private
- */
- function handleFrameSelected() {
- document.body.scrollLeft = 0;
- }
-
- /**
- * Called when a user mouse wheels (or trackpad scrolls) over the nav frame.
- * The wheel event is forwarded here and we scroll the body.
- * There's no way to figure out the actual scroll amount for a given delta.
- * It differs for every platform and even initWebKitWheelEvent takes a
- * pixel amount instead of a wheel delta. So we just choose something
- * reasonable and hope no one notices the difference.
- * @param {Object} params A structure that holds wheel deltas in X and Y.
- */
- function handleMouseWheel(params) {
- document.body.scrollTop -= params.deltaY * 49 / 120;
- document.body.scrollLeft -= params.deltaX * 49 / 120;
- }
-
- /**
- * Invokes a method on the parent window (UberPage). This is a convenience
- * method for API calls into the uber page.
- * @param {String} method The name of the method to invoke.
- * @param {Object=} opt_params Optional property bag of parameters to pass to
- * the invoked method.
- * @private
- */
- function invokeMethodOnParent(method, opt_params) {
- if (window.location == window.parent.location)
- return;
-
- invokeMethodOnWindow(window.parent, method, opt_params, 'chrome://chrome');
- }
-
- /**
- * Invokes a method on the target window.
- * @param {String} method The name of the method to invoke.
- * @param {Object=} opt_params Optional property bag of parameters to pass to
- * the invoked method.
- * @param {String=} opt_url The origin of the target window.
- * @private
- */
- function invokeMethodOnWindow(targetWindow, method, opt_params, opt_url) {
- var data = {method: method, params: opt_params};
- targetWindow.postMessage(data, opt_url ? opt_url : '*');
- }
-
- return {
- invokeMethodOnParent: invokeMethodOnParent,
- invokeMethodOnWindow: invokeMethodOnWindow,
- onContentFrameLoaded: onContentFrameLoaded,
- };
- });
-
- // Copyright (c) 2012 The Chromium Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
-
- // Copyright (c) 2012 The Chromium Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
-
- cr.define('options', function() {
- 'use strict';
-
- /**
- * Creates a new list of extension commands.
- * @param {Object=} opt_propertyBag Optional properties.
- * @constructor
- * @extends {cr.ui.div}
- */
- var ExtensionCommandList = cr.ui.define('div');
-
- /**
- * Returns whether the passed in |keyCode| is a valid extension command
- * char or not. This is restricted to A-Z and 0-9 (ignoring modifiers) at
- * the moment.
- * @param {int} keyCode The keycode to consider.
- * @return {boolean} Returns whether the char is valid.
- */
- function validChar(keyCode) {
- return (keyCode >= 'A'.charCodeAt(0) && keyCode <= 'Z'.charCodeAt(0)) ||
- (keyCode >= '0'.charCodeAt(0) && keyCode <= '9'.charCodeAt(0));
- }
-
- /**
- * Convert a keystroke event to string form, while taking into account
- * (ignoring) invalid extension commands.
- * @param {Event} event The keyboard event to convert.
- * @return {string} The keystroke as a string.
- */
- function keystrokeToString(event) {
- var output = '';
- if (cr.isMac && event.metaKey)
- output = 'Command+';
- if (event.ctrlKey)
- output = 'Ctrl+';
- if (!event.ctrlKey && event.altKey)
- output += 'Alt+';
- if (event.shiftKey)
- output += 'Shift+';
- if (validChar(event.keyCode))
- output += String.fromCharCode('A'.charCodeAt(0) + event.keyCode - 65);
- return output;
- }
-
- ExtensionCommandList.prototype = {
- __proto__: HTMLDivElement.prototype,
-
- /**
- * While capturing, this records the current (last) keyboard event generated
- * by the user. Will be |null| after capture and during capture when no
- * keyboard event has been generated.
- * @type: {keyboard event}.
- * @private
- */
- currentKeyEvent_: null,
-
- /**
- * While capturing, this keeps track of the previous selection so we can
- * revert back to if no valid assignment is made during capture.
- * @type: {string}.
- * @private
- */
- oldValue_: '',
-
- /**
- * While capturing, this keeps track of which element the user asked to
- * change.
- * @type: {HTMLElement}.
- * @private
- */
- capturingElement_: null,
-
- /** @override */
- decorate: function() {
- this.textContent = '';
-
- // Iterate over the extension data and add each item to the list.
- this.data_.commands.forEach(this.createNodeForExtension_.bind(this));
- },
-
- /**
- * Synthesizes and initializes an HTML element for the extension command
- * metadata given in |extension|.
- * @param {Object} extension A dictionary of extension metadata.
- * @private
- */
- createNodeForExtension_: function(extension) {
- var template = $('template-collection-extension-commands').querySelector(
- '.extension-command-list-extension-item-wrapper');
- var node = template.cloneNode(true);
-
- var title = node.querySelector('.extension-title');
- title.textContent = extension.name;
-
- this.appendChild(node);
-
- // Iterate over the commands data within the extension and add each item
- // to the list.
- extension.commands.forEach(this.createNodeForCommand_.bind(this));
- },
-
- /**
- * Synthesizes and initializes an HTML element for the extension command
- * metadata given in |command|.
- * @param {Object} command A dictionary of extension command metadata.
- * @private
- */
- createNodeForCommand_: function(command) {
- var template = $('template-collection-extension-commands').querySelector(
- '.extension-command-list-command-item-wrapper');
- var node = template.cloneNode(true);
- node.id = this.createElementId_(
- 'command', command.extension_id, command.command_name);
-
- var description = node.querySelector('.command-description');
- description.textContent = command.description;
-
- var shortcutNode = node.querySelector('.command-shortcut-text');
- shortcutNode.addEventListener('mouseup',
- this.startCapture_.bind(this));
- shortcutNode.addEventListener('blur', this.endCapture_.bind(this));
- shortcutNode.addEventListener('keydown',
- this.handleKeyDown_.bind(this));
- shortcutNode.addEventListener('keyup', this.handleKeyUp_.bind(this));
- if (!command.active) {
- shortcutNode.textContent =
- loadTimeData.getString('extensionCommandsInactive');
-
- var commandShortcut = node.querySelector('.command-shortcut');
- commandShortcut.classList.add('inactive-keybinding');
- } else {
- shortcutNode.textContent = command.keybinding;
- }
-
- var commandClear = node.querySelector('.command-clear');
- commandClear.id = this.createElementId_(
- 'clear', command.extension_id, command.command_name);
- commandClear.title = loadTimeData.getString('extensionCommandsDelete');
- commandClear.addEventListener('click', this.handleClear_.bind(this));
-
- this.appendChild(node);
- },
-
- /**
- * Starts keystroke capture to determine which key to use for a particular
- * extension command.
- * @param {Event} event The keyboard event to consider.
- * @private
- */
- startCapture_: function(event) {
- if (this.capturingElement_)
- return; // Already capturing.
-
- chrome.send('setShortcutHandlingSuspended', [true]);
-
- var shortcutNode = event.target;
- this.oldValue_ = shortcutNode.textContent;
- shortcutNode.textContent =
- loadTimeData.getString('extensionCommandsStartTyping');
- shortcutNode.parentElement.classList.add('capturing');
-
- var commandClear =
- shortcutNode.parentElement.querySelector('.command-clear');
- commandClear.hidden = true;
-
- this.capturingElement_ = event.target;
- },
-
- /**
- * Ends keystroke capture and either restores the old value or (if valid
- * value) sets the new value as active..
- * @param {Event} event The keyboard event to consider.
- * @private
- */
- endCapture_: function(event) {
- if (!this.capturingElement_)
- return; // Not capturing.
-
- chrome.send('setShortcutHandlingSuspended', [false]);
-
- var shortcutNode = this.capturingElement_;
- var commandShortcut = shortcutNode.parentElement;
-
- commandShortcut.classList.remove('capturing');
- commandShortcut.classList.remove('contains-chars');
-
- // When the capture ends, the user may have not given a complete and valid
- // input (or even no input at all). Only a valid key event followed by a
- // valid key combination will cause a shortcut selection to be activated.
- // If no valid selection was made, howver, revert back to what the textbox
- // had before to indicate that the shortcut registration was cancelled.
- if (!this.currentKeyEvent_ || !validChar(this.currentKeyEvent_.keyCode))
- shortcutNode.textContent = this.oldValue_;
-
- var commandClear = commandShortcut.querySelector('.command-clear');
- if (this.oldValue_ == '') {
- commandShortcut.classList.remove('clearable');
- commandClear.hidden = true;
- } else {
- commandShortcut.classList.add('clearable');
- commandClear.hidden = false;
- }
-
- this.oldValue_ = '';
- this.capturingElement_ = null;
- this.currentKeyEvent_ = null;
- },
-
- /**
- * The KeyDown handler.
- * @param {Event} event The keyboard event to consider.
- * @private
- */
- handleKeyDown_: function(event) {
- if (!this.capturingElement_)
- this.startCapture_(event);
-
- this.handleKey_(event);
- },
-
- /**
- * The KeyUp handler.
- * @param {Event} event The keyboard event to consider.
- * @private
- */
- handleKeyUp_: function(event) {
- // We want to make it easy to change from Ctrl+Shift+ to just Ctrl+ by
- // releasing Shift, but we also don't want it to be easy to lose for
- // example Ctrl+Shift+F to Ctrl+ just because you didn't release Ctrl
- // as fast as the other two keys. Therefore, we process KeyUp until you
- // have a valid combination and then stop processing it (meaning that once
- // you have a valid combination, we won't change it until the next
- // KeyDown message arrives).
- if (!this.currentKeyEvent_ || !validChar(this.currentKeyEvent_.keyCode)) {
- if (!event.ctrlKey && !event.altKey) {
- // If neither Ctrl nor Alt is pressed then it is not a valid shortcut.
- // That means we're back at the starting point so we should restart
- // capture.
- this.endCapture_(event);
- this.startCapture_(event);
- } else {
- this.handleKey_(event);
- }
- }
- },
-
- /**
- * A general key handler (used for both KeyDown and KeyUp).
- * @param {Event} event The keyboard event to consider.
- * @private
- */
- handleKey_: function(event) {
- // While capturing, we prevent all events from bubbling, to prevent
- // shortcuts lacking the right modifier (F3 for example) from activating
- // and ending capture prematurely.
- event.preventDefault();
- event.stopPropagation();
-
- if (!event.ctrlKey && !event.altKey && (!cr.isMac || !event.metaKey))
- return; // Ctrl or Alt is a must (or Cmd on Mac).
-
- var shortcutNode = this.capturingElement_;
- var keystroke = keystrokeToString(event);
- shortcutNode.textContent = keystroke;
- event.target.classList.add('contains-chars');
-
- if (validChar(event.keyCode)) {
- var node = event.target;
- while (node && !node.id)
- node = node.parentElement;
-
- this.oldValue_ = keystroke; // Forget what the old value was.
- var parsed = this.parseElementId_('command', node.id);
- chrome.send('setExtensionCommandShortcut',
- [parsed.extensionId, parsed.commandName, keystroke]);
- this.endCapture_(event);
- }
-
- this.currentKeyEvent_ = event;
- },
-
- /**
- * A handler for the delete command button.
- * @param {Event} event The mouse event to consider.
- * @private
- */
- handleClear_: function(event) {
- var parsed = this.parseElementId_('clear', event.target.id);
- chrome.send('setExtensionCommandShortcut',
- [parsed.extensionId, parsed.commandName, '']);
- },
-
- /**
- * A utility function to create a unique element id based on a namespace,
- * extension id and a command name.
- * @param {string} namespace The namespace to prepend the id with.
- * @param {string} extensionId The extension ID to use in the id.
- * @param {string} commandName The command name to append the id with.
- * @private
- */
- createElementId_: function(namespace, extensionId, commandName) {
- return namespace + '-' + extensionId + '-' + commandName;
- },
-
- /**
- * A utility function to parse a unique element id based on a namespace,
- * extension id and a command name.
- * @param {string} namespace The namespace to prepend the id with.
- * @param {string} id The id to parse.
- * @return {object} The parsed id, as an object with two members:
- * extensionID and commandName.
- * @private
- */
- parseElementId_: function(namespace, id) {
- var kExtensionIdLength = 32;
- return {
- extensionId: id.substring(namespace.length + 1,
- namespace.length + 1 + kExtensionIdLength),
- commandName: id.substring(namespace.length + 1 + kExtensionIdLength + 1)
- };
- },
- };
-
- return {
- ExtensionCommandList: ExtensionCommandList
- };
- });
-
-
- cr.define('extensions', function() {
- 'use strict';
-
- // The Extension Commands list object that will be used to show the commands
- // on the page.
- var ExtensionCommandList = options.ExtensionCommandList;
-
- /**
- * ExtensionCommandsOverlay class
- * Encapsulated handling of the 'Extension Commands' overlay page.
- * @constructor
- */
- function ExtensionCommandsOverlay() {
- }
-
- cr.addSingletonGetter(ExtensionCommandsOverlay);
-
- ExtensionCommandsOverlay.prototype = {
- /**
- * Initialize the page.
- */
- initializePage: function() {
- var overlay = $('overlay');
- cr.ui.overlay.setupOverlay(overlay);
- overlay.addEventListener('cancelOverlay', this.handleDismiss_.bind(this));
-
- $('extensionCommandsDismiss').addEventListener('click',
- this.handleDismiss_.bind(this));
-
- // This will request the data to show on the page and will get a response
- // back in returnExtensionsData.
- chrome.send('extensionCommandsRequestExtensionsData');
- },
-
- /**
- * Handles a click on the dismiss button.
- * @param {Event} e The click event.
- */
- handleDismiss_: function(e) {
- ExtensionSettings.showOverlay(null);
- },
- };
-
- /**
- * Called by the dom_ui_ to re-populate the page with data representing
- * the current state of extension commands.
- */
- ExtensionCommandsOverlay.returnExtensionsData = function(extensionsData) {
- ExtensionCommandList.prototype.data_ = extensionsData;
- var extensionCommandList = $('extension-command-list');
- ExtensionCommandList.decorate(extensionCommandList);
-
- // Make sure the config link is visible, since there are commands to show
- // and potentially configure.
- document.querySelector('.extension-commands-config').hidden =
- extensionsData.commands.length == 0;
-
- $('no-commands').hidden = extensionsData.commands.length > 0;
- var list = $('extension-command-list');
- if (extensionsData.commands.length == 0)
- list.classList.add('empty-extension-commands-list');
- else
- list.classList.remove('empty-extension-commands-list');
- }
-
- // Export
- return {
- ExtensionCommandsOverlay: ExtensionCommandsOverlay
- };
- });
-
- // Update the C++ call so this isn't necessary.
- var ExtensionCommandsOverlay = extensions.ExtensionCommandsOverlay;
-
- // Copyright (c) 2012 The Chromium Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
-
- cr.define('extensions', function() {
- var FocusManager = cr.ui.FocusManager;
-
- function ExtensionFocusManager() {
- }
-
- cr.addSingletonGetter(ExtensionFocusManager);
-
- ExtensionFocusManager.prototype = {
- __proto__: FocusManager.prototype,
-
- /** @override */
- getFocusParent: function() {
- var overlay = extensions.ExtensionSettings.getCurrentOverlay();
- return overlay || $('extension-settings');
- },
- };
-
- return {
- ExtensionFocusManager: ExtensionFocusManager,
- };
- });
-
- // Copyright (c) 2012 The Chromium Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
-
- cr.define('options', function() {
- 'use strict';
-
- /**
- * A lookup helper function to find the first node that has an id (starting
- * at |node| and going up the parent chain).
- * @param {Element} node The node to start looking at.
- */
- function findIdNode(node) {
- while (node && !node.id) {
- node = node.parentNode;
- }
- return node;
- }
-
- /**
- * Creates a new list of extensions.
- * @param {Object=} opt_propertyBag Optional properties.
- * @constructor
- * @extends {cr.ui.div}
- */
- var ExtensionsList = cr.ui.define('div');
-
- /**
- * @type {Object.<string, boolean>} A map from extension id to a boolean
- * indicating whether the incognito warning is showing. This persists
- * between calls to decorate.
- */
- var butterBarVisibility = {};
-
- ExtensionsList.prototype = {
- __proto__: HTMLDivElement.prototype,
-
- /** @override */
- decorate: function() {
- this.textContent = '';
-
- this.showExtensionNodes_();
- },
-
- getIdQueryParam_: function() {
- return parseQueryParams(document.location)['id'];
- },
-
- /**
- * Creates all extension items from scratch.
- * @private
- */
- showExtensionNodes_: function() {
- // Iterate over the extension data and add each item to the list.
- this.data_.extensions.forEach(this.createNode_, this);
-
- var id_to_highlight = this.getIdQueryParam_();
- if (id_to_highlight) {
- // Scroll offset should be calculated slightly higher than the actual
- // offset of the element being scrolled to, so that it ends up not all
- // the way at the top. That way it is clear that there are more elements
- // above the element being scrolled to.
- var scroll_fudge = 1.2;
- var offset = $(id_to_highlight).offsetTop -
- (scroll_fudge * $(id_to_highlight).clientHeight);
- var wrapper = this.parentNode;
- var list = wrapper.parentNode;
- list.scrollTop = offset;
- }
-
- if (this.data_.extensions.length == 0)
- this.classList.add('empty-extension-list');
- else
- this.classList.remove('empty-extension-list');
- },
-
- /**
- * Synthesizes and initializes an HTML element for the extension metadata
- * given in |extension|.
- * @param {Object} extension A dictionary of extension metadata.
- * @private
- */
- createNode_: function(extension) {
- var template = $('template-collection').querySelector(
- '.extension-list-item-wrapper');
- var node = template.cloneNode(true);
- node.id = extension.id;
-
- if (!extension.enabled || extension.terminated)
- node.classList.add('inactive-extension');
-
- if (!extension.userModifiable)
- node.classList.add('may-not-disable');
-
- var id_to_highlight = this.getIdQueryParam_();
- if (node.id == id_to_highlight)
- node.classList.add('extension-highlight');
-
- var item = node.querySelector('.extension-list-item');
- item.style.backgroundImage = 'url(' + extension.icon + ')';
-
- var title = node.querySelector('.extension-title');
- title.textContent = extension.name;
-
- var version = node.querySelector('.extension-version');
- version.textContent = extension.version;
-
- var disableReason = node.querySelector('.extension-disable-reason');
- disableReason.textContent = extension.disableReason;
-
- var locationText = node.querySelector('.location-text');
- locationText.textContent = extension.locationText;
-
- var description = node.querySelector('.extension-description span');
- description.textContent = extension.description;
-
- // The 'Show Browser Action' button.
- if (extension.enable_show_button) {
- var showButton = node.querySelector('.show-button');
- showButton.addEventListener('click', function(e) {
- chrome.send('extensionSettingsShowButton', [extension.id]);
- });
- showButton.hidden = false;
- }
-
- // The 'allow in incognito' checkbox.
- var incognito = node.querySelector('.incognito-control input');
- incognito.disabled = !extension.incognitoCanBeEnabled;
- incognito.checked = extension.enabledIncognito;
- if (!incognito.disabled) {
- incognito.addEventListener('change', function(e) {
- var checked = e.target.checked;
- butterBarVisibility[extension.id] = checked;
- butterBar.hidden = !checked || extension.is_hosted_app;
- chrome.send('extensionSettingsEnableIncognito',
- [extension.id, String(checked)]);
- });
- }
- var butterBar = node.querySelector('.butter-bar');
- butterBar.hidden = !butterBarVisibility[extension.id];
-
- // The 'allow file:// access' checkbox.
- if (extension.wantsFileAccess) {
- var fileAccess = node.querySelector('.file-access-control');
- fileAccess.addEventListener('click', function(e) {
- chrome.send('extensionSettingsAllowFileAccess',
- [extension.id, String(e.target.checked)]);
- });
- fileAccess.querySelector('input').checked = extension.allowFileAccess;
- fileAccess.hidden = false;
- }
-
- // The 'Options' checkbox.
- if (extension.enabled && extension.optionsUrl) {
- var options = node.querySelector('.options-link');
- options.addEventListener('click', function(e) {
- chrome.send('extensionSettingsOptions', [extension.id]);
- e.preventDefault();
- });
- options.hidden = false;
- }
-
- if (extension.allow_activity) {
- var activity = node.querySelector('.activity-link');
- activity.addEventListener('click', function(e) {
- chrome.send('navigateToUrl', [
- 'chrome://extension-activity?extensionId=' + extension.id,
- '_blank',
- e.button,
- e.altKey,
- e.ctrlKey,
- e.metaKey,
- e.shiftKey
- ]);
- e.preventDefault();
- });
- activity.hidden = false;
- }
-
- // The 'View in Web Store/View Web Site' link.
- if (extension.homepageUrl) {
- var siteLink = node.querySelector('.site-link');
- siteLink.href = extension.homepageUrl;
- siteLink.textContent = loadTimeData.getString(
- extension.homepageProvided ? 'extensionSettingsVisitWebsite' :
- 'extensionSettingsVisitWebStore');
- siteLink.hidden = false;
- }
-
- if (extension.allow_reload) {
- // The 'Reload' link.
- var reload = node.querySelector('.reload-link');
- reload.addEventListener('click', function(e) {
- chrome.send('extensionSettingsReload', [extension.id]);
- });
- reload.hidden = false;
-
- if (extension.is_platform_app) {
- // The 'Launch' link.
- var launch = node.querySelector('.launch-link');
- launch.addEventListener('click', function(e) {
- chrome.send('extensionSettingsLaunch', [extension.id]);
- });
- launch.hidden = false;
-
- // The 'Restart' link.
- var restart = node.querySelector('.restart-link');
- restart.addEventListener('click', function(e) {
- chrome.send('extensionSettingsRestart', [extension.id]);
- });
- restart.hidden = false;
- }
- }
-
- if (!extension.terminated) {
- // The 'Enabled' checkbox.
- var enable = node.querySelector('.enable-checkbox');
- enable.hidden = false;
- enable.querySelector('input').disabled = !extension.userModifiable;
-
- if (extension.userModifiable) {
- enable.addEventListener('click', function(e) {
- chrome.send('extensionSettingsEnable',
- [extension.id, e.target.checked ? 'true' : 'false']);
-
- // This may seem counter-intuitive (to not set/clear the checkmark)
- // but this page will be updated asynchronously if the extension
- // becomes enabled/disabled. It also might not become enabled or
- // disabled, because the user might e.g. get prompted when enabling
- // and choose not to.
- e.preventDefault();
- });
- }
-
- enable.querySelector('input').checked = extension.enabled;
- } else {
- var terminated_reload = node.querySelector('.terminated-reload-link');
- terminated_reload.hidden = false;
- terminated_reload.addEventListener('click', function(e) {
- chrome.send('extensionSettingsReload', [extension.id]);
- });
- }
-
- // 'Remove' button.
- var trashTemplate = $('template-collection').querySelector('.trash');
- var trash = trashTemplate.cloneNode(true);
- trash.title = loadTimeData.getString('extensionUninstall');
- trash.addEventListener('click', function(e) {
- chrome.send('extensionSettingsUninstall', [extension.id]);
- });
- node.querySelector('.enable-controls').appendChild(trash);
-
- // 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.
- if (extension.isUnpacked) {
- var loadPath = node.querySelector('.load-path');
- loadPath.hidden = false;
- loadPath.querySelector('span:nth-of-type(2)').textContent =
- ' ' + extension.path;
- }
-
- // Then the 'managed, cannot uninstall/disable' message.
- if (!extension.userModifiable)
- node.querySelector('.managed-message').hidden = false;
-
- // Then active views.
- if (extension.views.length > 0) {
- var activeViews = node.querySelector('.active-views');
- activeViews.hidden = false;
- var link = activeViews.querySelector('a');
-
- extension.views.forEach(function(view, i) {
- var label = view.path +
- (view.incognito ?
- ' ' + loadTimeData.getString('viewIncognito') : '') +
- (view.renderProcessId == -1 ?
- ' ' + loadTimeData.getString('viewInactive') : '');
- link.textContent = label;
- link.addEventListener('click', function(e) {
- // TODO(estade): remove conversion to string?
- chrome.send('extensionSettingsInspect', [
- String(extension.id),
- String(view.renderProcessId),
- String(view.renderViewId),
- view.incognito
- ]);
- });
-
- if (i < extension.views.length - 1) {
- link = link.cloneNode(true);
- activeViews.appendChild(link);
- }
- });
- }
-
- // The extension warnings (describing runtime issues).
- if (extension.warnings) {
- var panel = node.querySelector('.extension-warnings');
- panel.hidden = false;
- var list = panel.querySelector('ul');
- extension.warnings.forEach(function(warning) {
- list.appendChild(document.createElement('li')).innerText = warning;
- });
- }
-
- // The install warnings.
- if (extension.installWarnings) {
- var panel = node.querySelector('.install-warnings');
- panel.hidden = false;
- var list = panel.querySelector('ul');
- extension.installWarnings.forEach(function(warning) {
- var li = document.createElement('li');
- li[warning.isHTML ? 'innerHTML' : 'innerText'] = warning.message;
- list.appendChild(li);
- });
- }
-
- this.appendChild(node);
- }
- };
-
- return {
- ExtensionsList: ExtensionsList
- };
- });
-
- // Copyright (c) 2012 The Chromium Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
-
- cr.define('extensions', function() {
- /**
- * PackExtensionOverlay class
- * Encapsulated handling of the 'Pack Extension' overlay page.
- * @constructor
- */
- function PackExtensionOverlay() {
- }
-
- cr.addSingletonGetter(PackExtensionOverlay);
-
- PackExtensionOverlay.prototype = {
- /**
- * Initialize the page.
- */
- initializePage: function() {
- var overlay = $('overlay');
- cr.ui.overlay.setupOverlay(overlay);
- overlay.addEventListener('cancelOverlay', this.handleDismiss_.bind(this));
-
- $('packExtensionDismiss').addEventListener('click',
- this.handleDismiss_.bind(this));
- $('packExtensionCommit').addEventListener('click',
- this.handleCommit_.bind(this));
- $('browseExtensionDir').addEventListener('click',
- this.handleBrowseExtensionDir_.bind(this));
- $('browsePrivateKey').addEventListener('click',
- this.handleBrowsePrivateKey_.bind(this));
- },
-
- /**
- * Handles a click on the dismiss button.
- * @param {Event} e The click event.
- */
- handleDismiss_: function(e) {
- ExtensionSettings.showOverlay(null);
- },
-
- /**
- * Handles a click on the pack button.
- * @param {Event} e The click event.
- */
- handleCommit_: function(e) {
- var extensionPath = $('extensionRootDir').value;
- var privateKeyPath = $('extensionPrivateKey').value;
- chrome.send('pack', [extensionPath, privateKeyPath, 0]);
- },
-
- /**
- * Utility function which asks the C++ to show a platform-specific file
- * select dialog, and fire |callback| with the |filePath| that resulted.
- * |selectType| can be either 'file' or 'folder'. |operation| can be 'load'
- * or 'pem' which are signals to the C++ to do some operation-specific
- * configuration.
- * @private
- */
- showFileDialog_: function(selectType, operation, callback) {
- handleFilePathSelected = function(filePath) {
- callback(filePath);
- handleFilePathSelected = function() {};
- };
-
- chrome.send('packExtensionSelectFilePath', [selectType, operation]);
- },
-
- /**
- * Handles the showing of the extension directory browser.
- * @param {Event} e Change event.
- * @private
- */
- handleBrowseExtensionDir_: function(e) {
- this.showFileDialog_('folder', 'load', function(filePath) {
- $('extensionRootDir').value = filePath;
- });
- },
-
- /**
- * Handles the showing of the extension private key file.
- * @param {Event} e Change event.
- * @private
- */
- handleBrowsePrivateKey_: function(e) {
- this.showFileDialog_('file', 'pem', function(filePath) {
- $('extensionPrivateKey').value = filePath;
- });
- },
- };
-
- /**
- * Wrap up the pack process by showing the success |message| and closing
- * the overlay.
- * @param {String} message The message to show to the user.
- */
- PackExtensionOverlay.showSuccessMessage = function(message) {
- alertOverlay.setValues(
- loadTimeData.getString('packExtensionOverlay'),
- message,
- loadTimeData.getString('ok'),
- '',
- function() {
- ExtensionSettings.showOverlay(null);
- },
- null);
- ExtensionSettings.showOverlay($('alertOverlay'));
- };
-
- /**
- * Post an alert overlay showing |message|, and upon acknowledgement, close
- * the alert overlay and return to showing the PackExtensionOverlay.
- */
- PackExtensionOverlay.showError = function(message) {
- alertOverlay.setValues(
- loadTimeData.getString('packExtensionErrorTitle'),
- message,
- loadTimeData.getString('ok'),
- '',
- function() {
- ExtensionSettings.showOverlay($('packExtensionOverlay'));
- },
- null);
- ExtensionSettings.showOverlay($('alertOverlay'));
- };
-
- // Export
- return {
- PackExtensionOverlay: PackExtensionOverlay
- };
- });
-
- // Update the C++ call so this isn't necessary.
- var PackExtensionOverlay = extensions.PackExtensionOverlay;
-
-
- // Used for observing function of the backend datasource for this page by
- // tests.
- var webui_responded_ = false;
-
- cr.define('extensions', function() {
- var ExtensionsList = options.ExtensionsList;
-
- // Implements the DragWrapper handler interface.
- var dragWrapperHandler = {
- // @inheritdoc
- shouldAcceptDrag: function(e) {
- // We can't access filenames during the 'dragenter' event, so we have to
- // wait until 'drop' to decide whether to do something with the file or
- // not.
- // See: http://www.w3.org/TR/2011/WD-html5-20110113/dnd.html#concept-dnd-p
- return e.dataTransfer.types.indexOf('Files') > -1;
- },
- // @inheritdoc
- doDragEnter: function() {
- chrome.send('startDrag');
- ExtensionSettings.showOverlay(null);
- ExtensionSettings.showOverlay($('dropTargetOverlay'));
- },
- // @inheritdoc
- doDragLeave: function() {
- ExtensionSettings.showOverlay(null);
- chrome.send('stopDrag');
- },
- // @inheritdoc
- doDragOver: function(e) {
- e.preventDefault();
- },
- // @inheritdoc
- doDrop: function(e) {
- // Only process files that look like extensions. Other files should
- // navigate the browser normally.
- if (!e.dataTransfer.files.length ||
- !/\.(crx|user\.js)$/.test(e.dataTransfer.files[0].name)) {
- return;
- }
-
- chrome.send('installDroppedFile');
- ExtensionSettings.showOverlay(null);
- e.preventDefault();
- }
- };
-
- /**
- * ExtensionSettings class
- * @class
- */
- function ExtensionSettings() {}
-
- cr.addSingletonGetter(ExtensionSettings);
-
- ExtensionSettings.prototype = {
- __proto__: HTMLDivElement.prototype,
-
- /**
- * Perform initial setup.
- */
- initialize: function() {
- uber.onContentFrameLoaded();
-
- measureCheckboxStrings();
-
- // Set the title.
- var title = loadTimeData.getString('extensionSettings');
- uber.invokeMethodOnParent('setTitle', {title: title});
-
- // This will request the data to show on the page and will get a response
- // back in returnExtensionsData.
- chrome.send('extensionSettingsRequestExtensionsData');
-
- $('toggle-dev-on').addEventListener('change',
- this.handleToggleDevMode_.bind(this));
- $('dev-controls').addEventListener('webkitTransitionEnd',
- this.handleDevControlsTransitionEnd_.bind(this));
-
- // Set up the three dev mode buttons (load unpacked, pack and update).
- $('load-unpacked').addEventListener('click',
- this.handleLoadUnpackedExtension_.bind(this));
- $('pack-extension').addEventListener('click',
- this.handlePackExtension_.bind(this));
- $('update-extensions-now').addEventListener('click',
- this.handleUpdateExtensionNow_.bind(this));
-
- if (!loadTimeData.getBoolean('offStoreInstallEnabled')) {
- this.dragWrapper_ = new cr.ui.DragWrapper(document.documentElement,
- dragWrapperHandler);
- }
-
- var packExtensionOverlay = extensions.PackExtensionOverlay.getInstance();
- packExtensionOverlay.initializePage();
-
- // Hook up the configure commands link to the overlay.
- var link = document.querySelector('.extension-commands-config');
- link.addEventListener('click',
- this.handleExtensionCommandsConfig_.bind(this));
-
- // Initialize the Commands overlay.
- var extensionCommandsOverlay =
- extensions.ExtensionCommandsOverlay.getInstance();
- extensionCommandsOverlay.initializePage();
-
- cr.ui.overlay.setupOverlay($('dropTargetOverlay'));
-
- extensions.ExtensionFocusManager.getInstance().initialize();
-
- var path = document.location.pathname;
- if (path.length > 1) {
- // Skip starting slash and remove trailing slash (if any).
- var overlayName = path.slice(1).replace(/\/$/, '');
- if (overlayName == 'configureCommands')
- this.showExtensionCommandsConfigUi_();
- }
-
- preventDefaultOnPoundLinkClicks(); // From shared/js/util.js.
- },
-
- /**
- * Handles the Load Unpacked Extension button.
- * @param {Event} e Change event.
- * @private
- */
- handleLoadUnpackedExtension_: function(e) {
- chrome.send('extensionSettingsLoadUnpackedExtension');
-
- // TODO(jhawkins): Refactor metrics support out of options and use it
- // in extensions.html.
- chrome.send('coreOptionsUserMetricsAction',
- ['Options_LoadUnpackedExtension']);
- },
-
- /**
- * Handles the Pack Extension button.
- * @param {Event} e Change event.
- * @private
- */
- handlePackExtension_: function(e) {
- ExtensionSettings.showOverlay($('packExtensionOverlay'));
- chrome.send('coreOptionsUserMetricsAction', ['Options_PackExtension']);
- },
-
- /**
- * Shows the Extension Commands configuration UI.
- * @param {Event} e Change event.
- * @private
- */
- showExtensionCommandsConfigUi_: function(e) {
- ExtensionSettings.showOverlay($('extensionCommandsOverlay'));
- chrome.send('coreOptionsUserMetricsAction',
- ['Options_ExtensionCommands']);
- },
-
- /**
- * Handles the Configure (Extension) Commands link.
- * @param {Event} e Change event.
- * @private
- */
- handleExtensionCommandsConfig_: function(e) {
- this.showExtensionCommandsConfigUi_();
- },
-
- /**
- * Handles the Update Extension Now button.
- * @param {Event} e Change event.
- * @private
- */
- handleUpdateExtensionNow_: function(e) {
- chrome.send('extensionSettingsAutoupdate');
- },
-
- /**
- * Handles the Toggle Dev Mode button.
- * @param {Event} e Change event.
- * @private
- */
- handleToggleDevMode_: function(e) {
- if ($('toggle-dev-on').checked) {
- $('dev-controls').hidden = false;
- window.setTimeout(function() {
- $('extension-settings').classList.add('dev-mode');
- }, 0);
- } else {
- $('extension-settings').classList.remove('dev-mode');
- }
-
- chrome.send('extensionSettingsToggleDeveloperMode');
- },
-
- /**
- * Called when a transition has ended for #dev-controls.
- * @param {Event} e webkitTransitionEnd event.
- * @private
- */
- handleDevControlsTransitionEnd_: function(e) {
- if (e.propertyName == 'height' &&
- !$('extension-settings').classList.contains('dev-mode')) {
- $('dev-controls').hidden = true;
- }
- },
- };
-
- /**
- * Called by the dom_ui_ to re-populate the page with data representing
- * the current state of installed extensions.
- */
- ExtensionSettings.returnExtensionsData = function(extensionsData) {
- // We can get called many times in short order, thus we need to
- // be careful to remove the 'finished loading' timeout.
- if (this.loadingTimeout_)
- window.clearTimeout(this.loadingTimeout_);
- document.documentElement.classList.add('loading');
- this.loadingTimeout_ = window.setTimeout(function() {
- document.documentElement.classList.remove('loading');
- }, 0);
-
- webui_responded_ = true;
-
- if (extensionsData.extensions.length > 0) {
- // Enforce order specified in the data or (if equal) then sort by
- // extension name (case-insensitive).
- extensionsData.extensions.sort(function(a, b) {
- if (a.order == b.order) {
- a = a.name.toLowerCase();
- b = b.name.toLowerCase();
- return a < b ? -1 : (a > b ? 1 : 0);
- } else {
- return a.order < b.order ? -1 : 1;
- }
- });
- }
-
- var pageDiv = $('extension-settings');
- var marginTop = 0;
- if (extensionsData.managedMode) {
- pageDiv.classList.add('showing-banner');
- pageDiv.classList.add('managed-mode');
- $('toggle-dev-on').disabled = true;
- marginTop += 45;
- } else {
- pageDiv.classList.remove('showing-banner');
- pageDiv.classList.remove('managed-mode');
- $('toggle-dev-on').disabled = false;
- }
-
- if (extensionsData.showDisabledExtensionsWarning) {
- pageDiv.classList.add('showing-banner');
- pageDiv.classList.add('sideload-wipeout');
- marginTop += 60;
- }
- pageDiv.style.marginTop = marginTop + 'px';
-
- if (extensionsData.developerMode && !extensionsData.managedMode) {
- pageDiv.classList.add('dev-mode');
- $('toggle-dev-on').checked = true;
- $('dev-controls').hidden = false;
- } else {
- pageDiv.classList.remove('dev-mode');
- $('toggle-dev-on').checked = false;
- }
-
- $('load-unpacked').disabled = extensionsData.loadUnpackedDisabled;
-
- ExtensionsList.prototype.data_ = extensionsData;
- var extensionList = $('extension-settings-list');
- ExtensionsList.decorate(extensionList);
- }
-
- // Indicate that warning |message| has occured for pack of |crx_path| and
- // |pem_path| files. Ask if user wants override the warning. Send
- // |overrideFlags| to repeated 'pack' call to accomplish the override.
- ExtensionSettings.askToOverrideWarning =
- function(message, crx_path, pem_path, overrideFlags) {
- var closeAlert = function() {
- ExtensionSettings.showOverlay(null);
- };
-
- alertOverlay.setValues(
- loadTimeData.getString('packExtensionWarningTitle'),
- message,
- loadTimeData.getString('packExtensionProceedAnyway'),
- loadTimeData.getString('cancel'),
- function() {
- chrome.send('pack', [crx_path, pem_path, overrideFlags]);
- closeAlert();
- },
- closeAlert);
- ExtensionSettings.showOverlay($('alertOverlay'));
- }
-
- /**
- * Returns the current overlay or null if one does not exist.
- * @return {Element} The overlay element.
- */
- ExtensionSettings.getCurrentOverlay = function() {
- return document.querySelector('#overlay .page.showing');
- }
-
- /**
- * Sets the given overlay to show. This hides whatever overlay is currently
- * showing, if any.
- * @param {HTMLElement} node The overlay page to show. If falsey, all overlays
- * are hidden.
- */
- ExtensionSettings.showOverlay = function(node) {
- var currentlyShowingOverlay = ExtensionSettings.getCurrentOverlay();
- if (currentlyShowingOverlay)
- currentlyShowingOverlay.classList.remove('showing');
-
- if (node)
- node.classList.add('showing');
- overlay.hidden = !node;
- uber.invokeMethodOnParent(node ? 'beginInterceptingEvents' :
- 'stopInterceptingEvents');
- }
-
- /**
- * Utility function to find the width of various UI strings and synchronize
- * the width of relevant spans. This is crucial for making sure the
- * Enable/Enabled checkboxes align, as well as the Developer Mode checkbox.
- */
- function measureCheckboxStrings() {
- var trashWidth = 30;
- var measuringDiv = $('font-measuring-div');
- measuringDiv.textContent =
- loadTimeData.getString('extensionSettingsEnabled');
- var pxWidth = measuringDiv.clientWidth + trashWidth;
- measuringDiv.textContent =
- loadTimeData.getString('extensionSettingsEnable');
- pxWidth = Math.max(measuringDiv.clientWidth + trashWidth, pxWidth);
- measuringDiv.textContent =
- loadTimeData.getString('extensionSettingsDeveloperMode');
- pxWidth = Math.max(measuringDiv.clientWidth, pxWidth);
-
- var style = document.createElement('style');
- style.type = 'text/css';
- style.textContent =
- '.enable-checkbox-text {' +
- ' min-width: ' + (pxWidth - trashWidth) + 'px;' +
- '}' +
- '#dev-toggle span {' +
- ' min-width: ' + pxWidth + 'px;' +
- '}';
- document.querySelector('head').appendChild(style);
- }
-
- // Export
- return {
- ExtensionSettings: ExtensionSettings
- };
- });
-
- var ExtensionSettings = extensions.ExtensionSettings;
-
- window.addEventListener('load', function(e) {
- ExtensionSettings.getInstance().initialize();
- });
-