Use framework in the whiteboard app

pull/1/head
yflory 7 years ago
parent d37aa0646e
commit 60db53a993

@ -176,9 +176,12 @@ define([
} }
}; };
var contentUpdate = function (newContent) { var oldContent;
var contentUpdate = function (newContent, waitFor) {
if (JSONSortify(newContent) === JSONSortify(oldContent)) { return; }
try { try {
evContentUpdate.fire(newContent); evContentUpdate.fire(newContent, waitFor);
setTimeout(function () { oldContent = newContent; });
} catch (e) { } catch (e) {
console.log(e.stack); console.log(e.stack);
UI.errorLoadingScreen(e.message); UI.errorLoadingScreen(e.message);
@ -197,46 +200,48 @@ define([
cpNfInner.metadataMgr.updateMetadata(meta); cpNfInner.metadataMgr.updateMetadata(meta);
newContent = normalize(newContent); newContent = normalize(newContent);
contentUpdate(newContent); nThen(function (waitFor) {
contentUpdate(newContent, waitFor);
if (!readOnly) { }).nThen(function () {
var newContent2NoMeta = normalize(contentGetter()); if (!readOnly) {
var newContent2StrNoMeta = JSONSortify(newContent2NoMeta); var newContent2NoMeta = normalize(contentGetter());
var newContentStrNoMeta = JSONSortify(newContent); var newContent2StrNoMeta = JSONSortify(newContent2NoMeta);
var newContentStrNoMeta = JSONSortify(newContent);
if (newContent2StrNoMeta !== newContentStrNoMeta) {
console.error("shjson2 !== shjson"); if (newContent2StrNoMeta !== newContentStrNoMeta) {
onLocal(); console.error("shjson2 !== shjson");
onLocal();
/* pushing back over the wire is necessary, but it can
result in a feedback loop, which we call a browser /* pushing back over the wire is necessary, but it can
fight */ result in a feedback loop, which we call a browser
// what changed? fight */
var ops = ChainPad.Diff.diff(newContentStrNoMeta, newContent2StrNoMeta); // what changed?
// log the changes var ops = ChainPad.Diff.diff(newContentStrNoMeta, newContent2StrNoMeta);
console.log(newContentStrNoMeta); // log the changes
console.log(ops); console.log(newContentStrNoMeta);
var sop = JSON.stringify([ newContentStrNoMeta, ops ]); console.log(ops);
var sop = JSON.stringify([ newContentStrNoMeta, ops ]);
var fights = window.CryptPad_fights = window.CryptPad_fights || [];
var index = fights.indexOf(sop); var fights = window.CryptPad_fights = window.CryptPad_fights || [];
if (index === -1) { var index = fights.indexOf(sop);
fights.push(sop); if (index === -1) {
console.log("Found a new type of browser disagreement"); fights.push(sop);
console.log("You can inspect the list in your " + console.log("Found a new type of browser disagreement");
"console at `REALTIME_MODULE.fights`"); console.log("You can inspect the list in your " +
console.log(fights); "console at `REALTIME_MODULE.fights`");
} else { console.log(fights);
console.log("Encountered a known browser disagreement: " + } else {
"available at `REALTIME_MODULE.fights[%s]`", index); console.log("Encountered a known browser disagreement: " +
"available at `REALTIME_MODULE.fights[%s]`", index);
}
} }
} }
}
// Notify only when the content has changed, not when someone has joined/left // Notify only when the content has changed, not when someone has joined/left
if (JSONSortify(newContent) !== JSONSortify(oldContent)) { if (JSONSortify(newContent) !== JSONSortify(oldContent)) {
common.notify(); common.notify();
} }
});
}; };
var setHistoryMode = function (bool, update) { var setHistoryMode = function (bool, update) {
@ -289,58 +294,62 @@ define([
var newPad = false; var newPad = false;
if (newContentStr === '') { newPad = true; } if (newContentStr === '') { newPad = true; }
if (!newPad) { // contentUpdate may be async so we need an nthen here
var newContent = JSON.parse(newContentStr); nThen(function (waitFor) {
cpNfInner.metadataMgr.updateMetadata(extractMetadata(newContent)); if (!newPad) {
newContent = normalize(newContent); var newContent = JSON.parse(newContentStr);
contentUpdate(newContent); cpNfInner.metadataMgr.updateMetadata(extractMetadata(newContent));
} else { newContent = normalize(newContent);
if (!cpNfInner.metadataMgr.getPrivateData().isNewFile) { contentUpdate(newContent, waitFor);
// We're getting 'new pad' but there is an existing file } else {
// We don't know exactly why this can happen but under no circumstances if (!cpNfInner.metadataMgr.getPrivateData().isNewFile) {
// should we overwrite the content, so lets just try again. // We're getting 'new pad' but there is an existing file
console.log("userDoc is '' but this is not a new pad."); // We don't know exactly why this can happen but under no circumstances
console.log("Either this is an empty document which has not been touched"); // should we overwrite the content, so lets just try again.
console.log("Or else something is terribly wrong, reloading."); console.log("userDoc is '' but this is not a new pad.");
Feedback.send("NON_EMPTY_NEWDOC"); console.log("Either this is an empty document which has not been touched");
setTimeout(function () { common.gotoURL(); }, 1000); console.log("Or else something is terribly wrong, reloading.");
return; Feedback.send("NON_EMPTY_NEWDOC");
setTimeout(function () { common.gotoURL(); }, 1000);
return;
}
console.log('updating title');
title.updateTitle(title.defaultTitle);
evOnDefaultContentNeeded.fire();
}
}).nThen(function () {
stateChange(STATE.READY);
firstConnection = false;
if (!readOnly) { onLocal(); }
evOnReady.fire(newPad);
UI.removeLoadingScreen(emitResize);
var privateDat = cpNfInner.metadataMgr.getPrivateData();
var hash = privateDat.availableHashes.editHash ||
privateDat.availableHashes.viewHash;
var href = privateDat.pathname + '#' + hash;
if (AppConfig.textAnalyzer && textContentGetter) {
AppConfig.textAnalyzer(textContentGetter, privateDat.channel);
} }
console.log('updating title');
title.updateTitle(title.defaultTitle);
evOnDefaultContentNeeded.fire();
}
stateChange(STATE.READY);
firstConnection = false;
if (!readOnly) { onLocal(); }
evOnReady.fire(newPad);
UI.removeLoadingScreen(emitResize);
var privateDat = cpNfInner.metadataMgr.getPrivateData();
var hash = privateDat.availableHashes.editHash ||
privateDat.availableHashes.viewHash;
var href = privateDat.pathname + '#' + hash;
if (AppConfig.textAnalyzer && textContentGetter) {
AppConfig.textAnalyzer(textContentGetter, privateDat.channel);
}
if (options.thumbnail && privateDat.thumbnails) { if (options.thumbnail && privateDat.thumbnails) {
if (hash) { if (hash) {
options.thumbnail.href = href; options.thumbnail.href = href;
options.thumbnail.getContent = function () { options.thumbnail.getContent = function () {
if (!cpNfInner.chainpad) { return; } if (!cpNfInner.chainpad) { return; }
return cpNfInner.chainpad.getUserDoc(); return cpNfInner.chainpad.getUserDoc();
}; };
Thumb.initPadThumbnails(common, options.thumbnail); Thumb.initPadThumbnails(common, options.thumbnail);
}
} }
}
var skipTemp = Util.find(privateDat, ['settings', 'general', 'creation', 'noTemplate']); var skipTemp = Util.find(privateDat, ['settings', 'general', 'creation', 'noTemplate']);
var skipCreation = Util.find(privateDat, ['settings', 'general', 'creation', 'skip']); var skipCreation = Util.find(privateDat, ['settings', 'general', 'creation', 'skip']);
if (newPad && (!AppConfig.displayCreationScreen || (!skipTemp && skipCreation))) { if (newPad && (!AppConfig.displayCreationScreen || (!skipTemp && skipCreation))) {
common.openTemplatePicker(); common.openTemplatePicker();
} }
});
}; };
var onConnectionChange = function (info) { var onConnectionChange = function (info) {
if (state === STATE.DELETED) { return; } if (state === STATE.DELETED) { return; }
@ -385,13 +394,19 @@ define([
common.createButton('import', true, options, function (c, f) { common.createButton('import', true, options, function (c, f) {
if (async) { if (async) {
fi(c, f, function (content) { fi(c, f, function (content) {
contentUpdate(content); nThen(function (waitFor) {
onLocal(); contentUpdate(content, waitFor);
}).nThen(function () {
onLocal();
});
}); });
return; return;
} }
contentUpdate(fi(c, f)); nThen(function (waitFor) {
onLocal(); contentUpdate(fi(c, f), waitFor);
}).nThen(function () {
onLocal();
});
}) })
); );
}; };

@ -1,81 +1,59 @@
define([ define([
'jquery', 'jquery',
'/bower_components/chainpad-crypto/crypto.js',
'/common/toolbar3.js',
'json.sortify', 'json.sortify',
'/common/common-util.js',
'/bower_components/nthen/index.js', '/bower_components/nthen/index.js',
'/common/sframe-common.js', '/common/sframe-common.js',
'/common/sframe-app-framework.js',
'/common/common-util.js',
'/common/common-hash.js',
'/common/common-interface.js', '/common/common-interface.js',
'/api/config', '/common/common-thumbnail.js',
'/common/common-realtime.js',
'/customize/pages.js', '/customize/pages.js',
'/customize/messages.js', '/customize/messages.js',
'/customize/application_config.js',
'/common/common-thumbnail.js',
'/whiteboard/colors.js', '/whiteboard/colors.js',
'/customize/application_config.js',
'/bower_components/chainpad/chainpad.dist.js', '/bower_components/chainpad/chainpad.dist.js',
'/bower_components/secure-fabric.js/dist/fabric.min.js', '/bower_components/secure-fabric.js/dist/fabric.min.js',
'/bower_components/file-saver/FileSaver.min.js',
'css!/bower_components/bootstrap/dist/css/bootstrap.min.css',
'css!/bower_components/components-font-awesome/css/font-awesome.min.css',
'less!/customize/src/less2/main.less',
], function ( ], function (
$, $,
Crypto, Sortify,
Toolbar,
JSONSortify,
Util,
nThen, nThen,
SFCommon, SFCommon,
Framework,
Util,
Hash,
UI, UI,
ApiConfig, Thumb,
CommonRealtime,
Pages, Pages,
Messages, Messages,
AppConfig,
Thumb,
Colors, Colors,
AppConfig,
ChainPad) ChainPad)
{ {
var saveAs = window.saveAs;
var APP = window.APP = { var APP = window.APP = {
$: $ $: $
}; };
var Fabric = APP.Fabric = window.fabric; var Fabric = APP.Fabric = window.fabric;
var stringify = function (obj) { var verbose = function (x) { console.log(x); };
return JSONSortify(obj); verbose = function () {}; // comment out to enable verbose logging
};
var toolbar;
var andThen = function (common) { var mkControls = function (framework, canvas) {
var config = {};
/* Initialize Fabric */
var canvas = APP.canvas = new Fabric.Canvas('cp-app-whiteboard-canvas', {
containerClass: 'cp-app-whiteboard-canvas-container'
});
var $canvas = $('canvas');
var $controls = $('#cp-app-whiteboard-controls');
var $canvasContainer = $('canvas').parents('.cp-app-whiteboard-canvas-container');
var $pickers = $('#cp-app-whiteboard-pickers'); var $pickers = $('#cp-app-whiteboard-pickers');
var $colors = $('#cp-app-whiteboard-colors'); var $colors = $('#cp-app-whiteboard-colors');
var $cursors = $('#cp-app-whiteboard-cursors'); var $cursors = $('#cp-app-whiteboard-cursors');
var $deleteButton = $('#cp-app-whiteboard-delete'); var $controls = $('#cp-app-whiteboard-controls');
var $toggle = $('#cp-app-whiteboard-toggledraw');
var $width = $('#cp-app-whiteboard-width'); var $width = $('#cp-app-whiteboard-width');
var $widthLabel = $('label[for="cp-app-whiteboard-width"]'); var $widthLabel = $('label[for="cp-app-whiteboard-width"]');
var $opacity = $('#cp-app-whiteboard-opacity'); var $opacity = $('#cp-app-whiteboard-opacity');
var $opacityLabel = $('label[for="cp-app-whiteboard-opacity"]'); var $opacityLabel = $('label[for="cp-app-whiteboard-opacity"]');
var $toggle = $('#cp-app-whiteboard-toggledraw');
var $deleteButton = $('#cp-app-whiteboard-delete');
var metadataMgr = framework._.cpNfInner.metadataMgr;
// Brush
var readOnly = false;
var brush = { var brush = {
color: '#000000', color: '#000000',
opacity: 1 opacity: 1
@ -136,39 +114,6 @@ define([
updateBrushOpacity(); updateBrushOpacity();
$opacity.on('change', updateBrushOpacity); $opacity.on('change', updateBrushOpacity);
var pickColor = function (current, cb) {
var $picker = $('<input>', {
type: 'color',
value: '#FFFFFF',
})
.on('change', function () {
var color = this.value;
cb(color);
}).appendTo($pickers);
setTimeout(function () {
$picker.val(current);
$picker.click();
});
};
var setColor = function (c) {
c = Colors.rgb2hex(c);
brush.color = c;
canvas.freeDrawingBrush.color = Colors.hex2rgba(brush.color, brush.opacity);
APP.$color.css({
'color': c,
});
createCursor();
};
var palette = AppConfig.whiteboardPalette || [
'red', 'blue', 'green', 'white', 'black', 'purple',
'gray', 'beige', 'brown', 'cyan', 'darkcyan', 'gold', 'yellow', 'pink'
];
$('.cp-app-whiteboard-palette-color').on('click', function () {
var color = $(this).css('background-color');
setColor(color);
});
APP.draw = true; APP.draw = true;
var toggleDrawMode = function () { var toggleDrawMode = function () {
canvas.deactivateAll().renderAll(); canvas.deactivateAll().renderAll();
@ -191,74 +136,49 @@ define([
canvas.discardActiveGroup(); canvas.discardActiveGroup();
} }
canvas.renderAll(); canvas.renderAll();
config.onLocal(); framework.localChange();
}; };
$deleteButton.click(deleteSelection); $deleteButton.click(deleteSelection);
$(window).on('keyup', function (e) { $(window).on('keyup', function (e) {
if (e.which === 46) { deleteSelection (); } if (e.which === 46) { deleteSelection (); }
}); });
var setEditable = function (bool) {
APP.editable = bool;
if (readOnly && bool) { return; }
if (bool) { $controls.css('display', 'flex'); }
else { $controls.hide(); }
canvas.isDrawingMode = bool ? APP.draw : false; var pickColor = function (current, cb) {
if (!bool) { var $picker = $('<input>', {
canvas.deactivateAll(); type: 'color',
canvas.renderAll(); value: '#FFFFFF',
} })
canvas.forEachObject(function (object) { .on('change', function () {
object.selectable = bool; var color = this.value;
}); cb(color);
$canvasContainer.find('canvas').css('border-color', bool? 'black': 'red'); }).appendTo($pickers);
}; setTimeout(function () {
$picker.val(current);
var saveImage = APP.saveImage = function () { $picker.click();
var defaultName = "pretty-picture.png";
UI.prompt(Messages.exportPrompt, defaultName, function (filename) {
if (!(typeof(filename) === 'string' && filename)) { return; }
$canvas[0].toBlob(function (blob) {
saveAs(blob, filename);
});
}); });
}; };
var setColor = function (c) {
APP.FM = common.createFileManager({}); c = Colors.rgb2hex(c);
APP.upload = function (title) { brush.color = c;
var canvas = $canvas[0]; canvas.freeDrawingBrush.color = Colors.hex2rgba(brush.color, brush.opacity);
APP.canvas.deactivateAll().renderAll(); APP.$color.css({
canvas.toBlob(function (blob) { 'color': c,
blob.name = title;
APP.FM.handleFile(blob);
}); });
createCursor();
}; };
var initializing = true; var palette = AppConfig.whiteboardPalette || [
var $bar = $('#cp-toolbar'); 'red', 'blue', 'green', 'white', 'black', 'purple',
var Title; 'gray', 'beige', 'brown', 'cyan', 'darkcyan', 'gold', 'yellow', 'pink'
var cpNfInner; ];
var metadataMgr; $('.cp-app-whiteboard-palette-color').on('click', function () {
var color = $(this).css('background-color');
config = { setColor(color);
readOnly: readOnly, });
patchTransformer: ChainPad.NaiveJSONTransformer,
// cryptpad debug logging (default is 1)
// logLevel: 0,
validateContent: function (content) {
try {
JSON.parse(content);
return true;
} catch (e) {
console.log("Failed to parse, rejecting patch");
return false;
}
}
};
var addColorToPalette = function (color, i) { var addColorToPalette = function (color, i) {
if (readOnly) { return; } if (framework.isReadOnly()) { return; }
var $color = $('<span>', { var $color = $('<span>', {
'class': 'cp-app-whiteboard-palette-color', 'class': 'cp-app-whiteboard-palette-color',
}) })
@ -271,7 +191,7 @@ define([
}) })
.on('dblclick', function (e) { .on('dblclick', function (e) {
e.preventDefault(); e.preventDefault();
if (!APP.editable) { return; } if (framework.isLocked()) { return; }
pickColor(Colors.rgb2hex($color.css('background-color')), function (c) { pickColor(Colors.rgb2hex($color.css('background-color')), function (c) {
$color.css({ $color.css({
'background-color': c, 'background-color': c,
@ -287,7 +207,7 @@ define([
var first = true; var first = true;
var updatePalette = function (newPalette) { var updatePalette = function (newPalette) {
if (first || stringify(palette) !== stringify(newPalette)) { if (first || Sortify(palette) !== Sortify(newPalette)) {
palette = newPalette; palette = newPalette;
$colors.html('<div class="hidden">&nbsp;</div>'); $colors.html('<div class="hidden">&nbsp;</div>');
palette.forEach(addColorToPalette); palette.forEach(addColorToPalette);
@ -299,7 +219,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);
config.onLocal(); framework.localChange();
}; };
var makeColorButton = function ($container) { var makeColorButton = function ($container) {
@ -312,7 +232,7 @@ define([
return; return;
} }
var $color = APP.$color = common.createButton(null, true, { var $color = APP.$color = framework._.sfCommon.createButton(null, true, {
icon: 'fa-square', icon: 'fa-square',
title: Messages.canvas_chooseColor, title: Messages.canvas_chooseColor,
name: 'color', name: 'color',
@ -331,33 +251,73 @@ define([
return $color; return $color;
}; };
var stringifyInner = function (textValue) { updateLocalPalette(palette);
var obj = {
content: textValue, metadataMgr.onChange(function () {
metadata: metadataMgr.getMetadataLazy() var md = metadataMgr.getMetadata();
}; if (md.palette) {
// stringify the json and send it into chainpad updateLocalPalette(md.palette);
return stringify(obj); }
});
return {
palette: palette,
makeColorButton: makeColorButton,
updateLocalPalette: updateLocalPalette,
}; };
};
var mkHelpMenu = function (framework) {
var $appContainer = $('#cp-app-whiteboard-container');
var helpMenu = framework._.sfCommon.createHelpMenu(['whiteboard']);
$appContainer.prepend(helpMenu.menu);
framework._.toolbar.$drawer.append(helpMenu.button);
};
// Start of the main loop
var andThen2 = function (framework) {
var canvas = APP.canvas = new Fabric.Canvas('cp-app-whiteboard-canvas', {
containerClass: 'cp-app-whiteboard-canvas-container'
});
var $canvas = $('canvas');
var $canvasContainer = $('canvas').parents('.cp-app-whiteboard-canvas-container');
var $controls = $('#cp-app-whiteboard-controls');
var metadataMgr = framework._.cpNfInner.metadataMgr;
var onLocal = config.onLocal = function () { var setEditable = function (bool) {
if (initializing) { return; } if (bool) { $controls.css('display', 'flex'); }
if (readOnly) { return; } else { $controls.hide(); }
var content = stringifyInner(canvas.toDatalessJSON()); canvas.isDrawingMode = bool ? APP.draw : false;
if (!bool) {
try { canvas.deactivateAll();
APP.realtime.contentUpdate(content); canvas.renderAll();
} catch (e) {
APP.unrecoverable = true;
setEditable(false);
APP.toolbar.errorState(true, e.message);
var msg = Messages.chainpadError;
UI.errorLoadingScreen(msg, true, true);
console.error(e);
} }
canvas.forEachObject(function (object) {
object.selectable = bool;
});
$canvasContainer.find('canvas').css('border-color', bool? 'black': 'red');
}; };
mkHelpMenu(framework);
var controls = mkControls(framework, canvas);
// ---------------------------------------------
// Whiteboard custom buttons
// ---------------------------------------------
var $rightside = framework._.toolbar.$rightside;
APP.FM = framework._.sfCommon.createFileManager({});
APP.upload = function (title) {
var canvas = $canvas[0];
APP.canvas.deactivateAll().renderAll();
canvas.toBlob(function (blob) {
blob.name = title;
APP.FM.handleFile(blob);
});
};
var addImageToCanvas = function (img) { var addImageToCanvas = function (img) {
var w = img.width; var w = img.width;
var h = img.height; var h = img.height;
@ -370,313 +330,159 @@ 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);
onLocal(); framework.localChange();
}; };
var initThumbnails = function () { // Export to drive as PNG
var oldThumbnailState; framework._.sfCommon.createButton('savetodrive', true, {}).click(function () {
var privateDat = metadataMgr.getPrivateData(); var defaultName = framework._.title.getTitle();
if (!privateDat.thumbnails) { return; } UI.prompt(Messages.exportPrompt, defaultName + '.png', function (name) {
var hash = privateDat.availableHashes.editHash || if (name === null || !name.trim()) { return; }
privateDat.availableHashes.viewHash; APP.upload(name);
var href = privateDat.pathname + '#' + hash; });
var mkThumbnail = function () { }).appendTo($rightside);
if (!hash) { return; }
if (initializing) { return; } // Embed image
if (!APP.realtime) { return; } var onUpload = function (e) {
var content = APP.realtime.getUserDoc(); var file = e.target.files[0];
if (content === oldThumbnailState) { return; } var reader = new FileReader();
var D = Thumb.getResizedDimensions($canvas[0], 'pad'); reader.onload = function () {
Thumb.fromCanvas($canvas[0], D, function (err, b64) { var img = new Image();
oldThumbnailState = content; img.onload = function () {
Thumb.setPadThumbnail(common, href, privateDat.channel, b64); addImageToCanvas(img);
}); };
img.src = reader.result;
}; };
window.setInterval(mkThumbnail, Thumb.UPDATE_INTERVAL); reader.readAsDataURL(file);
window.setTimeout(mkThumbnail, Thumb.UPDATE_FIRST);
}; };
framework._.sfCommon.createButton('', true, {
config.onInit = function (info) { title: Messages.canvas_imageEmbed,
updateLocalPalette(palette); icon: 'fa-file-image-o',
readOnly = metadataMgr.getPrivateData().readOnly; name: 'embedImage'
}).click(function () {
Title = common.createTitle({}); $('<input>', {type:'file'}).on('change', onUpload).click();
}).appendTo($rightside);
var configTb = {
displayed: [ if (framework._.sfCommon.isLoggedIn()) {
'userlist', var fileDialogCfg = {
'title', onSelect: function (data) {
'useradmin', if (data.type === 'file') {
'spinner', var mt = '<media-tag src="' + data.src + '" data-crypto-key="cryptpad:' + data.key + '"></media-tag>';
'newpad', framework._.sfCommon.displayMediatagImage($(mt), function (err, $image) {
'share', Util.blobURLToImage($image.attr('src'), function (imgSrc) {
'limit', var img = new Image();
'unpinnedWarning' img.onload = function () { addImageToCanvas(img); };
], img.src = imgSrc;
title: Title.getTitleConfig(), });
metadataMgr: metadataMgr, });
readOnly: readOnly, return;
realtime: info.realtime, }
sfCommon: common, }
$container: $bar,
$contentContainer: $('#cp-app-whiteboard-canvas-area')
}; };
toolbar = APP.toolbar = Toolbar.create(configTb); framework._.sfCommon.initFilePicker(fileDialogCfg);
Title.setToolbar(toolbar); framework._.sfCommon.createButton('mediatag', true).click(function () {
var pickerCfg = {
var $rightside = toolbar.$rightside; types: ['file'],
var $drawer = toolbar.$drawer; where: ['root'],
filter: {
/* save as template */ fileType: ['image/']
if (!metadataMgr.getPrivateData().isTemplate) { }
var templateObj = {
rt: info.realtime,
getTitle: function () { return metadataMgr.getMetadata().title; }
}; };
var $templateButton = common.createButton('template', true, templateObj); framework._.sfCommon.openFilePicker(pickerCfg);
$rightside.append($templateButton); }).appendTo($rightside);
} }
/* add an export button */
var $export = common.createButton('export', true, {}, saveImage);
$drawer.append($export);
if (common.isLoggedIn()) {
common.createButton('savetodrive', true, {}, function () {})
.click(function () {
UI.prompt(Messages.exportPrompt, document.title + '.png',
function (name) {
if (name === null || !name.trim()) { return; }
APP.upload(name);
});
}).appendTo($rightside);
common.createButton('hashtag', true).appendTo($rightside);
}
var $forget = common.createButton('forget', true, {}, function (err) {
if (err) { return; }
setEditable(false);
});
$rightside.append($forget);
var $properties = common.createButton('properties', true);
toolbar.$drawer.append($properties);
var $appContainer = $('#cp-app-whiteboard-container');
var helpMenu = common.createHelpMenu(['whiteboard']);
$appContainer.prepend(helpMenu.menu);
toolbar.$drawer.append(helpMenu.button);
if (!readOnly) {
makeColorButton($rightside);
// Embed image
var onUpload = function (e) {
var file = e.target.files[0];
var reader = new FileReader();
reader.onload = function () {
var img = new Image();
img.onload = function () {
addImageToCanvas(img);
};
img.src = reader.result;
};
reader.readAsDataURL(file);
};
common.createButton('', true, {
title: Messages.canvas_imageEmbed,
icon: 'fa-file-image-o',
name: 'embedImage'
}).click(function () {
$('<input>', {type:'file'}).on('change', onUpload).click();
}).appendTo($rightside);
if (common.isLoggedIn()) {
var fileDialogCfg = {
onSelect: function (data) {
if (data.type === 'file') {
var mt = '<media-tag src="' + data.src + '" data-crypto-key="cryptpad:' + data.key + '"></media-tag>';
common.displayMediatagImage($(mt), function (err, $image) {
Util.blobURLToImage($image.attr('src'), function (imgSrc) {
var img = new Image();
img.onload = function () { addImageToCanvas(img); };
img.src = imgSrc;
});
});
return;
}
}
};
common.initFilePicker(fileDialogCfg);
APP.$mediaTagButton = common.createButton('mediatag', true).click(function () {
var pickerCfg = {
types: ['file'],
where: ['root'],
filter: {
fileType: ['image/']
}
};
common.openFilePicker(pickerCfg);
}).appendTo($rightside);
}
} else {
$colors.hide();
$controls.hide();
}
metadataMgr.onChange(function () {
var md = metadataMgr.getMetadata();
if (md.palette) {
updateLocalPalette(md.palette);
}
});
};
config.onReady = function (info) {
if (APP.realtime !== info.realtime) {
APP.realtime = info.realtime;
}
var userDoc = APP.realtime.getUserDoc();
var isNew = false;
var newDoc = '';
if (userDoc === "" || userDoc === "{}") { isNew = true; }
if (userDoc !== "") { if (framework.isReadOnly()) {
var hjson = JSON.parse(userDoc); setEditable(false);
} else {
if (hjson && hjson.metadata) { controls.makeColorButton($rightside);
metadataMgr.updateMetadata(hjson.metadata); }
}
if (typeof (hjson) !== 'object' || Array.isArray(hjson) ||
(hjson.metadata && typeof(hjson.metadata.type) !== 'undefined' &&
hjson.metadata.type !== 'whiteboard')) {
var errorText = Messages.typeError;
UI.errorLoadingScreen(errorText);
throw new Error(errorText);
}
newDoc = hjson.content;
} else {
Title.updateTitle(Title.defaultTitle);
}
nThen(function (waitFor) { $('#cp-app-whiteboard-clear').on('click', function () {
if (newDoc) { canvas.clear();
canvas.loadFromJSON(newDoc, waitFor(function () { framework.localChange();
console.log('loaded'); });
canvas.renderAll();
}));
}
}).nThen(function () {
setEditable(!readOnly);
initializing = false;
config.onLocal();
UI.removeLoadingScreen();
initThumbnails(); // ---------------------------------------------
// End custom
// ---------------------------------------------
if (readOnly) { return; } framework.onEditableChange(function () {
var locked = framework.isLocked() || framework.isReadOnly();
setEditable(!locked);
});
var privateDat = metadataMgr.getPrivateData(); framework.setFileExporter('png', function (cb) {
var skipTemp = Util.find(privateDat, $canvas[0].toBlob(function (blob) {
['settings', 'general', 'creation', 'noTemplate']); cb(blob);
var skipCreation = Util.find(privateDat, ['settings', 'general', 'creation', 'skip']);
if (isNew && (!AppConfig.displayCreationScreen || (!skipTemp && skipCreation))) {
common.openTemplatePicker();
}
}); });
});
}; framework.setNormalizer(function (c) {
return {
config.onRemote = function () { content: c.content
if (initializing) { return; } };
var userDoc = APP.realtime.getUserDoc(); });
var json = JSON.parse(userDoc);
var remoteDoc = json.content;
canvas.loadFromJSON(remoteDoc, function () { framework.onContentUpdate(function (newContent, waitFor) {
var content = newContent.content;
canvas.loadFromJSON(content, waitFor(function () {
canvas.renderAll(); canvas.renderAll();
if (json.metadata) { }));
metadataMgr.updateMetadata(json.metadata);
}
});
var content = canvas.toDatalessJSON();
if (content !== remoteDoc) { common.notify(); }
if (readOnly) { setEditable(false); }
};
config.onAbort = function () {
if (APP.unrecoverable) { return; }
// inform of network disconnect
setEditable(false);
toolbar.failed();
UI.alert(Messages.common_connectionLost, undefined, true);
};
config.onConnectionChange = function (info) {
if (APP.unrecoverable) { return; }
setEditable(info.state);
if (info.state) {
initializing = true;
//UI.findOKButton().click();
} else {
//UI.alert(Messages.common_connectionLost, undefined, true);
}
};
config.onError = function (err) {
common.onServerError(err, toolbar, function () {
APP.unrecoverable = true;
setEditable(false);
});
};
cpNfInner = common.startRealtime(config);
metadataMgr = cpNfInner.metadataMgr;
cpNfInner.onInfiniteSpinner(function () {
if (APP.unrecoverable) { return; }
setEditable(false);
UI.confirm(Messages.realtime_unrecoverableError, function (yes) {
if (!yes) { return; }
common.gotoURL();
});
}); });
canvas.on('mouse:up', onLocal); framework.setContentGetter(function () {
var content = canvas.toDatalessJSON();
$('#cp-app-whiteboard-clear').on('click', function () { return {
canvas.clear(); content: content
onLocal(); };
}); });
$('#save').on('click', function () { framework.onReady(function () {
saveImage(); var oldThumbnailState;
var privateDat = metadataMgr.getPrivateData();
if (!privateDat.thumbnails) { return; }
var hash = privateDat.availableHashes.editHash ||
privateDat.availableHashes.viewHash;
var href = privateDat.pathname + '#' + hash;
var mkThumbnail = function () {
if (!hash) { return; }
if (framework.getState() !== 'READY') { return; }
if (!framework._.cpNfInner.chainpad) { return; }
var content = framework._.cpNfInner.chainpad.getUserDoc();
if (content === oldThumbnailState) { return; }
var D = Thumb.getResizedDimensions($canvas[0], 'pad');
Thumb.fromCanvas($canvas[0], D, function (err, b64) {
oldThumbnailState = content;
Thumb.setPadThumbnail(framework._.sfCommon, href, privateDat.channel, b64);
});
};
window.setInterval(mkThumbnail, Thumb.UPDATE_INTERVAL);
window.setTimeout(mkThumbnail, Thumb.UPDATE_FIRST);
}); });
common.onLogout(function () { setEditable(false); }); canvas.on('mouse:up', framework.localChange);
framework.start();
}; };
var main = function () { var main = function () {
var common; // var framework;
nThen(function (waitFor) { nThen(function (waitFor) {
$(waitFor(function () { $(waitFor(function () {
UI.addLoadingScreen();
var $div = $('<div>').append(Pages['/whiteboard/']()); var $div = $('<div>').append(Pages['/whiteboard/']());
$('body').append($div.html()); $('body').append($div.html());
})); }));
SFCommon.create(waitFor(function (c) { APP.common = common = c; }));
}).nThen(function (waitFor) { }).nThen(function (waitFor) {
common.getSframeChannel().onReady(waitFor());
}).nThen(function (waitFor) { // Framework initialization
common.handleNewFile(waitFor); Framework.create({
}).nThen(function (/*waitFor*/) { patchTransformer: ChainPad.NaiveJSONTransformer,
andThen(common); toolbarContainer: '#cp-toolbar',
contentContainer: '#cp-app-whiteboard-canvas-area',
}, waitFor(function (framework) {
andThen2(framework);
}));
}); });
}; };
main(); main();

Loading…
Cancel
Save