Skip to content
This repository has been archived by the owner on Nov 3, 2021. It is now read-only.

Commit

Permalink
Merge pull request #28095 from rexboy7/1129386-targeted-context-menu
Browse files Browse the repository at this point in the history
Bug 1129386 - [Stingray][System] Send keyboard events to only focused co.... r=johnhu
  • Loading branch information
rexboy7 committed Feb 10, 2015
2 parents 63d943d + 1980fc8 commit 7463823
Show file tree
Hide file tree
Showing 6 changed files with 111 additions and 114 deletions.
16 changes: 10 additions & 6 deletions tv_apps/smart-system/js/app_modal_dialog.js
Expand Up @@ -267,7 +267,9 @@
}

this.simpleKeyNavigation.start(
[elements.alertOk], SimpleKeyNavigation.DIRECTION.HORIZONTAL);
[elements.alertOk],
SimpleKeyNavigation.DIRECTION.HORIZONTAL,
{target: elements.alert});

// XXX: Focusing smart-button fails at the second time popup if we don't
// postpone it. We need to find the root cause.
Expand Down Expand Up @@ -300,12 +302,13 @@
document.activeElement.blur();
var horizontalButtonNavigation = new SimpleKeyNavigation();
horizontalButtonNavigation.start(
[elements.promptCancel, elements.promptOk],
SimpleKeyNavigation.DIRECTION.HORIZONTAL,
true);
[elements.promptCancel, elements.promptOk],
SimpleKeyNavigation.DIRECTION.HORIZONTAL,
{isChild: true});
this.simpleKeyNavigation.start(
[elements.promptInput, horizontalButtonNavigation],
SimpleKeyNavigation.DIRECTION.VERTICAL);
SimpleKeyNavigation.DIRECTION.VERTICAL,
{target: elements.prompt});
elements.promptInput.select();
break;

Expand All @@ -331,7 +334,8 @@
document.activeElement.blur();
this.simpleKeyNavigation.start(
[elements.confirmCancel, elements.confirmOk],
SimpleKeyNavigation.DIRECTION.HORIZONTAL);
SimpleKeyNavigation.DIRECTION.HORIZONTAL,
{target: elements.confirm});

// XXX: Focusing smart-button fails at the second time popup if we don't
// postpone it. We need to find the root cause.
Expand Down
47 changes: 22 additions & 25 deletions tv_apps/smart-system/js/browser_context_menu.js
Expand Up @@ -23,15 +23,11 @@

this.keyNavigationAdapter = new KeyNavigationAdapter();
this.keyNavigationAdapter.on('move', function(key) {
this.scrollable.move(key);
}.bind(this));
// All behaviors which no need to have multple events while holding the
// key should use keyup.
this.keyNavigationAdapter.on('enter-keyup', function() {
this.scrollable.currentItem.click();
this.scrollable && this.scrollable.move(key);
}.bind(this));

// All behaviors which no need to have multple events while holding the
// key should use keyup
// key should use keyup
this.keyNavigationAdapter.on('esc-keyup', this.hide.bind(this));

this.circleAnimation = Animations
Expand All @@ -44,17 +40,10 @@

BrowserContextMenu.prototype.handleFocus = function(scrollable, elem) {
if (elem.nodeName) {
elem.classList.add('hover');
elem.focus();
}
};

BrowserContextMenu.prototype.handleUnfocus = function(scrollable, elem) {
if (elem.nodeName) {
elem.classList.remove('hover');
}
};

BrowserContextMenu.prototype.CLASS_NAME = 'BrowserContextMenu';
BrowserContextMenu.prototype.ELEMENT_PREFIX = 'contextmenu-';

Expand Down Expand Up @@ -116,8 +105,6 @@
BrowserContextMenu.prototype.show = function(evt) {
var detail = evt.detail;

this.keyNavigationAdapter.init();

var hasContextMenu = detail.contextmenu &&
detail.contextmenu.items.length > 0;
var hasSystemTargets = detail.systemTargets &&
Expand Down Expand Up @@ -145,6 +132,9 @@
evt.preventDefault();
evt.stopPropagation();
this.showMenu(items);

// We need to init this after showMenu for fetching this.element
this.keyNavigationAdapter.init(this.element);
};

BrowserContextMenu.prototype.hasMenuVisible = function() {
Expand All @@ -162,30 +152,40 @@
}
this._injected = true;
this.buildMenu(menu);
document.activeElement.blur();
this.scrollable.catchFocus();

