diff --git a/CHANGES.rst b/CHANGES.rst index dd7324d..bfd7cb3 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -7,12 +7,32 @@ Changelog for Isso - Nothing changed yet. -0.9.6 (unreleased) +0.9.7 (unreleased) ------------------ - Nothing changed yet. +0.9.6 (2014-08-18) +------------------ + +- remember name, email and website in localStorage, #119 + +- add option to hide voting feature, #115 + + data-isso-vote="true|false" + +- remove email field from JSON responses + + This is a quite serious issue. For the identicon, an expensive hash is used + to avoid the leakage of personal information like a real email address. A + `git blame` reveals, the email has been unintenionally exposed since the very + first release of Isso :-/ + + The testsuite now contains a dedicated test to prevent this error in the + future. + + 0.9.5 (2014-08-10) ------------------ diff --git a/docs/docs/configuration/client.rst b/docs/docs/configuration/client.rst index b67622f..9f465db 100644 --- a/docs/docs/configuration/client.rst +++ b/docs/docs/configuration/client.rst @@ -16,6 +16,7 @@ preferably in the script tag which embeds the JS: data-isso-avatar="true" data-isso-avatar-bg="#f0f0f0" data-isso-avatar-fg="#9abf88 #5698c4 #e279a3 #9163b6 ..." + data-isso-vote="true" src="/prefix/js/embed.js"> Furthermore you can override the automatic title detection inside @@ -88,6 +89,11 @@ scheme is based in `this color palette `_. Multiple colors must be separated by space. If you use less than eight colors and not a multiple of 2, the color distribution is not even. +data-isso-vote +-------------- + +Enable or disable voting feature on the client side. + data-isso-id ------------ diff --git a/isso/css/isso.css b/isso/css/isso.css index eef6b81..b0ed6d1 100644 --- a/isso/css/isso.css +++ b/isso/css/isso.css @@ -127,10 +127,11 @@ color: #111111 !important; text-shadow: #aaaaaa 0 0 1px !important; } -.isso-comment > div.text-wrapper > .isso-comment-footer a.reply, -.isso-comment > div.text-wrapper > .isso-comment-footer a.edit, -.isso-comment > div.text-wrapper > .isso-comment-footer a.cancel, -.isso-comment > div.text-wrapper > .isso-comment-footer a.delete { +.isso-comment > div.text-wrapper > .isso-comment-footer > a { + position: relative; + top: .2em; +} +.isso-comment > div.text-wrapper > .isso-comment-footer > a + a { padding-left: 1em; } .isso-comment > div.text-wrapper > .isso-comment-footer .votes { diff --git a/isso/js/app/config.js b/isso/js/app/config.js index 043cdb4..bae5b77 100644 --- a/isso/js/app/config.js +++ b/isso/js/app/config.js @@ -11,7 +11,8 @@ define(function() { "avatar": true, "avatar-bg": "#f0f0f0", "avatar-fg": ["#9abf88", "#5698c4", "#e279a3", "#9163b6", - "#be5168", "#f19670", "#e4bf80", "#447c69"].join(" ") + "#be5168", "#f19670", "#e4bf80", "#447c69"].join(" "), + "vote": true }; var js = document.getElementsByTagName("script"); diff --git a/isso/js/app/dom.js b/isso/js/app/dom.js index 364ece0..6338d1f 100644 --- a/isso/js/app/dom.js +++ b/isso/js/app/dom.js @@ -39,31 +39,31 @@ define(function() { }); }; - window.Element.prototype.toggle = function(type, on, off) { + window.Element.prototype.toggle = function(type, a, b) { /* Toggle between two internal states on event :param type: e.g. to - cycle form visibility. Callback :param on: is called on first event, - :param off: next time. + cycle form visibility. Callback :param a: is called on first event, + :param b: next time. You can skip to the next state without executing the callback with `toggler.next()`. You can prevent a cycle when you call `toggler.wait()` during an event. */ - function Toggle(el, on, off) { + function Toggle(el, a, b) { this.state = false; this.el = el; - this.on = on; - this.off = off; + this.a = a; + this.b = b; } Toggle.prototype.next = function next() { if (! this.state) { this.state = true; - this.on(this); + this.a(this); } else { this.state = false; - this.off(this); + this.b(this); } }; @@ -71,7 +71,7 @@ define(function() { this.state = ! this.state; }; - var toggler = new Toggle(this, on, off); + var toggler = new Toggle(this, a, b); this.on(type, function() { toggler.next(); }); diff --git a/isso/js/app/isso.js b/isso/js/app/isso.js index 168e3ea..ec97d63 100644 --- a/isso/js/app/isso.js +++ b/isso/js/app/isso.js @@ -7,7 +7,11 @@ define(["app/dom", "app/utils", "app/config", "app/api", "app/jade", "app/i18n", var Postbox = function(parent) { - var el = $.htmlify(jade.render("postbox")); + var el = $.htmlify(jade.render("postbox", { + "author": JSON.parse(localStorage.getItem("author")), + "email": JSON.parse(localStorage.getItem("email")), + "website": JSON.parse(localStorage.getItem("website")) + })); // callback on success (e.g. to toggle the reply button) el.onsuccess = function() {}; @@ -29,16 +33,19 @@ define(["app/dom", "app/utils", "app/config", "app/api", "app/jade", "app/i18n", return; } + var author = $("[name=author]", el).value || null, + email = $("[name=email]", el).value || null, + website = $("[name=website]", el).value || null; + + localStorage.setItem("author", JSON.stringify(author)); + localStorage.setItem("email", JSON.stringify(email)); + localStorage.setItem("website", JSON.stringify(website)); + api.create($("#isso-thread").getAttribute("data-isso-id"), { - author: $("[name=author]", el).value || null, - email: $("[name=email]", el).value || null, - website: $("[name=website]", el).value || null, + author: author, email: email, website: website, text: utils.text($(".textarea", el).innerHTML), parent: parent || null }).then(function(comment) { - $("[name=author]", el).value = ""; - $("[name=email]", el).value = ""; - $("[name=website]", el).value = ""; $(".textarea", el).innerHTML = ""; $(".textarea", el).blur(); insert(comment, true); @@ -144,31 +151,33 @@ define(["app/dom", "app/utils", "app/config", "app/api", "app/jade", "app/i18n", } ); - // update vote counter, but hide if votes sum to 0 - var votes = function(value) { - var span = $("span.votes", footer); - if (span === null && value !== 0) { - footer.prepend($.new("span.votes", value)); - } else { - if (value === 0) { - span.remove(); + if (config.vote) { + // update vote counter, but hide if votes sum to 0 + var votes = function (value) { + var span = $("span.votes", footer); + if (span === null && value !== 0) { + footer.prepend($.new("span.votes", value)); } else { - span.textContent = value; + if (value === 0) { + span.remove(); + } else { + span.textContent = value; + } } - } - }; + }; - $("a.upvote", footer).on("click", function() { - api.like(comment.id).then(function(rv) { - votes(rv.likes - rv.dislikes); + $("a.upvote", footer).on("click", function () { + api.like(comment.id).then(function (rv) { + votes(rv.likes - rv.dislikes); + }); }); - }); - $("a.downvote", footer).on("click", function() { - api.dislike(comment.id).then(function(rv) { - votes(rv.likes - rv.dislikes); + $("a.downvote", footer).on("click", function () { + api.dislike(comment.id).then(function (rv) { + votes(rv.likes - rv.dislikes); + }); }); - }); + } $("a.edit", footer).toggle("click", function(toggler) { diff --git a/isso/js/app/text/comment.jade b/isso/js/app/text/comment.jade index cbbb245..faa6618 100644 --- a/isso/js/app/text/comment.jade +++ b/isso/js/app/text/comment.jade @@ -23,13 +23,14 @@ div(class='isso-comment' id='isso-#{comment.id}') != comment.text div(class='isso-comment-footer') - if comment.likes - comment.dislikes != 0 - span(class='votes') #{comment.likes - comment.dislikes} - a(class='upvote' href='#') - i!= svg['arrow-up'] - span(class='spacer') | - a(class='downvote' href='#') - i!= svg['arrow-down'] + if conf.vote + if comment.likes - comment.dislikes != 0 + span(class='votes') #{comment.likes - comment.dislikes} + a(class='upvote' href='#') + != svg['arrow-up'] + span(class='spacer') | + a(class='downvote' href='#') + != svg['arrow-down'] a(class='reply' href='#') #{i18n('comment-reply')} a(class='edit' href='#') #{i18n('comment-edit')} a(class='delete' href='#') #{i18n('comment-delete')} diff --git a/isso/js/app/text/postbox.jade b/isso/js/app/text/postbox.jade index a2428de..0a85ae1 100644 --- a/isso/js/app/text/postbox.jade +++ b/isso/js/app/text/postbox.jade @@ -5,10 +5,13 @@ div(class='isso-postbox') = i18n('postbox-text') section(class='auth-section') p(class='input-wrapper') - input(type='text' name='author' placeholder=i18n('postbox-author')) + input(type='text' name='author' placeholder=i18n('postbox-author') + value=author !== null ? '#{author}' : '') p(class='input-wrapper') - input(type='email' name='email' placeholder=i18n('postbox-email')) + input(type='email' name='email' placeholder=i18n('postbox-email') + value=email != null ? '#{email}' : '') p(class='input-wrapper') - input(type='text' name='website' placeholder=i18n('postbox-website')) + input(type='text' name='website' placeholder=i18n('postbox-website') + value=website != null ? '#{website}' : '') p(class='post-action') input(type='submit' value=i18n('postbox-submit')) diff --git a/isso/views/comments.py b/isso/views/comments.py index c4a2058..0272fa3 100644 --- a/isso/views/comments.py +++ b/isso/views/comments.py @@ -71,7 +71,7 @@ def xhr(func): class API(object): - FIELDS = set(['id', 'parent', 'text', 'author', 'website', 'email', + FIELDS = set(['id', 'parent', 'text', 'author', 'website', 'mode', 'created', 'modified', 'likes', 'dislikes', 'hash']) # comment fields, that can be submitted