From 2d0337332d64065c5bf36dfb775c48976c0f730d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julius=20H=C3=A4rtl?= Date: Fri, 1 Mar 2019 13:02:12 +0100 Subject: [PATCH] Add toastify js as a OC.Notification replacement MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Julius Härtl --- core/css/server.scss | 3 +- core/css/toast.scss | 46 +++++++++++ core/src/OC/notification.js | 155 ++++++++++-------------------------- core/src/OCP/index.js | 6 +- core/src/OCP/toast.js | 89 +++++++++++++++++++++ package-lock.json | 54 ++++++++++++- package.json | 1 + 7 files changed, 235 insertions(+), 119 deletions(-) create mode 100644 core/css/toast.scss create mode 100644 core/src/OCP/toast.js diff --git a/core/css/server.scss b/core/css/server.scss index 7269847ad9..a0fc551a18 100644 --- a/core/css/server.scss +++ b/core/css/server.scss @@ -8,4 +8,5 @@ @import 'fixes.scss'; @import 'mobile.scss'; @import 'tooltip.scss'; -@import 'public.scss'; \ No newline at end of file +@import 'toast.scss'; +@import 'public.scss'; diff --git a/core/css/toast.scss b/core/css/toast.scss new file mode 100644 index 0000000000..242ae03b69 --- /dev/null +++ b/core/css/toast.scss @@ -0,0 +1,46 @@ +.toastify.toast { + min-width: 200px; + background: none; + background-color: var(--color-main-background); + color: var(--color-main-text); + box-shadow: 0 0 6px 0 var(--color-box-shadow); + padding: 12px; + padding-right: 34px; + margin-top: 45px; + + .toast-close { + position: absolute; + top: 0; + right: 0; + width: 38px; + opacity: 0.4; + padding: 12px; + @include icon-color('close', 'actions', $color-black, 2, true); + background-position: center; + background-repeat: no-repeat; + text-indent: 200%; + white-space: nowrap; + overflow: hidden; + + &:hover, &:focus, &:active { + cursor: pointer; + opacity: 1; + } + } +} +.toastify.toastify-top { + right: 10px; +} + +.toast-error { + border-left: 3px solid var(--color-error); +} +.toast-info { + border-left: 3px solid var(--color-primary); +} +.toast-warning { + border-left: 3px solid var(--color-warning); +} +.toast-success { + border-left: 3px solid var(--color-success); +} diff --git a/core/src/OC/notification.js b/core/src/OC/notification.js index 73220c71bd..45af158412 100644 --- a/core/src/OC/notification.js +++ b/core/src/OC/notification.js @@ -21,24 +21,22 @@ import _ from 'underscore' import $ from 'jquery' +import Toastify from 'toastify-js' /** * @todo Write documentation + * @deprecated 17.0.0 use OCP.Toast * @namespace OC.Notification */ export default { - queuedNotifications: [], + + updatableNotification: null, + getDefaultNotificationFunction: null, - /** - * @type Array - * @description array of notification timers - */ - notificationTimers: [], - /** * @param callback - * @todo Write documentation + * @deprecated 17.0.0 use OCP.Toast */ setDefault: function (callback) { this.getDefaultNotificationFunction = callback; @@ -52,10 +50,11 @@ export default { * * @param {jQuery} [$row] notification row * @param {Function} [callback] callback + * @deprecated 17.0.0 use OCP.Toast */ hide: function ($row, callback) { var self = this; - var $notification = $('#notification'); + var $notification = $('#content'); if (_.isFunction($row)) { // first arg is the callback @@ -64,46 +63,23 @@ export default { } if (!$row) { - console.warn('Missing argument $row in OC.Notification.hide() call, caller needs to be adjusted to only dismiss its own notification'); - // assume that the row to be hidden is the first one - $row = $notification.find('.row:first'); - } - - if ($row && $notification.find('.row').length > 1) { - // remove the row directly - $row.remove(); - if (callback) { - callback.call(); - } + console.error('Missing argument $row in OC.Notification.hide() call, caller needs to be adjusted to only dismiss its own notification'); return; } - _.defer(function () { - // fade out is supposed to only fade when there is a single row - // however, some code might call hide() and show() directly after, - // which results in more than one element - // in this case, simply delete that one element that was supposed to - // fade out - // - // FIXME: remove once all callers are adjusted to only hide their own notifications - if ($notification.find('.row').length > 1) { - $row.remove(); - return; + // remove the row directly + $row.each(function () { + $(this)[0].toastify.hideToast() + if (this === this.updatableNotification) { + this.updatableNotification = null } - - // else, fade out whatever was present - $notification.fadeOut('400', function () { - if (self.isHidden()) { - if (self.getDefaultNotificationFunction) { - self.getDefaultNotificationFunction.call(); - } - } - if (callback) { - callback.call(); - } - $notification.empty(); - }); - }); + }) + if (callback) { + callback.call() + } + if (this.getDefaultNotificationFunction) { + this.getDefaultNotificationFunction() + } }, /** @@ -116,45 +92,14 @@ export default { * @param {string} [options.type] notification type * @param {int} [options.timeout=0] timeout value, defaults to 0 (permanent) * @return {jQuery} jQuery element for notification row + * @deprecated 17.0.0 use OCP.Toast */ showHtml: function (html, options) { - options = options || {}; - _.defaults(options, { - timeout: 0 - }); - - var self = this; - var $notification = $('#notification'); - if (this.isHidden()) { - $notification.fadeIn().css('display', 'inline-block'); - } - var $row = $('
'); - if (options.type) { - $row.addClass('type-' + options.type); - } - if (options.type === 'error') { - // add a close button - var $closeButton = $(''); - $closeButton.attr('alt', t('core', 'Dismiss')); - $row.append($closeButton); - $closeButton.one('click', function () { - self.hide($row); - return false; - }); - $row.addClass('closeable'); - } - - $row.prepend(html); - $notification.append($row); - - if (options.timeout > 0) { - // register timeout to vanish notification - this.notificationTimers.push(setTimeout(function () { - self.hide($row); - }, (options.timeout * 1000))); - } - - return $row; + options = options || {} + options.showHtml = true + options.timeout = (options.timeout === 0) ? -1 : options.timeout + const toast = window.OCP.Toast.message(html, options) + return $(toast.toastElement) }, /** @@ -165,9 +110,11 @@ export default { * @param {string} [options.type] notification type * @param {int} [options.timeout=0] timeout value, defaults to 0 (permanent) * @return {jQuery} jQuery element for notification row + * @deprecated 17.0.0 use OCP.Toast */ show: function (text, options) { - return this.showHtml($('
').text(text).html(), options); + const toast = window.OCP.Toast.message(text, options); + return $(toast.toastElement); }, /** @@ -175,23 +122,14 @@ export default { * * @param {string} text Message to display * @return {jQuery} JQuery element for notificaiton row + * @deprecated 17.0.0 use OCP.Toast */ showUpdate: function (text) { - var $notification = $('#notification'); - // sanitise - var $html = $('
').text(text).html(); - - // new notification - if (text && $notification.find('.row').length == 0) { - return this.showHtml($html); + if (this.updatableNotification) { + this.updatableNotification.hideToast(); } - - var $row = $('
').prepend($html); - - // just update html in notification - $notification.html($row); - - return $row; + this.updatableNotification = OCP.Toast.message(text, {timeout: -1}) + return $(this.updatableNotification.toastElement); }, /** @@ -203,30 +141,21 @@ export default { * @param {int} [options.timeout=7] timeout in seconds, if this is 0 it will show the message permanently * @param {boolean} [options.isHTML=false] an indicator for HTML notifications (true) or text (false) * @param {string} [options.type] notification type + * @deprecated 17.0.0 use OCP.Toast */ showTemporary: function (text, options) { - var defaults = { - isHTML: false, - timeout: 7 - }; - options = options || {}; - // merge defaults with passed in options - _.defaults(options, defaults); - - var $row; - if (options.isHTML) { - $row = this.showHtml(text, options); - } else { - $row = this.show(text, options); - } - return $row; + options = options || {} + options.timeout = options.timeout || 7; + const toast = window.OCP.Toast.message(text, options); + return $(toast.toastElement); }, /** * Returns whether a notification is hidden. * @return {boolean} + * @deprecated 17.0.0 use OCP.Toast */ isHidden: function () { - return !$("#notification").find('.row').length; + return !$('#content').find('.toastify').length; } } diff --git a/core/src/OCP/index.js b/core/src/OCP/index.js index 6794531836..a4d8f46b88 100644 --- a/core/src/OCP/index.js +++ b/core/src/OCP/index.js @@ -6,14 +6,16 @@ import * as Comments from './comments' import * as InitialState from './initialstate' import Loader from './loader' import Collaboration from './collaboration' +import Toast from './toast' import * as WhatsNew from './whatsnew' /** @namespace OCP */ export default { AppConfig, + Collaboration, Comments, InitialState, Loader, - WhatsNew, - Collaboration + Toast, + WhatsNew }; diff --git a/core/src/OCP/toast.js b/core/src/OCP/toast.js new file mode 100644 index 0000000000..a9c96f14a7 --- /dev/null +++ b/core/src/OCP/toast.js @@ -0,0 +1,89 @@ +/* + * @copyright Copyright (c) 2019 Julius Härtl + * + * @author Julius Härtl + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +import Toastify from 'toastify-js' + +const TOAST_TYPE_CLASES = { + error: 'toast-error', + info: 'toast-info', + warning: 'toast-warning', + success: 'toast-success', + permanent: 'permanent' +} + +const Toast = { + + success(text, options = {}) { + options.type = 'success'; + return this.message(text, options) + }, + + warning(text, options = {}) { + options.type = 'warning'; + return this.message(text, options) + }, + + error(text, options = {}) { + options.type = 'error'; + return this.message(text, options) + }, + + info(text, options = {}) { + options.type = 'info'; + return this.message(text, options) + }, + + message(text, options) { + options = options || {}; + _.defaults(options, { + timeout: 7, + showHtml: false, + type: undefined, + close: true, + callback: () => {} + }); + if (!options.showHtml) { + text = $('
').text(text).html() + } + let classes = '' + if (options.type) { + classes = TOAST_TYPE_CLASES[options.type] + } + + const toast = Toastify({ + text: text, + duration: options.timeout ? options.timeout*1000 : null, + callback: options.callback, + close: options.close, + gravity: 'top', + selector: 'content', + positionLeft: false, + backgroundColor: '', + className: 'toast ' + classes + }) + toast.showToast() + // add toastify object to the element for reference in legacy OC.Notification + toast.toastElement.toastify = toast; + return toast + } +} +export default Toast diff --git a/package-lock.json b/package-lock.json index 5074a8d51f..4c0cd78057 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2330,6 +2330,34 @@ "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", "dev": true + }, + "jsesc": { + "version": "0.5.0", + "resolved": "http://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", + "integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=" + }, + "regexpu-core": { + "version": "1.0.0", + "resolved": "http://registry.npmjs.org/regexpu-core/-/regexpu-core-1.0.0.tgz", + "integrity": "sha1-hqdj9Y7k18L2sQLkdkBQ3n7ZDGs=", + "requires": { + "regenerate": "^1.2.1", + "regjsgen": "^0.2.0", + "regjsparser": "^0.1.4" + } + }, + "regjsgen": { + "version": "0.2.0", + "resolved": "http://registry.npmjs.org/regjsgen/-/regjsgen-0.2.0.tgz", + "integrity": "sha1-bAFq3qxVT3WCP+N6wFuS1aTtsfc=" + }, + "regjsparser": { + "version": "0.1.5", + "resolved": "http://registry.npmjs.org/regjsparser/-/regjsparser-0.1.5.tgz", + "integrity": "sha1-fuj4Tcb6eS0/0K4ijSS9lJ6tIFw=", + "requires": { + "jsesc": "~0.5.0" + } } } }, @@ -3782,6 +3810,21 @@ "optimist": "^0.6.1", "source-map": "^0.6.1", "uglify-js": "^3.1.4" + }, + "dependencies": { + "async": { + "version": "2.6.1", + "resolved": "http://registry.npmjs.org/async/-/async-2.6.1.tgz", + "integrity": "sha512-fNEiL2+AZt6AlAw/29Cr0UDe4sRAHCpEHh54WMz+Bb7QfNcFw4h3loofyJpLeQs4Yx7yuqu/2dLgM5hKOs6HlQ==", + "requires": { + "lodash": "^4.17.10" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + } } }, "handlebars-loader": { @@ -4740,9 +4783,9 @@ } }, "minimist": { - "version": "0.0.10", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz", - "integrity": "sha1-3j+YVD2/lggr5IrRoMfNqDYwHc8=" + "version": "0.0.8", + "resolved": "http://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=" }, "mississippi": { "version": "3.0.0", @@ -6950,6 +6993,11 @@ "repeat-string": "^1.6.1" } }, + "toastify-js": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/toastify-js/-/toastify-js-1.5.0.tgz", + "integrity": "sha512-tupU/X7DqwxYxTgT6n9SSEZLIGuwL1hFWg9uGQOzi8G04FLXoziw0GRF/TmuARrSQQCfIarfzoKEdDPG14Pr3Q==" + }, "tough-cookie": { "version": "2.4.3", "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz", diff --git a/package.json b/package.json index 106d11a823..3c53855a0d 100644 --- a/package.json +++ b/package.json @@ -48,6 +48,7 @@ "query-string": "^5.1.1", "snap.js": "^2.0.9", "strengthify": "git+https://github.com/MorrisJobke/strengthify.git#0.5.8", + "toastify-js": "^1.5.0", "underscore": "^1.9.1", "v-tooltip": "^2.0.2", "vue": "^2.6.10",