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',
};
config.displayCreationScreen = true;
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/alertify.less';
@import (once) '../../customize/src/less2/include/tokenfield.less';
@import (once) '../../customize/src/less2/include/creation.less';
@_cp-toolbar-color-warn: @colortheme_code-warn;
@ -11,6 +12,7 @@
.fileupload_main();
.alertify_main();
.tokenfield_main();
.creation_main();
// body
&.cp-app-code {

@ -387,7 +387,6 @@ define([
common.getAttribute(['general', 'markdown-help'], function (e, data) {
if (e) { return void console.error(e); }
if (data === true && $toolbarButton.length && tbState) {
console.log($toolbar.is(':visible'));
$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;
});

@ -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);
if(!parsed) { throw new Error("Cannot get template hash"); }
Crypt.get(parsed.hash, function (err, val) {
if (err) { throw new Error(err); }
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) {
// Load the new pad when the hash has changed
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 parsedOld = Hash.parsePadUrl(oldHref).hashData;
var parsedNew = Hash.parsePadUrl(newHref).hashData;

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

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

@ -373,13 +373,19 @@ define([
nThen(function (waitFor) {
UI.addLoadingScreen();
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) {
cpNfInner = common.startRealtime({
// really basic operational transform
patchTransformer: options.patchTransformer || ChainPad.SmartJSONTransformer,
// cryptpad debug logging (default is 1)
// logLevel: 0,
// logLevel: 2,
validateContent: options.validateContent || function (content) {
try {
JSON.parse(content);

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

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

@ -12,6 +12,7 @@ define([
var network;
var secret;
var hashes;
var isNewFile;
var CpNfOuter;
var Cryptpad;
var Crypto;
@ -19,10 +20,10 @@ define([
var SFrameChannel;
var sframeChan;
var FilePicker;
//var Messenger;
var Messaging;
var Notifier;
var Utils = {};
var AppConfig;
nThen(function (waitFor) {
// Load #2, the loading screen is up so grab whatever you need...
@ -41,11 +42,12 @@ define([
'/common/common-constants.js',
'/common/common-feedback.js',
'/common/outer/local-store.js',
'/customize/application_config.js',
'/common/outer/network-config.js',
'/bower_components/netflux-websocket/netflux-client.js',
], waitFor(function (_CpNfOuter, _Cryptpad, _Crypto, _Cryptget, _SFrameChannel,
_FilePicker, _Messaging, _Notifier, _Hash, _Util, _Realtime,
_Constants, _Feedback, _LocalStore, NetConfig, Netflux) {
_Constants, _Feedback, _LocalStore, _AppConfig, NetConfig, Netflux) {
CpNfOuter = _CpNfOuter;
Cryptpad = _Cryptpad;
Crypto = _Crypto;
@ -60,6 +62,7 @@ define([
Utils.Constants = _Constants;
Utils.Feedback = _Feedback;
Utils.LocalStore = _LocalStore;
AppConfig = _AppConfig;
if (localStorage.CRYPTPAD_URLARGS !== ApiConfig.requireConf.urlArgs) {
console.log("New version, flushing cache");
@ -131,13 +134,25 @@ define([
}
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 () {
console.log(isNewFile);
var readOnly = secret.keys && !secret.keys.editKeyStr;
if (!secret.keys) { secret.keys = secret.key; }
var parsed = Utils.Hash.parsePadUrl(window.location.href);
if (!parsed.type) { throw new Error(); }
var defaultTitle = Utils.Hash.getDefaultName(parsed);
var edPublic;
var updateMeta = function () {
//console.log('EV_METADATA_UPDATE');
var metaObj, isTemplate;
@ -145,6 +160,7 @@ define([
Cryptpad.getMetadata(waitFor(function (err, m) {
if (err) { console.log(err); }
metaObj = m;
edPublic = metaObj.priv.edPublic; // needed to create an owned pad
}));
Cryptpad.isTemplate(window.location.href, waitFor(function (err, t) {
if (err) { console.log(err); }
@ -169,7 +185,8 @@ define([
accounts: {
donateURL: Cryptpad.donateURL,
upgradeURL: Cryptpad.upgradeURL
}
},
isNewFile: isNewFile
};
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) {
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();
CpNfOuter.start({
sframeChan: sframeChan,
channel: secret.channel,
padRpc: Cryptpad.padRpc,
validateKey: secret.keys.validateKey || undefined,
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: sframeChan,
channel: secret.channel,
padRpc: Cryptpad.padRpc,
validateKey: secret.keys.validateKey || undefined,
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));
sframeChan.on('Q_CREATE_PAD', function (data, cb) {
if (!isNewFile || rtStarted) { return; }
// Create a new hash
var newHash = Utils.Hash.createRandomHash();
secret = Utils.Hash.getSecrets(parsed.type, newHash);
// Update the hash in the address bar
var ohc = window.onhashchange;
window.onhashchange = function () {};
window.location.hash = newHash;
window.onhashchange = ohc;
ohc({reset: true});
// Update metadata values and send new metadata inside
parsed = Utils.Hash.parsePadUrl(window.location.href);
defaultTitle = Utils.Hash.getDefaultName(parsed);
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.createLanguageSelector = callWithCommon(UIElements.createLanguageSelector);
funcs.createMarkdownToolbar = callWithCommon(UIElements.createMarkdownToolbar);
funcs.getPadCreationScreen = callWithCommon(UIElements.getPadCreationScreen);
// Thumb
funcs.displayThumbnail = callWithCommon(Thumb.displayThumbnail);

@ -209,5 +209,8 @@ define({
// Notifications about connection and disconnection from the network
'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