diff --git a/www/common/cryptpad-common.js b/www/common/cryptpad-common.js index 473fa815c..d2b361284 100644 --- a/www/common/cryptpad-common.js +++ b/www/common/cryptpad-common.js @@ -1794,6 +1794,26 @@ define([ return $userAdmin; }; + common.getShareHashes = function (cb) { + common.getRecentPads(function (err, recent) { + var parsed = parsePadUrl(window.location.href); + if (!parsed.type || !parsed.hashData) { return void cb('E_INVALID_HREF'); } + var secret = common.getSecrets(parsed.type, parsed.hash); + var channel = common.base64ToHex(parsed.hashData.channel); + var hashes = common.getHashes(channel, secret); + var options = []; + + // If we have a stronger version in drive, add it and add a redirect button + var stronger = recent && common.findStronger(null, recent); + if (stronger) { + var parsed = parsePadUrl(stronger); + hashes.editHash = parsed.hash; + } + + cb(null, hashes); + }); + }; + var CRYPTPAD_VERSION = 'cryptpad-version'; var updateLocalVersion = function () { // Check for CryptPad updates diff --git a/www/common/metadata-manager.js b/www/common/metadata-manager.js index 0d4976305..55606e78b 100644 --- a/www/common/metadata-manager.js +++ b/www/common/metadata-manager.js @@ -126,7 +126,7 @@ define([], function () { var list = members.slice().filter(function (m) { return m.length === 32; }); return list.length - Object.keys(metadataObj.users).length; }, - getPrivatedata : function () { + getPrivateData : function () { return priv; }, getNetfluxId : function () { diff --git a/www/common/sframe-common-interface.js b/www/common/sframe-common-interface.js new file mode 100644 index 000000000..1bfa553ed --- /dev/null +++ b/www/common/sframe-common-interface.js @@ -0,0 +1,168 @@ +define([ + 'jquery', + '/common/cryptpad-common.js' +], function ($, Cryptpad) { + var UI = {}; + var Messages = Cryptpad.Messages; + + UI.createUserAdminMenu = function (config) { + var Common = config.Common; + var metadataMgr = config.metadataMgr; + + var displayNameCls = config.displayNameCls || 'displayName'; + var $displayedName = $('', {'class': displayNameCls}); + + var accountName = metadataMgr.getPrivateData().accountName; + var origin = metadataMgr.getPrivateData().origin; + var padType = metadataMgr.getMetadata().type; + + var $userName = $('', {'class': 'userDisplayName'}); + var options = []; + if (config.displayNameCls) { + var $userAdminContent = $('

'); + if (accountName) { + var $userAccount = $('', {'class': 'userAccount'}).append(Messages.user_accountName + ': ' + Cryptpad.fixHTML(accountName)); + $userAdminContent.append($userAccount); + $userAdminContent.append($('
')); + } + if (config.displayName) { + // Hide "Display name:" in read only mode + $userName.append(Messages.user_displayName + ': '); + $userName.append($displayedName); + } + $userAdminContent.append($userName); + options.push({ + tag: 'p', + attributes: {'class': 'accountData'}, + content: $userAdminContent.html() + }); + } + if (padType !== 'drive') { + options.push({ + tag: 'a', + attributes: { + 'target': '_blank', + 'href': origin+'/drive/' + }, + content: Messages.login_accessDrive + }); + } + // Add the change display name button if not in read only mode + if (config.changeNameButtonCls && config.displayChangeName) { + options.push({ + tag: 'a', + attributes: {'class': config.changeNameButtonCls}, + content: Messages.user_rename + }); + } + if (accountName) { + options.push({ + tag: 'a', + attributes: {'class': 'profile'}, + content: Messages.profileButton + }); + } + if (padType !== 'settings') { + options.push({ + tag: 'a', + attributes: {'class': 'settings'}, + content: Messages.settingsButton + }); + } + // Add login or logout button depending on the current status + if (accountName) { + options.push({ + tag: 'a', + attributes: {'class': 'logout'}, + content: Messages.logoutButton + }); + } else { + options.push({ + tag: 'a', + attributes: {'class': 'login'}, + content: Messages.login_login + }); + options.push({ + tag: 'a', + attributes: {'class': 'register'}, + content: Messages.login_register + }); + } + var $icon = $('', {'class': 'fa fa-user-secret'}); + //var $userbig = $('', {'class': 'big'}).append($displayedName.clone()); + var $userButton = $('

').append($icon);//.append($userbig); + if (accountName) { + $userButton = $('
').append(accountName); + } + /*if (account && config.displayNameCls) { + $userbig.append($('', {'class': 'account-name'}).text('(' + accountName + ')')); + } else if (account) { + // If no display name, do not display the parentheses + $userbig.append($('', {'class': 'account-name'}).text(accountName)); + }*/ + var dropdownConfigUser = { + text: $userButton.html(), // Button initial text + options: options, // Entries displayed in the menu + left: true, // Open to the left of the button + container: config.$initBlock, // optional + feedback: "USER_ADMIN", + }; + var $userAdmin = Cryptpad.createDropdown(dropdownConfigUser); + + var $displayName = $userAdmin.find('.'+displayNameCls); + + var $avatar = $userAdmin.find('.buttonTitle'); + var updateButton = function () { + var myData = metadataMgr.getMetadata().users[metadataMgr.getNetfluxId()]; + if (!myData) { return; } + var newName = myData.name; + var url = myData.avatar; + $displayName.text(newName || Messages.anonymous); + console.log(newName || Messages.anonymous); + if (accountName) { + $avatar.html(''); + Cryptpad.displayAvatar($avatar, url, newName, function ($img) { + if ($img) { + $userAdmin.find('button').addClass('avatar'); + } + }); + } + }; + metadataMgr.onChange(updateButton); + updateButton(); + + $userAdmin.find('a.logout').click(function () { + Common.logout(function () { + window.top.location = origin+'/'; + }); + }); + $userAdmin.find('a.settings').click(function () { + if (padType) { + window.open(origin+'/settings/'); + } else { + window.top.location = origin+'/settings/'; + } + }); + $userAdmin.find('a.profile').click(function () { + if (padType) { + window.open(origin+'/profile/'); + } else { + window.top.location = origin+'/profile/'; + } + }); + $userAdmin.find('a.login').click(function () { + Common.setLoginRedirect(function () { + window.top.location = origin+'/login/'; + }); + }); + $userAdmin.find('a.register').click(function () { + Common.setLoginRedirect(function () { + window.top.location = origin+'/register/'; + }); + }); + + return $userAdmin; + }; + + return UI; +}); diff --git a/www/common/sframe-common-title.js b/www/common/sframe-common-title.js index 066f0328c..fd632f296 100644 --- a/www/common/sframe-common-title.js +++ b/www/common/sframe-common-title.js @@ -35,7 +35,8 @@ define(['jquery'], function ($) { if (isDefaultTitle()) { return getHeadingText() || fallback || ""; } else { - return exp.title || getHeadingText() || exp.defaultTitle; + var title = metadataMgr.getMetadata().title; + return title || getHeadingText() || exp.defaultTitle; } }; diff --git a/www/common/sframe-common.js b/www/common/sframe-common.js index 88cea7fde..4407bff83 100644 --- a/www/common/sframe-common.js +++ b/www/common/sframe-common.js @@ -3,9 +3,10 @@ define([ '/common/sframe-chainpad-netflux-inner.js', '/common/sframe-channel.js', '/common/sframe-common-title.js', + '/common/sframe-common-interface.js', '/common/metadata-manager.js', -], function (nThen, CpNfInner, SFrameChannel, Title, MetadataMgr) { +], function (nThen, CpNfInner, SFrameChannel, Title, UI, MetadataMgr) { // Chainpad Netflux Inner var funcs = {}; @@ -31,6 +32,9 @@ define([ titleUpdated = cb; }; + // UI + funcs.createUserAdminMenu = UI.createUserAdminMenu; + // Title module funcs.createTitle = Title.create; @@ -39,12 +43,34 @@ define([ return ctx.cpNfInner.metadataMgr.getMetadata().defaultTitle; }; + + funcs.setDisplayName = function (name, cb) { ctx.sframeChan.query('Q_SETTINGS_SET_DISPLAY_NAME', name, function (err) { if (cb) { cb(err); } }); }; + funcs.logout = function (cb) { + ctx.sframeChan.query('Q_LOGOUT', null, function (err) { + if (cb) { cb(err); } + }); + }; + + funcs.setLoginRedirect = function (cb) { + ctx.sframeChan.query('Q_SET_LOGIN_REDIRECT', null, function (err) { + if (cb) { cb(err); } + }); + }; + +/* funcs.storeLinkToClipboard = function (readOnly, cb) { + ctx.sframeChan.query('Q_STORE_LINK_TO_CLIPBOARD', readOnly, function (err) { + if (cb) { cb(err); } + }); + }; +*/ + // TODO + funcs.feedback = function () {}; Object.freeze(funcs); diff --git a/www/common/sframe-protocol.js b/www/common/sframe-protocol.js index 0d980ed11..6bc2285ad 100644 --- a/www/common/sframe-protocol.js +++ b/www/common/sframe-protocol.js @@ -44,4 +44,14 @@ define({ // Update the user's display-name which will be shown to contacts and people in the same pads. 'Q_SETTINGS_SET_DISPLAY_NAME': true, -}); \ No newline at end of file + + // Log the user out in all the tabs + 'Q_LOGOUT': true, + + // When moving to the login or register page from a pad, we need to redirect to that pad at the + // end of the login process. This query set the current href to the sessionStorage. + 'Q_SET_LOGIN_REDIRECT': true, + + // Store the editing or readonly link of the current pad to the clipboard (share button) + 'Q_STORE_LINK_TO_CLIPBOARD': true, +}); diff --git a/www/common/toolbar3.js b/www/common/toolbar3.js index 6f2ca4871..d32bfab3a 100644 --- a/www/common/toolbar3.js +++ b/www/common/toolbar3.js @@ -153,24 +153,7 @@ define([ 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 @@ -276,8 +259,6 @@ define([ 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) { @@ -300,8 +281,7 @@ define([ // Create sub-elements var createUserList = function (toolbar, config) { - if (!config.metadataMgr) { /* || !config.userList.list || - !config.userList.data || !config.userList.userNetfluxId) {*/ + if (!config.metadataMgr) { throw new Error("You must provide a `metadataMgr` to display the userlist"); } var $content = $('
', {'class': 'userlist-drawer'}); @@ -381,107 +361,92 @@ define([ }; var createShare = function (toolbar, config) { - var secret = Cryptpad.find(config, ['share', 'secret']); - var channel = Cryptpad.find(config, ['share', 'channel']); - if (!secret || !channel) { - throw new Error("Unable to display the share button: share.secret and share.channel required"); + if (!config.metadataMgr) { + throw new Error("You must provide a `metadataMgr` to display the userlist"); } - Cryptpad.getRecentPads(function (err, recent) { - var $shareIcon = $('', {'class': 'fa fa-share-alt'}); - var hashes = Cryptpad.getHashes(channel, secret); - var options = []; - - // If we have a stronger version in drive, add it and add a redirect button - var stronger = recent && Cryptpad.findStronger(null, recent); - if (stronger) { - var parsed = Cryptpad.parsePadUrl(stronger); - hashes.editHash = parsed.hash; - } + var metadataMgr = config.metadataMgr; + var origin = config.metadataMgr.getPrivateData().origin; + var pathname = config.metadataMgr.getPrivateData().pathname; + var hashes = metadataMgr.getPrivateData().availableHashes; + var readOnly = metadataMgr.getPrivateData().readOnly; - if (hashes.editHash) { - options.push({ - tag: 'a', - attributes: {title: Messages.editShareTitle, 'class': 'editShare'}, - content: ' ' + Messages.editShare - }); - if (stronger) { - // We're in view mode, display the "open editing link" button - options.push({ - tag: 'a', - attributes: { - title: Messages.editOpenTitle, - 'class': 'editOpen', - href: window.location.pathname + '#' + hashes.editHash, - target: '_blank' - }, - content: ' ' + Messages.editOpen - }); - } - options.push({tag: 'hr'}); - } - if (hashes.viewHash) { + var $shareIcon = $('', {'class': 'fa fa-share-alt'}); + var options = []; + + if (hashes.editHash) { + options.push({ + tag: 'a', + attributes: {title: Messages.editShareTitle, 'class': 'editShare'}, + content: ' ' + Messages.editShare + }); + if (readOnly) { + // We're in view mode, display the "open editing link" button options.push({ tag: 'a', - attributes: {title: Messages.viewShareTitle, 'class': 'viewShare'}, - content: ' ' + Messages.viewShare + attributes: { + title: Messages.editOpenTitle, + 'class': 'editOpen', + href: origin + pathname + '#' + hashes.editHash, + target: '_blank' + }, + content: ' ' + Messages.editOpen }); - if (hashes.editHash && !stronger) { - // We're in edit mode, display the "open readonly" button - options.push({ - tag: 'a', - attributes: { - title: Messages.viewOpenTitle, - 'class': 'viewOpen', - href: window.location.pathname + '#' + hashes.viewHash, - target: '_blank' - }, - content: ' ' + Messages.viewOpen - }); - } } - if (hashes.fileHash) { + options.push({tag: 'hr'}); + } + if (hashes.viewHash) { + options.push({ + tag: 'a', + attributes: {title: Messages.viewShareTitle, 'class': 'viewShare'}, + content: ' ' + Messages.viewShare + }); + if (!readOnly) { + // We're in edit mode, display the "open readonly" button options.push({ tag: 'a', - attributes: {title: Messages.viewShareTitle, 'class': 'fileShare'}, - content: ' ' + Messages.viewShare - }); - } - var dropdownConfigShare = { - text: $('
').append($shareIcon).html(), - options: options, - feedback: 'SHARE_MENU', - }; - var $shareBlock = Cryptpad.createDropdown(dropdownConfigShare); - //$shareBlock.find('button').attr('id', 'shareButton'); - $shareBlock.find('.dropdown-bar-content').addClass(SHARE_CLS).addClass(EDITSHARE_CLS).addClass(VIEWSHARE_CLS); - $shareBlock.addClass('shareButton'); - $shareBlock.find('button').attr('title', Messages.shareButton); - - if (hashes.editHash) { - $shareBlock.find('a.editShare').click(function () { - var url = window.location.origin + window.location.pathname + '#' + hashes.editHash; - var success = Cryptpad.Clipboard.copy(url); - if (success) { Cryptpad.log(Messages.shareSuccess); } - }); - } - if (hashes.viewHash) { - $shareBlock.find('a.viewShare').click(function () { - var url = window.location.origin + window.location.pathname + '#' + hashes.viewHash ; - var success = Cryptpad.Clipboard.copy(url); - if (success) { Cryptpad.log(Messages.shareSuccess); } - }); - } - if (hashes.fileHash) { - $shareBlock.find('a.fileShare').click(function () { - var url = window.location.origin + window.location.pathname + '#' + hashes.fileHash ; - var success = Cryptpad.Clipboard.copy(url); - if (success) { Cryptpad.log(Messages.shareSuccess); } + attributes: { + title: Messages.viewOpenTitle, + 'class': 'viewOpen', + href: origin + pathname + '#' + hashes.viewHash, + target: '_blank' + }, + content: ' ' + Messages.viewOpen }); } + } + var dropdownConfigShare = { + text: $('
').append($shareIcon).html(), + options: options, + feedback: 'SHARE_MENU', + }; + var $shareBlock = Cryptpad.createDropdown(dropdownConfigShare); + $shareBlock.find('.dropdown-bar-content').addClass(SHARE_CLS).addClass(EDITSHARE_CLS).addClass(VIEWSHARE_CLS); + $shareBlock.addClass('shareButton'); + $shareBlock.find('button').attr('title', Messages.shareButton); + + if (hashes.editHash) { + $shareBlock.find('a.editShare').click(function () { + /*Common.storeLinkToClipboard(false, function (err) { + if (!err) { Cryptpad.log(Messages.shareSuccess); } + });*/ + var url = origin + pathname + '#' + hashes.editHash; + var success = Cryptpad.Clipboard.copy(url); + if (success) { Cryptpad.log(Messages.shareSuccess); } + }); + } + if (hashes.viewHash) { + $shareBlock.find('a.viewShare').click(function () { + /*Common.storeLinkToClipboard(true, function (err) { + if (!err) { Cryptpad.log(Messages.shareSuccess); } + });*/ + var url = origin + pathname + '#' + hashes.viewHash; + var success = Cryptpad.Clipboard.copy(url); + if (success) { Cryptpad.log(Messages.shareSuccess); } + }); + } - toolbar.$leftside.append($shareBlock); - toolbar.share = $shareBlock; - }); + toolbar.$leftside.append($shareBlock); + toolbar.share = $shareBlock; return "Loading share button"; }; @@ -738,12 +703,11 @@ define([ return $limit; }; - var createNewPad = function (toolbar) { - /*var $newPad = $('', { - 'class': NEWPAD_CLS + " dropdown-bar" - }).appendTo(toolbar.$top);*/ + var createNewPad = function (toolbar, config) { var $newPad = toolbar.$top.find('.'+NEWPAD_CLS).show(); + var origin = config.metadataMgr.getPrivateData().origin; + var pads_options = []; Config.availablePadTypes.forEach(function (p) { if (p === 'drive') { return; } @@ -753,7 +717,7 @@ define([ tag: 'a', attributes: { 'target': '_blank', - 'href': '/' + p + '/', + 'href': origin + '/' + p + '/', }, content: $('
').append(Cryptpad.getIcon(p)).html() + Messages.type[p] }); @@ -777,10 +741,11 @@ define([ throw new Error("You must provide a `metadataMgr` to display the user menu"); } var metadataMgr = config.metadataMgr; - var myData = metadataMgr.getMetadata().users[metadataMgr.getNetfluxId()]; var $userAdmin = toolbar.$userAdmin.find('.'+USERADMIN_CLS).show(); var userMenuCfg = { - $initBlock: $userAdmin + $initBlock: $userAdmin, + metadataMgr: metadataMgr, + Common: Common }; if (!config.hideDisplayName) { $.extend(true, userMenuCfg, { @@ -792,52 +757,39 @@ define([ userMenuCfg.displayName = 1; userMenuCfg.displayChangeName = 1; } - Cryptpad.createUserAdminMenu(userMenuCfg); + Common.createUserAdminMenu(userMenuCfg); $userAdmin.find('button').attr('title', Messages.userAccountButton); - // TODO iframe var $userButton = toolbar.$userNameButton = $userAdmin.find('a.' + USERBUTTON_CLS); $userButton.click(function (e) { e.preventDefault(); e.stopPropagation(); - var lastName = myData.displayName; - //Cryptpad.getLastName(function (err, lastName) { - //if (err) { return void console.error("Cannot get last name", err); } - Cryptpad.prompt(Messages.changeNamePrompt, lastName || '', function (newName) { - if (newName === null && typeof(lastName) === "string") { return; } - if (newName === null) { newName = ''; } - else { Common.feedback('NAME_CHANGED'); } - Common.setDisplayName(newName, function (err) { - if (err) { - console.log("Couldn't set username"); - console.error(err); - return; - } - //Cryptpad.changeDisplayName(newName, true); Already done? - }); + var myData = metadataMgr.getMetadata().users[metadataMgr.getNetfluxId()]; + var lastName = myData.name; + Cryptpad.prompt(Messages.changeNamePrompt, lastName || '', function (newName) { + if (newName === null && typeof(lastName) === "string") { return; } + if (newName === null) { newName = ''; } + else { Common.feedback('NAME_CHANGED'); } + Common.setDisplayName(newName, function (err) { + if (err) { + console.log("Couldn't set username"); + console.error(err); + return; + } + //Cryptpad.changeDisplayName(newName, true); Already done? }); - //}); - }); - Cryptpad.onDisplayNameChanged(function () { - window.setTimeout(function () { - Cryptpad.findCancelButton().click(); - if (config.metadataMgr) { - updateUserList(toolbar, config); - return; - } - updateDisplayName(toolbar, config); - }, 0); + }); }); - updateDisplayName(toolbar, config); - return $userAdmin; }; // Events var initClickEvents = function (toolbar, config) { var removeDropdowns = function () { - toolbar.$toolbar.find('.cryptpad-dropdown').hide(); + window.setTimeout(function () { + toolbar.$toolbar.find('.cryptpad-dropdown').hide(); + }); }; var cancelEditTitle = function (e) { // Now we want to apply the title even if we click somewhere else @@ -886,7 +838,7 @@ define([ Cryptpad.log(Messages._getKey("notifyJoined", [name])); break; case 0: - oldname = (oldname === "") ? Messages.anonymous : oldname; + oldname = (!oldname) ? Messages.anonymous : oldname; Cryptpad.log(Messages._getKey("notifyRenamed", [oldname, name])); break; case -1: @@ -988,14 +940,14 @@ define([ // Create the subelements var tb = {}; tb['userlist'] = createUserList; - tb['share'] = createShare; - tb['fileshare'] = createFileShare; + tb['share'] = createShare; //TODO + tb['fileshare'] = createFileShare;//TODO tb['title'] = createTitle; - tb['pageTitle'] = createPageTitle; + tb['pageTitle'] = createPageTitle;//TODO tb['lag'] = $.noop; tb['spinner'] = createSpinner; tb['state'] = $.noop; - tb['limit'] = createLimit; + tb['limit'] = createLimit; // TODO tb['upgrade'] = $.noop; tb['newpad'] = createNewPad; tb['useradmin'] = createUserAdmin; diff --git a/www/pad2/main.js b/www/pad2/main.js index 65cebc166..fe8fbf603 100644 --- a/www/pad2/main.js +++ b/www/pad2/main.js @@ -471,7 +471,7 @@ define([ var titleCfg = { getHeadingText: getHeadingText }; Title = common.createTitle(titleCfg, realtimeOptions.onLocal, common, cpNfInner.metadataMgr); var configTb = { - displayed: ['userlist', 'title', 'useradmin'], + displayed: ['userlist', 'title', 'useradmin', 'spinner', 'newpad', 'share'], title: Title.getTitleConfig(), metadataMgr: cpNfInner.metadataMgr, readOnly: readOnly, diff --git a/www/pad2/outer.js b/www/pad2/outer.js index a17813b66..e955df54c 100644 --- a/www/pad2/outer.js +++ b/www/pad2/outer.js @@ -21,6 +21,7 @@ define([ ], function (SFrameChannel, CpNfOuter, nThen, Cryptpad, Crypto) { console.log('xxx'); var sframeChan; + var hashes; nThen(function (waitFor) { $(waitFor()); }).nThen(function (waitFor) { @@ -29,6 +30,8 @@ define([ console.log('sframe initialized'); })); Cryptpad.ready(waitFor()); + }).nThen(function (waitFor) { + Cryptpad.getShareHashes(waitFor(function (err, h) { hashes = h; })); }).nThen(function (waitFor) { var secret = Cryptpad.getSecrets(); var readOnly = secret.keys && !secret.keys.editKeyStr; @@ -61,7 +64,11 @@ define([ netfluxId: Cryptpad.getNetwork().webChannels[0].myID, }, priv: { - accountName: Cryptpad.getAccountName() + accountName: Cryptpad.getAccountName(), + origin: window.location.origin, + pathname: window.location.pathname, + readOnly: readOnly, + availableHashes: hashes } }); }); @@ -96,6 +103,15 @@ define([ }); }); + sframeChan.on('Q_LOGOUT', function (data, cb) { + Cryptpad.logout(cb); + }); + + sframeChan.on('Q_SET_LOGIN_REDIRECT', function (data, cb) { + sessionStorage.redirectTo = window.location.href; + cb(); + }); + CpNfOuter.start({ sframeChan: sframeChan, channel: secret.channel,