Commit fd4e05e8 authored by arv@google.com's avatar arv@google.com

Make action buttons listen to the enter key.

Hide menus when the window is blurred or the user presses Alt or Meta.

Only show tootlip for the title of the thumbnail.

Allow mouse over on the window menu.

Made the windows opaque but with a hsla background color to make it more readable.

Quote all background image URLs so that we can display icons for URLs with spaces in them.

Call preventDefault when using the keyboard to navigate the options menu so that the page does not scroll.

BUG=15268, 15503, 15715, 15769, 15411, 15458

TEST=See bug descriptions

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

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@19884 0039d316-1c4b-4281-b951-d872f2087c98
parent 120363b4
...@@ -468,14 +468,13 @@ html[dir='rtl'] .item { ...@@ -468,14 +468,13 @@ html[dir='rtl'] .item {
display: none; display: none;
border: 1px solid #999; border: 1px solid #999;
-webkit-box-shadow: 5px 5px 10px hsla(0, 0%, 0%, .3); -webkit-box-shadow: 5px 5px 10px hsla(0, 0%, 0%, .3);
background-color: white; background-color: hsla(213, 0%, 100%, .95);
width: 157px; width: 157px;
left: 0; left: 0;
white-space: nowrap; white-space: nowrap;
opacity: .9;
z-index: 1; z-index: 1;
pointer-events: none;
padding: 1px; padding: 1px;
cursor: default;
} }
.hbox { .hbox {
......
...@@ -230,8 +230,8 @@ logEvent('log start'); ...@@ -230,8 +230,8 @@ logEvent('log start');
jsdisplay="type == 'tab'" jsdisplay="type == 'tab'"
jsvalues="href:url; jsvalues="href:url;
title:title; title:title;
.style.backgroundImage:'url(chrome://favicon/' + url + .style.backgroundImage:'url("chrome://favicon/' +
')'; url + '")';
dir:direction; dir:direction;
.sessionId:sessionId" .sessionId:sessionId"
jscontent="title"></a> jscontent="title"></a>
...@@ -260,8 +260,8 @@ logEvent('log start'); ...@@ -260,8 +260,8 @@ logEvent('log start');
<a class="item" jsselect="$this" <a class="item" jsselect="$this"
jsdisplay="state != 'CANCELLED'" jsdisplay="state != 'CANCELLED'"
jsvalues="href:file_path;title:url; jsvalues="href:file_path;title:url;
.style.backgroundImage:'url(chrome://fileicon/' + .style.backgroundImage:'url(&quot;chrome://fileicon/' +
file_path + ')'; file_path + '&quot;)';
dir:direction; dir:direction;
.fileId:id" .fileId:id"
jscontent="file_name"></a> jscontent="file_name"></a>
...@@ -301,7 +301,8 @@ logEvent('log start'); ...@@ -301,7 +301,8 @@ logEvent('log start');
<div jsskip="true"> <div jsskip="true">
<div class="window-menu" id="window-menu"> <div class="window-menu" id="window-menu">
<span class="item" jsselect="$this" <span class="item" jsselect="$this"
jsvalues=".style.backgroundImage:'url(chrome://favicon/' + url + ')'; jsvalues=".style.backgroundImage:'url(&quot;chrome://favicon/' + url +
'&quot;)';
dir:direction;" dir:direction;"
jscontent="title"></span> jscontent="title"></span>
</div> </div>
......
...@@ -179,7 +179,6 @@ function renderMostVisited(data) { ...@@ -179,7 +179,6 @@ function renderMostVisited(data) {
continue; continue;
} }
t.title = d.title;
t.href = d.url; t.href = d.url;
t.querySelector('.pin').title = localStrings.getString(d.pinned ? t.querySelector('.pin').title = localStrings.getString(d.pinned ?
'unpinthumbnailtooltip' : 'pinthumbnailtooltip'); 'unpinthumbnailtooltip' : 'pinthumbnailtooltip');
...@@ -190,10 +189,10 @@ function renderMostVisited(data) { ...@@ -190,10 +189,10 @@ function renderMostVisited(data) {
// attack but setting style.backgroundImage = 'url(javascript:...)' does // attack but setting style.backgroundImage = 'url(javascript:...)' does
// not execute the JavaScript in WebKit. // not execute the JavaScript in WebKit.
t.querySelector('.thumbnail-wrapper').style.backgroundImage = t.querySelector('.thumbnail-wrapper').style.backgroundImage =
'url(chrome://thumb/' + d.url + ')'; 'url("chrome://thumb/' + d.url + '")';
var titleDiv = t.querySelector('.title > div'); var titleDiv = t.querySelector('.title > div');
titleDiv.textContent = d.title; titleDiv.title = titleDiv.textContent = d.title;
titleDiv.style.backgroundImage = 'url(chrome://favicon/' + d.url + ')'; titleDiv.style.backgroundImage = 'url("chrome://favicon/' + d.url + '")';
titleDiv.dir = d.direction; titleDiv.dir = d.direction;
} }
} }
...@@ -734,7 +733,7 @@ function OptionMenu(button, menu) { ...@@ -734,7 +733,7 @@ function OptionMenu(button, menu) {
this.menu = menu; this.menu = menu;
this.button.onmousedown = bind(this.handleMouseDown, this); this.button.onmousedown = bind(this.handleMouseDown, this);
this.button.onkeydown = bind(this.handleKeyDown, this); this.button.onkeydown = bind(this.handleKeyDown, this);
this.boundHideMenu_ = bind(this.hideMenu, this); this.boundHideMenu_ = bind(this.hide, this);
this.boundMaybeHide_ = bind(this.maybeHide_, this); this.boundMaybeHide_ = bind(this.maybeHide_, this);
this.menu.onmouseover = bind(this.handleMouseOver, this); this.menu.onmouseover = bind(this.handleMouseOver, this);
this.menu.onmouseout = bind(this.handleMouseOut, this); this.menu.onmouseout = bind(this.handleMouseOut, this);
...@@ -742,7 +741,9 @@ function OptionMenu(button, menu) { ...@@ -742,7 +741,9 @@ function OptionMenu(button, menu) {
} }
OptionMenu.prototype = { OptionMenu.prototype = {
showMenu: function() { show: function() {
windowMenu.hide();
this.menu.style.display = 'block'; this.menu.style.display = 'block';
this.button.focus(); this.button.focus();
...@@ -750,19 +751,17 @@ OptionMenu.prototype = { ...@@ -750,19 +751,17 @@ OptionMenu.prototype = {
// user clicks outside the menu or tabs away or the whole window is blurred. // user clicks outside the menu or tabs away or the whole window is blurred.
document.addEventListener('focus', this.boundMaybeHide_, true); document.addEventListener('focus', this.boundMaybeHide_, true);
document.addEventListener('mousedown', this.boundMaybeHide_, true); document.addEventListener('mousedown', this.boundMaybeHide_, true);
window.addEventListener('blur', this.boundHideMenu_);
}, },
hideMenu: function() { hide: function() {
this.menu.style.display = 'none'; this.menu.style.display = 'none';
this.setSelectedIndex(-1); this.setSelectedIndex(-1);
document.removeEventListener('focus', this.boundMaybeHide_, true); document.removeEventListener('focus', this.boundMaybeHide_, true);
document.removeEventListener('mousedown', this.boundMaybeHide_, true); document.removeEventListener('mousedown', this.boundMaybeHide_, true);
window.removeEventListener('blur', this.boundHide_);
}, },
isMenuShown: function() { isShown: function() {
return this.menu.style.display == 'block'; return this.menu.style.display == 'block';
}, },
...@@ -774,15 +773,15 @@ OptionMenu.prototype = { ...@@ -774,15 +773,15 @@ OptionMenu.prototype = {
*/ */
maybeHide_: function(e) { maybeHide_: function(e) {
if (!this.menu.contains(e.target) && !this.button.contains(e.target)) { if (!this.menu.contains(e.target) && !this.button.contains(e.target)) {
this.hideMenu(); this.hide();
} }
}, },
handleMouseDown: function(e) { handleMouseDown: function(e) {
if (this.isMenuShown()) { if (this.isShown()) {
this.hideMenu(); this.hide();
} else { } else {
this.showMenu(); this.show();
} }
}, },
...@@ -829,29 +828,35 @@ OptionMenu.prototype = { ...@@ -829,29 +828,35 @@ OptionMenu.prototype = {
switch (e.keyIdentifier) { switch (e.keyIdentifier) {
case 'Down': case 'Down':
if (!this.isMenuShown()) { if (!this.isShown()) {
this.showMenu(); this.show();
} }
selectNextVisible(1); selectNextVisible(1);
e.preventDefault();
break; break;
case 'Up': case 'Up':
if (!this.isMenuShown()) { if (!this.isShown()) {
this.showMenu(); this.show();
} }
selectNextVisible(-1); selectNextVisible(-1);
e.preventDefault();
break; break;
case 'Esc': case 'Esc':
case 'U+001B': // Maybe this is remote desktop playing a prank? case 'U+001B': // Maybe this is remote desktop playing a prank?
this.hideMenu(); this.hide();
break; break;
case 'Enter': case 'Enter':
if (this.isMenuShown()) { case 'U+0020': // Space
if (this.isShown()) {
if (item) { if (item) {
this.executeItem(item); this.executeItem(item);
} else {
this.hide();
} }
} else { } else {
this.showMenu(); this.show();
} }
e.preventDefault();
break; break;
} }
}, },
...@@ -885,12 +890,12 @@ OptionMenu.prototype = { ...@@ -885,12 +890,12 @@ OptionMenu.prototype = {
hideSection(section); hideSection(section);
} }
this.hideMenu(); this.hide();
saveShownSections(); saveShownSections();
} }
}; };
new OptionMenu($('option-button'), $('option-menu')); var optionMenu = new OptionMenu($('option-button'), $('option-menu'));
$('most-visited').addEventListener('click', function(e) { $('most-visited').addEventListener('click', function(e) {
var target = e.target; var target = e.target;
...@@ -940,59 +945,94 @@ function maybeReopenTab(e) { ...@@ -940,59 +945,94 @@ function maybeReopenTab(e) {
recentTabs.addEventListener('mouseover', maybeShowWindowMenu); recentTabs.addEventListener('mouseover', maybeShowWindowMenu);
recentTabs.addEventListener('focus', maybeShowWindowMenu, true); recentTabs.addEventListener('focus', maybeShowWindowMenu, true);
recentTabs.addEventListener('mouseout', maybeHideWindowMenu);
recentTabs.addEventListener('blur', maybeHideWindowMenu, true);
function maybeShowWindowMenu(e) { function maybeShowWindowMenu(e) {
var el = findAncestor(e.target, function(el) { var el = findAncestor(e.target, function(el) {
return el.tabItems !== undefined; return el.tabItems !== undefined;
}); });
if (el) { if (el) {
showWindowMenu(el, el.tabItems); windowMenu.show(e, el, el.tabItems);
} }
} }
function maybeHideWindowMenu(e) { /**
var el = findAncestor(e.target, function(el) { * This object represents a window/tooltip representing a closed window. It is
return el.tabItems !== undefined; * shown when hovering over a closed window item or when the item is focused. It
}); * gets hidden when blurred or when mousing out of the menu or the item.
if (el) { * @param {Element} menuEl The element to use as the menu.
$('window-menu').style.display = 'none'; * @constructor
} */
function WindowMenu(menuEl) {
this.menuEl = menuEl;
var self = this;
this.boundHide_ = bind(this.hide, this);
menuEl.onmouseover = function() {
clearTimeout(self.timer);
};
menuEl.onmouseout = this.boundHide_;
} }
function showWindowMenu(el, tabs) { WindowMenu.prototype = {
var menuEl = $('window-menu'); timer: 0,
processData('#window-menu', tabs); show: function(e, linkEl, tabs) {
var rect = el.getBoundingClientRect(); optionMenu.hide();
var bodyRect = document.body.getBoundingClientRect()
var rtl = document.documentElement.dir == 'rtl';
menuEl.style.display = 'block'; clearTimeout(this.timer);
menuEl.style.left = (rtl ? processData('#window-menu', tabs);
rect.left + bodyRect.left + rect.width - menuEl.offsetWidth : var rect = linkEl.getBoundingClientRect();
rect.left + bodyRect.left) + 'px'; var bodyRect = document.body.getBoundingClientRect()
menuEl.style.top = rect.top + bodyRect.top + rect.height + 'px'; var rtl = document.documentElement.dir == 'rtl';
} this.menuEl.style.display = 'block';
this.menuEl.style.left = (rtl ?
rect.left + bodyRect.left + rect.width - this.menuEl.offsetWidth :
rect.left + bodyRect.left) + 'px';
this.menuEl.style.top = rect.top + bodyRect.top + rect.height + 'px';
$('thumb-checkbox').addEventListener('change', function(e) { if (e.type == 'focus') {
if (e.target.checked) { linkEl.onblur = this.boundHide_;
showSection(Section.THUMB); } else { // mouseover
} else { linkEl.onmouseout = this.boundHide_;
hideSection(Section.THUMB); }
},
hide: function() {
// Delay before hiding.
var self = this;
this.timer = setTimeout(function() {
self.menuEl.style.display = 'none';
}, 100);
} }
saveShownSections(); };
});
$('list-checkbox').addEventListener('change', function(e) { var windowMenu = new WindowMenu($('window-menu'));
if (e.target.checked) {
showSection(Section.LIST); function getCheckboxHandler(section) {
} else { return function(e) {
hideSection(Section.LIST); if (e.type == 'keydown') {
if (e.keyIdentifier == 'Enter') {
e.target.checked = !e.target.checked;
} else {
return;
}
}
if (e.target.checked) {
showSection(section);
} else {
hideSection(section);
}
saveShownSections();
} }
saveShownSections(); }
});
$('thumb-checkbox').addEventListener('change',
getCheckboxHandler(Section.THUMB));
$('thumb-checkbox').addEventListener('keydown',
getCheckboxHandler(Section.THUMB));
$('list-checkbox').addEventListener('change',
getCheckboxHandler(Section.LIST));
$('list-checkbox').addEventListener('keydown',
getCheckboxHandler(Section.LIST));
window.addEventListener('load', bind(logEvent, global, 'onload fired')); window.addEventListener('load', bind(logEvent, global, 'onload fired'));
window.addEventListener('load', onDataLoaded); window.addEventListener('load', onDataLoaded);
...@@ -1000,6 +1040,18 @@ window.addEventListener('resize', handleWindowResize); ...@@ -1000,6 +1040,18 @@ window.addEventListener('resize', handleWindowResize);
document.addEventListener('DOMContentLoaded', bind(logEvent, global, document.addEventListener('DOMContentLoaded', bind(logEvent, global,
'domcontentloaded fired')); 'domcontentloaded fired'));
function hideAllMenus() {
windowMenu.hide();
optionMenu.hide();
}
window.addEventListener('blur', hideAllMenus);
window.addEventListener('keydown', function(e) {
if (e.keyIdentifier == 'Alt' || e.keyIdentifier == 'Meta') {
hideAllMenus();
}
}, true);
// DnD // DnD
var dnd = { var dnd = {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment