| Index: remoting/webapp/app_remoting/js/context_menu_dom.js
 | 
| diff --git a/remoting/webapp/app_remoting/js/context_menu_dom.js b/remoting/webapp/app_remoting/js/context_menu_dom.js
 | 
| deleted file mode 100644
 | 
| index 78222140868d9332af1ad64ecb28c028fb87164f..0000000000000000000000000000000000000000
 | 
| --- a/remoting/webapp/app_remoting/js/context_menu_dom.js
 | 
| +++ /dev/null
 | 
| @@ -1,314 +0,0 @@
 | 
| -// Copyright 2014 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
 | 
| - * Provide an alternative location for the application's context menu items
 | 
| - * on platforms that don't provide it.
 | 
| - *
 | 
| - * To mimic the behaviour of an OS-provided context menu, the menu is dismissed
 | 
| - * in three situations:
 | 
| - *
 | 
| - * 1. When the window loses focus (i.e, the user has clicked on another window
 | 
| - *    or on the desktop).
 | 
| - * 2. When the user selects an option from the menu.
 | 
| - * 3. When the user clicks on another part of the same window; this is achieved
 | 
| - *    using an invisible screen element behind the menu, but in front of all
 | 
| - *    other DOM.
 | 
| - *
 | 
| - * TODO(jamiewalch): Fold this functionality into remoting.MenuButton.
 | 
| - */
 | 
| -'use strict';
 | 
| -
 | 
| -/** @suppress {duplicate} */
 | 
| -var remoting = remoting || {};
 | 
| -
 | 
| -/**
 | 
| - * @constructor
 | 
| - * @implements {remoting.WindowShape.ClientUI}
 | 
| - * @implements {remoting.ContextMenuAdapter}
 | 
| - * @param {HTMLElement} root The root of the context menu DOM.
 | 
| - * @param {remoting.WindowShape} windowShape
 | 
| - */
 | 
| -remoting.ContextMenuDom = function(root, windowShape) {
 | 
| -  /** @private {HTMLElement} */
 | 
| -  this.root_ = root;
 | 
| -  /** @private {HTMLElement} */
 | 
| -  this.stub_ = /** @type {HTMLElement} */
 | 
| -      (this.root_.querySelector('.context-menu-stub'));
 | 
| -  /** @private {HTMLElement} */
 | 
| -  this.icon_ = /** @type {HTMLElement} */
 | 
| -      (this.root_.querySelector('.context-menu-icon'));
 | 
| -  /** @private {HTMLElement} */
 | 
| -  this.screen_ = /** @type {HTMLElement} */
 | 
| -      (this.root_.querySelector('.context-menu-screen'));
 | 
| -  /** @private {HTMLElement} */
 | 
| -  this.menu_ = /** @type {HTMLElement} */ (this.root_.querySelector('ul'));
 | 
| -  /** @private {number} */
 | 
| -  this.bottom_ = 8;
 | 
| -  /** @private {base.EventSourceImpl} */
 | 
| -  this.eventSource_ = new base.EventSourceImpl();
 | 
| -  /** @private {string} */
 | 
| -  this.eventName_ = '_click';
 | 
| -  /**
 | 
| -   * Since the same element is used to lock the icon open and to drag it, we
 | 
| -   * must keep track of drag events so that the corresponding click event can
 | 
| -   * be ignored.
 | 
| -   *
 | 
| -   * @private {boolean}
 | 
| -   */
 | 
| -  this.stubDragged_ = false;
 | 
| -
 | 
| -  /** @private */
 | 
| -  this.windowShape_ = windowShape;
 | 
| -
 | 
| -  /**
 | 
| -   * @private
 | 
| -   */
 | 
| -  this.dragAndDrop_ = new remoting.DragAndDrop(
 | 
| -      this.stub_, this.onDragUpdate_.bind(this));
 | 
| -
 | 
| -  this.eventSource_.defineEvents([this.eventName_]);
 | 
| -  this.root_.addEventListener(
 | 
| -      'transitionend', this.onTransitionEnd_.bind(this), false);
 | 
| -  this.stub_.addEventListener('click', this.onStubClick_.bind(this), false);
 | 
| -  this.icon_.addEventListener('click', this.onIconClick_.bind(this), false);
 | 
| -  this.screen_.addEventListener('click', this.onIconClick_.bind(this), false);
 | 
| -
 | 
| -  this.root_.hidden = false;
 | 
| -  this.root_.style.bottom = this.bottom_ + 'px';
 | 
| -  this.windowShape_.registerClientUI(this);
 | 
| -};
 | 
