diff --git a/docs/docs/configuration/server.rst b/docs/docs/configuration/server.rst
index cb39ccd03..df70bde5b 100644
--- a/docs/docs/configuration/server.rst
+++ b/docs/docs/configuration/server.rst
@@ -308,6 +308,30 @@ algorithm
Arguments have to be in that order, but can be reduced to `pbkdf2:4096`
for example to override the iterations only.
+User
+----
+
+Give yourself, your friends and/or your contributors lightweight accounts. These can be used
+to later stylize your comments through CSS and distinguish them from the from anonymous commenters.
+
+.. code-block:: ini
+
+ [user]
+ accounts =
+ Administrator,hunter9
+ John Smith,passw0rd
+
+accounts
+ List of protected accounts. Each account is a name / password pair.
+ If a commenter enters a protected account name, they will be required to enter
+ the corresponding password in order to post their comment.
+ The password field will be offered in place of email.
+
+ The "sluggified" user names will then be added as CSS classses on the comments.
+ For the above example, classes will be: `isso-known-user isso-user-administrator`
+ and `isso-known-user isso-user-john_smith`.
+
+
Appendum
--------
diff --git a/isso/css/isso.css b/isso/css/isso.css
index b0ed6d1e4..de2978ef9 100644
--- a/isso/css/isso.css
+++ b/isso/css/isso.css
@@ -18,6 +18,8 @@
#isso-thread .textarea {
min-height: 58px;
outline: 0;
+ -webkit-transition: border-color 0.3s, color 0.3s;
+ transition: border-color 0.3s, color 0.3s;
}
#isso-thread .textarea.placeholder {
color: #AAA;
@@ -184,6 +186,8 @@
line-height: 1.4em;
border: 1px solid rgba(0, 0, 0, 0.2);
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
+ -webkit-transition: border-color 0.3s, color 0.3s;
+ transition: border-color 0.3s, color 0.3s;
}
.isso-postbox > .form-wrapper > .auth-section .post-action {
display: inline-block;
@@ -206,6 +210,20 @@
.isso-postbox > .form-wrapper > .auth-section .post-action > input:active {
background-color: #BBB;
}
+.isso-postbox > .form-wrapper > .auth-section .input-wrapper-password {
+ display: none;
+}
+.isso-postbox.isso-postbox-password-mode > .form-wrapper > .auth-section .input-wrapper-password {
+ display: inline-block;
+}
+.isso-postbox.isso-postbox-password-mode > .form-wrapper > .auth-section .input-wrapper-email {
+ display: none;
+}
+.textarea.has-error,
+.isso-postbox > .form-wrapper > .auth-section input.has-error {
+ border-color: red!important;
+ color: red;
+}
@media screen and (max-width:600px) {
.isso-postbox > .form-wrapper > .auth-section .input-wrapper {
display: block;
diff --git a/isso/js/app/api.js b/isso/js/app/api.js
index d0fbf2f6f..d8cd0d77a 100644
--- a/isso/js/app/api.js
+++ b/isso/js/app/api.js
@@ -64,6 +64,7 @@ define(["app/lib/promise", "app/globals"], function(Q, globals) {
xhr.open(method, url, true);
xhr.withCredentials = true;
xhr.setRequestHeader("Content-Type", "application/json");
+ xhr.setRequestHeader("Accept", "application/json");
xhr.onreadystatechange = function () {
if (xhr.readyState === 4) {
@@ -71,7 +72,7 @@ define(["app/lib/promise", "app/globals"], function(Q, globals) {
}
};
} catch (exception) {
- (reject || console.log)(exception.message);
+ (reject || console.error)(exception.message);
}
xhr.send(data);
@@ -89,6 +90,19 @@ define(["app/lib/promise", "app/globals"], function(Q, globals) {
return rv.substring(0, rv.length - 1); // chop off trailing "&"
};
+ var info = function () {
+ var deferred = Q.defer();
+ curl("GET", endpoint + "/info", null,
+ function (rv) {
+ if (rv.status >= 200 && rv.status < 300) {
+ deferred.resolve(JSON.parse(rv.body));
+ } else {
+ deferred.reject({message: rv.body, status: rv.status});
+ }
+ });
+ return deferred.promise;
+ };
+
var create = function(tid, data) {
var deferred = Q.defer();
curl("POST", endpoint + "/new?" + qs({uri: tid || location}), JSON.stringify(data),
@@ -96,7 +110,7 @@ define(["app/lib/promise", "app/globals"], function(Q, globals) {
if (rv.status === 201 || rv.status === 202) {
deferred.resolve(JSON.parse(rv.body));
} else {
- deferred.reject(rv.body);
+ deferred.reject({message: rv.body, status: rv.status});
}
});
return deferred.promise;
@@ -110,7 +124,7 @@ define(["app/lib/promise", "app/globals"], function(Q, globals) {
} else if (rv.status === 200) {
deferred.resolve(JSON.parse(rv.body));
} else {
- deferred.reject(rv.body);
+ deferred.reject({message: rv.body, status: rv.status});
}
});
return deferred.promise;
@@ -124,7 +138,7 @@ define(["app/lib/promise", "app/globals"], function(Q, globals) {
} else if (rv.status === 200) {
deferred.resolve(JSON.parse(rv.body) === null);
} else {
- deferred.reject(rv.body);
+ deferred.reject({message: rv.body, status: rv.status});
}
});
return deferred.promise;
@@ -159,7 +173,7 @@ define(["app/lib/promise", "app/globals"], function(Q, globals) {
} else if (rv.status === 404) {
deferred.resolve({total_replies: 0});
} else {
- deferred.reject(rv.body);
+ deferred.reject({message: rv.body, status: rv.status});
}
});
return deferred.promise;
@@ -171,7 +185,7 @@ define(["app/lib/promise", "app/globals"], function(Q, globals) {
if (rv.status === 200) {
deferred.resolve(JSON.parse(rv.body));
} else {
- deferred.reject(rv.body);
+ deferred.reject({message: rv.body, status: rv.status});
}
});
return deferred.promise;
@@ -195,6 +209,7 @@ define(["app/lib/promise", "app/globals"], function(Q, globals) {
endpoint: endpoint,
salt: salt,
+ info: info,
create: create,
modify: modify,
remove: remove,
diff --git a/isso/js/app/dom.js b/isso/js/app/dom.js
index 9a506097f..24fd5eed3 100644
--- a/isso/js/app/dom.js
+++ b/isso/js/app/dom.js
@@ -32,8 +32,16 @@ define(function() {
/**
* Shortcut for `Element.addEventListener`, prevents default event
* by default, set :param prevents: to `false` to change that behavior.
+ * You can also provide an array of types, to listen on multiple events
*/
this.on = function(type, listener, prevent) {
+ if (Array.isArray(type)) {
+ var that = this;
+ type.forEach(function (type) {
+ that.on(type, listener, prevent);
+ });
+ return;
+ }
node.addEventListener(type, function(event) {
listener(event);
if (prevent === undefined || prevent) {
diff --git a/isso/js/app/i18n/bg.js b/isso/js/app/i18n/bg.js
index 45ac24b86..215c9dc78 100644
--- a/isso/js/app/i18n/bg.js
+++ b/isso/js/app/i18n/bg.js
@@ -2,6 +2,7 @@ define({
"postbox-text": "Въведете коментара си тук (поне 3 знака)",
"postbox-author": "Име/псевдоним (незадължително)",
"postbox-email": "Ел. поща (незадължително)",
+ "postbox-password": "Парола",
"postbox-website": "Уебсайт (незадължително)",
"postbox-submit": "Публикуване",
"num-comments": "1 коментар\n{{ n }} коментара",
diff --git a/isso/js/app/i18n/cs.js b/isso/js/app/i18n/cs.js
index 77e640142..ef9010138 100644
--- a/isso/js/app/i18n/cs.js
+++ b/isso/js/app/i18n/cs.js
@@ -2,6 +2,7 @@ define({
"postbox-text": "Sem napiště svůj komentář (nejméně 3 znaky)",
"postbox-author": "Jméno (nepovinné)",
"postbox-email": "E-mail (nepovinný)",
+ "postbox-password": "Heslo",
"postbox-website": "Web (nepovinný)",
"postbox-submit": "Publikovat",
"num-comments": "Jeden komentář\n{{ n }} Komentářů",
diff --git a/isso/js/app/i18n/de.js b/isso/js/app/i18n/de.js
index 5ac0610d1..d85b68928 100644
--- a/isso/js/app/i18n/de.js
+++ b/isso/js/app/i18n/de.js
@@ -2,6 +2,7 @@ define({
"postbox-text": "Kommentar hier eintippen (mindestens 3 Zeichen)",
"postbox-author": "Name (optional)",
"postbox-email": "Email (optional)",
+ "postbox-password": "Passwort",
"postbox-website": "Website (optional)",
"postbox-submit": "Abschicken",
"num-comments": "1 Kommentar\n{{ n }} Kommentare",
diff --git a/isso/js/app/i18n/el_GR.js b/isso/js/app/i18n/el_GR.js
index 5155a2d5a..0384968fb 100644
--- a/isso/js/app/i18n/el_GR.js
+++ b/isso/js/app/i18n/el_GR.js
@@ -2,6 +2,7 @@ define({
"postbox-text": "Γράψτε το σχόλιο εδώ (τουλάχιστον 3 χαρακτήρες)",
"postbox-author": "Όνομα (προαιρετικό)",
"postbox-email": "E-mail (προαιρετικό)",
+ "postbox-password": "Κωδικός πρόσβασης",
"postbox-website": "Ιστοσελίδα (προαιρετικό)",
"postbox-submit": "Υποβολή",
"num-comments": "Ένα σχόλιο\n{{ n }} σχόλια",
diff --git a/isso/js/app/i18n/en.js b/isso/js/app/i18n/en.js
index ec4b4d0f3..d3fbb67b7 100644
--- a/isso/js/app/i18n/en.js
+++ b/isso/js/app/i18n/en.js
@@ -2,6 +2,7 @@ define({
"postbox-text": "Type Comment Here (at least 3 chars)",
"postbox-author": "Name (optional)",
"postbox-email": "E-mail (optional)",
+ "postbox-password": "Password",
"postbox-website": "Website (optional)",
"postbox-submit": "Submit",
diff --git a/isso/js/app/i18n/eo.js b/isso/js/app/i18n/eo.js
index 76150f3a9..6ecfd5fe5 100644
--- a/isso/js/app/i18n/eo.js
+++ b/isso/js/app/i18n/eo.js
@@ -2,6 +2,7 @@ define({
"postbox-text": "Tajpu komenton ĉi-tie (almenaŭ 3 signoj)",
"postbox-author": "Nomo (malnepra)",
"postbox-email": "Retadreso (malnepra)",
+ "postbox-password": "Pasvorto",
"postbox-website": "Retejo (malnepra)",
"postbox-submit": "Sendu",
"num-comments": "{{ n }} komento\n{{ n }} komentoj",
diff --git a/isso/js/app/i18n/es.js b/isso/js/app/i18n/es.js
index c25d6cd68..4438d9cdc 100644
--- a/isso/js/app/i18n/es.js
+++ b/isso/js/app/i18n/es.js
@@ -2,6 +2,7 @@ define({
"postbox-text": "Escriba su comentario aquí (al menos 3 caracteres)",
"postbox-author": "Nombre (opcional)",
"postbox-email": "E-mail (opcional)",
+ "postbox-password": "Contraseña",
"postbox-website": "Sitio web (opcional)",
"postbox-submit": "Enviar",
"num-comments": "Un Comentario\n{{ n }} Comentarios",
diff --git a/isso/js/app/i18n/fr.js b/isso/js/app/i18n/fr.js
index e29d024e9..a9b952ce8 100644
--- a/isso/js/app/i18n/fr.js
+++ b/isso/js/app/i18n/fr.js
@@ -2,6 +2,7 @@ define({
"postbox-text": "Insérez votre commentaire ici (au moins 3 lettres)",
"postbox-author": "Nom (optionnel)",
"postbox-email": "Courriel (optionnel)",
+ "postbox-password": "Mot de passe",
"postbox-website": "Site web (optionnel)",
"postbox-submit": "Soumettre",
"num-comments": "{{ n }} commentaire\n{{ n }} commentaires",
diff --git a/isso/js/app/i18n/hr.js b/isso/js/app/i18n/hr.js
index 1ae645243..b4f10d7c1 100644
--- a/isso/js/app/i18n/hr.js
+++ b/isso/js/app/i18n/hr.js
@@ -2,6 +2,7 @@ define({
"postbox-text": "Napiši komentar ovdje (najmanje 3 znaka)",
"postbox-author": "Ime (neobavezno)",
"postbox-email": "E-mail (neobavezno)",
+ "postbox-password": "Lozinka",
"postbox-website": "Web stranica (neobavezno)",
"postbox-submit": "Pošalji",
"num-comments": "Jedan komentar\n{{ n }} komentara",
diff --git a/isso/js/app/i18n/it.js b/isso/js/app/i18n/it.js
index 31eeb2ca1..e3e4108b0 100644
--- a/isso/js/app/i18n/it.js
+++ b/isso/js/app/i18n/it.js
@@ -2,6 +2,7 @@ define({
"postbox-text": "Scrivi un commento qui (minimo 3 caratteri)",
"postbox-author": "Nome (opzionale)",
"postbox-email": "E-mail (opzionale)",
+ "postbox-password": "Parola d'ordine",
"postbox-website": "Sito web (opzionale)",
"postbox-submit": "Invia",
"num-comments": "Un Commento\n{{ n }} Commenti",
diff --git a/isso/js/app/i18n/nl.js b/isso/js/app/i18n/nl.js
index 04164b663..5943ab1cc 100644
--- a/isso/js/app/i18n/nl.js
+++ b/isso/js/app/i18n/nl.js
@@ -2,6 +2,7 @@ define({
"postbox-text": "Typ reactie hier (minstens 3 karakters)",
"postbox-author": "Naam (optioneel)",
"postbox-email": "E-mail (optioneel)",
+ "postbox-password": "Wachtwoord",
"postbox-website": "Website (optioneel)",
"postbox-submit": "Versturen",
"num-comments": "Één reactie\n{{ n }} reacties",
diff --git a/isso/js/app/i18n/pl.js b/isso/js/app/i18n/pl.js
index d9afe7db7..166722408 100644
--- a/isso/js/app/i18n/pl.js
+++ b/isso/js/app/i18n/pl.js
@@ -2,6 +2,7 @@ define({
"postbox-text": "Tutaj wpisz komentarz (co najmniej 3 znaki)",
"postbox-author": "Imię/nick (opcjonalnie)",
"postbox-email": "E-mail (opcjonalnie)",
+ "postbox-password": "Hasło",
"postbox-website": "Strona (opcjonalnie)",
"postbox-submit": "Wyślij",
"num-comments": "Jeden komentarz\n{{ n }} komentarzy",
diff --git a/isso/js/app/i18n/ru.js b/isso/js/app/i18n/ru.js
index a5af03e21..4dc00eaac 100644
--- a/isso/js/app/i18n/ru.js
+++ b/isso/js/app/i18n/ru.js
@@ -2,6 +2,7 @@ define({
"postbox-text": "Оставить комментарий (минимум 3 символа)",
"postbox-author": "Имя (необязательно)",
"postbox-email": "Email (необязательно)",
+ "postbox-password": "Пароль",
"postbox-website": "Сайт (необязательно)",
"postbox-submit": "Отправить",
"num-comments": "{{ n }} комментарий\n{{ n }} комментария\n{{ n }} комментариев",
diff --git a/isso/js/app/i18n/sv.js b/isso/js/app/i18n/sv.js
index cafbdda40..534574c75 100644
--- a/isso/js/app/i18n/sv.js
+++ b/isso/js/app/i18n/sv.js
@@ -2,6 +2,7 @@ define({
"postbox-text": "Skriv din kommentar här (minst 3 tecken)",
"postbox-author": "Namn (frivilligt)",
"postbox-email": "E-mail (frivilligt)",
+ "postbox-password": "Lösenord",
"postbox-website": "Hemsida (frivilligt)",
"postbox-submit": "Skicka",
"num-comments": "En kommentar\n{{ n }} kommentarer",
diff --git a/isso/js/app/i18n/vi.js b/isso/js/app/i18n/vi.js
index 72a30929a..5077088f5 100644
--- a/isso/js/app/i18n/vi.js
+++ b/isso/js/app/i18n/vi.js
@@ -2,6 +2,7 @@ define({
"postbox-text": "Nhập bình luận tại đây (tối thiểu 3 ký tự)",
"postbox-author": "Tên (tùy chọn)",
"postbox-email": "E-mail (tùy chọn)",
+ "postbox-password": "Mật khẩu",
"postbox-website": "Website (tùy chọn)",
"postbox-submit": "Gửi",
diff --git a/isso/js/app/i18n/zh_CN.js b/isso/js/app/i18n/zh_CN.js
index 70ae0817b..ab470476b 100644
--- a/isso/js/app/i18n/zh_CN.js
+++ b/isso/js/app/i18n/zh_CN.js
@@ -2,6 +2,7 @@ define({
"postbox-text": "在此输入评论(最少3个字符)",
"postbox-author": "名字(可选)",
"postbox-email": "E-mail(可选)",
+ "postbox-password": "密码",
"postbox-website": "网站(可选)",
"postbox-submit": "提交",
diff --git a/isso/js/app/i18n/zh_TW.js b/isso/js/app/i18n/zh_TW.js
index 20191da6b..f41d1b9ea 100644
--- a/isso/js/app/i18n/zh_TW.js
+++ b/isso/js/app/i18n/zh_TW.js
@@ -2,6 +2,7 @@ define({
"postbox-text": "在此輸入留言(至少3個字元)",
"postbox-author": "名稱(非必填)",
"postbox-email": "電子信箱(非必填)",
+ "postbox-password": "密碼",
"postbox-website": "個人網站(非必填)",
"postbox-submit": "送出",
diff --git a/isso/js/app/isso.js b/isso/js/app/isso.js
index 22841648f..f1f5780ad 100644
--- a/isso/js/app/isso.js
+++ b/isso/js/app/isso.js
@@ -5,89 +5,147 @@ define(["app/dom", "app/utils", "app/config", "app/api", "app/jade", "app/i18n",
"use strict";
- var Postbox = function(parent) {
+ var validateText = function(el, config) {
+ if (utils.text(el.innerHTML).length < 3 || el.classList.contains("placeholder")) {
+ el.classList.add('has-error');
+ el.focus();
+ return false;
+ }
+ return true;
+ };
+
+ var validateAuthor = function(el, config) {
+ if (config["require-author"] && el.value.length <= 0) {
+ el.classList.add('has-error');
+ el.focus();
+ return false;
+ }
+ return true;
+ };
+
+ var validateEmail = function(el, config) {
+ if ((config["require-email"] && el.value.length <= 0) || (el.value.length && el.value.indexOf("@") < 0)) {
+ el.classList.add('has-error');
+ el.focus();
+ return false;
+ }
+ return true;
+ };
+
+ var Postbox = function(server, parent) {
var localStorage = utils.localStorageImpl,
el = $.htmlify(jade.render("postbox", {
"author": JSON.parse(localStorage.getItem("author")),
+ "password": JSON.parse(localStorage.getItem("password")),
"email": JSON.parse(localStorage.getItem("email")),
"website": JSON.parse(localStorage.getItem("website"))
}));
+ var inputs = {
+ author: $("[name=author]", el),
+ email: $("[name=email]", el),
+ password: $("[name=password]", el),
+ website: $("[name=website]", el),
+ text: $(".textarea", el),
+ submit: $("[type=submit]", el)
+ };
+
+ inputs.author.on(['change', 'keyup'], update);
+ inputs.email.on(['change', 'keyup'], update);
+ inputs.password.on(['change', 'keyup'], update);
+ inputs.website.on(['change', 'keyup'], update);
+ inputs.text.on(['change', 'keyup'], update);
+
+ var passwordMode = false;
+
// callback on success (e.g. to toggle the reply button)
el.onsuccess = function() {};
- el.validate = function() {
- if (utils.text($(".textarea", this).innerHTML).length < 3 ||
- $(".textarea", this).classList.contains("placeholder"))
- {
- $(".textarea", this).focus();
- return false;
- }
- if (config["require-email"] &&
- $("[name='email']", this).value.length <= 0)
- {
- $("[name='email']", this).focus();
- return false;
- }
- if (config["require-author"] &&
- $("[name='author']", this).value.length <= 0)
- {
- $("[name='author']", this).focus();
- return false;
- }
- return true;
- };
-
// email is not optional if this config parameter is set
if (config["require-email"]) {
- $("[name='email']", el).placeholder =
- $("[name='email']", el).placeholder.replace(/ \(.*\)/, "");
+ inputs.email.placeholder = inputs.email.placeholder.replace(/ \(.*\)/, "");
}
// author is not optional if this config parameter is set
if (config["require-author"]) {
- $("[name='author']", el).placeholder =
- $("[name='author']", el).placeholder.replace(/ \(.*\)/, "");
+ inputs.author.placeholder = inputs.author.placeholder.replace(/ \(.*\)/, "");
}
// submit form, initialize optional fields with `null` and reset form.
// If replied to a comment, remove form completely.
- $("[type=submit]", el).on("click", function() {
- if (! el.validate()) {
+ inputs.submit.on("click", function() {
+ if (3 > Number(validateText(inputs.text, config)) +
+ Number(validateAuthor(inputs.author, config)) +
+ (passwordMode ? 1 : Number(validateEmail(inputs.email, config)))) {
return;
}
- var author = $("[name=author]", el).value || null,
- email = $("[name=email]", el).value || null,
- website = $("[name=website]", el).value || null;
+ var author = inputs.author.value || null,
+ email = inputs.email.value || null,
+ password = inputs.password.value || null,
+ website = inputs.website.value || null;
localStorage.setItem("author", JSON.stringify(author));
localStorage.setItem("email", JSON.stringify(email));
+ localStorage.setItem("password", JSON.stringify(password));
localStorage.setItem("website", JSON.stringify(website));
+ ['author', 'email', 'password', 'website', 'text'].forEach(function (key) {
+ inputs[key].classList.remove("has-error");
+ });
+
api.create($("#isso-thread").getAttribute("data-isso-id"), {
- author: author, email: email, website: website,
+ author: author, email: email, password: password, website: website,
text: utils.text($(".textarea", el).innerHTML),
parent: parent || null,
title: $("#isso-thread").getAttribute("data-title") || null
- }).then(function(comment) {
- $(".textarea", el).innerHTML = "";
- $(".textarea", el).blur();
- insert(comment, true);
-
- if (parent !== null) {
- el.onsuccess();
+ }).then(
+ function(comment) {
+ inputs.text.innerHTML = "";
+ inputs.text.blur();
+ insert(comment, server, true);
+
+ if (parent !== null) {
+ el.onsuccess();
+ }
+ },
+ function (err) {
+ if (err.status === 401) {
+ inputs.password.classList.add('has-error');
+ } else {
+ console.error(err.message);
+ }
}
- });
+ );
});
lib.editorify($(".textarea", el));
+ update();
+
return el;
+
+ function update(e) {
+ if (e) {
+ e.target.classList.remove("has-error");
+ }
+
+ if (!e || e.target.name === "author") {
+ var isKnownUser = server.users.indexOf(inputs.author.value) >= 0;
+ if (isKnownUser && !passwordMode) {
+ el.classList.add('isso-postbox-password-mode');
+ passwordMode = true;
+ }
+ else if (!isKnownUser && passwordMode) {
+ el.classList.remove('isso-postbox-password-mode');
+ passwordMode = false;
+ }
+ }
+ }
};
- var insert_loader = function(comment, lastcreated) {
+ var insert_loader = function(comment, server, lastcreated) {
var entrypoint;
if (comment.id === null) {
entrypoint = $("#isso-root");
@@ -113,23 +171,23 @@ define(["app/dom", "app/utils", "app/config", "app/api", "app/jade", "app/i18n",
var lastcreated = 0;
rv.replies.forEach(function(commentObject) {
- insert(commentObject, false);
+ insert(commentObject, server, false);
if(commentObject.created > lastcreated) {
lastcreated = commentObject.created;
}
});
if(rv.hidden_replies > 0) {
- insert_loader(rv, lastcreated);
+ insert_loader(rv, server, lastcreated);
}
},
function(err) {
- console.log(err);
+ console.error(err);
});
});
};
- var insert = function(comment, scrollIntoView) {
+ var insert = function(comment, server, scrollIntoView) {
var el = $.htmlify(jade.render("comment", {"comment": comment}));
// update datetime every 60 seconds
@@ -153,6 +211,11 @@ define(["app/dom", "app/utils", "app/config", "app/api", "app/jade", "app/i18n",
entrypoint = $("#isso-" + comment.parent + " > .text-wrapper > .isso-follow-up");
}
+ if (server.users && server.users.indexOf(comment.author) >= 0) {
+ el.classList.add("isso-known-user");
+ el.classList.add("isso-user-" + utils.slug(comment.author));
+ }
+
entrypoint.append(el);
if (scrollIntoView) {
@@ -166,7 +229,7 @@ define(["app/dom", "app/utils", "app/config", "app/api", "app/jade", "app/i18n",
var form = null; // XXX: probably a good place for a closure
$("a.reply", footer).toggle("click",
function(toggler) {
- form = footer.insertAfter(new Postbox(comment.parent === null ? comment.id : comment.parent));
+ form = footer.insertAfter(new Postbox(server, comment.parent === null ? comment.id : comment.parent));
form.onsuccess = function() { toggler.next(); };
$(".textarea", form).focus();
$("a.reply", footer).textContent = i18n.translate("comment-close");
@@ -241,16 +304,14 @@ define(["app/dom", "app/utils", "app/config", "app/api", "app/jade", "app/i18n",
var avatar = config["avatar"] ? $(".avatar", el, false)[0] : null;
if (! toggler.canceled && textarea !== null) {
- if (utils.text(textarea.innerHTML).length < 3) {
- textarea.focus();
+ if (!validateText(textarea, config)) {
toggler.wait();
return;
- } else {
- api.modify(comment.id, {"text": utils.text(textarea.innerHTML)}).then(function(rv) {
- text.innerHTML = rv.text;
- comment.text = rv.text;
- });
}
+ api.modify(comment.id, {"text": utils.text(textarea.innerHTML)}).then(function(rv) {
+ text.innerHTML = rv.text;
+ comment.text = rv.text;
+ });
} else {
text.innerHTML = comment.text;
}
@@ -325,14 +386,14 @@ define(["app/dom", "app/utils", "app/config", "app/api", "app/jade", "app/i18n",
if(comment.hasOwnProperty('replies')) {
var lastcreated = 0;
comment.replies.forEach(function(replyObject) {
- insert(replyObject, false);
+ insert(replyObject, server, false);
if(replyObject.created > lastcreated) {
lastcreated = replyObject.created;
}
});
if(comment.hidden_replies > 0) {
- insert_loader(comment, lastcreated);
+ insert_loader(comment, server, lastcreated);
}
}
diff --git a/isso/js/app/text/postbox.jade b/isso/js/app/text/postbox.jade
index 0a85ae188..0e8e8cc3e 100644
--- a/isso/js/app/text/postbox.jade
+++ b/isso/js/app/text/postbox.jade
@@ -4,14 +4,17 @@ div(class='isso-postbox')
div(class='textarea placeholder' contenteditable='true')
= i18n('postbox-text')
section(class='auth-section')
- p(class='input-wrapper')
- input(type='text' name='author' placeholder=i18n('postbox-author')
+ p(class='input-wrapper input-wrapper-author')
+ input(type='text' name='author' placeholder=i18n('postbox-author') title=i18n('postbox-author')
value=author !== null ? '#{author}' : '')
- p(class='input-wrapper')
- input(type='email' name='email' placeholder=i18n('postbox-email')
+ p(class='input-wrapper input-wrapper-email')
+ input(type='email' name='email' placeholder=i18n('postbox-email') title=i18n('postbox-email')
value=email != null ? '#{email}' : '')
- p(class='input-wrapper')
- input(type='text' name='website' placeholder=i18n('postbox-website')
+ p(class='input-wrapper input-wrapper-password')
+ input(type='password' name='password' placeholder=i18n('postbox-password') title=i18n('postbox-password')
+ value=password != null ? '#{password}' : '')
+ p(class='input-wrapper input-wrapper-website')
+ input(type='text' name='website' placeholder=i18n('postbox-website') title=i18n('postbox-website')
value=website != null ? '#{website}' : '')
p(class='post-action')
input(type='submit' value=i18n('postbox-submit'))
diff --git a/isso/js/app/utils.js b/isso/js/app/utils.js
index f971770ae..bd7b99d69 100644
--- a/isso/js/app/utils.js
+++ b/isso/js/app/utils.js
@@ -68,6 +68,10 @@ define(["app/i18n"], function(i18n) {
.replace(/\n/gi, '
');
};
+ var slug = function (str) {
+ return str.replace(/[^A-Za-z0-9_-]/g, '_').toLowerCase();
+ };
+
// Safari private browsing mode supports localStorage, but throws QUOTA_EXCEEDED_ERR
var localStorageImpl;
try {
@@ -94,6 +98,7 @@ define(["app/i18n"], function(i18n) {
cookie: cookie,
pad: pad,
ago: ago,
+ slug: slug,
text: text,
detext: detext,
localStorageImpl: localStorageImpl
diff --git a/isso/js/embed.js b/isso/js/embed.js
index 680880b7a..efe2ee40d 100644
--- a/isso/js/embed.js
+++ b/isso/js/embed.js
@@ -3,7 +3,7 @@
* Distributed under the MIT license
*/
-require(["app/lib/ready", "app/config", "app/i18n", "app/api", "app/isso", "app/count", "app/dom", "app/text/css", "app/text/svg", "app/jade"], function(domready, config, i18n, api, isso, count, $, css, svg, jade) {
+require(["app/lib/ready", "app/config", "app/i18n", "app/api", "app/isso", "app/count", "app/dom", "app/text/css", "app/text/svg", "app/jade", "app/lib/promise"], function(domready, config, i18n, api, isso, count, $, css, svg, jade, Q) {
"use strict";
@@ -27,41 +27,65 @@ require(["app/lib/ready", "app/config", "app/i18n", "app/api", "app/isso", "app/
return console.log("abort, #isso-thread is missing");
}
- $("#isso-thread").append($.new('h4'));
- $("#isso-thread").append(new isso.Postbox(null));
- $("#isso-thread").append('