Merge branch 'creationpage' into staging
This commit is contained in:
@@ -6,11 +6,12 @@ define([
|
||||
'/common/common-language.js',
|
||||
'/common/common-interface.js',
|
||||
'/common/common-feedback.js',
|
||||
'/common/hyperscript.js',
|
||||
'/common/media-tag.js',
|
||||
'/customize/messages.js',
|
||||
|
||||
'css!/common/tippy.css',
|
||||
], function ($, Config, Util, Hash, Language, UI, Feedback, MediaTag, Messages) {
|
||||
], function ($, Config, Util, Hash, Language, UI, Feedback, h, MediaTag, Messages) {
|
||||
var UIElements = {};
|
||||
|
||||
// Configure MediaTags to use our local viewer
|
||||
@@ -387,7 +388,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 +1120,169 @@ define([
|
||||
});
|
||||
};
|
||||
|
||||
UIElements.getPadCreationScreen = function (common, cb) {
|
||||
if (!common.isLoggedIn()) { return void cb(); }
|
||||
var sframeChan = common.getSframeChannel();
|
||||
var metadataMgr = common.getMetadataMgr();
|
||||
var type = metadataMgr.getMetadataLazy().type;
|
||||
|
||||
var $body = $('body');
|
||||
var $creationContainer = $('<div>', { id: 'cp-creation-container' }).appendTo($body);
|
||||
var $creation = $('<div>', { id: 'cp-creation' }).appendTo($creationContainer);
|
||||
|
||||
var setHTML = function (e, html) {
|
||||
e.innerHTML = html;
|
||||
return e;
|
||||
};
|
||||
|
||||
// Title
|
||||
$creation.append(h('h1.cp-creation-title', Messages['button_new'+type]));
|
||||
|
||||
// Deleted pad warning
|
||||
if (metadataMgr.getPrivateData().isDeleted) {
|
||||
$creation.append(h('div.cp-creation-deleted', Messages.creation_404));
|
||||
}
|
||||
|
||||
var createHelper = function (text) {
|
||||
var q = h('span.cp-creation-help.fa.fa-question', {
|
||||
title: text
|
||||
});
|
||||
return q;
|
||||
};
|
||||
|
||||
// Owned pads
|
||||
var owned = h('div.cp-creation-owned', [
|
||||
h('h2', [
|
||||
Messages.creation_ownedTitle,
|
||||
createHelper(Messages.creation_owned1 + '\n' + Messages.creation_owned2)
|
||||
]),
|
||||
setHTML(h('p'), Messages.creation_owned1 + '<br>' + Messages.creation_owned2),
|
||||
h('input#cp-creation-owned-true.cp-creation-owned-value', {
|
||||
type: 'radio',
|
||||
name: 'cp-creation-owned',
|
||||
value: 1,
|
||||
checked: 'checked'
|
||||
}),
|
||||
h('label', { 'for': 'cp-creation-owned-true' }, Messages.creation_ownedTrue),
|
||||
h('input#cp-creation-owned-false.cp-creation-owned-value', {
|
||||
type: 'radio',
|
||||
name: 'cp-creation-owned',
|
||||
value: 0
|
||||
}),
|
||||
h('label', { 'for': 'cp-creation-owned-false' }, Messages.creation_ownedFalse)
|
||||
]);
|
||||
$creation.append(owned);
|
||||
|
||||
// Life time
|
||||
var expire = h('div.cp-creation-expire', [
|
||||
h('h2', [
|
||||
Messages.creation_expireTitle,
|
||||
createHelper(Messages.creation_expire1, Messages.creation_expire2)
|
||||
]),
|
||||
setHTML(h('p'), Messages.creation_expire1 + '<br>' + Messages.creation_expire2),
|
||||
h('input#cp-creation-expire-false.cp-creation-expire-value', {
|
||||
type: 'radio',
|
||||
name: 'cp-creation-expire',
|
||||
value: 0,
|
||||
checked: 'checked'
|
||||
}),
|
||||
h('label', { 'for': 'cp-creation-expire-false' }, Messages.creation_expireFalse),
|
||||
h('input#cp-creation-expire-true.cp-creation-expire-value', {
|
||||
type: 'radio',
|
||||
name: 'cp-creation-expire',
|
||||
value: 1
|
||||
}),
|
||||
h('label', { 'for': 'cp-creation-expire-true' }, [
|
||||
Messages.creation_expireTrue,
|
||||
h('span.cp-creation-expire-picker', [
|
||||
h('input#cp-creation-expire-val', {
|
||||
type: "number",
|
||||
min: 1,
|
||||
max: 100,
|
||||
value: 3
|
||||
}),
|
||||
h('select#cp-creation-expire-unit', [
|
||||
h('option', { value: 'hour' }, Messages.creation_expireHours),
|
||||
h('option', { value: 'day' }, Messages.creation_expireDays),
|
||||
h('option', {
|
||||
value: 'month',
|
||||
selected: 'selected'
|
||||
}, Messages.creation_expireMonths)
|
||||
])
|
||||
])
|
||||
])
|
||||
]);
|
||||
$creation.append(expire);
|
||||
|
||||
// Create the pad
|
||||
var create = function (template) {
|
||||
// Type of pad
|
||||
var ownedVal = parseInt($('input[name="cp-creation-owned"]:checked').val());
|
||||
// Life time
|
||||
var expireVal = 0;
|
||||
if(parseInt($('input[name="cp-creation-expire"]:checked').val())) {
|
||||
var unit = 0;
|
||||
switch ($('#cp-creation-expire-unit').val()) {
|
||||
case "hour" : unit = 3600; break;
|
||||
case "day" : unit = 3600 * 24; break;
|
||||
case "month": unit = 3600 * 24 * 30; break;
|
||||
default: unit = 0;
|
||||
}
|
||||
expireVal = ($('#cp-creation-expire-val').val() || 0) * unit;
|
||||
}
|
||||
|
||||
// TODO remove these lines
|
||||
ownedVal = undefined;
|
||||
expire = undefined;
|
||||
|
||||
sframeChan.query("Q_CREATE_PAD", {
|
||||
owned: ownedVal,
|
||||
expire: expireVal,
|
||||
template: template
|
||||
}, function () {
|
||||
$creation.remove();
|
||||
cb();
|
||||
});
|
||||
};
|
||||
|
||||
var $create = $(h('div.cp-creation-create', [
|
||||
h('h2', Messages.creation_createTitle)
|
||||
])).appendTo($creation);
|
||||
// Pick a template?
|
||||
sframeChan.query("Q_TEMPLATE_EXIST", type, function (err, data) {
|
||||
if (!data) { return; }
|
||||
var $templateButton = $('<button>').text(Messages.creation_createFromTemplate)
|
||||
.appendTo($create);
|
||||
|
||||
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) {
|
||||
create(data.href);
|
||||
first = false;
|
||||
}
|
||||
}
|
||||
};
|
||||
common.initFilePicker(fileDialogCfg);
|
||||
});
|
||||
});
|
||||
|
||||
var $button = $('<button>').text(Messages.creation_createFromScratch).appendTo($create);
|
||||
$button.click(function () {
|
||||
create();
|
||||
});
|
||||
};
|
||||
|
||||
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,20 @@ define([
|
||||
nThen(function (waitFor) {
|
||||
UI.addLoadingScreen();
|
||||
SFCommon.create(waitFor(function (c) { common = c; }));
|
||||
}).nThen(function (waitFor) {
|
||||
common.getSframeChannel().onReady(waitFor());
|
||||
}).nThen(function (waitFor) {
|
||||
if (!AppConfig.displayCreationScreen) { return; }
|
||||
if (common.getMetadataMgr().getPrivateData().isNewFile) {
|
||||
common.getPadCreationScreen(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,9 @@ define([
|
||||
accounts: {
|
||||
donateURL: Cryptpad.donateURL,
|
||||
upgradeURL: Cryptpad.upgradeURL
|
||||
}
|
||||
},
|
||||
isNewFile: isNewFile,
|
||||
isDeleted: window.location.hash.length > 0
|
||||
};
|
||||
for (var k in additionalPriv) { metaObj.priv[k] = additionalPriv[k]; }
|
||||
|
||||
@@ -540,43 +558,97 @@ define([
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
// 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;
|
||||
};
|
||||
|
||||
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.expire) {
|
||||
//rtConfig.expire = data.expire;
|
||||
}
|
||||
|
||||
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; }
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
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));
|
||||
}
|
||||
});
|
||||
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,
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user