diff --git a/www/common/common-inner.js b/www/common/common-inner.js new file mode 100644 index 000000000..921d10e88 --- /dev/null +++ b/www/common/common-inner.js @@ -0,0 +1,8 @@ +define([ + 'jquery' +], function ($) { + var common = {}; + + + return common; +}); diff --git a/www/common/metadata-manager.js b/www/common/metadata-manager.js index a9c9f0b54..e68d0d2f3 100644 --- a/www/common/metadata-manager.js +++ b/www/common/metadata-manager.js @@ -20,18 +20,21 @@ define([], function () { } var mdo = {}; // We don't want to add our user data to the object multiple times. - var containsYou = false; + //var containsYou = false; //console.log(metadataObj); + console.log(metadataObj.users); Object.keys(metadataObj.users).forEach(function (x) { if (members.indexOf(x) === -1) { return; } mdo[x] = metadataObj.users[x]; - if (metadataObj.users[x].uid === meta.user.uid) { + /*if (metadataObj.users[x].uid === meta.user.uid) { //console.log('document already contains you'); containsYou = true; - } + }*/ }); - if (!containsYou) { mdo[meta.user.netfluxId] = meta.user; } + //if (!containsYou) { mdo[meta.user.netfluxId] = meta.user; } + mdo[meta.user.netfluxId] = meta.user; metadataObj.users = mdo; + dirty = false; changeHandlers.forEach(function (f) { f(); }); }; @@ -74,8 +77,15 @@ define([], function () { checkUpdate(); return Object.freeze(JSON.parse(JSON.stringify(metadataObj))); }, - onChange: function (f) { changeHandlers.push(f); } + onChange: function (f) { changeHandlers.push(f); }, + getNetfluxId: function () { + return meta && meta.user && meta.user.netfluxId; + }, + getUserlist: function () { + var list = members.slice().filter(function (m) { return m.length === 32; }); + return list; + } }); }; return Object.freeze({ create: create }); -}); \ No newline at end of file +}); diff --git a/www/common/toolbar3.js b/www/common/toolbar3.js new file mode 100644 index 000000000..7b5cd287a --- /dev/null +++ b/www/common/toolbar3.js @@ -0,0 +1,1044 @@ +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(), + }); + + // TODO iframe + // var parsed = Cryptpad.parsePadUrl(window.location.href); + var parsed = { type:'pad' }; + 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})); + + // TODO + /* + 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.getUserlist(); + var userData = config.userList.getMetadata().users; + + 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.getUserlist(); + var userData = config.userList.getMetadata().users; +console.log(userList, userData); + 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 + // TODO iframe enable friends + //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) { + // TODO clean comments + if (config.userList) { /* && config.userList.list && config.userList.userNetfluxId) {*/ + //var userList = config.userList.list; + //userList.change.push + var metadataMgr = config.userList; + metadataMgr.onChange(function () { + var users = metadataMgr.getUserlist(); + if (users.indexOf(metadataMgr.getNetfluxId()) !== -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', title: Messages.userListButton}); + + var $button = $('