Add a pad creation page

pull/1/head
yflory 7 years ago
parent 0080dd7624
commit e96d54e655

@ -65,5 +65,7 @@ define(function() {
contacts: 'fa-users', contacts: 'fa-users',
}; };
config.displayCreationScreen = true;
return config; return config;
}); });

@ -0,0 +1,36 @@
@import (once) "./colortheme-all.less";
.creation_main() {
#cp-creation {
position: fixed;
z-index: 10000000; // #loading
top: 0px;
bottom: 0px;
left: 0px;
right: 0px;
background: @colortheme_loading-bg;
color: @colortheme_loading-color;
text-align: center;
font-size: 1.5em;
.cp-loading-container {
margin-top: 50vh;
transform: translateY(-50%);
}
.cp-loading-cryptofist {
margin-left: auto;
margin-right: auto;
height: 300px;
margin-bottom: 2em;
@media screen and (max-height: @browser_media-short-screen) {
display: none;
}
}
.cp-loading-spinner-container {
position: relative;
height: 100px;
> div {
height: 100px;
}
}
}
}

@ -4,6 +4,7 @@
@import (once) '../../customize/src/less2/include/fileupload.less'; @import (once) '../../customize/src/less2/include/fileupload.less';
@import (once) '../../customize/src/less2/include/alertify.less'; @import (once) '../../customize/src/less2/include/alertify.less';
@import (once) '../../customize/src/less2/include/tokenfield.less'; @import (once) '../../customize/src/less2/include/tokenfield.less';
@import (once) '../../customize/src/less2/include/creation.less';
@_cp-toolbar-color-warn: @colortheme_code-warn; @_cp-toolbar-color-warn: @colortheme_code-warn;
@ -11,6 +12,7 @@
.fileupload_main(); .fileupload_main();
.alertify_main(); .alertify_main();
.tokenfield_main(); .tokenfield_main();
.creation_main();
// body // body
&.cp-app-code { &.cp-app-code {

@ -387,7 +387,6 @@ define([
common.getAttribute(['general', 'markdown-help'], function (e, data) { common.getAttribute(['general', 'markdown-help'], function (e, data) {
if (e) { return void console.error(e); } if (e) { return void console.error(e); }
if (data === true && $toolbarButton.length && tbState) { if (data === true && $toolbarButton.length && tbState) {
console.log($toolbar.is(':visible'));
$toolbarButton.click(); $toolbarButton.click();
} }
}); });
@ -1120,5 +1119,81 @@ define([
}); });
}; };
UIElements.getPadCreationScreen = function (common, Toolbar, cb) {
if (!common.isLoggedIn()) { return void cb(); }
var sframeChan = common.getSframeChannel();
var metadataMgr = common.getMetadataMgr();
var $body = $('body');
var $creation = $('<div>', { id: 'cp-creation' }).appendTo($body);
var $bar = $('<div>', {'class': 'cp-toolbar'}).appendTo($creation);
// Create a toolbar?
var displayed = ['useradmin', 'newpad', 'limit', 'pageTitle'];
var configTb = {
displayed: displayed,
hideDisplayName: true,
$container: $bar,
metadataMgr: metadataMgr,
sfCommon: common,
pageTitle: 'Pad creation BETA'
};
var toolbar = Toolbar.create(configTb);
toolbar.$rightside.html('');
// Create the pad
var create = function (template) {
sframeChan.query("Q_CREATE_PAD", {
owned: true, // TODO
expire: false, // TODO
template: template
}, function () {
$creation.remove();
cb();
});
};
// Pick a template?
var type = metadataMgr.getMetadataLazy().type;
sframeChan.query("Q_TEMPLATE_EXIST", type, function (err, data) {
if (!data) { return; }
var $templateButton = $('<button>').text('Create pad from template')
.appendTo($creation);
var pickerCfg = {
types: [type],
where: ['template'],
hidden: true
};
common.openFilePicker(pickerCfg);
$templateButton.click(function () {
// Show the template picker
delete pickerCfg.hidden;
common.openFilePicker(pickerCfg);
var first = true; // We can only pick a template once (for a new document)
var fileDialogCfg = {
onSelect: function (data) {
if (data.type === type && first) {
//UI.addLoadingScreen({hideTips: true});
create(data.href);
first = false;
/*sframeChan.query('Q_TEMPLATE_USE', data.href, function () {
UI.removeLoadingScreen();
Feedback.send('TEMPLATE_USED');
});*/
//if (focus) { focus.focus(); }
//return;
}
}
};
common.initFilePicker(fileDialogCfg);
});
});
var $button = $('<button>').text('Create pad').appendTo($creation);
$button.click();
};
return UIElements; return UIElements;
}); });