| -
 | 
| -remoting.ContextMenuDom.prototype.dispose = function() {
 | 
| -  this.windowShape_.unregisterClientUI(this);
 | 
| -};
 | 
| -
 | 
| -/**
 | 
| - * @param {Array<{left: number, top: number, width: number, height: number}>}
 | 
| - *     rects List of rectangles.
 | 
| - */
 | 
| -remoting.ContextMenuDom.prototype.addToRegion = function(rects) {
 | 
| -  var rect = /** @type {ClientRect} */ (this.root_.getBoundingClientRect());
 | 
| -  // Clip the menu position to the main window in case the screen size has
 | 
| -  // changed or a recent drag event tried to move it out of bounds.
 | 
| -  if (rect.top < 0) {
 | 
| -    this.bottom_ += rect.top;
 | 
| -    this.root_.style.bottom = this.bottom_ + 'px';
 | 
| -    rect = this.root_.getBoundingClientRect();
 | 
| -  }
 | 
| -
 | 
| -  rects.push(rect);
 | 
| -  if (this.root_.classList.contains('menu-opened')) {
 | 
| -    var menuRect = this.menu_.getBoundingClientRect();
 | 
| -    rects.push(menuRect);
 | 
| -  }
 | 
| -};
 | 
| -
 | 
| -/**
 | 
| - * @param {string} id An identifier for the menu entry.
 | 
| - * @param {string} title The text to display in the menu.
 | 
| - * @param {boolean} isCheckable True if the state of this menu entry should
 | 
| - *     have a check-box and manage its toggle state automatically. Note that
 | 
| - *     checkable menu entries always start off unchecked.
 | 
| - * @param {string=} opt_parentId The id of the parent menu item for submenus.
 | 
| - */
 | 
| -remoting.ContextMenuDom.prototype.create = function(
 | 
| -    id, title, isCheckable, opt_parentId) {
 | 
| -  var menuEntry = /** @type {HTMLElement} */ (document.createElement('li'));
 | 
| -  menuEntry.innerText = title;
 | 
| -  menuEntry.setAttribute('data-id', id);
 | 
| -  if (isCheckable) {
 | 
| -    menuEntry.setAttribute('data-checkable', true);
 | 
| -  }
 | 
| -  menuEntry.addEventListener('click', this.onClick_.bind(this), false);
 | 
| -  /** @type {Node} */
 | 
| -  var insertBefore = null;
 | 
| -  if (opt_parentId) {
 | 
| -    var parent = /** @type {HTMLElement} */
 | 
| -        (this.menu_.querySelector('[data-id="' + opt_parentId + '"]'));
 | 
| -    console.assert(
 | 
| -        parent != null,
 | 
| -        'No parent match for [data-id="' + /** @type {string} */(opt_parentId) +
 | 
| -        '"] in create().');
 | 
| -    console.assert(!parent.classList.contains('menu-group-item'),
 | 
| -                   'Nested sub-menus are not supported.');
 | 
| -    parent.classList.add('menu-group-header');
 | 
| -    menuEntry.classList.add('menu-group-item');
 | 
| -    insertBefore = this.getInsertionPointForParent(
 | 
| -        /** @type {string} */(opt_parentId));
 | 
| -  }
 | 
| -  this.menu_.insertBefore(menuEntry, insertBefore);
 | 
| -};
 | 
