home *** CD-ROM | disk | FTP | other *** search
/ Freelog 115 / FreelogNo115-MaiJuin2013.iso / Internet / AvantBrowser / asetup.exe / _data / webkit / chrome.dll / 0 / BINDATA / 526 < prev    next >
Encoding:
Text File  |  2013-04-03  |  11.5 KB  |  332 lines

  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.
  4.  
  5. cr.define('options', function() {
  6.   'use strict';
  7.  
  8.   /**
  9.    * Creates a new list of extension commands.
  10.    * @param {Object=} opt_propertyBag Optional properties.
  11.    * @constructor
  12.    * @extends {cr.ui.div}
  13.    */
  14.   var ExtensionCommandList = cr.ui.define('div');
  15.  
  16.   /**
  17.    * Returns whether the passed in |keyCode| is a valid extension command
  18.    * char or not. This is restricted to A-Z and 0-9 (ignoring modifiers) at
  19.    * the moment.
  20.    * @param {int} keyCode The keycode to consider.
  21.    * @return {boolean} Returns whether the char is valid.
  22.    */
  23.   function validChar(keyCode) {
  24.     return (keyCode >= 'A'.charCodeAt(0) && keyCode <= 'Z'.charCodeAt(0)) ||
  25.            (keyCode >= '0'.charCodeAt(0) && keyCode <= '9'.charCodeAt(0));
  26.   }
  27.  
  28.   /**
  29.    * Convert a keystroke event to string form, while taking into account
  30.    * (ignoring) invalid extension commands.
  31.    * @param {Event} event The keyboard event to convert.
  32.    * @return {string} The keystroke as a string.
  33.    */
  34.   function keystrokeToString(event) {
  35.     var output = '';
  36.     if (cr.isMac && event.metaKey)
  37.       output = 'Command+';
  38.     if (event.ctrlKey)
  39.       output = 'Ctrl+';
  40.     if (!event.ctrlKey && event.altKey)
  41.       output += 'Alt+';
  42.     if (event.shiftKey)
  43.       output += 'Shift+';
  44.     if (validChar(event.keyCode))
  45.       output += String.fromCharCode('A'.charCodeAt(0) + event.keyCode - 65);
  46.     return output;
  47.   }
  48.  
  49.   ExtensionCommandList.prototype = {
  50.     __proto__: HTMLDivElement.prototype,
  51.  
  52.     /**
  53.      * While capturing, this records the current (last) keyboard event generated
  54.      * by the user. Will be |null| after capture and during capture when no
  55.      * keyboard event has been generated.
  56.      * @type: {keyboard event}.
  57.      * @private
  58.      */
  59.     currentKeyEvent_: null,
  60.  
  61.     /**
  62.      * While capturing, this keeps track of the previous selection so we can
  63.      * revert back to if no valid assignment is made during capture.
  64.      * @type: {string}.
  65.      * @private
  66.      */
  67.     oldValue_: '',
  68.  
  69.     /**
  70.      * While capturing, this keeps track of which element the user asked to
  71.      * change.
  72.      * @type: {HTMLElement}.
  73.      * @private
  74.      */
  75.     capturingElement_: null,
  76.  
  77.     /** @override */
  78.     decorate: function() {
  79.       this.textContent = '';
  80.  
  81.       // Iterate over the extension data and add each item to the list.
  82.       this.data_.commands.forEach(this.createNodeForExtension_.bind(this));
  83.     },
  84.  
  85.     /**
  86.      * Synthesizes and initializes an HTML element for the extension command
  87.      * metadata given in |extension|.
  88.      * @param {Object} extension A dictionary of extension metadata.
  89.      * @private
  90.      */
  91.     createNodeForExtension_: function(extension) {
  92.       var template = $('template-collection-extension-commands').querySelector(
  93.           '.extension-command-list-extension-item-wrapper');
  94.       var node = template.cloneNode(true);
  95.  
  96.       var title = node.querySelector('.extension-title');
  97.       title.textContent = extension.name;
  98.  
  99.       this.appendChild(node);
  100.  
  101.       // Iterate over the commands data within the extension and add each item
  102.       // to the list.
  103.       extension.commands.forEach(this.createNodeForCommand_.bind(this));
  104.     },
  105.  
  106.     /**
  107.      * Synthesizes and initializes an HTML element for the extension command
  108.      * metadata given in |command|.
  109.      * @param {Object} command A dictionary of extension command metadata.
  110.      * @private
  111.      */
  112.     createNodeForCommand_: function(command) {
  113.       var template = $('template-collection-extension-commands').querySelector(
  114.           '.extension-command-list-command-item-wrapper');
  115.       var node = template.cloneNode(true);
  116.       node.id = this.createElementId_(
  117.           'command', command.extension_id, command.command_name);
  118.  
  119.       var description = node.querySelector('.command-description');
  120.       description.textContent = command.description;
  121.  
  122.       var shortcutNode = node.querySelector('.command-shortcut-text');
  123.       shortcutNode.addEventListener('mouseup',
  124.                                     this.startCapture_.bind(this));
  125.       shortcutNode.addEventListener('blur', this.endCapture_.bind(this));
  126.       shortcutNode.addEventListener('keydown',
  127.                                     this.handleKeyDown_.bind(this));
  128.       shortcutNode.addEventListener('keyup', this.handleKeyUp_.bind(this));
  129.       if (!command.active) {
  130.         shortcutNode.textContent =
  131.             loadTimeData.getString('extensionCommandsInactive');
  132.  
  133.         var commandShortcut = node.querySelector('.command-shortcut');
  134.         commandShortcut.classList.add('inactive-keybinding');
  135.       } else {
  136.         shortcutNode.textContent = command.keybinding;
  137.       }
  138.  
  139.       var commandClear = node.querySelector('.command-clear');
  140.       commandClear.id = this.createElementId_(
  141.           'clear', command.extension_id, command.command_name);
  142.       commandClear.title = loadTimeData.getString('extensionCommandsDelete');
  143.       commandClear.addEventListener('click', this.handleClear_.bind(this));
  144.  
  145.       this.appendChild(node);
  146.     },
  147.  
  148.     /**
  149.      * Starts keystroke capture to determine which key to use for a particular
  150.      * extension command.
  151.      * @param {Event} event The keyboard event to consider.
  152.      * @private
  153.      */
  154.     startCapture_: function(event) {
  155.       if (this.capturingElement_)
  156.         return;  // Already capturing.
  157.  
  158.       chrome.send('setShortcutHandlingSuspended', [true]);
  159.  
  160.       var shortcutNode = event.target;
  161.       this.oldValue_ = shortcutNode.textContent;
  162.       shortcutNode.textContent =
  163.           loadTimeData.getString('extensionCommandsStartTyping');
  164.       shortcutNode.parentElement.classList.add('capturing');
  165.  
  166.       var commandClear =
  167.           shortcutNode.parentElement.querySelector('.command-clear');
  168.       commandClear.hidden = true;
  169.  
  170.       this.capturingElement_ = event.target;
  171.     },
  172.  
  173.     /**
  174.      * Ends keystroke capture and either restores the old value or (if valid
  175.      * value) sets the new value as active..
  176.      * @param {Event} event The keyboard event to consider.
  177.      * @private
  178.      */
  179.     endCapture_: function(event) {
  180.       if (!this.capturingElement_)
  181.         return;  // Not capturing.
  182.  
  183.       chrome.send('setShortcutHandlingSuspended', [false]);
  184.  
  185.       var shortcutNode = this.capturingElement_;
  186.       var commandShortcut = shortcutNode.parentElement;
  187.  
  188.       commandShortcut.classList.remove('capturing');
  189.       commandShortcut.classList.remove('contains-chars');
  190.  
  191.       // When the capture ends, the user may have not given a complete and valid
  192.       // input (or even no input at all). Only a valid key event followed by a
  193.       // valid key combination will cause a shortcut selection to be activated.
  194.       // If no valid selection was made, howver, revert back to what the textbox
  195.       // had before to indicate that the shortcut registration was cancelled.
  196.       if (!this.currentKeyEvent_ || !validChar(this.currentKeyEvent_.keyCode))
  197.         shortcutNode.textContent = this.oldValue_;
  198.  
  199.       var commandClear = commandShortcut.querySelector('.command-clear');
  200.       if (this.oldValue_ == '') {
  201.         commandShortcut.classList.remove('clearable');
  202.         commandClear.hidden = true;
  203.       } else {
  204.         commandShortcut.classList.add('clearable');
  205.         commandClear.hidden = false;
  206.       }
  207.  
  208.       this.oldValue_ = '';
  209.       this.capturingElement_ = null;
  210.       this.currentKeyEvent_ = null;
  211.     },
  212.  
  213.     /**
  214.      * The KeyDown handler.
  215.      * @param {Event} event The keyboard event to consider.
  216.      * @private
  217.      */
  218.     handleKeyDown_: function(event) {
  219.       if (!this.capturingElement_)
  220.         this.startCapture_(event);
  221.  
  222.       this.handleKey_(event);
  223.     },
  224.  
  225.     /**
  226.      * The KeyUp handler.
  227.      * @param {Event} event The keyboard event to consider.
  228.      * @private
  229.      */
  230.     handleKeyUp_: function(event) {
  231.       // We want to make it easy to change from Ctrl+Shift+ to just Ctrl+ by
  232.       // releasing Shift, but we also don't want it to be easy to lose for
  233.       // example Ctrl+Shift+F to Ctrl+ just because you didn't release Ctrl
  234.       // as fast as the other two keys. Therefore, we process KeyUp until you
  235.       // have a valid combination and then stop processing it (meaning that once
  236.       // you have a valid combination, we won't change it until the next
  237.       // KeyDown message arrives).
  238.       if (!this.currentKeyEvent_ || !validChar(this.currentKeyEvent_.keyCode)) {
  239.         if (!event.ctrlKey && !event.altKey) {
  240.           // If neither Ctrl nor Alt is pressed then it is not a valid shortcut.
  241.           // That means we're back at the starting point so we should restart
  242.           // capture.
  243.           this.endCapture_(event);
  244.           this.startCapture_(event);
  245.         } else {
  246.           this.handleKey_(event);
  247.         }
  248.       }
  249.     },
  250.  
  251.     /**
  252.      * A general key handler (used for both KeyDown and KeyUp).
  253.      * @param {Event} event The keyboard event to consider.
  254.      * @private
  255.      */
  256.     handleKey_: function(event) {
  257.       // While capturing, we prevent all events from bubbling, to prevent
  258.       // shortcuts lacking the right modifier (F3 for example) from activating
  259.       // and ending capture prematurely.
  260.       event.preventDefault();
  261.       event.stopPropagation();
  262.  
  263.       if (!event.ctrlKey && !event.altKey && (!cr.isMac || !event.metaKey))
  264.         return;  // Ctrl or Alt is a must (or Cmd on Mac).
  265.  
  266.       var shortcutNode = this.capturingElement_;
  267.       var keystroke = keystrokeToString(event);
  268.       shortcutNode.textContent = keystroke;
  269.       event.target.classList.add('contains-chars');
  270.  
  271.       if (validChar(event.keyCode)) {
  272.         var node = event.target;
  273.         while (node && !node.id)
  274.           node = node.parentElement;
  275.  
  276.         this.oldValue_ = keystroke;  // Forget what the old value was.
  277.         var parsed = this.parseElementId_('command', node.id);
  278.         chrome.send('setExtensionCommandShortcut',
  279.                     [parsed.extensionId, parsed.commandName, keystroke]);
  280.         this.endCapture_(event);
  281.       }
  282.  
  283.       this.currentKeyEvent_ = event;
  284.     },
  285.  
  286.     /**
  287.      * A handler for the delete command button.
  288.      * @param {Event} event The mouse event to consider.
  289.      * @private
  290.      */
  291.     handleClear_: function(event) {
  292.       var parsed = this.parseElementId_('clear', event.target.id);
  293.       chrome.send('setExtensionCommandShortcut',
  294.           [parsed.extensionId, parsed.commandName, '']);
  295.     },
  296.  
  297.     /**
  298.      * A utility function to create a unique element id based on a namespace,
  299.      * extension id and a command name.
  300.      * @param {string} namespace   The namespace to prepend the id with.
  301.      * @param {string} extensionId The extension ID to use in the id.
  302.      * @param {string} commandName The command name to append the id with.
  303.      * @private
  304.      */
  305.     createElementId_: function(namespace, extensionId, commandName) {
  306.       return namespace + '-' + extensionId + '-' + commandName;
  307.     },
  308.  
  309.     /**
  310.      * A utility function to parse a unique element id based on a namespace,
  311.      * extension id and a command name.
  312.      * @param {string} namespace   The namespace to prepend the id with.
  313.      * @param {string} id          The id to parse.
  314.      * @return {object} The parsed id, as an object with two members:
  315.      *                  extensionID and commandName.
  316.      * @private
  317.      */
  318.     parseElementId_: function(namespace, id) {
  319.       var kExtensionIdLength = 32;
  320.       return {
  321.         extensionId: id.substring(namespace.length + 1,
  322.                                   namespace.length + 1 + kExtensionIdLength),
  323.         commandName: id.substring(namespace.length + 1 + kExtensionIdLength + 1)
  324.       };
  325.     },
  326.   };
  327.  
  328.   return {
  329.     ExtensionCommandList: ExtensionCommandList
  330.   };
  331. });
  332.