Migrate settings to use a sandboxed iframe
parent
c1ba08cfc6
commit
101482b8cc
@ -0,0 +1,81 @@
|
||||
define([
|
||||
'jquery',
|
||||
'/customize/messages.js'
|
||||
], function($, Messages) {
|
||||
var LS_LANG = "CRYPTPAD_LANG";
|
||||
|
||||
var Msg = {};
|
||||
|
||||
Msg.getLanguage = Messages._getLanguage;
|
||||
|
||||
// Add handler to the language selector
|
||||
Msg.setLanguage = function (l, sframeChan, cb) {
|
||||
console.log(sframeChan);
|
||||
if (sframeChan) {
|
||||
// We're in the sandbox
|
||||
sframeChan.query("Q_LANGUAGE_SET", l, cb);
|
||||
return;
|
||||
}
|
||||
localStorage.setItem(LS_LANG, l);
|
||||
cb();
|
||||
};
|
||||
|
||||
Msg.initSelector = function ($select, sfcommon) {
|
||||
var selector = $select || $('#cp-language-selector');
|
||||
|
||||
if (!selector.length) { return; }
|
||||
|
||||
var language = Messages._getLanguage();
|
||||
|
||||
// Select the current language in the list
|
||||
selector.setValue(language || 'en');
|
||||
|
||||
// Listen for language change
|
||||
$(selector).find('a.cp-language-value').on('click', function () {
|
||||
var newLanguage = $(this).attr('data-value');
|
||||
Msg.setLanguage(newLanguage, sfcommon && sfcommon.getSframeChannel(), function () {
|
||||
if (newLanguage !== language) {
|
||||
if (sfcommon) {
|
||||
sfcommon.gotoURL();
|
||||
return;
|
||||
}
|
||||
window.location.reload();
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
Msg.applyTranslation = function () {
|
||||
var translateText = function (i, e) {
|
||||
var $el = $(e);
|
||||
var key = $el.data('localization');
|
||||
$el.html(Messages[key]);
|
||||
};
|
||||
var translateAppend = function (i, e) {
|
||||
var $el = $(e);
|
||||
var key = $el.data('localization-append');
|
||||
$el.append(Messages[key]);
|
||||
};
|
||||
var translateTitle = function () {
|
||||
var $el = $(this);
|
||||
var key = $el.data('localization-title');
|
||||
$el.attr('title', Messages[key]);
|
||||
};
|
||||
var translatePlaceholder = function () {
|
||||
var $el = $(this);
|
||||
var key = $el.data('localization-placeholder');
|
||||
$el.attr('placeholder', Messages[key]);
|
||||
};
|
||||
$('[data-localization]').each(translateText);
|
||||
$('[data-localization-append]').each(translateAppend);
|
||||
$('[data-localization-title]').each(translateTitle);
|
||||
$('[data-localization-placeholder]').each(translatePlaceholder);
|
||||
$('#pad-iframe').contents().find('[data-localization]').each(translateText);
|
||||
$('#pad-iframe').contents().find('[data-localization-append]').each(translateAppend);
|
||||
$('#pad-iframe').contents().find('[data-localization-title]').each(translateTitle);
|
||||
$('#pad-iframe').contents().find('[data-localization-placeholder]').each(translatePlaceholder);
|
||||
};
|
||||
|
||||
return Msg;
|
||||
|
||||
});
|
@ -1,5 +1,5 @@
|
||||
define([
|
||||
'/customize/messages.js',
|
||||
], function (Messages) {
|
||||
Messages._applyTranslation();
|
||||
'/common/common-language.js',
|
||||
], function (Language) {
|
||||
Language.applyTranslation();
|
||||
});
|
||||
|
@ -0,0 +1,16 @@
|
||||
<!DOCTYPE html>
|
||||
<html class="cp">
|
||||
<!-- If this file is not called customize.dist/src/template.html, it is generated -->
|
||||
<head>
|
||||
<title data-localization="main_title">CryptPad: Zero Knowledge, Collaborative Real Time Editing</title>
|
||||
<meta content="text/html; charset=utf-8" http-equiv="content-type"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
|
||||
<link rel="icon" type="image/png" href="/customize/main-favicon.png" id="favicon"/>
|
||||
<script async data-bootload="/customize/template.js" data-main="/common/boot.js?ver=1.0" src="/bower_components/requirejs/require.js?ver=2.3.5"></script>
|
||||
</head>
|
||||
<body class="html">
|
||||
<noscript>
|
||||
<p><strong>OOPS</strong> In order to do encryption in your browser, Javascript is really <strong>really</strong> required.</p>
|
||||
<p><strong>OUPS</strong> Afin de pouvoir réaliser le chiffrement dans votre navigateur, Javascript est <strong>vraiment</strong> nécessaire.</p>
|
||||
</noscript>
|
||||
</html>
|
@ -0,0 +1,67 @@
|
||||
@import (once) "../../customize/src/less2/include/colortheme.less";
|
||||
@import (once) "../../customize/src/less2/include/browser.less";
|
||||
@import (once) "../../customize/src/less2/include/toolbar.less";
|
||||
@import (once) "../../customize/src/less2/include/markdown.less";
|
||||
@import (once) '../../customize/src/less2/include/alertify.less';
|
||||
@import (once) '../../customize/src/less2/include/sidebar-layout.less';
|
||||
@import (once) "../../customize/src/less2/include/limit-bar.less";
|
||||
|
||||
.toolbar_main();
|
||||
.alertify_main();
|
||||
.sidebar-layout_main();
|
||||
.limit-bar_main();
|
||||
|
||||
// body
|
||||
&.cp-app-settings {
|
||||
display: flex;
|
||||
flex-flow: column;
|
||||
#cp-sidebarlayout-container {
|
||||
#cp-sidebarlayout-rightside {
|
||||
.cp-settings-userfeedback, .cp-settings-thumbnails {
|
||||
input[type="checkbox"] {
|
||||
vertical-align: middle;
|
||||
margin-right: 5px;
|
||||
}
|
||||
}
|
||||
.cp-settings-language-selector {
|
||||
button.btn {
|
||||
width: @sidebar_button-width;
|
||||
background-color: @colortheme_sidebar-button-alt-bg;
|
||||
border-color: #adadad;
|
||||
color: black;
|
||||
&:hover {
|
||||
background-color: darken(@colortheme_sidebar-button-alt-bg, 15%);
|
||||
}
|
||||
}
|
||||
}
|
||||
.cp-sidebarlayout-input-block {
|
||||
input {
|
||||
border-top-right-radius: 0;
|
||||
border-bottom-right-radius: 0;
|
||||
padding: 5px;
|
||||
padding-left: 15px;
|
||||
&[type="number"] {
|
||||
border-right: 1px solid #adadad;
|
||||
}
|
||||
&[type="checkbox"] {
|
||||
margin-right: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
.cp-settings-info-block {
|
||||
[type="text"] {
|
||||
width: @sidebar_button-width;
|
||||
}
|
||||
}
|
||||
.cp-settings-backup-drive {
|
||||
button {
|
||||
span.fa {
|
||||
margin-right: 5px;
|
||||
}
|
||||
margin-right: 5px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,16 +1,38 @@
|
||||
<!DOCTYPE html>
|
||||
<html class="cp">
|
||||
<!-- If this file is not called customize.dist/src/template.html, it is generated -->
|
||||
<html>
|
||||
<head>
|
||||
<title data-localization="main_title">CryptPad: Zero Knowledge, Collaborative Real Time Editing</title>
|
||||
<title>CryptPad</title>
|
||||
<meta content="text/html; charset=utf-8" http-equiv="content-type"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
|
||||
<link rel="icon" type="image/png" href="/customize/main-favicon.png" id="favicon"/>
|
||||
<script async data-bootload="/customize/template.js" data-main="/common/boot.js?ver=1.0" src="/bower_components/requirejs/require.js?ver=2.3.5"></script>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="referrer" content="no-referrer" />
|
||||
<script async data-bootload="main.js" data-main="/common/boot.js?ver=1.0" src="/bower_components/requirejs/require.js?ver=2.3.5"></script>
|
||||
<style>
|
||||
html, body {
|
||||
margin: 0px;
|
||||
padding: 0px;
|
||||
}
|
||||
#sbox-iframe {
|
||||
position:fixed;
|
||||
top:0px;
|
||||
left:0px;
|
||||
bottom:0px;
|
||||
right:0px;
|
||||
width:100%;
|
||||
height:100%;
|
||||
border:none;
|
||||
margin:0;
|
||||
padding:0;
|
||||
overflow:hidden;
|
||||
}
|
||||
#sbox-filePicker-iframe {
|
||||
position: fixed;
|
||||
top:0; left:0;
|
||||
bottom:0; right:0;
|
||||
width:100%;
|
||||
height: 100%;
|
||||
border: 0;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body class="html">
|
||||
<noscript>
|
||||
<p><strong>OOPS</strong> In order to do encryption in your browser, Javascript is really <strong>really</strong> required.</p>
|
||||
<p><strong>OUPS</strong> Afin de pouvoir réaliser le chiffrement dans votre navigateur, Javascript est <strong>vraiment</strong> nécessaire.</p>
|
||||
</noscript>
|
||||
</html>
|
||||
<body>
|
||||
<iframe id="sbox-iframe">
|
||||
|
@ -0,0 +1,18 @@
|
||||
<!DOCTYPE html>
|
||||
<html class="cp-app-noscroll">
|
||||
<head>
|
||||
<meta content="text/html; charset=utf-8" http-equiv="content-type"/>
|
||||
<script async data-bootload="/settings/inner.js" data-main="/common/sframe-boot.js?ver=1.4" src="/bower_components/requirejs/require.js?ver=2.3.5"></script>
|
||||
<style>
|
||||
.loading-hidden { display: none; }
|
||||
</style>
|
||||
</head>
|
||||
<body class="cp-app-settings">
|
||||
<div id="cp-toolbar" class="cp-toolbar-container"></div>
|
||||
<div id="cp-sidebarlayout-container"></div>
|
||||
<noscript>
|
||||
<p><strong>OOPS</strong> In order to do encryption in your browser, Javascript is really <strong>really</strong> required.</p>
|
||||
<p><strong>OUPS</strong> Afin de pouvoir réaliser le chiffrement dans votre navigateur, Javascript est <strong>vraiment</strong> nécessaire.</p>
|
||||
</noscript>
|
||||
</body>
|
||||
</html>
|
@ -0,0 +1,551 @@
|
||||
define([
|
||||
'jquery',
|
||||
'/common/toolbar3.js',
|
||||
'/common/cryptpad-common.js',
|
||||
'/bower_components/nthen/index.js',
|
||||
'/common/sframe-common.js',
|
||||
'/customize/pages.js',
|
||||
|
||||
'css!/bower_components/bootstrap/dist/css/bootstrap.min.css',
|
||||
'less!/bower_components/components-font-awesome/css/font-awesome.min.css',
|
||||
'less!/customize/src/less2/main.less',
|
||||
], function (
|
||||
$,
|
||||
Toolbar,
|
||||
Cryptpad,
|
||||
nThen,
|
||||
SFCommon,
|
||||
Pages
|
||||
)
|
||||
{
|
||||
var Messages = Cryptpad.Messages;
|
||||
var APP = window.APP = {
|
||||
Cryptpad: Cryptpad,
|
||||
};
|
||||
var onConnectError = function () {
|
||||
Cryptpad.errorLoadingScreen(Messages.websocketError);
|
||||
};
|
||||
|
||||
var common;
|
||||
var metadataMgr;
|
||||
var privateData;
|
||||
var sframeChan;
|
||||
|
||||
var categories = {
|
||||
'account': [
|
||||
'cp-settings-info-block',
|
||||
'cp-settings-displayname',
|
||||
'cp-settings-language-selector',
|
||||
'cp-settings-logout-everywhere',
|
||||
'cp-settings-resettips',
|
||||
'cp-settings-thumbnails',
|
||||
'cp-settings-userfeedback'
|
||||
],
|
||||
'drive': [
|
||||
'cp-settings-backup-drive',
|
||||
'cp-settings-import-local-pads',
|
||||
'cp-settings-reset-drive'
|
||||
],
|
||||
'code': [
|
||||
'cp-settings-indent-unit',
|
||||
'cp-settings-indent-type'
|
||||
]
|
||||
};
|
||||
|
||||
var createInfoBlock = function () {
|
||||
var $div = $('<div>', {'class': 'cp-settings-info-block'});
|
||||
|
||||
var $account = $('<div>', {'class': 'cp-sidebarlayout-element'}).appendTo($div);
|
||||
var accountName = privateData.accountName;
|
||||
var $label = $('<span>', {'class': 'label'}).text(Messages.user_accountName);
|
||||
var $name = $('<span>').text(accountName || '');
|
||||
if (!accountName) {
|
||||
$label.text('');
|
||||
$name.text(Messages.settings_anonymous);
|
||||
}
|
||||
$account.append($label).append($name);
|
||||
|
||||
var publicKey = privateData.edPublic;
|
||||
if (publicKey) {
|
||||
var $key = $('<div>', {'class': 'cp-sidebarlayout-element'}).appendTo($div);
|
||||
var userHref = Cryptpad.getUserHrefFromKeys(accountName, publicKey);
|
||||
var $pubLabel = $('<span>', {'class': 'label'})
|
||||
.text(Messages.settings_publicSigningKey);
|
||||
$key.append($pubLabel).append(Cryptpad.dialog.selectable(userHref));
|
||||
}
|
||||
|
||||
return $div;
|
||||
};
|
||||
|
||||
// Create the block containing the display name field
|
||||
var createDisplayNameInput = function () {
|
||||
var $div = $('<div>', {'class': 'cp-settings-displayname cp-sidebarlayout-element'});
|
||||
$('<label>', {'for' : 'cp-settings-displayname'}).text(Messages.user_displayName).appendTo($div);
|
||||
var $inputBlock = $('<div>', {'class': 'cp-sidebarlayout-input-block'}).appendTo($div);
|
||||
var $input = $('<input>', {
|
||||
'type': 'text',
|
||||
'id': 'cp-settings-displayname',
|
||||
'placeholder': Messages.anonymous}).appendTo($inputBlock);
|
||||
var $save = $('<button>', {'class': 'btn btn-primary'}).text(Messages.settings_save).appendTo($inputBlock);
|
||||
var $ok = $('<span>', {'class': 'fa fa-check', title: Messages.saved}).hide().appendTo($div);
|
||||
var $spinner = $('<span>', {'class': 'fa fa-spinner fa-pulse'}).hide().appendTo($div);
|
||||
|
||||
var displayName = metadataMgr.getUserData().name || '';
|
||||
$input.val(displayName);
|
||||
|
||||
// When the display name is changed (enter or button clicked)
|
||||
var todo = function () {
|
||||
displayName = $input.val();
|
||||
if (displayName === metadataMgr.getUserData().name) { return; }
|
||||
$spinner.show();
|
||||
common.setDisplayName(displayName, function () {
|
||||
$spinner.hide();
|
||||
$ok.show();
|
||||
});
|
||||
};
|
||||
$input.on('keyup', function (e) {
|
||||
if ($input.val() !== displayName) { $ok.hide(); }
|
||||
if (e.which === 13) { todo(); }
|
||||
});
|
||||
$save.click(todo);
|
||||
|
||||
// On remote change
|
||||
var onChange = function () {
|
||||
if (metadataMgr.getUserData().name !== $input.val()) {
|
||||
$input.val(metadataMgr.getUserData().name);
|
||||
$input.focusout();
|
||||
}
|
||||
};
|
||||
metadataMgr.onChange(onChange);
|
||||
|
||||
return $div;
|
||||
};
|
||||
var createIndentUnitSelector = function () {
|
||||
var $div = $('<div>', {
|
||||
'class': 'cp-settings-indent-unit cp-sidebarlayout-element'
|
||||
});
|
||||
$('<label>').text(Messages.settings_codeIndentation).appendTo($div);
|
||||
|
||||
var $inputBlock = $('<div>', {
|
||||
'class': 'cp-sidebarlayout-input-block',
|
||||
}).appendTo($div);
|
||||
|
||||
var $input = $('<input>', {
|
||||
'min': 1,
|
||||
'max': 8,
|
||||
type: 'number',
|
||||
}).on('change', function () {
|
||||
var val = parseInt($input.val());
|
||||
if (typeof(val) !== 'number') { return; }
|
||||
common.setAttribute(['codemirror', 'indentUnit'], val);
|
||||
}).appendTo($inputBlock);
|
||||
|
||||
common.getAttribute(['codemirror', 'indentUnit'], function (e, val) {
|
||||
if (e) { return void console.error(e); }
|
||||
if (typeof(val) !== 'number') {
|
||||
$input.val(2);
|
||||
} else {
|
||||
$input.val(val);
|
||||
}
|
||||
});
|
||||
return $div;
|
||||
};
|
||||
|
||||
var createIndentTypeSelector = function (obj) {
|
||||
var key = 'indentWithTabs';
|
||||
|
||||
var $div = $('<div>', {
|
||||
'class': 'cp-settings-indent-type cp-sidebarlayout-element'
|
||||
});
|
||||
$('<label>').text(Messages.settings_codeUseTabs).appendTo($div);
|
||||
|
||||
var $inputBlock = $('<div>', {
|
||||
'class': 'cp-sidebarlayout-input-block',
|
||||
}).css('flex-flow', 'column')
|
||||
.appendTo($div);
|
||||
|
||||
var $input = $('<input>', {
|
||||
type: 'checkbox',
|
||||
}).on('change', function () {
|
||||
var val = $input.is(':checked');
|
||||
if (typeof(val) !== 'boolean') { return; }
|
||||
common.setAttribute(['codemirror', key], val);
|
||||
}).appendTo($inputBlock);
|
||||
|
||||
/*proxy.on('change', ['settings', 'codemirror', key], function (o, n) {
|
||||
$input[0].checked = !!n;
|
||||
});*/
|
||||
|
||||
common.getAttribute(['codemirror', key], function (e, val) {
|
||||
if (e) { return void console.error(e); }
|
||||
$input[0].checked = !!val;
|
||||
});
|
||||
return $div;
|
||||
};
|
||||
|
||||
var createResetTips = function () {
|
||||
var $div = $('<div>', {'class': 'cp-settings-resettips cp-sidebarlayout-element'});
|
||||
$('<label>').text(Messages.settings_resetTips).appendTo($div);
|
||||
$('<span>', {'class': 'cp-sidebarlayout-description'})
|
||||
.text(Messages.settings_resetTipsButton).appendTo($div);
|
||||
var $button = $('<button>', {'id': 'cp-settings-resettips', 'class': 'btn btn-primary'})
|
||||
.text(Messages.settings_resetTipsAction).appendTo($div);
|
||||
|
||||
var localStore = window.cryptpadStore;
|
||||
$button.click(function () {
|
||||
Object.keys(localStore).forEach(function (k) {
|
||||
if(k.slice(0, 9) === "hide-info") {
|
||||
localStore.put(k, undefined);
|
||||
}
|
||||
});
|
||||
Cryptpad.alert(Messages.settings_resetTipsDone);
|
||||
});
|
||||
|
||||
return $div;
|
||||
};
|
||||
|
||||
var createThumbnails = function () {
|
||||
var $div = $('<div>', {'class': 'cp-settings-thumbnails cp-sidebarlayout-element'});
|
||||
$('<label>').text(Messages.settings_thumbnails).appendTo($div);
|
||||
|
||||
// Disable
|
||||
$('<span>', {'class': 'cp-sidebarlayout-description'})
|
||||
.text(Messages.settings_disableThumbnailsDescription).appendTo($div);
|
||||
var $label = $('<label>', { 'for': 'disableThumbnails', 'class': 'noTitle' })
|
||||
.text(Messages.settings_disableThumbnailsAction);
|
||||
|
||||
var $ok = $('<span>', {'class': 'fa fa-check', title: Messages.saved});
|
||||
var $spinner = $('<span>', {'class': 'fa fa-spinner fa-pulse'});
|
||||
|
||||
var $checkbox = $('<input>', {
|
||||
'type': 'checkbox',
|
||||
id: 'disableThumbnails'
|
||||
}).on('change', function () {
|
||||
$spinner.show();
|
||||
$ok.hide();
|
||||
var val = $checkbox.is(':checked') || false;
|
||||
common.setAttribute(['general', 'disableThumbnails'], val, function () {
|
||||
$spinner.hide();
|
||||
$ok.show();
|
||||
});
|
||||
});
|
||||
|
||||
$checkbox.appendTo($div);
|
||||
$label.appendTo($div);
|
||||
|
||||
$ok.hide().appendTo($div);
|
||||
$spinner.hide().appendTo($div);
|
||||
|
||||
common.getAttribute(['general', 'disableThumbnails'], function (e, val) {
|
||||
$checkbox[0].checked = val;
|
||||
});
|
||||
|
||||
// Reset
|
||||
$('<span>', {'class': 'cp-sidebarlayout-description'})
|
||||
.text(Messages.settings_resetThumbnailsDescription).appendTo($div);
|
||||
var $button = $('<button>', {'id': 'resetThumbnails', 'class': 'btn btn-primary'})
|
||||
.text(Messages.settings_resetThumbnailsAction).appendTo($div);
|
||||
|
||||
$button.click(function () {
|
||||
sframeChan.query("Q_THUMBNAIL_CLEAR", null, function (err) {
|
||||
if (err) { return void console.error("Cannot clear localForage"); }
|
||||
Cryptpad.alert(Messages.settings_resetThumbnailsDone);
|
||||
});
|
||||
});
|
||||
|
||||
return $div;
|
||||
};
|
||||
|
||||
var createBackupDrive = function () {
|
||||
var $div = $('<div>', {'class': 'cp-settings-backup-drive cp-sidebarlayout-element'});
|
||||
|
||||
var accountName = privateData.accountName;
|
||||
var displayName = metadataMgr.getUserData().name || '';
|
||||
|
||||
var exportFile = function () {
|
||||
sframeChan.query("Q_SETTINGS_DRIVE_GET", null, function (err, data) {
|
||||
if (err) { return void console.error(err); }
|
||||
var sjson = JSON.stringify(data);
|
||||
var name = displayName || accountName || Messages.anonymous;
|
||||
var suggestion = name + '-' + new Date().toDateString();
|
||||
Cryptpad.prompt(Cryptpad.Messages.exportPrompt,
|
||||
Cryptpad.fixFileName(suggestion) + '.json', function (filename) {
|
||||
if (!(typeof(filename) === 'string' && filename)) { return; }
|
||||
var blob = new Blob([sjson], {type: "application/json;charset=utf-8"});
|
||||
saveAs(blob, filename);
|
||||
});
|
||||
});
|
||||
};
|
||||
var importFile = function (content) {
|
||||
var $spinner = $('<span>', {'class': 'fa fa-spinner fa-pulse'}).appendTo($div);
|
||||
try {
|
||||
var data = JSON.parse(content);
|
||||
sframeChan.query("Q_SETTINGS_DRIVE_SET", data, function (e) {
|
||||
if (e) { console.error(e); }
|
||||
$spinner.remove();
|
||||
});
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
};
|
||||
|
||||
$('<label>', {'for' : 'exportDrive'}).text(Messages.settings_backupCategory).appendTo($div);
|
||||
$('<span>', {'class': 'cp-sidebarlayout-description'})
|
||||
.text(Messages.settings_backupTitle).appendTo($div);
|
||||
/* add an export button */
|
||||
var $export = common.createButton('export', true, {}, exportFile);
|
||||
$export.attr('class', 'btn btn-success').text(Messages.settings_backup);
|
||||
$div.append($export);
|
||||
|
||||
/* add an import button */
|
||||
var $import = common.createButton('import', true, {}, importFile);
|
||||
$import.attr('class', 'btn btn-success').text(Messages.settings_restore);
|
||||
$div.append($import);
|
||||
|
||||
return $div;
|
||||
};
|
||||
|
||||
var createResetDrive = function (obj) {
|
||||
var $div = $('<div>', {'class': 'cp-settings-reset-drive cp-sidebarlayout-element'});
|
||||
$('<label>').text(Messages.settings_resetNewTitle).appendTo($div);
|
||||
$('<span>', {'class': 'cp-sidebarlayout-description'})
|
||||
.text(Messages.settings_reset).appendTo($div);
|
||||
var $button = $('<button>', {'id': 'cp-settings-reset-drive', 'class': 'btn btn-danger'})
|
||||
.text(Messages.settings_resetButton).appendTo($div);
|
||||
|
||||
$button.click(function () {
|
||||
Cryptpad.prompt(Messages.settings_resetPrompt, "", function (val) {
|
||||
if (val !== "I love CryptPad") {
|
||||
Cryptpad.alert(Messages.settings_resetError);
|
||||
return;
|
||||
}
|
||||
sframeChan.query("Q_SETTINGS_DRIVE_RESET", null, function (err) {
|
||||
if (err) { return void console.error(err); }
|
||||
Cryptpad.alert(Messages.settings_resetDone);
|
||||
});
|
||||
}, undefined, true);
|
||||
});
|
||||
|
||||
return $div;
|
||||
};
|
||||
|
||||
var createUserFeedbackToggle = function () {
|
||||
var $div = $('<div>', { 'class': 'cp-settings-userfeedback cp-sidebarlayout-element'});
|
||||
|
||||
$('<span>', {'class': 'label'}).text(Messages.settings_userFeedbackTitle).appendTo($div);
|
||||
|
||||
var $label = $('<label>', { 'for': 'cp-settings-userfeedback', 'class': 'noTitle' })
|
||||
.text(Messages.settings_userFeedback);
|
||||
|
||||
$('<span>', {'class': 'cp-sidebarlayout-description'})
|
||||
.append(Messages.settings_userFeedbackHint1)
|
||||
.append(Messages.settings_userFeedbackHint2).appendTo($div);
|
||||
|
||||
var $ok = $('<span>', {'class': 'fa fa-check', title: Messages.saved});
|
||||
var $spinner = $('<span>', {'class': 'fa fa-spinner fa-pulse'});
|
||||
|
||||
var $checkbox = $('<input>', {
|
||||
'type': 'checkbox',
|
||||
id: 'cp-settings-userfeedback'
|
||||
}).on('change', function () {
|
||||
$spinner.show();
|
||||
$ok.hide();
|
||||
var val = $checkbox.is(':checked') || false;
|
||||
common.setAttribute(['general', 'allowUserFeedback'], val, function () {
|
||||
$spinner.hide();
|
||||
$ok.show();
|
||||
});
|
||||
});
|
||||
|
||||
$checkbox.appendTo($div);
|
||||
$label.appendTo($div);
|
||||
|
||||
$ok.hide().appendTo($div);
|
||||
$spinner.hide().appendTo($div);
|
||||
|
||||
if (privateData.feedbackAllowed) {
|
||||
$checkbox[0].checked = true;
|
||||
}
|
||||
return $div;
|
||||
};
|
||||
|
||||
var createUsageButton = function () {
|
||||
common.createUsageBar(function (err, $bar) {
|
||||
if (err) { return void console.error(err); }
|
||||
APP.$usage.html('').append($bar);
|
||||
}, true);
|
||||
};
|
||||
|
||||
var createLogoutEverywhere = function () {
|
||||
var $div = $('<div>', { 'class': 'cp-settings-logout-everywhere cp-sidebarlayout-element'});
|
||||
$('<label>', { 'for': 'cp-settings-logout-everywhere'})
|
||||
.text(Messages.settings_logoutEverywhereTitle).appendTo($div);
|
||||
$('<span>', {'class': 'cp-sidebarlayout-description'})
|
||||
.text(Messages.settings_logoutEverywhere).appendTo($div);
|
||||
var $button = $('<button>', {
|
||||
id: 'cp-settings-logout-everywhere',
|
||||
'class': 'btn btn-primary'
|
||||
}).text(Messages.settings_logoutEverywhereButton)
|
||||
.appendTo($div);
|
||||
var $ok = $('<span>', {'class': 'fa fa-check', title: Messages.saved}).hide().appendTo($div);
|
||||
var $spinner = $('<span>', {'class': 'fa fa-spinner fa-pulse'}).hide().appendTo($div);
|
||||
|
||||
$button.click(function () {
|
||||
|
||||
Cryptpad.confirm(Messages.settings_logoutEverywhereConfirm, function (yes) {
|
||||
if (!yes) { return; }
|
||||
$spinner.show();
|
||||
$ok.hide();
|
||||
|
||||
sframeChan.query('Q_SETTINGS_LOGOUT', null, function (err) {
|
||||
$spinner.hide();
|
||||
$ok.show();
|
||||
window.setTimeout(function () {
|
||||
$ok.fadeOut(1500);
|
||||
}, 2500);
|
||||
});
|
||||
});
|
||||
});
|
||||
return $div;
|
||||
};
|
||||
|
||||
var createImportLocalPads = function () {
|
||||
if (!common.isLoggedIn()) { return; }
|
||||
var $div = $('<div>', {'class': 'cp-settings-import-local-pads cp-sidebarlayout-element'});
|
||||
$('<label>', {'for' : 'cp-settings-import-local-pads'})
|
||||
.text(Messages.settings_import).appendTo($div);
|
||||
$('<span>', {'class': 'cp-sidebarlayout-description'})
|
||||
.text(Messages.settings_importTitle).appendTo($div);
|
||||
var $button = $('<button>', {
|
||||
'id': 'cp-settings-import-local-pads',
|
||||
'class': 'btn btn-primary'
|
||||
}).text(Messages.settings_import).appendTo($div);
|
||||
var $ok = $('<span>', {'class': 'fa fa-check', title: Messages.saved}).hide().appendTo($div);
|
||||
var $spinner = $('<span>', {'class': 'fa fa-spinner fa-pulse'}).hide().appendTo($div);
|
||||
|
||||
$button.click(function () {
|
||||
Cryptpad.confirm(Messages.settings_importConfirm, function (yes) {
|
||||
if (!yes) { return; }
|
||||
$spinner.show();
|
||||
$ok.hide();
|
||||
sframeChan.query('Q_SETTINGS_IMPORT_LOCAL', null, function (err) {
|
||||
$spinner.hide();
|
||||
$ok.show();
|
||||
Cryptpad.alert(Messages.settings_importDone);
|
||||
});
|
||||
}, undefined, true);
|
||||
});
|
||||
|
||||
return $div;
|
||||
};
|
||||
|
||||
var createLanguageSelector = function () {
|
||||
var $div = $('<div>', {'class': 'cp-settings-language-selector cp-sidebarlayout-element'});
|
||||
$('<label>').text(Messages.language).appendTo($div);
|
||||
var $b = common.createLanguageSelector($div);
|
||||
$b.find('button').addClass('btn btn-secondary');
|
||||
return $div;
|
||||
};
|
||||
|
||||
|
||||
var hideCategories = function () {
|
||||
APP.$rightside.find('> div').hide();
|
||||
};
|
||||
var showCategories = function (cat) {
|
||||
hideCategories();
|
||||
cat.forEach(function (c) {
|
||||
APP.$rightside.find('.'+c).show();
|
||||
});
|
||||
};
|
||||
|
||||
var createLeftside = function () {
|
||||
var $categories = $('<div>', {'class': 'cp-sidebarlayout-categories'})
|
||||
.appendTo(APP.$leftside);
|
||||
APP.$usage = $('<div>', {'class': 'usage'}).appendTo(APP.$leftside);
|
||||
var active = 'account';
|
||||
Object.keys(categories).forEach(function (key) {
|
||||
var $category = $('<div>', {'class': 'cp-sidebarlayout-category'}).appendTo($categories);
|
||||
if (key === 'account') { $category.append($('<span>', {'class': 'fa fa-user-o'})); }
|
||||
if (key === 'drive') { $category.append($('<span>', {'class': 'fa fa-hdd-o'})); }
|
||||
if (key === 'code') { $category.append($('<span>', {'class': 'fa fa-file-code-o' })); }
|
||||
|
||||
if (key === active) {
|
||||
$category.addClass('cp-leftside-active');
|
||||
}
|
||||
|
||||
$category.click(function () {
|
||||
active = key;
|
||||
$categories.find('.cp-leftside-active').removeClass('cp-leftside-active');
|
||||
$category.addClass('cp-leftside-active');
|
||||
showCategories(categories[key]);
|
||||
});
|
||||
|
||||
$category.append(Messages['settings_cat_'+key]);
|
||||
});
|
||||
showCategories(categories[active]);
|
||||
};
|
||||
|
||||
|
||||
|
||||
nThen(function (waitFor) {
|
||||
$(waitFor(Cryptpad.addLoadingScreen));
|
||||
SFCommon.create(waitFor(function (c) { APP.common = common = c; }));
|
||||
}).nThen(function (waitFor) {
|
||||
APP.$container = $('#cp-sidebarlayout-container');
|
||||
APP.$toolbar = $('#cp-toolbar');
|
||||
APP.$leftside = $('<div>', {id: 'cp-sidebarlayout-leftside'}).appendTo(APP.$container);
|
||||
APP.$rightside = $('<div>', {id: 'cp-sidebarlayout-rightside'}).appendTo(APP.$container);
|
||||
sframeChan = common.getSframeChannel();
|
||||
sframeChan.onReady(waitFor());
|
||||
}).nThen(function (/*waitFor*/) {
|
||||
Cryptpad.onError(function (info) {
|
||||
if (info && info.type === "store") {
|
||||
onConnectError();
|
||||
}
|
||||
});
|
||||
|
||||
metadataMgr = common.getMetadataMgr();
|
||||
privateData = metadataMgr.getPrivateData();
|
||||
|
||||
// Toolbar
|
||||
var displayed = ['useradmin', 'newpad', 'limit', 'pageTitle'];
|
||||
var configTb = {
|
||||
displayed: displayed,
|
||||
common: Cryptpad,
|
||||
sfCommon: common,
|
||||
$container: APP.$toolbar,
|
||||
pageTitle: Messages.settings_title,
|
||||
metadataMgr: common.getMetadataMgr(),
|
||||
};
|
||||
APP.toolbar = Toolbar.create(configTb);
|
||||
APP.toolbar.$rightside.hide();
|
||||
|
||||
// Content
|
||||
var $rightside = APP.$rightside;
|
||||
$rightside.append(createInfoBlock());
|
||||
$rightside.append(createDisplayNameInput());
|
||||
$rightside.append(createLanguageSelector());
|
||||
$rightside.append(createIndentUnitSelector());
|
||||
$rightside.append(createIndentTypeSelector());
|
||||
|
||||
if (common.isLoggedIn()) {
|
||||
$rightside.append(createLogoutEverywhere());
|
||||
}
|
||||
$rightside.append(createResetTips());
|
||||
$rightside.append(createThumbnails());
|
||||
$rightside.append(createBackupDrive());
|
||||
$rightside.append(createImportLocalPads());
|
||||
$rightside.append(createResetDrive());
|
||||
$rightside.append(createUserFeedbackToggle());
|
||||
|
||||
// TODO RPC
|
||||
//obj.proxy.on('change', [], refresh);
|
||||
//obj.proxy.on('remove', [], refresh);
|
||||
//Cryptpad.onDisplayNameChanged(refresh);
|
||||
|
||||
createLeftside();
|
||||
createUsageButton();
|
||||
|
||||
Cryptpad.removeLoadingScreen();
|
||||
});
|
||||
});
|
@ -0,0 +1,528 @@
|
||||
define([
|
||||
'jquery',
|
||||
'/common/cryptpad-common.js',
|
||||
'/common/hyperscript.js',
|
||||
'/bower_components/marked/marked.min.js',
|
||||
'/common/media-tag.js',
|
||||
], function ($, Cryptpad, h, Marked, MediaTag) {
|
||||
'use strict';
|
||||
|
||||
var UI = {};
|
||||
var Messages = Cryptpad.Messages;
|
||||
|
||||
var m = function (md) {
|
||||
var d = h('div.cp-app-contacts-content');
|
||||
try {
|
||||
d.innerHTML = Marked(md || '');
|
||||
var $d = $(d);
|
||||
// remove potentially malicious elements
|
||||
$d.find('script, iframe, object, applet, video, audio').remove();
|
||||
|
||||
// activate media-tags
|
||||
$d.find('media-tag').each(function (i, e) { MediaTag(e); });
|
||||
} catch (e) {
|
||||
console.error(md);
|
||||
console.error(e);
|
||||
}
|
||||
return d;
|
||||
};
|
||||
|
||||
var dataQuery = function (curvePublic) {
|
||||
return '[data-key="' + curvePublic + '"]';
|
||||
};
|
||||
|
||||
var initChannel = function (state, curvePublic, info) {
|
||||
console.log('initializing channel for [%s]', curvePublic);
|
||||
state.channels[curvePublic] = {
|
||||
messages: [],
|
||||
HEAD: info.lastKnownHash,
|
||||
TAIL: null,
|
||||
};
|
||||
};
|
||||
|
||||
UI.create = function (messenger, $userlist, $messages, common) {
|
||||
var origin = common.getMetadataMgr().getPrivateData().origin;
|
||||
|
||||
var state = window.state = {
|
||||
active: '',
|
||||
};
|
||||
|
||||
state.channels = {};
|
||||
var displayNames = state.displayNames = {};
|
||||
|
||||
var avatars = state.avatars = {};
|
||||
var setActive = function (curvePublic) {
|
||||
state.active = curvePublic;
|
||||
};
|
||||
var isActive = function (curvePublic) {
|
||||
return curvePublic === state.active;
|
||||
};
|
||||
|
||||
var find = {};
|
||||
find.inList = function (curvePublic) {
|
||||
return $userlist.find(dataQuery(curvePublic));
|
||||
};
|
||||
|
||||
var notify = function (curvePublic) {
|
||||
find.inList(curvePublic).addClass('cp-app-contacts-notify');
|
||||
};
|
||||
var unnotify = function (curvePublic) {
|
||||
find.inList(curvePublic).removeClass('cp-app-contacts-notify');
|
||||
};
|
||||
|
||||
var markup = {};
|
||||
markup.message = function (msg) {
|
||||
var curvePublic = msg.author;
|
||||
var name = displayNames[msg.author];
|
||||
return h('div.cp-app-contacts-message', {
|
||||
title: msg.time? new Date(msg.time).toLocaleString(): '?',
|
||||
'data-key': curvePublic,
|
||||
}, [
|
||||
name? h('div.cp-app-contacts-sender', name): undefined,
|
||||
m(msg.text),
|
||||
]);
|
||||
};
|
||||
|
||||
var getChat = function (curvePublic) {
|
||||
return $messages.find(dataQuery(curvePublic));
|
||||
};
|
||||
|
||||
var normalizeLabels = function ($messagebox) {
|
||||
$messagebox.find('div.cp-app-contacts-message').toArray().reduce(function (a, b) {
|
||||
var $b = $(b);
|
||||
if ($(a).data('key') === $b.data('key')) {
|
||||
$b.find('.cp-app-contacts-sender').hide();
|
||||
return a;
|
||||
}
|
||||
return b;
|
||||
}, []);
|
||||
};
|
||||
|
||||
markup.chatbox = function (curvePublic, data) {
|
||||
var moreHistory = h('span.cp-app-contacts-more-history.fa.fa-history', {
|
||||
title: Messages.contacts_fetchHistory,
|
||||
});
|
||||
var displayName = data.displayName;
|
||||
|
||||
var fetching = false;
|
||||
var $moreHistory = $(moreHistory).click(function () {
|
||||
if (fetching) { return; }
|
||||
|
||||
// get oldest known message...
|
||||
var channel = state.channels[curvePublic];
|
||||
|
||||
if (channel.exhausted) {
|
||||
return void $moreHistory.addClass('cp-app-contacts-faded');
|
||||
}
|
||||
|
||||
console.log('getting history');
|
||||
var sig = channel.TAIL || channel.HEAD;
|
||||
|
||||
fetching = true;
|
||||
var $messagebox = $(getChat(curvePublic)).find('.cp-app-contacts-messages');
|
||||
messenger.getMoreHistory(curvePublic, sig, 10, function (e, history) {
|
||||
fetching = false;
|
||||
if (e) { return void console.error(e); }
|
||||
|
||||
if (history.length === 0) {
|
||||
channel.exhausted = true;
|
||||
return;
|
||||
}
|
||||
|
||||
history.forEach(function (msg) {
|
||||
if (channel.exhausted) { return; }
|
||||
if (msg.sig) {
|
||||
if (msg.sig === channel.TAIL) {
|
||||
console.error('No more messages to fetch');
|
||||
channel.exhausted = true;
|
||||
console.log(channel);
|
||||
return void $moreHistory.addClass('cp-app-contacts-faded');
|
||||
} else {
|
||||
channel.TAIL = msg.sig;
|
||||
}
|
||||
} else {
|
||||
return void console.error('expected signature');
|
||||
}
|
||||
if (msg.type !== 'MSG') { return; }
|
||||
|
||||
// FIXME Schlameil the painter (performance does not scale well)
|
||||
if (channel.messages.some(function (old) {
|
||||
return msg.sig === old.sig;
|
||||
})) { return; }
|
||||
|
||||
channel.messages.unshift(msg);
|
||||
var el_message = markup.message(msg);
|
||||
$messagebox.prepend(el_message);
|
||||
});
|
||||
normalizeLabels($messagebox);
|
||||
});
|
||||
});
|
||||
|
||||
var removeHistory = h('span.cp-app-contacts-remove-history.fa.fa-eraser', {
|
||||
title: Messages.contacts_removeHistoryTitle
|
||||
});
|
||||
|
||||
$(removeHistory).click(function () {
|
||||
Cryptpad.confirm(Messages.contacts_confirmRemoveHistory, function (yes) {
|
||||
if (!yes) { return; }
|
||||
Cryptpad.clearOwnedChannel(data.channel, function (e) {
|
||||
if (e) {
|
||||
console.error(e);
|
||||
Cryptpad.alert(Messages.contacts_removeHistoryServerError);
|
||||
return;
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
var avatar = h('div.cp-avatar');
|
||||
var header = h('div.cp-app-contacts-header', [
|
||||
avatar,
|
||||
moreHistory,
|
||||
removeHistory,
|
||||
]);
|
||||
var messages = h('div.cp-app-contacts-messages');
|
||||
var input = h('textarea', {
|
||||
placeholder: Messages.contacts_typeHere
|
||||
});
|
||||
var sendButton = h('button.btn.btn-primary.fa.fa-paper-plane', {
|
||||
title: Messages.contacts_send,
|
||||
});
|
||||
|
||||
var rightCol = h('span.cp-app-contacts-right-col', [
|
||||
h('span.cp-app-contacts-name', displayName),
|
||||
]);
|
||||
|
||||
var $avatar = $(avatar);
|
||||
if (data.avatar && avatars[data.avatar]) {
|
||||
$avatar.append(avatars[data.avatar]).append(rightCol);
|
||||
} else {
|
||||
common.displayAvatar($avatar, data.avatar, data.displayName, function ($img) {
|
||||
if (data.avatar && $img) {
|
||||
avatars[data.avatar] = $img[0].outerHTML;
|
||||
}
|
||||
$(rightCol).insertAfter($avatar);
|
||||
});
|
||||
}
|
||||
|
||||
var sending = false;
|
||||
var send = function (content) {
|
||||
if (typeof(content) !== 'string' || !content.trim()) { return; }
|
||||
if (sending) { return false; }
|
||||
sending = true;
|
||||
messenger.sendMessage(curvePublic, content, function (e) {
|
||||
if (e) {
|
||||
// failed to send
|
||||
return void console.error('failed to send');
|
||||
}
|
||||
input.value = '';
|
||||
sending = false;
|
||||
console.log('sent successfully');
|
||||
var $messagebox = $(messages);
|
||||
|
||||
var height = $messagebox[0].scrollHeight;
|
||||
$messagebox.scrollTop(height);
|
||||
});
|
||||
};
|
||||
|
||||
var onKeyDown = function (e) {
|
||||
// ignore anything that isn't 'enter'
|
||||
if (e.keyCode !== 13) { return; }
|
||||
// send unless they're holding a ctrl-key or shift
|
||||
if (!e.ctrlKey && !e.shiftKey) {
|
||||
send(this.value);
|
||||
return false;
|
||||
}
|
||||
|
||||
// insert a newline if they're holding either
|
||||
var val = this.value;
|
||||
var start = this.selectionState;
|
||||
var end = this.selectionEnd;
|
||||
|
||||
if (![start,end].some(function (x) {
|
||||
return typeof(x) !== 'number';
|
||||
})) {
|
||||
this.value = val.slice(0, start) + '\n' + val.slice(end);
|
||||
this.selectionStart = this.selectionEnd = start + 1;
|
||||
} else if (document.selection && document.selection.createRange) {
|
||||
this.focus();
|
||||
var range = document.selection.createRange();
|
||||
range.text = '\r\n';
|
||||
range.collapse(false);
|
||||
range.select();
|
||||
}
|
||||
return false;
|
||||
};
|
||||
$(input).on('keydown', onKeyDown);
|
||||
$(sendButton).click(function () { send(input.value); });
|
||||
|
||||
return h('div.cp-app-contacts-chat', {
|
||||
'data-key': curvePublic,
|
||||
}, [
|
||||
header,
|
||||
messages,
|
||||
h('div.cp-app-contacts-input', [
|
||||
input,
|
||||
sendButton,
|
||||
]),
|
||||
]);
|
||||
};
|
||||
|
||||
var hideInfo = function () {
|
||||
$messages.find('.cp-app-contacts-info').hide();
|
||||
};
|
||||
|
||||
var updateStatus = function (curvePublic) {
|
||||
var $status = find.inList(curvePublic).find('.cp-app-contacts-status');
|
||||
// FIXME this stopped working :(
|
||||
messenger.getStatus(curvePublic, function (e, online) {
|
||||
// if error maybe you shouldn't display this friend...
|
||||
if (e) {
|
||||
find.inList(curvePublic).hide();
|
||||
getChat(curvePublic).hide();
|
||||
|
||||
return void console.error(curvePublic, e);
|
||||
}
|
||||
if (online) {
|
||||
return void $status
|
||||
.removeClass('cp-app-contacts-offline').addClass('cp-app-contacts-online');
|
||||
}
|
||||
$status.removeClass('cp-app-contacts-online').addClass('cp-app-contacts-offline');
|
||||
});
|
||||
};
|
||||
|
||||
var display = function (curvePublic) {
|
||||
var channel = state.channels[curvePublic];
|
||||
var lastMsg = channel.messages.slice(-1)[0];
|
||||
|
||||
if (lastMsg) {
|
||||
channel.HEAD = lastMsg.sig;
|
||||
messenger.setChannelHead(curvePublic, channel.HEAD, function (e) {
|
||||
if (e) { console.error(e); }
|
||||
});
|
||||
}
|
||||
|
||||
setActive(curvePublic);
|
||||
unnotify(curvePublic);
|
||||
var $chat = getChat(curvePublic);
|
||||
hideInfo();
|
||||
$messages.find('div.cp-app-contacts-chat[data-key]').hide();
|
||||
if ($chat.length) {
|
||||
var $chat_messages = $chat.find('div.cp-app-contacts-message');
|
||||
if (!$chat_messages.length) {
|
||||
var $more = $chat.find('.cp-app-contacts-more-history');
|
||||
$more.click();
|
||||
}
|
||||
return void $chat.show();
|
||||
}
|
||||
messenger.getFriendInfo(curvePublic, function (e, info) {
|
||||
if (e) { return void console.error(e); } // FIXME
|
||||
var chatbox = markup.chatbox(curvePublic, info);
|
||||
$messages.append(chatbox);
|
||||
});
|
||||
};
|
||||
|
||||
var removeFriend = function (curvePublic) {
|
||||
messenger.removeFriend(curvePublic, function (e /*, removed */) {
|
||||
if (e) { return void console.error(e); }
|
||||
find.inList(curvePublic).remove();
|
||||
//console.log(removed);
|
||||
});
|
||||
};
|
||||
|
||||
markup.friend = function (data) {
|
||||
var curvePublic = data.curvePublic;
|
||||
var friend = h('div.cp-app-contacts-friend.cp-avatar', {
|
||||
'data-key': curvePublic,
|
||||
});
|
||||
|
||||
var remove = h('span.cp-app-contacts-remove.fa.fa-user-times', {
|
||||
title: Messages.contacts_remove
|
||||
});
|
||||
var status = h('span.cp-app-contacts-status');
|
||||
var rightCol = h('span.cp-app-contacts-right-col', [
|
||||
h('span.cp-app-contacts-name', [data.displayName]),
|
||||
remove,
|
||||
]);
|
||||
|
||||
var $friend = $(friend)
|
||||
.click(function () {
|
||||
display(curvePublic);
|
||||
})
|
||||
.dblclick(function () {
|
||||
if (data.profile) { window.open(origin + '/profile/#' + data.profile); }
|
||||
});
|
||||
|
||||
$(remove).click(function (e) {
|
||||
e.stopPropagation();
|
||||
Cryptpad.confirm(Messages._getKey('contacts_confirmRemove', [
|
||||
Cryptpad.fixHTML(data.displayName)
|
||||
]), function (yes) {
|
||||
if (!yes) { return; }
|
||||
removeFriend(curvePublic, function (e) {
|
||||
if (e) { return void console.error(e); }
|
||||
});
|
||||
// TODO remove friend from userlist ui
|
||||
// FIXME seems to trigger EJOINED from netflux-websocket (from server);
|
||||
// (tried to join a channel in which you were already present)
|
||||
}, undefined, true);
|
||||
});
|
||||
|
||||
if (data.avatar && avatars[data.avatar]) {
|
||||
$friend.append(avatars[data.avatar]);
|
||||
$friend.append(rightCol);
|
||||
} else {
|
||||
common.displayAvatar($friend, data.avatar, data.displayName, function ($img) {
|
||||
if (data.avatar && $img) {
|
||||
avatars[data.avatar] = $img[0].outerHTML;
|
||||
}
|
||||
$friend.append(rightCol);
|
||||
});
|
||||
}
|
||||
$friend.append(status);
|
||||
return $friend;
|
||||
};
|
||||
|
||||
var isBottomedOut = function ($elem) {
|
||||
return ($elem[0].scrollHeight - $elem.scrollTop() === $elem.outerHeight());
|
||||
};
|
||||
|
||||
var initializing = true;
|
||||
messenger.on('message', function (message) {
|
||||
if (!initializing) { Cryptpad.notify(); }
|
||||
var curvePublic = message.curve;
|
||||
|
||||
var name = displayNames[curvePublic];
|
||||
var chat = getChat(curvePublic, name);
|
||||
|
||||
console.log(message);
|
||||
|
||||
var el_message = markup.message(message);
|
||||
|
||||
state.channels[curvePublic].messages.push(message);
|
||||
|
||||
var $chat = $(chat);
|
||||
|
||||
if (!$chat.length) {
|
||||
console.error("Got a message but the chat isn't open");
|
||||
}
|
||||
|
||||
var $messagebox = $chat.find('.cp-app-contacts-messages');
|
||||
var shouldScroll = isBottomedOut($messagebox);
|
||||
|
||||
$messagebox.append(el_message);
|
||||
|
||||
if (shouldScroll) {
|
||||
$messagebox.scrollTop($messagebox.outerHeight());
|
||||
}
|
||||
normalizeLabels($messagebox);
|
||||
|
||||
var channel = state.channels[curvePublic];
|
||||
if (!channel) {
|
||||
console.error('expected channel [%s] to be open', curvePublic);
|
||||
return;
|
||||
}
|
||||
|
||||
if (isActive(curvePublic)) {
|
||||
channel.HEAD = message.sig;
|
||||
messenger.setChannelHead(curvePublic, message.sig, function (e) {
|
||||
if (e) { return void console.error(e); }
|
||||
});
|
||||
return;
|
||||
}
|
||||
var lastMsg = channel.messages.slice(-1)[0];
|
||||
if (lastMsg.sig !== channel.HEAD) {
|
||||
return void notify(curvePublic);
|
||||
}
|
||||
unnotify(curvePublic);
|
||||
});
|
||||
|
||||
messenger.on('join', function (curvePublic, channel) {
|
||||
channel = channel;
|
||||
updateStatus(curvePublic);
|
||||
});
|
||||
messenger.on('leave', function (curvePublic, channel) {
|
||||
channel = channel;
|
||||
updateStatus(curvePublic);
|
||||
});
|
||||
|
||||
// change in your friend list
|
||||
messenger.on('update', function (info, curvePublic) {
|
||||
var name = displayNames[curvePublic] = info.displayName;
|
||||
|
||||
// update label in friend list
|
||||
find.inList(curvePublic).find('.cp-app-contacts-name').text(name);
|
||||
|
||||
// update title bar and messages
|
||||
$messages.find(dataQuery(curvePublic) + ' .cp-app-contacts-header ' +
|
||||
'.cp-app-contacts-name, div.cp-app-contacts-message'+
|
||||
dataQuery(curvePublic) + ' div.cp-app-contacts-sender').text(name).text(name);
|
||||
});
|
||||
|
||||
var connectToFriend = function (curvePublic, cb) {
|
||||
messenger.getFriendInfo(curvePublic, function (e, info) {
|
||||
if (e) { return void console.error(e); }
|
||||
var name = displayNames[curvePublic] = info.displayName;
|
||||
initChannel(state, curvePublic, info);
|
||||
|
||||
var chatbox = markup.chatbox(curvePublic, info);
|
||||
$(chatbox).hide();
|
||||
$messages.append(chatbox);
|
||||
|
||||
var friend = markup.friend(info, name);
|
||||
$userlist.append(friend);
|
||||
messenger.openFriendChannel(curvePublic, function (e) {
|
||||
if (e) { return void console.error(e); }
|
||||
cb();
|
||||
updateStatus(curvePublic);
|
||||
// don't add friends that are already in your userlist
|
||||
//if (friendExistsInUserList(k)) { return; }
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
messenger.on('friend', function (curvePublic) {
|
||||
console.log('new friend: ', curvePublic);
|
||||
//console.error("TODO redraw user list");
|
||||
//console.error("TODO connect to new friend");
|
||||
// FIXME this doesn't work right now because the friend hasn't been fully added?
|
||||
connectToFriend(curvePublic, function () {
|
||||
//console.error('connected');
|
||||
});
|
||||
});
|
||||
|
||||
messenger.on('unfriend', function (curvePublic) {
|
||||
console.log('unfriend', curvePublic);
|
||||
find.inList(curvePublic).remove();
|
||||
console.error('TODO remove chatbox');
|
||||
console.error('TODO show something if that chatbox was active');
|
||||
});
|
||||
|
||||
Cryptpad.onDisplayNameChanged(function () {
|
||||
//messenger.checkNewFriends();
|
||||
messenger.updateMyData();
|
||||
});
|
||||
|
||||
// FIXME dirty hack
|
||||
messenger.getMyInfo(function (e, info) {
|
||||
displayNames[info.curvePublic] = info.displayName;
|
||||
});
|
||||
|
||||
messenger.getFriendList(function (e, keys) {
|
||||
var count = keys.length + 1;
|
||||
var ready = function () {
|
||||
count--;
|
||||
if (count === 0) {
|
||||
initializing = false;
|
||||
Cryptpad.removeLoadingScreen();
|
||||
}
|
||||
};
|
||||
ready();
|
||||
keys.forEach(function (curvePublic) {
|
||||
connectToFriend(curvePublic, ready);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
return UI;
|
||||
});
|
Loading…
Reference in New Issue