this._createCloseMenuHandler();
this.circleAnimation.play({type: 'grow'}, function() {
this.element.classList.add('visible');
Animations.doBubbleAnimation(
this.contextFrame, '.' + this.ELEMENT_PREFIX + 'button', 100);
// XXX: We need to wait a short interval before we can focus on the
// button element. (This is NOT related to bubble animation above)
// so we temporarily use setTimeout here.
// This may need to be fixed from Gecko.
setTimeout(function() {
document.activeElement.blur();
this.scrollable.catchFocus();
}.bind(this), 100);
}.bind(this));
},

BrowserContextMenu.prototype._createElement = function(item) {
var self = this;

var container = document.createElement('div');
var action = document.createElement('button');
var action = document.createElement('smart-button');
var icon = document.createElement('div');

action.dataset.id = item.id;
action.dataset.value = item.value;
var l10nPayload = item.labelL10nId ? item.labelL10nId : {raw: item.label};
SharedUtils.localizeElement(action, l10nPayload);

action.className = self.ELEMENT_PREFIX + 'button';
action.setAttribute('type', 'contextmenu');

icon.classList.add('icon');
if (item.icon) {
icon.classList.add(item.iconClass || 'icon');
icon.style.backgroundImage = 'url(' + item.icon + ')';
}

Expand All @@ -200,7 +200,7 @@
this.elements.list.appendChild(container);
},