@ -402,13 +402,15 @@ define([
}); });
}; };
common.useTemplate = function (href, Crypt, cb) { common.useTemplate = function (href, Crypt, cb, opts) {
// opts is used to overrides options for chainpad-netflux in cryptput
// it allows us to add owners and expiration time if it is a new file
var parsed = Hash.parsePadUrl(href); var parsed = Hash.parsePadUrl(href);
if(!parsed) { throw new Error("Cannot get template hash"); } if(!parsed) { throw new Error("Cannot get template hash"); }
Crypt.get(parsed.hash, function (err, val) { Crypt.get(parsed.hash, function (err, val) {
if (err) { throw new Error(err); } if (err) { throw new Error(err); }
var p = Hash.parsePadUrl(window.location.href); var p = Hash.parsePadUrl(window.location.href);
Crypt.put(p.hash, val, cb); Crypt.put(p.hash, val, cb, opts);
}); });
}; };
@ -750,7 +752,8 @@ define([
}).nThen(function (waitFor) { }).nThen(function (waitFor) {
// Load the new pad when the hash has changed // Load the new pad when the hash has changed
var oldHref = document.location.href; var oldHref = document.location.href;
window.onhashchange = function () { window.onhashchange = function (ev) {
if (ev && ev.reset) { oldHref = document.location.href; return; }
var newHref = document.location.href; var newHref = document.location.href;
var parsedOld = Hash.parsePadUrl(oldHref).hashData; var parsedOld = Hash.parsePadUrl(oldHref).hashData;
var parsedNew = Hash.parsePadUrl(newHref).hashData; var parsedNew = Hash.parsePadUrl(newHref).hashData;

@ -742,6 +742,9 @@ define([
}, // post EV_PAD_DISCONNECT }, // post EV_PAD_DISCONNECT
channel: data.channel, channel: data.channel,
validateKey: data.validateKey, validateKey: data.validateKey,
owners: data.owners,
password: data.password,
expire: data.expire,
network: store.network, network: store.network,
readOnly: data.readOnly, readOnly: data.readOnly,
onConnect: function (wc, sendMessage) { onConnect: function (wc, sendMessage) {

@ -33,6 +33,9 @@ define([], function () {
var onLeave = conf.onLeave; var onLeave = conf.onLeave;
var onReady = conf.onReady; var onReady = conf.onReady;
var onDisconnect = conf.onDisconnect; var onDisconnect = conf.onDisconnect;
var owners = conf.owners;
var password = conf.password;
var expire = conf.expire;
conf = undefined; conf = undefined;
var initializing = true; var initializing = true;
@ -177,6 +180,13 @@ define([], function () {
}); });
network.historyKeeper = hk; network.historyKeeper = hk;
var cfg = {
validateKey: validateKey,
lastKnownHash: lastKnownHash,
owners: owners,
expire: expire,
password: password
};
var msg = ['GET_HISTORY', wc.id]; var msg = ['GET_HISTORY', wc.id];
// Add the validateKey if we are the channel creator and we have a validateKey // Add the validateKey if we are the channel creator and we have a validateKey
msg.push(validateKey); msg.push(validateKey);

@ -373,13 +373,19 @@ define([
nThen(function (waitFor) { nThen(function (waitFor) {
UI.addLoadingScreen(); UI.addLoadingScreen();
SFCommon.create(waitFor(function (c) { common = c; })); SFCommon.create(waitFor(function (c) { common = c; }));
}).nThen(function (waitFor) {
if (!AppConfig.displayCreationScreen) { return; }
if (common.getMetadataMgr().getPrivateData().isNewFile) {
console.log('newFile');
common.getPadCreationScreen(Toolbar, waitFor());
}
}).nThen(function (waitFor) { }).nThen(function (waitFor) {
cpNfInner = common.startRealtime({ cpNfInner = common.startRealtime({
// really basic operational transform // really basic operational transform
patchTransformer: options.patchTransformer || ChainPad.SmartJSONTransformer, patchTransformer: options.patchTransformer || ChainPad.SmartJSONTransformer,
// cryptpad debug logging (default is 1) // cryptpad debug logging (default is 1)
// logLevel: 0, // logLevel: 2,
validateContent: options.validateContent || function (content) { validateContent: options.validateContent || function (content) {
try { try {
JSON.parse(content); JSON.parse(content);

@ -27,6 +27,9 @@ define([], function () {
var readOnly = conf.readOnly || false; var readOnly = conf.readOnly || false;
var padRpc = conf.padRpc; var padRpc = conf.padRpc;
var sframeChan = conf.sframeChan; var sframeChan = conf.sframeChan;
var password = conf.password;
var owners = conf.owners;
var expire = conf.expire;
var onConnect = conf.onConnect || function () { }; var onConnect = conf.onConnect || function () { };
conf = undefined; conf = undefined;
@ -98,7 +101,10 @@ define([], function () {
padRpc.joinPad({ padRpc.joinPad({
channel: channel || null, channel: channel || null,
validateKey: validateKey, validateKey: validateKey,
readOnly: readOnly readOnly: readOnly,
owners: owners,
password: password,
expire: expire
}, function(data) { }, function(data) {
onOpen(data); onOpen(data);
}); });

@ -36,7 +36,7 @@ define([
//patchTransformer: ChainPad.NaiveJSONTransformer, //patchTransformer: ChainPad.NaiveJSONTransformer,
//logLevel: 0, //logLevel: 0,
//transformFunction: JsonOT.validate, //transformFunction: JsonOT.validate,
logLevel: config.debug ? 1 : 0, logLevel: config.debug ? 2 : 0,
noPrune: true noPrune: true
}); });
}; };

@ -12,6 +12,7 @@ define([
var network; var network;
var secret; var secret;
var hashes; var hashes;
var isNewFile;
var CpNfOuter; var CpNfOuter;
var Cryptpad; var Cryptpad;
var Crypto; var Crypto;
@ -19,10 +20,10 @@ define([
var SFrameChannel; var SFrameChannel;
var sframeChan; var sframeChan;
var FilePicker; var FilePicker;
//var Messenger;
var Messaging; var Messaging;
var Notifier; var Notifier;
var Utils = {}; var Utils = {};
var AppConfig;
nThen(function (waitFor) { nThen(function (waitFor) {
// Load #2, the loading screen is up so grab whatever you need... // Load #2, the loading screen is up so grab whatever you need...
@ -41,11 +42,12 @@ define([
'/common/common-constants.js', '/common/common-constants.js',
'/common/common-feedback.js', '/common/common-feedback.js',
'/common/outer/local-store.js', '/common/outer/local-store.js',
'/customize/application_config.js',
'/common/outer/network-config.js', '/common/outer/network-config.js',
'/bower_components/netflux-websocket/netflux-client.js', '/bower_components/netflux-websocket/netflux-client.js',
], waitFor(function (_CpNfOuter, _Cryptpad, _Crypto, _Cryptget, _SFrameChannel, ], waitFor(function (_CpNfOuter, _Cryptpad, _Crypto, _Cryptget, _SFrameChannel,
_FilePicker, _Messaging, _Notifier, _Hash, _Util, _Realtime, _FilePicker, _Messaging, _Notifier, _Hash, _Util, _Realtime,
_Constants, _Feedback, _LocalStore, NetConfig, Netflux) { _Constants, _Feedback, _LocalStore, _AppConfig, NetConfig, Netflux) {
CpNfOuter = _CpNfOuter; CpNfOuter = _CpNfOuter;
Cryptpad = _Cryptpad; Cryptpad = _Cryptpad;
Crypto = _Crypto; Crypto = _Crypto;
@ -60,6 +62,7 @@ define([
Utils.Constants = _Constants; Utils.Constants = _Constants;
Utils.Feedback = _Feedback; Utils.Feedback = _Feedback;
Utils.LocalStore = _LocalStore; Utils.LocalStore = _LocalStore;
AppConfig = _AppConfig;
if (localStorage.CRYPTPAD_URLARGS !== ApiConfig.requireConf.urlArgs) { if (localStorage.CRYPTPAD_URLARGS !== ApiConfig.requireConf.urlArgs) {
console.log("New version, flushing cache"); console.log("New version, flushing cache");
@ -131,13 +134,25 @@ define([
} }
Cryptpad.getShareHashes(secret, waitFor(function (err, h) { hashes = h; })); Cryptpad.getShareHashes(secret, waitFor(function (err, h) { hashes = h; }));
} }
}).nThen(function (waitFor) {
// Check if the pad exists on server
if (!window.location.hash) { isNewFile = true; return; }
Cryptpad.getFileSize(window.location.href, waitFor(function (err, size) {
console.log(size);
if (size) {
isNewFile = false;
return;
}
isNewFile = true;
}));
}).nThen(function () { }).nThen(function () {
console.log(isNewFile);
var readOnly = secret.keys && !secret.keys.editKeyStr; var readOnly = secret.keys && !secret.keys.editKeyStr;
if (!secret.keys) { secret.keys = secret.key; } if (!secret.keys) { secret.keys = secret.key; }
var parsed = Utils.Hash.parsePadUrl(window.location.href); var parsed = Utils.Hash.parsePadUrl(window.location.href);
if (!parsed.type) { throw new Error(); } if (!parsed.type) { throw new Error(); }
var defaultTitle = Utils.Hash.getDefaultName(parsed); var defaultTitle = Utils.Hash.getDefaultName(parsed);
var edPublic;
var updateMeta = function () { var updateMeta = function () {
//console.log('EV_METADATA_UPDATE'); //console.log('EV_METADATA_UPDATE');
var metaObj, isTemplate; var metaObj, isTemplate;
@ -145,6 +160,7 @@ define([
Cryptpad.getMetadata(waitFor(function (err, m) { Cryptpad.getMetadata(waitFor(function (err, m) {
if (err) { console.log(err); } if (err) { console.log(err); }
metaObj = m; metaObj = m;
edPublic = metaObj.priv.edPublic; // needed to create an owned pad
})); }));
Cryptpad.isTemplate(window.location.href, waitFor(function (err, t) { Cryptpad.isTemplate(window.location.href, waitFor(function (err, t) {
if (err) { console.log(err); } if (err) { console.log(err); }
@ -169,7 +185,8 @@ define([
accounts: { accounts: {
donateURL: Cryptpad.donateURL, donateURL: Cryptpad.donateURL,
upgradeURL: Cryptpad.upgradeURL upgradeURL: Cryptpad.upgradeURL
} },
isNewFile: isNewFile
}; };
for (var k in additionalPriv) { metaObj.priv[k] = additionalPriv[k]; } for (var k in additionalPriv) { metaObj.priv[k] = additionalPriv[k]; }
@ -540,43 +557,94 @@ define([
}); });
} }
sframeChan.ready();
Utils.Feedback.reportAppUsage();
if (!realtime) { return; } // Join the netflux channel
var rtStarted = false;
var startRealtime = function () {
rtStarted = true;
var replaceHash = function (hash) {
if (window.history && window.history.replaceState) {
if (!/^#/.test(hash)) { hash = '#' + hash; }
void window.history.replaceState({}, window.document.title, hash);
if (typeof(window.onhashchange) === 'function') {
window.onhashchange();
}
return;
}
window.location.hash = hash;
};
var replaceHash = function (hash) { CpNfOuter.start({
if (window.history && window.history.replaceState) { sframeChan: sframeChan,
if (!/^#/.test(hash)) { hash = '#' + hash; } channel: secret.channel,
void window.history.replaceState({}, window.document.title, hash); padRpc: Cryptpad.padRpc,
if (typeof(window.onhashchange) === 'function') { validateKey: secret.keys.validateKey || undefined,
window.onhashchange(); readOnly: readOnly,
crypto: Crypto.createEncryptor(secret.keys),
onConnect: function (wc) {
if (window.location.hash && window.location.hash !== '#') {
window.location = parsed.getUrl({
present: parsed.hashData.present,
embed: parsed.hashData.embed
});
return;
}
if (readOnly || cfg.noHash) { return; }
replaceHash(Utils.Hash.getEditHashFromKeys(wc, secret.keys));
} }
return; });
}
window.location.hash = hash;
}; };
CpNfOuter.start({ sframeChan.on('Q_CREATE_PAD', function (data, cb) {
sframeChan: sframeChan, if (!isNewFile || rtStarted) { return; }
channel: secret.channel, // Create a new hash
padRpc: Cryptpad.padRpc, var newHash = Utils.Hash.createRandomHash();
validateKey: secret.keys.validateKey || undefined, secret = Utils.Hash.getSecrets(parsed.type, newHash);
readOnly: readOnly,
crypto: Crypto.createEncryptor(secret.keys), // Update the hash in the address bar
onConnect: function (wc) { var ohc = window.onhashchange;
if (window.location.hash && window.location.hash !== '#') { window.onhashchange = function () {};
window.location = parsed.getUrl({ window.location.hash = newHash;
present: parsed.hashData.present, window.onhashchange = ohc;
embed: parsed.hashData.embed ohc({reset: true});
});
return; // Update metadata values and send new metadata inside
} parsed = Utils.Hash.parsePadUrl(window.location.href);
if (readOnly || cfg.noHash) { return; } defaultTitle = Utils.Hash.getDefaultName(parsed);
replaceHash(Utils.Hash.getEditHashFromKeys(wc, secret.keys)); readOnly = false;
updateMeta();
var rtConfig = {};
console.log(edPublic);
if (data.owned) {
//rtConfig.owners = [edPublic];
} }
if (data.template) {
// Pass rtConfig to useTemplate because Cryptput will create the file and
// we need to have the owners and expiration time in the first line on the
// server
Cryptpad.useTemplate(data.template, Cryptget, function () {
startRealtime();
cb();
}, rtConfig);
return;
};
// Start realtime outside the iframe and callback
console.log(data);
startRealtime(rtConfig);
cb();
}); });
sframeChan.ready();
Utils.Feedback.reportAppUsage();
if (!realtime) { return; }
if (isNewFile && AppConfig.displayCreationScreen) { return; }
startRealtime();
}); });
}; };

@ -90,6 +90,7 @@ define([
funcs.updateTags = callWithCommon(UIElements.updateTags); funcs.updateTags = callWithCommon(UIElements.updateTags);
funcs.createLanguageSelector = callWithCommon(UIElements.createLanguageSelector); funcs.createLanguageSelector = callWithCommon(UIElements.createLanguageSelector);
funcs.createMarkdownToolbar = callWithCommon(UIElements.createMarkdownToolbar); funcs.createMarkdownToolbar = callWithCommon(UIElements.createMarkdownToolbar);
funcs.getPadCreationScreen = callWithCommon(UIElements.getPadCreationScreen);
// Thumb // Thumb
funcs.displayThumbnail = callWithCommon(Thumb.displayThumbnail); funcs.displayThumbnail = callWithCommon(Thumb.displayThumbnail);

@ -209,5 +209,8 @@ define({
// Notifications about connection and disconnection from the network // Notifications about connection and disconnection from the network
'EV_NETWORK_DISCONNECT': true, 'EV_NETWORK_DISCONNECT': true,
'EV_NETWORK_RECONNECT': true 'EV_NETWORK_RECONNECT': true,
// Pad creation screen: create a pad with the selected attributes (owned, expire)
'Q_CREATE_PAD': true,
}); });

Loading…
Cancel
Save