diff --git a/isso/__init__.py b/isso/__init__.py index 9fac5c3..12b3d44 100644 --- a/isso/__init__.py +++ b/isso/__init__.py @@ -155,7 +155,8 @@ def main(): sys.exit(0) app = SharedDataMiddleware(isso.wsgi_app, { - '/static': join(dirname(__file__), 'static/') + '/static': join(dirname(__file__), 'static/'), + '/client': join(dirname(__file__), 'client/') }) run_simple(conf.get('server', 'host'), conf.getint('server', 'port'), diff --git a/isso/client/app/api.js b/isso/client/app/api.js new file mode 100644 index 0000000..5914504 --- /dev/null +++ b/isso/client/app/api.js @@ -0,0 +1,111 @@ +/* + * Copyright 2013, Martin Zimmermann . All rights reserved. + * License: BSD Style, 2 clauses. See isso/__init__.py. + */ + +define(["lib/q", "app/models"], function(Q, models) { + + // http://stackoverflow.com/questions/17544965/unhandled-rejection-reasons-should-be-empty + Q.stopUnhandledRejectionTracking(); + Q.longStackSupport = true; + + var endpoint = null, + location = window.location.pathname; + + // guess Isso API location + var js = document.getElementsByTagName("script"); + for (var i = 0; i < js.length; i++) { + if (js[i].src.match("/client/require\\.js$")) { + endpoint = js[i].src.substring(0, js[i].src.length - 18); + break; + } + + throw "no Isso API location found"; + } + + var curl = function(method, url, data) { + + var request = new XMLHttpRequest(); + var response = Q.defer(); + + function onload() { + response.resolve({status: request.status, body: request.responseText}); + } + + try { + request.open(method, url, true); + request.overrideMimeType("application/javascript"); + + request.onreadystatechange = function () { + if (request.readyState === 4) { + onload(); + } + }; + } catch (exception) { + response.reject(exception.message); + } + + request.send(data); + return response.promise; + }; + + var qs = function(params) { + rv = ""; + for (var key in params) { + if (params.hasOwnProperty(key)) { + rv += key + "=" + encodeURIComponent(params[key]) + "&"; + } + } + + return rv.substring(0, rv.length - 1) // chop off trailing "&" + } + + var create = function(data) { + + return curl("POST", endpoint + "/new?" + qs({uri: location}), JSON.stringify(data)) + .then(function (rv) { + if (rv.status == 201 || rv.status == 202) { + return JSON.parse(rv.body); + } else { + msg = rv.body.match("

(.+)

") + throw {status: rv.status, reason: (msg && msg[1]) || rv.body} + } + }) + } + + var modify = function(data) { + // ... + } + + var remove = function(id) { + return curl("DELETE", endpoint + "/?" + qs({uri: location, id: id}), null) + .then(function(rv) { + if (rv.status == 200) { + return rv; + } else { + throw {status: rv.status, reason: rv.body} + } + }) + } + + var fetchall = function() { + + return curl("GET", endpoint + "/?" + qs({uri: location}), null) + .then(function (rv) { + if (rv.status == 200) { + return JSON.parse(rv.body) + } else { + msg = rv.body.match("

(.+)

") + throw {status: rv.status, reason: (msg && msg[1]) || rv.body} + } + }) + } + + return { + endpoint: endpoint, + create: create, + remove: remove, + fetchall: fetchall + } + +}); \ No newline at end of file diff --git a/isso/client/app/forms.js b/isso/client/app/forms.js new file mode 100644 index 0000000..4330cc7 --- /dev/null +++ b/isso/client/app/forms.js @@ -0,0 +1,54 @@ +define(["lib/HTML", "./logging"], function(HTML, logging) { + + var msgbox = function(defaults) { + + var form = document.createElement("div") + form.className = "isso-comment-box" + HTML.ify(form); + + var optional = form.add("ul.optional"); + optional.add("li>input[type=text name=author placeholder=Name ]").value = defaults.author || ""; + optional.add("li>input[type=email name=email placeholder=Email]").value = defaults.email || ""; + optional.add("li>input[type=url name=website placeholder=Website]").value = defaults.website || ""; + + var textarea = form.add("div>textarea[rows=2 name=text]"); + textarea.value = defaults.text || ""; + textarea.placeholder = "Kommentar hier eintippen (andere Felder sind optional)" + textarea.onfocus = function() { + textarea.rows = 10 + }; + textarea.onblur = function() { setTimeout(function() { + if (textarea.value == "" && document.activeElement != textarea) { + textarea.rows = 2 + }}, 500)}; + + form.add("input[type=submit]").value = "Kommentar hinzufügen"; + form.add("span"); + return form; + + } + + var validate = function(msgbox) { + if (msgbox.query("textarea").value.length < 3) { + msgbox.query("textarea").focus(); + msgbox.span.className = "isso-popup" + msgbox.span.innerHTML = "Dein Kommentar sollte schon etwas länger sein."; + msgbox.span.addEventListener("click", function(event) { + msgbox.span.className = ""; + msgbox.span.innerHTML = ""; + }) + setTimeout(function() { + msgbox.span.className = "" + msgbox.span.innerHTML = "" + }, 5000 ) + return false; + } + + return true; + } + + return { + msgbox: msgbox, + validate: validate + } +}); \ No newline at end of file diff --git a/isso/client/app/isso.js b/isso/client/app/isso.js new file mode 100644 index 0000000..cbb3e8f --- /dev/null +++ b/isso/client/app/isso.js @@ -0,0 +1,202 @@ +/* Isso – Ich schrei sonst! + * + * Copyright 2013, Martin Zimmermann . All rights reserved. + * License: BSD Style, 2 clauses. See isso/__init__.py. + */ + + +define(["lib/q", "lib/HTML", "helper/utils", "./api", "./forms", "./logging"], function(Q, HTML, utils, api, forms, logging) { + + var defaults = { + text: "Lorem ipsum ...", author: "Anonymous", + email: "info@example.org", website: "..." + }; + + var insert = function(comment) { + /* + * insert a comment (JSON/object) into the #isso-thread or below a parent (#isso-N), renders some HTML and + * registers events to reply to, edit and remove a comment. + */ + + if (comment.parent) { + entrypoint = HTML.query("#isso-" + comment.parent).add("div.isso-follow-up"); + } else { + entrypoint = HTML.query("div#isso-root") + } + + entrypoint.add("article.isso-comment#isso-" + comment.id) + .add("header+span.avatar+div.text+footer") + var node = HTML.query("#isso-" + comment.id), + date = new Date(parseInt(comment.created) * 1000); + + if (comment.mode == 2) { + node.header.add("span.note").textContent = 'Kommentar muss noch freigeschaltet werden'; + } else if (comment.mode == 4) { // deleted + node.classList.add('deleted'); + node.header.add("span.note").textContent = "Kommentar gelöscht." + } + + if (comment.website) { + var el = node.header.add("a.author") + el.textContent= comment.author || 'Anonymous'; + el.href = comment.website; + el.rel = "nofollow" + } else { + node.header.add("span.author").innerHTML = comment.author || 'Anonymous'; + } + + node.header.add("span.spacer").textContent = "•"; + + var permalink = node.header.add("a.permalink"); + permalink.href = '#isso-' + comment.id; + permalink.add("date[datetime=" + date.getUTCFullYear() + "-" + date.getUTCMonth() + "-" + date.getUTCDay() + "]") + .textContent = utils.ago(date); + + node.query("span.avatar").add("img[width=48 height=48]"); + + if (comment.mode == 4) { + node.query(".text").add("p").value = " " + } else { + node.query(".text").innerHTML = comment.text; + } + + node.footer.add("a.liek{Liek}").href = "#"; + node.footer.add("a.reply{Antworten}").href = "#"; + + if (utils.read(window.location.pathname + "-" + comment.id)) { + node.footer.add("a.delete{Löschen}").href = "#"; + node.footer.add("a.edit{Bearbeiten}").href = "#"; + + var delbtn = node.query("a.delete"), + editbtn = node.query("a.edit"); + + delbtn.addEventListener("click", function(event) { + if (delbtn.textContent == "Bestätigen") { + api.remove(comment.id).then(function(rv) { + console.log(rv); + }) + } else { + delbtn.textContent = "Bestätigen" + setTimeout(function() {delbtn.textContent = "Löschen"}, 1500) + } + event.preventDefault(); + }) + } + +// if (read(path + '-' + post['id'])) { +// $('#isso_' + post['id'] + '> footer > a:first-child') +// .after(brew(['a', {'class': 'delete', 'href': '#'}, 'Löschen'])) +// .after(brew(['a', {'class': 'edit', 'href': '#'}, 'Bearbeiten'])); +// +// // DELETE +// $('#isso_' + post['id'] + ' > footer .delete').on('click', function(event) { +// isso.remove(post['id'], function(status, rv) { +// // XXX comment might not actually deleted +// $('#isso_' + post['id']).remove(); +// }); +// event.stop(); +// }); +// +// // EDIT +// $('#isso_' + post['id'] + ' > footer .edit').on('click', function(event) { +// +// if ($('#issoform_' + post['id']).length == 0) { // HTML form not shown +// isso.plain(post['id'], function(status, rv) { +// if (status != 200) return alert('Mööp'); +// var rv = form(post['id'], JSON.parse(rv), function(form, id) { +// isso.modify(id, extract(form, post['parent']), function(status, rv) { +// if (status != 200) return alert('Mööp'); +// +// $('#issoform_' + post['id']).remove(); +// $('#isso_' + post['id']).remove(); +// insert(JSON.parse(rv)); +// }); +// }); +// +// $('#isso_' + post['id']).after(rv); +// $('input[type="submit"]', rv)[0].value = 'Bestätigen.'; +// }); +// } else { +// $('#issoform_' + post['id']).remove(); +// }; +// event.stop(); +// }); +// }; + + // ability to answer directly to a comment + HTML.query("#isso-" + comment.id + " a.reply").addEventListener("click", function(event) { + + // remove active form when clicked again or reply to another comment + var active = HTML.query(".isso-active-msgbox"); // [] when empty, element if not + + if (! (active instanceof Array)) { + active.query("div.isso-comment-box").remove() + active.classList.remove("isso-active-msgbox"); + active.query("a.reply").textContent = "Antworten" + + if (active.id == "isso-" + comment.id) { + event.preventDefault(); + return; + } + } + + var msgbox = forms.msgbox({}) + HTML.query("#isso-" + comment.id).footer.appendChild(msgbox) + HTML.query("#isso-" + comment.id).classList.add("isso-active-msgbox"); + HTML.query("#isso-" + comment.id + " a.reply").textContent = "Schließen"; + + msgbox.query("input[type=submit]").addEventListener("click", function(event) { + forms.validate(msgbox) && api.create({ + author: msgbox.query("[name=author]").value, + email: msgbox.query("[name=email]").value, + website: msgbox.query("[name=website]").value, + text: msgbox.query("textarea").value, + parent: comment.id }) + .then(function(rv) { + // remove box on submit + msgbox.parentNode.parentNode.classList.remove("isso-active-msgbox"); + msgbox.parentNode.parentNode.query("a.reply").textContent = "Antworten" + msgbox.remove() + insert(rv); + }) + event.preventDefault() + }); + event.preventDefault(); + }); + } + + var init = function() { + + console.log(utils.heading()); + +// return; + + var rootmsgbox = forms.msgbox({}); + HTML.query("#isso-thread").add("div#isso-root").add(rootmsgbox); + rootmsgbox.query("input[type=submit]").addEventListener("click", function(event) { + forms.validate(rootmsgbox) && api.create({ + author: rootmsgbox.query("[name=author]").value, + email: rootmsgbox.query("[name=email]").value, + website: rootmsgbox.query("[name=website]").value, + text: rootmsgbox.query("textarea").value, + parent: null }) + .then(function(rv) { + // remove box on submit + rootmsgbox.remove() + insert(rv); + }) + event.preventDefault() + }); + + api.fetchall() + .then(function(comments) { + for (var i in comments) { + insert(comments[i]) + }}) + .fail(logging.error) + } + + return { + init: init + } +}); \ No newline at end of file diff --git a/isso/client/app/logging.js b/isso/client/app/logging.js new file mode 100644 index 0000000..ff7e8cb --- /dev/null +++ b/isso/client/app/logging.js @@ -0,0 +1,9 @@ +define({ + error: function(err) { + if ("status" in err && "reason" in err) { + console.error("%i: %s", err.status, err.reason) + } else { + console.error(err.stack) + } + } +}) \ No newline at end of file diff --git a/isso/client/app/models.js b/isso/client/app/models.js new file mode 100644 index 0000000..e587d17 --- /dev/null +++ b/isso/client/app/models.js @@ -0,0 +1,10 @@ +define(function() { + + function Comment(data) { + this.text = data["text"]; + } + + return { + Comment: Comment + } +}); \ No newline at end of file diff --git a/isso/client/embed.js b/isso/client/embed.js new file mode 100644 index 0000000..0935925 --- /dev/null +++ b/isso/client/embed.js @@ -0,0 +1,5 @@ +require(["lib/ready", "app/isso"], function(domready, isso) { + domready(function() { + isso.init(); + }) +}); diff --git a/isso/client/helper/utils.js b/isso/client/helper/utils.js new file mode 100644 index 0000000..569a537 --- /dev/null +++ b/isso/client/helper/utils.js @@ -0,0 +1,81 @@ +/* Copyright 2013, Martin Zimmermann . All rights reserved. + * License: BSD Style, 2 clauses. See isso/__init__.py. + * + * utility functions + */ + +define({ + + // return `cookie` string if set + read: function(cookie) { + return (document.cookie.match('(^|; )' + cookie + '=([^;]*)') || 0)[2] + }, + + ago: function(date) { + /*! + * JavaScript Pretty Date + * Copyright (c) 2011 John Resig (ejohn.org) + * Licensed under the MIT and GPL licenses. + */ + var diff = (((new Date()).getTime() - date.getTime()) / 1000), + day_diff = Math.floor(diff / 86400); + + if (isNaN(day_diff) || day_diff < 0 || day_diff >= 31) + return; + + return day_diff == 0 && ( + diff < 60 && "just now" || + diff < 120 && "1 minute ago" || + diff < 3600 && "vor " + Math.floor(diff / 60) + " Minuten" || + diff < 7200 && "vor einer Stunde" || + diff < 86400 && "vor " + Math.floor(diff / 3600) + " Stunden") || + day_diff == 1 && "Gestern" || + day_diff < 7 && "vor " + day_diff + " Tagen" || + day_diff < 31 && "vor " + Math.ceil(day_diff / 7) + " Wochen"; + }, + + heading: function() { + /* + * return first level heading that is probably the + * blog title. If no h1 is found, "Untitled." is used. + */ + var el = document.getElementById("isso-thread"); + var visited = []; + + var recurse = function(node) { + for (var i = 0; i < node.childNodes.length; i++) { + var child = node.childNodes[i]; + + if (child.nodeType != child.ELEMENT_NODE) { + continue; + } + + if (child.nodeName == "H1") { + return child; + } + + if (visited.indexOf(child) == -1) { + return recurse(child); + } + } + } + + while (true) { + + visited.push(el); + + if (el == document.documentElement) { + break + } + + var rv = recurse(el); + if (rv) { + return rv.textContent + } + + el = el.parentNode; + } + + return "Untitled." + } +}); \ No newline at end of file diff --git a/isso/client/isso.js b/isso/client/isso.js index b49ccc5..68d7812 100644 --- a/isso/client/isso.js +++ b/isso/client/isso.js @@ -1,41 +1,35 @@ /* Isso – Ich schrei sonst! * - * Copyright 2012, Martin Zimmermann . All rights reserved. + * Copyright 2013, Martin Zimmermann . All rights reserved. * License: BSD Style, 2 clauses. See isso/__init__.py. - * - * - * Code requires Bean, Bonzo, Qwery, domReady (all are part of jeesh) and - * reqwest. To ease integration with websites, all classes are prefixed - * with `isso`. */ // Uhm. Namespaces are one honking great idea, aren't they? -var isso = isso || {}, - prefix = "", - path = encodeURIComponent(window.location.pathname); - -// XXX -isso.prefix = prefix; -isso.path = path; +var isso = {}; -/* - * isso specific helpers to create, modify, remove and receive comments - */ +var init = function() { + var isso = new Object(); -function verify(data) { - return data['text'] == null ? false : true -}; + // guess Isso API location + var js = document.getElementsByTagName("script"); + for (var i = 0; i < js.length; i++) { + if (js[i].src.match("/client/require\\.js$")) { + isso.location = js[i].src.substring(0, 18); + break; + } + } + + console.log(isso.location) +} isso.create = function(data, func) { - if (!verify(data)) { - return; - } + var request = new XMLHttpRequest(); - $.ajax('POST', prefix + '/1.0/' + isso.path + '/new', - JSON.stringify(data), {'Content-Type': 'application/json'}).then(func); +// $.ajax('POST', prefix + '/1.0/' + isso.path + '/new', +// JSON.stringify(data), {'Content-Type': 'application/json'}).then(func); }; diff --git a/isso/client/lib/HTML.js b/isso/client/lib/HTML.js new file mode 100644 index 0000000..3814e62 --- /dev/null +++ b/isso/client/lib/HTML.js @@ -0,0 +1,4 @@ +/*! HTML - v0.10.2 - 2013-08-25 +* http://nbubna.github.io/HTML/ +* Copyright (c) 2013 ESHA Research; Licensed MIT, GPL */ +!function(a,b,c){"use strict";var d={version:"0.10.2",slice:Array.prototype.slice,list:function(a,b){return 1===a.length?d.node(a[0],b):((b||!a.each)&&(a.slice||(a=d.slice.call(a)),d.methods(a),a.length&&d.children(a[0],a)),a)},node:function(a,b){return(b||!a.each)&&(d.methods(a),d.children(a)),a},methods:function(a){for(var b in d.fn)d.define(a,b,d.fn[b])},children:function(a,b){for(var c=a._children={},e=0,f=a.childNodes.length;f>e;e++){var g=a.childNodes[e],h=d.key(g);(c[h]||(c[h]=[])).push(g),d.define(a,h),b&&d.define(b,h,void 0,a)}return c},key:function(a){return a.tagName?a.tagName.toLowerCase():"_other"},define:function(a,b,c,e){if(!(b in a))try{e=e||a,Object.defineProperty(a,b,void 0!==c?{value:c}:{get:function(){return e._children||d.children(e),d.list(e._children[b]||[])}})}catch(f){}},mutation:function(a){var b=a.target;delete b[b._internal?"_internal":"_children"]},unique:function(a,b,c){return c.indexOf(a)===b},fn:{each:function(a){var b,c,e=this.forEach?this:[this],f=[];"string"==typeof a&&(b=d.resolve[a]||a,c=d.slice.call(arguments,1),a=function(a,e){return d.resolve(b,a,c,e)});for(var g,h=0,i=e.length;i>h;h++)g=a.call(e,d.node(e[h]),h,e),(g||b&&void 0!==g)&&(g.forEach?f.push.apply(f,g):f.push(g));return f[0]||f[0]===!1?f[0].matches?d.list(f.filter(d.unique)):f:this},find:function(){try{a.console.warn("find() is deprecated. Please use query().")}finally{return this.query.apply(this,arguments)}},query:function(a){for(var b=this.forEach?this:[this],c=[],e=0,f=b.length;f>e;e++)for(var g=b[e].querySelectorAll(a),h=0,i=g.length;i>h;h++)c.push(g[h]);return d.list(c)},only:function(a,b){var c=this.forEach?this:[this];return d.list(a>=0||0>a?c.slice(a,b||a+1||void 0):c.filter("function"==typeof a?a:function(b){return b.matches(a)}))}},resolve:function(a,b,c,e){var f=a,g=b;if(c=c.length?d.fill(c,e,g):null,f.indexOf(".")>0){for(var h=f.split(".");h.length>1&&(g=g[f=h.shift()]););g=g||b,f=g?h[0]:a}var i=g[f];if(void 0!==i){if("function"==typeof i)return i.apply(g,c);if(!c)return i;g[f]=c[0]}else{if(!c)return b.getAttribute(a);null===c[0]?b.removeAttribute(a):b.setAttribute(a,c[0])}},fill:function(a,b,c){for(var d=[],e=0,f=a.length;f>e;e++){var g=a[e],h=typeof g;d[e]="string"===h?g.replace(/\$\{i\}/g,b):"function"===h?g(c,b,a):g}return d}},e=d.node(b.documentElement);e._=d,d.define(e,"ify",function(a,b){return!a||"length"in a?d.list(a||[],b):d.node(a,b)});var f=Element.prototype,g="atchesSelector";d.define(f,"matches",f.m||f["webkitM"+g]||f["mozM"+g]||f["msM"+g]),c?new c(function(a){a.forEach(d.mutation)}).observe(e,{childList:!0,subtree:!0}):b.addEventListener("DOMSubtreeModified",d.mutation),"function"==typeof define&&define.amd?define(function(){return e}):"undefined"!=typeof module&&module.exports?module.exports=e:a[e.getAttribute("data-html-reference")||"HTML"]=e,b.addEventListener("DOMContentLoaded",function(){d.node(e,!0)})}(window,document,window.MutationObserver),function(a,b){"use strict";var c=b.fn.add=function(a,b){return this.each(function(d){return c.all(d,a,b)})};c.all=function(a,b,d){if("string"==typeof b)return c.create(a,b,d);if("length"in b){for(var e=[],f=0,g=b.length;g>f;f++)e.push(c.all(a,b[f],d));return e}return c.insert(a,b,d),b},c.create=function(b,d,e){return c.insert(b,a.createElement(d),e)},c.insert=function(a,d,e){var f=c.find(a,e);return f?a.insertBefore(d,f):a.appendChild(d),b.updated(a),d},c.find=function(a,b){switch(typeof b){case"string":return a[b+"Child"];case"number":return a.children[b];case"object":return b;case"function":return b.call(a,a)}},b.updated=function(a){a._internal=!0,b.children(a)},b.fn.remove=function(a){return this.each(function(c){var d=c.parentNode;return d&&(d.removeChild(c),b.updated(d),a)?d:void 0})}}(document,document.documentElement._),function(a,b){"use strict";var c=b._,d=c.fn.event=function(){try{window.console.warn("event() is deprecated. https://github.com/nbubna/HTML/issues/1")}catch(a){}var b,e=c.slice.call(arguments),f=this,g=[];return e[0]?!e[1]||e[1].forEach?b="trigger":(b="on",1===e[0]&&(e[4]=e.shift()),(!e[2]||e[2].forEach)&&(e.splice(1,0,!1),e.splice(4,1)),e[3]=(e[3]||[]).slice(0),"string"==typeof e[2]&&(e[5]=e[2],e[3].unshift(e[2]),e[2]=c.fn.each)):(b="off",e.shift(),"function"==typeof e[1]&&e.splice(1,0,!1)),(e[0]||"").split(" ").forEach(function(a){e[0]=a,f.each(function(a){g.push(d[b].apply(a,e))})}),"trigger"===b?1===g.length?g[0]:g:this},e=Array.prototype.concat;d.on=function(a,b,e,f,g,h){var i=function(a){d.heard.call(this,a,b,e,f,g,h)};this.addEventListener(a,i),c.define(this,"_evt",[]),this._evt.push([a,b,h||e,i])},d.off=function(a,b,c){if(this._evt)for(var d=0;di;i++){var k=f[i];h=c.emmet[k.charAt(0)].call(h,k.substr(1),g)||h}return c.insert(b,g,e),h},c.emmetRE=function(){var a="\\"+Object.keys(c.emmet).join("|\\");return new RegExp("(?="+a+")","g")},c.emmet={"#":function(a){this.id=a},".":function(a){var b=this.getAttribute("class")||"";b=b+(b?" ":"")+a,this.setAttribute("class",b)},"[":function(a){a=a.substr(0,a.length-1).match(/(?:[^\s"]+|"[^"]*")+/g);for(var b=0,c=a.length;c>b;b++){var d=a[b].split("=");this.setAttribute(d[0],(d[1]||"").replace(/"/g,""))}},">":function(b){if(b){var c=a.createElement(b);return this.appendChild(c),c}return this},"+":function(a,b){return c.emmet[">"].call(this.parentNode||b,a)},"*":function(a){for(var b=this.parentNode,c=[this],d=1;a>d;d++)c.push(this.cloneNode(!0)),b.appendChild(c[d]);return c},"^":function(a,b){return c.emmet["+"].call(this.parentNode||b,a,b)},"{":function(b){this.appendChild(a.createTextNode(b.substr(0,b.length-1)))}}}(document,document.documentElement._); \ No newline at end of file diff --git a/isso/client/lib/q.js b/isso/client/lib/q.js new file mode 100644 index 0000000..fe96ca8 --- /dev/null +++ b/isso/client/lib/q.js @@ -0,0 +1,1937 @@ +// vim:ts=4:sts=4:sw=4: +/*! + * + * Copyright 2009-2012 Kris Kowal under the terms of the MIT + * license found at http://github.com/kriskowal/q/raw/master/LICENSE + * + * With parts by Tyler Close + * Copyright 2007-2009 Tyler Close under the terms of the MIT X license found + * at http://www.opensource.org/licenses/mit-license.html + * Forked at ref_send.js version: 2009-05-11 + * + * With parts by Mark Miller + * Copyright (C) 2011 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +(function (definition) { + // Turn off strict mode for this function so we can assign to global.Q + /* jshint strict: false */ + + // This file will function properly as a - - - - + + + + + + + + + + +
+ + {% block body %} + + {% endblock %} + + +
+ +
+
+

Isso – Ich schrei sonst!

+
+
+ +
+ +
+ + + + + + + diff --git a/isso/templates/base.mako b/isso/templates/base.mako deleted file mode 100644 index 1aff922..0000000 --- a/isso/templates/base.mako +++ /dev/null @@ -1,123 +0,0 @@ - - - <%block name="title" /> - - - - - - - ${self.body()} - \ No newline at end of file diff --git a/isso/templates/login.j2 b/isso/templates/login.j2 new file mode 100644 index 0000000..61d248c --- /dev/null +++ b/isso/templates/login.j2 @@ -0,0 +1,69 @@ + + + + + Sign in · Isso + + + + + + + + + + + + + + + +
+ + + +
+ + + diff --git a/isso/templates/login.mako b/isso/templates/login.mako deleted file mode 100644 index b18b130..0000000 --- a/isso/templates/login.mako +++ /dev/null @@ -1,38 +0,0 @@ -<%inherit file="base.mako"/> - -<%block name="title"> - Isso – Login - - -<%block name="style"> - - #login { - margin: 280px 270px 0 270px; - padding: 30px; - background-color: rgb(245, 245, 245); - box-shadow: 0px 0px 1px 0px; - text-align: center; - } - - .button { - border: 1px solid #006; - margin-left: 2px; - padding: 2px 4px 2px 4px; - } - - #login input { - margin-top: 8px; - text-align: center; - } - #login input:-moz-placeholder, #login input::-webkit-input-placeholder {} { - color: #CCC; - } - - - -
-
- - -
-
diff --git a/isso/views/comment.py b/isso/views/comment.py index 7050869..dbccc95 100644 --- a/isso/views/comment.py +++ b/isso/views/comment.py @@ -9,7 +9,7 @@ import urllib from itsdangerous import SignatureExpired, BadSignature from werkzeug.wrappers import Response -from werkzeug.exceptions import abort +from werkzeug.exceptions import abort, BadRequest from isso import models, utils @@ -24,12 +24,12 @@ class requires: def dec(app, env, req, *args, **kwargs): if self.param not in req.args: - abort(400) + raise BadRequest("missing %s query" % self.param) try: kwargs[self.param] = self.type(req.args[self.param]) except TypeError: - abort(400) + raise BadRequest("invalid type for %s, expected %s" % (self.param, self.type)) return func(app, env, req, *args, **kwargs) @@ -45,6 +45,7 @@ def create(app, environ, request, uri): try: comment = models.Comment.fromjson(request.data) except ValueError as e: + print(1) return Response(unicode(e), 400) for attr in 'author', 'email', 'website': @@ -52,11 +53,13 @@ def create(app, environ, request, uri): try: setattr(comment, attr, cgi.escape(getattr(comment, attr))) except AttributeError: + print(1) Response('', 400) try: rv = app.db.add(uri, comment) except ValueError: + print(1) abort(400) # FIXME: custom exception class, error descr md5 = rv.md5