| -
 | 
| -/**
 | 
| - * @param {string} id
 | 
| - * @param {string} title
 | 
| - */
 | 
| -remoting.ContextMenuDom.prototype.updateTitle = function(id, title) {
 | 
| -  var node = this.menu_.querySelector('[data-id="' + id + '"]');
 | 
| -  if (node) {
 | 
| -    node.innerText = title;
 | 
| -  }
 | 
| -};
 | 
| -
 | 
| -/**
 | 
| - * @param {string} id
 | 
| - * @param {boolean} checked
 | 
| - */
 | 
| -remoting.ContextMenuDom.prototype.updateCheckState = function(id, checked) {
 | 
| -  var node = /** @type {HTMLElement} */
 | 
| -      (this.menu_.querySelector('[data-id="' + id + '"]'));
 | 
| -  if (node) {
 | 
| -    if (checked) {
 | 
| -      node.classList.add('selected');
 | 
| -    } else {
 | 
| -      node.classList.remove('selected');
 | 
| -    }
 | 
| -  }
 | 
| -};
 | 
| -
 | 
| -/**
 | 
| - * @param {string} id
 | 
| - */
 | 
| -remoting.ContextMenuDom.prototype.remove = function(id) {
 | 
| -  var node = this.menu_.querySelector('[data-id="' + id + '"]');
 | 
| -  if (node) {
 | 
| -    this.menu_.removeChild(node);
 | 
| -  }
 | 
| -};
 | 
| -
 | 
| -/**
 | 
| - * @param {function(OnClickData=):void} listener
 | 
| - */
 | 
| -remoting.ContextMenuDom.prototype.addListener = function(listener) {
 | 
| -  this.eventSource_.addEventListener(this.eventName_, listener);
 | 
| -};
 | 
| -
 | 
| -/**
 | 
| - * @param {Event} event
 | 
| - * @private
 | 
| - */
 | 
| -remoting.ContextMenuDom.prototype.onClick_ = function(event) {
 | 
| -  var element = /** @type {HTMLElement} */ (event.target);
 | 
| -  if (element.getAttribute('data-checkable')) {
 | 
| -    element.classList.toggle('selected')
 | 
| -  }
 | 
| -  var clickData = {
 | 
| -    menuItemId: element.getAttribute('data-id'),
 | 
| -    checked: element.classList.contains('selected')
 | 
| -  };
 | 
| -  this.eventSource_.raiseEvent(this.eventName_, clickData);
 | 
| -  this.onIconClick_();
 | 
| -};
 | 
| -
 | 
| -/**
 | 
| - * Get the insertion point for the specified sub-menu. This is the menu item
 | 
| - * immediately following the last child of that menu group, or null if there
 | 
| - * are no menu items after that group.
 | 
| - *
 | 
| - * @param {string} parentId
 | 
| - * @return {Node?}
 | 
| - */
 | 
| -remoting.ContextMenuDom.prototype.getInsertionPointForParent = function(
 | 
| -    parentId) {
 | 
| -  var parentNode = this.menu_.querySelector('[data-id="' + parentId + '"]');
 | 
| -  console.assert(parentNode != null,
 | 
| -                 'No parent match for [data-id="' + parentId +
 | 
| -                 '"] in getInsertionPointForParent().');
 | 
| -  var childNode = /** @type {HTMLElement} */ (parentNode.nextSibling);
 | 
| -  while (childNode != null && childNode.classList.contains('menu-group-item')) {
 | 
| -    childNode = childNode.nextSibling;
 | 
| -  }
 | 
| -  return childNode;
 | 
| -};
 | 
| -
 | 
| -/**
 | 
| - * Called when the CSS show/hide transition completes. Since this changes the
 | 
| - * visible dimensions of the context menu, the visible region of the window
 | 
| - * needs to be recomputed.
 | 
| - *
 | 
| - * @private
 | 
| - */
 | 
