', {'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 oldUrl;
+ var updateButton = function () {
+ var myData = metadataMgr.getUserData();
+ if (!myData) { return; }
+ var newName = myData.name;
+ var url = myData.avatar;
+ $displayName.text(newName || Messages.anonymous);
+ if (accountName && oldUrl !== url) {
+ $avatar.html('');
+ UI.displayAvatar(Common, $avatar, url, newName, function ($img) {
+ oldUrl = url;
+ if ($img) {
+ $userAdmin.find('button').addClass('avatar');
+ }
+ });
+ }
+ };
+ metadataMgr.onChange(updateButton);
+ updateButton();
+
+ $userAdmin.find('a.logout').click(function () {
+ Common.logout(function () {
+ window.parent.location = origin+'/';
+ });
+ });
+ $userAdmin.find('a.settings').click(function () {
+ if (padType) {
+ window.open(origin+'/settings/');
+ } else {
+ window.parent.location = origin+'/settings/';
+ }
+ });
+ $userAdmin.find('a.profile').click(function () {
+ if (padType) {
+ window.open(origin+'/profile/');
+ } else {
+ window.parent.location = origin+'/profile/';
+ }
+ });
+ $userAdmin.find('a.login').click(function () {
+ Common.setLoginRedirect(function () {
+ window.parent.location = origin+'/login/';
+ });
+ });
+ $userAdmin.find('a.register').click(function () {
+ Common.setLoginRedirect(function () {
+ window.parent.location = origin+'/register/';
+ });
+ });
+
+ return $userAdmin;
+ };
+
+ return UI;
+});
diff --git a/www/common/sframe-common-title.js b/www/common/sframe-common-title.js
new file mode 100644
index 000000000..7e44d14fd
--- /dev/null
+++ b/www/common/sframe-common-title.js
@@ -0,0 +1,84 @@
+define(['jquery'], function ($) {
+ var module = {};
+
+ module.create = function (cfg, onLocal, Common, metadataMgr) {
+ var exp = {};
+
+ exp.defaultTitle = Common.getDefaultTitle();
+
+ exp.title = document.title;
+
+ cfg = cfg || {};
+
+ var getHeadingText = cfg.getHeadingText || function () { return; };
+
+/* var updateLocalTitle = function (newTitle) {
+ console.error(newTitle);
+ exp.title = newTitle;
+ onLocal();
+ if (typeof cfg.updateLocalTitle === "function") {
+ cfg.updateLocalTitle(newTitle);
+ } else {
+ document.title = newTitle;
+ }
+ };*/
+
+ var $title;
+ exp.setToolbar = function (toolbar) {
+ $title = toolbar && toolbar.title;
+ };
+
+ exp.getTitle = function () { return exp.title; };
+ var isDefaultTitle = exp.isDefaultTitle = function (){return exp.title === exp.defaultTitle;};
+
+ var suggestTitle = exp.suggestTitle = function (fallback) {
+ if (isDefaultTitle()) {
+ return getHeadingText() || fallback || "";
+ } else {
+ var title = metadataMgr.getMetadata().title;
+ return title || getHeadingText() || exp.defaultTitle;
+ }
+ };
+
+ /*var renameCb = function (err, newTitle) {
+ if (err) { return; }
+ onLocal();
+ //updateLocalTitle(newTitle);
+ };*/
+
+ // update title: href is optional; if not specified, we use window.location.href
+ exp.updateTitle = function (newTitle, cb) {
+ cb = cb || $.noop;
+ if (newTitle === exp.title) { return; }
+ Common.updateTitle(newTitle, cb);
+ };
+
+ // TODO not needed?
+ /*exp.updateDefaultTitle = function (newDefaultTitle) {
+ exp.defaultTitle = newDefaultTitle;
+ if (!$title) { return; }
+ $title.find('input').attr("placeholder", exp.defaultTitle);
+ };*/
+
+ metadataMgr.onChange(function () {
+ var md = metadataMgr.getMetadata();
+ $title.find('span.title').text(md.title || md.defaultTitle);
+ $title.find('input').val(md.title || md.defaultTitle);
+ exp.title = md.title;
+ //exp.updateTitle(md.title || md.defaultTitle);
+ });
+
+ exp.getTitleConfig = function () {
+ return {
+ updateTitle: exp.updateTitle,
+ suggestName: suggestTitle,
+ defaultName: exp.defaultTitle
+ };
+ };
+
+ return exp;
+ };
+
+ return module;
+});
+
diff --git a/www/common/sframe-common.js b/www/common/sframe-common.js
new file mode 100644
index 000000000..bf42642a2
--- /dev/null
+++ b/www/common/sframe-common.js
@@ -0,0 +1,328 @@
+define([
+ 'jquery',
+ '/bower_components/nthen/index.js',
+ '/customize/messages.js',
+ '/common/sframe-chainpad-netflux-inner.js',
+ '/common/sframe-channel.js',
+ '/common/sframe-common-title.js',
+ '/common/sframe-common-interface.js',
+ '/common/sframe-common-history.js',
+ '/common/metadata-manager.js',
+
+ '/customize/application_config.js',
+ '/common/cryptpad-common.js',
+ '/common/common-realtime.js'
+], function ($, nThen, Messages, CpNfInner, SFrameChannel, Title, UI, History, MetadataMgr,
+ AppConfig, Cryptpad, CommonRealtime) {
+
+ // Chainpad Netflux Inner
+ var funcs = {};
+ var ctx = {};
+
+ funcs.Messages = Messages;
+
+ funcs.startRealtime = function (options) {
+ if (ctx.cpNfInner) { return ctx.cpNfInner; }
+ options.sframeChan = ctx.sframeChan;
+ options.metadataMgr = ctx.metadataMgr;
+ ctx.cpNfInner = CpNfInner.start(options);
+ ctx.cpNfInner.metadataMgr.onChangeLazy(options.onLocal);
+ return ctx.cpNfInner;
+ };
+
+ funcs.getMetadataMgr = function () {
+ return ctx.metadataMgr;
+ };
+ funcs.getCryptpadCommon = function () {
+ return Cryptpad;
+ };
+
+ var isLoggedIn = funcs.isLoggedIn = function () {
+ if (!ctx.cpNfInner) { throw new Error("cpNfInner is not ready!"); }
+ return ctx.cpNfInner.metadataMgr.getPrivateData().accountName;
+ };
+
+ var titleUpdated;
+ funcs.updateTitle = function (title, cb) {
+ ctx.metadataMgr.updateTitle(title);
+ titleUpdated = cb;
+ };
+
+ // UI
+ funcs.createUserAdminMenu = UI.createUserAdminMenu;
+ funcs.displayAvatar = UI.displayAvatar;
+
+ // History
+ funcs.getHistory = function (config) { return History.create(funcs, config); };
+
+ // Title module
+ funcs.createTitle = Title.create;
+
+ funcs.getDefaultTitle = function () {
+ if (!ctx.cpNfInner) { throw new Error("cpNfInner is not ready!"); }
+ 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.notify = function () {
+ ctx.sframeChan.event('EV_NOTIFY');
+ };
+
+ funcs.setLoginRedirect = function (cb) {
+ ctx.sframeChan.query('Q_SET_LOGIN_REDIRECT', null, function (err) {
+ if (cb) { cb(err); }
+ });
+ };
+
+ funcs.sendAnonRpcMsg = function (msg, content, cb) {
+ ctx.sframeChan.query('Q_ANON_RPC_MESSAGE', {
+ msg: msg,
+ content: content
+ }, function (err, data) {
+ if (cb) { cb(data); }
+ });
+ };
+
+ funcs.isOverPinLimit = function (cb) {
+ ctx.sframeChan.query('Q_GET_PIN_LIMIT_STATUS', null, function (err, data) {
+ cb(data.error, data.overLimit, data.limits);
+ });
+ };
+
+ funcs.getFullHistory = function (realtime, cb) {
+ ctx.sframeChan.on('EV_RT_HIST_MESSAGE', function (content) {
+ realtime.message(content);
+ });
+ ctx.sframeChan.query('Q_GET_FULL_HISTORY', null, cb);
+ };
+
+ // Friends
+ var pendingFriends = [];
+ funcs.getPendingFriends = function () {
+ return pendingFriends.slice();
+ };
+ funcs.sendFriendRequest = function (netfluxId) {
+ ctx.sframeChan.query('Q_SEND_FRIEND_REQUEST', netfluxId, $.noop);
+ pendingFriends.push(netfluxId);
+ };
+
+ // Feedback
+ funcs.feedback = function (action, force) {
+ if (force !== true) {
+ if (!action) { return; }
+ try {
+ if (!ctx.metadataMgr.getPrivateData().feedbackAllowed) { return; }
+ } catch (e) { return void console.error(e); }
+ }
+ var randomToken = Math.random().toString(16).replace(/0./, '');
+ //var origin = ctx.metadataMgr.getPrivateData().origin;
+ var href = /*origin +*/ '/common/feedback.html?' + action + '=' + randomToken;
+ $.ajax({
+ type: "HEAD",
+ url: href,
+ });
+ };
+ var prepareFeedback = function (key) {
+ if (typeof(key) !== 'string') { return $.noop; }
+
+ var type = ctx.metadataMgr.getMetadata().type;
+ return function () {
+ funcs.feedback((key + (type? '_' + type: '')).toUpperCase());
+ };
+ };
+
+ // BUTTONS
+ var isStrongestStored = function () {
+ var data = ctx.metadataMgr.getPrivateData();
+ return !data.readOnly || !data.availableHashes.editHash;
+ };
+ funcs.createButton = function (type, rightside, data, callback) {
+ var button;
+ var size = "17px";
+ switch (type) {
+ case 'export':
+ button = $('