diff --git a/customize.dist/translations/messages.fr.js b/customize.dist/translations/messages.fr.js index e719a44d9..24fff7a37 100644 --- a/customize.dist/translations/messages.fr.js +++ b/customize.dist/translations/messages.fr.js @@ -436,11 +436,10 @@ define(function () { ].join(''); out.codeInitialState = [ - '/*\n', - ' Voici l\'éditeur de code collaboratif et Zero Knowledge de CryptPad.\n', - ' Ce que vous tapez ici est chiffré de manière que seules les personnes avec le lien peuvent y accéder.\n', - ' Vous pouvez choisir le langage de programmation pour la coloration syntaxique, ainsi que le thème de couleurs, dans le coin supérieur droit.\n', - '*/' + '# Éditeur de code collaboratif et Zero Knowledge de CryptPad\n', + '\n', + '* Ce que vous tapez ici est chiffré de manière que seules les personnes avec le lien peuvent y accéder.\n', + '* Vous pouvez choisir le langage de programmation pour la coloration syntaxique, ainsi que le thème de couleurs, dans le coin supérieur droit.' ].join(''); out.slideInitialState = [ diff --git a/customize.dist/translations/messages.js b/customize.dist/translations/messages.js index 10efcb2df..c357cb557 100644 --- a/customize.dist/translations/messages.js +++ b/customize.dist/translations/messages.js @@ -450,11 +450,10 @@ define(function () { ].join(''); out.codeInitialState = [ - '/*\n', - ' This is the CryptPad Zero Knowledge collaborative code editor.\n', - ' What you type here is encrypted so only people who have the link can access it.\n', - ' You can choose the programming language to highlight and the UI color scheme in the upper right.\n', - '*/' + '# CryptPad\'s Zero Knowledge collaborative code editor\n', + '\n', + '* What you type here is encrypted so only people who have the link can access it.\n', + '* You can choose the programming language to highlight and the UI color scheme in the upper right.' ].join(''); out.slideInitialState = [ diff --git a/www/common/diffMarked.js b/www/common/diffMarked.js new file mode 100644 index 000000000..b3cc5fe1e --- /dev/null +++ b/www/common/diffMarked.js @@ -0,0 +1,109 @@ +define([ + 'jquery', + '/bower_components/marked/marked.min.js', + '/bower_components/diff-dom/diffDOM.js' +],function ($, Marked) { + var DiffMd = {} + + var DiffDOM = window.diffDOM; + var renderer = DiffMd.renderer = new Marked.Renderer(); + + Marked.setOptions({ + renderer: renderer + }); + + DiffMd.render = function (md) { + return Marked(md); + }; + + var forbiddenTags = [ + 'SCRIPT', + 'IFRAME', + 'OBJECT', + 'APPLET', + 'VIDEO', + 'AUDIO', + ]; + var unsafeTag = function (info) { + if (['addAttribute', 'modifyAttribute'].indexOf(info.diff.action) !== -1) { + if (/^on/.test(info.diff.name)) { + console.log("Rejecting forbidden element attribute with name", info.diff.name); + return true; + } + } + if (['addElement', 'replaceElement'].indexOf(info.diff.action) !== -1) { + var msg = "Rejecting forbidden tag of type (%s)"; + if (info.diff.element && forbiddenTags.indexOf(info.diff.element.nodeName) !== -1) { + console.log(msg, info.diff.element.nodeName); + return true; + } else if (info.diff.newValue && forbiddenTags.indexOf(info.diff.newValue.nodeName) !== -1) { + console.log("Replacing restricted element type (%s) with PRE", info.diff.newValue.nodeName); + info.diff.newValue.nodeName = 'PRE'; + } + } + }; + + var slice = function (coll) { + return Array.prototype.slice.call(coll); + }; + + /* remove listeners from the DOM */ + var removeListeners = function (root) { + slice(root.attributes).map(function (attr) { + if (/^on/.test(attr.name)) { + root.attributes.removeNamedItem(attr.name); + } + }); + // all the way down + slice(root.children).forEach(removeListeners); + }; + + var domFromHTML = function (html) { + var Dom = new DOMParser().parseFromString(html, "text/html"); + removeListeners(Dom.body); + return Dom; + }; + + var DD = new DiffDOM({ + preDiffApply: function (info) { + if (unsafeTag(info)) { return true; } + } + }); + + var makeDiff = function (A, B, id) { + var Err; + var Els = [A, B].map(function (frag) { + if (typeof(frag) === 'object') { + if (!frag || (frag && !frag.body)) { + Err = "No body"; + return; + } + var els = frag.body.querySelectorAll('#'+id); + if (els.length) { + return els[0]; + } + } + Err = 'No candidate found'; + }); + if (Err) { return Err; } + var patch = DD.diff(Els[0], Els[1]); + return patch; + }; + + var apply = DiffMd.apply = function (newHtml, $content) { + var id = $content.attr('id'); + if (!id) { throw new Error("The element must have a valid id"); } + var $div = $('
', {id: id}).append(newHtml); + var Dom = domFromHTML($('
').append($div).html()); + var oldDom = domFromHTML($content[0].outerHTML); + var patch = makeDiff(oldDom, Dom, id); + if (typeof(patch) === 'string') { + throw new Error(patch); + } else { + DD.apply($content[0], patch); + } + }; + + return DiffMd; +}); +