BrowserContextMenu.prototype._createTransitionHandler = function() {
BrowserContextMenu.prototype._createCloseMenuHandler = function() {
var self = this;
var onFrameDisappear = function onFrameDisappear(evt) {
if (evt.propertyName === 'opacity' &&
Expand Down Expand Up @@ -229,16 +229,13 @@
this.elements.list.innerHTML = '';
items.forEach(this._createElement, this);

this._createTransitionHandler();

this.scrollable = new XScrollable({
frameElem: this.elements.listFrame,
listElem: this.elements.list,
itemClassName: self.ELEMENT_PREFIX + 'button',
margin: 8.2
spacing: 8.2
});
this.scrollable.on('focus', this.handleFocus.bind(this));
this.scrollable.on('unfocus', this.handleUnfocus.bind(this));
};

BrowserContextMenu.prototype._listItems = function(detail) {
Expand Down
3 changes: 2 additions & 1 deletion tv_apps/smart-system/js/interactive_notifications.js
Expand Up @@ -189,7 +189,8 @@
// focus() for us when the focus switches to another button.
this._keyNavigator.start([$('notification-button-0'),
$('notification-button-1')],
SimpleKeyNavigation.DIRECTION.HORIZONTAL);
SimpleKeyNavigation.DIRECTION.HORIZONTAL,
{target: this._banner});
} else {
document.activeElement.blur();
}
Expand Down
137 changes: 65 additions & 72 deletions tv_apps/smart-system/style/action_menu/action_menu_extended.css
Expand Up @@ -7,10 +7,10 @@
height: calc(100% - 7rem);
}

/* Extending action menu with icon capability & transition*/
/* Extending action menu with icon capability & transition */

form[role="dialog"][data-type="action"] > div > menu > div > button .icon,
form[role="dialog"][data-type="object"] > div > menu > div > button .icon {
smart-button[type="contextmenu"] > .icon {
content: attr(data-icon);
background-position: center top 4.8rem;
background-size: 10rem;
background-repeat: no-repeat;
Expand All @@ -21,8 +21,7 @@ form[role="dialog"][data-type="object"] > div > menu > div > button .icon {
height: 100%;
}

form[role="dialog"][data-type="action"] > div > menu > div > button.hover .icon,
form[role="dialog"][data-type="object"] > div > menu > div > button.hover .icon {
smart-button[type="contextmenu"].focused:not(.pressed) > .icon {
filter: url(invert.svg#invert);
opacity: 0.824;
}
Expand All @@ -40,77 +39,71 @@ form[role="dialog"][data-type="object"].visible {
transform: translateY(0);
}

@media (min-width: 768px) {
form[role="dialog"][data-type="action"],
form[role="dialog"][data-type="object"] {
-moz-box-sizing: border-box;
background-color: rgba(0,0,0,0.9);
}

form[role="dialog"][data-type="action"] > header,
form[role="dialog"][data-type="object"] > header {
top: 5rem;
left: 7.6rem;
font-size: 5.4rem;
font-style: italic;
height: 10rem;
color: white;
border: none;
padding: 0;
}
form[role="dialog"][data-type="action"],
form[role="dialog"][data-type="object"] {
-moz-box-sizing: border-box;
background-color: rgba(0,0,0,0.9);
}

form[role="dialog"][data-type="action"] > div,
form[role="dialog"][data-type="object"] > div {
margin: 0 auto;
width: 100%;
height: 30rem;
padding-top: 3rem;
top: calc(50% - 15rem);
left: 0;
text-align: center;
overflow: hidden;
position: absolute;
}
form[role="dialog"][data-type="action"] > header,
form[role="dialog"][data-type="object"] > header {
top: 5rem;
left: 7.6rem;
font-size: 5.4rem;
font-style: italic;
height: 10rem;
color: white;
border: none;
padding: 0;
}

form[role="dialog"][data-type="action"] > div > menu {
transition: transform 0.2s ease;
}
form[role="dialog"][data-type="action"] > div,
form[role="dialog"][data-type="object"] > div {
margin: 0 auto;
width: 100%;
height: 30rem;
padding-top: 3rem;
top: calc(50% - 15rem);
left: 0;
text-align: center;
overflow: hidden;
position: absolute;
}

form[role="dialog"][data-type="action"] > div > menu > div,
form[role="dialog"][data-type="action"] > div > menu > div {
position: absolute;
left: 0;
margin: 0 3rem;
}
form[role="dialog"][data-type="action"] > div > menu {
transition: transform 0.2s ease;
}

form[role="dialog"][data-type="action"] > div > menu > div > button,
form[role="dialog"][data-type="object"] > div > menu > div > button {
width: 24rem;
height: 24rem;
border-radius: 12rem;
background-color: #5f5f5f;
padding-top: 14.8rem;
padding-bottom: 5rem;
font-size: 2rem;
font-style: italic;
text-align: center;
color: white;
transition: transform 0.2s ease, background-color 0.2s ease;
}
form[role="dialog"][data-type="action"] > div > menu > div,
form[role="dialog"][data-type="action"] > div > menu > div {
position: absolute;
left: 0;
margin: 0 3rem;
}

form[role="dialog"][data-type="action"] > div > menu > div > button.hover,
form[role="dialog"][data-type="object"] > div > menu > div > button.hover {
transform: scale(1.2);
background-color: white;
color: #2d2d2d;
}
smart-button[type="contextmenu"] {
width: 24rem;
height: 24rem;
border-radius: 12rem;
background-color: #5f5f5f;
padding-top: 14.8rem;
padding-bottom: 5rem;
font-size: 2rem;
font-style: italic;
text-align: center;
color: white;
line-height: 2.8rem;
box-sizing: border-box;
}

form[role="dialog"][data-type="action"] > div > menu > div > button.pressed,
form[role="dialog"][data-type="object"] > div > menu > div > button.pressed {
background-color: #00caf2;
color: white;
}
smart-button[type="contextmenu"].focused {
transform: scale(1.2);
color: #2d2d2d;
background-color: white;
}

[role="dialog"][data-type="action"] > div > menu > div:last-child > button:before {
display: none;
}
smart-button[type="contextmenu"].pressed {
transform: scale(1);
background-color: #00caf2;
color: white;
}
11 changes: 6 additions & 5 deletions tv_apps/tv_shared/js/key_navigation_adapter.js
Expand Up @@ -8,13 +8,14 @@
}

KeyNavigationAdapter.prototype = evt({
init: function kna_init() {
window.addEventListener('keydown', this);
window.addEventListener('keyup', this);
init: function kna_init(targetElement) {
this._targetElement = targetElement || window;
this._targetElement.addEventListener('keydown', this);
this._targetElement.addEventListener('keyup', this);
},
uninit: function kna_uninit() {
window.removeEventListener('keydown', this);
window.removeEventListener('keyup', this);
this._targetElement.removeEventListener('keydown', this);
this._targetElement.removeEventListener('keyup', this);
},

handleEvent: function kna_handleEvent(evt) {
Expand Down
11 changes: 6 additions & 5 deletions tv_apps/tv_shared/js/simple_key_navigation.js
Expand Up @@ -19,17 +19,18 @@
'VERTICAL': 'vertical'
});

proto.start = function skn_start(list, direction, isChild) {
proto.start = function skn_start(list, direction, options) {
this.direction = direction;
this.updateList(list);
this.isChild = !!isChild;
if (!isChild) {
window.addEventListener('keydown', this);
this.isChild = !!options.isChild;
this.target = options.target || window;
if (!this.isChild) {
this.target.addEventListener('keydown', this);
}
};

proto.stop = function skn_stop() {
window.removeEventListener('keydown', this);
this.target.removeEventListener('keydown', this);
};

proto.updateList = function skn_updateList(list) {
Expand Down

0 comments on commit 7463823

Please sign in to comment.