define([ 'jquery', '/customize/application_config.js', '/api/config', ], function ($, Config, ApiConfig) { var Messages = {}; var Cryptpad; var Bar = { constants: {}, }; var SPINNER_DISAPPEAR_TIME = 1000; // Toolbar parts var TOOLBAR_CLS = Bar.constants.toolbar = 'cryptpad-toolbar'; var TOP_CLS = Bar.constants.top = 'cryptpad-toolbar-top'; var LEFTSIDE_CLS = Bar.constants.leftside = 'cryptpad-toolbar-leftside'; var RIGHTSIDE_CLS = Bar.constants.rightside = 'cryptpad-toolbar-rightside'; var DRAWER_CLS = Bar.constants.drawer = 'drawer-content'; var HISTORY_CLS = Bar.constants.history = 'cryptpad-toolbar-history'; // Userlist var USERLIST_CLS = Bar.constants.userlist = "cryptpad-dropdown-users"; var EDITSHARE_CLS = Bar.constants.editShare = "cryptpad-dropdown-editShare"; var VIEWSHARE_CLS = Bar.constants.viewShare = "cryptpad-dropdown-viewShare"; var SHARE_CLS = Bar.constants.viewShare = "cryptpad-dropdown-share"; // Top parts var USER_CLS = Bar.constants.userAdmin = "cryptpad-user"; var SPINNER_CLS = Bar.constants.spinner = 'cryptpad-spinner'; var LIMIT_CLS = Bar.constants.lag = 'cryptpad-limit'; var TITLE_CLS = Bar.constants.title = "cryptpad-title"; var NEWPAD_CLS = Bar.constants.newpad = "cryptpad-new"; // User admin menu var USERADMIN_CLS = Bar.constants.user = 'cryptpad-user-dropdown'; var USERNAME_CLS = Bar.constants.username = 'cryptpad-toolbar-username'; var READONLY_CLS = Bar.constants.readonly = 'cryptpad-readonly'; var USERBUTTON_CLS = Bar.constants.changeUsername = "cryptpad-change-username"; // Create the toolbar element var uid = function () { return 'cryptpad-uid-' + String(Math.random()).substring(2); }; var createRealtimeToolbar = function (config) { if (!config.$container) { return; } var $container = config.$container; var $toolbar = $('
', { 'class': TOOLBAR_CLS, id: uid(), }); var parsed = Cryptpad.parsePadUrl(window.location.href); if (typeof parsed.type === "string") { config.$container.parents('body').addClass('app-' + parsed.type); } var $topContainer = $('
', {'class': TOP_CLS}); $('', {'class': 'filler'}).appendTo($topContainer); var $userContainer = $('', { 'class': USER_CLS }).appendTo($topContainer); $('', {'class': LIMIT_CLS}).hide().appendTo($userContainer); $('', {'class': NEWPAD_CLS + ' dropdown-bar'}).hide().appendTo($userContainer); $('', {'class': USERADMIN_CLS + ' dropdown-bar'}).hide().appendTo($userContainer); $toolbar.append($topContainer) .append($('
', {'class': LEFTSIDE_CLS})) .append($('
', {'class': RIGHTSIDE_CLS})) .append($('
', {'class': HISTORY_CLS})); var $rightside = $toolbar.find('.'+RIGHTSIDE_CLS); if (!config.hideDrawer) { var $drawerContent = $('
', { 'class': DRAWER_CLS,// + ' dropdown-bar-content cryptpad-dropdown' 'tabindex': 1 }).appendTo($rightside).hide(); var $drawer = Cryptpad.createButton('more', true).appendTo($rightside); $drawer.click(function () { $drawerContent.toggle(); $drawer.removeClass('active'); if ($drawerContent.is(':visible')) { $drawer.addClass('active'); $drawerContent.focus(); } }); var onBlur = function (e) { if (e.relatedTarget) { if ($(e.relatedTarget).is('.drawer-button')) { return; } if ($(e.relatedTarget).parents('.'+DRAWER_CLS).length) { $(e.relatedTarget).blur(onBlur); return; } } $drawer.removeClass('active'); $drawerContent.hide(); }; $drawerContent.blur(onBlur); } // The 'notitle' class removes the line added for the title with a small screen if (!config.title || typeof config.title !== "object") { $toolbar.addClass('notitle'); } $container.prepend($toolbar); $container.on('drop dragover', function (e) { e.preventDefault(); e.stopPropagation(); }); return $toolbar; }; // Userlist elements var getOtherUsers = function(config) { var userList = config.userList.list.users; var userData = config.userList.data; var i = 0; // duplicates counter var list = []; // Display only one time each user (if he is connected in multiple tabs) var uids = []; userList.forEach(function(user) { //if (user !== userNetfluxId) { var data = userData[user] || {}; var userId = data.uid; if (!userId) { return; } data.netfluxId = user; if (uids.indexOf(userId) === -1) {// && (!myUid || userId !== myUid)) { uids.push(userId); list.push(data); } else { i++; } //} }); return { list: list, duplicates: i }; }; var arrayIntersect = function(a, b) { return $.grep(a, function(i) { return $.inArray(i, b) > -1; }); }; var updateDisplayName = function (toolbar, config) { // Change username in useradmin dropdown var name = Cryptpad.getDisplayName(); if (config.displayed.indexOf('useradmin') !== -1) { var $userAdminElement = toolbar.$userAdmin; var $userElement = $userAdminElement.find('.' + USERNAME_CLS); $userElement.show(); if (config.readOnly === 1) { $userElement.addClass(READONLY_CLS).text(Messages.readonly); } else { if (!name) { name = Messages.anonymous; } $userElement.removeClass(READONLY_CLS).text(name); } } }; var avatars = {}; var updateUserList = function (toolbar, config) { // Make sure the elements are displayed var $userButtons = toolbar.userlist; var $userlistContent = toolbar.userlistContent; var userList = config.userList.list.users; var userData = config.userList.data; var numberOfUsers = userList.length; // If we are using old pads (readonly unavailable), only editing users are in userList. // With new pads, we also have readonly users in userList, so we have to intersect with // the userData to have only the editing users. We can't use userData directly since it // may contain data about users that have already left the channel. userList = config.readOnly === -1 ? userList : arrayIntersect(userList, Object.keys(userData)); // Names of editing users var others = getOtherUsers(config); var editUsersNames = others.list; var duplicates = others.duplicates; // Number of duplicates editUsersNames.sort(function (a, b) { var na = a.name || Messages.anonymous; var nb = b.name || Messages.anonymous; return na.toLowerCase() > nb.toLowerCase(); }); var numberOfEditUsers = userList.length - duplicates; var numberOfViewUsers = numberOfUsers - userList.length; // Update the userlist var $editUsers = $userlistContent.find('.' + USERLIST_CLS).html(''); Cryptpad.clearTooltips(); var $editUsersList = $('
', {'class': 'userlist-others'}); // Editors var pendingFriends = Cryptpad.getPendingInvites(); editUsersNames.forEach(function (data) { var name = data.name || Messages.anonymous; var $span = $('', {'class': 'avatar'}); var $rightCol = $('', {'class': 'right-col'}); var $nameSpan = $('', {'class': 'name'}).text(name).appendTo($rightCol); var proxy = Cryptpad.getProxy(); var isMe = data.curvePublic === proxy.curvePublic; if (Cryptpad.isLoggedIn() && data.curvePublic) { if (isMe) { $span.attr('title', Messages._getKey('userlist_thisIsYou', [ name ])); $nameSpan.text(name); } else if (!proxy.friends || !proxy.friends[data.curvePublic]) { if (pendingFriends.indexOf(data.netfluxId) !== -1) { $('', {'class': 'friend'}).text(Messages.userlist_pending) .appendTo($rightCol); } else { $('', { 'class': 'fa fa-user-plus friend', 'title': Messages._getKey('userlist_addAsFriendTitle', [ name ]) }).appendTo($rightCol).click(function (e) { e.stopPropagation(); Cryptpad.inviteFromUserlist(Cryptpad, data.netfluxId); }); } } } if (data.profile) { $span.addClass('clickable'); $span.click(function () { window.open('/profile/#' + data.profile); }); } if (data.avatar && avatars[data.avatar]) { $span.append(avatars[data.avatar]); $span.append($rightCol); } else { Cryptpad.displayAvatar($span, data.avatar, name, function ($img) { if (data.avatar && $img) { avatars[data.avatar] = $img[0].outerHTML; } $span.append($rightCol); }); } $span.data('uid', data.uid); $editUsersList.append($span); }); $editUsers.append($editUsersList); // Viewers if (numberOfViewUsers > 0) { var viewText = '
'; var viewerText = numberOfViewUsers !== 1 ? Messages.viewers : Messages.viewer; viewText += numberOfViewUsers + ' ' + viewerText + '
'; $editUsers.append(viewText); } // Update the buttons var fa_editusers = ''; var fa_viewusers = ''; var $spansmall = $('').html(fa_editusers + ' ' + numberOfEditUsers + '   ' + fa_viewusers + ' ' + numberOfViewUsers); $userButtons.find('.buttonTitle').html('').append($spansmall); updateDisplayName(toolbar, config); }; var initUserList = function (toolbar, config) { if (config.userList && config.userList.list && config.userList.userNetfluxId) { var userList = config.userList.list; userList.change.push(function () { var users = userList.users; if (users.indexOf(config.userList.userNetfluxId) !== -1) {toolbar.connected = true;} if (!toolbar.connected) { return; } if (config.userList.data) { updateUserList(toolbar, config); } }); } }; // Create sub-elements var createUserList = function (toolbar, config) { if (!config.userList || !config.userList.list || !config.userList.data || !config.userList.userNetfluxId) { throw new Error("You must provide a `userList` object to display the userlist"); } var $content = $('
', {'class': 'userlist-drawer'}); $content.on('drop dragover', function (e) { e.preventDefault(); e.stopPropagation(); }); var $closeIcon = $('', {"class": "fa fa-window-close close"}).appendTo($content); $('

').text(Messages.users).appendTo($content); $('

', {'class': USERLIST_CLS}).appendTo($content); toolbar.userlistContent = $content; var $container = $('', {id: 'userButtons'}); var $button = $('