| -remoting.ContextMenuDom.prototype.onTransitionEnd_ = function() {
 | 
| -  this.windowShape_.updateClientWindowShape();
 | 
| -};
 | 
| -
 | 
| -/**
 | 
| - * Toggle the visibility of the context menu icon.
 | 
| - *
 | 
| - * @private
 | 
| - */
 | 
| -remoting.ContextMenuDom.prototype.onStubClick_ = function() {
 | 
| -  if (this.stubDragged_) {
 | 
| -    this.stubDragged_ = false;
 | 
| -    return;
 | 
| -  }
 | 
| -  this.root_.classList.toggle('opened');
 | 
| -};
 | 
| -
 | 
| -/**
 | 
| - * Toggle the visibility of the context menu.
 | 
| - *
 | 
| - * @private
 | 
| - */
 | 
| -remoting.ContextMenuDom.prototype.onIconClick_ = function() {
 | 
| -  this.showMenu_(!this.menu_.classList.contains('opened'));
 | 
| -};
 | 
| -
 | 
| -/**
 | 
| - * Explicitly show or hide the context menu.
 | 
| - *
 | 
| - * @param {boolean} show True to show the menu; false to hide it.
 | 
| - * @private
 | 
| - */
 | 
| -remoting.ContextMenuDom.prototype.showMenu_ = function(show) {
 | 
| -  if (show) {
 | 
| -    // Ensure that the menu doesn't extend off the top or bottom of the
 | 
| -    // screen by aligning it to the top or bottom of the icon, depending
 | 
| -    // on the latter's vertical position.
 | 
| -    var menuRect =
 | 
| -        /** @type {ClientRect} */ (this.menu_.getBoundingClientRect());
 | 
| -    if (menuRect.bottom > window.innerHeight) {
 | 
| -      this.menu_.classList.add('menu-align-bottom');
 | 
| -    } else {
 | 
| -      this.menu_.classList.remove('menu-align-bottom');
 | 
| -    }
 | 
| -
 | 
| -    /** @type {remoting.ContextMenuDom} */
 | 
| -    var that = this;
 | 
| -    var onBlur = function() {
 | 
| -      that.showMenu_(false);
 | 
| -      window.removeEventListener('blur', onBlur, false);
 | 
| -    };
 | 
| -    window.addEventListener('blur', onBlur, false);
 | 
| -
 | 
| -    // Show the menu and prevent the icon from auto-hiding on mouse-out.
 | 
| -    this.menu_.classList.add('opened');
 | 
| -    this.root_.classList.add('menu-opened');
 | 
| -
 | 
| -  } else {  // if (!show)
 | 
| -    this.menu_.classList.remove('opened');
 | 
| -    this.root_.classList.remove('menu-opened');
 | 
| -  }
 | 
| -
 | 
| -  this.screen_.hidden = !show;
 | 
| -  this.windowShape_.updateClientWindowShape();
 | 
| -};
 | 
| -
 | 
| -/**
 | 
| - * @param {number} deltaX
 | 
| - * @param {number} deltaY
 | 
| - * @private
 | 
| - */
 | 
| -remoting.ContextMenuDom.prototype.onDragUpdate_ = function(deltaX, deltaY) {
 | 
| -  this.stubDragged_ = true;
 | 
| -  this.bottom_ -= deltaY;
 | 
| -  this.root_.style.bottom = this.bottom_ + 'px';
 | 
| -  // Deferring the window shape update until the DOM update has completed
 | 
| -  // helps keep the position of the context menu consistent with the window
 | 
| -  // shape (though it's still not perfect).
 | 
| -  window.requestAnimationFrame(
 | 
| -      this.windowShape_.updateClientWindowShape.bind(this.windowShape_));
 | 
| -};
 | 
| 
 |