Merge branch 'code2' into staging

This commit is contained in:
yflory
2017-09-05 11:38:17 +02:00
77 changed files with 4430 additions and 2369 deletions

View File

@@ -16,7 +16,8 @@ define([
CodeMirror.modeURL = "cm/mode/%N/%N";
var $pad = $('#pad-iframe');
var $textarea = exp.$textarea = $pad.contents().find('#editor1');
var $textarea = exp.$textarea = $('#editor1');
if (!$textarea.length) { $textarea = exp.$textarea = $pad.contents().find('#editor1'); }
var Title;
var onLocal = function () {};
@@ -228,6 +229,7 @@ define([
var ext = /.+\.([^.]+)$/.exec(file.name);
if (ext[1]) {
mode = CMeditor.findModeByExtension(ext[1]);
mode = mode && mode.mode || null;
}
} else {
mode = mime && mime.mode || null;

View File

@@ -1,12 +1,13 @@
define([
'jquery',
'/file/file-crypto.js',
'/common/common-thumbnail.js',
'/bower_components/tweetnacl/nacl-fast.min.js',
], function ($, FileCrypto) {
], function ($, FileCrypto, Thumb) {
var Nacl = window.nacl;
var module = {};
var blobToArrayBuffer = function (blob, cb) {
var blobToArrayBuffer = module.blobToArrayBuffer = function (blob, cb) {
var reader = new FileReader();
reader.onloadend = function () {
cb(void 0, this.result);
@@ -23,6 +24,85 @@ define([
}
};
module.upload = function (file, noStore, common, updateProgress, onComplete, onError, onPending) {
var u8 = file.blob; // This is not a blob but a uint8array
var metadata = file.metadata;
var key = Nacl.randomBytes(32);
var next = FileCrypto.encrypt(u8, metadata, key);
var estimate = FileCrypto.computeEncryptedSize(u8.length, metadata);
var sendChunk = function (box, cb) {
var enc = Nacl.util.encodeBase64(box);
common.rpc.send.unauthenticated('UPLOAD', enc, function (e, msg) {
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;
var title = metadata.name;
if (noStore) { return void onComplete(href); }
common.renamePad(title || "", href, function (err) {
if (err) { return void console.error(err); }
onComplete(href);
});
});
};
common.uploadStatus(estimate, function (e, pending) {
if (e) {
console.error(e);
onError(e);
return;
}
if (pending) {
return void onPending(function () {
// if the user wants to cancel the pending upload to execute that one
common.uploadCancel(function (e, res) {
if (e) {
return void console.error(e);
}
console.log(res);
next(again);
});
});
}
next(again);
});
};
module.create = function (common, config) {
var File = {};
@@ -62,7 +142,8 @@ define([
};
var upload = function (file) {
var blob = file.blob;
var blob = file.blob; // This is not a blob but an array buffer
var u8 = new Uint8Array(blob);
var metadata = file.metadata;
var id = file.id;
if (queue.inProgress) { return; }
@@ -83,112 +164,49 @@ define([
});
};
var u8 = new Uint8Array(blob);
var onComplete = function (href) {
$link.attr('href', href)
.click(function (e) {
e.preventDefault();
window.open($link.attr('href'), '_blank');
});
var title = metadata.name;
common.log(Messages._getKey('upload_success', [title]));
common.prepareFeedback('upload')();
var key = Nacl.randomBytes(32);
var next = FileCrypto.encrypt(u8, metadata, key);
if (config.onUploaded) {
var data = getData(file, href);
config.onUploaded(file.dropEvent, data);
}
var estimate = FileCrypto.computeEncryptedSize(blob.byteLength, metadata);
queue.inProgress = false;
queue.next();
};
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 onError = function (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);
};
var onPending = function (cb) {
common.confirm(Messages.upload_uploadPending, function (yes) {
if (!yes) { return; }
cb();
});
};
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');
});
var title = metadata.name;
var onComplete = function () {
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();
};
if (config.noStore) { return void onComplete(); }
common.renamePad(title || "", href, function (err) {
if (err) { return void console.error(err); } // TODO
onComplete();
});
//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);
});
file.blob = u8;
module.upload(file, config.noStore, common, updateProgress, onComplete, onError, onPending);
};
var prettySize = function (bytes) {
@@ -246,30 +264,46 @@ define([
var handleFile = File.handleFile = function (file, e, thumbnail) {
var thumb;
var finish = function (arrayBuffer) {
var file_arraybuffer;
var finish = function () {
var metadata = {
name: file.name,
type: file.type,
};
if (thumb) { metadata.thumbnail = thumb; }
queue.push({
blob: arrayBuffer,
blob: file_arraybuffer,
metadata: metadata,
dropEvent: e
});
};
var processFile = function () {
blobToArrayBuffer(file, function (e, buffer) {
finish(buffer);
});
};
if (!thumbnail) { return void processFile(); }
blobToArrayBuffer(thumbnail, function (e, buffer) {
blobToArrayBuffer(file, function (e, buffer) {
if (e) { console.error(e); }
thumb = arrayBufferToString(buffer);
processFile();
file_arraybuffer = buffer;
if (thumbnail) { // there is already a thumbnail
return blobToArrayBuffer(thumbnail, function (e, buffer) {
if (e) { console.error(e); }
thumb = arrayBufferToString(buffer);
finish();
});
}
if (!Thumb.isSupportedType(file.type)) { return finish(); }
// make a resized thumbnail from the image..
Thumb.fromImageBlob(file, function (e, thumb_blob) {
if (e) { console.error(e); }
if (!thumb_blob) { return finish(); }
blobToArrayBuffer(thumb_blob, function (e, buffer) {
if (e) {
console.error(e);
return finish();
}
thumb = arrayBufferToString(buffer);
finish();
});
});
});
};

View File

@@ -280,28 +280,13 @@ define([
};
};
var $fileIcon = $('<span>', {"class": "fa fa-file-text-o file icon"});
var $fileAppIcon = $('<span>', {"class": "fa fa-file-text-o file icon fileColor"});
var $padIcon = $('<span>', {"class": "fa fa-file-word-o file icon padColor"});
var $codeIcon = $('<span>', {"class": "fa fa-file-code-o file icon codeColor"});
var $slideIcon = $('<span>', {"class": "fa fa-file-powerpoint-o file icon slideColor"});
var $pollIcon = $('<span>', {"class": "fa fa-calendar file icon pollColor"});
var $whiteboardIcon = $('<span>', {"class": "fa fa-paint-brush whiteboardColor"});
var $todoIcon = $('<span>', {"class": "fa fa-tasks todoColor"});
var $contactsIcon = $('<span>', {"class": "fa fa-users friendsColor"});
var $defaultIcon = $('<span>', {"class": "fa fa-file-text-o"});
UI.getIcon = function (type) {
var $icon;
var $icon = $defaultIcon.clone();
switch(type) {
case 'pad': $icon = $padIcon.clone(); break;
case 'file': $icon = $fileAppIcon.clone(); break;
case 'code': $icon = $codeIcon.clone(); break;
case 'slide': $icon = $slideIcon.clone(); break;
case 'poll': $icon = $pollIcon.clone(); break;
case 'whiteboard': $icon = $whiteboardIcon.clone(); break;
case 'todo': $icon = $todoIcon.clone(); break;
case 'contacts': $icon = $contactsIcon.clone(); break;
default: $icon = $fileIcon.clone();
if (AppConfig.applicationsIcon && AppConfig.applicationsIcon[type]) {
var appClass = ' cp-icon-color-'+type;
$icon = $('<span>', {'class': 'fa ' + AppConfig.applicationsIcon[type] + appClass});
}
return $icon;

View File

@@ -48,9 +48,10 @@ define([
});
};
Msg.getFriendChannelsList = function (proxy) {
Msg.getFriendChannelsList = function (common) {
var list = [];
eachFriend(proxy, function (friend) {
var proxy = common.getProxy();
eachFriend(proxy.friends, function (friend) {
list.push(friend.channel);
});
return list;

View File

@@ -3,7 +3,18 @@ define([
], function () {
var Nacl = window.nacl;
var Thumb = {
dimension: 150, // thumbnails are all 150px
dimension: 100,
};
var supportedTypes = [
'image/png',
'image/jpeg',
'image/jpg',
'image/gif', // TODO confirm this is true
];
Thumb.isSupportedType = function (type) {
return supportedTypes.indexOf(type) !== -1;
};
// create thumbnail image from metadata
@@ -27,22 +38,67 @@ define([
}
};
var getResizedDimensions = function (img) {
var h = img.height;
var w = img.width;
var dim = Thumb.dimension;
// if the image is too small, don't bother making a thumbnail
if (h <= dim || w <= dim) { return null; }
// the image is taller than it is wide, so scale to that.
var r = dim / (h > w? h: w); // ratio
var d;
if (h > w) {
d = Math.floor(((h * r) - dim) / 2);
return {
x1: 0,
x2: dim,
y1: d,
y2: dim + d,
};
} else {
d = Math.floor(((w * r) - dim) / 2);
return {
x1: d,
x2: dim + d,
y1: 0,
y2: dim,
};
}
};
// assumes that your canvas is square
// nodeback returning blob
Thumb.fromCanvas = function (canvas, cb) {
canvas = canvas;
Thumb.fromCanvas = Thumb.fromImage = function (canvas, cb) {
var c2 = document.createElement('canvas');
var d = Thumb.dimension;
c2.width = d;
c2.height = 2;
var D = getResizedDimensions(canvas);
if (!D) { return void cb('TOO_SMALL'); }
c2.width = Thumb.dimension;
c2.height = Thumb.dimension;
var ctx = c2.getContext('2d');
ctx.drawImage(canvas, 0, 0, d, d);
ctx.drawImage(canvas, D.x1, D.y1, D.x2, D.y2);
c2.toBlob(function (blob) {
cb(void 0, blob);
});
};
Thumb.fromImageBlob = function (blob, cb) {
var url = URL.createObjectURL(blob);
var img = new Image();
img.onload = function () {
Thumb.fromImage(img, cb);
};
img.onerror = function () {
cb('ERROR');
};
img.src = url;
};
Thumb.fromVideo = function (video, cb) {
cb = cb; // WIP
};

View File

@@ -80,6 +80,7 @@ define([
common.getIcon = UI.getIcon;
common.addTooltips = UI.addTooltips;
common.clearTooltips = UI.clearTooltips;
common.importContent = UI.importContent;
// import common utilities for export
common.find = Util.find;
@@ -617,6 +618,16 @@ define([
});
common.findOKButton().text(Messages.cancelButton);
};
// Secure iframes
common.useTemplate = function (href, Crypt, cb) {
var parsed = parsePadUrl(href);
if(!parsed) { throw new Error("Cannot get template hash"); }
Crypt.get(parsed.hash, function (err, val) {
if (err) { throw new Error(err); }
var p = parsePadUrl(window.location.href);
Crypt.put(p.hash, val, cb);
});
};
// STORAGE
/* fetch and migrate your pad history from the store */
@@ -784,7 +795,7 @@ define([
var proxy = store.getProxy();
var fo = proxy.fo;
var hashes = [];
var list = fo.getFiles().filter(function (id) {
var list = fo.getFiles([fo.ROOT]).filter(function (id) {
var href = fo.getFileData(id).href;
var parsed = parsePadUrl(href);
if ((parsed.type === 'file' || parsed.type === 'media')
@@ -795,6 +806,27 @@ define([
});
return list;
};
// Needed for the secure filepicker app
common.getSecureFilesList = function (filter, cb) {
var store = common.getStore();
if (!store) { return void cb("Store is not ready"); }
var proxy = store.getProxy();
var fo = proxy.fo;
var list = {};
var hashes = [];
var types = filter.types;
var where = filter.where;
fo.getFiles(where).forEach(function (id) {
var data = fo.getFileData(id);
var parsed = parsePadUrl(data.href);
if ((!types || types.length === 0 || types.indexOf(parsed.type) !== -1)
&& hashes.indexOf(parsed.hash) === -1) {
hashes.push(parsed.hash);
list[id] = data;
}
});
cb (null, list);
};
var getUserChannelList = common.getUserChannelList = function () {
var store = common.getStore();
@@ -1014,6 +1046,9 @@ define([
rpc.uploadCancel(cb);
};
common.uploadFileSecure = Files.upload;
/* Create a usage bar which keeps track of how much storage space is used
by your CryptDrive. The getPinnedUsage RPC is one of the heavier calls,
so we throttle its usage. Clients will not update more than once per
@@ -1475,7 +1510,7 @@ define([
};
// This is duplicated in drive/main.js, it should be unified
var getFileIcon = function (data) {
var getFileIcon = common.getFileIcon = function (data) {
var $icon = common.getIcon();
if (!data) { return $icon; }
@@ -1483,12 +1518,8 @@ define([
var href = data.href;
if (!href) { return $icon; }
if (href.indexOf('/pad/') !== -1) { $icon = common.getIcon('pad'); }
else if (href.indexOf('/code/') !== -1) { $icon = common.getIcon('code'); }
else if (href.indexOf('/slide/') !== -1) { $icon = common.getIcon('slide'); }
else if (href.indexOf('/poll/') !== -1) { $icon = common.getIcon('poll'); }
else if (href.indexOf('/whiteboard/') !== -1) { $icon = common.getIcon('whiteboard'); }
else if (href.indexOf('/file/') !== -1) { $icon = common.getIcon('file'); }
var type = common.parsePadUrl(href).type;
$icon = common.getIcon(type);
return $icon;
};
@@ -1502,16 +1533,24 @@ define([
'id': cfg.id
});
}
var hide = function () {
if (cfg.onClose) { return void cfg.onClose(); }
$blockContainer.hide();
};
$blockContainer.html('').appendTo($body);
var $block = $('<div>', {'class': 'cp-modal'}).appendTo($blockContainer);
$('<span>', {
'class': 'cp-modal-close fa fa-times',
'title': Messages.filePicker_close
}).click(function () {
$blockContainer.hide();
}).appendTo($block);
}).click(hide).appendTo($block);
$body.click(hide);
$block.click(function (e) {
e.stopPropagation();
});
$body.keydown(function (e) {
if (e.which === 27) { $blockContainer.hide(); }
if (e.which === 27) {
hide();
}
});
return $blockContainer;
};
@@ -1589,7 +1628,7 @@ define([
// Container
var $container = $(config.container);
var containerConfig = {
'class': 'dropdown-bar'
'class': 'cp-dropdown-container'
};
if (config.buttonTitle) {
containerConfig.title = config.buttonTitle;
@@ -1602,14 +1641,14 @@ define([
// Button
var $button = $('<button>', {
'class': ''
}).append($('<span>', {'class': 'buttonTitle'}).html(config.text || ""));
}).append($('<span>', {'class': 'cp-dropdown-button-title'}).html(config.text || ""));
/*$('<span>', {
'class': 'fa fa-caret-down',
}).appendTo($button);*/
// Menu
var $innerblock = $('<div>', {'class': 'cryptpad-dropdown dropdown-bar-content'});
if (config.left) { $innerblock.addClass('left'); }
var $innerblock = $('<div>', {'class': 'cp-dropdown-content'});
if (config.left) { $innerblock.addClass('cp-dropdown-left'); }
config.options.forEach(function (o) {
if (!isValidOption(o)) { return; }
@@ -1622,8 +1661,8 @@ define([
var setActive = function ($el) {
if ($el.length !== 1) { return; }
$innerblock.find('.active').removeClass('active');
$el.addClass('active');
$innerblock.find('.cp-dropdown-element-active').removeClass('cp-dropdown-element(active');
$el.addClass('cp-dropdown-element-active');
var scroll = $el.position().top + $innerblock.scrollTop();
if (scroll < $innerblock.scrollTop()) {
$innerblock.scrollTop(scroll);
@@ -1638,7 +1677,7 @@ define([
var show = function () {
$innerblock.show();
$innerblock.find('.active').removeClass('active');
$innerblock.find('.cp-dropdown-element-active').removeClass('cp-dropdown-element-active');
if (config.isSelect && value) {
var $val = $innerblock.find('[data-value="'+value+'"]');
setActive($val);
@@ -1650,10 +1689,10 @@ define([
$container.click(function (e) {
e.stopPropagation();
var state = $innerblock.is(':visible');
$('.dropdown-bar-content').hide();
$('.cp-dropdown-content').hide();
try {
$('iframe').each(function (idx, ifrw) {
$(ifrw).contents().find('.dropdown-bar-content').hide();
$(ifrw).contents().find('.cp-dropdown-content').hide();
});
} catch (er) {
// empty try catch in case this iframe is problematic (cross-origin)
@@ -1669,7 +1708,7 @@ define([
var pressed = '';
var to;
$container.keydown(function (e) {
var $value = $innerblock.find('[data-value].active');
var $value = $innerblock.find('[data-value].cp-dropdown-element-active');
if (e.which === 38) { // Up
if ($value.length) {
var $prev = $value.prev();
@@ -1710,7 +1749,7 @@ define([
value = val;
var $val = $innerblock.find('[data-value="'+val+'"]');
var textValue = name || $val.html() || val;
$button.find('.buttonTitle').html(textValue);
$button.find('.cp-dropdown-button-title').html(textValue);
};
$container.getValue = function () {
return value || '';
@@ -1857,7 +1896,7 @@ define([
var oldUrl;
if (account && !config.static && store) {
var $avatar = $userAdmin.find('.buttonTitle');
var $avatar = $userAdmin.find('.cp-dropdown-button-title');
var updateButton = function (newName) {
var profile = store.getProfile();
var url = profile && profile.avatar;

View File

@@ -1,47 +1,50 @@
@import (once) '../customize/src/less2/include/colortheme.less';
@import '../customize/src/less2/include/modal.less';
#fileDialog {
.cp-modal {
.fileContainer {
display: flex;
flex-wrap: wrap;
justify-content: center;
overflow-y: auto;
}
.element {
@darker: darken(@colortheme_modal-fg, 30%);
width: 200px;
min-width: 200px;
height: 1em;
padding: 0.5em;
margin: 5px;
box-sizing: content-box;
text-align: left;
line-height: 1em;
cursor: pointer;
background-color: #111;
color: @darker;
transition: all 0.1s;
&:hover {
color: @colortheme_modal-fg;
.fileDialog_main () {
#fileDialog {
display: none;
.cp-modal {
.fileContainer {
display: flex;
flex-wrap: wrap;
justify-content: center;
overflow-y: auto;
}
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
.element {
@darker: darken(@colortheme_modal-fg, 30%);
align-items: center;
width: 200px;
min-width: 200px;
height: 1em;
padding: 0.5em;
margin: 5px;
box-sizing: content-box;
.fa {
text-align: left;
line-height: 1em;
cursor: pointer;
margin-right: 0.5em;
background-color: #111;
color: @darker;
transition: all 0.1s;
&:hover {
color: @colortheme_modal-fg;
}
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
align-items: center;
.fa {
cursor: pointer;
margin-right: 0.5em;
}
}
}
}

View File

@@ -4,7 +4,8 @@ define([
'/bower_components/chainpad-crypto/crypto.js?v=0.1.5',
'/bower_components/textpatcher/TextPatcher.amd.js',
'/common/userObject.js',
], function ($, Listmap, Crypto, TextPatcher, FO) {
'/common/migrate-user-object.js'
], function ($, Listmap, Crypto, TextPatcher, FO, Migrate) {
/*
This module uses localStorage, which is synchronous, but exposes an
asyncronous API. This is so that we can substitute other storage
@@ -155,6 +156,8 @@ define([
var todo = function () {
fo.fixFiles();
Migrate(proxy, Cryptpad);
//storeObj = proxy;
store = initStore(fo, proxy, exp);
if (typeof(f) === 'function') {

File diff suppressed because one or more lines are too long

View File

@@ -73,6 +73,7 @@ define(['json.sortify'], function (Sortify) {
});
};
console.log('here register');
sframeChan.on('EV_METADATA_UPDATE', function (ev) {
meta = ev;
if (ev.priv) {

View File

@@ -0,0 +1,68 @@
define([], function () {
// Start migration check
// Versions:
// 1: migrate pad attributes
// 2: migrate indent settings (codemirror)
return function (userObject, Cryptpad) {
var version = userObject.version || 0;
// Migration 1: pad attributes moved to filesData
var migrateAttributes = function () {
var files = userObject && userObject.drive;
if (!files) { return; }
var migratePadAttributes = function (el, id, parsed) {
// Migrate old pad attributes
['userid', 'previewMode'].forEach(function (attr) {
var key = parsed.hash + '.' + attr;
var key2 = parsed.hash.slice(0,-1) + '.' + attr;// old pads not ending with /
if (typeof(files[key]) !== "undefined" || typeof(files[key2]) !== "undefined") {
console.log("Migrating pad attribute", attr, "for pad", id);
el[attr] = files[key] || files[key2];
delete files[key];
delete files[key2];
}
});
};
var filesData = files.filesData;
if (!filesData) { return; }
var el, parsed;
for (var id in filesData) {
id = Number(id);
el = filesData[id];
parsed = el.href && Cryptpad.parsePadUrl(el.href);
if (!parsed) { continue; }
migratePadAttributes(el, id, parsed);
}
// Migration done
};
if (version < 1) {
migrateAttributes();
Cryptpad.feedback('Migrate-1', true);
userObject.version = version = 1;
}
// Migration 2: indentation settings for CodeMirror moved from root to 'settings'
var migrateIndent = function () {
var indentKey = 'cryptpad.indentUnit';
var useTabsKey = 'cryptpad.indentWithTabs';
userObject.settings = userObject.settings || {};
if (userObject[indentKey]) {
userObject.settings.indentUnit = userObject[indentKey];
delete userObject[indentKey];
}
if (userObject[useTabsKey]) {
userObject.settings.indentWithTabs = userObject[useTabsKey];
delete userObject[useTabsKey];
}
};
if (version < 2) {
migrateIndent();
Cryptpad.feedback('Migrate-2', true);
userObject.version = version = 2;
}
};
});

View File

@@ -109,8 +109,9 @@ define([
window.addEventListener('message', function (msg) {
var data = JSON.parse(msg.data);
if (ow !== msg.source) {
console.log("DROP Message from unexpected source");
console.log(msg);
return;
//console.log("DROP Message from unexpected source");
//console.log(msg);
} else if (!otherWindow) {
otherWindow = ow;
ow.postMessage(JSON.stringify({ txid: data.txid }), '*');

View File

@@ -0,0 +1,302 @@
define([
'jquery',
'/file/file-crypto.js',
'/bower_components/tweetnacl/nacl-fast.min.js',
], function ($, FileCrypto) {
var Nacl = window.nacl;
var module = {};
var blobToArrayBuffer = function (blob, cb) {
var reader = new FileReader();
reader.onloadend = function () {
cb(void 0, this.result);
};
reader.readAsArrayBuffer(blob);
};
var arrayBufferToString = function (AB) {
try {
return Nacl.util.encodeBase64(new Uint8Array(AB));
} catch (e) {
console.error(e);
return null;
}
};
module.create = function (common, config) {
var File = {};
var Cryptpad = common.getCryptpadCommon();
var Messages = Cryptpad.Messages;
var queue = File.queue = {
queue: [],
inProgress: false
};
var uid = function () {
return 'cp-fileupload-element-' + String(Math.random()).substring(2);
};
var $table = File.$table = $('<table>', { id: 'cp-fileupload-table' });
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) {
console.log($body);
File.$container = $('<div>', { id: 'cp-fileupload' }).append($table).appendTo($body);
console.log('done');
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 sframeChan = common.getSframeChannel();
var onError = $.noop,
onComplete = $.noop,
updateProgress = $.noop,
onPending = $.noop;
sframeChan.on('EV_FILE_UPLOAD_STATE', function (data) {
if (data.error) {
return void onError(data.error);
}
if (data.complete && data.href) {
return void onComplete(data.href);
}
if (typeof data.progress !== "undefined") {
return void updateProgress(data.progress);
}
});
sframeChan.on('Q_CANCEL_PENDING_FILE_UPLOAD', function (data, cb) {
onPending(cb);
});
var upload = function (file) {
var blob = file.blob; // This is not a blob but an array buffer
var u8 = new Uint8Array(blob);
var metadata = file.metadata;
var id = file.id;
var dropEvent = file.dropEvent;
delete file.dropEvent;
if (queue.inProgress) { return; }
queue.inProgress = true;
var $row = $table.find('tr[id="'+id+'"]');
$row.find('.cp-fileupload-table-cancel').html('-');
var $pv = $row.find('.cp-fileupload-table-progress-value');
var $pb = $row.find('.cp-fileupload-table-progress-container');
var $pc = $row.find('.cp-fileupload-table-progress');
var $link = $row.find('.cp-fileupload-table-link');
updateProgress = function (progressValue) {
$pv.text(Math.round(progressValue*100)/100 + '%');
$pb.css({
width: (progressValue/100)*$pc.width()+'px'
});
};
onComplete = function (href) {
$link.attr('href', href)
.click(function (e) {
e.preventDefault();
window.open($link.attr('href'), '_blank');
});
var title = metadata.name;
Cryptpad.log(Messages._getKey('upload_success', [title]));
common.prepareFeedback('upload')();
if (config.onUploaded) {
var data = getData(file, href);
config.onUploaded(dropEvent, data);
}
queue.inProgress = false;
queue.next();
};
onError = function (e) {
queue.inProgress = false;
queue.next();
if (e === 'TOO_LARGE') {
// TODO update table to say too big?
return void Cryptpad.alert(Messages.upload_tooLarge);
}
if (e === 'NOT_ENOUGH_SPACE') {
// TODO update table to say not enough space?
return void Cryptpad.alert(Messages.upload_notEnoughSpace);
}
console.error(e);
return void Cryptpad.alert(Messages.upload_serverError);
};
onPending = function (cb) {
Cryptpad.confirm(Messages.upload_uploadPending, cb);
};
file.noStore = config.noStore;
try {
file.blob = Nacl.util.encodeBase64(u8);
common.uploadFile(file, function () {
console.log('Upload started...');
});
} catch (e) {
Cryptpad.alert(Messages.upload_serverError);
}
};
var prettySize = function (bytes) {
var kB = Cryptpad.bytesToKilobytes(bytes);
if (kB < 1024) { return kB + Messages.KB; }
var mB = Cryptpad.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; }
// setTimeout to fix a firefox error 'NS_ERROR_NOT_AVAILABLE'
window.setTimeout(function () { File.$container.show(); });
var file = queue.queue.shift();
upload(file);
};
queue.push = function (obj) {
var id = uid();
obj.id = id;
queue.queue.push(obj);
// setTimeout to fix a firefox error 'NS_ERROR_NOT_AVAILABLE'
window.setTimeout(function () { $table.show(); });
var estimate = FileCrypto.computeEncryptedSize(obj.blob.byteLength, obj.metadata);
var $progressBar = $('<div>', {'class':'cp-fileupload-table-progress-container'});
var $progressValue = $('<span>', {'class':'cp-fileupload-table-progress-value'}).text(Messages.upload_pending);
var $tr = $('<tr>', {id: id}).appendTo($table);
var $cancel = $('<span>', {'class': 'cp-fileupload-table-cancel-button fa fa-times'}).click(function () {
queue.queue = queue.queue.filter(function (el) { return el.id !== id; });
$cancel.remove();
$tr.find('.cp-fileupload-table-cancel').text('-');
$tr.find('.cp-fileupload-table-progress-value').text(Messages.upload_cancelled);
});
var $link = $('<a>', {
'class': 'cp-fileupload-table-link',
'rel': 'noopener noreferrer'
}).text(obj.metadata.name);
$('<td>').append($link).appendTo($tr);
$('<td>').text(prettySize(estimate)).appendTo($tr);
$('<td>', {'class': 'cp-fileupload-table-progress'}).append($progressBar).append($progressValue).appendTo($tr);
$('<td>', {'class': 'cp-fileupload-table-cancel'}).append($cancel).appendTo($tr);
queue.next();
};
var handleFile = File.handleFile = function (file, e, thumbnail) {
var thumb;
var finish = function (arrayBuffer) {
var metadata = {
name: file.name,
type: file.type,
};
if (thumb) { metadata.thumbnail = thumb; }
queue.push({
blob: arrayBuffer,
metadata: metadata,
dropEvent: e
});
};
var processFile = function () {
blobToArrayBuffer(file, function (e, buffer) {
finish(buffer);
});
};
if (!thumbnail) { return void processFile(); }
blobToArrayBuffer(thumbnail, function (e, buffer) {
if (e) { console.error(e); }
thumb = arrayBufferToString(buffer);
processFile();
});
};
var onFileDrop = File.onFileDrop = function (file, e) {
if (!common.isLoggedIn()) {
return Cryptpad.alert(common.Messages.upload_mustLogin);
}
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; }
if (!$area) { return; }
$hoverArea
.on('dragenter', function (e) {
e.preventDefault();
e.stopPropagation();
counter++;
$hoverArea.addClass('cp-fileupload-hovering');
})
.on('dragleave', function (e) {
e.preventDefault();
e.stopPropagation();
counter--;
if (counter <= 0) {
$hoverArea.removeClass('cp-fileupload-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('cp-fileupload-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;
});

View File

@@ -81,9 +81,9 @@ define([
var states = [];
var c = states.length - 1;
var $hist = $toolbar.find('.cryptpad-toolbar-history');
var $left = $toolbar.find('.cryptpad-toolbar-leftside');
var $right = $toolbar.find('.cryptpad-toolbar-rightside');
var $hist = $toolbar.find('.cp-toolbar-history');
var $left = $toolbar.find('.cp-toolbar-leftside');
var $right = $toolbar.find('.cp-toolbar-rightside');
var $cke = $toolbar.find('.cke_toolbox_main');
$hist.html('').show();
@@ -111,9 +111,9 @@ define([
var val = states[i].getContent().doc;
c = i;
if (typeof onUpdate === "function") { onUpdate(); }
$hist.find('.next, .previous').css('visibility', '');
if (c === states.length - 1) { $hist.find('.next').css('visibility', 'hidden'); }
if (c === 0) { $hist.find('.previous').css('visibility', 'hidden'); }
$hist.find('.cp-toolbar-history-next, .cp-toolbar-history-previous').css('visibility', '');
if (c === states.length - 1) { $hist.find('.cp-toolbar-history-next').css('visibility', 'hidden'); }
if (c === 0) { $hist.find('.cp-toolbar-history-previous').css('visibility', 'hidden'); }
return val || '';
};
@@ -128,18 +128,18 @@ define([
var display = function () {
$hist.html('');
var $prev =$('<button>', {
'class': 'previous fa fa-step-backward buttonPrimary',
'class': 'cp-toolbar-history-previous fa fa-step-backward buttonPrimary',
title: Messages.history_prev
}).appendTo($hist);
var $nav = $('<div>', {'class': 'goto'}).appendTo($hist);
var $nav = $('<div>', {'class': 'cp-toolbar-history-goto'}).appendTo($hist);
var $next = $('<button>', {
'class': 'next fa fa-step-forward buttonPrimary',
'class': 'cp-toolbar-history-next fa fa-step-forward buttonPrimary',
title: Messages.history_next
}).appendTo($hist);
$('<label>').text(Messages.history_version).appendTo($nav);
var $cur = $('<input>', {
'class' : 'gotoInput',
'class' : 'cp-toolbar-history-goto-input',
'type' : 'number',
'min' : '1',
'max' : states.length
@@ -150,11 +150,11 @@ define([
var $label2 = $('<label>').text(' / '+ states.length).appendTo($nav);
$('<br>').appendTo($nav);
var $close = $('<button>', {
'class':'closeHistory',
'class':'cp-toolbar-history-close',
title: Messages.history_closeTitle
}).text(Messages.history_closeTitle).appendTo($nav);
var $rev = $('<button>', {
'class':'revertHistory buttonSuccess',
'class':'cp-toolbar-history-revert buttonSuccess',
title: Messages.history_restoreTitle
}).text(Messages.history_restore).appendTo($nav);
if (History.readOnly) { $rev.hide(); }
@@ -170,6 +170,7 @@ define([
$left.show();
$right.show();
$cke.show();
$(window).trigger('resize');
};
// Buttons actions
@@ -203,6 +204,7 @@ define([
// Display the latest content
render(get(c));
$(window).trigger('resize');
};
// Load all the history messages into a new chainpad object

View File

@@ -39,7 +39,7 @@ define([
var MutationObserver = window.MutationObserver;
var displayDefault = function () {
var text = Cryptpad.getFirstEmojiOrCharacter(name);
var $avatar = $('<span>', {'class': 'default'}).text(text);
var $avatar = $('<span>', {'class': 'cp-avatar-default'}).text(text);
$container.append($avatar);
if (cb) { cb(); }
};
@@ -207,7 +207,7 @@ define([
var $displayName = $userAdmin.find('.'+displayNameCls);
var $avatar = $userAdmin.find('.buttonTitle');
var $avatar = $userAdmin.find('.cp-dropdown-button-title');
var oldUrl;
var updateButton = function () {
var myData = metadataMgr.getUserData();
@@ -220,7 +220,7 @@ define([
UI.displayAvatar(Common, $avatar, url, newName, function ($img) {
oldUrl = url;
if ($img) {
$userAdmin.find('button').addClass('avatar');
$userAdmin.find('button').addClass('cp-avatar');
}
});
}
@@ -260,6 +260,44 @@ define([
return $userAdmin;
};
UI.initFilePicker = function (common, cfg) {
var onSelect = cfg.onSelect || $.noop;
var sframeChan = common.getSframeChannel();
sframeChan.on("EV_FILE_PICKED", function (data) {
onSelect(data);
});
};
UI.openFilePicker = function (common, types) {
var sframeChan = common.getSframeChannel();
sframeChan.event("EV_FILE_PICKER_OPEN", types);
};
UI.openTemplatePicker = function (common) {
var metadataMgr = common.getMetadataMgr();
var type = metadataMgr.getMetadataLazy().type;
var first = true; // We can only pick a template once (for a new document)
var fileDialogCfg = {
onSelect: function (data) {
if (data.type === type && first) {
Cryptpad.addLoadingScreen(null, true);
var sframeChan = common.getSframeChannel();
sframeChan.query('Q_TEMPLATE_USE', data.href, function () {
first = false;
Cryptpad.removeLoadingScreen();
common.feedback('TEMPLATE_USED');
});
return;
}
}
};
common.initFilePicker(common, fileDialogCfg);
var pickerCfg = {
types: [type],
where: ['template']
};
common.openFilePicker(common, pickerCfg);
};
return UI;
});

View File

@@ -0,0 +1,302 @@
// Load #1, load as little as possible because we are in a race to get the loading screen up.
define([
'/bower_components/nthen/index.js',
'/api/config',
'jquery',
], function (nThen, ApiConfig, $) {
var common = {};
common.start = function () {
var secret;
var hashes;
var CpNfOuter;
var Cryptpad;
var Crypto;
var Cryptget;
var sframeChan;
var FilePicker;
nThen(function (waitFor) {
// Load #2, the loading screen is up so grab whatever you need...
require([
'/common/sframe-chainpad-netflux-outer.js',
'/common/cryptpad-common.js',
'/bower_components/chainpad-crypto/crypto.js',
'/common/cryptget.js',
'/common/sframe-channel.js',
'/filepicker/main.js',
], waitFor(function (_CpNfOuter, _Cryptpad, _Crypto, _Cryptget, SFrameChannel,
_FilePicker) {
CpNfOuter = _CpNfOuter;
Cryptpad = _Cryptpad;
Crypto = _Crypto;
Cryptget = _Cryptget;
FilePicker = _FilePicker;
SFrameChannel.create($('#sbox-iframe')[0].contentWindow, waitFor(function (sfc) {
sframeChan = sfc;
}));
Cryptpad.ready(waitFor());
}));
}).nThen(function (waitFor) {
secret = Cryptpad.getSecrets();
if (!secret.channel) {
// New pad: create a new random channel id
secret.channel = Cryptpad.createChannelId();
}
Cryptpad.getShareHashes(secret, waitFor(function (err, h) { hashes = h; }));
}).nThen(function () {
var readOnly = secret.keys && !secret.keys.editKeyStr;
if (!secret.keys) { secret.keys = secret.key; }
var parsed = Cryptpad.parsePadUrl(window.location.href);
if (!parsed.type) { throw new Error(); }
var defaultTitle = Cryptpad.getDefaultName(parsed);
var proxy = Cryptpad.getProxy();
var updateMeta = function () {
//console.log('EV_METADATA_UPDATE');
var name;
nThen(function (waitFor) {
Cryptpad.getLastName(waitFor(function (err, n) {
if (err) { console.log(err); }
name = n;
}));
}).nThen(function (/*waitFor*/) {
sframeChan.event('EV_METADATA_UPDATE', {
doc: {
defaultTitle: defaultTitle,
type: parsed.type
},
user: {
name: name,
uid: Cryptpad.getUid(),
avatar: Cryptpad.getAvatarUrl(),
profile: Cryptpad.getProfileUrl(),
curvePublic: proxy.curvePublic,
netfluxId: Cryptpad.getNetwork().webChannels[0].myID,
},
priv: {
accountName: Cryptpad.getAccountName(),
origin: window.location.origin,
pathname: window.location.pathname,
readOnly: readOnly,
availableHashes: hashes,
isTemplate: Cryptpad.isTemplate(window.location.href),
feedbackAllowed: Cryptpad.isFeedbackAllowed(),
friends: proxy.friends || {},
settings: proxy.settings || {}
}
});
});
};
Cryptpad.onDisplayNameChanged(updateMeta);
sframeChan.onReg('EV_METADATA_UPDATE', updateMeta);
proxy.on('change', 'settings', updateMeta);
Cryptpad.onError(function (info) {
console.log('error');
console.log(info);
if (info && info.type === "store") {
//onConnectError();
}
});
sframeChan.on('Q_ANON_RPC_MESSAGE', function (data, cb) {
Cryptpad.anonRpcMsg(data.msg, data.content, function (err, response) {
cb({error: err, response: response});
});
});
sframeChan.on('Q_SET_PAD_TITLE_IN_DRIVE', function (newTitle, cb) {
document.title = newTitle;
Cryptpad.renamePad(newTitle, undefined, function (err) {
if (err) { cb('ERROR'); } else { cb(); }
});
});
sframeChan.on('Q_SETTINGS_SET_DISPLAY_NAME', function (newName, cb) {
Cryptpad.setAttribute('username', newName, function (err) {
if (err) {
console.log("Couldn't set username");
console.error(err);
cb('ERROR');
return;
}
Cryptpad.changeDisplayName(newName, true);
cb();
});
});
sframeChan.on('Q_LOGOUT', function (data, cb) {
Cryptpad.logout(cb);
});
sframeChan.on('EV_NOTIFY', function () {
Cryptpad.notify();
});
sframeChan.on('Q_SET_LOGIN_REDIRECT', function (data, cb) {
sessionStorage.redirectTo = window.location.href;
cb();
});
sframeChan.on('Q_GET_PIN_LIMIT_STATUS', function (data, cb) {
Cryptpad.isOverPinLimit(function (e, overLimit, limits) {
cb({
error: e,
overLimit: overLimit,
limits: limits
});
});
});
sframeChan.on('Q_MOVE_TO_TRASH', function (data, cb) {
Cryptpad.moveToTrash(cb);
});
sframeChan.on('Q_SAVE_AS_TEMPLATE', function (data, cb) {
Cryptpad.saveAsTemplate(Cryptget.put, data, cb);
});
sframeChan.on('Q_SEND_FRIEND_REQUEST', function (netfluxId, cb) {
Cryptpad.inviteFromUserlist(Cryptpad, netfluxId);
cb();
});
Cryptpad.onFriendRequest = function (confirmText, cb) {
sframeChan.query('Q_INCOMING_FRIEND_REQUEST', confirmText, function (err, data) {
cb(data);
});
};
Cryptpad.onFriendComplete = function (data) {
sframeChan.event('EV_FRIEND_REQUEST', data);
};
sframeChan.on('Q_GET_FULL_HISTORY', function (data, cb) {
var network = Cryptpad.getNetwork();
var hkn = network.historyKeeper;
var crypto = Crypto.createEncryptor(secret.keys);
// Get the history messages and send them to the iframe
var parse = function (msg) {
try {
return JSON.parse(msg);
} catch (e) {
return null;
}
};
var onMsg = function (msg) {
var parsed = parse(msg);
if (parsed[0] === 'FULL_HISTORY_END') {
console.log('END');
cb();
return;
}
if (parsed[0] !== 'FULL_HISTORY') { return; }
if (parsed[1] && parsed[1].validateKey) { // First message
secret.keys.validateKey = parsed[1].validateKey;
return;
}
msg = parsed[1][4];
if (msg) {
msg = msg.replace(/^cp\|/, '');
var decryptedMsg = crypto.decrypt(msg, secret.keys.validateKey);
sframeChan.event('EV_RT_HIST_MESSAGE', decryptedMsg);
}
};
network.on('message', onMsg);
network.sendto(hkn, JSON.stringify(['GET_FULL_HISTORY', secret.channel, secret.keys.validateKey]));
});
sframeChan.on('Q_GET_PAD_ATTRIBUTE', function (data, cb) {
Cryptpad.getPadAttribute(data.key, function (e, data) {
cb({
error: e,
data: data
});
});
});
sframeChan.on('Q_SET_PAD_ATTRIBUTE', function (data, cb) {
Cryptpad.setPadAttribute(data.key, data.value, function (e) {
cb({error:e});
});
});
var onFileUpload = function (sframeChan, data, cb) {
var sendEvent = function (data) {
sframeChan.event("EV_FILE_UPLOAD_STATE", data);
};
var updateProgress = function (progressValue) {
sendEvent({
progress: progressValue
});
};
var onComplete = function (href) {
sendEvent({
complete: true,
href: href
});
};
var onError = function (e) {
sendEvent({
error: e
});
};
var onPending = function (cb) {
sframeChan.query('Q_CANCEL_PENDING_FILE_UPLOAD', null, function (err, data) {
if (data) {
cb();
}
});
};
data.blob = Crypto.Nacl.util.decodeBase64(data.blob);
Cryptpad.uploadFileSecure(data, data.noStore, Cryptpad, updateProgress, onComplete, onError, onPending);
cb();
};
sframeChan.on('Q_UPLOAD_FILE', function (data, cb) {
onFileUpload(sframeChan, data, cb);
});
var FP = {};
var initFilePicker = function (types) {
var config = {};
config.onFilePicked = function (data) {
sframeChan.event('EV_FILE_PICKED', data);
};
config.onClose = function () {
FP.$iframe.hide();
};
config.onFileUpload = onFileUpload;
config.types = types;
if (!FP.$iframe) {
FP.$iframe = $('<iframe>', {id: 'sbox-filePicker-iframe'}).appendTo($('body'));
FP.picker = FilePicker.create(config);
} else {
FP.$iframe.show();
FP.picker.refresh(types);
}
};
sframeChan.on('EV_FILE_PICKER_OPEN', function (data) {
initFilePicker(data);
});
sframeChan.on('Q_TEMPLATE_USE', function (href, cb) {
Cryptpad.useTemplate(href, Cryptget, cb);
});
CpNfOuter.start({
sframeChan: sframeChan,
channel: secret.channel,
network: Cryptpad.getNetwork(),
validateKey: secret.keys.validateKey || undefined,
readOnly: readOnly,
crypto: Crypto.createEncryptor(secret.keys),
onConnect: function (wc) {
if (readOnly) { return; }
Cryptpad.replaceHash(Cryptpad.getEditHashFromKeys(wc.id, secret.keys));
}
});
Cryptpad.reportAppUsage();
});
};
return common;
});

View File

@@ -62,7 +62,7 @@ define(['jquery'], function ($) {
metadataMgr.onChange(function () {
var md = metadataMgr.getMetadata();
$title.find('span.title').text(md.title || md.defaultTitle);
$title.find('span.cp-toolbar-title-value').text(md.title || md.defaultTitle);
$title.find('input').val(md.title || md.defaultTitle);
exp.title = md.title;
//exp.updateTitle(md.title || md.defaultTitle);

View File

@@ -7,12 +7,13 @@ define([
'/common/sframe-common-title.js',
'/common/sframe-common-interface.js',
'/common/sframe-common-history.js',
'/common/sframe-common-file.js',
'/common/metadata-manager.js',
'/customize/application_config.js',
'/common/cryptpad-common.js',
'/common/common-realtime.js'
], function ($, nThen, Messages, CpNfInner, SFrameChannel, Title, UI, History, MetadataMgr,
], function ($, nThen, Messages, CpNfInner, SFrameChannel, Title, UI, History, File, MetadataMgr,
AppConfig, Cryptpad, CommonRealtime) {
// Chainpad Netflux Inner
@@ -36,6 +37,9 @@ define([
funcs.getCryptpadCommon = function () {
return Cryptpad;
};
funcs.getSframeChannel = function () {
return ctx.sframeChan;
};
var isLoggedIn = funcs.isLoggedIn = function () {
if (!ctx.cpNfInner) { throw new Error("cpNfInner is not ready!"); }
@@ -51,6 +55,9 @@ define([
// UI
funcs.createUserAdminMenu = UI.createUserAdminMenu;
funcs.displayAvatar = UI.displayAvatar;
funcs.initFilePicker = UI.initFilePicker;
funcs.openFilePicker = UI.openFilePicker;
funcs.openTemplatePicker = UI.openTemplatePicker;
// History
funcs.getHistory = function (config) { return History.create(funcs, config); };
@@ -107,6 +114,26 @@ define([
ctx.sframeChan.query('Q_GET_FULL_HISTORY', null, cb);
};
funcs.getPadAttribute = function (key, cb) {
ctx.sframeChan.query('Q_GET_PAD_ATTRIBUTE', {
key: key
}, function (err, res) {
cb (err || res.error, res.data);
});
};
funcs.setPadAttribute = function (key, value, cb) {
ctx.sframeChan.query('Q_SET_PAD_ATTRIBUTE', {
key: key,
value: value
}, cb);
};
// Files
funcs.uploadFile = function (data, cb) {
ctx.sframeChan.query('Q_UPLOAD_FILE', data, cb);
};
funcs.createFileManager = function (config) { return File.create(funcs, config); };
// Friends
var pendingFriends = [];
funcs.getPendingFriends = function () {
@@ -133,7 +160,7 @@ define([
url: href,
});
};
var prepareFeedback = function (key) {
var prepareFeedback = funcs.prepareFeedback = function (key) {
if (typeof(key) !== 'string') { return $.noop; }
var type = ctx.metadataMgr.getMetadata().type;
@@ -155,7 +182,7 @@ define([
button = $('<button>', {
'class': 'fa fa-download',
title: Messages.exportButtonTitle,
}).append($('<span>', {'class': 'drawer'}).text(Messages.exportButton));
}).append($('<span>', {'class': 'cp-toolbar-drawer-element'}).text(Messages.exportButton));
button.click(prepareFeedback(type));
if (callback) {
@@ -166,7 +193,7 @@ define([
button = $('<button>', {
'class': 'fa fa-upload',
title: Messages.importButtonTitle,
}).append($('<span>', {'class': 'drawer'}).text(Messages.importButton));
}).append($('<span>', {'class': 'cp-toolbar-drawer-element'}).text(Messages.importButton));
if (callback) {
button
.click(prepareFeedback(type))
@@ -175,6 +202,30 @@ define([
}, {accept: data ? data.accept : undefined}));
}
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
};
if (data.filter && !data.filter(file)) {
Cryptpad.log('TODO: invalid avatar (type or size)');
return;
}
data.FM.handleFile(file, ev);
if (callback) { callback(); }
});
if (data.accept) { $input.attr('accept', data.accept); }
button.click(function () { $input.click(); });
break;
case 'template':
if (!AppConfig.enableTemplates) { return; }
button = $('<button>', {
@@ -230,7 +281,7 @@ define([
style: 'font:'+size+' FontAwesome'
});
if (!isStrongestStored()) {
button.addClass('hidden');
button.addClass('cp-toolbar-hidden');
}
if (callback) {
button
@@ -259,7 +310,7 @@ define([
button = $('<button>', {
title: Messages.historyButton,
'class': "fa fa-history history",
}).append($('<span>', {'class': 'drawer'}).text(Messages.historyText));
}).append($('<span>', {'class': 'cp-toolbar-drawer-element'}).text(Messages.historyText));
if (data.histConfig) {
button
.click(prepareFeedback(type))
@@ -271,7 +322,7 @@ define([
case 'more':
button = $('<button>', {
title: Messages.moreActions || 'TODO',
'class': "drawer-button fa fa-ellipsis-h",
'class': "cp-toolbar-drawer-button fa fa-ellipsis-h",
style: 'font:'+size+' FontAwesome'
});
break;
@@ -283,18 +334,26 @@ define([
.click(prepareFeedback(type));
}
if (rightside) {
button.addClass('rightside-button');
button.addClass('cp-toolbar-rightside-button');
}
return button;
};
// Can, only be called by the filepicker app
funcs.getFilesList = function (types, cb) {
ctx.sframeChan.query('Q_GET_FILES_LIST', types, function (err, data) {
cb(err || data.error, data.data);
});
};
/* funcs.storeLinkToClipboard = function (readOnly, cb) {
ctx.sframeChan.query('Q_STORE_LINK_TO_CLIPBOARD', readOnly, function (err) {
if (cb) { cb(err); }
});
};
*/
Object.freeze(funcs);
return { create: function (cb) {
nThen(function (waitFor) {

View File

@@ -82,4 +82,29 @@ define({
// Set the tab notification when the content of the pad changes
'EV_NOTIFY': true,
// Send the new settings to the inner iframe when they are changed in the proxy
'EV_SETTINGS_UPDATE': true,
// Get and set pad attributes stored in the drive from the inner iframe
'Q_GET_PAD_ATTRIBUTE': true,
'Q_SET_PAD_ATTRIBUTE': true,
// Open/close the File picker (sent from the iframe to the outside)
'EV_FILE_PICKER_OPEN': true,
'EV_FILE_PICKER_CLOSE': true,
'EV_FILE_PICKER_REFRESH': true,
// File selected in the file picker: sent from the filepicker iframe to the outside
// and then send to the inner iframe
'EV_FILE_PICKED': true,
// Get all the files from the drive to display them in a file picker secure app
'Q_GET_FILES_LIST': true,
// Template picked, replace the content of the pad
'Q_TEMPLATE_USE': true,
// File upload queries and events
'Q_UPLOAD_FILE': true,
'EV_FILE_UPLOAD_STATE': true,
'Q_CANCEL_PENDING_FILE_UPLOAD': true,
});

View File

@@ -64,8 +64,8 @@ define([
'class': USER_CLS
}).appendTo($topContainer);
$('<span>', {'class': LIMIT_CLS}).hide().appendTo($userContainer);
$('<span>', {'class': NEWPAD_CLS + ' dropdown-bar'}).hide().appendTo($userContainer);
$('<span>', {'class': USERADMIN_CLS + ' dropdown-bar'}).hide().appendTo($userContainer);
$('<span>', {'class': NEWPAD_CLS + ' cp-dropdown-container'}).hide().appendTo($userContainer);
$('<span>', {'class': USERADMIN_CLS + ' cp-dropdown-container'}).hide().appendTo($userContainer);
$toolbar.append($topContainer)
.append($('<div>', {'class': LEFTSIDE_CLS}))
@@ -75,7 +75,7 @@ define([
var $rightside = $toolbar.find('.'+RIGHTSIDE_CLS);
if (!config.hideDrawer) {
var $drawerContent = $('<div>', {
'class': DRAWER_CLS,// + ' dropdown-bar-content cryptpad-dropdown'
'class': DRAWER_CLS,
'tabindex': 1
}).appendTo($rightside).hide();
var $drawer = Cryptpad.createButton('more', true).appendTo($rightside);
@@ -270,7 +270,7 @@ define([
var fa_editusers = '<span class="fa fa-users"></span>';
var fa_viewusers = '<span class="fa fa-eye"></span>';
var $spansmall = $('<span>').html(fa_editusers + ' ' + numberOfEditUsers + '&nbsp;&nbsp; ' + fa_viewusers + ' ' + numberOfViewUsers);
$userButtons.find('.buttonTitle').html('').append($spansmall);
$userButtons.find('.cp-dropdown-button-title').html('').append($spansmall);
updateDisplayName(toolbar, config);
};
@@ -311,7 +311,7 @@ define([
var $container = $('<span>', {id: 'userButtons', title: Messages.userListButton});
var $button = $('<button>').appendTo($container);
$('<span>',{'class': 'buttonTitle'}).appendTo($button);
$('<span>',{'class': 'cp-dropdown-button-title'}).appendTo($button);
toolbar.$leftside.prepend($container);
@@ -444,7 +444,7 @@ define([
};
var $shareBlock = Cryptpad.createDropdown(dropdownConfigShare);
//$shareBlock.find('button').attr('id', 'shareButton');
$shareBlock.find('.dropdown-bar-content').addClass(SHARE_CLS).addClass(EDITSHARE_CLS).addClass(VIEWSHARE_CLS);
$shareBlock.find('.cp-dropdown-content').addClass(SHARE_CLS).addClass(EDITSHARE_CLS).addClass(VIEWSHARE_CLS);
$shareBlock.addClass('shareButton');
$shareBlock.find('button').attr('title', Messages.shareButton);
@@ -731,9 +731,6 @@ define([
};
var createNewPad = function (toolbar) {
/*var $newPad = $('<span>', {
'class': NEWPAD_CLS + " dropdown-bar"
}).appendTo(toolbar.$top);*/
var $newPad = toolbar.$top.find('.'+NEWPAD_CLS).show();
var pads_options = [];
@@ -822,7 +819,7 @@ define([
// Events
var initClickEvents = function (toolbar, config) {
var removeDropdowns = function () {
toolbar.$toolbar.find('.cryptpad-dropdown').hide();
toolbar.$toolbar.find('.cp-dropdown-content').hide();
};
var cancelEditTitle = function (e) {
// Now we want to apply the title even if we click somewhere else

View File

@@ -14,36 +14,37 @@ define([
var SPINNER_DISAPPEAR_TIME = 1000;
// Toolbar parts
var TOOLBAR_CLS = Bar.constants.toolbar = 'cryptpad-toolbar';
var TOP_CLS = Bar.constants.top = 'cryptpad-toolbar-top';
var LEFTSIDE_CLS = Bar.constants.leftside = 'cryptpad-toolbar-leftside';
var RIGHTSIDE_CLS = Bar.constants.rightside = 'cryptpad-toolbar-rightside';
var DRAWER_CLS = Bar.constants.drawer = 'drawer-content';
var HISTORY_CLS = Bar.constants.history = 'cryptpad-toolbar-history';
var TOOLBAR_CLS = Bar.constants.toolbar = 'cp-toolbar';
var TOP_CLS = Bar.constants.top = 'cp-toolbar-top';
var LEFTSIDE_CLS = Bar.constants.leftside = 'cp-toolbar-leftside';
var RIGHTSIDE_CLS = Bar.constants.rightside = 'cp-toolbar-rightside';
var DRAWER_CLS = Bar.constants.drawer = 'cp-toolbar-drawer-content';
var HISTORY_CLS = Bar.constants.history = 'cp-toolbar-history';
// Userlist
var USERLIST_CLS = Bar.constants.userlist = "cryptpad-dropdown-users";
var EDITSHARE_CLS = Bar.constants.editShare = "cryptpad-dropdown-editShare";
var VIEWSHARE_CLS = Bar.constants.viewShare = "cryptpad-dropdown-viewShare";
var SHARE_CLS = Bar.constants.viewShare = "cryptpad-dropdown-share";
var USERLIST_CLS = Bar.constants.userlist = "cp-toolbar-users";
var EDITSHARE_CLS = Bar.constants.editShare = "cp-toolbar-share-edit";
var VIEWSHARE_CLS = Bar.constants.viewShare = "cp-toolbar-share-view";
var SHARE_CLS = Bar.constants.viewShare = "cp-toolbar-share";
// Top parts
var USER_CLS = Bar.constants.userAdmin = "cryptpad-user";
var SPINNER_CLS = Bar.constants.spinner = 'cryptpad-spinner';
var LIMIT_CLS = Bar.constants.lag = 'cryptpad-limit';
var TITLE_CLS = Bar.constants.title = "cryptpad-title";
var NEWPAD_CLS = Bar.constants.newpad = "cryptpad-new";
var USER_CLS = Bar.constants.userAdmin = "cp-toolbar-user";
var SPINNER_CLS = Bar.constants.spinner = 'cp-toolbar-spinner';
var LIMIT_CLS = Bar.constants.limit = 'cp-toolbar-limit';
var TITLE_CLS = Bar.constants.title = "cp-toolbar-title";
var NEWPAD_CLS = Bar.constants.newpad = "cp-toolbar-new";
var LINK_CLS = Bar.constants.link = "cp-toolbar-link";
// User admin menu
var USERADMIN_CLS = Bar.constants.user = 'cryptpad-user-dropdown';
var USERNAME_CLS = Bar.constants.username = 'cryptpad-toolbar-username';
/*var READONLY_CLS = */Bar.constants.readonly = 'cryptpad-readonly';
var USERBUTTON_CLS = Bar.constants.changeUsername = "cryptpad-change-username";
var USERADMIN_CLS = Bar.constants.user = 'cp-toolbar-user-dropdown';
var USERNAME_CLS = Bar.constants.username = 'cp-toolbar-user-name';
/*var READONLY_CLS = */Bar.constants.readonly = 'cp-toolbar-readonly';
var USERBUTTON_CLS = Bar.constants.changeUsername = "cp-toolbar-user-rename";
// Create the toolbar element
var uid = function () {
return 'cryptpad-uid-' + String(Math.random()).substring(2);
return 'cp-toolbar-uid-' + String(Math.random()).substring(2);
};
var createRealtimeToolbar = function (config) {
@@ -54,21 +55,14 @@ define([
id: uid(),
});
// TODO iframe
// var parsed = Cryptpad.parsePadUrl(window.location.href);
var parsed = { type:'pad' };
if (typeof parsed.type === "string") {
config.$container.parents('body').addClass('app-' + parsed.type);
}
var $topContainer = $('<div>', {'class': TOP_CLS});
$('<span>', {'class': 'filler'}).appendTo($topContainer);
$('<span>', {'class': 'cp-toolbar-top-filler'}).appendTo($topContainer);
var $userContainer = $('<span>', {
'class': USER_CLS
}).appendTo($topContainer);
$('<span>', {'class': LIMIT_CLS}).hide().appendTo($userContainer);
$('<span>', {'class': NEWPAD_CLS + ' dropdown-bar'}).hide().appendTo($userContainer);
$('<span>', {'class': USERADMIN_CLS + ' dropdown-bar'}).hide().appendTo($userContainer);
$('<span>', {'class': NEWPAD_CLS + ' cp-dropdown-container'}).hide().appendTo($userContainer);
$('<span>', {'class': USERADMIN_CLS + ' cp-dropdown-container'}).hide().appendTo($userContainer);
$toolbar.append($topContainer)
.append($('<div>', {'class': LEFTSIDE_CLS}))
@@ -78,27 +72,27 @@ define([
var $rightside = $toolbar.find('.'+RIGHTSIDE_CLS);
if (!config.hideDrawer) {
var $drawerContent = $('<div>', {
'class': DRAWER_CLS,// + ' dropdown-bar-content cryptpad-dropdown'
'class': DRAWER_CLS,
'tabindex': 1
}).appendTo($rightside).hide();
var $drawer = Cryptpad.createButton('more', true).appendTo($rightside);
var $drawer = Common.createButton('more', true).appendTo($rightside);
$drawer.click(function () {
$drawerContent.toggle();
$drawer.removeClass('active');
$drawer.removeClass('cp-toolbar-button-active');
if ($drawerContent.is(':visible')) {
$drawer.addClass('active');
$drawer.addClass('cp-toolbar-button-active');
$drawerContent.focus();
}
});
var onBlur = function (e) {
if (e.relatedTarget) {
if ($(e.relatedTarget).is('.drawer-button')) { return; }
if ($(e.relatedTarget).is('.cp-toolbar-drawer-button')) { return; }
if ($(e.relatedTarget).parents('.'+DRAWER_CLS).length) {
$(e.relatedTarget).blur(onBlur);
return;
}
}
$drawer.removeClass('active');
$drawer.removeClass('cp-toolbar-button-active');
$drawerContent.hide();
};
$drawerContent.blur(onBlur);
@@ -106,7 +100,7 @@ define([
// The 'notitle' class removes the line added for the title with a small screen
if (!config.title || typeof config.title !== "object") {
$toolbar.addClass('notitle');
$toolbar.addClass('cp-toolbar-notitle');
}
$container.prepend($toolbar);
@@ -185,15 +179,15 @@ define([
var $editUsers = $userlistContent.find('.' + USERLIST_CLS).html('');
Cryptpad.clearTooltips();
var $editUsersList = $('<div>', {'class': 'userlist-others'});
var $editUsersList = $('<div>', {'class': 'cp-toolbar-userlist-others'});
// Editors
var pendingFriends = Common.getPendingFriends();
editUsersNames.forEach(function (data) {
var name = data.name || Messages.anonymous;
var $span = $('<span>', {'class': 'avatar'});
var $rightCol = $('<span>', {'class': 'right-col'});
var $nameSpan = $('<span>', {'class': 'name'}).text(name).appendTo($rightCol);
var $span = $('<span>', {'class': 'cp-avatar'});
var $rightCol = $('<span>', {'class': 'cp-toolbar-userlist-rightcol'});
var $nameSpan = $('<span>', {'class': 'cp-toolbar-userlist-name'}).text(name).appendTo($rightCol);
var isMe = data.curvePublic === user.curvePublic;
if (Common.isLoggedIn() && data.curvePublic) {
if (isMe) {
@@ -203,11 +197,11 @@ define([
$nameSpan.text(name);
} else if (!friends[data.curvePublic]) {
if (pendingFriends.indexOf(data.netfluxId) !== -1) {
$('<span>', {'class': 'friend'}).text(Messages.userlist_pending)
$('<span>', {'class': 'cp-toolbar-userlist-friend'}).text(Messages.userlist_pending)
.appendTo($rightCol);
} else {
$('<span>', {
'class': 'fa fa-user-plus friend',
'class': 'fa fa-user-plus cp-toolbar-userlist-friend',
'title': Messages._getKey('userlist_addAsFriendTitle', [
name
])
@@ -219,7 +213,7 @@ define([
}
}
if (data.profile) {
$span.addClass('clickable');
$span.addClass('cp-userlist-clickable');
$span.click(function () {
window.open(origin+'/profile/#' + data.profile);
});
@@ -242,7 +236,7 @@ define([
// Viewers
if (numberOfViewUsers > 0) {
var viewText = '<div class="viewer">';
var viewText = '<div class="cp-toolbar-userlist-viewer">';
var viewerText = numberOfViewUsers !== 1 ? Messages.viewers : Messages.viewer;
viewText += numberOfViewUsers + ' ' + viewerText + '</div>';
$editUsers.append(viewText);
@@ -252,7 +246,7 @@ define([
var fa_editusers = '<span class="fa fa-users"></span>';
var fa_viewusers = '<span class="fa fa-eye"></span>';
var $spansmall = $('<span>').html(fa_editusers + ' ' + numberOfEditUsers + '&nbsp;&nbsp; ' + fa_viewusers + ' ' + numberOfViewUsers);
$userButtons.find('.buttonTitle').html('').append($spansmall);
$userButtons.find('.cp-dropdown-button-title').html('').append($spansmall);
};
var initUserList = function (toolbar, config) {
@@ -278,21 +272,21 @@ define([
if (!config.metadataMgr) {
throw new Error("You must provide a `metadataMgr` to display the userlist");
}
var $content = $('<div>', {'class': 'userlist-drawer'});
var $content = $('<div>', {'class': 'cp-toolbar-userlist-drawer'});
$content.on('drop dragover', function (e) {
e.preventDefault();
e.stopPropagation();
});
var $closeIcon = $('<span>', {"class": "fa fa-window-close close"}).appendTo($content);
var $closeIcon = $('<span>', {"class": "fa fa-window-close cp-toolbar-userlist-drawer-close"}).appendTo($content);
$('<h2>').text(Messages.users).appendTo($content);
$('<p>', {'class': USERLIST_CLS}).appendTo($content);
toolbar.userlistContent = $content;
var $container = $('<span>', {id: 'userButtons', title: Messages.userListButton});
var $container = $('<span>', {id: 'cp-toolbar-userlist-drawer-open', title: Messages.userListButton});
var $button = $('<button>').appendTo($container);
$('<span>',{'class': 'buttonTitle'}).appendTo($button);
$('<span>',{'class': 'cp-dropdown-button-title'}).appendTo($button);
toolbar.$leftside.prepend($container);
@@ -304,7 +298,7 @@ define([
var mobile = $('body').width() <= 600;
var hide = function () {
$content.hide();
$button.removeClass('active');
$button.removeClass('cp-toolbar-button-active');
$ck.css({
'padding-left': '',
});
@@ -314,7 +308,7 @@ define([
if (mobile) {
$ck.hide();
}
$button.addClass('active');
$button.addClass('cp-toolbar-button-active');
$ck.css({
'padding-left': '175px',
});
@@ -370,7 +364,7 @@ define([
if (hashes.editHash) {
options.push({
tag: 'a',
attributes: {title: Messages.editShareTitle, 'class': 'editShare'},
attributes: {title: Messages.editShareTitle, 'class': 'cp-toolbar-share-edit-copy'},
content: '<span class="fa fa-users"></span> ' + Messages.editShare
});
if (readOnly) {
@@ -379,7 +373,7 @@ define([
tag: 'a',
attributes: {
title: Messages.editOpenTitle,
'class': 'editOpen',
'class': 'cp-toolbar-share-edit-open',
href: origin + pathname + '#' + hashes.editHash,
target: '_blank'
},
@@ -391,7 +385,7 @@ define([
if (hashes.viewHash) {
options.push({
tag: 'a',
attributes: {title: Messages.viewShareTitle, 'class': 'viewShare'},
attributes: {title: Messages.viewShareTitle, 'class': 'cp-toolbar-share-view-copy'},
content: '<span class="fa fa-eye"></span> ' + Messages.viewShare
});
if (!readOnly) {
@@ -400,7 +394,7 @@ define([
tag: 'a',
attributes: {
title: Messages.viewOpenTitle,
'class': 'viewOpen',
'class': 'cp-toolbar-share-view-open',
href: origin + pathname + '#' + hashes.viewHash,
target: '_blank'
},
@@ -414,12 +408,12 @@ define([
feedback: 'SHARE_MENU',
};
var $shareBlock = Cryptpad.createDropdown(dropdownConfigShare);
$shareBlock.find('.dropdown-bar-content').addClass(SHARE_CLS).addClass(EDITSHARE_CLS).addClass(VIEWSHARE_CLS);
$shareBlock.addClass('shareButton');
$shareBlock.find('.cp-dropdown-content').addClass(SHARE_CLS).addClass(EDITSHARE_CLS).addClass(VIEWSHARE_CLS);
$shareBlock.addClass('cp-toolbar-share-button');
$shareBlock.find('button').attr('title', Messages.shareButton);
if (hashes.editHash) {
$shareBlock.find('a.editShare').click(function () {
$shareBlock.find('a.cp-toolbar-share-edit-copy').click(function () {
/*Common.storeLinkToClipboard(false, function (err) {
if (!err) { Cryptpad.log(Messages.shareSuccess); }
});*/
@@ -429,7 +423,7 @@ define([
});
}
if (hashes.viewHash) {
$shareBlock.find('a.viewShare').click(function () {
$shareBlock.find('a.cp-toolbar-share-view-copy').click(function () {
/*Common.storeLinkToClipboard(true, function (err) {
if (!err) { Cryptpad.log(Messages.shareSuccess); }
});*/
@@ -451,7 +445,7 @@ define([
}
var $shareIcon = $('<span>', {'class': 'fa fa-share-alt'});
var $button = $('<button>', {'title': Messages.shareButton}).append($shareIcon);
$button.addClass('shareButton');
$button.addClass('cp-toolbar-share-button');
$button.click(function () {
var url = window.location.href;
var success = Cryptpad.Clipboard.copy(url);
@@ -464,11 +458,10 @@ define([
var createTitle = function (toolbar, config) {
var $titleContainer = $('<span>', {
id: 'toolbarTitle',
'class': TITLE_CLS
}).appendTo(toolbar.$top);
var $hoverable = $('<span>', {'class': 'hoverable'}).appendTo($titleContainer);
var $hoverable = $('<span>', {'class': 'cp-toolbar-title-hoverable'}).appendTo($titleContainer);
if (typeof config.title !== "object") {
console.error("config.title", config);
@@ -480,18 +473,18 @@ define([
// Buttons
var $text = $('<span>', {
'class': 'title'
'class': 'cp-toolbar-title-value'
}).appendTo($hoverable);
var $pencilIcon = $('<span>', {
'class': 'pencilIcon',
'class': 'cp-toolbar-title-edit',
'title': Messages.clickToEdit
});
var $saveIcon = $('<span>', {
'class': 'saveIcon',
'class': 'cp-toolbar-title-save',
'title': Messages.saveTitle
}).hide();
if (config.readOnly === 1) {
$titleContainer.append($('<span>', {'class': 'readOnly'})
$titleContainer.append($('<span>', {'class': 'cp-toolbar-title-readonly'})
.text('('+Messages.readonly+')'));
}
if (config.readOnly === 1 || typeof(Cryptpad) === "undefined") { return $titleContainer; }
@@ -501,14 +494,14 @@ define([
}).appendTo($hoverable).hide();
if (config.readOnly !== 1) {
$text.attr("title", Messages.clickToEdit);
$text.addClass("editable");
$text.addClass("cp-toolbar-title-editable");
var $icon = $('<span>', {
'class': 'fa fa-pencil readonly',
'class': 'fa fa-pencil cp-toolbar-title-icon-readonly',
style: 'font-family: FontAwesome;'
});
$pencilIcon.append($icon).appendTo($hoverable);
var $icon2 = $('<span>', {
'class': 'fa fa-check readonly',
'class': 'fa fa-check cp-toolbar-title-icon-readonly',
style: 'font-family: FontAwesome;'
});
$saveIcon.append($icon2).appendTo($hoverable);
@@ -571,23 +564,22 @@ define([
var createPageTitle = function (toolbar, config) {
if (config.title || !config.pageTitle) { return; }
var $titleContainer = $('<span>', {
id: 'toolbarTitle',
'class': TITLE_CLS
}).appendTo(toolbar.$top);
toolbar.$top.find('.filler').hide();
var $hoverable = $('<span>', {'class': 'hoverable'}).appendTo($titleContainer);
var $hoverable = $('<span>', {'class': 'cp-toolbar-title-hoverable'}).appendTo($titleContainer);
// Buttons
$('<span>', {
'class': 'title pageTitle'
'class': 'cp-toolbar-title-value cp-toolbar-title-value-page'
}).appendTo($hoverable).text(config.pageTitle);
};
var createLinkToMain = function (toolbar, config) {
var $linkContainer = $('<span>', {
'class': "cryptpad-link"
'class': LINK_CLS
}).appendTo(toolbar.$top);
// We need to override the "a" tag action here because it is inside the iframe!
@@ -601,7 +593,7 @@ define([
var $aTag = $('<a>', {
href: href,
title: buttonTitle,
'class': "cryptpad-logo"
'class': "cp-toolbar-link-logo"
}).append($('<img>', {
src: '/customize/images/logo_white.png?' + ApiConfig.requireConf.urlArgs
}));
@@ -784,7 +776,7 @@ define([
var initClickEvents = function (toolbar, config) {
var removeDropdowns = function () {
window.setTimeout(function () {
toolbar.$toolbar.find('.cryptpad-dropdown').hide();
toolbar.$toolbar.find('.cp-dropdown-content').hide();
});
};
var cancelEditTitle = function (e) {

View File

@@ -24,6 +24,11 @@ define([
var NEW_FOLDER_NAME = Messages.fm_newFolder;
var NEW_FILE_NAME = Messages.fm_newFile;
exp.ROOT = ROOT;
exp.UNSORTED = UNSORTED;
exp.TRASH = TRASH;
exp.TEMPLATE = TEMPLATE;
// Logging
var logging = function () {
console.log.apply(console, arguments);
@@ -151,6 +156,7 @@ define([
if (!attr || !attr.trim()) { return void cb("E_INVAL_ATTR"); }
var data = getFileData(id);
data[attr] = clone(value);
cb(null);
};
// PATHS
@@ -849,6 +855,7 @@ define([
}
try {
debug("Migrating file system...");
Cryptpad.feedback('Migrate-oldFilesData', true);
files.migrate = 1;
var next = function () {
var oldData = files[OLD_FILES_DATA].slice();