Merge branch 'whiteboard' into soon
This commit is contained in:
commit
fe14399e67
@ -11,6 +11,7 @@ var Meta = require("../metadata");
|
|||||||
var Extras = require("../hk-util");
|
var Extras = require("../hk-util");
|
||||||
|
|
||||||
const readFileBin = require("../stream-file").readFileBin;
|
const readFileBin = require("../stream-file").readFileBin;
|
||||||
|
const BatchRead = require("../batch-read");
|
||||||
|
|
||||||
const Schedule = require("../schedule");
|
const Schedule = require("../schedule");
|
||||||
const isValidChannelId = function (id) {
|
const isValidChannelId = function (id) {
|
||||||
@ -62,7 +63,7 @@ const destroyStream = function (stream) {
|
|||||||
if (!stream) { return; }
|
if (!stream) { return; }
|
||||||
try { stream.close(); } catch (err) { console.error(err); }
|
try { stream.close(); } catch (err) { console.error(err); }
|
||||||
setTimeout(function () {
|
setTimeout(function () {
|
||||||
try { stream.destroy(); } catch (err) { console.log(err); }
|
try { stream.destroy(); } catch (err) { console.error(err); }
|
||||||
}, 5000);
|
}, 5000);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -142,7 +143,6 @@ var closeChannel = function (env, channelName, cb) {
|
|||||||
destroyStream(stream, channelName);
|
destroyStream(stream, channelName);
|
||||||
}
|
}
|
||||||
delete env.channels[channelName];
|
delete env.channels[channelName];
|
||||||
env.openFiles--;
|
|
||||||
cb();
|
cb();
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
cb(err);
|
cb(err);
|
||||||
@ -291,7 +291,7 @@ var writeMetadata = function (env, channelId, data, cb) {
|
|||||||
|
|
||||||
|
|
||||||
// check if a file exists at $path
|
// check if a file exists at $path
|
||||||
var checkPath = function (path, callback) {
|
var checkPath = function (path, callback) { // callback's second arg is never used...
|
||||||
Fs.stat(path, function (err) {
|
Fs.stat(path, function (err) {
|
||||||
if (!err) {
|
if (!err) {
|
||||||
callback(undefined, true);
|
callback(undefined, true);
|
||||||
@ -633,7 +633,7 @@ var unarchiveChannel = function (env, channelName, cb) {
|
|||||||
}));
|
}));
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
/*
|
||||||
var flushUnusedChannels = function (env, cb, frame) {
|
var flushUnusedChannels = function (env, cb, frame) {
|
||||||
var currentTime = +new Date();
|
var currentTime = +new Date();
|
||||||
|
|
||||||
@ -655,6 +655,7 @@ var flushUnusedChannels = function (env, cb, frame) {
|
|||||||
});
|
});
|
||||||
cb();
|
cb();
|
||||||
};
|
};
|
||||||
|
*/
|
||||||
|
|
||||||
/* channelBytes
|
/* channelBytes
|
||||||
calls back with an error or the size (in bytes) of a channel and its metadata
|
calls back with an error or the size (in bytes) of a channel and its metadata
|
||||||
@ -687,106 +688,63 @@ var channelBytes = function (env, chanName, cb) {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
/*::
|
var getChannel = function (env, id, _callback) {
|
||||||
export type ChainPadServer_ChannelInternal_t = {
|
var cb = Util.once(Util.mkAsync(_callback));
|
||||||
atime: number,
|
|
||||||
writeStream: typeof(process.stdout),
|
// if the channel is in memory
|
||||||
whenLoaded: ?Array<(err:?Error, chan:?ChainPadServer_ChannelInternal_t)=>void>,
|
|
||||||
onError: Array<(?Error)=>void>,
|
|
||||||
path: string
|
|
||||||
};
|
|
||||||
*/
|
|
||||||
var getChannel = function ( // XXX BatchRead
|
|
||||||
env,
|
|
||||||
id,
|
|
||||||
_callback /*:(err:?Error, chan:?ChainPadServer_ChannelInternal_t)=>void*/
|
|
||||||
) {
|
|
||||||
//console.log("getting channel [%s]", id);
|
|
||||||
var callback = Util.once(Util.mkAsync(_callback));
|
|
||||||
if (env.channels[id]) {
|
if (env.channels[id]) {
|
||||||
var chan = env.channels[id];
|
var chan = env.channels[id];
|
||||||
chan.atime = +new Date();
|
// delay its pending close a little longer
|
||||||
if (chan.whenLoaded) {
|
chan.delayClose();
|
||||||
chan.whenLoaded.push(callback);
|
// and return its writeStream
|
||||||
} else {
|
return void cb(void 0, chan);
|
||||||
callback(undefined, chan);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (env.openFiles >= env.openFileLimit) {
|
// otherwise you need to open it or wait until its pending open completes
|
||||||
// FIXME warn if this is the case?
|
return void env.batchGetChannel(id, cb, function (done) {
|
||||||
// alternatively use graceful-fs to handle lots of concurrent reads
|
|
||||||
// if you're running out of open files, asynchronously clean up expired files
|
|
||||||
// do it on a shorter timeframe, though (half of normal)
|
|
||||||
setTimeout(function () {
|
|
||||||
//console.log("FLUSHING UNUSED CHANNELS");
|
|
||||||
flushUnusedChannels(env, function () {
|
|
||||||
if (env.verbose) {
|
|
||||||
console.log("Approaching open file descriptor limit. Cleaning up");
|
|
||||||
}
|
|
||||||
}, env.channelExpirationMs / 2);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
var path = mkPath(env, id);
|
var path = mkPath(env, id);
|
||||||
var channel /*:ChainPadServer_ChannelInternal_t*/ = env.channels[id] = {
|
var channel = {
|
||||||
atime: +new Date(),
|
onError: [],
|
||||||
writeStream: (undefined /*:any*/),
|
|
||||||
whenLoaded: [ callback ],
|
|
||||||
onError: [ ],
|
|
||||||
path: path
|
|
||||||
};
|
};
|
||||||
var complete = function (err) {
|
nThen(function (w) {
|
||||||
var whenLoaded = channel.whenLoaded;
|
// create the path to the file if it doesn't exist
|
||||||
// no guarantee stream.on('error') will not cause this to be called multiple times
|
checkPath(path, w(function (err) {
|
||||||
if (!whenLoaded) { return; }
|
|
||||||
channel.whenLoaded = undefined;
|
|
||||||
if (err) {
|
if (err) {
|
||||||
delete env.channels[id];
|
w.abort();
|
||||||
|
return void done(err);
|
||||||
}
|
}
|
||||||
if (!channel.writeStream) {
|
|
||||||
throw new Error("getChannel() complete called without channel writeStream"); // XXX
|
|
||||||
}
|
|
||||||
whenLoaded.forEach(function (wl) { wl(err, (err) ? undefined : channel); });
|
|
||||||
};
|
|
||||||
var fileExists;
|
|
||||||
nThen(function (waitFor) {
|
|
||||||
checkPath(path, waitFor(function (err, exists) {
|
|
||||||
if (err) {
|
|
||||||
waitFor.abort();
|
|
||||||
return void complete(err);
|
|
||||||
}
|
|
||||||
fileExists = exists;
|
|
||||||
}));
|
}));
|
||||||
}).nThen(function (waitFor) {
|
}).nThen(function (w) {
|
||||||
var stream = channel.writeStream = Fs.createWriteStream(path, { flags: 'a' }); // XXX
|
var stream = channel.writeStream = Fs.createWriteStream(path, { flags: 'a' });
|
||||||
env.openFiles++;
|
stream.on('open', w());
|
||||||
stream.on('open', waitFor());
|
stream.on('error', function (err) {
|
||||||
stream.on('error', function (err /*:?Error*/) {
|
w.abort();
|
||||||
env.openFiles--;
|
|
||||||
// this might be called after this nThen block closes.
|
// this might be called after this nThen block closes.
|
||||||
if (channel.whenLoaded) {
|
|
||||||
complete(err);
|
|
||||||
} else {
|
|
||||||
channel.onError.forEach(function (handler) {
|
channel.onError.forEach(function (handler) {
|
||||||
handler(err);
|
handler(err);
|
||||||
});
|
});
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}).nThen(function () {
|
}).nThen(function () {
|
||||||
complete();
|
channel.delayClose = Util.throttle(function () {
|
||||||
|
delete env.channels[id];
|
||||||
|
destroyStream(channel.writeStream, path);
|
||||||
|
//console.log("closing writestream");
|
||||||
|
}, 30000);
|
||||||
|
channel.delayClose();
|
||||||
|
env.channels[id] = channel;
|
||||||
|
done(void 0, channel);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
// write a message to the disk as raw bytes
|
// write a message to the disk as raw bytes
|
||||||
const messageBin = (env, chanName, msgBin, cb) => {
|
const messageBin = (env, chanName, msgBin, cb) => {
|
||||||
var complete = Util.once(cb);
|
var complete = Util.once(cb);
|
||||||
getChannel(env, chanName, function (err, chan) { // XXX
|
getChannel(env, chanName, function (err, chan) {
|
||||||
if (!chan) { return void complete(err); }
|
if (!chan) { return void complete(err); }
|
||||||
chan.onError.push(complete);
|
chan.onError.push(complete);
|
||||||
chan.writeStream.write(msgBin, function () {
|
chan.writeStream.write(msgBin, function () {
|
||||||
chan.onError.splice(chan.onError.indexOf(complete), 1);
|
chan.onError.splice(chan.onError.indexOf(complete), 1);
|
||||||
chan.atime = +new Date(); // XXX we should just throttle closing, much simpler and less error prone
|
|
||||||
complete();
|
complete();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -1000,8 +958,7 @@ module.exports.create = function (conf, cb) {
|
|||||||
channels: { },
|
channels: { },
|
||||||
channelExpirationMs: conf.channelExpirationMs || 30000,
|
channelExpirationMs: conf.channelExpirationMs || 30000,
|
||||||
verbose: conf.verbose,
|
verbose: conf.verbose,
|
||||||
openFiles: 0,
|
batchGetChannel: BatchRead('store_batch_channel'),
|
||||||
openFileLimit: conf.openFileLimit || 2048,
|
|
||||||
};
|
};
|
||||||
var it;
|
var it;
|
||||||
|
|
||||||
@ -1240,7 +1197,8 @@ module.exports.create = function (conf, cb) {
|
|||||||
},
|
},
|
||||||
// iterate over open channels and close any that are not active
|
// iterate over open channels and close any that are not active
|
||||||
flushUnusedChannels: function (cb) {
|
flushUnusedChannels: function (cb) {
|
||||||
flushUnusedChannels(env, cb);
|
cb("DEPRECATED");
|
||||||
|
//flushUnusedChannels(env, cb);
|
||||||
},
|
},
|
||||||
// write to a log file
|
// write to a log file
|
||||||
log: function (channelName, content, cb) {
|
log: function (channelName, content, cb) {
|
||||||
@ -1255,7 +1213,8 @@ module.exports.create = function (conf, cb) {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
/*
|
||||||
it = setInterval(function () {
|
it = setInterval(function () {
|
||||||
flushUnusedChannels(env, function () { });
|
flushUnusedChannels(env, function () { });
|
||||||
}, 5000);
|
}, 5000);*/
|
||||||
};
|
};
|
||||||
|
|||||||
@ -43,6 +43,7 @@ define([
|
|||||||
'stats': [
|
'stats': [
|
||||||
'cp-admin-active-sessions',
|
'cp-admin-active-sessions',
|
||||||
'cp-admin-active-pads',
|
'cp-admin-active-pads',
|
||||||
|
'cp-admin-open-files',
|
||||||
'cp-admin-registered',
|
'cp-admin-registered',
|
||||||
'cp-admin-disk-usage',
|
'cp-admin-disk-usage',
|
||||||
],
|
],
|
||||||
@ -119,6 +120,17 @@ define([
|
|||||||
});
|
});
|
||||||
return $div;
|
return $div;
|
||||||
};
|
};
|
||||||
|
create['open-files'] = function () {
|
||||||
|
var key = 'open-files'; // XXX
|
||||||
|
var $div = makeBlock(key);
|
||||||
|
sFrameChan.query('Q_ADMIN_RPC', {
|
||||||
|
cmd: 'GET_FILE_DESCRIPTOR_COUNT',
|
||||||
|
}, function (e, data) {
|
||||||
|
console.log(e, data);
|
||||||
|
$div.append(h('pre', String(data)));
|
||||||
|
});
|
||||||
|
return $div;
|
||||||
|
};
|
||||||
create['registered'] = function () {
|
create['registered'] = function () {
|
||||||
var key = 'registered';
|
var key = 'registered';
|
||||||
var $div = makeBlock(key);
|
var $div = makeBlock(key);
|
||||||
|
|||||||
@ -803,6 +803,17 @@ define([
|
|||||||
var chan = [data.channel];
|
var chan = [data.channel];
|
||||||
if (data.rtChannel) { chan.push(data.rtChannel); }
|
if (data.rtChannel) { chan.push(data.rtChannel); }
|
||||||
if (data.lastVersion) { chan.push(Hash.hrefToHexChannelId(data.lastVersion)); }
|
if (data.lastVersion) { chan.push(Hash.hrefToHexChannelId(data.lastVersion)); }
|
||||||
|
var channels = chan.filter(function (c) { return c.length === 32; }).map(function (id) {
|
||||||
|
if (id === data.rtChannel && data.lastVersion && data.lastCpHash) {
|
||||||
|
return {
|
||||||
|
channel: id,
|
||||||
|
lastKnownHash: data.lastCpHash
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
channel: id
|
||||||
|
};
|
||||||
|
});
|
||||||
var history = common.makeUniversal('history');
|
var history = common.makeUniversal('history');
|
||||||
var trimChannels = [];
|
var trimChannels = [];
|
||||||
NThen(function (waitFor) {
|
NThen(function (waitFor) {
|
||||||
@ -819,7 +830,7 @@ define([
|
|||||||
if (!owned) { return; }
|
if (!owned) { return; }
|
||||||
history.execCommand('GET_HISTORY_SIZE', {
|
history.execCommand('GET_HISTORY_SIZE', {
|
||||||
pad: true,
|
pad: true,
|
||||||
channels: chan.filter(function (c) { return c.length === 32; }),
|
channels: channels,
|
||||||
teamId: typeof(owned) === "number" && owned
|
teamId: typeof(owned) === "number" && owned
|
||||||
}, waitFor(function (obj) {
|
}, waitFor(function (obj) {
|
||||||
if (obj && obj.error) { return; }
|
if (obj && obj.error) { return; }
|
||||||
|
|||||||
@ -259,12 +259,14 @@ define([
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Handle disconnect/reconnect
|
// Handle disconnect/reconnect
|
||||||
var setEditable = function (state) {
|
var setEditable = function (state, isHistory) {
|
||||||
if (APP.closed || !APP.$content || !$.contains(document.documentElement, APP.$content[0])) { return; }
|
if (APP.closed || !APP.$content || !$.contains(document.documentElement, APP.$content[0])) { return; }
|
||||||
APP.editable = !APP.readOnly && state;
|
APP.editable = !APP.readOnly && state;
|
||||||
if (!state) {
|
if (!state) {
|
||||||
APP.$content.addClass('cp-app-drive-readonly');
|
APP.$content.addClass('cp-app-drive-readonly');
|
||||||
|
if (!isHistory) {
|
||||||
$('#cp-app-drive-connection-state').show();
|
$('#cp-app-drive-connection-state').show();
|
||||||
|
}
|
||||||
$('[draggable="true"]').attr('draggable', false);
|
$('[draggable="true"]').attr('draggable', false);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@ -3865,6 +3867,7 @@ define([
|
|||||||
|
|
||||||
var opts = {};
|
var opts = {};
|
||||||
opts.href = Hash.getRelativeHref(data.href || data.roHref);
|
opts.href = Hash.getRelativeHref(data.href || data.roHref);
|
||||||
|
opts.channel = data.channel;
|
||||||
|
|
||||||
if (manager.isSharedFolder(el)) {
|
if (manager.isSharedFolder(el)) {
|
||||||
var ro = folders[el] && folders[el].version >= 2;
|
var ro = folders[el] && folders[el].version >= 2;
|
||||||
|
|||||||
@ -104,10 +104,14 @@ define([
|
|||||||
return metadataMgr.getNetfluxId() + '-' + privateData.clientId;
|
return metadataMgr.getNetfluxId() + '-' + privateData.clientId;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
var getEditor = function () {
|
||||||
|
return window.frames[0].editor || window.frames[0].editorCell;
|
||||||
|
};
|
||||||
|
|
||||||
var setEditable = function (state) {
|
var setEditable = function (state) {
|
||||||
$('#cp-app-oo-editor').find('#cp-app-oo-offline').remove();
|
$('#cp-app-oo-editor').find('#cp-app-oo-offline').remove();
|
||||||
try {
|
try {
|
||||||
window.frames[0].editor.asc_setViewMode(!state);
|
getEditor().asc_setViewMode(!state);
|
||||||
//window.frames[0].editor.setViewModeDisconnect(true);
|
//window.frames[0].editor.setViewModeDisconnect(true);
|
||||||
} catch (e) {}
|
} catch (e) {}
|
||||||
if (!state && !readOnly) {
|
if (!state && !readOnly) {
|
||||||
@ -241,10 +245,6 @@ define([
|
|||||||
cpIndex: 0
|
cpIndex: 0
|
||||||
};
|
};
|
||||||
|
|
||||||
var getEditor = function () {
|
|
||||||
return window.frames[0].editor || window.frames[0].editorCell;
|
|
||||||
};
|
|
||||||
|
|
||||||
var getContent = function () {
|
var getContent = function () {
|
||||||
try {
|
try {
|
||||||
return getEditor().asc_nativeGetFile();
|
return getEditor().asc_nativeGetFile();
|
||||||
@ -325,6 +325,7 @@ define([
|
|||||||
body: $('body'),
|
body: $('body'),
|
||||||
onUploaded: function (ev, data) {
|
onUploaded: function (ev, data) {
|
||||||
if (!data || !data.url) { return; }
|
if (!data || !data.url) { return; }
|
||||||
|
data.hash = ev.hash;
|
||||||
sframeChan.query('Q_OO_SAVE', data, function (err) {
|
sframeChan.query('Q_OO_SAVE', data, function (err) {
|
||||||
onUploaded(ev, data, err);
|
onUploaded(ev, data, err);
|
||||||
});
|
});
|
||||||
@ -846,7 +847,7 @@ define([
|
|||||||
"id": String(myOOId), //"c0c3bf82-20d7-4663-bf6d-7fa39c598b1d",
|
"id": String(myOOId), //"c0c3bf82-20d7-4663-bf6d-7fa39c598b1d",
|
||||||
"firstname": metadataMgr.getUserData().name || Messages.anonymous,
|
"firstname": metadataMgr.getUserData().name || Messages.anonymous,
|
||||||
},
|
},
|
||||||
"mode": readOnly || lock ? "view" : "edit",
|
"mode": lock ? "view" : "edit",
|
||||||
"lang": (navigator.language || navigator.userLanguage || '').slice(0,2)
|
"lang": (navigator.language || navigator.userLanguage || '').slice(0,2)
|
||||||
},
|
},
|
||||||
"events": {
|
"events": {
|
||||||
@ -1556,6 +1557,7 @@ define([
|
|||||||
content = hjson.content || content;
|
content = hjson.content || content;
|
||||||
var newLatest = getLastCp();
|
var newLatest = getLastCp();
|
||||||
sframeChan.query('Q_OO_SAVE', {
|
sframeChan.query('Q_OO_SAVE', {
|
||||||
|
hash: newLatest.hash,
|
||||||
url: newLatest.file
|
url: newLatest.file
|
||||||
}, function () { });
|
}, function () { });
|
||||||
newDoc = !content.hashes || Object.keys(content.hashes).length === 0;
|
newDoc = !content.hashes || Object.keys(content.hashes).length === 0;
|
||||||
@ -1649,6 +1651,7 @@ define([
|
|||||||
var newLatest = getLastCp();
|
var newLatest = getLastCp();
|
||||||
if (newLatest.index > latest.index) {
|
if (newLatest.index > latest.index) {
|
||||||
sframeChan.query('Q_OO_SAVE', {
|
sframeChan.query('Q_OO_SAVE', {
|
||||||
|
hash: newLatest.hash,
|
||||||
url: newLatest.file
|
url: newLatest.file
|
||||||
}, function () { });
|
}, function () { });
|
||||||
}
|
}
|
||||||
|
|||||||
@ -61,6 +61,7 @@ define([
|
|||||||
if (e) { return void cb(e); }
|
if (e) { return void cb(e); }
|
||||||
Cryptpad.setPadAttribute('lastVersion', data.url, cb);
|
Cryptpad.setPadAttribute('lastVersion', data.url, cb);
|
||||||
});
|
});
|
||||||
|
Cryptpad.setPadAttribute('lastCpHash', data.hash, cb);
|
||||||
});
|
});
|
||||||
sframeChan.on('Q_OO_OPENCHANNEL', function (data, cb) {
|
sframeChan.on('Q_OO_OPENCHANNEL', function (data, cb) {
|
||||||
Cryptpad.getPadAttribute('rtChannel', function (err, res) {
|
Cryptpad.getPadAttribute('rtChannel', function (err, res) {
|
||||||
|
|||||||
@ -36,6 +36,7 @@ define([
|
|||||||
return void cb();
|
return void cb();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var txid = Math.floor(Math.random() * 1000000);
|
||||||
var onOpen = function (wc) {
|
var onOpen = function (wc) {
|
||||||
|
|
||||||
ctx.channels[channel] = ctx.channels[channel] || {
|
ctx.channels[channel] = ctx.channels[channel] || {
|
||||||
@ -91,6 +92,7 @@ define([
|
|||||||
|
|
||||||
var hk = network.historyKeeper;
|
var hk = network.historyKeeper;
|
||||||
var cfg = {
|
var cfg = {
|
||||||
|
txid: txid,
|
||||||
lastKnownHash: chan.lastKnownHash || chan.lastCpHash,
|
lastKnownHash: chan.lastKnownHash || chan.lastCpHash,
|
||||||
metadata: {
|
metadata: {
|
||||||
validateKey: obj.validateKey,
|
validateKey: obj.validateKey,
|
||||||
@ -121,6 +123,8 @@ define([
|
|||||||
} catch (e) {}
|
} catch (e) {}
|
||||||
if (!parsed) { return; }
|
if (!parsed) { return; }
|
||||||
|
|
||||||
|
// If there is a txid, make sure it's ours or abort
|
||||||
|
if (parsed.txid && parsed.txid !== txid) { return; }
|
||||||
|
|
||||||
// Keep only metadata messages for the current channel
|
// Keep only metadata messages for the current channel
|
||||||
if (parsed.channel && parsed.channel !== channel) { return; }
|
if (parsed.channel && parsed.channel !== channel) { return; }
|
||||||
@ -138,6 +142,11 @@ define([
|
|||||||
}
|
}
|
||||||
if (parsed.error && parsed.channel) { return; }
|
if (parsed.error && parsed.channel) { return; }
|
||||||
|
|
||||||
|
// If there is a txid, make sure it's ours or abort
|
||||||
|
if (Array.isArray(parsed) && parsed[0] && parsed[0] !== txid) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
msg = parsed[4];
|
msg = parsed[4];
|
||||||
|
|
||||||
// Keep only the history for our channel
|
// Keep only the history for our channel
|
||||||
|
|||||||
@ -54,6 +54,9 @@ define([
|
|||||||
if (!lm.proxy.notifications) {
|
if (!lm.proxy.notifications) {
|
||||||
lm.proxy.notifications = Util.find(ctx.store.proxy, ['mailboxes', 'notifications', 'channel']);
|
lm.proxy.notifications = Util.find(ctx.store.proxy, ['mailboxes', 'notifications', 'channel']);
|
||||||
}
|
}
|
||||||
|
if (!lm.proxy.edPublic) {
|
||||||
|
lm.proxy.edPublic = ctx.store.proxy.edPublic;
|
||||||
|
}
|
||||||
if (ctx.onReadyHandlers.length) {
|
if (ctx.onReadyHandlers.length) {
|
||||||
ctx.onReadyHandlers.forEach(function (f) {
|
ctx.onReadyHandlers.forEach(function (f) {
|
||||||
try {
|
try {
|
||||||
|
|||||||
@ -203,7 +203,6 @@ define([
|
|||||||
var base = exp.getStructure();
|
var base = exp.getStructure();
|
||||||
return typeof (obj) === "object" &&
|
return typeof (obj) === "object" &&
|
||||||
Object.keys(base).every(function (key) {
|
Object.keys(base).every(function (key) {
|
||||||
console.log(key, obj[key], type(obj[key]));
|
|
||||||
return obj[key] && type(base[key]) === type(obj[key]);
|
return obj[key] && type(base[key]) === type(obj[key]);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|||||||
@ -119,7 +119,7 @@ define([
|
|||||||
|
|
||||||
var setHistory = function (bool, update) {
|
var setHistory = function (bool, update) {
|
||||||
history.isHistoryMode = bool;
|
history.isHistoryMode = bool;
|
||||||
setEditable(!bool);
|
setEditable(!bool, true);
|
||||||
if (!bool && update) {
|
if (!bool && update) {
|
||||||
history.onLeaveHistory();
|
history.onLeaveHistory();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -457,6 +457,34 @@ define([
|
|||||||
APP.editor.save();
|
APP.editor.save();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Messages.profile_copyKey = "Copy edPublic key"; // XXX
|
||||||
|
var addPublicKey = function ($container) {
|
||||||
|
if (!APP.readOnly) { return; }
|
||||||
|
|
||||||
|
var $div = $(h('div.cp-sidebarlayout-element')).appendTo($container);
|
||||||
|
APP.$edPublic = $('<button>', {
|
||||||
|
'class': 'btn btn-success',
|
||||||
|
}).append(h('i.fa.fa-key'))
|
||||||
|
.append(h('span', Messages.profile_copyKey))
|
||||||
|
.click(function () {
|
||||||
|
if (!APP.getEdPublic) { return; }
|
||||||
|
APP.getEdPublic();
|
||||||
|
}).appendTo($div).hide();
|
||||||
|
};
|
||||||
|
var setPublicKeyButton = function (data) {
|
||||||
|
if (!data.edPublic || APP.getEdPublic || !APP.readOnly) { return; }
|
||||||
|
APP.$edPublic.show();
|
||||||
|
APP.getEdPublic = function () {
|
||||||
|
var metadataMgr = APP.common.getMetadataMgr();
|
||||||
|
var privateData = metadataMgr.getPrivateData();
|
||||||
|
var name = data.name.toLowerCase().replace(/[^a-zA-Z0-9]+/g, "-");
|
||||||
|
var ed = data.edPublic.replace(/\//g, '-');
|
||||||
|
var url = privateData.origin + '/user/#/1/' + name + '/' + ed;
|
||||||
|
var success = Clipboard.copy(url);
|
||||||
|
if (success) { UI.log(Messages.shareSuccess); }
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
var createLeftside = function () {
|
var createLeftside = function () {
|
||||||
var $categories = $('<div>', {'class': 'cp-sidebarlayout-categories'}).appendTo(APP.$leftside);
|
var $categories = $('<div>', {'class': 'cp-sidebarlayout-categories'}).appendTo(APP.$leftside);
|
||||||
var $category = $('<div>', {'class': 'cp-sidebarlayout-category'}).appendTo($categories);
|
var $category = $('<div>', {'class': 'cp-sidebarlayout-category'}).appendTo($categories);
|
||||||
@ -477,6 +505,7 @@ define([
|
|||||||
addFriendRequest($rightside);
|
addFriendRequest($rightside);
|
||||||
addMuteButton($rightside);
|
addMuteButton($rightside);
|
||||||
addDescription(APP.$rightside);
|
addDescription(APP.$rightside);
|
||||||
|
addPublicKey(APP.$rightside);
|
||||||
addViewButton($rightside);
|
addViewButton($rightside);
|
||||||
APP.initialized = true;
|
APP.initialized = true;
|
||||||
createLeftside();
|
createLeftside();
|
||||||
@ -490,6 +519,7 @@ define([
|
|||||||
refreshDescription(data);
|
refreshDescription(data);
|
||||||
refreshFriendRequest(data);
|
refreshFriendRequest(data);
|
||||||
refreshMute(data);
|
refreshMute(data);
|
||||||
|
setPublicKeyButton(data);
|
||||||
};
|
};
|
||||||
|
|
||||||
var createToolbar = function () {
|
var createToolbar = function () {
|
||||||
|
|||||||
@ -35,7 +35,6 @@
|
|||||||
#cp-app-whiteboard-container {
|
#cp-app-whiteboard-container {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-flow: column;
|
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -43,14 +42,17 @@
|
|||||||
#cp-app-whiteboard-canvas-area {
|
#cp-app-whiteboard-canvas-area {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
display: flex;
|
display: flex;
|
||||||
|
min-height: 0;
|
||||||
}
|
}
|
||||||
// created by fabricjs. styled so defaults don't break anything
|
// created by fabricjs. styled so defaults don't break anything
|
||||||
.cp-app-whiteboard-canvas-container {
|
.cp-app-whiteboard-canvas-container {
|
||||||
|
width: 100%;
|
||||||
margin: auto;
|
margin: auto;
|
||||||
background: white;
|
background: white;
|
||||||
flex: 1;
|
flex: 1;
|
||||||
min-height: 0;
|
min-height: 0;
|
||||||
& > canvas {
|
& > canvas {
|
||||||
|
width: 100%;
|
||||||
border: 1px solid black;
|
border: 1px solid black;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -137,7 +137,7 @@ define([
|
|||||||
canvas.discardActiveGroup();
|
canvas.discardActiveGroup();
|
||||||
}
|
}
|
||||||
canvas.renderAll();
|
canvas.renderAll();
|
||||||
framework.localChange();
|
APP.onLocal();
|
||||||
};
|
};
|
||||||
$deleteButton.click(deleteSelection);
|
$deleteButton.click(deleteSelection);
|
||||||
$(window).on('keyup', function (e) {
|
$(window).on('keyup', function (e) {
|
||||||
@ -220,7 +220,7 @@ define([
|
|||||||
var metadata = JSON.parse(JSON.stringify(metadataMgr.getMetadata()));
|
var metadata = JSON.parse(JSON.stringify(metadataMgr.getMetadata()));
|
||||||
metadata.palette = newPalette;
|
metadata.palette = newPalette;
|
||||||
metadataMgr.updateMetadata(metadata);
|
metadataMgr.updateMetadata(metadata);
|
||||||
framework.localChange();
|
APP.onLocal();
|
||||||
};
|
};
|
||||||
|
|
||||||
var makeColorButton = function ($container) {
|
var makeColorButton = function ($container) {
|
||||||
@ -284,6 +284,34 @@ define([
|
|||||||
});
|
});
|
||||||
var $canvas = $('canvas');
|
var $canvas = $('canvas');
|
||||||
var $canvasContainer = $('canvas').parents('.cp-app-whiteboard-canvas-container');
|
var $canvasContainer = $('canvas').parents('.cp-app-whiteboard-canvas-container');
|
||||||
|
var $container = $('#cp-app-whiteboard-container');
|
||||||
|
|
||||||
|
// Max for old macs: 2048×1464
|
||||||
|
// Max for IE: 8192x8192
|
||||||
|
var MAX = 8192;
|
||||||
|
var onResize = APP.onResize = function () {
|
||||||
|
var w = $container.width();
|
||||||
|
var h = $container.height();
|
||||||
|
canvas.forEachObject(function (obj) {
|
||||||
|
var c = obj.getCoords();
|
||||||
|
Object.keys(c).forEach(function (k) {
|
||||||
|
if (c[k].x > w) { w = c[k].x + 1; }
|
||||||
|
if (c[k].y > h) { h = c[k].y + 1; }
|
||||||
|
});
|
||||||
|
});
|
||||||
|
w = Math.min(w, MAX);
|
||||||
|
h = Math.min(h, MAX);
|
||||||
|
canvas.setWidth(w);
|
||||||
|
canvas.setHeight(h);
|
||||||
|
canvas.calcOffset();
|
||||||
|
};
|
||||||
|
$(window).on('resize', onResize);
|
||||||
|
|
||||||
|
var onLocal = APP.onLocal = function () {
|
||||||
|
framework.localChange();
|
||||||
|
APP.onResize();
|
||||||
|
};
|
||||||
|
|
||||||
var $controls = $('#cp-app-whiteboard-controls');
|
var $controls = $('#cp-app-whiteboard-controls');
|
||||||
var metadataMgr = framework._.cpNfInner.metadataMgr;
|
var metadataMgr = framework._.cpNfInner.metadataMgr;
|
||||||
|
|
||||||
@ -333,7 +361,7 @@ define([
|
|||||||
}
|
}
|
||||||
var cImg = new Fabric.Image(img, { left:0, top:0, angle:0, });
|
var cImg = new Fabric.Image(img, { left:0, top:0, angle:0, });
|
||||||
APP.canvas.add(cImg);
|
APP.canvas.add(cImg);
|
||||||
framework.localChange();
|
onLocal();
|
||||||
};
|
};
|
||||||
|
|
||||||
// Embed image
|
// Embed image
|
||||||
@ -403,7 +431,7 @@ define([
|
|||||||
|
|
||||||
$('#cp-app-whiteboard-clear').on('click', function () {
|
$('#cp-app-whiteboard-clear').on('click', function () {
|
||||||
canvas.clear();
|
canvas.clear();
|
||||||
framework.localChange();
|
onLocal();
|
||||||
});
|
});
|
||||||
|
|
||||||
// ---------------------------------------------
|
// ---------------------------------------------
|
||||||
@ -432,6 +460,7 @@ define([
|
|||||||
var content = newContent.content;
|
var content = newContent.content;
|
||||||
canvas.loadFromJSON(content, waitFor(function () {
|
canvas.loadFromJSON(content, waitFor(function () {
|
||||||
canvas.renderAll();
|
canvas.renderAll();
|
||||||
|
onResize();
|
||||||
}));
|
}));
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -461,7 +490,7 @@ define([
|
|||||||
window.setTimeout(mkThumbnail, Thumb.UPDATE_FIRST);
|
window.setTimeout(mkThumbnail, Thumb.UPDATE_FIRST);
|
||||||
});
|
});
|
||||||
|
|
||||||
canvas.on('mouse:up', framework.localChange);
|
canvas.on('mouse:up', onLocal);
|
||||||
framework.start();
|
framework.start();
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -471,8 +500,6 @@ define([
|
|||||||
h('div#cp-app-whiteboard-canvas-area',
|
h('div#cp-app-whiteboard-canvas-area',
|
||||||
h('div#cp-app-whiteboard-container',
|
h('div#cp-app-whiteboard-container',
|
||||||
h('canvas#cp-app-whiteboard-canvas', {
|
h('canvas#cp-app-whiteboard-canvas', {
|
||||||
width: 600,
|
|
||||||
height: 600
|
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user