diff --git a/customize.dist/messages.js b/customize.dist/messages.js index 736b244a1..4674f9490 100755 --- a/customize.dist/messages.js +++ b/customize.dist/messages.js @@ -141,6 +141,8 @@ define(req, function(AppConfig, Default, Language) { Messages.badges_premium = "Premium user"; Messages.badges_error = "Error while validating this user's data"; Messages.profile_badges = "Badges"; + Messages.user_profile = 'Go to user profile'; + Messages.add_password = "Add your document password"; Messages.show_password = "Show password"; Messages.hide_password = "Hide password"; Messages.page_next = "Next page"; diff --git a/www/common/common-ui-elements.js b/www/common/common-ui-elements.js index 26f7f7561..b5b26b0d9 100644 --- a/www/common/common-ui-elements.js +++ b/www/common/common-ui-elements.js @@ -4469,5 +4469,61 @@ define([ return container; }; + UIElements.reorderDOM = function ($content, isDrawer) { + var reorderDOM = Util.throttle(function ($content, observer) { + if (!$content.length) { return; } + + // List all children based on their "order" property + var map = {}; + $content[0].childNodes.forEach((node) => { + try { + if (!node.attributes) { return; } + let nodeWithOrder; + if (isDrawer) { // HACK: the order is set on their inner "a" tag + let $n = $(node); + if (!$n.attr('class') && + ($n.find('.fa').length || $n.find('.cptools').length)) { + nodeWithOrder = $n.find('.fa')[0] || $n.find('.cptools')[0]; + } + } + var order = getComputedStyle(nodeWithOrder || node).getPropertyValue("order"); + var a = map[order] = map[order] || []; + a.push(node); + } catch (e) { console.error(e, node); } + }); + + // Disconnect the observer while we're reordering to avoid infinite loop + observer.disconnect(); + Object.keys(map).sort(function (a, b) { + return Number(a) - Number(b); + }).forEach(function (k) { + var arr = map[k]; + if (!Number(k)) { return; } // No need to "append" if order is -1 + // Reorder + arr.forEach(function (node) { + $content.append(node); + }); + }); + observer.start(); + }, 100); + + let observer = new MutationObserver(function(mutations) { + mutations.forEach(function(mutation) { + if (mutation.addedNodes.length) { + reorderDOM($content, observer); + } + }); + }); + observer.start = function () { + if (!$content.length) { return; } + observer.observe($content[0], { + childList: true + }); + }; + observer.start(); + }; + + + return UIElements; }); diff --git a/www/common/sframe-common-mailbox.js b/www/common/sframe-common-mailbox.js index bf05bdd18..d84ea457a 100644 --- a/www/common/sframe-common-mailbox.js +++ b/www/common/sframe-common-mailbox.js @@ -81,17 +81,22 @@ define([ Common.openURL(Hash.hashToHref('', 'calendar')); }); } else if (userData && typeof(userData) === "object" && userData.profile) { - avatar = h('span.cp-avatar'); + avatar = h('span.cp-avatar',{ + tabindex: 0, + title: Messages.user_profile, + 'aria-label': Messages.user_profile, + role: 'button' + }); Common.displayAvatar($(avatar), userData.avatar, userData.displayName || userData.name); - $(avatar).click(function (e) { + const handler = function (e) { e.stopPropagation(); Common.openURL(Hash.hashToHref(userData.profile, 'profile')); - }); + }; + Util.onClickEnter($(avatar), handler, { space: true }); } else if (userData && userData.supportTeam) { avatar = h('span.cp-avatar-image', h('img', { src:'/customize/CryptPad_logo.svg' })); } var order = -Math.floor((Util.find(data, ['content', 'msg', 'ctime']) || 0) / 1000); - const tabIndexValue = undefined;//data.content.isDismissible ? undefined : '0'; notif = h('li.cp-notification', { role: 'menuitem', tabindex: '0', @@ -100,7 +105,7 @@ define([ }, [ avatar, h('div.cp-notification-content', { - tabindex: tabIndexValue + tabindex: 0 }, [ h('p', data.content.msg.type + ' - ' +formatData(data)) ]) @@ -119,15 +124,19 @@ define([ $(notif).find('.cp-notification-content p').html(data.content.getFormatText()); }, 60000); } + const label = $(notif).find('.cp-notification-content p').text(); + $(notif).find('.cp-notification-content').attr('aria-label', label); } $(notif).mouseenter((e) => { e.stopPropagation(); - $(notif).focus(); + if($(notif).find('li[tabindex="0"]').length) { + $(notif).focus(); + }; }); if (data.content.isClickable) { - $(notif).find('.cp-notification-content').addClass("cp-clickable").on('click keypress', function (event) { + $(notif).find('.cp-notification-content').addClass("cp-clickable").attr('role', 'link').on('click keypress', function (event) { if (event.type === 'click' || (event.type === 'keypress' && event.which === 13)) { data.content.handler(); } @@ -136,7 +145,10 @@ define([ if (data.content.isDismissible) { var dismissIcon = h('span.fa.fa-times'); var dismiss = h('div.cp-notification-dismiss', { + tabindex: 0, title: Messages.notifications_dismiss, + 'aria-label': Messages.notifications_dismiss, + role: 'button' }, dismissIcon); $(dismiss).addClass("cp-clickable") .on('click keypress', function (event) { diff --git a/www/common/toolbar.js b/www/common/toolbar.js index 3e06c6e3f..ef1b94a18 100644 --- a/www/common/toolbar.js +++ b/www/common/toolbar.js @@ -65,60 +65,6 @@ MessengerUI, Messages, Pages, PadTypes) { return 'cp-toolbar-uid-' + String(Math.random()).substring(2); }; - var observeChildren = function ($content, isDrawer) { - var reorderDOM = Util.throttle(function ($content, observer) { - if (!$content.length) { return; } - - // List all children based on their "order" property - var map = {}; - $content[0].childNodes.forEach((node) => { - try { - if (!node.attributes) { return; } - let nodeWithOrder; - if (isDrawer) { // HACK: the order is set on their inner "a" tag - let $n = $(node); - if (!$n.attr('class') && - ($n.find('.fa').length || $n.find('.cptools').length)) { - nodeWithOrder = $n.find('.fa')[0] || $n.find('.cptools')[0]; - } - } - var order = getComputedStyle(nodeWithOrder || node).getPropertyValue("order"); - var a = map[order] = map[order] || []; - a.push(node); - } catch (e) { console.error(e, node); } - }); - - // Disconnect the observer while we're reordering to avoid infinite loop - observer.disconnect(); - Object.keys(map).sort(function (a, b) { - return Number(a) - Number(b); - }).forEach(function (k) { - var arr = map[k]; - if (!Number(k)) { return; } // No need to "append" if order is 0 - // Reorder - arr.forEach(function (node) { - $content.append(node); - }); - }); - observer.start(); - }, 100); - - let observer = new MutationObserver(function(mutations) { - mutations.forEach(function(mutation) { - if (mutation.addedNodes.length) { - reorderDOM($content, observer); - } - }); - }); - observer.start = function () { - if (!$content.length) { return; } - observer.observe($content[0], { - childList: true - }); - }; - observer.start(); - }; - var createRealtimeToolbar = function (config) { if (!config.$container) { return; } var $container = config.$container; @@ -1231,7 +1177,7 @@ MessengerUI, Messages, Pages, PadTypes) { $button.attr('aria-label', Messages.notificationsPage); var $n = $button.find('.cp-dropdown-button-title').hide(); var $empty = $(div).find('.cp-notifications-empty'); - observeChildren($(div)); + UIElements.reorderDOM($(div)); var refresh = function () { updateUserList(toolbar, config); @@ -1457,14 +1403,14 @@ MessengerUI, Messages, Pages, PadTypes) { toolbar.$history = $toolbar.find('.'+Bar.constants.history); toolbar.$user = $toolbar.find('.'+Bar.constants.userAdmin); - observeChildren(toolbar.$drawer, true); - observeChildren(toolbar.$bottomL); - observeChildren(toolbar.$bottomM); - observeChildren(toolbar.$bottomR); - observeChildren(toolbar.$top); - observeChildren(toolbar.$user); + UIElements.reorderDOM(toolbar.$drawer, true); + UIElements.reorderDOM(toolbar.$bottomL); + UIElements.reorderDOM(toolbar.$bottomM); + UIElements.reorderDOM(toolbar.$bottomR); + UIElements.reorderDOM(toolbar.$top); + UIElements.reorderDOM(toolbar.$user); if (config.$contentContainer) { - observeChildren(config.$contentContainer); + UIElements.reorderDOM(config.$contentContainer); } toolbar.$userAdmin = $toolbar.find('.'+Bar.constants.userAdmin); diff --git a/www/notifications/app-notifications.less b/www/notifications/app-notifications.less index b3dcf439c..56c784f8b 100644 --- a/www/notifications/app-notifications.less +++ b/www/notifications/app-notifications.less @@ -21,6 +21,10 @@ &:hover { background-color: @cp_notif-hover; } + &:focus-visible { + outline: @variables_focus_style; + border-radius: @variables_radius; + } } .cp-app-notifications-panel { @@ -59,6 +63,8 @@ justify-content: center; align-items: center; width: 3rem; + border-radius: @variables_radius; + margin: 0.2rem; } } } @@ -90,16 +96,20 @@ } .cp-avatar { .avatar_main(48px); - padding: 0 10px; + padding: 5px; + margin: 0.2rem; cursor: pointer; &:hover { background-color: @cp_notif-hover; } + &:focus-visible { + outline: @variables_focus_style; + border-radius: @variables_radius; + } } .cp-avatar-calendar { font-size: 45px; - padding: 0 12px; - overflow: hidden; + padding: 12px; } &.cp-app-notification-archived { background-color: @cp_notif-bg; @@ -114,16 +124,18 @@ flex-direction: row; justify-content: flex-start; align-items: center; + margin: 0.1rem; + &:focus-visible { + outline: @variables_focus_style; + border-radius: @variables_radius; + } p { display: inline-block; margin: 1rem 1rem; flex: 1; - min-width: 0; } .notification-time { - margin: 1rem 1rem; - color: grey; - margin-left: auto; + margin: 1rem 1rem 1rem auto; } } @@ -136,6 +148,10 @@ align-items: center; border-left: 1px solid @cp_notif-table-border; width: 3rem; + margin: 0.2rem; + &:focus-visible{ + border-radius: @variables_radius; + } } } } diff --git a/www/notifications/inner.js b/www/notifications/inner.js index 8228f73c5..dfde1dd67 100644 --- a/www/notifications/inner.js +++ b/www/notifications/inner.js @@ -12,7 +12,9 @@ define([ '/common/hyperscript.js', '/customize/messages.js', '/common/common-interface.js', + '/common/common-ui-elements.js', '/common/notifications.js', + '/common/common-util.js', 'css!/components/bootstrap/dist/css/bootstrap.min.css', 'css!/components/components-font-awesome/css/font-awesome.min.css', @@ -27,7 +29,9 @@ define([ h, Messages, UI, - Notifications + UIElements, + Notifications, + Util, ) { var APP = {}; @@ -74,14 +78,16 @@ define([ h("h5.cp-app-notifications-panel-title", (Messages.notificationsPage || "Notifications") + " - " + categoryName), h("div.cp-app-notifications-panel-titlebar-buttons", [ - dismissAll = h("div.cp-app-notifications-dismissall.cp-clickable", { title: Messages.notifications_dismissAll || "Dismiss All" }, h("span.fa.fa-trash")), + dismissAll = h("div.cp-app-notifications-dismissall.cp-clickable", { tabindex: 0, title: Messages.notifications_dismissAll || "Dismiss All", 'aria-label': Messages.notifications_dismissAll || "Dismiss All", role: 'button' }, h("span.fa.fa-trash")), ]), ]), - notifsList = h("div.cp-app-notifications-panel-list", [ + notifsList = h("div.cp-app-notifications-panel-list", {'role': 'list', 'aria-label': (Messages.notificationsPage || "Notifications") + " " + categoryName }, [ h("div.cp-notification.no-notifications", Messages.notifications_empty), ]), ]); + UIElements.reorderDOM($(notifsList)); + // add notification var addNotification = function (data, el) { // if the type of notification correspond @@ -89,6 +95,8 @@ define([ notifsData.push(data); var icon = $(el).find(".cp-reminder"); $(icon).addClass('cp-avatar-calendar'); + $(el).attr('tabindex', -1); + $(el).attr('role', 'listitem'); $(notifsList).prepend(el); } }; @@ -107,6 +115,7 @@ define([ var time = new Date(data.content.time); $(el).find(".cp-notification-content").append(h("span.notification-time", time.toLocaleString())); $(el).addClass("cp-app-notification-archived"); + $(el).attr('tabindex', -1); if (isDataUnread) { $(el).hide(); } else { @@ -122,7 +131,7 @@ define([ var loadmore; var lastKnownHash; $(dismissAll).remove(); - loadmore = h("div.cp-app-notification-loadmore.cp-clickable", Messages.history_loadMore); + loadmore = h("button.cp-app-notification-loadmore.cp-clickable", Messages.history_loadMore); $(loadmore).click(function () { common.mailbox.getNotificationsHistory('notifications', 10, lastKnownHash, function (err, messages, end) { if (!Array.isArray(messages)) { return; } @@ -153,14 +162,17 @@ define([ $('.cp-app-notification-archived[data-hash="' + data.hash + '"]').css('display', 'flex'); } }); - - $(dismissAll).click(function () { + const handler = function (e) { + if (!notifsData) { + return; + } notifsData.forEach(function (data) { if (data.content.isDismissible) { data.content.dismissHandler(); } }); - }); + }; + Util.onClickEnter($(dismissAll), handler, { space: true }); return $div; }; @@ -198,18 +210,18 @@ define([ }); }; var createLeftside = function () { - var $categories = $('
', {'class': 'cp-sidebarlayout-categories'}) + var $categories = $('
', {'class': 'cp-sidebarlayout-categories', 'role': 'menu' }) .appendTo(APP.$leftside); var metadataMgr = common.getMetadataMgr(); var privateData = metadataMgr.getPrivateData(); var active = privateData.category || 'all'; common.setHash(active); Object.keys(categories).forEach(function (key) { - var $category = $('
', {'class': 'cp-sidebarlayout-category', 'tabindex': 0}).appendTo($categories); - if (key === 'all') { $category.append($('', {'class': 'fa fa-bars'})); } - if (key === 'friends') { $category.append($('', {'class': 'fa fa-user'})); } - if (key === 'pads') { $category.append($('', {'class': 'cptools cptools-richtext'})); } - if (key === 'archived') { $category.append($('', {'class': 'fa fa-archive'})); } + var $category = $('
', {'class': 'cp-sidebarlayout-category', 'tabindex': 0, 'role': 'menuitem'}).appendTo($categories); + if (key === 'all') { $category.append($('', {'class': 'fa fa-bars', 'aria-hidden': 'true'})); } + if (key === 'friends') { $category.append($('', {'class': 'fa fa-user', 'aria-hidden': 'true'})); } + if (key === 'pads') { $category.append($('', {'class': 'cptools cptools-richtext', 'aria-hidden': 'true'})); } + if (key === 'archived') { $category.append($('', {'class': 'fa fa-archive', 'aria-hidden': 'true'})); } if (key === active) { $category.addClass('cp-leftside-active');