Commit 551d7d73 authored by kristipark's avatar kristipark Committed by Commit Bot

[NTP] Support the error notification customization and move its handler to local_ntp.js

Allow the error notification content to be customized by the caller,
and moved the error notification handler from custom_backgrounds.js to
local_ntp.js (the notification will be reused for custom link errors).

Also adjusted the notification styling to better match spec.

Screenshots:
https://screenshot.googleplex.com/BN02EbSSKLM.png
https://screenshot.googleplex.com/KpxwyZJ4N3T.png

Bug: 874188
Change-Id: Ibf4ebed906fd36916a4f0ddb2170a2dbe8870ab3
Reviewed-on: https://chromium-review.googlesource.com/1182787
Commit-Queue: Kristi Park <kristipark@chromium.org>
Reviewed-by: default avatarFernando Serboncini <fserb@chromium.org>
Cr-Commit-Position: refs/heads/master@{#585991}
parent a6b0ab61
...@@ -169,6 +169,13 @@ customBackgrounds.selectedTile = null; ...@@ -169,6 +169,13 @@ customBackgrounds.selectedTile = null;
*/ */
customBackgrounds.dialogCollectionsSource = customBackgrounds.SOURCES.NONE; customBackgrounds.dialogCollectionsSource = customBackgrounds.SOURCES.NONE;
/*
* Called when the error notification should be shown.
* @type {?Function}
* @private
*/
customBackgrounds.showErrorNotification;
/** /**
* Alias for document.getElementById. * Alias for document.getElementById.
* @param {string} id The ID of the element to find. * @param {string} id The ID of the element to find.
...@@ -785,8 +792,10 @@ customBackgrounds.networkStateChanged = function(online) { ...@@ -785,8 +792,10 @@ customBackgrounds.networkStateChanged = function(online) {
/** /**
* Initialize the settings menu, custom backgrounds dialogs, and custom links * Initialize the settings menu, custom backgrounds dialogs, and custom links
* menu items. Set the text and event handlers for the various elements. * menu items. Set the text and event handlers for the various elements.
* @param {?Function} showErrorNotification Called when the error notification
* should be displayed
*/ */
customBackgrounds.init = function() { customBackgrounds.init = function(showErrorNotification) {
ntpApiHandle = window.chrome.embeddedSearch.newTabPage; ntpApiHandle = window.chrome.embeddedSearch.newTabPage;
let editDialog = $(customBackgrounds.IDS.EDIT_BG_DIALOG); let editDialog = $(customBackgrounds.IDS.EDIT_BG_DIALOG);
let menu = $(customBackgrounds.IDS.MENU); let menu = $(customBackgrounds.IDS.MENU);
...@@ -873,7 +882,7 @@ customBackgrounds.init = function() { ...@@ -873,7 +882,7 @@ customBackgrounds.init = function() {
if (configData.isCustomLinksEnabled) if (configData.isCustomLinksEnabled)
customBackgrounds.initCustomLinksItems(); customBackgrounds.initCustomLinksItems();
if (configData.isCustomBackgroundsEnabled) if (configData.isCustomBackgroundsEnabled)
customBackgrounds.initCustomBackgrounds(); customBackgrounds.initCustomBackgrounds(showErrorNotification);
}; };
/** /**
...@@ -921,8 +930,12 @@ customBackgrounds.initCustomLinksItems = function() { ...@@ -921,8 +930,12 @@ customBackgrounds.initCustomLinksItems = function() {
/** /**
* Initialize the settings menu and custom backgrounds dialogs. Set the * Initialize the settings menu and custom backgrounds dialogs. Set the
* text and event handlers for the various elements. * text and event handlers for the various elements.
* @param {?Function} showErrorNotification Called when the error notification
* should be displayed
*/ */
customBackgrounds.initCustomBackgrounds = function() { customBackgrounds.initCustomBackgrounds = function(showErrorNotification) {
customBackgrounds.showErrorNotification = showErrorNotification;
var editDialog = $(customBackgrounds.IDS.EDIT_BG_DIALOG); var editDialog = $(customBackgrounds.IDS.EDIT_BG_DIALOG);
var menu = $(customBackgrounds.IDS.MENU); var menu = $(customBackgrounds.IDS.MENU);
...@@ -1158,73 +1171,33 @@ customBackgrounds.initCustomBackgrounds = function() { ...@@ -1158,73 +1171,33 @@ customBackgrounds.initCustomBackgrounds = function() {
}; };
}; };
customBackgrounds.hideMessageBox = function() {
let message = $(customBackgrounds.IDS.MSG_BOX_CONTAINER);
if (!message.classList.contains(customBackgrounds.CLASSES.FLOAT_UP)) {
return;
}
window.clearTimeout(customBackgrounds.delayedHideNotification);
message.classList.remove(customBackgrounds.CLASSES.FLOAT_UP);
let afterHide = (event) => {
if (event.propertyName == 'bottom') {
$(IDS.MSG_BOX).classList.add(customBackgrounds.CLASSES.HIDE_MSG_BOX);
$(IDS.MSG_BOX).classList.remove(customBackgrounds.CLASSES.HAS_LINK);
notification.removeEventListener('transitionend', afterHide);
}
};
};
customBackgrounds.showMessageBox = function() {
$(customBackgrounds.IDS.MSG_BOX_CONTAINER)
.classList.remove(customBackgrounds.CLASSES.HIDE_MSG_BOX);
// Timeout is required for the "float up" transition to work. Modifying the
// "display" property prevents transitions from activating.
window.setTimeout(() => {
$(customBackgrounds.IDS.MSG_BOX_CONTAINER)
.classList.add(customBackgrounds.CLASSES.FLOAT_UP);
}, 20);
// Automatically hide the notification after a period of time.
customBackgrounds.delayedHideNotification = window.setTimeout(() => {
customBackgrounds.hideMessageBox();
}, customBackgrounds.NOTIFICATION_TIMEOUT);
};
customBackgrounds.handleError = function(errors) { customBackgrounds.handleError = function(errors) {
var msgBox = $(customBackgrounds.IDS.MSG_BOX_MSG);
var msgBoxLink = $(customBackgrounds.IDS.MSG_BOX_LINK);
var unavailableString = configData.translatedStrings.backgroundsUnavailable; var unavailableString = configData.translatedStrings.backgroundsUnavailable;
if (errors != 'undefined') { if (errors != 'undefined') {
// Network errors. // Network errors.
if (errors.net_error) { if (errors.net_error) {
if (errors.net_error_no != 0) { if (errors.net_error_no != 0) {
msgBox.textContent = configData.translatedStrings.connectionError; let onClick = () => {
msgBoxLink.textContent = configData.translatedStrings.moreInfo;
msgBoxLink.classList.add(customBackgrounds.CLASSES.HAS_LINK);
msgBoxLink.onclick = function() {
window.open( window.open(
'https://chrome://network-error/' + errors.net_error_no, 'https://chrome://network-error/' + errors.net_error_no,
'_blank'); '_blank');
}; };
customBackgrounds.showErrorNotification(
configData.translatedStrings.connectionError,
configData.translatedStrings.moreInfo, onClick);
} else { } else {
msgBox.textContent = customBackgrounds.showErrorNotification(
configData.translatedStrings.connectionErrorNoPeriod; configData.translatedStrings.connectionErrorNoPeriod);
} }
customBackgrounds.showMessageBox(); } else if (errors.auth_error) { // Auth errors (Google Photos only).
// Auth errors (Google Photos only).
} else if (errors.auth_error) {
window.open('https://photos.google.com/login', '_blank'); window.open('https://photos.google.com/login', '_blank');
// Service errors. } else if (errors.service_error) { // Service errors.
} else if (errors.service_error) { customBackgrounds.showErrorNotification(unavailableString);
msgBox.textContent = unavailableString;
customBackgrounds.showMessageBox();
} }
return; return;
} }
// Generic error when we can't tell what went wrong. // Generic error when we can't tell what went wrong.
msgBox.textContent = unavailableString; customBackgrounds.showErrorNotification(unavailableString);
customBackgrounds.showMessageBox();
}; };
...@@ -553,7 +553,7 @@ html[dir=rtl] #mv-notice-x { ...@@ -553,7 +553,7 @@ html[dir=rtl] #mv-notice-x {
bottom: 0; bottom: 0;
} }
.md-icons #mv-notice-container.mv-notice-hide { .md-icons #mv-notice-container.notice-hide {
display: none; display: none;
} }
...@@ -570,7 +570,7 @@ html[dir=rtl] #mv-notice-x { ...@@ -570,7 +570,7 @@ html[dir=rtl] #mv-notice-x {
border: 1px solid rgb(218, 220, 224); border: 1px solid rgb(218, 220, 224);
/* Necessary for a "pill" shape. Using 50% creates an oval. */ /* Necessary for a "pill" shape. Using 50% creates an oval. */
border-radius: 500px; border-radius: 500px;
font-family: 'Roboto'; font-family: 'Roboto', arial, sans-serif;
font-weight: normal; font-weight: normal;
height: 32px; height: 32px;
margin: 0 auto; margin: 0 auto;
...@@ -605,7 +605,7 @@ html[dir=rtl] #mv-notice-x { ...@@ -605,7 +605,7 @@ html[dir=rtl] #mv-notice-x {
.md-icons #mv-notice-links span { .md-icons #mv-notice-links span {
/* Necessary for a "pill" shape. Using 50% creates an oval. */ /* Necessary for a "pill" shape. Using 50% creates an oval. */
border-radius: 500px; border-radius: 500px;
color: rgb(26,115,232); color: rgb(26, 115, 232);
margin-inline-start: 0; margin-inline-start: 0;
padding: 0 16px; padding: 0 16px;
position: relative; position: relative;
...@@ -645,7 +645,7 @@ html[dir=rtl] #mv-notice-x { ...@@ -645,7 +645,7 @@ html[dir=rtl] #mv-notice-x {
transition-property: opacity; transition-property: opacity;
} }
#mv-notice.mv-notice-hide { #mv-notice.notice-hide {
display: none; display: none;
} }
...@@ -807,56 +807,94 @@ input:checked + .toggle::before { ...@@ -807,56 +807,94 @@ input:checked + .toggle::before {
transform: translateX(26px); transform: translateX(26px);
} }
#message-box-container { #error-notice-container {
bottom: -50px; bottom: -50px;
margin-bottom: 16px; margin-bottom: 16px;
position: fixed; position: fixed;
transition: bottom 400ms; transition: bottom 400ms;
vertical-align: middle; user-select: none;
visibility: hidden;
width: 100%; width: 100%;
} }
#message-box { #error-notice-container.float-up {
bottom: 0;
}
#error-notice {
background-color: white; background-color: white;
border: 1px solid rgb(218, 220, 224); border: 1px solid rgb(218, 220, 224);
border-radius: 16px; /* Necessary for a "pill" shape. Using 50% creates an oval. */
color: rgb(255, 0, 0); border-radius: 500px;
color: rgb(217, 48, 37);
font-family: 'Roboto', arial, sans-serif; font-family: 'Roboto', arial, sans-serif;
font-size: 12px; font-size: 12px;
font-weight: normal;
height: 32px; height: 32px;
left: 50%;
margin: 0 auto; margin: 0 auto;
padding: 0 16px 0 4px; opacity: 1;
text-align: center; padding: 0;
visibility: visible;
width: fit-content; width: fit-content;
} }
#message-box-container.float-up { #error-notice.notice-hide {
bottom: 0; display: none;
} }
#message-box-container.message-box-hide { #error-notice-icon-container {
display: none; position: relative;
} }
#message-box-icon { #error-notice-icon {
background: url(../../../../ui/webui/resources/images/error.svg) no-repeat center; background: url(../../../../ui/webui/resources/images/error.svg) no-repeat center;
height: 18px; background-size: 18px 18px;
margin-right: 4px; height: 32px;
margin-left: 8px;
position: absolute;
width: 18px; width: 18px;
} }
#message-box-link.has-link { #error-notice-msg {
color: rgb(66, 133, 244); cursor: default;
margin-left: 6px; padding: 0 16px 0 36px;
}
#error-notice.has-link #error-notice-msg {
padding-right: 0;
} }
#message-box-message, #error-notice span:not(#error-notice-icon-container) {
#message-box-link,
#message-box-icon {
vertical-align: middle;
display: inline-block; display: inline-block;
height: auto;
line-height: 32px; line-height: 32px;
vertical-align: unset;
}
#error-notice-link {
/* Necessary for a "pill" shape. Using 50% creates an oval. */
border-radius: 500px;
color: rgb(26, 115, 232);
cursor: pointer;
display: none;
outline: none;
padding: 0 16px;
}
#error-notice:not(.has-link) #error-notice-link {
display: none;
}
#error-notice.has-link #error-notice-link {
display: inline;
}
#error-notice-link:hover,
#error-notice-link:focus {
text-decoration: underline;
}
#error-notice-link:hover,
#error-notice-link:active {
background-color: rgba(26,115,232, 0.1);
text-decoration: none;
transition: background-color 200ms;
} }
...@@ -64,7 +64,7 @@ ...@@ -64,7 +64,7 @@
<div id="mv-tiles"></div> <div id="mv-tiles"></div>
<!-- Notification shown when a tile is blacklisted. --> <!-- Notification shown when a tile is blacklisted. -->
<div id="mv-notice-container"> <div id="mv-notice-container">
<div id="mv-notice" class="mv-notice-hide" role="alert"> <div id="mv-notice" class="notice-hide" role="alert">
<span id="mv-msg"></span> <span id="mv-msg"></span>
<!-- Links in the notification. --> <!-- Links in the notification. -->
<span id="mv-notice-links"> <span id="mv-notice-links">
...@@ -78,17 +78,20 @@ ...@@ -78,17 +78,20 @@
</div> </div>
<div id="attribution"><div id="attribution-text"></div></div> <div id="attribution"><div id="attribution-text"></div></div>
<div id="error-notice-container">
<div id="error-notice" class="notice-hide" role="alert">
<span id="error-notice-icon-container">
<div id="error-notice-icon"></div>
</span>
<span id="error-notice-msg"></span>
<span id="error-notice-link" class="ripple" tabindex="0" role="button"></span>
</div>
</div>
<div id="edit-bg" tabindex="0" hidden> <div id="edit-bg" tabindex="0" hidden>
<div id="edit-bg-gear" tabindex="-1" role="button"></div> <div id="edit-bg-gear" tabindex="-1" role="button"></div>
</div> </div>
<div id="message-box-container" class="message-box-hide">
<div id="message-box">
<div id="message-box-icon"></div>
<div id="message-box-message"></div>
<div id="message-box-link" class="ripple"></div>
</div>
</div>
<div id="custom-bg-attr"></div> <div id="custom-bg-attr"></div>
</div> </div>
......
...@@ -105,8 +105,10 @@ var CLASSES = { ...@@ -105,8 +105,10 @@ var CLASSES = {
RIPPLE_EFFECT: 'ripple-effect', RIPPLE_EFFECT: 'ripple-effect',
// Applies drag focus style to the fakebox // Applies drag focus style to the fakebox
FAKEBOX_DRAG_FOCUS: 'fakebox-drag-focused', FAKEBOX_DRAG_FOCUS: 'fakebox-drag-focused',
// Applies a different style to the error notification if a link is present.
HAS_LINK: 'has-link',
HIDE_FAKEBOX: 'hide-fakebox', HIDE_FAKEBOX: 'hide-fakebox',
HIDE_NOTIFICATION: 'mv-notice-hide', HIDE_NOTIFICATION: 'notice-hide',
INITED: 'inited', // Reveals the <body> once init() is done. INITED: 'inited', // Reveals the <body> once init() is done.
LEFT_ALIGN_ATTRIBUTION: 'left-align-attribution', LEFT_ALIGN_ATTRIBUTION: 'left-align-attribution',
MATERIAL_DESIGN: 'md', // Applies Material Design styles to the page MATERIAL_DESIGN: 'md', // Applies Material Design styles to the page
...@@ -130,6 +132,10 @@ var IDS = { ...@@ -130,6 +132,10 @@ var IDS = {
ATTRIBUTION_TEXT: 'attribution-text', ATTRIBUTION_TEXT: 'attribution-text',
CUSTOM_LINKS_EDIT_IFRAME: 'custom-links-edit', CUSTOM_LINKS_EDIT_IFRAME: 'custom-links-edit',
CUSTOM_LINKS_EDIT_IFRAME_DIALOG: 'custom-links-edit-dialog', CUSTOM_LINKS_EDIT_IFRAME_DIALOG: 'custom-links-edit-dialog',
ERROR_NOTIFICATION: 'error-notice',
ERROR_NOTIFICATION_CONTAINER: 'error-notice-container',
ERROR_NOTIFICATION_LINK: 'error-notice-link',
ERROR_NOTIFICATION_MSG: 'error-notice-msg',
FAKEBOX: 'fakebox', FAKEBOX: 'fakebox',
FAKEBOX_INPUT: 'fakebox-input', FAKEBOX_INPUT: 'fakebox-input',
FAKEBOX_TEXT: 'fakebox-text', FAKEBOX_TEXT: 'fakebox-text',
...@@ -264,11 +270,11 @@ var lastBlacklistedTile = null; ...@@ -264,11 +270,11 @@ var lastBlacklistedTile = null;
/** /**
* The timeout id for automatically hiding the Most Visited notification. * The timeout function for automatically hiding the pop-up notification. Only
* Invalid ids will silently do nothing. * set if a notification is visible.
* @type {number} * @type {?Object}
*/ */
let delayedHideNotification = -1; let delayedHideNotification;
/** /**
...@@ -278,6 +284,26 @@ let delayedHideNotification = -1; ...@@ -278,6 +284,26 @@ let delayedHideNotification = -1;
var ntpApiHandle; var ntpApiHandle;
/**
* Returns a timeout that can be executed early.
* @param {!Function} timeout The timeout function.
* @param {number} delay The timeout delay.
* @return {Object}
*/
function createExecutableTimeout(timeout, delay) {
let timeoutId = window.setTimeout(timeout, delay);
return {
clear: () => {
window.clearTimeout(timeoutId);
},
trigger: () => {
window.clearTimeout(timeoutId);
return timeout();
}
};
}
/** /**
* Returns theme background info, first checking for history.state.notheme. If * Returns theme background info, first checking for history.state.notheme. If
* the page has notheme set, returns a fallback light-colored theme. * the page has notheme set, returns a fallback light-colored theme.
...@@ -598,25 +624,15 @@ function onDeleteCustomLinkDone(success) { ...@@ -598,25 +624,15 @@ function onDeleteCustomLinkDone(success) {
/** /**
* Shows the pop-up notification and triggers a delay to hide it. The message * Shows the Most Visited pop-up notification and triggers a delay to hide it.
* will be set to |msg|. * The message will be set to |msg|.
* @param {string} msg The notification message. * @param {string} msg The notification message.
*/ */
function showNotification(msg) { function showNotification(msg) {
$(IDS.NOTIFICATION_MESSAGE).textContent = msg; $(IDS.NOTIFICATION_MESSAGE).textContent = msg;
if (configData.isMDIconsEnabled) { if (configData.isMDIconsEnabled) {
$(IDS.NOTIFICATION).classList.remove(CLASSES.HIDE_NOTIFICATION); floatUpNotification($(IDS.NOTIFICATION), $(IDS.NOTIFICATION_CONTAINER));
// Timeout is required for the "float up" transition to work. Modifying the
// "display" property prevents transitions from activating.
window.setTimeout(() => {
$(IDS.NOTIFICATION_CONTAINER).classList.add(CLASSES.FLOAT_UP);
}, 20);
// Automatically hide the notification after a period of time.
delayedHideNotification = window.setTimeout(() => {
hideNotification();
}, NOTIFICATION_TIMEOUT);
} else { } else {
var notification = $(IDS.NOTIFICATION); var notification = $(IDS.NOTIFICATION);
notification.classList.remove(CLASSES.HIDE_NOTIFICATION); notification.classList.remove(CLASSES.HIDE_NOTIFICATION);
...@@ -628,24 +644,11 @@ function showNotification(msg) { ...@@ -628,24 +644,11 @@ function showNotification(msg) {
/** /**
* Hides the pop-up notification. * Hides the Most Visited pop-up notification.
*/ */
function hideNotification() { function hideNotification() {
if (configData.isMDIconsEnabled) { if (configData.isMDIconsEnabled) {
let notification = $(IDS.NOTIFICATION_CONTAINER); floatDownNotification($(IDS.NOTIFICATION), $(IDS.NOTIFICATION_CONTAINER));
if (!notification.classList.contains(CLASSES.FLOAT_UP)) {
return;
}
window.clearTimeout(delayedHideNotification);
notification.classList.remove(CLASSES.FLOAT_UP);
let afterHide = (event) => {
if (event.propertyName == 'bottom') {
$(IDS.NOTIFICATION).classList.add(CLASSES.HIDE_NOTIFICATION);
notification.removeEventListener('transitionend', afterHide);
}
};
notification.addEventListener('transitionend', afterHide);
} else { } else {
var notification = $(IDS.NOTIFICATION); var notification = $(IDS.NOTIFICATION);
notification.classList.add(CLASSES.HIDE_NOTIFICATION); notification.classList.add(CLASSES.HIDE_NOTIFICATION);
...@@ -654,6 +657,87 @@ function hideNotification() { ...@@ -654,6 +657,87 @@ function hideNotification() {
} }
/**
* Shows the error pop-up notification and triggers a delay to hide it. The
* message will be set to |msg|. If |linkName| and |linkOnClick| are present,
* shows an error link with text set to |linkName| and onclick handled by
* |linkOnClick|.
* @param {string} msg The notification message.
* @param {?string} linkName The error link text.
* @param {?Function} linkOnClick The error link onclick handler.
*/
function showErrorNotification(msg, linkName, linkOnClick) {
let notification = $(IDS.ERROR_NOTIFICATION);
$(IDS.ERROR_NOTIFICATION_MSG).textContent = msg;
if (linkName && linkOnClick) {
let notificationLink = $(IDS.ERROR_NOTIFICATION_LINK);
notificationLink.textContent = linkName;
notificationLink.onclick = linkOnClick;
notification.classList.add(CLASSES.HAS_LINK);
} else {
notification.classList.remove(CLASSES.HAS_LINK);
}
floatUpNotification(notification, $(IDS.ERROR_NOTIFICATION_CONTAINER));
}
/**
* Animates the specified notification to float up. Automatically hides any
* pre-existing notification and sets a delayed timer to hide the new
* notification.
* @param {!Element} notification The notification element.
* @param {!Element} notificationContainer The notification container element.
*/
function floatUpNotification(notification, notificationContainer) {
// Hide any pre-existing notification.
if (delayedHideNotification) {
delayedHideNotification.trigger();
delayedHideNotification = null;
}
notification.classList.remove(CLASSES.HIDE_NOTIFICATION);
// Timeout is required for the "float up" transition to work. Modifying the
// "display" property prevents transitions from activating.
window.setTimeout(() => {
notificationContainer.classList.add(CLASSES.FLOAT_UP);
}, 20);
// Automatically hide the notification after a period of time.
delayedHideNotification = createExecutableTimeout(() => {
floatDownNotification(notification, notificationContainer);
}, NOTIFICATION_TIMEOUT);
}
/**
* Animates the pop-up notification to float down, and clears the timeout to
* hide the notification.
* @param {!Element} notification The notification element.
* @param {!Element} notificationContainer The notification container element.
*/
function floatDownNotification(notification, notificationContainer) {
if (!notificationContainer.classList.contains(CLASSES.FLOAT_UP))
return;
// Clear the timeout to hide the notification.
if (delayedHideNotification) {
delayedHideNotification.clear();
delayedHideNotification = null;
}
// Reset notification visibility once the animation is complete.
notificationContainer.classList.remove(CLASSES.FLOAT_UP);
let afterHide = (event) => {
if (event.propertyName == 'bottom') {
notification.classList.add(CLASSES.HIDE_NOTIFICATION);
notification.classList.remove(CLASSES.HAS_LINK);
notificationContainer.removeEventListener('transitionend', afterHide);
}
};
notification.addEventListener('transitionend', afterHide);
}
/** /**
* Handles a click on the notification undo link by hiding the notification and * Handles a click on the notification undo link by hiding the notification and
* informing Chrome. * informing Chrome.
...@@ -990,7 +1074,7 @@ function init() { ...@@ -990,7 +1074,7 @@ function init() {
if (configData.isCustomBackgroundsEnabled || if (configData.isCustomBackgroundsEnabled ||
configData.isCustomLinksEnabled) { configData.isCustomLinksEnabled) {
customBackgrounds.init(); customBackgrounds.init(showErrorNotification);
} }
......
...@@ -54,7 +54,7 @@ ...@@ -54,7 +54,7 @@
<div id="mv-tiles"></div> <div id="mv-tiles"></div>
<!-- Notification shown when a tile is blacklisted. --> <!-- Notification shown when a tile is blacklisted. -->
<div id="mv-notice-container"> <div id="mv-notice-container">
<div id="mv-notice" class="mv-notice-hide" role="alert"> <div id="mv-notice" class="notice-hide" role="alert">
<span id="mv-msg"></span> <span id="mv-msg"></span>
<!-- Links in the notification. --> <!-- Links in the notification. -->
<span id="mv-notice-links"> <span id="mv-notice-links">
...@@ -68,17 +68,20 @@ ...@@ -68,17 +68,20 @@
</div> </div>
<div id="attribution"><div id="attribution-text"></div></div> <div id="attribution"><div id="attribution-text"></div></div>
<div id="error-notice-container">
<div id="error-notice" class="notice-hide" role="alert">
<span id="error-notice-icon-container">
<div id="error-notice-icon"></div>
</span>
<span id="error-notice-msg"></span>
<span id="error-notice-link" class="ripple" tabindex="0" role="button"></span>
</div>
</div>
<div id="edit-bg" hidden> <div id="edit-bg" hidden>
<button id="edit-bg-gear"></button> <button id="edit-bg-gear"></button>
</div> </div>
<div id="message-box-container" class="message-box-hide">
<div id="message-box">
<div id="message-box-icon"></div>
<div id="message-box-message"></div>
<div id="message-box-link" class="ripple"></div>
</div>
</div>
<div id="custom-bg-attr"></div> <div id="custom-bg-attr"></div>
</div> </div>
......
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