Merge branch 'staging' into exportFolderTests

This commit is contained in:
ClemDee
2019-08-14 14:58:38 +02:00
20 changed files with 514 additions and 189 deletions

View File

@@ -230,9 +230,15 @@ define([
if (!Visible.currently()) { to = window.setTimeout(interval, Thumb.UPDATE_FIRST); }
};
var addThumbnail = function (err, thumb, $span, cb) {
var u8 = Nacl.util.decodeBase64(thumb.split(',')[1]);
var blob = new Blob([u8], {
type: 'image/png'
});
var url = URL.createObjectURL(blob);
var img = new Image();
img.src = thumb.slice(0,5) === 'data:' ? thumb : 'data:image/png;base64,'+thumb;
img.src = url;
$span.find('.cp-icon').hide();
$span.prepend(img);
cb($(img));

View File

@@ -573,9 +573,9 @@ define([
onFriendShare.reg(saveValue);
var getLinkValue = function (initValue) {
var val = initValue || {};
var edit = initValue ? val.edit : Util.isChecked($(link).find('#cp-share-editable-true'));
var embed = initValue ? val.embed : Util.isChecked($(link).find('#cp-share-embed'));
var present = initValue ? val.present : Util.isChecked($(link).find('#cp-share-present'));
var edit = val.edit !== undefined ? val.edit : Util.isChecked($(link).find('#cp-share-editable-true'));
var embed = val.embed !== undefined ? val.embed : Util.isChecked($(link).find('#cp-share-embed'));
var present = val.present !== undefined ? val.present : Util.isChecked($(link).find('#cp-share-present'));
var hash = (!hashes.viewHash || (edit && hashes.editHash)) ? hashes.editHash : hashes.viewHash;
var href = origin + pathname + '#' + hash;
@@ -2104,6 +2104,9 @@ define([
};
UIElements.createNewPadModal = function (common) {
// if in drive, show new pad modal instead
if ($("body.cp-app-drive").length !== 0) { return void $(".cp-app-drive-element-row.cp-app-drive-new-ghost").click(); }
var $modal = UIElements.createModal({
id: 'cp-app-toolbar-creation-dialog',
$body: $('body')
@@ -2766,8 +2769,12 @@ define([
UIElements.displayCrowdfunding(common);
modal.delete();
});
var waitingForStoringCb = false;
$(store).click(function () {
if (waitingForStoringCb) { return; }
waitingForStoringCb = true;
common.getSframeChannel().query("Q_AUTOSTORE_STORE", null, function (err, obj) {
waitingForStoringCb = false;
var error = err || (obj && obj.error);
if (error) {
if (error === 'E_OVER_LIMIT') {
@@ -2854,11 +2861,27 @@ define([
'aria-labelledBy': 'dropdownMenu',
'style': 'display:block;position:static;margin-bottom:5px;'
}, [
h('li', h('a.dropdown-item', {
h('li', h('a.cp-app-code-context-saveindrive.dropdown-item', {
'tabindex': '-1',
}, Messages.pad_mediatagImport))
'data-icon': "fa-cloud-upload",
}, Messages.pad_mediatagImport)),
h('li', h('a.cp-app-code-context-download.dropdown-item', {
'tabindex': '-1',
'data-icon': "fa-download",
}, Messages.download_mt_button)),
])
]);
// create the icon for each contextmenu option
$(menu).find("li a.dropdown-item").each(function (i, el) {
var $icon = $("<span>");
if ($(el).attr('data-icon')) {
var font = $(el).attr('data-icon').indexOf('cptools') === 0 ? 'cptools' : 'fa';
$icon.addClass(font).addClass($(el).attr('data-icon'));
} else {
$icon.text($(el).text());
}
$(el).prepend($icon);
});
var m = createContextMenu(menu);
mediatagContextMenu = m;
@@ -2868,7 +2891,13 @@ define([
e.stopPropagation();
m.hide();
var $mt = $menu.data('mediatag');
common.importMediaTag($mt);
if ($(this).hasClass("cp-app-code-context-saveindrive")) {
common.importMediaTag($mt);
}
else if ($(this).hasClass("cp-app-code-context-download")) {
var media = $mt[0]._mediaObject;
window.saveAs(media._blob.content, media.name);
}
});
return m;

View File

@@ -319,6 +319,12 @@ define([], function () {
return window.innerHeight < 800 || window.innerWidth < 800;
};
Util.stripTags = function (text) {
var div = document.createElement("div");
div.innerHTML = text;
return div.innerText;
};
return Util;
});
}(self));

View File

@@ -52,11 +52,12 @@ define([
Object.keys(b).forEach(function (k) { a[k] = b[k]; });
};
var get = function (hash, cb, opt) {
var get = function (hash, cb, opt, progress) {
if (typeof(cb) !== 'function') {
throw new Error('Cryptget expects a callback');
}
opt = opt || {};
progress = progress || function () {};
var config = makeConfig(hash, opt);
var Session = { cb: cb, hasNetwork: Boolean(opt.network) };
@@ -65,6 +66,7 @@ define([
var rt = Session.session = info.realtime;
Session.network = info.network;
Session.leave = info.leave;
progress(1);
finish(Session, void 0, rt.getUserDoc());
};
@@ -72,6 +74,16 @@ define([
finish(Session, info.error);
};
// We use the new onMessage handler to compute the progress:
// we should receive 2 checkpoints max, so 100 messages max
// We're going to consider that 1 message = 1%, and we'll send 100%
// at the end
var i = 0;
config.onMessage = function () {
i++;
progress(Math.min(0.99, i/100));
};
overwrite(config, opt);
Session.realtime = CPNetflux.start(config);

View File

@@ -254,8 +254,12 @@ define([
common.clearOwnedChannel = function (channel, cb) {
postMessage("CLEAR_OWNED_CHANNEL", channel, cb);
};
common.removeOwnedChannel = function (channel, cb) {
postMessage("REMOVE_OWNED_CHANNEL", channel, cb);
// "force" allows you to delete your drive ID
common.removeOwnedChannel = function (channel, cb, force) {
postMessage("REMOVE_OWNED_CHANNEL", {
channel: channel,
force: force
}, cb);
};
common.getDeletedPads = function (data, cb) {
@@ -950,7 +954,7 @@ define([
common.logoutFromAll(waitFor(function () {
postMessage("DISCONNECT");
}));
}));
}), true);
}
}).nThen(function (waitFor) {
if (!oldIsOwned) {

View File

@@ -15,6 +15,7 @@ define([
var DiffDOM = window.diffDOM;
var renderer = new Marked.Renderer();
var restrictedRenderer = new Marked.Renderer();
var Mermaid = {
init: function () {}
@@ -61,13 +62,18 @@ define([
return h('div.cp-md-toc', content).outerHTML;
};
DiffMd.render = function (md, sanitize) {
DiffMd.render = function (md, sanitize, restrictedMd) {
Marked.setOptions({
renderer: restrictedMd ? restrictedRenderer : renderer,
});
var r = Marked(md, {
sanitize: sanitize
});
// Add Table of Content
r = r.replace(/<div class="cp-md-toc"><\/div>/g, getTOC());
if (!restrictedMd) {
r = r.replace(/<div class="cp-md-toc"><\/div>/g, getTOC());
}
toc = [];
return r;
@@ -83,12 +89,7 @@ define([
return defaultCode.apply(renderer, arguments);
}
};
var stripTags = function (text) {
var div = document.createElement("div");
div.innerHTML = text;
return div.innerText;
};
restrictedRenderer.code = renderer.code;
renderer.heading = function (text, level) {
var i = 0;
@@ -105,10 +106,13 @@ define([
toc.push({
level: level,
id: id,
title: stripTags(text)
title: Util.stripTags(text)
});
return "<h" + level + " id=\"" + id + "\"><a href=\"#" + id + "\" class=\"anchor\"></a>" + text + "</h" + level + ">";
};
restrictedRenderer.heading = function (text) {
return text;
};
// Tasks list
var checkedTaskItemPtn = /^\s*(<p>)?\[[xX]\](<\/p>)?\s*/;
@@ -138,6 +142,13 @@ define([
var cls = (isCheckedTaskItem || isUncheckedTaskItem || hasBogusInput) ? ' class="todo-list-item"' : '';
return '<li'+ cls + '>' + text + '</li>\n';
};
restrictedRenderer.listitem = function (text) {
if (bogusCheckPtn.test(text)) {
text = text.replace(bogusCheckPtn, '');
}
return '<li>' + text + '</li>\n';
};
renderer.image = function (href, title, text) {
if (href.slice(0,6) === '/file/') {
// DEPRECATED
@@ -162,12 +173,19 @@ define([
out += this.options.xhtml ? '/>' : '>';
return out;
};
restrictedRenderer.image = renderer.image;
var renderParagraph = function (p) {
return /<media\-tag[\s\S]*>/i.test(p)? p + '\n': '<p>' + p + '</p>\n';
};
renderer.paragraph = function (p) {
if (p === '[TOC]') {
return '<p><div class="cp-md-toc"></div></p>';
}
return /<media\-tag[\s\S]*>/i.test(p)? p + '\n': '<p>' + p + '</p>\n';
return renderParagraph(p);
};
restrictedRenderer.paragraph = function (p) {
return renderParagraph(p);
};
var MutationObserver = window.MutationObserver;

View File

@@ -30,9 +30,22 @@
};
var isplainTextFile = function (metadata) {
// does its type begins with "text/"
if (metadata.type.indexOf("text/") === 0) { return true; }
// no type and no file extension -> let's guess it's plain text
var parsedName = /^(\.?.+?)(\.[^.]+)?$/.exec(metadata.name) || [];
if (!metadata.type && !parsedName[2]) { return true; }
// other exceptions
if (metadata.type === 'application/x-javascript') { return true; }
if (metadata.type === 'application/xml') { return true; }
return false;
};
// Default config, can be overriden per media-tag call
var config = {
allowed: [
'text/plain',
'image/png',
'image/jpeg',
'image/jpg',
@@ -53,6 +66,23 @@
text: "Download"
},
Plugins: {
/**
* @param {object} metadataObject {name, metadatatype, owners} containing metadata of the file
* @param {strint} url Url of the blob object
* @param {Blob} content Blob object containing the data of the file
* @param {object} cfg Object {Plugins, allowed, download, pdf} containing infos about plugins
* @param {function} cb Callback function: (err, pluginElement) => {}
*/
text: function (metadata, url, content, cfg, cb) {
var plainText = document.createElement('div');
plainText.className = "plain-text-reader";
var reader = new FileReader();
reader.addEventListener('loadend', function (e) {
plainText.innerText = e.srcElement.result;
cb(void 0, plainText);
});
reader.readAsText(content);
},
image: function (metadata, url, content, cfg, cb) {
var img = document.createElement('img');
img.setAttribute('src', url);
@@ -271,6 +301,9 @@
var blob = decrypted.content;
var mediaType = getType(mediaObject, metadata, cfg);
if (isplainTextFile(metadata)) {
mediaType = "text";
}
if (mediaType === 'application') {
mediaType = mediaObject.extension;

View File

@@ -151,7 +151,7 @@ define([
});
try {
var $d = $(d);
DiffMd.apply(DiffMd.render(md || '', true), $d, common);
DiffMd.apply(DiffMd.render(md || '', true, true), $d, common);
$d.addClass("cp-app-contacts-content");
// override link clicking, because we're in an iframe
@@ -197,7 +197,7 @@ define([
var getChat = function (id) {
return $messages.find(dataQuery(id));
};
var scrollChatToBottom = function () {
var $messagebox = $('.cp-app-contacts-messages');
$messagebox.scrollTop($messagebox[0].scrollHeight);

View File

@@ -99,6 +99,7 @@ define(['json.sortify'], function (Sortify) {
var addAuthor = function () {
if (!meta.user || !meta.user.netfluxId || !priv || !priv.edPublic) { return; }
var authors = metadataObj.authors || {};
var old = Sortify(authors);
if (!authors[priv.edPublic]) {
authors[priv.edPublic] = {
nId: [meta.user.netfluxId],
@@ -110,9 +111,11 @@ define(['json.sortify'], function (Sortify) {
authors[priv.edPublic].nId.push(meta.user.netfluxId);
}
}
metadataObj.authors = authors;
metadataLazyObj.authors = JSON.parse(JSON.stringify(authors));
change();
if (Sortify(authors) !== old) {
metadataObj.authors = authors;
metadataLazyObj.authors = JSON.parse(JSON.stringify(authors));
change();
}
};
var netfluxId;

View File

@@ -34,7 +34,7 @@ define([
var sendDriveEvent = function () {};
var registerProxyEvents = function () {};
var storeHash;
var storeHash, storeChannel;
var store = window.CryptPad_AsyncStore = {
modules: {}
@@ -239,6 +239,20 @@ define([
Store.removeOwnedChannel = function (clientId, data, cb) {
if (!store.rpc) { return void cb({error: 'RPC_NOT_READY'}); }
// "data" used to be a string (channelID), now it can also be an object
// data.force tells us we can safely remove the drive ID
var channel = data;
var force = false;
if (data && typeof(data) === "object") {
channel = data.channel;
force = data.force;
}
if (channel === storeChannel && !force) {
return void cb({error: 'User drive removal blocked!'});
}
store.rpc.removeOwnedChannel(data, function (err) {
cb({error:err});
});
@@ -573,7 +587,10 @@ define([
}));
}).nThen(function (waitFor) {
// Delete Drive
Store.removeOwnedChannel(clientId, secret.channel, waitFor());
Store.removeOwnedChannel(clientId, {
channel: secret.channel,
force: true
}, waitFor());
}).nThen(function () {
store.network.disconnect();
cb({
@@ -786,6 +803,7 @@ define([
var h = p.hashData;
if (AppConfig.disableAnonymousStore && !store.loggedIn) { return void cb(); }
if (p.type === "debug") { return void cb(); }
var channelData = Store.channels && Store.channels[channel];
@@ -1090,7 +1108,6 @@ define([
var channels = Store.channels = store.channels = {};
Store.joinPad = function (clientId, data) {
console.log('joining', data.channel);
var isNew = typeof channels[data.channel] === "undefined";
var channel = channels[data.channel] = channels[data.channel] || {
queue: [],
@@ -1915,6 +1932,7 @@ define([
}
// No password for drive
var secret = Hash.getSecrets('drive', hash);
storeChannel = secret.channel;
var listmapConfig = {
data: {},
websocketURL: NetConfig.getWebsocketURL(),

View File

@@ -99,9 +99,17 @@ define([
// lines beginning with a hash are potentially valuable
// works for markdown, python, bash, etc.
var hash = /^#+(.*?)$/;
var hashAndLink = /^#+\s*\[(.*?)\]\(.*\)\s*$/;
if (hash.test(line)) {
// test for link inside the title, and set text just to the name of the link
if (hashAndLink.test(line)) {
line.replace(hashAndLink, function (a, one) {
text = Util.stripTags(one);
});
return true;
}
line.replace(hash, function (a, one) {
text = one;
text = Util.stripTags(one);
});
return true;
}
@@ -387,21 +395,32 @@ define([
exp.mkIndentSettings = function (metadataMgr) {
var setIndentation = function (units, useTabs, fontSize, spellcheck) {
if (typeof(units) !== 'number') { return; }
var doc = editor.getDoc();
editor.setOption('indentUnit', units);
editor.setOption('tabSize', units);
editor.setOption('indentWithTabs', useTabs);
editor.setOption('spellcheck', spellcheck);
if (!useTabs) {
editor.setOption("extraKeys", {
Tab: function() {
editor.replaceSelection(Array(units + 1).join(" "));
editor.setOption("extraKeys", {
Tab: function() {
if (doc.somethingSelected()) {
editor.execCommand("indentMore");
}
});
} else {
editor.setOption("extraKeys", {
Tab: undefined,
});
}
else {
if (!useTabs) { editor.execCommand("insertSoftTab"); }
else { editor.execCommand("insertTab"); }
}
},
"Shift-Tab": function () {
editor.execCommand("indentLess");
},
"Backspace": function () {
var cursor = doc.getCursor();
var line = doc.getLine(cursor.line);
if (line.substring(0, cursor.ch).trim() === "") { editor.execCommand("indentLess"); }
else { editor.execCommand("delCharBefore"); }
},
});
$('.CodeMirror').css('font-size', fontSize+'px');
};

View File

@@ -838,13 +838,6 @@ define([
Cryptpad.setLanguage(data, cb);
});
sframeChan.on('Q_CLEAR_OWNED_CHANNEL', function (channel, cb) {
Cryptpad.clearOwnedChannel(channel, cb);
});
sframeChan.on('Q_REMOVE_OWNED_CHANNEL', function (channel, cb) {
Cryptpad.removeOwnedChannel(channel, cb);
});
sframeChan.on('Q_GET_ALL_TAGS', function (data, cb) {
Cryptpad.listAllTags(function (err, tags) {
cb({