diff --git a/customize.dist/application_config.js b/customize.dist/application_config.js index 1ac8a8bab..8f190a9ad 100644 --- a/customize.dist/application_config.js +++ b/customize.dist/application_config.js @@ -32,6 +32,7 @@ define(function() { '#FF00C0', // hot pink '#800080', // purple ]; + config.enableTemplates = true; return config; }); diff --git a/customize.dist/translations/messages.fr.js b/customize.dist/translations/messages.fr.js index edc717b57..6d8b3899a 100644 --- a/customize.dist/translations/messages.fr.js +++ b/customize.dist/translations/messages.fr.js @@ -75,6 +75,11 @@ define(function () { out.newButton = 'Nouveau'; out.newButtonTitle = 'Créer un nouveau pad'; + out.saveTemplateButton = "Sauver en tant que modèle"; + out.saveTemplatePrompt = "Choisir un titre pour ce modèle"; + out.templateSaved = "Modèle enregistré !"; + out.selectTemplate = "Sélectionner un modèle ou appuyer sur Échap"; + out.presentButtonTitle = "Entrer en mode présentation"; out.presentSuccess = 'Appuyer sur Échap pour quitter le mode présentation'; @@ -146,8 +151,11 @@ define(function () { // Canvas out.canvas_clear = "Nettoyer"; + out.canvas_delete = "Supprimer la sélection"; out.canvas_disable = "Désactiver le dessin"; out.canvas_enable = "Activer le dessin"; + out.canvas_width = "Épaisseur"; + out.canvas_opacity = "Opacité"; // File manager diff --git a/customize.dist/translations/messages.js b/customize.dist/translations/messages.js index 2af12e044..66f771033 100644 --- a/customize.dist/translations/messages.js +++ b/customize.dist/translations/messages.js @@ -77,6 +77,11 @@ define(function () { out.newButton = 'New'; out.newButtonTitle = 'Create a new pad'; + out.saveTemplateButton = "Save as template"; + out.saveTemplatePrompt = "Choose a title for the template"; + out.templateSaved = "Template saved!"; + out.selectTemplate = "Select a template or press escape"; + out.presentButtonTitle = "Enter presentation mode"; out.presentSuccess = 'Hit ESC to exit presentation mode'; @@ -148,8 +153,11 @@ define(function () { // Canvas out.canvas_clear = "Clear"; + out.canvas_delete = "Delete selection"; out.canvas_disable = "Disable draw"; out.canvas_enable = "Enable draw"; + out.canvas_width = "Width"; + out.canvas_opacity = "Opacity"; // File manager diff --git a/www/code/main.js b/www/code/main.js index 8127cb566..227c1e1fa 100644 --- a/www/code/main.js +++ b/www/code/main.js @@ -7,13 +7,14 @@ define([ 'json.sortify', '/bower_components/chainpad-json-validator/json-ot.js', '/common/cryptpad-common.js', + '/common/cryptget.js', '/common/modes.js', '/common/themes.js', '/common/visible.js', '/common/notify.js', '/bower_components/file-saver/FileSaver.min.js', '/bower_components/jquery/dist/jquery.min.js', -], function (Crypto, Realtime, TextPatcher, Toolbar, JSONSortify, JsonOT, Cryptpad, Modes, Themes, Visible, Notify) { +], function (Crypto, Realtime, TextPatcher, Toolbar, JSONSortify, JsonOT, Cryptpad, Cryptget, Modes, Themes, Visible, Notify) { var $ = window.jQuery; var saveAs = window.saveAs; var Messages = Cryptpad.Messages; @@ -401,6 +402,17 @@ define([ editHash = Cryptpad.getEditHashFromKeys(info.channel, secret.keys); } + /* save as template */ + if (!Cryptpad.isTemplate(window.location.href)) { + var templateObj = { + rt: info.realtime, + Crypt: Cryptget, + getTitle: function () { return document.title; } + }; + var $templateButton = Cryptpad.createButton('template', true, templateObj); + $rightside.append($templateButton); + } + /* add an export button */ var $export = Cryptpad.createButton('export', true, {}, exportText); $rightside.append($export); @@ -532,6 +544,8 @@ define([ var userDoc = module.realtime.getUserDoc(); + var isNew = false; + if (userDoc === "" || userDoc === "{}") { isNew = true; } var newDoc = ""; if(userDoc !== "") { @@ -599,6 +613,9 @@ define([ onLocal(); module.$userNameButton.click(); } + if (isNew) { + Cryptpad.selectTemplate('code', info.realtime, Cryptget); + } }); }; diff --git a/www/common/cryptpad-common.js b/www/common/cryptpad-common.js index daeb00eee..770326430 100644 --- a/www/common/cryptpad-common.js +++ b/www/common/cryptpad-common.js @@ -498,7 +498,7 @@ load pinpad dynamically only after you know that it will be needed */ }; var makePad = function (href, title) { - var now = ''+new Date(); + var now = +new Date(); return { href: href, atime: now, @@ -557,6 +557,41 @@ load pinpad dynamically only after you know that it will be needed */ getStore().addTemplate(href); }; + var isTemplate = common.isTemplate = function (href) { + var rhref = getRelativeHref(href); + var templates = listTemplates(); + return templates.some(function (t) { + return t.href === rhref; + }); + }; + var selectTemplate = common.selectTemplate = function (type, rt, Crypt) { + if (!AppConfig.enableTemplates) { return; } + var temps = listTemplates(type); + if (temps.length === 0) { return; } + var $content = $('
'); + $('').text(Messages.selectTemplate).appendTo($content); + $('

', {id:"selectTemplate"}).appendTo($content); + Cryptpad.alert($content.html(), null, true); + var $p = $('#selectTemplate'); + temps.forEach(function (t, i) { + $('', {href: t.href, title: t.title}).text(t.title).click(function (e) { + e.preventDefault(); + var parsed = parsePadUrl(t.href); + if(!parsed) { throw new Error("Cannot get template hash"); } + common.addLoadingScreen(null, true); + Crypt.get(parsed.hash, function (err, val) { + if (err) { throw new Error(err); } + var p = parsePadUrl(window.location.href); + Crypt.put(p.hash, val, function (e) { + common.findOKButton().click(); + common.removeLoadingScreen(); + }); + }); + }).appendTo($p); + if (i !== temps.length) { $('
').appendTo($p); } + }); + common.findOKButton().text(Messages.cancelButton); + }; // STORAGE /* fetch and migrate your pad history from localStorage */ @@ -1118,6 +1153,56 @@ load pinpad dynamically only after you know that it will be needed */ })); } break; + case 'template': + if (!AppConfig.enableTemplates) { return; } + button = $(' - + + +

 
diff --git a/www/whiteboard/main.js b/www/whiteboard/main.js index 4b843dd3f..d5523104c 100644 --- a/www/whiteboard/main.js +++ b/www/whiteboard/main.js @@ -11,13 +11,15 @@ define([ 'json.sortify', '/bower_components/chainpad-json-validator/json-ot.js', '/common/cryptpad-common.js', + '/common/cryptget.js', + '/whiteboard/colors.js', '/common/visible.js', '/common/notify.js', '/customize/application_config.js', '/bower_components/secure-fabric.js/dist/fabric.min.js', '/bower_components/jquery/dist/jquery.min.js', '/bower_components/file-saver/FileSaver.min.js', -], function (Config, Realtime, Crypto, Toolbar, TextPatcher, JSONSortify, JsonOT, Cryptpad, Visible, Notify, AppConfig) { +], function (Config, Realtime, Crypto, Toolbar, TextPatcher, JSONSortify, JsonOT, Cryptpad, Cryptget, Colors, Visible, Notify, AppConfig) { var saveAs = window.saveAs; var Messages = Cryptpad.Messages; @@ -47,15 +49,23 @@ define([ var $pickers = $('#pickers'); var $colors = $('#colors'); var $cursors = $('#cursors'); + var $deleteButton = $('#delete'); + + var brush = { + color: '#000000', + opacity: 1 + }; var $toggle = $('#toggleDraw'); var $width = $('#width'); var $widthLabel = $('label[for="width"]'); - + var $opacity = $('#opacity'); + var $opacityLabel = $('label[for="opacity"]'); +window.canvas = canvas; var createCursor = function () { var w = canvas.freeDrawingBrush.width; var c = canvas.freeDrawingBrush.color; - var size = w > 30 ? w : w+30; + var size = w > 30 ? w+2 : w+32; $cursors.html(''); var $ccanvas = $cursors.find('canvas'); var ccanvas = $ccanvas[0]; @@ -69,7 +79,9 @@ define([ ctx.arc(centerX, centerY, radius, 0, 2 * Math.PI, false); ctx.fillStyle = c; ctx.fill(); - ctx.lineWidth = 0; + ctx.lineWidth = 1; + ctx.strokeStyle = brush.color; + ctx.stroke(); ctx.beginPath(); ctx.moveTo(size/2, 0); ctx.lineTo(size/2, 10); @@ -79,9 +91,6 @@ define([ ctx.strokeStyle = '#000000'; ctx.stroke(); - //context.lineWidth = w/2; - //context.strokeStyle = '#000000'; - //context.stroke(); var img = ccanvas.toDataURL("image/png"); var $img = $('', { @@ -102,6 +111,17 @@ define([ $width.on('change', updateBrushWidth); + var updateBrushOpacity = function () { + var val = $opacity.val(); + brush.opacity = Number(val); + canvas.freeDrawingBrush.color = Colors.hex2rgba(brush.color, brush.opacity); + $opacityLabel.text(val); + createCursor(); + }; + updateBrushOpacity(); + + $opacity.on('change', updateBrushOpacity); + var pickColor = function (current, cb) { var $picker = $('', { type: 'color', @@ -120,21 +140,15 @@ define([ }; var setColor = function (c) { - canvas.freeDrawingBrush.color = c; + c = Colors.rgb2hex(c); + brush.color = c; + canvas.freeDrawingBrush.color = Colors.hex2rgba(brush.color, brush.opacity); module.$color.css({ 'color': c, }); createCursor(); }; - var rgb2hex = function (rgb) { - if (rgb.indexOf('#') === 0) { return rgb; } - rgb = rgb.match(/^rgb\((\d+),\s*(\d+),\s*(\d+)\)$/); - var hex = function (x) { - return ("0" + parseInt(x).toString(16)).slice(-2); - }; - return "#" + hex(rgb[1]) + hex(rgb[2]) + hex(rgb[3]); - }; var palette = AppConfig.whiteboardPalette || [ 'red', 'blue', 'green', 'white', 'black', 'purple', @@ -151,9 +165,29 @@ define([ module.draw = !module.draw; canvas.isDrawingMode = module.draw; $toggle.text(module.draw ? Messages.canvas_disable : Messages.canvas_enable); + if (module.draw) { $deleteButton.hide(); } + else { $deleteButton.show(); } }; $toggle.click(toggleDrawMode); + var deleteSelection = function () { + if (canvas.getActiveObject()) { + canvas.getActiveObject().remove(); + } + if (canvas.getActiveGroup()) { + canvas.getActiveGroup()._objects.forEach(function (el) { + el.remove(); + }); + canvas.discardActiveGroup(); + } + canvas.renderAll(); + onLocal(); + }; + $deleteButton.click(deleteSelection); + $(window).on('keyup', function (e) { + if (e.which === 46) { deleteSelection (); } + }); + var setEditable = function (bool) { if (readOnly && bool) { return; } if (bool) { $controls.show(); } @@ -233,12 +267,12 @@ define([ 'background-color': color, }) .click(function () { - var c = rgb2hex($color.css('background-color')); + var c = Colors.rgb2hex($color.css('background-color')); setColor(c); }) .on('dblclick', function (e) { e.preventDefault(); - pickColor(rgb2hex($color.css('background-color')), function (c) { + pickColor(Colors.rgb2hex($color.css('background-color')), function (c) { $color.css({ 'background-color': c, }); @@ -327,6 +361,17 @@ define([ var $rightside = $bar.find('.' + Toolbar.constants.rightside); module.$userNameButton = $($bar.find('.' + Toolbar.constants.changeUsername)); + /* save as template */ + if (!Cryptpad.isTemplate(window.location.href)) { + var templateObj = { + rt: info.realtime, + Crypt: Cryptget, + getTitle: function () { return document.title; } + }; + var $templateButton = Cryptpad.createButton('template', true, templateObj); + $rightside.append($templateButton); + } + var $export = Cryptpad.createButton('export', true, {}, saveImage); $rightside.append($export); @@ -498,6 +543,10 @@ define([ realtime: realtime }); + var isNew = false; + var userDoc = module.realtime.getUserDoc(); + if (userDoc === "" || userDoc === "{}") { isNew = true; } + Cryptpad.removeLoadingScreen(); setEditable(true); initializing = false; @@ -528,6 +577,9 @@ define([ onLocal(); module.$userNameButton.click(); } + if (isNew) { + Cryptpad.selectTemplate('whiteboard', info.realtime, Cryptget); + } }); }; diff --git a/www/whiteboard/whiteboard.css b/www/whiteboard/whiteboard.css index 5fe1b6841..a0619360b 100644 --- a/www/whiteboard/whiteboard.css +++ b/www/whiteboard/whiteboard.css @@ -33,11 +33,13 @@ body { line-height: 100px; padding-bottom: 5px; } -#controls #width { +#controls #width, +#controls #opacity { position: relative; vertical-align: middle; } #controls #clear, +#controls #delete, #controls #toggleDraw { display: inline; vertical-align: middle; diff --git a/www/whiteboard/whiteboard.less b/www/whiteboard/whiteboard.less index 75c979456..81c7e0bfe 100644 --- a/www/whiteboard/whiteboard.less +++ b/www/whiteboard/whiteboard.less @@ -42,10 +42,10 @@ body { line-height: 100px; padding-bottom: 5px; - #width { + #width, #opacity { .middle; } - #clear, #toggleDraw { + #clear, #delete, #toggleDraw { display: inline; vertical-align: middle; }