Commit c2111e06 authored by kristipark's avatar kristipark Committed by Commit Bot

[NTP] Improve accessibility for MV tiles and custom links

- Remove outline on click for:
  - Speech microphone icon
  - Shortcut
  - Edit link icon
  - Edit link dialog buttons
- Fix icon for restore default:
  - https://screenshot.googleplex.com/iVG7ohvNcXUp.png
- Prevent keyboard navigation to disabled "Restore default..." options.
- Keyboard navigation will start at edit dialog after it opens.
- Show add shortcut title for adding instead of edit shortcut.
- Can tab to add shortcut button.
- Keyboard navigation will remain within the edit shortcut dialog when
  open.
- Remove dark gray on click for the edit icon when dark theme/custom
  background.
- Clicking "Done" without modifying anything closes the dialog.
- Allow screen reader to move left/right through the links and edit link
  icons. (User must first use ctrl+shift+opt+down to enter the iframe).
- Prefill URL field with "https://". Text will turn dark gray on text
  input.
  - https://screenshot.googleplex.com/oBJNX4KHxeq.png
  - https://screenshot.googleplex.com/YpbDqiz0hkM.png
- Added labels to all buttons for screen readers ("name" attribute).
  - Edit = "Edit shortcut <title>"
  - Delete = "Remove <title>"
  - Cancel = "Cancel"
  - Edit icon = "Edit shortcut <title>"

