Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(6324)

Unified Diff: chrome/browser/resources/bluetooth_internals/snackbar.js

Issue 2568283003: bluetooth: Add notification system to internals page. (Closed)
Patch Set: Remove margin, fix bug where snackbar dismisses if shown with no focus Created 4 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: chrome/browser/resources/bluetooth_internals/snackbar.js
diff --git a/chrome/browser/resources/bluetooth_internals/snackbar.js b/chrome/browser/resources/bluetooth_internals/snackbar.js
new file mode 100644
index 0000000000000000000000000000000000000000..9cca49e23420cdf81f5cd01551ce2acb0a2e3e16
--- /dev/null
+++ b/chrome/browser/resources/bluetooth_internals/snackbar.js
@@ -0,0 +1,226 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+/**
+ * Javascript for Snackbar controls, served from chrome://bluetooth-internals/.
+ */
+
+cr.define('snackbar', function() {
+ /** @typedef {{
+ * message: string,
+ * type: string,
+ * actionText: (string|undefined),
+ * action: (function()|undefined)
+ * }}
+ */
+ var SnackbarOptions;
+
+ /** @const {number} */ var SHOW_DURATION = 5000;
+
+ /**
+ * Enum of Snackbar types. Used by Snackbar to determine the styling for the
+ * Snackbar.
+ * @enum {string}
+ */
+ var SnackbarType = {
+ INFO: 'info',
+ SUCCESS: 'success',
+ WARNING: 'warning',
+ ERROR: 'error',
+ };
+
+ /**
+ * Notification bar for displaying a simple message with an action link.
+ * This element should not be instantiated directly. Instead, users should
+ * use the Snackbar.show and Snackbar.dismiss functions to ensure proper
+ * queuing of messages.
+ */
+ var Snackbar = cr.ui.define('div');
+
+ Snackbar.prototype = {
+ __proto__: HTMLDivElement.prototype,
+
+ /**
+ * Decorates an element as a UI element class. Creates the message div and
+ * action link for the new Snackbar.
+ */
+ decorate: function() {
+ this.classList.add('snackbar');
+ this.messageDiv_ = document.createElement('div');
+ this.appendChild(this.messageDiv_);
+ this.actionLink_ = document.createElement('a', 'action-link');
+ this.appendChild(this.actionLink_);
+
+ this.boundStartTimeout_ = this.startTimeout_.bind(this);
+ this.boundStopTimeout_ = this.stopTimeout_.bind(this);
+ this.addEventListener('mouseleave', this.boundStartTimeout_);
+ this.addEventListener('mouseenter', this.boundStopTimeout_);
+
+ this.timeoutId_ = null;
+ },
+
+ /**
+ * Initializes the content of the Snackbar with the given |options|
+ * including the message, action link text, and click action of the link.
+ * @param {!SnackbarOptions} options
+ */
+ initialize: function(options) {
+ this.messageDiv_.textContent = options.message;
+ this.classList.add(options.type);
+ this.actionLink_.textContent = options.actionText || 'Dismiss';
+
+ this.actionLink_.addEventListener('click', function() {
+ if (options.action) options.action();
+ this.dismiss();
+ }.bind(this));
+ },
+
+ /**
+ * Shows the Snackbar.
+ */
+ show: function() {
+ this.classList.add('open');
+ if (Snackbar.hasContentFocus_) this.startTimeout_();
+ else this.stopTimeout_();
+
+ document.addEventListener('contentfocus', this.boundStartTimeout_);
+ document.addEventListener('contentblur', this.boundStopTimeout_);
+ },
+
+ /**
+ * Dismisses the Snackbar. Once the Snackbar is completely hidden, the
+ * 'dismissed' event is fired.
+ */
+ dismiss: function() {
+ this.addEventListener('webkitTransitionEnd', function(event) {
+ if (event.propertyName === 'transform')
+ this.dispatchEvent(new CustomEvent('dismissed'));
+ }.bind(this));
+
+ ensureTransitionEndEvent(this, SHOW_DURATION);
+ this.classList.remove('open');
+
+ document.removeEventListener('contentfocus', this.boundStartTimeout_);
+ document.removeEventListener('contentblur', this.boundStopTimeout_);
+ },
+
+ /**
+ * Starts the timeout for dismissing the Snackbar.
+ * @private
+ */
+ startTimeout_: function() {
+ this.timeoutId_ = setTimeout(function() {
+ this.dismiss();
+ }.bind(this), SHOW_DURATION);
+ },
+
+ /**
+ * Stops the timeout for dismissing the Snackbar. Only clears the timeout
+ * when the Snackbar is open.
+ * @private
+ */
+ stopTimeout_: function() {
+ if (this.classList.contains('open')) {
+ clearTimeout(this.timeoutId_);
+ this.timeoutId_ = null;
+ }
+ },
+ };
+
+ /** @private {?Snackbar} */
+ Snackbar.current_ = null;
+
+ /** @private {!Array<!SnackbarOptions>} */
+ Snackbar.queue_ = [];
+
+ /** @private {boolean} */
+ Snackbar.hasContentFocus_ = true;
+
+ // There is a chance where the snackbar is shown but the content doesn't have
+ // focus. In this case, the current focus state must be tracked so the
+ // snackbar can pause the dismiss timeout.
+ document.addEventListener('contentfocus', function() {
+ Snackbar.hasContentFocus_ = true;
+ });
+ document.addEventListener('contentblur', function() {
+ Snackbar.hasContentFocus_ = false;
+ });
+
+ /**
+ * TODO(crbug.com/675299): Add ability to specify parent element to Snackbar.
+ * Creates a Snackbar and shows it if one is not showing already. If a
+ * Snackbar is already active, the next Snackbar is queued.
+ * @param {string} message The message to display in the Snackbar.
+ * @param {string=} opt_type A string determining the Snackbar type: info,
+ * success, warning, error. If not provided, info type is used.
+ * @param {string=} opt_actionText The text to display for the action link.
+ * @param {function()=} opt_action A function to be called when the user
+ * presses the action link.
+ * @return {!Snackbar}
+ */
+ Snackbar.show = function(message, opt_type, opt_actionText, opt_action) {
+ var options = {
+ message: message,
+ type: opt_type || SnackbarType.INFO,
+ actionText: opt_actionText,
+ action: opt_action,
+ };
+
+ var newSnackbar = new Snackbar();
+ newSnackbar.initialize(options);
+
+ if (Snackbar.current_)
+ Snackbar.queue_.push(newSnackbar);
+ else
+ Snackbar.show_(newSnackbar);
+
+ return newSnackbar;
+ };
+
+ /**
+ * TODO(crbug.com/675299): Add ability to specify parent element to Snackbar.
+ * Creates a Snackbar and sets events for queuing the next Snackbar to show.
+ * @param {!Snackbar} newSnackbar
+ * @private
+ */
+ Snackbar.show_ = function(newSnackbar) {
+ $('snackbar-container').appendChild(newSnackbar);
+
+ newSnackbar.addEventListener('dismissed', function() {
+ $('snackbar-container').removeChild(Snackbar.current_);
+
+ var newSnackbar = Snackbar.queue_.shift();
+ if (newSnackbar) {
+ Snackbar.show_(newSnackbar);
+ return;
+ }
+
+ Snackbar.current_ = null;
+ });
+
+ Snackbar.current_ = newSnackbar;
+
+ // Show the Snackbar after a slight delay to allow for a layout reflow.
+ setTimeout(function() {
+ newSnackbar.show();
+ }, 10);
+ };
+
+ /**
+ * Dismisses the Snackbar currently showing.
+ * @param {boolean} clearQueue If true, clears the Snackbar queue before
+ * dismissing.
+ */
+ Snackbar.dismiss = function(clearQueue) {
+ if (clearQueue) Snackbar.queue_ = [];
+ if (Snackbar.current_) Snackbar.current_.dismiss();
+ };
+
+
+
+ return {
+ Snackbar: Snackbar,
+ SnackbarType: SnackbarType,
+ };
+});

Powered by Google App Engine
This is Rietveld 408576698