From 090bc22fd9703492c5cf2f76a0a9c16ffa580e0a Mon Sep 17 00:00:00 2001
From: "oshima@chromium.org"
 <oshima@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>
Date: Tue, 12 Oct 2010 04:21:08 +0000
Subject: Switch WrenchMenu to use domui. * Add WrenchMenu class that
 implements zoom/edit commands. * changed toolkit_view to use domui menu. *
 Add accelerator support. * allow subclass to have its own css.

this also addresses comments on
 * removed clearTimeout
 * move init code to decorate as much as possible
 * changed init:config to setter
 * use 'hidden' rule to hide it, instead of not adding it.
 * I didn't change addHandler as now target and menuitem does not necessary the same.

BUG=6497
TEST=

Review URL: http://codereview.chromium.org/3601021

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@62244 0039d316-1c4b-4281-b951-d872f2087c98
---
 chrome/browser/resources/menu.css        |  14 +-
 chrome/browser/resources/menu.html       |   1 +
 chrome/browser/resources/menu.js         | 218 ++++++++++++----------
 chrome/browser/resources/wrench_menu.css |  43 +++++
 chrome/browser/resources/wrench_menu.js  | 308 ++++++++++++++++++++++++++++++-
 5 files changed, 487 insertions(+), 97 deletions(-)
 create mode 100644 chrome/browser/resources/wrench_menu.css

(limited to 'chrome/browser/resources')

