summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorarv@chromium.org <arv@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-09-06 18:34:06 +0000
committerarv@chromium.org <arv@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-09-06 18:34:06 +0000
commit02b18209b05fc5c465d4518b9d7a4df1135c1a95 (patch)
tree1f79efbfd51b38a30f5441962e86752ea76956ca
parent004f80b0ab3bc8467b4df5a15b3e2fe040569aee (diff)
downloadchromium_src-02b18209b05fc5c465d4518b9d7a4df1135c1a95.zip
chromium_src-02b18209b05fc5c465d4518b9d7a4df1135c1a95.tar.gz
chromium_src-02b18209b05fc5c465d4518b9d7a4df1135c1a95.tar.bz2
NTP: Adds a context menu to the apps section
This uses the cr Menu system and replaces the old options menu with a cr Menu. BUG=52446 TEST=Start chrome with enable-apps. Install some apps. Right clicking on an app should show a context menu. Clicking the wrench should show the same menu. Review URL: http://codereview.chromium.org/3315005 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@58648 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--chrome/browser/dom_ui/ntp_resource_cache.cc6
-rw-r--r--chrome/browser/resources/new_new_tab.css56
-rw-r--r--chrome/browser/resources/new_new_tab.html44
-rw-r--r--chrome/browser/resources/new_new_tab.js214
-rw-r--r--chrome/browser/resources/new_tab_theme.css3
-rw-r--r--chrome/browser/resources/ntp/apps.css77
-rw-r--r--chrome/browser/resources/ntp/apps.js235
-rw-r--r--chrome/browser/resources/ntp/most_visited.js21
-rw-r--r--chrome/browser/resources/shared/css/menu.css4
-rw-r--r--chrome/browser/resources/shared/js/cr/ui/command.js2
-rw-r--r--chrome/browser/resources/shared/js/cr/ui/position_util.js11
11 files changed, 235 insertions, 438 deletions
diff --git a/chrome/browser/dom_ui/ntp_resource_cache.cc b/chrome/browser/dom_ui/ntp_resource_cache.cc
index c2209bd..a3e5020 100644
--- a/chrome/browser/dom_ui/ntp_resource_cache.cc
+++ b/chrome/browser/dom_ui/ntp_resource_cache.cc
@@ -11,7 +11,6 @@
#include "app/l10n_util.h"
#include "app/resource_bundle.h"
#include "app/theme_provider.h"
-#include "base/command_line.h"
#include "base/file_util.h"
#include "base/ref_counted_memory.h"
#include "base/string16.h"
@@ -304,11 +303,6 @@ void NTPResourceCache::CreateNewTabHTML() {
Animation::ShouldRenderRichAnimation() ? "true" : "false";
localized_strings.SetString("anim", anim);
- const CommandLine* command_line = CommandLine::ForCurrentProcess();
- bool has_3d =
- command_line->HasSwitch(switches::kEnableAcceleratedCompositing);
- localized_strings.SetString("has_3d", has_3d ? "true" : "false");
-
// Pass the shown_sections pref early so that we can prevent flicker.
const int shown_sections = ShownSectionsHandler::GetShownSections(
profile_->GetPrefs());
diff --git a/chrome/browser/resources/new_new_tab.css b/chrome/browser/resources/new_new_tab.css
index 68d7cd7..f43aaa8 100644
--- a/chrome/browser/resources/new_new_tab.css
+++ b/chrome/browser/resources/new_new_tab.css
@@ -129,7 +129,7 @@ html[anim=false] *,
background: no-repeat 0% 50%;
padding: 2px;
padding-left: 18px;
- background-size: 16px;
+ background-size: 16px 16px;
background-color: hsla(213, 63%, 93%, 0);
display: block;
line-height: 20px;
@@ -219,47 +219,6 @@ html[dir=rtl] .item {
pointer-events: none;
}
-#option-menu {
- right: 0;
- left: auto;
- min-width: 175px;
- z-index: 3;
-}
-
-html[dir=rtl] #option-button,
-html[dir=rtl] #option-menu {
- right: auto;
- left: 0;
-}
-
-#option-menu > * {
- /* Work around rendering bug. */
- outline: 1px solid transparent;
-}
-
-#option-menu > [command=show]:before,
-#option-menu > [command=hide]:before {
- -webkit-margin-start: -14px;
- content: '\00a0'; /* non breaking space */
- display: inline-block;
- background-position: 0 50%;
- background-repeat: no-repeat;
- width: 14px;
-}
-
-html[dir=rtl] #option-menu > [command=show]:before,
-html[dir=rtl] #option-menu > [command=hide]:before {
- background-position-x: 100%;
-}
-
-#option-menu > [command=hide]:before {
- background-image: url('ntp/checkbox_black.png');
-}
-
-#option-menu > [selected][command=hide]:active:before {
- background-image: url('ntp/checkbox_white.png');
-}
-
#attribution {
position: fixed;
right: 5px;
@@ -367,17 +326,18 @@ html[dir=rtl] .section > h2 .settings-wrapper {
}
.section > h2 .settings {
- position: absolute;
- left: 5px;
- top: 5px;
- width: 11px;
- height: 11px;
/* TODO(aa): Need a better image. This one is semi-transparent. Also, I think
a gear would be better. */
+ background-color: transparent;
background-image: url(chrome://theme/IDR_BALLOON_WRENCH);
background-position: center center;
background-repeat: no-repeat;
- background-size: 100%;
+ border: 0;
+ height: 11px;
+ left: 5px;
+ position: absolute;
+ top: 5px;
+ width: 11px;
}
.section.hidden > h2 .settings-wrapper {
diff --git a/chrome/browser/resources/new_new_tab.html b/chrome/browser/resources/new_new_tab.html
index 2080c71..1a88c6d 100644
--- a/chrome/browser/resources/new_new_tab.html
+++ b/chrome/browser/resources/new_new_tab.html
@@ -4,8 +4,7 @@
bookmarkbarattached:bookmarkbarattached;
hasattribution:hasattribution;
anim:anim;
- syncispresent:syncispresent;
- has_3d:has_3d">
+ syncispresent:syncispresent">
<head>
<meta charset="utf-8">
<title i18n-content="title"></title>
@@ -123,10 +122,6 @@ if ('mode' in hashParams) {
</div>
<div id="main">
- <menu id="option-menu">
- <div command="clear-all-blacklisted"
- i18n-content="restorethumbnails"></div>
- </menu>
<div id="notification">
<span>&nbsp;</span>
@@ -152,7 +147,9 @@ if ('mode' in hashParams) {
<img class="disclosure" src="ntp/ntp_disclosure_triangle.png">
<div class="back"></div>
<span i18n-content="mostvisited"></span>
- <div class="settings-wrapper"><div class="settings"></div></div>
+ <div class="settings-wrapper">
+ <button class="settings" menu="#option-menu"></button>
+ </div>
</h2>
<div class="miniview"></div>
</div>
@@ -179,6 +176,22 @@ if ('mode' in hashParams) {
<div class="window-menu" id="window-tooltip"></div>
+<command id="clear-all-blacklisted" i18n-values=".label:restorethumbnails">
+<command id="apps-launch-command">
+<command id="apps-options-command" i18n-values=".label:appoptions">
+<command id="apps-uninstall-command" i18n-values=".label:appuninstall">
+
+<menu id="option-menu">
+ <button command="#clear-all-blacklisted"></button>
+</menu>
+
+<menu id="app-context-menu">
+ <button class="default" command="#apps-launch-command"></button>
+ <hr>
+ <button command="#apps-options-command"></button>
+ <button command="#apps-uninstall-command"></button>
+</menu>
+
</body>
<script src="shared/js/i18n_template.js"></script>
@@ -188,12 +201,29 @@ i18nTemplate.process(document, templateData);
<script src="shared/js/local_strings.js"></script>
<script src="shared/js/class_list.js"></script>
<script src="shared/js/parse_html_subset.js"></script>
+
+<script src="shared/js/cr.js"></script>
+<script src="shared/js/cr/ui.js"></script>
+<script src="shared/js/cr/ui/command.js"></script>
+<script src="shared/js/cr/ui/menu_item.js"></script>
+<script src="shared/js/cr/ui/menu.js"></script>
+<script src="shared/js/cr/ui/position_util.js"></script>
+<script src="shared/js/cr/ui/menu_button.js"></script>
+<script src="shared/js/cr/ui/context_menu_button.js"></script>
+<script src="shared/js/cr/ui/context_menu_handler.js"></script>
+
<script src="ntp/util.js"></script>
<script src="ntp/most_visited.js"></script>
<script src="new_new_tab.js"></script>
<script src="ntp/apps.js"></script>
<script>
+cr.ui.decorate('menu', cr.ui.Menu);
+cr.ui.decorate('command', cr.ui.Command);
+cr.ui.decorate('button[menu]', cr.ui.MenuButton);
+</script>
+
+<script>
updateSimpleSection('apps', Section.APPS);
updateSimpleSection('most-visited', Section.THUMB);
updateSimpleSection('recently-closed', Section.RECENT);
diff --git a/chrome/browser/resources/new_new_tab.js b/chrome/browser/resources/new_new_tab.js
index 6fbd6c7..79a459f 100644
--- a/chrome/browser/resources/new_new_tab.js
+++ b/chrome/browser/resources/new_new_tab.js
@@ -647,208 +647,13 @@ function showFirstRunNotification() {
notification.classList.add('first-run');
}
-/**
- * This handles the option menu.
- * @param {Element} button The button element.
- * @param {Element} menu The menu element.
- * @constructor
- */
-function OptionMenu(button, menu) {
- this.button = button;
- this.menu = menu;
- this.button.onclick = bind(this.handleClick, this);
- this.button.onmousedown = bind(this.handleMouseDown, this);
- this.button.onkeydown = bind(this.handleKeyDown, this);
- this.boundHideMenu_ = bind(this.hide, this);
- this.boundMaybeHide_ = bind(this.maybeHide_, this);
- this.menu.onmouseover = bind(this.handleMouseOver, this);
- this.menu.onmouseout = bind(this.handleMouseOut, this);
- this.menu.onmouseup = bind(this.handleMouseUp, this);
-}
-
-OptionMenu.prototype = {
- show: function() {
- this.positionMenu_();
- this.menu.style.display = 'block';
- this.button.classList.add('open');
- this.button.focus();
-
- // Listen to document and window events so that we hide the menu when the
- // user clicks outside the menu or tabs away or the whole window is blurred.
- document.addEventListener('focus', this.boundMaybeHide_, true);
- document.addEventListener('mousedown', this.boundMaybeHide_, true);
- },
-
- positionMenu_: function() {
- var rect = this.button.getBoundingClientRect();
- this.menu.style.top = rect.bottom + 'px';
- if (document.documentElement.dir == 'rtl')
- this.menu.style.left = rect.left + 'px';
- else
- this.menu.style.right = (document.body.clientWidth - rect.right) + 'px'
- },
-
- hide: function() {
- this.menu.style.display = 'none';
- this.button.classList.remove('open');
- this.setSelectedIndex(-1);
-
- document.removeEventListener('focus', this.boundMaybeHide_, true);
- document.removeEventListener('mousedown', this.boundMaybeHide_, true);
- },
-
- isShown: function() {
- return this.menu.style.display == 'block';
- },
-
- /**
- * Callback for document mousedown and focus. It checks if the user tried to
- * navigate to a different element on the page and if so hides the menu.
- * @param {Event} e The mouse or focus event.
- * @private
- */
- maybeHide_: function(e) {
- if (!this.menu.contains(e.target) && !this.button.contains(e.target)) {
- this.hide();
- }
- },
-
- handleMouseDown: function(e) {
- if (this.isShown()) {
- this.hide();
- } else {
- this.show();
- }
- },
-
- handleClick: function(e) {
- e.stopPropagation();
- },
-
- handleMouseOver: function(e) {
- var el = e.target;
- if (!el.hasAttribute('command')) {
- this.setSelectedIndex(-1);
- } else {
- var index = Array.prototype.indexOf.call(this.menu.children, el);
- this.setSelectedIndex(index);
- }
- },
-
- handleMouseOut: function(e) {
- this.setSelectedIndex(-1);
- },
-
- handleMouseUp: function(e) {
- var item = this.getSelectedItem();
- if (item) {
- this.executeItem(item);
- }
- },
-
- handleKeyDown: function(e) {
- var item = this.getSelectedItem();
-
- var self = this;
- function selectNextVisible(m) {
- var children = self.menu.children;
- var len = children.length;
- var i = self.selectedIndex_;
- if (i == -1 && m == -1) {
- // Edge case when we need to go the last item fisrt.
- i = 0;
- }
- while (true) {
- i = (i + m + len) % len;
- item = children[i];
- if (item && item.hasAttribute('command') &&
- item.style.display != 'none') {
- break;
- }
- }
- if (item) {
- self.setSelectedIndex(i);
- }
- }
-
- switch (e.keyIdentifier) {
- case 'Down':
- if (!this.isShown()) {
- this.show();
- }
- selectNextVisible(1);
- e.preventDefault();
- break;
- case 'Up':
- if (!this.isShown()) {
- this.show();
- }
- selectNextVisible(-1);
- e.preventDefault();
- break;
- case 'Esc':
- case 'U+001B': // Maybe this is remote desktop playing a prank?
- this.hide();
- break;
- case 'Enter':
- case 'U+0020': // Space
- if (this.isShown()) {
- if (item) {
- this.executeItem(item);
- } else {
- this.hide();
- }
- } else {
- this.show();
- }
- e.preventDefault();
- break;
- }
- },
-
- selectedIndex_: -1,
- setSelectedIndex: function(i) {
- if (i != this.selectedIndex_) {
- var items = this.menu.children;
- var oldItem = items[this.selectedIndex_];
- if (oldItem) {
- oldItem.removeAttribute('selected');
- }
- var newItem = items[i];
- if (newItem) {
- newItem.setAttribute('selected', 'selected');
- }
- this.selectedIndex_ = i;
- }
- },
-
- getSelectedItem: function() {
- return this.menu.children[this.selectedIndex_] || null;
- },
-
- executeItem: function(item) {
- var command = item.getAttribute('command');
- if (command in this.commands) {
- this.commands[command].call(this, item);
- }
-
- this.hide();
- }
-};
-
-var optionMenu = new OptionMenu(
- document.querySelector('#most-visited h2 .settings-wrapper'),
- $('option-menu'));
-optionMenu.commands = {
- 'clear-all-blacklisted' : function() {
- mostVisited.clearAllBlacklisted();
- chrome.send('getMostVisited');
- }
-};
-
$('main').addEventListener('click', function(e) {
var p = e.target;
while (p && p.tagName != 'H2') {
+ // In case the user clicks on a button we do not want to expand/collapse a
+ // section.
+ if (p.tagName == 'BUTTON')
+ return;
p = p.parentNode;
}
@@ -1066,17 +871,6 @@ function callGetSyncMessageIfSyncIsPresent() {
}
}
-function hideAllMenus() {
- optionMenu.hide();
-}
-
-window.addEventListener('blur', hideAllMenus);
-window.addEventListener('keydown', function(e) {
- if (e.keyIdentifier == 'Alt' || e.keyIdentifier == 'Meta') {
- hideAllMenus();
- }
-}, true);
-
// Tooltip for elements that have text that overflows.
document.addEventListener('mouseover', function(e) {
// We don't want to do this while we are dragging because it makes things very
diff --git a/chrome/browser/resources/new_tab_theme.css b/chrome/browser/resources/new_tab_theme.css
index 237274e..e21eaef 100644
--- a/chrome/browser/resources/new_tab_theme.css
+++ b/chrome/browser/resources/new_tab_theme.css
@@ -134,8 +134,7 @@ body {
color: $8; /* COLOR_NTP_TEXT */
}
-.app:hover > .front > a,
-.app > .back {
+.app:hover > a {
color: $$3; /* COLOR_NTP_SECTION_TEXT */
background-color: $$1; /* COLOR_NTP_SECTION */;
}
diff --git a/chrome/browser/resources/ntp/apps.css b/chrome/browser/resources/ntp/apps.css
index 1527d9b..9c51f44 100644
--- a/chrome/browser/resources/ntp/apps.css
+++ b/chrome/browser/resources/ntp/apps.css
@@ -13,8 +13,6 @@
width: 124px; /* 920 / 7 - margin * 2 */
}
-.app > .front,
-.app > .back,
.app a {
border-radius: 10px;
bottom: 0;
@@ -24,12 +22,6 @@
top: 0;
}
-.app > .front,
-.app > .back {
- -webkit-backface-visibility: hidden;
- -webkit-transition: -webkit-transform .15s;
-}
-
.app a {
-webkit-transition: background-color .5s;
background: rgba(255, 255, 255, 0) /* transparent white */
@@ -45,8 +37,9 @@
white-space: nowrap;
}
-.app .flip {
+.app .app-settings {
background-color: transparent;
+ background-position: center center;
border: 0;
height: 14px;
padding: 0;
@@ -56,49 +49,24 @@
width: 14px;
}
-.app > .front > .flip {
+.app > .app-settings {
-webkit-transition: opacity .3s;
-webkit-transition-delay: 0;
background-image: url(chrome://theme/IDR_BALLOON_WRENCH);
opacity: 0;
}
-.app > .front > .flip:hover {
+.app > .app-settings:hover {
-webkit-transition: none;
background-image: url(chrome://theme/IDR_BALLOON_WRENCH_H);
}
-.app:hover > .front > .flip,
-.app > .front > .flip:focus {
+.app:hover > .app-settings,
+.app > .app-settings:focus {
-webkit-transition-delay: .5s;
opacity: .9;
}
-.app > .back > .flip {
- background-image: url(chrome://theme/IDR_BALLOON_CLOSE);
- opacity: .9;
-}
-
-.app > .back > .flip:hover {
- background-image: url(chrome://theme/IDR_BALLOON_CLOSE_HOVER);
-}
-
-.app > .back {
- padding: 10px;
-}
-
-.app > .back > h2 {
- font-size: 100%;
- margin: 10px 0;
- overflow: hidden;
- text-overflow: ellipsis;
- white-space: nowrap;
-}
-
-.app > .back > button:not(.flip) {
- width: 100%;
-}
-
@-webkit-keyframes bounce {
0% {
-webkit-transform: scale(0, 0);
@@ -122,37 +90,10 @@
-webkit-transition: opacity .5s;
}
-a[app_id=web-store-entry] {
+a[app-id=web-store-entry] {
background-image: url("web_store_icon.png");
}
-/* Make items on the wrong side non focusable by hiding them. */
-.app:not(.config) > .back button,
-.app.config > .front button,
-.app.config > .front a {
- display: none;
-}
-
-html[has_3d=true] .app.config > .front {
- -webkit-transform: rotateY(180deg);
-}
-
-html[has_3d=true] .app > .back {
- -webkit-transform: rotateY(-180deg);
-}
-
-html[has_3d=true] .app.config > .back {
- -webkit-transform: rotateY(0deg);
-}
-
-html[has_3d=false] .app.config > .front {
- display: none;
-}
-
-html[has_3d=false] .app > .back {
- display: none;
-}
-
-html[has_3d=false] .app.config > .back {
- display: block;
+menu > button.default {
+ font-weight: bold;
}
diff --git a/chrome/browser/resources/ntp/apps.js b/chrome/browser/resources/ntp/apps.js
index 0099634..c946b4d 100644
--- a/chrome/browser/resources/ntp/apps.js
+++ b/chrome/browser/resources/ntp/apps.js
@@ -30,111 +30,164 @@ function getAppsCallback(data) {
layoutSections();
}
-var apps = {
- /**
- * @this {!HTMLAnchorElement}
- */
- handleClick_: function() {
+var apps = (function() {
+
+ function createElement(app) {
+ var div = document.createElement('div');
+ div.className = 'app';
+
+ var a = div.appendChild(document.createElement('a'));
+ a.setAttribute('app-id', app['id']);
+ a.xtitle = a.textContent = app['name'];
+ a.href = app['launch_url'];
+
+ return div;
+ }
+
+ function createContextMenu(app) {
+ var menu = new cr.ui.Menu;
+ var button = document.createElement(button);
+ }
+
+ function launchApp(appId) {
+ var appsSection = $('apps');
+ var expanded = !appsSection.classList.contains('hidden');
+ var element = document.querySelector(
+ (expanded ? '.maxiview' : '.miniview') + ' a[app-id=' + appId + ']');
+
// TODO(arv): Handle zoom?
- var rect = this.getBoundingClientRect();
- var cs = getComputedStyle(this);
+ var rect = element.getBoundingClientRect();
+ var cs = getComputedStyle(element);
var size = cs.backgroundSize.split(/\s+/); // background-size has the
// format '123px 456px'.
+
var width = parseInt(size[0], 10);
var height = parseInt(size[1], 10);
- // We are using background-position-x 50%.
- var left = rect.left + ((rect.width - width) >> 1); // Integer divide by 2.
- var top = rect.top + parseInt(cs.backgroundPositionY, 10);
- chrome.send('launchApp', [this.getAttribute("app_id"),
+ var top, left;
+ if (expanded) {
+ // We are using background-position-x 50%.
+ top = rect.top + parseInt(cs.backgroundPositionY, 10);
+ left = rect.left + ((rect.width - width) >> 1); // Integer divide by 2.
+
+ } else {
+ // We are using background-position-y 50%.
+ top = rect.top + ((rect.height - width) >> 1); // Integer divide by 2.
+ if (getComputedStyle(element).direction == 'rtl')
+ left = rect.left + rect.width - width;
+ else
+ left = rect.left;
+ }
+
+ chrome.send('launchApp', [appId,
String(left), String(top),
String(width), String(height)]);
+ }
+
+ /**
+ * @this {!HTMLAnchorElement}
+ */
+ function handleClick(e) {
+ var appId = e.currentTarget.getAttribute('app-id');
+ launchApp(appId);
return false;
- },
+ }
- createElement_: function(app) {
- var div = document.createElement('div');
- div.className = 'app';
+ var currentApp;
- var front = div.appendChild(document.createElement('div'));
- front.className = 'front';
+ function addContextMenu(el, app) {
+ el.addEventListener('contextmenu', cr.ui.contextMenuHandler);
+ el.addEventListener('keydown', cr.ui.contextMenuHandler);
+ el.addEventListener('keyup', cr.ui.contextMenuHandler);
- var a = front.appendChild(document.createElement('a'));
- a.setAttribute('app_id', app['id']);
- a.xtitle = a.textContent = app['name'];
- a.href = app['launch_url'];
+ Object.defineProperty(el, 'contextMenu', {
+ get: function() {
+ currentApp = app;
- return div;
- },
-
- createElement: function(app) {
- var div = this.createElement_(app);
- var front = div.firstChild;
- var a = front.firstChild;
-
- a.onclick = apps.handleClick_;
- a.style.backgroundImage = url(app['icon_big']);
- if (hashParams['app-id'] == app['id']) {
- div.setAttribute('new', 'new');
- // Delay changing the attribute a bit to let the page settle down a bit.
- setTimeout(function() {
- div.setAttribute('new', 'installed');
- }, 500);
- }
+ $('apps-launch-command').label = app['name'];
+ $('apps-options-command').canExecuteChange();
- var settingsButton = front.appendChild(document.createElement('button'));
- settingsButton.className = 'flip';
- settingsButton.title = localStrings.getString('appsettings');
-
- var back = div.appendChild(document.createElement('div'));
- back.className = 'back';
-
- var header = back.appendChild(document.createElement('h2'));
- header.textContent = app['name'];
-
- var optionsButton = back.appendChild(document.createElement('button'));
- optionsButton.textContent = localStrings.getString('appoptions');
- optionsButton.disabled = !app['options_url'];
- optionsButton.onclick = function() {
- window.location = app['options_url'];
- };
-
- var uninstallButton = back.appendChild(document.createElement('button'));
- uninstallButton.textContent = uninstallButton.xtitle =
- localStrings.getString('appuninstall');
- uninstallButton.onclick = function() {
- chrome.send('uninstallApp', [app['id']]);
- };
-
- var closeButton = back.appendChild(document.createElement('button'));
- closeButton.title = localStrings.getString('close');
- closeButton.className = 'flip';
- closeButton.onclick = settingsButton.onclick = function() {
- div.classList.toggle('config');
- };
+ return $('app-context-menu');
+ }
+ });
+ }
- return div;
- },
+ document.addEventListener('command', function(e) {
+ if (!currentApp)
+ return;
+
+ switch (e.command.id) {
+ case 'apps-options-command':
+ window.location = currentApp['options_url'];
+ break;
+ case 'apps-launch-command':
+ launchApp(currentApp['id']);
+ break;
+ case 'apps-uninstall-command':
+ chrome.send('uninstallApp', [currentApp['id']]);
+ break;
+ }
+ });
- createMiniviewElement: function(app) {
- var span = document.createElement('span');
- var a = span.appendChild(document.createElement('a'));
+ document.addEventListener('canExecute', function(e) {
+ switch (e.command.id) {
+ case 'apps-options-command':
+ e.canExecute = currentApp && currentApp['options_url'];
+ break;
+ case 'apps-launch-command':
+ case 'apps-uninstall-command':
+ e.canExecute = true;
+ break;
+ }
+ });
- a.setAttribute('app_id', app['id']);
- a.textContent = app['name'];
- a.href = app['launch_url'];
- a.onclick = apps.handleClick_;
- a.style.backgroundImage = url(app['icon_small']);
- a.className = 'item';
- span.appendChild(a);
- return span;
- },
-
- createWebStoreElement: function() {
- return this.createElement_({
- 'id': 'web-store-entry',
- 'name': localStrings.getString('web_store_title'),
- 'launch_url': localStrings.getString('web_store_url')
- });
- }
-};
+ return {
+ createElement: function(app) {
+ var div = createElement(app);
+ var a = div.firstChild;
+
+ a.onclick = handleClick;
+ a.style.backgroundImage = url(app['icon_big']);
+ if (hashParams['app-id'] == app['id']) {
+ div.setAttribute('new', 'new');
+ // Delay changing the attribute a bit to let the page settle down a bit.
+ setTimeout(function() {
+ div.setAttribute('new', 'installed');
+ }, 500);
+ }
+
+ var settingsButton = div.appendChild(new cr.ui.ContextMenuButton);
+ settingsButton.className = 'app-settings';
+ settingsButton.title = localStrings.getString('appsettings');
+
+ addContextMenu(div, app);
+
+ return div;
+ },
+
+ createMiniviewElement: function(app) {
+ var span = document.createElement('span');
+ var a = span.appendChild(document.createElement('a'));
+
+ a.setAttribute('app-id', app['id']);
+ a.textContent = app['name'];
+ a.href = app['launch_url'];
+ a.onclick = handleClick;
+ a.style.backgroundImage = url(app['icon_small']);
+ a.className = 'item';
+ span.appendChild(a);
+
+ addContextMenu(span, app);
+
+ return span;
+ },
+
+ createWebStoreElement: function() {
+ return createElement({
+ 'id': 'web-store-entry',
+ 'name': localStrings.getString('web_store_title'),
+ 'launch_url': localStrings.getString('web_store_url')
+ });
+ }
+ };
+})();
diff --git a/chrome/browser/resources/ntp/most_visited.js b/chrome/browser/resources/ntp/most_visited.js
index 7dac8a4..bff2c1f 100644
--- a/chrome/browser/resources/ntp/most_visited.js
+++ b/chrome/browser/resources/ntp/most_visited.js
@@ -56,6 +56,10 @@ var MostVisited = (function() {
document.addEventListener('DOMContentLoaded',
bind(this.ensureSmallGridCorrect, this));
+ // Commands
+ document.addEventListener('command', bind(this.handleCommand_, this));
+ document.addEventListener('canExecute', bind(this.handleCanExecute_, this));
+
// DND
el.addEventListener('dragstart', bind(this.handleDragStart_, this));
el.addEventListener('dragenter', bind(this.handleDragEnter_, this));
@@ -300,6 +304,23 @@ var MostVisited = (function() {
return this.getMostVisitedLayoutRects_()[index];
},
+ // Commands
+
+ handleCommand_: function(e) {
+ var commandId = e.command.id;
+ switch (commandId) {
+ case 'clear-all-blacklisted':
+ this.clearAllBlacklisted();
+ chrome.send('getMostVisited');
+ break;
+ }
+ },
+
+ handleCanExecute_: function(e) {
+ if (e.command.id == 'clear-all-blacklisted')
+ e.canExecute = true;
+ },
+
// DND
currentOverItem_: null,
diff --git a/chrome/browser/resources/shared/css/menu.css b/chrome/browser/resources/shared/css/menu.css
index 9ee83e6..39ddafd 100644
--- a/chrome/browser/resources/shared/css/menu.css
+++ b/chrome/browser/resources/shared/css/menu.css
@@ -1,17 +1,17 @@
menu {
display: none;
- position: absolute;
+ position: fixed;
border: 1px solid rgba(0, 0, 0, .50);
-webkit-box-shadow: 0px 2px 4px rgba(0, 0, 0, .50);
color: black;
background: -webkit-gradient(linear, 0 0, 0 100%, from(#fff), to(#eee));
left: 0;
white-space: nowrap;
- z-index: 2;
padding: 8px 0;
margin: 0;
cursor: default;
border-radius: 3px;
+ z-index: 3;
}
menu > * {
diff --git a/chrome/browser/resources/shared/js/cr/ui/command.js b/chrome/browser/resources/shared/js/cr/ui/command.js
index 4df2275..4f4610d 100644
--- a/chrome/browser/resources/shared/js/cr/ui/command.js
+++ b/chrome/browser/resources/shared/js/cr/ui/command.js
@@ -282,7 +282,7 @@ cr.define('cr.ui', function() {
return this.canExecute_;
},
set canExecute(canExecute) {
- this.canExecute_ = canExecute;
+ this.canExecute_ = !!canExecute;
this.stopPropagation();
}
};
diff --git a/chrome/browser/resources/shared/js/cr/ui/position_util.js b/chrome/browser/resources/shared/js/cr/ui/position_util.js
index 85e86b2..380e9e1 100644
--- a/chrome/browser/resources/shared/js/cr/ui/position_util.js
+++ b/chrome/browser/resources/shared/js/cr/ui/position_util.js
@@ -57,10 +57,15 @@ cr.define('cr.ui', function() {
*/
function positionPopupAroundRect(anchorRect, popupElement, type) {
var popupRect = popupElement.getBoundingClientRect();
- var popupContainer = popupElement.offsetParent;
+ var popupContainer;
+ var cs = popupElement.ownerDocument.defaultView.
+ getComputedStyle(popupElement);
+ if (cs.position == 'fixed')
+ popupContainer = popupElement.ownerDocument.body;
+ else
+ popupContainer = popupElement.offsetParent;
var availRect = popupContainer.getBoundingClientRect();
- var rtl = popupElement.ownerDocument.defaultView.
- getComputedStyle(popupElement).direction == 'rtl';
+ var rtl = cs.direction == 'rtl';
// Flip BEFORE, AFTER based on RTL.
if (rtl) {