Bug: 864357
Change-Id: Ie33248a0f633180e81e7a55373b06fb564f5596a
Reviewed-on: https://chromium-review.googlesource.com/1161096
Commit-Queue: Kristi Park <kristipark@chromium.org>
Reviewed-by: default avatarMathieu Perreault <mathp@chromium.org>
Cr-Commit-Position: refs/heads/master@{#580949}
parent 631ac11a
......@@ -145,7 +145,7 @@ html[dir=rtl] .bg-option-img {
width: 100%;
}
#custom-link-restore-default .bg-option-img {
#custom-links-restore-default .bg-option-img {
background: rgb(241, 243, 244) url(icons/link_gray.svg) no-repeat center;
border-radius: 50%;
}
......
......@@ -2,8 +2,8 @@
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file. */
#edit-link-dialog::backdrop {
background-color: rgba(255, 255, 255, .75);
body {
overflow: hidden;
}
#edit-link-dialog {
......@@ -21,6 +21,10 @@
z-index: 10000;
}
#edit-link-dialog::backdrop {
background: transparent;
}
#edit-link-dialog > div {
width: 100%;
}
......@@ -64,6 +68,10 @@ input {
width: calc(100% - 16px);
}
#url-field:not(.text-modified) {
color: rgba(32, 33, 36, 0.38);
}
.underline {
border-bottom: 2px solid rgb(26, 115, 232);
bottom: 0;
......@@ -132,15 +140,15 @@ button {
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
}
button:disabled {
transition: none;
}
button.primary {
background-color: rgb(26, 115, 232);
color: white;
}
button:focus:not(:active) {
box-shadow: 0 0 0 2px rgba(26, 115, 232, 0.4);
}
button.primary:disabled {
background-color: rgb(241, 243, 244);
color: rgb(128, 134, 139);
......
......@@ -17,15 +17,15 @@
<label id="title-field-name" class="field-title"></label>
<div class="input-container">
<input id="title-field" class="field-input" type="text"
autocomplete="no" tabindex="0" required></input>
autocomplete="off" tabindex="0" required></input>
<div class="underline"></div>
</div>
</div>
<div id="url" class="field-container">
<label id="url-field-name" class="field-title"></label>
<div class="input-container">
<input id="url-field" class="field-input" type="text"
autocomplete="url" tabindex="0" required></input>
<input id="url-field" class="field-input" type="text" value="https://"
autocomplete="off" tabindex="0" required></input>
<div class="underline"></div>
</div>
<div id="invalid-url" class="error-msg"></div>
......
......@@ -35,6 +35,28 @@ const IDS = {
};
/**
* Enum for classes.
* @enum {string}
* @const
*/
const CLASSES = {
// Applied if the input field has been modified.
TEXT_MODIFIED: 'text-modified',
};
/**
* Enum for key codes.
* @enum {int}
* @const
*/
const KEYCODES = {
ENTER: 13,
ESC: 27,
};
/**
* The origin of this request, i.e. 'https://www.google.TLD' for the remote NTP,
* or 'chrome-search://local-ntp' for the local NTP.
......@@ -61,6 +83,27 @@ let prepopulatedLink = {
};
/**
* The title of the dialog when adding a link.
* @type {string}
*/
let addLinkTitle = '';
/**
* The title of the dialog when editing a link.
* @type {string}
*/
let editLinkTitle = '';
/**
* The accessibility title of remove link button.
* @type {string}
*/
let deleteLinkTitle = '';
/**
* True if the provided url is valid.
* @type {string}
......@@ -91,6 +134,12 @@ function prepopulateFields(rid) {
prepopulatedLink.rid = rid;
$(IDS.TITLE_FIELD).value = prepopulatedLink.title = data.title;
$(IDS.URL_FIELD).value = prepopulatedLink.url = data.url;
$(IDS.URL_FIELD).classList.add(CLASSES.TEXT_MODIFIED);
// Set accessibility names.
$(IDS.DELETE).name = deleteLinkTitle + ' ' + data.title;
$(IDS.DONE).name = editLinkTitle + ' ' + data.title;
$(IDS.DONE).title = editLinkTitle;
}
......@@ -123,9 +172,8 @@ function showInvalidUrlUntilTextInput() {
/**
* Send a message to close the edit dialog. Called when the edit flow has been
* completed. If the fields were unchanged, does not update the link data.
* @param {!Event} event The click event.
*/
function finishEditLink(event) {
function finishEditLink() {
// Show error message for invalid urls.
if (!isValidURL($(IDS.URL_FIELD).value)) {
showInvalidUrlUntilTextInput();
......@@ -135,17 +183,17 @@ function finishEditLink(event) {
let newUrl = '';
let newTitle = '';
if ($(IDS.URL_FIELD).value != prepopulatedLink.url)
if ($(IDS.URL_FIELD).value != prepopulatedLink.url &&
$(IDS.URL_FIELD).value != 'https://')
newUrl = $(IDS.URL_FIELD).value;
if ($(IDS.TITLE_FIELD).value != prepopulatedLink.title)
newTitle = $(IDS.TITLE_FIELD).value;
// Do not update link if fields were unchanged.
if (!newUrl && !newTitle)
return;
chrome.embeddedSearch.newTabPage.updateCustomLink(
prepopulatedLink.rid, newUrl, newTitle);
// Update the link only if a field was changed.
if (!!newUrl || !!newTitle) {
chrome.embeddedSearch.newTabPage.updateCustomLink(
prepopulatedLink.rid, newUrl, newTitle);
}
closeDialog();
}
......@@ -166,13 +214,17 @@ function deleteLink(event) {
*/
function closeDialog() {
window.parent.postMessage({cmd: 'closeDialog'}, DOMAIN_ORIGIN);
$(IDS.FORM).reset();
$(IDS.URL_FIELD_CONTAINER).classList.remove('invalid');
$(IDS.DELETE).disabled = false;
$(IDS.DONE).disabled = false;
prepopulatedLink.rid = -1;
prepopulatedLink.title = '';
prepopulatedLink.url = '';
// Small delay to allow the dialog close before cleaning up.
window.setTimeout(function() {
$(IDS.FORM).reset();
$(IDS.URL_FIELD_CONTAINER).classList.remove('invalid');
$(IDS.URL_FIELD).classList.remove(CLASSES.TEXT_MODIFIED);
$(IDS.DELETE).disabled = false;
$(IDS.DONE).disabled = false;
prepopulatedLink.rid = -1;
prepopulatedLink.title = '';
prepopulatedLink.url = '';
}, 10);
}
......@@ -185,15 +237,38 @@ function handlePostMessage(event) {
let args = event.data;
if (cmd === 'linkData') {
if (args.tid) { // We are editing a link, prepopulate the link data.
$(IDS.DIALOG_TITLE).textContent = editLinkTitle;
prepopulateFields(args.tid);
} else { // We are adding a link, disable the delete button.
$(IDS.DIALOG_TITLE).textContent = addLinkTitle;
$(IDS.DELETE).disabled = true;
disableSubmitUntilTextInput();
// Set accessibility names.
$(IDS.DONE).name = $(IDS.DONE).title = addLinkTitle;
}
}
}
/**
* Disables the focus outline for |element| on mousedown.
* @param {Element} element The element to remove the focus outline from.
*/
function disableOutlineOnMouseClick(element) {
element.addEventListener('mousedown', (event) => {
element.style.outline = 'none';
let resetOutline = (event) => {
// Clear current focus to prevent the outline from reappearing when the
// user switches windows.
document.activeElement.blur();
element.style.outline = '';
element.removeEventListener('blur', resetOutline);
};
element.addEventListener('blur', resetOutline);
});
}
/**
* Does some initialization and shows the dialog window.
*/
......@@ -216,24 +291,46 @@ function init() {
}
// Populate text content.
$(IDS.DIALOG_TITLE).textContent = queryArgs['title'];
addLinkTitle = queryArgs['addTitle'];
editLinkTitle = queryArgs['editTitle'];
deleteLinkTitle = queryArgs['linkRemove'];
$(IDS.DIALOG_TITLE).textContent = addLinkTitle;
$(IDS.TITLE_FIELD_NAME).textContent = queryArgs['nameField'];
$(IDS.TITLE_FIELD_NAME).name = queryArgs['nameField'];
$(IDS.URL_FIELD_NAME).textContent = queryArgs['urlField'];
$(IDS.URL_FIELD_NAME).name = queryArgs['urlField'];
$(IDS.DELETE).textContent = queryArgs['linkRemove'];
$(IDS.CANCEL).textContent = queryArgs['linkCancel'];
$(IDS.DONE).textContent = queryArgs['linkDone'];
$(IDS.DELETE).textContent = $(IDS.DELETE).title = queryArgs['linkRemove'];
$(IDS.CANCEL).textContent = $(IDS.CANCEL).title = $(IDS.CANCEL).name =
queryArgs['linkCancel'];
$(IDS.DONE).textContent = $(IDS.DONE).title = queryArgs['linkDone'];
$(IDS.INVALID_URL).textContent = queryArgs['invalidUrl'];
// Set up event listeners.
$(IDS.URL_FIELD).addEventListener('input', (event) => {
if (!$(IDS.URL_FIELD).classList.contains(CLASSES.TEXT_MODIFIED))
$(IDS.URL_FIELD).classList.add(CLASSES.TEXT_MODIFIED);
});
$(IDS.DELETE).addEventListener('click', deleteLink);
$(IDS.CANCEL).addEventListener('click', closeDialog);
$(IDS.FORM).addEventListener('submit', (event) => {
// Prevent the form from submitting and modifying the URL.
event.preventDefault();
finishEditLink(event);
finishEditLink();
});
$(IDS.FORM).onkeyup = (event) => {
if (event.keyCode === KEYCODES.ENTER) {
event.preventDefault();
if ($(IDS.DONE).disabled)
closeDialog();
else
finishEditLink();
} else if (event.keyCode === KEYCODES.ESC) {
closeDialog();
}
};
disableOutlineOnMouseClick($(IDS.DELETE));
disableOutlineOnMouseClick($(IDS.CANCEL));
disableOutlineOnMouseClick($(IDS.DONE));
// Change input field name to blue on input field focus.
let changeColor = (fieldTitle) => {
......
......@@ -75,10 +75,6 @@ body.inited {
display: block;
}
body.hidden {
overflow: hidden;
}
/* Button defaults vary by platform. Reset CSS so that the NTP can use buttons
* as a kind of clickable div. */
button {
......@@ -676,14 +672,26 @@ html[dir=rtl] #attribution,
width: 100%;
}
#custom-links-edit-dialog {
background: transparent;
border: none;
height: 100%;
padding: 0;
position: absolute;
top: 0;
width: 100%;
}
#custom-links-edit-dialog::backdrop {
background-color: rgba(255, 255, 255, .75);
}
#custom-links-edit {
border: none;
display: none;
height: 100%;
position: absolute;
top: 0;
width: 100%;
z-index: 10000;
}
#custom-links-edit.show {
......
......@@ -110,6 +110,7 @@ var IDS = {
ATTRIBUTION: 'attribution',
ATTRIBUTION_TEXT: 'attribution-text',
CUSTOM_LINKS_EDIT_IFRAME: 'custom-links-edit',
CUSTOM_LINKS_EDIT_IFRAME_DIALOG: 'custom-links-edit-dialog',
FAKEBOX: 'fakebox',
FAKEBOX_INPUT: 'fakebox-input',
FAKEBOX_TEXT: 'fakebox-text',
......@@ -353,6 +354,8 @@ function renderTheme() {
.classList.toggle(
customBackgrounds.CLASSES.OPTION_DISABLED,
!info.customBackgroundConfigured);
$(customBackgrounds.IDS.RESTORE_DEFAULT).tabIndex =
(info.customBackgroundConfigured ? 0 : -1);
if (configData.isGooglePage) {
// Hide the settings menu or individual options if the related features are
......@@ -714,17 +717,6 @@ function setFakeboxVisibility(show) {
}
/**
* @param {boolean} show True if do show the edit custom link dialog and disable
* scrolling.
*/
function setEditCustomLinkDialogVisibility(show) {
$(IDS.CUSTOM_LINKS_EDIT_IFRAME)
.classList.toggle(CLASSES.SHOW_EDIT_DIALOG, show);
document.body.classList.toggle(CLASSES.HIDE_BODY_OVERFLOW, show);
}
/**
* @param {!Element} element The element to register the handler for.
* @param {number} keycode The keycode of the key to register.
......@@ -765,6 +757,8 @@ function handlePostMessage(event) {
.classList.toggle(
customBackgrounds.CLASSES.OPTION_DISABLED,
!args.showRestoreDefault);
$(customBackgrounds.IDS.CUSTOM_LINKS_RESTORE_DEFAULT).tabIndex =
(args.showRestoreDefault ? 0 : -1);
}
} else if (cmd === 'tileBlacklisted') {
if (configData.isCustomLinksEnabled) {
......@@ -787,9 +781,12 @@ function handlePostMessage(event) {
} else if (cmd === 'startEditLink') {
$(IDS.CUSTOM_LINKS_EDIT_IFRAME)
.contentWindow.postMessage({cmd: 'linkData', tid: args.tid}, '*');
setEditCustomLinkDialogVisibility(true);
// Small delay to allow the dialog to finish setting up before displaying.
window.setTimeout(function() {
$(IDS.CUSTOM_LINKS_EDIT_IFRAME_DIALOG).showModal();
}, 10);
} else if (cmd === 'closeDialog') {
setEditCustomLinkDialogVisibility(false);
$(IDS.CUSTOM_LINKS_EDIT_IFRAME_DIALOG).close();
}
}
......@@ -880,6 +877,26 @@ function addRippleAnimations() {
}
}
/**
* Disables the focus outline for |element| on mousedown.
* @param {Element} element The element to remove the focus outline from.
*/
function disableOutlineOnMouseClick(element) {
element.addEventListener('mousedown', (event) => {
element.style.outline = 'none';
let resetOutline = (event) => {
// Clear current focus to prevent the outline from reappearing when the
// user switches windows.
document.activeElement.blur();
element.style.outline = '';
element.removeEventListener('blur', resetOutline);
};
element.addEventListener('blur', resetOutline);
});
}
/**
* Prepares the New Tab Page by adding listeners, the most visited pages
* section, and Google-specific elements for a Google-provided page.
......@@ -997,6 +1014,7 @@ function init() {
inputbox.ondragleave = function() {
setFakeboxDragFocus(false);
};
disableOutlineOnMouseClick($(IDS.FAKEBOX_MICROPHONE));
// Update the fakebox style to match the current key capturing state.
setFakeboxFocus(searchboxApiHandle.isKeyCaptureEnabled);
......@@ -1109,7 +1127,10 @@ function init() {
clArgs.push('rtl=1');
clArgs.push(
'title=' +
'addTitle=' +
encodeURIComponent(configData.translatedStrings.addLinkTitle));
clArgs.push(
'editTitle=' +
encodeURIComponent(configData.translatedStrings.editLinkTitle));
clArgs.push(
'nameField=' +
......@@ -1136,7 +1157,10 @@ function init() {
clIframe.name = IDS.CUSTOM_LINKS_EDIT_IFRAME;
clIframe.title = configData.translatedStrings.editLinkTitle;
clIframe.src = 'chrome-search://most-visited/edit.html?' + clArgs.join('&');
document.body.appendChild(clIframe);
let clIframeDialog = document.createElement('dialog');
clIframeDialog.id = IDS.CUSTOM_LINKS_EDIT_IFRAME_DIALOG;
clIframeDialog.appendChild(clIframe);
document.body.appendChild(clIframeDialog);
}
window.addEventListener('message', handlePostMessage);
......
......@@ -375,14 +375,12 @@ html[dir=rtl] .mv-favicon {
display: none;
}
.md-tile {
.md-tile-container {
border-radius: 4px;
box-sizing: border-box;
cursor: pointer;
height: var(--md-tile-height);
margin-bottom: var(--md-tile-margin);
opacity: 1;
padding: var(--md-tile-padding-vertical) var(--md-tile-padding-horizontal);
position: relative;
transition-property:
background, background-color, border-color, box-shadow, opacity,
......@@ -390,29 +388,34 @@ html[dir=rtl] .mv-favicon {
width: var(--md-tile-width);
}
.md-tile {
cursor: pointer;
padding: var(--md-tile-padding-vertical) var(--md-tile-padding-horizontal);
}
.md-empty-tile {
display: none;
}
.md-tile:hover {
.md-tile-container:hover {
background-color: rgba(33, 32, 36, 0.06);
}
body.dark-theme .md-tile:hover {
body.dark-theme .md-tile-container:hover {
background-color: rgba(255, 255, 255, 0.1);
}
.md-tile:hover > .md-menu {
.md-tile-container:hover .md-menu {
opacity: 1;
transition-delay: 500ms;
}
body.dark-theme .md-tile:active .md-menu::after {
background-color: rgba(33, 32, 36, 0.71);
transition-delay: 500ms;
body.dark-theme .md-tile-container:active + .md-menu::after {
background-color: rgb(189, 193, 198);
transition-delay: 0ms;
}
.md-tile.blacklisted {
.md-tile-container.blacklisted {
margin: 0;
padding: 0;
transform: scale(0, 0);
......@@ -426,20 +429,10 @@ body.dark-theme .md-tile:active .md-menu::after {
display: flex;
flex-flow: column nowrap;
height: 100%;
position: relative;
width: 100%;
z-index: -1;
}
.md-link {
height: 100%;
left: 0;
position: absolute;
right: 0;
top: 0;
width: 100%;
}
.md-icon {
margin-bottom: var(--md-icon-margin-bottom);
}
......@@ -508,7 +501,6 @@ body.dark-theme .md-title {
body.using-theme .md-title-container {
background-color: white;
border-radius: 12px;
height: 24px;
padding: 4px;
}
......
......@@ -30,15 +30,15 @@ const CLASSES = {
MD_FALLBACK_BACKGROUND: 'md-fallback-background',
MD_FALLBACK_LETTER: 'md-fallback-letter',
MD_FAVICON: 'md-favicon',
MD_LINK: 'md-link',
MD_ICON: 'md-icon',
MD_ICON_BACKGROUND: 'md-icon-background',
MD_ADD_ICON: 'md-add-icon',
MD_ADD_BACKGROUND: 'md-add-background',
MD_MENU: 'md-menu',
MD_EDIT_MENU: 'md-edit-menu',
MD_TILE: 'md-tile',
MD_TILE: 'md-tile-container',
MD_TILE_INNER: 'md-tile-inner',
MD_TILE_LINK: 'md-tile',
MD_TITLE: 'md-title',
MD_TITLE_CONTAINER: 'md-title-container',
};
......@@ -453,6 +453,25 @@ var isSchemeAllowed = function(url) {
};
/**
* Disables the focus outline for |element| on mousedown.
* @param {Element} element The element to remove the focus outline from.
*/
function disableOutlineOnMouseClick(element) {
element.addEventListener('mousedown', (event) => {
element.style.outline = 'none';
let resetOutline = (event) => {
// Clear current focus to prevent the outline from reappearing when the
// user switches windows.
document.activeElement.blur();
element.style.outline = '';
element.removeEventListener('blur', resetOutline);
};
element.addEventListener('blur', resetOutline);
});
}
/**
* Renders a MostVisited tile to the DOM.
* @param {object} data Object containing rid, url, title, favicon, thumbnail,
......@@ -628,12 +647,14 @@ var renderMostVisitedTile = function(data) {
* @return {Element}
*/
function renderMaterialDesignTile(data) {
let mdTile = document.createElement('a');
let mdTile = document.createElement('div');
mdTile.role = 'none';
if (data == null) {
mdTile.className = CLASSES.MD_EMPTY_TILE;
return mdTile;
}
mdTile.className = CLASSES.MD_TILE;
if (data.isCustomLink)
tilesAreCustomLinks = true;
......@@ -643,16 +664,18 @@ function renderMaterialDesignTile(data) {
// This is set in the load/error event for the favicon image.
let tileType = TileVisualType.NONE;
mdTile.className = CLASSES.MD_TILE;
mdTile.setAttribute('data-tid', data.tid);
mdTile.setAttribute('data-pos', position);
let mdTileLink = document.createElement('a');
mdTileLink.className = CLASSES.MD_TILE_LINK;
mdTileLink.tabIndex = 0;
mdTileLink.setAttribute('data-tid', data.tid);
mdTileLink.setAttribute('data-pos', position);
if (isSchemeAllowed(data.url)) {
mdTile.href = data.url;
mdTileLink.href = data.url;
}
mdTile.setAttribute('aria-label', data.title);
mdTile.title = data.title;
mdTileLink.setAttribute('aria-label', data.title);
mdTileLink.title = data.title;
mdTile.addEventListener('click', function(ev) {
mdTileLink.addEventListener('click', function(ev) {
if (data.isAddButton) {
editCustomLink();
} else {
......@@ -661,7 +684,7 @@ function renderMaterialDesignTile(data) {
data.dataGenerationTime);
}
});
mdTile.addEventListener('keydown', function(event) {
mdTileLink.addEventListener('keydown', function(event) {
if ((event.keyCode == 46 /* DELETE */ ||
event.keyCode == 8 /* BACKSPACE */) &&
!data.isAddButton) {
......@@ -673,14 +696,18 @@ function renderMaterialDesignTile(data) {
event.preventDefault();
this.click();
} else if (event.keyCode == 37 /* LEFT */) {
const tiles = document.querySelectorAll('#mv-tiles .' + CLASSES.MD_TILE);
tiles[Math.max(this.getAttribute('data-pos') - 1, 0)].focus();
const tiles =
document.querySelectorAll('#mv-tiles .' + CLASSES.MD_TILE_LINK);
tiles[Math.max(Number(this.getAttribute('data-pos')) - 1, 0)].focus();
} else if (event.keyCode == 39 /* RIGHT */) {
const tiles = document.querySelectorAll('#mv-tiles .' + CLASSES.MD_TILE);
tiles[Math.min(this.getAttribute('data-pos') + 1, tiles.length - 1)]
const tiles =
document.querySelectorAll('#mv-tiles .' + CLASSES.MD_TILE_LINK);
tiles[Math.min(
Number(this.getAttribute('data-pos')) + 1, tiles.length - 1)]
.focus();
}
});
disableOutlineOnMouseClick(mdTileLink);
let mdTileInner = document.createElement('div');
mdTileInner.className = CLASSES.MD_TILE_INNER;
......@@ -754,7 +781,8 @@ function renderMaterialDesignTile(data) {
mdTitle.style.direction = data.direction || 'ltr';
mdTitleContainer.appendChild(mdTitle);
mdTileInner.appendChild(mdTitleContainer);
mdTile.appendChild(mdTileInner);
mdTileLink.appendChild(mdTileInner);
mdTile.appendChild(mdTileLink);
if (!data.isAddButton) {
let mdMenu = document.createElement('button');
......@@ -762,6 +790,7 @@ function renderMaterialDesignTile(data) {
if (isCustomLinksEnabled) {
mdMenu.classList.add(CLASSES.MD_EDIT_MENU);
mdMenu.title = queryArgs['editLinkTooltip'] || '';
mdMenu.name = (queryArgs['editLinkTooltip'] || '') + ' ' + data.title;
mdMenu.addEventListener('click', function(ev) {
editCustomLink(data.tid);
ev.preventDefault();
......@@ -769,18 +798,20 @@ function renderMaterialDesignTile(data) {
});
} else {
mdMenu.title = queryArgs['removeTooltip'] || '';
mdMenu.name = (queryArgs['removeTooltip'] || '') + ' ' + data.title;
mdMenu.addEventListener('click', function(ev) {
removeAllOldTiles();
blacklistTile(mdTile);
blacklistTile(mdTileLink);
ev.preventDefault();
ev.stopPropagation();
});
}
// Don't allow the event to bubble out to the containing tile, as that would
// trigger navigation to the tile URL.
mdMenu.addEventListener('keydown', function(event) {
mdMenu.addEventListener('keydown', function(ev) {
event.stopPropagation();
});
disableOutlineOnMouseClick(mdMenu);
mdTile.appendChild(mdMenu);
}
......
......@@ -193,14 +193,14 @@ std::unique_ptr<base::DictionaryValue> GetTranslatedStrings(bool is_google) {
IDS_NTP_CUSTOM_BG_PHOTO_SELECTED);
// Custom Links
AddString(translated_strings.get(), "addLink",
AddString(translated_strings.get(), "addLinkTitle",
IDS_NTP_CUSTOM_LINKS_ADD_SHORTCUT_TITLE);
AddString(translated_strings.get(), "addLinkTooltip",
IDS_NTP_CUSTOM_LINKS_ADD_SHORTCUT_TOOLTIP);
AddString(translated_strings.get(), "editLinkTooltip",
IDS_NTP_CUSTOM_LINKS_EDIT_SHORTCUT_TOOLTIP);
AddString(translated_strings.get(), "editLinkTitle",
IDS_NTP_CUSTOM_LINKS_EDIT_SHORTCUT);
AddString(translated_strings.get(), "editLinkTooltip",
IDS_NTP_CUSTOM_LINKS_EDIT_SHORTCUT_TOOLTIP);
AddString(translated_strings.get(), "nameField", IDS_NTP_CUSTOM_LINKS_NAME);
AddString(translated_strings.get(), "urlField", IDS_NTP_CUSTOM_LINKS_URL);
AddString(translated_strings.get(), "linkRemove",
......
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