Fix merge error

pull/1/head
Caleb James DeLisle 8 years ago
commit f8ac3a6ad3

@ -14,7 +14,12 @@ let historyKeeperKeys = {};
const now = function () { return (new Date()).getTime(); };
const socketSendable = function (socket) {
return socket && socket.readyState === 1;
};
const sendMsg = function (ctx, user, msg) {
if (!socketSendable(user.socket)) { return; }
try {
if (ctx.config.logToStdout) { console.log('<' + JSON.stringify(msg)); }
user.socket.send(JSON.stringify(msg));
@ -272,7 +277,7 @@ let run = module.exports.run = function (storage, socketServer, config) {
});
}, 5000);
socketServer.on('connection', function(socket) {
if(socket.upgradeReq.url !== '/cryptpad_websocket') { return; }
if(socket.upgradeReq.url !== (config.websocketPath || '/cryptpad_websocket')) { return; }
let conn = socket.upgradeReq.connection;
let user = {
addr: conn.remoteAddress + '|' + conn.remotePort,

@ -9,8 +9,22 @@ module.exports = {
// the port on which your httpd will listen
httpPort: 3000,
// the port used for websockets
websocketPort: 3000,
/* your server's websocket url is configurable
(default: '/cryptpad_websocket')
websocketPath can be relative, of the form '/path/to/websocket'
or absolute, specifying a particular URL
'wss://cryptpad.fr:3000/cryptpad_websocket'
*/
websocketPath: '/cryptpad_websocket',
/* it is assumed that your websocket will bind to the same port as http
you can override this behaviour by supplying a number via websocketPort
*/
//websocketPort: 3000,
/* Cryptpad can log activity to stdout
* This may be useful for debugging

@ -4,7 +4,7 @@ define(function() {
/* Select the buttons displayed on the main page to create new collaborative sessions
* Existing types : pad, code, poll, slide
*/
config.availablePadTypes = ['pad', 'code', 'poll'];
config.availablePadTypes = ['pad', 'code', 'poll', 'slide'];
return config;
});

@ -57,8 +57,12 @@
<center>
<noscript>
<p data-localization="main_oops">
<!-- JS required -->
<p>
<strong>OOPS</strong> In order to do encryption in your browser, Javascript is really <strong>really</strong> required.
</p>
<hr>
<p>
<strong>OUPS</strong> Afin de pouvoir réaliser le cryptage depuis votre navigateur, Javascript est <strong>vraiment</strong> requis.
</p>
</noscript>
<h5 id="tryit" data-localization="tryIt"></h5>
@ -87,8 +91,6 @@
</div>
<div id="bottom-bar"></div>
</body>
</html>

@ -154,6 +154,9 @@ tr {
margin-bottom: 12px;
white-space: nowrap;
}
.alertify button {
margin: 3px 0px;
}
/* Tables */
table {
border-collapse: collapse;

@ -12,9 +12,6 @@ define([
Cryptpad: Cryptpad,
};
DecorateToolbar.main($('#bottom-bar'));
Cryptpad.styleAlerts();
var padTypes = {
'/pad/': Messages.type.pad,
'/code/': Messages.type.code,
@ -22,9 +19,9 @@ define([
'/slide/': Messages.type.slide,
};
var $table = $('table.scroll');
var $tbody = $table.find('tbody');
var $tryit = $('#tryit');
var $table;
var $tbody;
var $tryit;
var now = new Date();
var hasRecent = false;
@ -138,11 +135,18 @@ define([
});
};
displayCreateButtons();
Cryptpad.ready(function () {
console.log("ready");
refreshTable();
$table = $('table.scroll');
$tbody = $table.find('tbody');
$tryit = $('#tryit');
DecorateToolbar.main($('#bottom-bar'));
Cryptpad.styleAlerts();
displayCreateButtons();
refreshTable();
if (Cryptpad.store && Cryptpad.store.change) {
Cryptpad.store.change(function (data) {
if (data.key === 'CryptPad_RECENTPADS') {

@ -74,8 +74,6 @@
</div>
<div id="bottom-bar"></div>
</body>
</html>

@ -187,6 +187,9 @@ p, pre, td, a, table, tr {
margin-bottom: 2 * 6px;
white-space: nowrap;
}
.alertify button {
margin: 3px 0px;
}
/* Tables */
table {

@ -17,8 +17,12 @@
<center>
<noscript>
<p data-localization="main_oops">
<!-- JS required -->
<p>
<strong>OOPS</strong> In order to do encryption in your browser, Javascript is really <strong>really</strong> required.
</p>
<hr>
<p>
<strong>OUPS</strong> Afin de pouvoir réaliser le cryptage depuis votre navigateur, Javascript est <strong>vraiment</strong> requis.
</p>
</noscript>
<h5 id="tryit" data-localization="tryIt"></h5>

@ -20,8 +20,6 @@
<div id="main">
{{main}}
</div>
<div id="bottom-bar"></div>
</body>
</html>

@ -51,8 +51,6 @@
</div>
<div id="bottom-bar"></div>
</body>
</html>

@ -34,7 +34,7 @@ define(function () {
out.anonymous = "Vous êtes actuellement anonyme";
out.greenLight = "Tout fonctionne bien";
out.orangeLight = "Votre connexion est lente, ce qui réduit la qualité de l'éditeur"
out.orangeLight = "Votre connexion est lente, ce qui réduit la qualité de l'éditeur";
out.redLight = "Vous êtes déconnectés de la session";
out.importButton = 'IMPORTER';
@ -74,7 +74,10 @@ define(function () {
out.getViewButton = 'LECTURE SEULE';
out.getViewButtonTitle = "Obtenir l'adresse d'accès à ce document en lecture seule";
out.readonlyUrl = 'URL de lecture seule';
out.readonlyUrl = 'Document en lecture seule';
out.copyReadOnly = "Copier l'URL dans le presse-papiers";
out.openReadOnly = "Ouvrir dans un nouvel onglet";
out.disconnectAlert = 'Perte de la connexion au réseau !';
@ -142,7 +145,6 @@ define(function () {
out.main_about = 'À propos';
out.main_about_p1 = 'Vous pouvez en apprendre davantage sur notre <a href="/privacy.html" title="">politique de confidentialité</a> et nos <a href="/terms.html">conditions d\'utilisation</a>.';
out.main_about_p2 = 'Si vous avez des questions ou commentaires, vous pouvez <a href="https://twitter.com/cryptpad">nous tweeter</a>, ouvrir une issue sur <a href="https://github.com/xwiki-labs/cryptpad/issues/" title="our issue tracker">Github</a>, venir dire bonjour sur IRC (<a href="http://webchat.freenode.net?channels=%23cryptpad&uio=MT1mYWxzZSY5PXRydWUmMTE9Mjg3JjE1PXRydWUe7" title="freenode webchat">irc.freenode.net</a>), ou <a href="mailto:research@xwiki.com">nous envoyer un email</a>.';
out.main_oops = '<strong>OUPS</strong> Afin de pouvoir réaliser le cryptage depuis votre navigateur, Javascript est <strong>vraiment</strong> requis.';
out.table_type = 'Type';
out.table_link = 'Lien';

@ -57,7 +57,7 @@ define(function () {
out.renameConflict = 'Another pad already has that title';
out.forgetButton = 'FORGET';
out.forgetButtonTitle = 'remove this document from your home page listings';
out.forgetButtonTitle = 'Remove this document from your home page listings';
out.forgetPrompt = 'Clicking OK will remove the URL for this pad from localStorage, are you sure?';
out.shareButton = 'SHARE';
@ -75,7 +75,9 @@ define(function () {
out.getViewButton = 'READ-ONLY URL';
out.getViewButtonTitle = 'Get the read-only URL for this document';
out.readonlyUrl = 'Read only URL';
out.readonlyUrl = 'Read only document';
out.copyReadOnly = "Copy URL to clipboard";
out.openReadOnly = "Open in a new tab";
out.disconnectAlert = 'Network connection lost!';
@ -142,8 +144,8 @@ define(function () {
out.main_howitworks_p1 = 'CryptPad uses a variant of the <a href="https://en.wikipedia.org/wiki/Operational_transformation">Operational transformation</a> algorithm which is able to find distributed consensus using a Nakamoto Blockchain, a construct popularized by <a href="https://en.wikipedia.org/wiki/Bitcoin">Bitcoin</a>. This way the algorithm can avoid the need for a central server to resolve Operational Transform Edit Conflicts and without the need for resolving conflicts, the server can be kept unaware of the content which is being edited on the pad.';
out.main_about = 'About';
out.main_about_p1 = 'You can read more about our <a href="/privacy.html" title="">privacy policy</a> and <a href="/terms.html">terms of service</a>.';
out.main_about_p2 = 'If you have any questions or comments, you can <a href="https://twitter.com/cryptpad">tweet us</a>, open an issue <a href="https://github.com/xwiki-labs/cryptpad/issues/" title="our issue tracker">on github</a>, come say hi on irc (<a href="http://webchat.freenode.net?channels=%23cryptpad&uio=MT1mYWxzZSY5PXRydWUmMTE9Mjg3JjE1PXRydWUe7" title="freenode webchat">irc.freenode.net</a>), or <a href="mailto:research@xwiki.com">send us an email</a>.';
out.main_oops = '<strong>OOPS</strong> In order to do encryption in your browser, Javascript is really <strong>really</strong> required.';
out.table_type = 'Type';
out.table_link = 'Link';

@ -83,10 +83,9 @@ app.get('/api/config', function(req, res){
var host = req.headers.host.replace(/\:[0-9]+/, '');
res.setHeader('Content-Type', 'text/javascript');
res.send('define(' + JSON.stringify({
websocketPath: config.websocketPath,
websocketURL:'ws' + ((httpsOpts) ? 's' : '') + '://' + host + ':' +
websocketPort + '/cryptpad_websocket',
webrtcURL:'ws' + ((httpsOpts) ? 's' : '') + '://' + host + ':' +
websocketPort + '/cryptpad_webrtc',
}) + ');');
});

@ -1,6 +1,5 @@
require.config({ paths: { 'json.sortify': '/bower_components/json.sortify/dist/JSON.sortify' } });
define([
'/api/config?cb=' + Math.random().toString(16).substring(2),
'/customize/messages.js?app=code',
'/bower_components/chainpad-crypto/crypto.js',
'/bower_components/chainpad-netflux/chainpad-netflux.js',
@ -16,7 +15,7 @@ define([
'/bower_components/file-saver/FileSaver.min.js',
'/bower_components/jquery/dist/jquery.min.js',
'/customize/pad.js'
], function (Config, /*RTCode,*/ Messages, Crypto, Realtime, TextPatcher, Toolbar, JSONSortify, JsonOT, Cryptpad, Modes, Themes, Visible, Notify) {
], function (Messages, Crypto, Realtime, TextPatcher, Toolbar, JSONSortify, JsonOT, Cryptpad, Modes, Themes, Visible, Notify) {
var $ = window.jQuery;
var saveAs = window.saveAs;
@ -134,7 +133,7 @@ define([
var config = {
//initialState: Messages.codeInitialState,
initialState: '{}',
websocketURL: Config.websocketURL,
websocketURL: Cryptpad.getWebsocketURL(),
channel: secret.channel,
// our public key
validateKey: secret.keys.validateKey || undefined,
@ -146,6 +145,11 @@ define([
var canonicalize = function (t) { return t.replace(/\r\n/g, '\n'); };
var isDefaultTitle = function () {
var parsed = Cryptpad.parsePadUrl(window.location.href);
return Cryptpad.isDefaultName(parsed, document.title);
};
var initializing = true;
var onLocal = config.onLocal = function () {
@ -158,9 +162,11 @@ define([
// append the userlist to the hyperjson structure
obj.metadata = {
users: userList,
title: document.title
users: userList
};
if (!isDefaultTitle()) {
obj.metadata.title = document.title;
}
// set mode too...
obj.highlightMode = module.highlightMode;
@ -243,7 +249,7 @@ define([
var parsed = Cryptpad.parsePadUrl(window.location.href);
var name = Cryptpad.getDefaultName(parsed, []);
if (document.title.slice(0, name.length) === name) {
if (Cryptpad.isDefaultName(parsed, document.title)) {
return getHeadingText() || document.title;
} else {
return document.title || getHeadingText() || name;
@ -265,6 +271,32 @@ define([
saveAs(blob, filename);
});
};
var importText = function (content, file) {
var $bar = $('#pad-iframe')[0].contentWindow.$('#cme_toolbox');
var mode;
var mime = CodeMirror.findModeByMIME(file.type);
if (!mime) {
var ext = /.+\.([^.]+)$/.exec(file.name);
if (ext[1]) {
mode = CodeMirror.findModeByExtension(ext[1]);
}
} else {
mode = mime && mime.mode || null;
}
if (mode && Modes.list.some(function (o) { return o.mode === mode; })) {
setMode(mode);
$bar.find('#language-mode').val(mode);
} else {
console.log("Couldn't find a suitable highlighting mode: %s", mode);
setMode('text');
$bar.find('#language-mode').val('text');
}
editor.setValue(content);
onLocal();
};
var onInit = config.onInit = function (info) {
var $bar = $('#pad-iframe')[0].contentWindow.$('#cme_toolbox');
@ -285,113 +317,45 @@ define([
editHash = Cryptpad.getEditHashFromKeys(info.channel, secret.keys);
}
/* add a "change username" button */
getLastName(function (err, lastName) {
var $username = Cryptpad.createButton('username', true)
.click(function() {
Cryptpad.prompt(Messages.changeNamePrompt, lastName, function (newName) {
setName(newName);
});
});
var usernameCb = function (newName) {
setName (newName);
};
var $username = Cryptpad.createButton('username', true, {lastName: lastName}, usernameCb);
$rightside.append($username);
});
/* add an export button */
var $export = Cryptpad.createButton('export', true).click(exportText);
var $export = Cryptpad.createButton('export', true, {}, exportText);
$rightside.append($export);
if (!readOnly) {
/* add an import button */
var $import = Cryptpad.createButton('import', true)
.click(Cryptpad.importContent('text/plain', function (content, file) {
var mode;
var mime = CodeMirror.findModeByMIME(file.type);
if (!mime) {
var ext = /.+\.([^.]+)$/.exec(file.name);
if (ext[1]) {
mode = CodeMirror.findModeByExtension(ext[1]);
}
} else {
mode = mime && mime.mode || null;
}
if (mode && Modes.list.some(function (o) { return o.mode === mode; })) {
setMode(mode);
$bar.find('#language-mode').val(mode);
} else {
console.log("Couldn't find a suitable highlighting mode: %s", mode);
setMode('text');
$bar.find('#language-mode').val('text');
}
editor.setValue(content);
onLocal();
}));
var $import = Cryptpad.createButton('import', true, {}, importText);
$rightside.append($import);
}
/* add a rename button */
var $setTitle = Cryptpad.createButton('rename', true)
.click(function () {
var suggestion = suggestName();
Cryptpad.prompt(Messages.renamePrompt,
suggestion, function (title, ev) {
if (title === null) { return; }
Cryptpad.causesNamingConflict(title, function (err, conflicts) {
if (err) {
console.log("Unable to determine if name caused a conflict");
console.error(err);
return;
}
if (conflicts) {
Cryptpad.alert(Messages.renameConflict);
return;
}
Cryptpad.setPadTitle(title, function (err, data) {
if (err) {
console.log("unable to set pad title");
console.log(err);
return;
}
document.title = title;
onLocal();
});
});
});
});
$rightside.append($setTitle);
/* add a rename button */
var renameCb = function (err, title) {
if (err) { return; }
document.title = title;
onLocal();
};
var $setTitle = Cryptpad.createButton('rename', true, {suggestName: suggestName}, renameCb);
$rightside.append($setTitle);
}
/* add a forget button */
var $forgetPad = Cryptpad.createButton('forget', true)
.click(function () {
var href = window.location.href;
Cryptpad.confirm(Messages.forgetPrompt, function (yes) {
if (!yes) { return; }
Cryptpad.forgetPad(href, function (err, data) {
if (err) {
console.log("unable to forget pad");
console.error(err);
return;
}
var parsed = Cryptpad.parsePadUrl(href);
document.title = Cryptpad.getDefaultName(parsed, []);
});
});
});
var forgetCb = function (err, title) {
if (err) { return; }
document.title = title;
};
var $forgetPad = Cryptpad.createButton('forget', true, {}, forgetCb);
$rightside.append($forgetPad);
if (!readOnly && viewHash) {
/* add a 'links' button */
var $links = Cryptpad.createButton('readonly', true)
.click(function () {
var baseUrl = window.location.origin + window.location.pathname + '#';
var content = '<b>' + Messages.readonlyUrl + '</b><br><a>' + baseUrl + viewHash + '</a><br>';
Cryptpad.alert(content);
});
var $links = Cryptpad.createButton('readonly', true, {viewHash: viewHash});
$rightside.append($links);
}
@ -470,7 +434,7 @@ define([
return;
}
document.title = title || info.channel.slice(0, 8);
Cryptpad.rememberPad(title, function (err, data) {
Cryptpad.setPadTitle(title, function (err, data) {
if (err) {
console.log("Unable to set pad title");
console.error(err);
@ -657,11 +621,13 @@ define([
var hjson2 = {
content: localDoc,
metadata: {
users: userList,
title: document.title
users: userList
},
highlightMode: highlightMode,
};
if (!isDefaultTitle()) {
hjson2.metadata.title = document.title;
}
var shjson2 = stringify(hjson2);
if (shjson2 !== shjson) {
console.error("shjson2 !== shjson");

@ -1,14 +1,16 @@
define([
'/api/config?cb=' + Math.random().toString(16).slice(2),
'/customize/messages.js',
'/customize/store.js',
'/bower_components/chainpad-crypto/crypto.js',
'/bower_components/alertifyjs/dist/js/alertify.js',
'/bower_components/spin.js/spin.min.js',
'/common/clipboard.js',
'/customize/user.js',
'/bower_components/jquery/dist/jquery.min.js',
], function (Messages, Store, Crypto, Alertify, Spinner, User) {
], function (Config, Messages, Store, Crypto, Alertify, Spinner, Clipboard, User) {
/* This file exposes functionality which is specific to Cryptpad, but not to
any particular pad type. This includes functions for committing metadata
about pads to your local storage for future use and improved usability.
@ -36,6 +38,18 @@ define([
throw new Error("Store is not ready!");
};
var getWebsocketURL = common.getWebsocketURL = function () {
if (!Config.websocketPath) { return Config.websocketURL; }
var path = Config.websocketPath;
if (/^ws{1,2}:\/\//.test(path)) { return path; }
var protocol = window.location.protocol.replace(/http/, 'ws');
var host = window.location.host;
var url = protocol + '//' + host + path;
return url;
};
/*
* cb(err, proxy);
*/
@ -137,6 +151,26 @@ define([
};
var parseHash = common.parseHash = function (hash) {
var parsed = {};
if (hash.slice(0,1) !== '/' && hash.length >= 56) {
// Old hash
parsed.channel = hash.slice(0, 32);
parsed.key = hash.slice(32);
parsed.version = 0;
return parsed;
}
var hashArr = hash.split('/');
if (hashArr[1] && hashArr[1] === '1') {
parsed.version = 1;
parsed.mode = hashArr[2];
parsed.channel = hashArr[3];
parsed.key = hashArr[4];
parsed.present = hashArr[5] && hashArr[5] === 'present';
return parsed;
}
return;
};
var getEditHashFromKeys = common.getEditHashFromKeys = function (chanKey, keys) {
if (typeof keys === 'string') {
return chanKey + keys;
@ -295,6 +329,10 @@ define([
while (!isNameAvailable(name + ' - ' + untitledIndex, parsed, recentPads)) { untitledIndex++; }
return name + ' - ' + untitledIndex;
};
var isDefaultName = common.isDefaultName = function (parsed, title) {
var name = getDefaultName(parsed, []);
return title.slice(0, name.length) === name;
};
var makePad = function (href, title) {
var now = ''+new Date();
@ -397,51 +435,10 @@ define([
}, legacy);
};
// STORAGE
var rememberPad = common.rememberPad = window.rememberPad = function (title, cb) {
// bail out early
if (!/#/.test(window.location.hash)) { return; }
getRecentPads(function (err, pads) {
if (err) {
cb(err);
return;
}
var now = ''+new Date();
var href = window.location.href;
var parsed = parsePadUrl(window.location.href);
var isUpdate = false;
var out = pads.map(function (pad) {
var p = parsePadUrl(pad.href);
if (p.hash === parsed.hash && p.type === parsed.type) {
isUpdate = true;
// bump the atime
pad.atime = now;
pad.title = title;
pad.href = href;
}
return pad;
});
if (!isUpdate) {
// href, ctime, atime, title
out.push(makePad(href, title));
}
setRecentPads(out, function (err, data) {
cb(err, data);
});
});
};
// STORAGE
var setPadTitle = common.setPadTitle = function (name, cb) {
var href = window.location.href;
var parsed = parsePadUrl(href);
getRecentPads(function (err, recent) {
if (err) {
cb(err);
@ -449,10 +446,29 @@ define([
}
var contains;
var renamed = recent.map(function (pad) {
var p = parsePadUrl(pad.href);
if (p.hash === parsed.hash && p.type === parsed.type) {
if (p.type !== parsed.type) { return pad; }
var shouldUpdate = p.hash === parsed.hash;
// Version 1 : we have up to 4 differents hash for 1 pad, keep the strongest :
// Edit > Edit (present) > View > View (present)
var pHash = parseHash(p.hash);
var parsedHash = parseHash(parsed.hash);
if (!shouldUpdate && pHash.version === 1 && parsedHash.version === 1 && pHash.channel === parsedHash.channel) {
if (pHash.mode === 'view' && parsedHash.mode === 'edit') { shouldUpdate = true; }
else if (pHash.mode === parsedHash.mode && pHash.present) { shouldUpdate = true; }
else {
// Editing a "weaker" version of a stored hash : update the date and do not push the current hash
pad.atime = new Date().toISOString();
contains = true;
return pad;
}
}
if (shouldUpdate) {
contains = true;
// update the atime
pad.atime = new Date().toISOString();
@ -541,7 +557,23 @@ define([
Store.ready(function (err, store) {
common.store = env.store = store;
cb();
$(function() {
// Race condition : if document.body is undefined when alertify.js is loaded, Alertify
// won't work. We have to reset it now to make sure it uses a correct "body"
Alertify.reset();
if($('#pad-iframe').length) {
var $iframe = $('#pad-iframe');
var iframe = $iframe[0];
var iframeDoc = iframe.contentDocument || iframe.contentWindow.document;
if (iframeDoc.readyState === 'complete') {
cb();
return;
}
$iframe.load(cb);
return;
}
cb();
});
return;
/*
authorize(function (err, proxy) {
@ -610,7 +642,7 @@ define([
/*
* Buttons
*/
var createButton = common.createButton = function (type, rightside) {
var createButton = common.createButton = function (type, rightside, data, callback) {
var button;
var size = "17px";
switch (type) {
@ -620,6 +652,9 @@ define([
'class': "fa fa-download",
style: 'font:'+size+' FontAwesome'
});
if (callback) {
button.click(callback);
}
break;
case 'import':
button = $('<button>', {
@ -627,6 +662,11 @@ define([
'class': "fa fa-upload",
style: 'font:'+size+' FontAwesome'
});
if (callback) {
button.click(common.importContent('text/plain', function (content, file) {
callback(content, file);
}));
}
break;
case 'rename':
button = $('<button>', {
@ -635,6 +675,40 @@ define([
'class': "fa fa-bookmark cryptpad-rename",
style: 'font:'+size+' FontAwesome'
});
if (data && data.suggestName && callback) {
var suggestName = data.suggestName;
button.click(function() {
var suggestion = suggestName();
common.prompt(Messages.renamePrompt,
suggestion, function (title, ev) {
if (title === null) { return; }
common.causesNamingConflict(title, function (err, conflicts) {
if (err) {
console.log("Unable to determine if name caused a conflict");
console.error(err);
callback(err, title);
return;
}
if (conflicts) {
common.alert(Messages.renameConflict);
return;
}
common.setPadTitle(title, function (err, data) {
if (err) {
console.log("unable to set pad title");
console.log(err);
return;
}
callback(null, title);
});
});
});
});
}
break;
case 'forget':
button = $('<button>', {
@ -643,6 +717,25 @@ define([
'class': "fa fa-trash cryptpad-forget",
style: 'font:'+size+' FontAwesome'
});
if (callback) {
button.click(function() {
var href = window.location.href;
common.confirm(Messages.forgetPrompt, function (yes) {
if (!yes) { return; }
common.forgetPad(href, function (err, data) {
if (err) {
console.log("unable to forget pad");
console.error(err);
callback(err, null);
return;
}
var parsed = common.parsePadUrl(href);
callback(null, common.getDefaultName(parsed, []));
});
});
});
}
break;
case 'username':
button = $('<button>', {
@ -650,6 +743,14 @@ define([
'class': "fa fa-user",
style: 'font:'+size+' FontAwesome'
});
if (data && typeof data.lastName !== "undefined" && callback) {
var lastName = data.lastName;
button.click(function() {
common.prompt(Messages.changeNamePrompt, lastName, function (newName) {
callback(newName);
});
});
}
break;
case 'readonly':
button = $('<button>', {
@ -657,6 +758,37 @@ define([
'class': "fa fa-eye",
style: 'font:'+size+' FontAwesome'
});
if (data && data.viewHash) {
var viewHash = data.viewHash;
button.click(function() {
var baseUrl = window.location.origin + window.location.pathname + '#';
var url = baseUrl + viewHash;
var $content = $('<div>').text(Messages.readonlyUrl);
var $copy = $('<button>', {
id: "cryptpad-readonly-copy",
'class': "button action"
}).text(Messages.copyReadOnly);
var $open = $('<button>', {
id: "cryptpad-readonly-open",
'class': "button action"
}).text(Messages.openReadOnly);
$content.append('<br>').append($copy).append($open);
common.alert($content.html());
$("#cryptpad-readonly-copy").click(function() {
var success = Clipboard.copy(url);
if (success) {
common.log(Messages.shareSuccess);
common.findOKButton().click();
return;
}
});
$("#cryptpad-readonly-open").click(function() {
window.open(url);
});
if (callback) { callback(); }
});
}
break;
case 'present':
button = $('<button>', {
@ -679,7 +811,7 @@ define([
});
}
if (rightside) {
button.addClass('rightside-button')
button.addClass('rightside-button');
}
return button;
};

@ -180,9 +180,10 @@ define([
var lagLight = $('<div>', {
'class': 'lag'
});
var title;
if(lag) {
firstConnection = false;
var title = Messages.lag + ' : ' + lag + ' ms\n';
title = Messages.lag + ' : ' + lag + ' ms\n';
if (lag.waiting || lag > 1000) {
lagLight.addClass('lag-orange');
title += Messages.orangeLight;

@ -1,6 +1,5 @@
require.config({ paths: { 'json.sortify': '/bower_components/json.sortify/dist/JSON.sortify' } });
define([
'/api/config?cb=' + Math.random().toString(16).substring(2),
'/customize/messages.js?app=pad',
'/bower_components/chainpad-crypto/crypto.js',
'/bower_components/chainpad-netflux/chainpad-netflux.js',
@ -18,7 +17,7 @@ define([
'/bower_components/diff-dom/diffDOM.js',
'/bower_components/jquery/dist/jquery.min.js',
'/customize/pad.js'
], function (Config, Messages, Crypto, realtimeInput, Hyperjson,
], function (Messages, Crypto, realtimeInput, Hyperjson,
Toolbar, Cursor, JsonOT, TypingTest, JSONSortify, TextPatcher, Cryptpad,
Visible, Notify) {
var $ = window.jQuery;
@ -294,6 +293,33 @@ define([
});
};
var isDefaultTitle = function () {
var parsed = Cryptpad.parsePadUrl(window.location.href);
return Cryptpad.isDefaultName(parsed, document.title);
};
var getHeadingText = function () {
var text;
if (['h1', 'h2', 'h3'].some(function (t) {
var $header = $(inner).find(t + ':first-of-type');
if ($header.length && $header.text()) {
text = $header.text();
return true;
}
})) { return text; }
};
var suggestName = function () {
var parsed = Cryptpad.parsePadUrl(window.location.href);
var name = Cryptpad.getDefaultName(parsed, []);
if (Cryptpad.isDefaultName(parsed, document.title)) {
return getHeadingText() || document.title;
} else {
return document.title || getHeadingText() || name;
}
};
var DD = new DiffDom(diffOptions);
// apply patches, and try not to lose the cursor in the process!
@ -312,9 +338,11 @@ define([
hjson[3] = {
metadata: {
users: userList,
title: document.title
}
};
if (!isDefaultTitle()) {
hjson[3].metadata.title = document.title;
}
return stringify(hjson);
};
@ -323,7 +351,7 @@ define([
initialState: stringifyDOM(inner) || '{}',
// the websocket URL
websocketURL: Config.websocketURL,
websocketURL: Cryptpad.getWebsocketURL(),
// the channel we will communicate over
channel: secret.channel,
@ -461,28 +489,6 @@ define([
return new DOMParser().parseFromString(html, 'text/html');
};
var getHeadingText = function () {
var text;
if (['h1', 'h2', 'h3'].some(function (t) {
var $header = $(inner).find(t + ':first-of-type');
if ($header.length && $header.text()) {
text = $header.text();
return true;
}
})) { return text; }
};
var suggestName = module.suggestName = function () {
var parsed = Cryptpad.parsePadUrl(window.location.href);
var name = Cryptpad.getDefaultName(parsed, []);
if (document.title.slice(0, name.length) === name) {
return getHeadingText() || document.title;
} else {
return document.title || getHeadingText() || name;
}
};
var exportFile = function () {
var html = getHTML();
var suggestion = suggestName();
@ -493,6 +499,11 @@ define([
saveAs(blob, filename);
});
};
var importFile = function (content, file) {
var shjson = stringify(Hyperjson.fromDOM(domFromHTML(content).body));
applyHjson(shjson);
realtimeOptions.onLocal();
};
var onInit = realtimeOptions.onInit = function (info) {
var $bar = $('#pad-iframe')[0].contentWindow.$('#cke_1_toolbox');
@ -513,80 +524,45 @@ define([
editHash = Cryptpad.getEditHashFromKeys(info.channel, secret.keys);
}
/* add a "change username" button */
getLastName(function (err, lastName) {
var $username = Cryptpad.createButton('username', true)
.click(function() {
Cryptpad.prompt(Messages.changeNamePrompt, lastName, function (newName) {
setName(newName);
});
});
var usernameCb = function (newName) {
setName (newName);
};
var $username = Cryptpad.createButton('username', true, {lastName: lastName}, usernameCb);
$rightside.append($username);
});
/* add an export button */
var $export = Cryptpad.createButton('export', true).click(exportFile);
var $export = Cryptpad.createButton('export', true, {}, exportFile);
$rightside.append($export);
if (!readOnly) {
/* add an import button */
var $import = Cryptpad.createButton('import', true)
.click(Cryptpad.importContent('text/plain', function (content) {
var shjson = stringify(Hyperjson.fromDOM(domFromHTML(content).body));
applyHjson(shjson);
realtimeOptions.onLocal();
}));
var $import = Cryptpad.createButton('import', true, {}, importFile);
$rightside.append($import);
}
/* add a rename button */
var $rename = Cryptpad.createButton('rename', true)
.click(function () {
var suggestion = suggestName();
Cryptpad.prompt(Messages.renamePrompt, suggestion, function (title) {
if (title === null) { return; }
Cryptpad.causesNamingConflict(title, function (err, conflicts) {
if (conflicts) {
Cryptpad.alert(Messages.renameConflict);
return;
}
Cryptpad.setPadTitle(title, function (err, data) {
if (err) {
console.log("Couldn't set pad title");
console.error(err);
return;
}
document.title = title;
editor.fire('change');
});
});
});
});
$rightside.append($rename);
/* add a rename button */
var renameCb = function (err, title) {
if (err) { return; }
document.title = title;
editor.fire('change');
};
var $setTitle = Cryptpad.createButton('rename', true, {suggestName: suggestName}, renameCb);
$rightside.append($setTitle);
}
/* add a forget button */
var $forgetPad = Cryptpad.createButton('forget', true)
.click(function () {
var href = window.location.href;
Cryptpad.confirm(Messages.forgetPrompt, function (yes) {
if (!yes) { return; }
Cryptpad.forgetPad(href, function (err, data) {
var parsed = Cryptpad.parsePadUrl(href);
document.title = Cryptpad.getDefaultName(parsed, []);
});
});
});
var forgetCb = function (err, title) {
if (err) { return; }
document.title = title;
};
var $forgetPad = Cryptpad.createButton('forget', true, {}, forgetCb);
$rightside.append($forgetPad);
if (!readOnly && viewHash) {
/* add a 'links' button */
var $links = Cryptpad.createButton('readonly', true)
.click(function () {
var baseUrl = window.location.origin + window.location.pathname + '#';
var content = '<b>' + Messages.readonlyUrl + '</b><br><a>' + baseUrl + viewHash + '</a><br>';
Cryptpad.alert(content);
});
var $links = Cryptpad.createButton('readonly', true, {viewHash: viewHash});
$rightside.append($links);
}
@ -602,7 +578,7 @@ define([
return;
}
document.title = title || info.channel.slice(0, 8);
Cryptpad.rememberPad(title, function (err, data) {
Cryptpad.setPadTitle(title, function (err, data) {
if (err) {
console.log("Couldn't remember pad");
console.error(err);

@ -456,6 +456,21 @@ define([
module.tabNotification = Notify.tab(1000, 10);
};
var updateTitle = function (newTitle) {
if (newTitle === document.title) { return; }
// Change the title now, and set it back to the old value if there is an error
var oldTitle = document.title;
document.title = newTitle;
Cryptpad.setPadTitle(newTitle, function (err, data) {
if (err) {
console.log("Couldn't set pad title");
console.error(err);
document.title = oldTitle;
return;
}
});
};
// don't make changes until the interface is ready
setEditable(false);
@ -464,9 +479,12 @@ define([
module.ready = true;
var proxy = module.rt.proxy;
var First = false;
if (proxy.metadata && proxy.metadata.title) {
updateTitle(proxy.metadata.title);
}
// ensure that proxy.info and proxy.table exist
['info', 'table'].forEach(function (k) {
if (typeof(proxy[k]) === 'undefined') {
@ -627,19 +645,8 @@ define([
}
})
.on('change', ['metadata'], function (o, n, p) {
var newTitle = n.title;
if (newTitle === document.title) { return; }
// Change the title now, and set it back to the old value if there is an error
var oldTitle = document.title;
document.title = newTitle;
Cryptpad.setPadTitle(newTitle, function (err, data) {
if (err) {
console.log("Couldn't set pad title");
console.error(err);
document.title = oldTitle;
return;
}
});
var newTitle = proxy.metadata.title;
updateTitle(newTitle);
})
.on('remove', [], function (o, p, root) {
//console.log("remove: (%s, [%s])", o, p.join(', '));
@ -704,60 +711,34 @@ define([
}
};
$toolbar.append(Button({
id: 'forget',
'class': 'forget button action',
title: Messages.forgetButtonTitle,
}).text(Messages.forgetButton).click(function () {
var href = window.location.href;
Cryptpad.confirm(Messages.forgetPrompt, function (yes) {
if (!yes) { return; }
Cryptpad.forgetPad(href, function (err, data) {
if (err) {
console.log("unable to forget pad");
console.error(err);
return;
}
var parsed = Cryptpad.parsePadUrl(href);
document.title = Cryptpad.getDefaultName(parsed, []);
});
});
}));
$toolbar.append(Button({
id: 'rename',
'class': 'rename button action',
title: Messages.renameButtonTitle,
}).text(Messages.renameButton).click(function () {
var suggestion = suggestName();
Cryptpad.prompt(Messages.renamePrompt,
suggestion, function (title, ev) {
if (title === null) { return; }
Cryptpad.causesNamingConflict(title, function (err, conflicts) {
if (conflicts) {
Cryptpad.alert(Messages.renameConflict);
return;
}
Cryptpad.setPadTitle(title, function (err, data) {
if (err) {
console.log("unable to set pad title");
console.error(err);
return;
}
document.title = title;
module.tabNotification.update(title);
var proxy = module.rt.proxy;
if (proxy.metadata) {
proxy.metadata.title = title;
}
else {
proxy.metadata = {title: title};
}
});
});
});
}));
/* add a forget button */
var forgetCb = function (err, title) {
if (err) { return; }
document.title = title;
};
var $forgetPad = Cryptpad.createButton('forget', false, {}, forgetCb)
.text(Messages.forgetButton)
.removeAttr('style')
.attr('class', 'action button forget');
$toolbar.append($forgetPad);
/* add a rename button */
var renameCb = function (err, title) {
if (err) { return; }
document.title = title;
var proxy = module.rt.proxy;
if (proxy.metadata) {
proxy.metadata.title = title;
}
else {
proxy.metadata = {title: title};
}
};
var $setTitle = Cryptpad.createButton('rename', true, {suggestName: suggestName}, renameCb)
.text(Messages.renameButton)
.removeAttr('style')
.attr('class', 'action button rename');
$toolbar.append($setTitle);
if (!readOnly) {
$toolbar.append(Button({
@ -774,16 +755,10 @@ define([
if (!readOnly && module.viewHash) {
/* add a 'links' button */
var $links = $('<button>', {
title: Messages.getViewButtonTitle
})
var $links = Cryptpad.createButton('readonly', true, {viewHash: module.viewHash})
.text(Messages.getViewButton)
.addClass('button action')
.click(function () {
var baseUrl = window.location.origin + window.location.pathname + '#';
var content = '<b>' + Messages.readonlyUrl + '</b><br><a>' + baseUrl + module.viewHash + '</a><br>';
Cryptpad.alert(content);
});
.removeAttr('style')
.attr('class', 'action button readonly');
$toolbar.append($links);
}
@ -890,7 +865,7 @@ define([
};
var config = {
websocketURL: Config.websocketURL,
websocketURL: Cryptpad.getWebsocketURL(),
channel: secret.channel,
data: {},
// our public key
@ -923,7 +898,7 @@ define([
Cryptpad.getPadTitle(function (err, title) {
title = document.title = title || info.channel.slice(0, 8);
Cryptpad.rememberPad(title, function (err, data) {
Cryptpad.setPadTitle(title, function (err, data) {
if (err) {
console.log("unable to remember pad");
console.log(err);

@ -1,6 +1,5 @@
require.config({ paths: { 'json.sortify': '/bower_components/json.sortify/dist/JSON.sortify' } });
define([
'/api/config?cb=' + Math.random().toString(16).substring(2),
'/customize/messages.js?app=code',
'/bower_components/chainpad-crypto/crypto.js',
'/bower_components/chainpad-netflux/chainpad-netflux.js',
@ -14,11 +13,10 @@ define([
'/common/visible.js',
'/common/notify.js',
'/slide/slide.js',
'/common/clipboard.js',
'/bower_components/file-saver/FileSaver.min.js',
'/bower_components/jquery/dist/jquery.min.js',
'/customize/pad.js'
], function (Config, /*RTCode,*/ Messages, Crypto, Realtime, TextPatcher, Toolbar, JSONSortify, JsonOT, Cryptpad, Modes, Themes, Visible, Notify, Slide, Clipboard) {
], function (Messages, Crypto, Realtime, TextPatcher, Toolbar, JSONSortify, JsonOT, Cryptpad, Modes, Themes, Visible, Notify, Slide) {
var $ = window.jQuery;
var saveAs = window.saveAs;
@ -28,12 +26,12 @@ define([
TextPatcher: TextPatcher,
Slide: Slide,
};
var APP = window.APP;
Cryptpad.styleAlerts();
module.spinner.show();
var ifrw = module.ifrw = $('#pad-iframe')[0].contentWindow;
var stringify = function (obj) {
return JSONSortify(obj);
};
@ -47,6 +45,7 @@ define([
};
$(function () {
var ifrw = module.ifrw = $('#pad-iframe')[0].contentWindow;
var toolbar;
var secret = Cryptpad.getSecrets();
@ -127,7 +126,7 @@ define([
var $modal = $pad.contents().find('#modal');
var $content = $pad.contents().find('#content');
Slide.setModal($modal, $content, $pad);
Slide.setModal($modal, $content, $pad, ifrw);
var enterPresentationMode = function (shouldLog) {
Slide.show(true, $textarea.val());
@ -169,7 +168,7 @@ define([
var config = {
//initialState: Messages.codeInitialState,
initialState: '{}',
websocketURL: Config.websocketURL,
websocketURL: Cryptpad.getWebsocketURL(),
channel: secret.channel,
// our public key
validateKey: secret.keys.validateKey || undefined,
@ -181,6 +180,11 @@ define([
var canonicalize = function (t) { return t.replace(/\r\n/g, '\n'); };
var isDefaultTitle = function () {
var parsed = Cryptpad.parsePadUrl(window.location.href);
return Cryptpad.isDefaultName(parsed, APP.title);
};
var initializing = true;
var onLocal = config.onLocal = function () {
@ -193,10 +197,11 @@ define([
// append the userlist to the hyperjson structure
obj.metadata = {
users: userList,
title: APP.title
users: userList
};
if (!isDefaultTitle()) {
obj.metadata.title = APP.title;
}
// stringify the json and send it into chainpad
var shjson = stringify(obj);
@ -258,7 +263,7 @@ define([
var parsed = Cryptpad.parsePadUrl(window.location.href);
var name = Cryptpad.getDefaultName(parsed, []);
if (APP.title.slice(0, name.length) === name) {
if (Cryptpad.isDefaultName(parsed, APP.title)) {
return getHeadingText() || APP.title;
} else {
return APP.title || getHeadingText() || name;
@ -280,6 +285,32 @@ define([
saveAs(blob, filename);
});
};
var importText = function (content, file) {
var $bar = $('#pad-iframe')[0].contentWindow.$('#cme_toolbox');
var mode;
var mime = CodeMirror.findModeByMIME(file.type);
if (!mime) {
var ext = /.+\.([^.]+)$/.exec(file.name);
if (ext[1]) {
mode = CodeMirror.findModeByExtension(ext[1]);
}
} else {
mode = mime && mime.mode || null;
}
if (mode && Modes.list.some(function (o) { return o.mode === mode; })) {
setMode(mode);
$bar.find('#language-mode').val(mode);
} else {
console.log("Couldn't find a suitable highlighting mode: %s", mode);
setMode('text');
$bar.find('#language-mode').val('text');
}
editor.setValue(content);
onLocal();
};
var onInit = config.onInit = function (info) {
var $bar = $('#pad-iframe')[0].contentWindow.$('#cme_toolbox');
@ -300,116 +331,47 @@ define([
editHash = Cryptpad.getEditHashFromKeys(info.channel, secret.keys);
}
/* add a "change username" button */
getLastName(function (err, lastName) {
var $username = Cryptpad.createButton('username', true)
.click(function() {
Cryptpad.prompt(Messages.changeNamePrompt, lastName, function (newName) {
setName(newName);
});
});
var usernameCb = function (newName) {
setName (newName);
};
var $username = Cryptpad.createButton('username', true, {lastName: lastName}, usernameCb);
$rightside.append($username);
});
/* add an export button */
var $export = Cryptpad.createButton('export', true).click(exportText);
var $export = Cryptpad.createButton('export', true, {}, exportText);
$rightside.append($export);
if (!readOnly) {
/* add an import button */
var $import = Cryptpad.createButton('import', true)
.click(Cryptpad.importContent('text/plain', function (content, file) {
var mode;
var mime = CodeMirror.findModeByMIME(file.type);
if (!mime) {
var ext = /.+\.([^.]+)$/.exec(file.name);
if (ext[1]) {
mode = CodeMirror.findModeByExtension(ext[1]);
}
} else {
mode = mime && mime.mode || null;
}
if (mode && Modes.list.some(function (o) { return o.mode === mode; })) {
setMode(mode);
$bar.find('#language-mode').val(mode);
} else {
console.log("Couldn't find a suitable highlighting mode: %s", mode);
setMode('text');
$bar.find('#language-mode').val('text');
}
editor.setValue(content);
onLocal();
}));
var $import = Cryptpad.createButton('import', true, {}, importText);
$rightside.append($import);
}
/* add a rename button */
var $setTitle = Cryptpad.createButton('rename', true)
.click(function () {
var suggestion = suggestName();
Cryptpad.prompt(Messages.renamePrompt,
suggestion, function (title, ev) {
if (title === null) { return; }
Cryptpad.causesNamingConflict(title, function (err, conflicts) {
if (err) {
console.log("Unable to determine if name caused a conflict");
console.error(err);
return;
}
if (conflicts) {
Cryptpad.alert(Messages.renameConflict);
return;
}
Cryptpad.setPadTitle(title, function (err, data) {
if (err) {
console.log("unable to set pad title");
console.log(err);
return;
}
APP.title = title;
setTabTitle();
onLocal();
});
});
});
});
$rightside.append($setTitle);
/* add a rename button */
var renameCb = function (err, title) {
if (err) { return; }
APP.title = title;
setTabTitle();
onLocal();
};
var $setTitle = Cryptpad.createButton('rename', true, {suggestName: suggestName}, renameCb);
$rightside.append($setTitle);
}
/* add a forget button */
var $forgetPad = Cryptpad.createButton('forget', true)
.click(function () {
var href = window.location.href;
Cryptpad.confirm(Messages.forgetPrompt, function (yes) {
if (!yes) { return; }
Cryptpad.forgetPad(href, function (err, data) {
if (err) {
console.log("unable to forget pad");
console.error(err);
return;
}
var parsed = Cryptpad.parsePadUrl(href);
APP.title = Cryptpad.getDefaultName(parsed, []);
setTabTitle();
});
});
});
var forgetCb = function (err, title) {
if (err) { return; }
APP.title = title;
setTabTitle();
};
var $forgetPad = Cryptpad.createButton('forget', true, {}, forgetCb);
$rightside.append($forgetPad);
if (!readOnly && viewHash) {
/* add a 'links' button */
var $links = Cryptpad.createButton('readonly', true)
.click(function () {
var baseUrl = window.location.origin + window.location.pathname + '#';
var url = baseUrl + viewHash + '/present';
var content = '<b>' + Messages.readonlyUrl + '</b><br><a href="' + url + '" target="_blank" rel="noopener noreferrer">' + url + '</a><br>';
Cryptpad.alert(content);
});
var $links = Cryptpad.createButton('readonly', true, {viewHash: viewHash + '/present'});
$rightside.append($links);
}
@ -429,7 +391,7 @@ define([
}
$rightside.append($leavePresent);
$language = $('<span>', {
var $language = $('<span>', {
'style': "margin-right: 10px;"
}).text(Messages.type.slide + " (Markdown)");
$rightside.append($language);
@ -485,7 +447,7 @@ define([
return;
}
document.title = APP.title = title || info.channel.slice(0, 8);
Cryptpad.rememberPad(title, function (err, data) {
Cryptpad.setPadTitle(title, function (err, data) {
if (err) {
console.log("Unable to set pad title");
console.error(err);
@ -684,11 +646,13 @@ define([
var hjson2 = {
content: localDoc,
metadata: {
users: userList,
title: APP.title
users: userList
},
highlightMode: highlightMode,
};
if (!isDefaultTitle()) {
hjson2.metadata.title = APP.title;
}
var shjson2 = stringify(hjson2);
if (shjson2 !== shjson) {
console.error("shjson2 !== shjson");

@ -14,14 +14,15 @@ define([
content: [],
changeHandlers: [],
};
var ifrw = $('#pad-iframe')[0].contentWindow;
var ifrw;
var $modal;
var $content;
var $pad;
Slide.setModal = function ($m, $c, $p) {
Slide.setModal = function ($m, $c, $p, iframe) {
$modal = Slide.$modal = $m;
$content = Slide.$content = $c;
$pad = Slide.$pad = $p;
ifrw = Slide.ifrw = iframe;
};
Slide.onChange = function (f) {

Loading…
Cancel
Save