diff --git a/chrome/browser/resources/menu.css b/chrome/browser/resources/menu.css
index a279618..2c9b055 100644
--- a/chrome/browser/resources/menu.css
+++ b/chrome/browser/resources/menu.css
@@ -10,10 +10,13 @@ body {
 .menu-item {
   white-space: nowrap;
   margin: 0;
-  padding-top: 0;
-  padding-bottom: 0;
+  padding-top: 1px;
+  padding-bottom: 1px;
   background-repeat: no-repeat;
   -webkit-padding-end: 19px;
+  display: -webkit-box;
+  -webkit-box-orient: horizontal;
+  overflow: hidden;
 }
 
 .disabled {
@@ -25,10 +28,15 @@ body {
 }
 
 .menu-label {
-  display: inline-block;
+  -webkit-box-flex: 1;
   vertical-align: middle;
 }
 
+.accelerator { 
+  opacity: 0.3;
+  -webkit-margin-start: 15px;
+}
+
 .left-icon {
   background-position: 4px center;
 }
diff --git a/chrome/browser/resources/menu.html b/chrome/browser/resources/menu.html
index f35e2fd..f6acc6a 100644
--- a/chrome/browser/resources/menu.html
+++ b/chrome/browser/resources/menu.html
@@ -6,6 +6,7 @@
     <script src="shared/js/cr.js"></script>
     <script src="shared/js/cr/ui.js"></script>
     <script src="menu.js"></script>
+    <style i18n-content="menu_css"></style>
     <script i18n-content="menu_source"></script>
   </head>
   <body>
diff --git a/chrome/browser/resources/menu.js b/chrome/browser/resources/menu.js
index 67e34fa..805550c 100644
--- a/chrome/browser/resources/menu.js
+++ b/chrome/browser/resources/menu.js
@@ -15,9 +15,14 @@ var MNEMONIC_REGEXP = /([^&]*)&(.)(.*)/;
 
 /**
  * Sends 'activate' DOMUI message.
+ * @param {number} index The index of menu item to activate in menu model.
+ * @param {string} mode The activation mode, one of 'close_and_activate', or
+ *    'activate_no_close'.
+ * TODO(oshima): change these string to enum numbers once it becomes possible
+ * to pass number to C++.
  */
-function sendActivate(index) {
-  chrome.send('activate', [String(index), 'close_and_activate']);
+function sendActivate(index, mode) {
+  chrome.send('activate', [String(index), mode]);
 }
 
 /**
@@ -42,9 +47,11 @@ MenuItem.prototype = {
    * @param {Object} attrs JSON object that represents this menu items
    *    properties.  This is created from menu model in C code.  See
    *    chromeos/views/native_menu_domui.cc.
-   * @param {number} leftIconWidth The left icon's width. 0 if no icon.
+   * @param {Object} model The model object.
    */
-  init: function(menu, attrs, leftIconWidth) {
+  init: function(menu, attrs, model) {
+    // The left icon's width. 0 if no icon.
+    var leftIconWidth = model.maxIconWidth;
     this.menu_ = menu;
     this.attrs = attrs;
     var attrs = this.attrs;
@@ -54,24 +61,27 @@ MenuItem.prototype = {
                attrs.type == 'submenu' ||
                attrs.type == 'check' ||
                attrs.type == 'radio') {
-      this.initMenuItem_(leftIconWidth);
+      this.initMenuItem_();
+      this.initPadding_(leftIconWidth);
     } else {
+      // This should not happend.
       this.classList.add('disabled');
       this.textContent = 'unknown';
     }
-    this.classList.add(leftIconWidth ? 'has-icon' : 'no-icon');
 
-    if (attrs.visible) {
-      menu.appendChild(this);
+    menu.appendChild(this);
+    if (!attrs.visible) {
+      this.classList.add('hidden');
     }
   },
 
   /**
    * Changes the selection state of the menu item.
-   * @param {boolean} b True to set the selection, or false otherwise.
+   * @param {boolean} selected True to set the selection, or false
+   *     otherwise.
    */
-  set selected(b) {
-    if (b) {
+  set selected(selected) {
+    if (selected) {
       this.classList.add('selected');
       this.menu_.selectedItem = this;
     } else {
@@ -87,7 +97,8 @@ MenuItem.prototype = {
       this.menu_.openSubmenu(this);
     } else if (this.attrs.type != 'separator' &&
                this.className.indexOf('selected') >= 0) {
-      sendActivate(this.menu_.getMenuItemIndexOf(this));
+      sendActivate(this.menu_.getMenuItemIndexOf(this),
+                   'close_and_activate');
     }
   },
 
@@ -104,56 +115,30 @@ MenuItem.prototype = {
    * Internal method to initiailze the MenuItem.
    * @private
    */
-  initMenuItem_: function(leftIconWidth) {
+  initMenuItem_: function() {
     var attrs = this.attrs;
     this.className = 'menu-item ' + attrs.type;
-    this.menu_.addHandlers(this);
-    var mnemonic = MNEMONIC_REGEXP.exec(attrs.label);
-    if (mnemonic) {
-       var c = mnemonic[2];
-       this.menu_.registerMnemonicKey(c, this);
-    }
-    if (leftIconWidth > 0) {
-      this.classList.add('left-icon');
-
-      var url;
-      if (attrs.type == 'radio') {
-        url = attrs.checked ?
-            this.menu_.config_.radioOnUrl :
-            this.menu_.config_.radioOffUrl;
-      } else if (attrs.icon) {
-        url = attrs.icon;
-      } else if (attrs.type == 'check' && attrs.checked) {
-        url = this.menu_.config_.checkUrl;
-      }
-      if (url) {
-        this.style.backgroundImage = 'url(' + url + ')';
-      }
-      // TODO(oshima): figure out how to update left padding in rule.
-      // 4 is the padding on left side of icon.
-      var padding =
-          4 + leftIconWidth + this.menu_.config_.icon_to_label_padding;
-      this.style.paddingLeft = padding + 'px';
-    }
+    this.menu_.addHandlers(this, this);
     var label = document.createElement('div');
 
     label.className = 'menu-label';
-
-    if (!mnemonic) {
-      label.textContent = attrs.label;
-    } else {
-      label.appendChild(document.createTextNode(mnemonic[1]));
-      label.appendChild(document.createElement('span'));
-      label.appendChild(document.createTextNode(mnemonic[3]));
-      label.childNodes[1].className = 'mnemonic';
-      label.childNodes[1].textContent = mnemonic[2];
-    }
+    this.menu_.addLabelTo(this, attrs.label, label,
+                          true /* enable mnemonic */);
 
     if (attrs.font) {
       label.style.font = attrs.font;
     }
     this.appendChild(label);
 
+
+    if (attrs.accel) {
+      var accel = document.createElement('div');
+      accel.className = 'accelerator';
+      accel.textContent = attrs.accel;
+      accel.style.font = attrs.font;
+      this.appendChild(accel);
+    }
+
     if (attrs.type == 'submenu') {
       // This overrides left-icon's position, but it's OK as submenu
       // shoudln't have left-icon.
@@ -161,6 +146,34 @@ MenuItem.prototype = {
       this.style.backgroundImage = 'url(' + this.menu_.config_.arrowUrl + ')';
     }
   },
+
+  initPadding_: function(leftIconWidth) {
+    if (leftIconWidth <= 0) {
+      this.classList.add('no-icon');
+      return;
+    }
+    this.classList.add('left-icon');
+
+    var url;
+    var attrs = this.attrs;
+    if (attrs.type == 'radio') {
+      url = attrs.checked ?
+          this.menu_.config_.radioOnUrl :
+          this.menu_.config_.radioOffUrl;
+    } else if (attrs.icon) {
+      url = attrs.icon;
+    } else if (attrs.type == 'check' && attrs.checked) {
+      url = this.menu_.config_.checkUrl;
+    }
+    if (url) {
+      this.style.backgroundImage = 'url(' + url + ')';
+    }
+    // TODO(oshima): figure out how to update left padding in rule.
+    // 4 is the padding on left side of icon.
+    var padding =
+        4 + leftIconWidth + this.menu_.config_.icon_to_label_padding;
+    this.style.WebkitPaddingStart = padding + 'px';
+  },
 };
 
 /**
@@ -274,6 +287,37 @@ Menu.prototype = {
   },
 
   /**
+   * Adds a label to {@code targetDiv}. A label may contain
+   * mnemonic key, preceded by '&'.
+   * @param {MenuItem} item The menu item to be activated by mnemonic
+   *    key.
+   * @param {string} label The label string to be added to
+   *    {@code targetDiv}.
+   * @param {HTMLElement} div The div element the label is added to.
+   * @param {boolean} enableMnemonic True to enable mnemonic, or false
+   *    to not to interprete mnemonic key. The function removes '&'
+   *    from the label in both cases.
+   */
+  addLabelTo: function(item, label, targetDiv, enableMnemonic) {
+    var mnemonic = MNEMONIC_REGEXP.exec(label);
+    if (mnemonic && enableMnemonic) {
+      var c = mnemonic[2].toLowerCase();
+      this.mnemonics_[c] = item;
+    }
+    if (!mnemonic) {
+      targetDiv.textContent = label;
+    } else if (enableMnemonic) {
+      targetDiv.appendChild(document.createTextNode(mnemonic[1]));
+      targetDiv.appendChild(document.createElement('span'));
+      targetDiv.appendChild(document.createTextNode(mnemonic[3]));
+      targetDiv.childNodes[1].className = 'mnemonic';
+      targetDiv.childNodes[1].textContent = mnemonic[2];
+    } else {
+      targetDiv.textContent = mnemonic.splice(1, 3).join('');
+    }
+  },
+
+  /**
    * Returns the index of the {@code item}.
    */
   getMenuItemIndexOf: function(item) {
@@ -281,10 +325,12 @@ Menu.prototype = {
   },
 
   /**
-   * A template method to create MenuItem object.
-   * Subclass class can override to return custom menu item.
+   * A template method to create an item object. It can be a subclass
+   * of MenuItem, or any HTMLElement that implements {@code init},
+   * {@code activate} methods as well as {@code selected} attribute.
+   * @param {Object} attrs The menu item's properties passed from C++.
    */
-  createMenuItem: function() {
+  createMenuItem: function(attrs) {
     return new MenuItem();
   },
 
@@ -301,7 +347,7 @@ Menu.prototype = {
     for (var i = 0; i < model.items.length; i++) {
       var attrs = model.items[i];
       var item = this.createMenuItem(attrs);
-      item.init(this, attrs, model.maxIconWidth);
+      item.init(this, attrs, model);
       this.items_.push(item);
     }
     this.onResize_();
@@ -320,28 +366,19 @@ Menu.prototype = {
   },
 
   /**
-   * Registers mnemonic key.
-   * @param {string} c A mnemonic key to activate item.
-   * @param {MenuItem} item An item to be activated when {@code c} is pressed.
-   */
-  registerMnemonicKey: function(c, item) {
-    this.mnemonics_[c.toLowerCase()] = item;
-  },
-
-  /**
    * Add event handlers for the item.
    */
-  addHandlers: function(item) {
+  addHandlers: function(item, target) {
     var menu = this;
-    item.addEventListener('mouseover', function(event) {
+    target.addEventListener('mouseover', function(event) {
       menu.onMouseover_(event, item);
     });
     if (item.attrs.enabled) {
-      item.addEventListener('mouseup', function(event) {
+      target.addEventListener('mouseup', function(event) {
         menu.onClick_(event, item);
       });
     } else {
-      item.classList.add('disabled');
+      target.classList.add('disabled');
     }
   },
 
@@ -395,7 +432,7 @@ Menu.prototype = {
   /**
    * Open submenu {@code item}. It does nothing if the submenu is
    * already opened.
-   * @param {MenuItem} item the submenu item to open.
+   * @param {MenuItem} item The submenu item to open.
    */
   openSubmenu: function(item) {
     this.cancelSubmenuTimer_();
@@ -462,8 +499,10 @@ Menu.prototype = {
     // Handles mnemonic.
     var c = String.fromCharCode(event.keyCode);
     var item = this.mnemonics_[c.toLowerCase()];
-    if (item)
+    if (item) {
+      item.selected = true;
       item.activate();
+    }
   },
 
   // Mouse Event handlers
@@ -556,7 +595,7 @@ Menu.prototype = {
    * Find a next selectable item. If nothing is selected, the 1st
    * selectable item will be chosen. Returns null if nothing is
    * selectable.
-   * @param {number} incr specifies the direction to search, 1 to
+   * @param {number} incr Specifies the direction to search, 1 to
    * downwards and -1 for upwards.
    * @private
    */
@@ -571,7 +610,8 @@ Menu.prototype = {
     for (var i = 0; i < len; i++) {
       index = (index + incr + len) % len;
       var item = this.items_[index];
-      if (item.attrs.enabled && item.attrs.type != 'separator')
+      if (item.attrs.enabled && item.attrs.type != 'separator' &&
+          !item.classList.contains('hidden'))
         return item;
     }
     return null;
@@ -582,32 +622,26 @@ Menu.prototype = {
    * @private
    */
   cancelSubmenuTimer_: function() {
-    if (this.openSubmenuTimer_) {
-      clearTimeout(this.openSubmenuTimer_);
-      this.openSubmenuTimer_ = 0;
-    }
-    if (this.closeSubmenuTimer_) {
-      clearTimeout(this.closeSubmenuTimer_);
-      this.closeSubmenuTimer_ = 0;
-    }
+    clearTimeout(this.openSubmenuTimer_);
+    this.openSubmenuTimer_ = 0;
+    clearTimeout(this.closeSubmenuTimer_);
+    this.closeSubmenuTimer_ = 0;
   },
 
   /**
    * Starts auto scroll.
-   * @param {number} tick the number of pixels to scroll.
+   * @param {number} tick The number of pixels to scroll.
    * @private
    */
   autoScroll_: function(tick) {
     var previous = this.scrollTop;
     this.scrollTop += tick;
-    if (this.scrollTop != previous) {
-      var menu = this;
-      this.scrollTimer_ = setTimeout(
-          function() {
-            menu.autoScroll_(tick);
-          },
-          SCROLL_INTERVAL_MS);
-    }
+    var menu = this;
+    this.scrollTimer_ = setTimeout(
+        function() {
+          menu.autoScroll_(tick);
+        },
+        SCROLL_INTERVAL_MS);
   },
 
   /**
@@ -615,10 +649,8 @@ Menu.prototype = {
    * @private
    */
   stopScroll_: function () {
-    if (this.scrollTimer_) {
-      clearTimeout(this.scrollTimer_);
-      this.scrollTimer_ = 0;
-    }
+    clearTimeout(this.scrollTimer_);
+    this.scrollTimer_ = 0;
   },
 
   /**
diff --git a/chrome/browser/resources/wrench_menu.css b/chrome/browser/resources/wrench_menu.css
new file mode 100644
index 0000000..b696068
--- /dev/null
+++ b/chrome/browser/resources/wrench_menu.css
@@ -0,0 +1,43 @@
+.fullscreen {
+  background-image: url('../../app/theme/fullscreen_menu_button.png');
+  background-position: center center;
+  background-repeat: no-repeat;
+  border: solid 1px rgba(0, 0, 0, 0.3);
+  border-radius: 3px;
+  width: 23px;
+  height: 23px;
+  -webkit-margin-start: 4px;
+}
+
+.edit-button {
+  padding: 2px;
+  text-align: center;
+  min-width: 35px;
+}
+
+.left-button {
+  border: solid 1px rgba(0, 0, 0, 0.3);
+  border-top-left-radius: 3px;
+  border-bottom-left-radius: 3px;
+}
+
+.right-button {
+  border: solid 1px rgba(0, 0, 0, 0.3);
+  border-top-right-radius: 3px;
+  border-bottom-right-radius: 3px;
+}
+
+.center-button {
+  border-top: solid 1px rgba(0, 0, 0, 0.3);
+  border-bottom: solid 1px rgba(0, 0, 0, 0.3);
+}
+
+.zoom-button {
+  text-align: center;
+  width: 15px;
+}
+
+.zoom-percent {
+  min-width: 40px;
+  text-align: center;
+}
diff --git a/chrome/browser/resources/wrench_menu.js b/chrome/browser/resources/wrench_menu.js
index c45e432..8566270 100644
--- a/chrome/browser/resources/wrench_menu.js
+++ b/chrome/browser/resources/wrench_menu.js
@@ -2,4 +2,310 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-// T.B.D.
+/**
+ * ButtonCommand class for small buttons on menu items.
+ */
+var ButtonCommand = cr.ui.define('div');
+
+ButtonCommand.prototype = {
+  __proto__: HTMLDivElement.prototype,
+
+  /**
+   * Decorate Button item.
+   */
+  decorate: function() {
+  },
+
+  /**
+   * Changes the selection state of the menu item.
+   * @param {boolean} selected True to set the selection, or false otherwise.
+   */
+  set selected(selected) {
+    if (selected) {
+      this.classList.add('selected');
+      this.menu_.selectedItem = this;
+    } else {
+      this.classList.remove('selected');
+    }
+  },
+
+  /**
+   * Activate the menu item.
+   */
+  activate: function() {
+    sendActivate(this.menu_.getMenuItemIndexOf(this),
+                 'close_and_activate');
+  },
+};
+
+/**
+ * EditCommand implements Copy and Paste command.
+ */
+var EditCommand = cr.ui.define('div');
+
+EditCommand.prototype = {
+  __proto__: ButtonCommand.prototype,
+
+  /**
+   * Initialize the menu item.
+   * @override
+   */
+  init: function(menu, attrs, model) {
+    this.menu_ = menu;
+    this.attrs = attrs;
+    if (this.attrs.font) {
+      this.style.font = attrs.font;
+    }
+    menu.addHandlers(this, this);
+    if (attrs.command_id == menu.config_.IDC_COPY) {
+      menu.addLabelTo(this, menu.config_.IDS_COPY, this,
+                      false /* no mnemonic */);
+    } else {
+      menu.addLabelTo(this, menu.config_.IDS_PASTE, this,
+                      false /* no mnemonic */);
+    }
+  },
+};
+
+/**
+ * EditMenuItem which has Copy and Paste commands inside.
+ */
+var EditMenuItem = cr.ui.define('div');
+
+EditMenuItem.prototype = {
+  __proto__: MenuItem.prototype,
+
+  /**
+   * Initialize
+   */
+  decorate: function() {
+    this.className = 'menu-item';
+    this.label_ = document.createElement('div');
+    this.label_.className = 'menu-label';
+    this.cut_ = document.createElement('div');
+    this.cut_.className = 'edit-button left-button';
+    this.copy_ = new EditCommand();
+    this.copy_.className = 'edit-button center-button';
+    this.paste_ = new EditCommand();
+    this.paste_.className = 'edit-button right-button';
+
+    this.appendChild(this.label_);
+    this.appendChild(this.cut_);
+    this.appendChild(this.copy_);
+    this.appendChild(this.paste_);
+  },
+
+  /**
+   * Activates the command.
+   * @override
+   */
+  activate: function() {
+    sendActivate(this.menu_.getMenuItemIndexOf(this),
+                 'close_and_activate');
+  },
+
+  /**
+   * @override
+   */
+  set selected(selected) {
+    if (selected) {
+      this.cut_.classList.add('selected');
+      this.menu_.selectedItem = this;
+    } else {
+      this.cut_.classList.remove('selected');
+    }
+  },
+
+  /**
+   * Initialize the edit items with configuration info.
+   * @override
+   */
+  initMenuItem_: function() {
+    this.label_.textContent =
+        this.menu_.config_.IDS_EDIT2;
+    if (this.attrs.font) {
+      this.label_.style.font = this.attrs.font;
+      this.cut_.style.font = this.attrs.font;
+    }
+    this.menu_.addLabelTo(
+        this, this.menu_.config_.IDS_CUT, this.cut_,
+        false /* no mnemonic */);
+    this.menu_.addHandlers(this, this.cut_);
+  },
+};
+
+/**
+ * ZoomCommand class implements Zoom plus and fullscreen.
+ */
+var ZoomCommand = cr.ui.define('div');
+
+ZoomCommand.prototype = {
+  __proto__: ButtonCommand.prototype,
+
+  /**
+   * Initialize the menu item.
+   * @override
+   */
+  init: function(menu, attrs, model) {
+    this.menu_ = menu;
+    this.attrs = attrs;
+    menu.addHandlers(this, this);
+    if (attrs.command_id == menu.config_.IDC_ZOOM_PLUS) {
+      this.textContent = '+';
+    }
+    if (this.attrs.font) {
+      this.style.font = attrs.font;
+    }
+  },
+
+  /**
+   * Activate zoom plus and full screen commands.
+   * @override
+   */
+  activate: function() {
+    sendActivate(this.menu_.getMenuItemIndexOf(this),
+                 this.attrs.command_id == this.menu_.config_.IDC_ZOOM_PLUS ?
+                 'activate_no_close' : 'close_and_activate');
+  },
+};
+
+/**
+ * ZoomMenuItem which has plus and fullscreen buttons inside.
+ */
+var ZoomMenuItem = cr.ui.define('div');
+
+ZoomMenuItem.prototype = {
+  __proto__: MenuItem.prototype,
+
+  /**
+   * Decorate Zoom button item.
+   */
+  decorate: function() {
+    this.className = 'menu-item';
+
+    this.label_ = document.createElement('div');
+    this.label_.className = 'menu-label';
+    this.minus_ = document.createElement('div');
+    this.minus_.className = 'zoom-button left-button';
+    this.minus_.textContent = '-';
+    this.plus_ = new ZoomCommand();
+    this.plus_.className = 'zoom-button right-button';
+    this.percent_ = document.createElement('div');
+    this.percent_.className = 'zoom-percent center-button';
+    this.fullscreen_ = new ZoomCommand();
+    this.fullscreen_.className = 'fullscreen';
+
+    this.appendChild(this.label_);
+    this.appendChild(this.minus_);
+    this.appendChild(this.percent_);
+    this.appendChild(this.plus_);
+    this.appendChild(this.fullscreen_);
+  },
+
+  /**
+   * Activates the cut command.
+   * @override
+   */
+  activate: function() {
+    sendActivate(this.menu_.getMenuItemIndexOf(this),
+                 'activate_no_close');
+  },
+
+  /**
+   * Updates zoom controls.
+   * @params {JSON} params JSON object to configure zoom controls.
+   */
+  updateZoomControls: function(params) {
+    this.attrs.enabled = params.plus;
+    if (params.plus) {
+      this.plus_.classList.remove('disabled');
+    } else {
+      this.plus_.classList.add('disabled');
+    }
+    this.attrs.enabled = params.minus;
+    if (params.minus) {
+      this.classList.remove('disabled');
+    } else {
+      this.classList.add('disabled');
+    }
+    this.percent_.textContent = params.percent;
+  },
+
+  /**
+   * @override
+   */
+  set selected(selected) {
+    if (selected) {
+      this.minus_.classList.add('selected');
+      this.menu_.selectedItem = this;
+    } else {
+      this.minus_.classList.remove('selected');
+    }
+  },
+
+  /**
+   * Initializes the zoom menu item with configuration info.
+   * @override
+   */
+  initMenuItem_: function() {
+    this.label_.textContent =
+        this.menu_.config_.IDS_ZOOM_MENU2;
+    this.menu_.addHandlers(this, this.minus_);
+
+    if (this.attrs.font) {
+      this.label_.style.font = this.attrs.font;
+      this.minus_.style.font = this.attrs.font;
+      this.percent_.style.font = this.attrs.font;
+    }
+  },
+};
+
+/**
+ * WrenchMenu
+ */
+var WrenchMenu = cr.ui.define('div');
+
+WrenchMenu.prototype = {
+  __proto__: Menu.prototype,
+
+  /**
+   * Decorate Zoom button item.
+   */
+  decorate: function() {
+    Menu.prototype.decorate.call(this);
+    this.edit_ = new EditMenuItem();
+    this.zoom_ = new ZoomMenuItem();
+  },
+
+  /**
+   * Create a MenuItem for given {@code attrs}.
+   * @override
+   */
+  createMenuItem: function(attrs) {
+    switch(attrs.command_id) {
+      case this.config_.IDC_CUT:
+        return this.edit_;
+      case this.config_.IDC_COPY:
+        return this.edit_.copy_;
+      case this.config_.IDC_PASTE:
+        return this.edit_.paste_;
+      case this.config_.IDC_ZOOM_MINUS:
+        return this.zoom_;
+      case this.config_.IDC_ZOOM_PLUS:
+        return this.zoom_.plus_;
+      case this.config_.IDC_FULLSCREEN:
+        return this.zoom_.fullscreen_;
+      default:
+        return new MenuItem();
+    }
+  },
+
+  updateZoomControls: function(params) {
+    this.zoom_.updateZoomControls(params);
+  },
+};
+
+function updateZoomControls(params) {
+  var menu = document.getElementById('viewport');
+  menu.updateZoomControls(params);
+}
-- 
cgit v1.1