Merge branch 'staging' into newCk
This commit is contained in:
@@ -20,5 +20,25 @@ define([], function () {
|
||||
};
|
||||
}
|
||||
|
||||
var failStore = function () {
|
||||
console.error(new Error('wut'));
|
||||
require(['jquery'], function ($) {
|
||||
$.ajax({
|
||||
type: 'HEAD',
|
||||
url: '/common/feedback.html?NO_LOCALSTORAGE=' + (+new Date()),
|
||||
});
|
||||
});
|
||||
window.alert("CryptPad needs localStorage to work, try a different browser");
|
||||
};
|
||||
|
||||
try {
|
||||
var test_key = 'localStorage_test';
|
||||
var testval = Math.random().toString();
|
||||
localStorage.setItem(test_key, testval);
|
||||
if (localStorage.getItem(test_key) !== testval) {
|
||||
failStore();
|
||||
}
|
||||
} catch (e) { console.error(e); failStore(); }
|
||||
|
||||
require([document.querySelector('script[data-bootload]').getAttribute('data-bootload')]);
|
||||
});
|
||||
|
||||
294
www/common/common-file.js
Normal file
294
www/common/common-file.js
Normal file
@@ -0,0 +1,294 @@
|
||||
define([
|
||||
'jquery',
|
||||
'/file/file-crypto.js',
|
||||
'/bower_components/tweetnacl/nacl-fast.min.js',
|
||||
], function ($, FileCrypto) {
|
||||
var Nacl = window.nacl;
|
||||
var module = {};
|
||||
|
||||
module.create = function (common, config) {
|
||||
var File = {};
|
||||
|
||||
var Messages = common.Messages;
|
||||
|
||||
var queue = File.queue = {
|
||||
queue: [],
|
||||
inProgress: false
|
||||
};
|
||||
|
||||
var uid = function () {
|
||||
return 'file-' + String(Math.random()).substring(2);
|
||||
};
|
||||
|
||||
var $table = File.$table = $('<table>', { id: 'uploadStatus' });
|
||||
var $thead = $('<tr>').appendTo($table);
|
||||
$('<td>').text(Messages.upload_name).appendTo($thead);
|
||||
$('<td>').text(Messages.upload_size).appendTo($thead);
|
||||
$('<td>').text(Messages.upload_progress).appendTo($thead);
|
||||
$('<td>').text(Messages.cancel).appendTo($thead);
|
||||
|
||||
var createTableContainer = function ($body) {
|
||||
File.$container = $('<div>', { id: 'uploadStatusContainer' }).append($table).appendTo($body);
|
||||
return File.$container;
|
||||
};
|
||||
|
||||
var getData = function (file, href) {
|
||||
var data = {};
|
||||
|
||||
data.name = file.metadata.name;
|
||||
data.url = href;
|
||||
if (file.metadata.type.slice(0,6) === 'image/') {
|
||||
data.mediatag = true;
|
||||
}
|
||||
|
||||
return data;
|
||||
};
|
||||
|
||||
var upload = function (file) {
|
||||
var blob = file.blob;
|
||||
var metadata = file.metadata;
|
||||
var id = file.id;
|
||||
if (queue.inProgress) { return; }
|
||||
queue.inProgress = true;
|
||||
|
||||
var $row = $table.find('tr[id="'+id+'"]');
|
||||
|
||||
$row.find('.upCancel').html('-');
|
||||
var $pv = $row.find('.progressValue');
|
||||
var $pb = $row.find('.progressContainer');
|
||||
var $link = $row.find('.upLink');
|
||||
|
||||
var updateProgress = function (progressValue) {
|
||||
$pv.text(Math.round(progressValue*100)/100 + '%');
|
||||
$pb.css({
|
||||
width: (progressValue/100)*188+'px'
|
||||
});
|
||||
};
|
||||
|
||||
var u8 = new Uint8Array(blob);
|
||||
|
||||
var key = Nacl.randomBytes(32);
|
||||
var next = FileCrypto.encrypt(u8, metadata, key);
|
||||
|
||||
var estimate = FileCrypto.computeEncryptedSize(blob.byteLength, metadata);
|
||||
|
||||
var sendChunk = function (box, cb) {
|
||||
var enc = Nacl.util.encodeBase64(box);
|
||||
common.rpc.send.unauthenticated('UPLOAD', enc, function (e, msg) {
|
||||
console.log(box);
|
||||
cb(e, msg);
|
||||
});
|
||||
};
|
||||
|
||||
var actual = 0;
|
||||
var again = function (err, box) {
|
||||
if (err) { throw new Error(err); }
|
||||
if (box) {
|
||||
actual += box.length;
|
||||
var progressValue = (actual / estimate * 100);
|
||||
updateProgress(progressValue);
|
||||
|
||||
return void sendChunk(box, function (e) {
|
||||
if (e) { return console.error(e); }
|
||||
next(again);
|
||||
});
|
||||
}
|
||||
|
||||
if (actual !== estimate) {
|
||||
console.error('Estimated size does not match actual size');
|
||||
}
|
||||
|
||||
// if not box then done
|
||||
common.uploadComplete(function (e, id) {
|
||||
if (e) { return void console.error(e); }
|
||||
var uri = ['', 'blob', id.slice(0,2), id].join('/');
|
||||
console.log("encrypted blob is now available as %s", uri);
|
||||
|
||||
var b64Key = Nacl.util.encodeBase64(key);
|
||||
|
||||
var hash = common.getFileHashFromKeys(id, b64Key);
|
||||
var href = '/file/#' + hash;
|
||||
$link.attr('href', href)
|
||||
.click(function (e) {
|
||||
e.preventDefault();
|
||||
window.open($link.attr('href'), '_blank');
|
||||
});
|
||||
|
||||
// TODO add button to table which copies link to clipboard?
|
||||
//APP.toolbar.addElement(['fileshare'], {});
|
||||
|
||||
var title = metadata.name;
|
||||
|
||||
common.renamePad(title || "", href, function (err) {
|
||||
if (err) { return void console.error(err); } // TODO
|
||||
console.log(title);
|
||||
common.log(Messages._getKey('upload_success', [title]));
|
||||
common.prepareFeedback('upload')();
|
||||
|
||||
if (config.onUploaded) {
|
||||
var data = getData(file, href);
|
||||
config.onUploaded(file.dropEvent, data);
|
||||
}
|
||||
|
||||
queue.inProgress = false;
|
||||
queue.next();
|
||||
});
|
||||
//Title.updateTitle(title || "", href);
|
||||
//APP.toolbar.title.show();
|
||||
});
|
||||
};
|
||||
|
||||
common.uploadStatus(estimate, function (e, pending) {
|
||||
if (e) {
|
||||
queue.inProgress = false;
|
||||
queue.next();
|
||||
if (e === 'TOO_LARGE') {
|
||||
// TODO update table to say too big?
|
||||
return void common.alert(Messages.upload_tooLarge);
|
||||
}
|
||||
if (e === 'NOT_ENOUGH_SPACE') {
|
||||
// TODO update table to say not enough space?
|
||||
return void common.alert(Messages.upload_notEnoughSpace);
|
||||
}
|
||||
console.error(e);
|
||||
return void common.alert(Messages.upload_serverError);
|
||||
}
|
||||
|
||||
if (pending) {
|
||||
// TODO keep this message in case of pending files in another window?
|
||||
return void common.confirm(Messages.upload_uploadPending, function (yes) {
|
||||
if (!yes) { return; }
|
||||
common.uploadCancel(function (e, res) {
|
||||
if (e) {
|
||||
return void console.error(e);
|
||||
}
|
||||
console.log(res);
|
||||
next(again);
|
||||
});
|
||||
});
|
||||
}
|
||||
next(again);
|
||||
});
|
||||
};
|
||||
|
||||
var prettySize = function (bytes) {
|
||||
var kB = common.bytesToKilobytes(bytes);
|
||||
if (kB < 1024) { return kB + Messages.KB; }
|
||||
var mB = common.bytesToMegabytes(bytes);
|
||||
return mB + Messages.MB;
|
||||
};
|
||||
|
||||
queue.next = function () {
|
||||
if (queue.queue.length === 0) {
|
||||
queue.to = window.setTimeout(function () {
|
||||
if (config.keepTable) { return; }
|
||||
File.$container.fadeOut();
|
||||
}, 3000);
|
||||
return;
|
||||
}
|
||||
if (queue.inProgress) { return; }
|
||||
File.$container.show();
|
||||
var file = queue.queue.shift();
|
||||
upload(file);
|
||||
};
|
||||
queue.push = function (obj) {
|
||||
var id = uid();
|
||||
obj.id = id;
|
||||
queue.queue.push(obj);
|
||||
|
||||
$table.show();
|
||||
var estimate = FileCrypto.computeEncryptedSize(obj.blob.byteLength, obj.metadata);
|
||||
|
||||
var $progressBar = $('<div>', {'class':'progressContainer'});
|
||||
var $progressValue = $('<span>', {'class':'progressValue'}).text(Messages.upload_pending);
|
||||
|
||||
var $tr = $('<tr>', {id: id}).appendTo($table);
|
||||
|
||||
var $cancel = $('<span>', {'class': 'cancel fa fa-times'}).click(function () {
|
||||
queue.queue = queue.queue.filter(function (el) { return el.id !== id; });
|
||||
$cancel.remove();
|
||||
$tr.find('.upCancel').text('-');
|
||||
$tr.find('.progressValue').text(Messages.upload_cancelled);
|
||||
});
|
||||
|
||||
var $link = $('<a>', {
|
||||
'class': 'upLink',
|
||||
'rel': 'noopener noreferrer'
|
||||
}).text(obj.metadata.name);
|
||||
|
||||
$('<td>').append($link).appendTo($tr);
|
||||
$('<td>').text(prettySize(estimate)).appendTo($tr);
|
||||
$('<td>', {'class': 'upProgress'}).append($progressBar).append($progressValue).appendTo($tr);
|
||||
$('<td>', {'class': 'upCancel'}).append($cancel).appendTo($tr);
|
||||
|
||||
queue.next();
|
||||
};
|
||||
|
||||
var handleFile = File.handleFile = function (file, e) {
|
||||
var reader = new FileReader();
|
||||
reader.onloadend = function () {
|
||||
queue.push({
|
||||
blob: this.result,
|
||||
metadata: {
|
||||
name: file.name,
|
||||
type: file.type,
|
||||
},
|
||||
dropEvent: e
|
||||
});
|
||||
};
|
||||
reader.readAsArrayBuffer(file);
|
||||
};
|
||||
|
||||
var onFileDrop = File.onFileDrop = function (file, e) {
|
||||
Array.prototype.slice.call(file).forEach(function (d) {
|
||||
handleFile(d, e);
|
||||
});
|
||||
};
|
||||
|
||||
var createAreaHandlers = File.createDropArea = function ($area, $hoverArea) {
|
||||
var counter = 0;
|
||||
if (!$hoverArea) { $hoverArea = $area; }
|
||||
$hoverArea
|
||||
.on('dragenter', function (e) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
counter++;
|
||||
$hoverArea.addClass('hovering');
|
||||
})
|
||||
.on('dragleave', function (e) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
counter--;
|
||||
if (counter <= 0) {
|
||||
$hoverArea.removeClass('hovering');
|
||||
}
|
||||
});
|
||||
|
||||
$area
|
||||
.on('drag dragstart dragend dragover drop dragenter dragleave', function (e) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
})
|
||||
.on('drop', function (e) {
|
||||
e.stopPropagation();
|
||||
var dropped = e.originalEvent.dataTransfer.files;
|
||||
counter = 0;
|
||||
$hoverArea.removeClass('hovering');
|
||||
onFileDrop(dropped, e);
|
||||
});
|
||||
};
|
||||
|
||||
var createUploader = function ($area, $hover, $body) {
|
||||
if (!config.noHandlers) {
|
||||
createAreaHandlers($area, null);
|
||||
}
|
||||
createTableContainer($body);
|
||||
};
|
||||
|
||||
createUploader(config.dropArea, config.hoverArea, config.body);
|
||||
|
||||
return File;
|
||||
};
|
||||
|
||||
return module;
|
||||
});
|
||||
@@ -37,6 +37,17 @@ define([
|
||||
|
||||
var parsed = config.href ? common.parsePadUrl(config.href) : {};
|
||||
var secret = common.getSecrets(parsed.type, parsed.hash);
|
||||
|
||||
History.readOnly = 1;
|
||||
if (!secret.keys) {
|
||||
secret.keys = secret.key;
|
||||
History.readOnly = 2;
|
||||
}
|
||||
else if (!secret.keys.validateKey) {
|
||||
secret.keys.validateKey = true;
|
||||
History.readOnly = 0;
|
||||
}
|
||||
|
||||
var crypto = Crypto.createEncryptor(secret.keys);
|
||||
|
||||
var to = window.setTimeout(function () {
|
||||
@@ -185,6 +196,7 @@ define([
|
||||
'class':'revertHistory buttonSuccess',
|
||||
title: Messages.history_restoreTitle
|
||||
}).text(Messages.history_restore).appendTo($nav);
|
||||
if (!History.readOnly) { $rev.hide(); }
|
||||
|
||||
onUpdate = function () {
|
||||
$cur.attr('max', states.length);
|
||||
|
||||
@@ -14,6 +14,7 @@ define(function () {
|
||||
var getHeadingText = cfg.getHeadingText || function () { return; };
|
||||
var updateLocalTitle = function (newTitle) {
|
||||
exp.title = newTitle;
|
||||
onLocal();
|
||||
if (typeof cfg.updateLocalTitle === "function") {
|
||||
cfg.updateLocalTitle(newTitle);
|
||||
} else {
|
||||
@@ -43,11 +44,12 @@ define(function () {
|
||||
onLocal();
|
||||
};
|
||||
|
||||
exp.updateTitle = function (newTitle) {
|
||||
// update title: href is optional; if not specified, we use window.location.href
|
||||
exp.updateTitle = function (newTitle, href) {
|
||||
if (newTitle === exp.title) { return; }
|
||||
// Change the title now, and set it back to the old value if there is an error
|
||||
var oldTitle = exp.title;
|
||||
Cryptpad.renamePad(newTitle, function (err, data) {
|
||||
Cryptpad.renamePad(newTitle, href, function (err, data) {
|
||||
if (err) {
|
||||
console.log("Couldn't set pad title");
|
||||
console.error(err);
|
||||
|
||||
@@ -68,7 +68,11 @@ define([], function () {
|
||||
Util.replaceHash = function (hash) {
|
||||
if (window.history && window.history.replaceState) {
|
||||
if (!/^#/.test(hash)) { hash = '#' + hash; }
|
||||
return void window.history.replaceState({}, window.document.title, hash);
|
||||
void window.history.replaceState({}, window.document.title, hash);
|
||||
if (typeof(window.onhashchange) === 'function') {
|
||||
window.onhashchange();
|
||||
}
|
||||
return;
|
||||
}
|
||||
window.location.hash = hash;
|
||||
};
|
||||
|
||||
@@ -11,11 +11,13 @@ define([
|
||||
'/common/common-title.js',
|
||||
'/common/common-metadata.js',
|
||||
'/common/common-codemirror.js',
|
||||
'/common/common-file.js',
|
||||
|
||||
'/common/clipboard.js',
|
||||
'/common/pinpad.js',
|
||||
'/customize/application_config.js'
|
||||
], function ($, Config, Messages, Store, Util, Hash, UI, History, UserList, Title, Metadata, CodeMirror, Clipboard, Pinpad, AppConfig) {
|
||||
], function ($, Config, Messages, Store, Util, Hash, UI, History, UserList, Title, Metadata,
|
||||
CodeMirror, Files, Clipboard, Pinpad, AppConfig) {
|
||||
|
||||
/* This file exposes functionality which is specific to Cryptpad, but not to
|
||||
any particular pad type. This includes functions for committing metadata
|
||||
@@ -114,6 +116,9 @@ define([
|
||||
// CodeMirror
|
||||
common.createCodemirror = CodeMirror.create;
|
||||
|
||||
// Files
|
||||
common.createFileManager = function (config) { return Files.create(common, config); };
|
||||
|
||||
// History
|
||||
common.getHistory = function (config) { return History.create(common, config); };
|
||||
|
||||
@@ -126,6 +131,11 @@ define([
|
||||
return store.getProxy().proxy;
|
||||
}
|
||||
};
|
||||
common.getFO = function () {
|
||||
if (store && store.getProxy()) {
|
||||
return store.getProxy().fo;
|
||||
}
|
||||
};
|
||||
var getNetwork = common.getNetwork = function () {
|
||||
if (store) {
|
||||
if (store.getProxy() && store.getProxy().info) {
|
||||
@@ -144,7 +154,6 @@ define([
|
||||
}
|
||||
|
||||
var href = '/common/feedback.html?' + action + '=' + (+new Date());
|
||||
console.log('[feedback] %s', href);
|
||||
$.ajax({
|
||||
type: "HEAD",
|
||||
url: href,
|
||||
@@ -300,7 +309,7 @@ define([
|
||||
cb(parsed);
|
||||
}
|
||||
if (!pad.title) {
|
||||
pad.title = common.getDefaultname(parsed);
|
||||
pad.title = common.getDefaultName(parsed);
|
||||
}
|
||||
return parsed.hashData;
|
||||
};
|
||||
@@ -520,8 +529,8 @@ define([
|
||||
cb ("store.forgetPad is not a function");
|
||||
};
|
||||
|
||||
common.setPadTitle = function (name, cb) {
|
||||
var href = window.location.href;
|
||||
common.setPadTitle = function (name, padHref, cb) {
|
||||
var href = padHref || window.location.href;
|
||||
var parsed = parsePadUrl(href);
|
||||
if (!parsed.hash) { return; }
|
||||
href = getRelativeHref(href);
|
||||
@@ -581,19 +590,6 @@ define([
|
||||
return pad;
|
||||
});
|
||||
|
||||
if (!contains && href) {
|
||||
var data = makePad(href, name);
|
||||
getStore().pushData(data, function (e, id) {
|
||||
if (e) {
|
||||
if (e === 'E_OVER_LIMIT') {
|
||||
common.alert(Messages.pinLimitNotPinned, null, true);
|
||||
return;
|
||||
}
|
||||
else { throw new Error("Cannot push this pad to CryptDrive", e); }
|
||||
}
|
||||
getStore().addPad(id, common.initialPath);
|
||||
});
|
||||
}
|
||||
if (updateWeaker.length > 0) {
|
||||
updateWeaker.forEach(function (obj) {
|
||||
// If we have a stronger url, and if all the occurences of the weaker were
|
||||
@@ -601,6 +597,20 @@ define([
|
||||
getStore().restoreHref(obj.n);
|
||||
});
|
||||
}
|
||||
if (!contains && href) {
|
||||
var data = makePad(href, name);
|
||||
getStore().pushData(data, function (e, id) {
|
||||
if (e) {
|
||||
if (e === 'E_OVER_LIMIT') {
|
||||
common.alert(Messages.pinLimitNotPinned, null, true);
|
||||
}
|
||||
return void cb(e);
|
||||
}
|
||||
getStore().addPad(id, common.initialPath);
|
||||
cb(err, recent);
|
||||
});
|
||||
return;
|
||||
}
|
||||
cb(err, recent);
|
||||
});
|
||||
};
|
||||
@@ -621,24 +631,41 @@ define([
|
||||
/*
|
||||
* Buttons
|
||||
*/
|
||||
common.renamePad = function (title, callback) {
|
||||
common.renamePad = function (title, href, callback) {
|
||||
if (title === null) { return; }
|
||||
|
||||
if (title.trim() === "") {
|
||||
var parsed = parsePadUrl(window.location.href);
|
||||
var parsed = parsePadUrl(href || window.location.href);
|
||||
title = getDefaultName(parsed);
|
||||
}
|
||||
|
||||
common.setPadTitle(title, function (err) {
|
||||
common.setPadTitle(title, href, function (err) {
|
||||
if (err) {
|
||||
console.log("unable to set pad title");
|
||||
console.log(err);
|
||||
console.error(err);
|
||||
return;
|
||||
}
|
||||
callback(null, title);
|
||||
});
|
||||
};
|
||||
|
||||
common.getUserFilesList = function () {
|
||||
var store = common.getStore();
|
||||
var proxy = store.getProxy();
|
||||
var fo = proxy.fo;
|
||||
var hashes = [];
|
||||
var list = fo.getFiles().filter(function (id) {
|
||||
var href = fo.getFileData(id).href;
|
||||
var parsed = parsePadUrl(href);
|
||||
if ((parsed.type === 'file' || parsed.type === 'media')
|
||||
&& hashes.indexOf(parsed.hash) === -1) {
|
||||
hashes.push(parsed.hash);
|
||||
return true;
|
||||
}
|
||||
});
|
||||
return list;
|
||||
};
|
||||
|
||||
var getUserChannelList = common.getUserChannelList = function () {
|
||||
var store = common.getStore();
|
||||
var proxy = store.getProxy();
|
||||
@@ -879,6 +906,21 @@ define([
|
||||
common.getPinnedUsage(todo);
|
||||
};
|
||||
|
||||
var getAppSuffix = function () {
|
||||
var parts = window.location.pathname.split('/')
|
||||
.filter(function (x) { return x; });
|
||||
|
||||
if (!parts[0]) { return ''; }
|
||||
return '_' + parts[0].toUpperCase();
|
||||
};
|
||||
|
||||
var prepareFeedback = common.prepareFeedback = function (key) {
|
||||
if (typeof(key) !== 'string') { return $.noop; }
|
||||
return function () {
|
||||
feedback(key.toUpperCase() + getAppSuffix());
|
||||
};
|
||||
};
|
||||
|
||||
common.createButton = function (type, rightside, data, callback) {
|
||||
var button;
|
||||
var size = "17px";
|
||||
@@ -887,6 +929,8 @@ define([
|
||||
button = $('<button>', {
|
||||
title: Messages.exportButtonTitle,
|
||||
}).append($('<span>', {'class':'fa fa-download', style: 'font:'+size+' FontAwesome'}));
|
||||
|
||||
button.click(prepareFeedback(type));
|
||||
if (callback) {
|
||||
button.click(callback);
|
||||
}
|
||||
@@ -896,18 +940,40 @@ define([
|
||||
title: Messages.importButtonTitle,
|
||||
}).append($('<span>', {'class':'fa fa-upload', style: 'font:'+size+' FontAwesome'}));
|
||||
if (callback) {
|
||||
button.click(UI.importContent('text/plain', function (content, file) {
|
||||
button
|
||||
.click(prepareFeedback(type))
|
||||
.click(UI.importContent('text/plain', function (content, file) {
|
||||
callback(content, file);
|
||||
}));
|
||||
}
|
||||
break;
|
||||
case 'upload':
|
||||
button = $('<button>', {
|
||||
'class': 'btn btn-primary new',
|
||||
title: Messages.uploadButtonTitle,
|
||||
}).append($('<span>', {'class':'fa fa-upload'})).append(' '+Messages.uploadButton);
|
||||
if (!data.FM) { return; }
|
||||
var $input = $('<input>', {
|
||||
'type': 'file',
|
||||
'style': 'display: none;'
|
||||
}).on('change', function (e) {
|
||||
var file = e.target.files[0];
|
||||
var ev = {
|
||||
target: data.target
|
||||
};
|
||||
data.FM.handleFile(file, ev);
|
||||
if (callback) { callback(); }
|
||||
});
|
||||
button.click(function () { $input.click(); });
|
||||
break;
|
||||
case 'template':
|
||||
if (!AppConfig.enableTemplates) { return; }
|
||||
button = $('<button>', {
|
||||
title: Messages.saveTemplateButton,
|
||||
}).append($('<span>', {'class':'fa fa-bookmark', style: 'font:'+size+' FontAwesome'}));
|
||||
if (data.rt && data.Crypt) {
|
||||
button.click(function () {
|
||||
button
|
||||
.click(function () {
|
||||
var title = data.getTitle() || document.title;
|
||||
var todo = function (val) {
|
||||
if (typeof(val) !== "string") { return; }
|
||||
@@ -965,7 +1031,9 @@ define([
|
||||
}
|
||||
});
|
||||
if (callback) {
|
||||
button.click(function() {
|
||||
button
|
||||
.click(prepareFeedback(type))
|
||||
.click(function() {
|
||||
var href = window.location.href;
|
||||
var msg = isLoggedIn() ? Messages.forgetPrompt : Messages.fm_removePermanentlyDialog;
|
||||
common.confirm(msg, function (yes) {
|
||||
@@ -1021,7 +1089,9 @@ define([
|
||||
style: 'font:'+size+' FontAwesome'
|
||||
});
|
||||
if (data.histConfig) {
|
||||
button.click(function () {
|
||||
button
|
||||
.click(prepareFeedback(type))
|
||||
.click(function () {
|
||||
common.getHistory(data.histConfig);
|
||||
});
|
||||
}
|
||||
@@ -1030,7 +1100,8 @@ define([
|
||||
button = $('<button>', {
|
||||
'class': "fa fa-question",
|
||||
style: 'font:'+size+' FontAwesome'
|
||||
});
|
||||
})
|
||||
.click(prepareFeedback(type));
|
||||
}
|
||||
if (rightside) {
|
||||
button.addClass('rightside-button');
|
||||
@@ -1378,8 +1449,8 @@ define([
|
||||
initialized = true;
|
||||
|
||||
updateLocalVersion();
|
||||
|
||||
f(void 0, env);
|
||||
if (typeof(window.onhashchange) === 'function') { window.onhashchange(); }
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1422,6 +1493,7 @@ define([
|
||||
|| parsedOld.channel !== parsedNew.channel
|
||||
|| parsedOld.mode !== parsedNew.mode
|
||||
|| parsedOld.key !== parsedNew.key)) {
|
||||
if (!parsedOld.channel) { oldHref = newHref; return; }
|
||||
document.location.reload();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
define([
|
||||
'jquery',
|
||||
'/bower_components/marked/marked.min.js',
|
||||
'/bower_components/diff-dom/diffDOM.js'
|
||||
],function ($, Marked) {
|
||||
'/common/cryptpad-common.js',
|
||||
'/common/media-tag.js',
|
||||
'/bower_components/diff-dom/diffDOM.js',
|
||||
'/bower_components/tweetnacl/nacl-fast.min.js',
|
||||
],function ($, Marked, Cryptpad, MediaTag) {
|
||||
var DiffMd = {};
|
||||
|
||||
var DiffDOM = window.diffDOM;
|
||||
@@ -33,6 +36,20 @@ define([
|
||||
var cls = (isCheckedTaskItem || isUncheckedTaskItem) ? ' class="todo-list-item"' : '';
|
||||
return '<li'+ cls + '>' + text + '</li>\n';
|
||||
};
|
||||
renderer.image = function (href, title, text) {
|
||||
if (href.slice(0,6) === '/file/') {
|
||||
var parsed = Cryptpad.parsePadUrl(href);
|
||||
var hexFileName = Cryptpad.base64ToHex(parsed.hashData.channel);
|
||||
var mt = '<media-tag src="/blob/' + hexFileName.slice(0,2) + '/' + hexFileName + '" data-crypto-key="cryptpad:' + parsed.hashData.key + '"></media-tag>';
|
||||
return mt;
|
||||
}
|
||||
var out = '<img src="' + href + '" alt="' + text + '"';
|
||||
if (title) {
|
||||
out += ' title="' + title + '"';
|
||||
}
|
||||
out += this.options.xhtml ? '/>' : '>';
|
||||
return out;
|
||||
};
|
||||
|
||||
var forbiddenTags = [
|
||||
'SCRIPT',
|
||||
@@ -43,6 +60,10 @@ define([
|
||||
'AUDIO',
|
||||
];
|
||||
var unsafeTag = function (info) {
|
||||
if (info.node && $(info.node).parents('media-tag').length) {
|
||||
// Do not remove elements inside a media-tag
|
||||
return true;
|
||||
}
|
||||
if (['addAttribute', 'modifyAttribute'].indexOf(info.diff.action) !== -1) {
|
||||
if (/^on/.test(info.diff.name)) {
|
||||
console.log("Rejecting forbidden element attribute with name", info.diff.name);
|
||||
@@ -61,6 +82,7 @@ define([
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
var slice = function (coll) {
|
||||
return Array.prototype.slice.call(coll);
|
||||
};
|
||||
@@ -85,7 +107,7 @@ define([
|
||||
var DD = new DiffDOM({
|
||||
preDiffApply: function (info) {
|
||||
if (unsafeTag(info)) { return true; }
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
var makeDiff = function (A, B, id) {
|
||||
@@ -119,9 +141,18 @@ define([
|
||||
throw new Error(patch);
|
||||
} else {
|
||||
DD.apply($content[0], patch);
|
||||
var $mts = $content.find('media-tag:not(:has(*))');
|
||||
$mts.each(function (i, el) {
|
||||
MediaTag(el);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
$(window.document).on('decryption', function (e) {
|
||||
var decrypted = e.originalEvent;
|
||||
if (decrypted.callback) { decrypted.callback(); }
|
||||
});
|
||||
|
||||
return DiffMd;
|
||||
});
|
||||
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -105,7 +105,7 @@ define([
|
||||
var oldFo = FO.init(parsed.drive, {
|
||||
Cryptpad: Cryptpad
|
||||
});
|
||||
var todo = function () {
|
||||
var onMigrated = function () {
|
||||
oldFo.fixFiles();
|
||||
var newData = Cryptpad.getStore().getProxy();
|
||||
var newFo = newData.fo;
|
||||
@@ -151,8 +151,10 @@ define([
|
||||
proxy.FS_hashes = [];
|
||||
}
|
||||
proxy.FS_hashes.push(localStorage.FS_hash);
|
||||
if (typeof(cb) === "function") { cb(); }
|
||||
};
|
||||
oldFo.migrate(todo);
|
||||
oldFo.migrate(onMigrated);
|
||||
return;
|
||||
}
|
||||
if (typeof(cb) === "function") { cb(); }
|
||||
};
|
||||
|
||||
@@ -63,6 +63,7 @@ types of messages:
|
||||
// RPC responses are arrays. this message isn't meant for us.
|
||||
return;
|
||||
}
|
||||
if (/FULL_HISTORY/.test(parsed[0])) { return; }
|
||||
|
||||
var response = parsed.slice(2);
|
||||
|
||||
@@ -98,7 +99,7 @@ types of messages:
|
||||
delete ctx.pending[txid];
|
||||
return;
|
||||
}
|
||||
console.error("received message for txid[%s] with no callback", txid);
|
||||
console.error("received message [%s] for txid[%s] with no callback", msg, txid);
|
||||
};
|
||||
|
||||
var create = function (network, edPrivateKey, edPublicKey, cb) {
|
||||
|
||||
@@ -96,6 +96,10 @@ define([
|
||||
} else {
|
||||
styleToolbar($container);
|
||||
}
|
||||
$container.on('drop dragover', function (e) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
});
|
||||
return $toolbar;
|
||||
};
|
||||
|
||||
|
||||
@@ -520,7 +520,7 @@ define([
|
||||
|
||||
// ADD
|
||||
var add = exp.add = function (id, path) {
|
||||
if (!Cryptpad.isLoggedIn()) { return; }
|
||||
if (!Cryptpad.isLoggedIn() && !config.testMode) { return; }
|
||||
var data = files[FILES_DATA][id];
|
||||
if (!data || typeof(data) !== "object") { return; }
|
||||
var newPath = path, parentEl;
|
||||
@@ -559,7 +559,7 @@ define([
|
||||
exp.forget = function (href) {
|
||||
var id = getIdFromHref(href);
|
||||
if (!id) { return; }
|
||||
if (!Cryptpad.isLoggedIn()) {
|
||||
if (!Cryptpad.isLoggedIn() && !config.testMode) {
|
||||
// delete permanently
|
||||
exp.removePadAttribute(href);
|
||||
spliceFileData(id);
|
||||
@@ -588,7 +588,7 @@ define([
|
||||
};
|
||||
var checkDeletedFiles = function () {
|
||||
// Nothing in OLD_FILES_DATA for workgroups
|
||||
if (workgroup || !Cryptpad.isLoggedIn()) { return; }
|
||||
if (workgroup || (!Cryptpad.isLoggedIn() && !config.testMode)) { return; }
|
||||
|
||||
var filesList = getFiles([ROOT, 'hrefArray', TRASH]);
|
||||
var fData = files[FILES_DATA];
|
||||
@@ -617,7 +617,7 @@ define([
|
||||
var trashPaths = paths.filter(function(x) { return isPathIn(x, [TRASH]); });
|
||||
var allFilesPaths = paths.filter(function(x) { return isPathIn(x, [FILES_DATA]); });
|
||||
|
||||
if (!Cryptpad.isLoggedIn()) {
|
||||
if (!Cryptpad.isLoggedIn() && !config.testMode) {
|
||||
allFilesPaths.forEach(function (path) {
|
||||
var el = find(path);
|
||||
if (!el) { return; }
|
||||
@@ -967,7 +967,7 @@ define([
|
||||
toClean.push(id);
|
||||
continue;
|
||||
}
|
||||
if (Cryptpad.isLoggedIn() && rootFiles.indexOf(id) === -1) {
|
||||
if ((Cryptpad.isLoggedIn() || config.testMode) && rootFiles.indexOf(id) === -1) {
|
||||
debug("An element in filesData was not in ROOT, TEMPLATE or TRASH.", id, el);
|
||||
var newName = Cryptpad.createChannelId();
|
||||
root[newName] = id;
|
||||
|
||||
Reference in New Issue
Block a user