Merge branch 'remove-q-lib'

This commit is contained in:
Martin Zimmermann 2014-01-07 14:36:06 +01:00
commit dcd473967b
8 changed files with 149 additions and 86 deletions

View File

@ -39,7 +39,7 @@ Compile SCSS to CSS:
Install JS components: Install JS components:
~> cd isso/js ~> cd isso/js
~> bower install almond q requirejs requirejs-domready requirejs-text ~> bower install almond requirejs requirejs-domready requirejs-text
Integration Integration

View File

@ -30,7 +30,7 @@
</li> </li>
<li> <li>
<p><strong>client-side JavaScript</strong></p> <p><strong>client-side JavaScript</strong></p>
<p>Embed a single JS file, 54kb (18kb gzipped) and you are <p>Embed a single JS file, 52kb (16kb gzipped) and you are
done.</p> done.</p>
<p>Supports Firefox, Safari, Chrome and IE10.</p> <p>Supports Firefox, Safari, Chrome and IE10.</p>
</li> </li>

View File

@ -1,41 +1,14 @@
define(["q"], function(Q) { define(["app/lib/promise"], function(Q) {
"use strict"; "use strict";
Q.stopUnhandledRejectionTracking();
Q.longStackSupport = true;
var salt = "Eech7co8Ohloopo9Ol6baimi", var salt = "Eech7co8Ohloopo9Ol6baimi",
location = window.location.pathname; location = window.location.pathname;
var rules = {
"/": [200, 404],
"/new": [201, 202],
"/id/\\d+": [200, 403, 404],
"/id/\\d+/(like/dislike)": [200],
"/count": [200]
};
/*
* Detect Isso API endpoint. There are typically two use cases:
*
* 1. use minified, single-file JavaScript. The browser interprets
* scripts sequentially, thus we can safely use the last script
* tag. Then, we chop off some characters -- /js/embed.min.s --
* and we're done.
*
* If the script is not served by Isso directly, a custom data
* attribute can be used to override the default detection
* mechanism:
*
* .. code-block:: html
*
* <script data-isso="http://example.tld/path/" src="/.../embed.min.js"></script>
*/
var script, endpoint, var script, endpoint,
js = document.getElementsByTagName("script"); js = document.getElementsByTagName("script");
// prefer `data-isso="//host/api/endpoint"` if provided
for (var i = 0; i < js.length; i++) { for (var i = 0; i < js.length; i++) {
if (js[i].hasAttribute("data-isso")) { if (js[i].hasAttribute("data-isso")) {
endpoint = js[i].getAttribute("data-isso"); endpoint = js[i].getAttribute("data-isso");
@ -43,6 +16,7 @@ define(["q"], function(Q) {
} }
} }
// if no async-script is embedded, use the last script tag of `js`
if (! endpoint) { if (! endpoint) {
for (i = 0; i < js.length; i++) { for (i = 0; i < js.length; i++) {
if (js[i].getAttribute("async") || js[i].getAttribute("defer")) { if (js[i].getAttribute("async") || js[i].getAttribute("defer")) {
@ -61,24 +35,22 @@ define(["q"], function(Q) {
endpoint = endpoint.substring(0, endpoint.length - 1); endpoint = endpoint.substring(0, endpoint.length - 1);
} }
var curl = function(method, url, data) { var curl = function(method, url, data, resolve, reject) {
var xhr = new XMLHttpRequest(); var xhr = new XMLHttpRequest();
var response = Q.defer();
function onload() { function onload() {
var rule = url.replace(endpoint, "").split("?", 1)[0];
var cookie = xhr.getResponseHeader("X-Set-Cookie"); var cookie = xhr.getResponseHeader("X-Set-Cookie");
if (cookie && cookie.match(/^isso-/)) { if (cookie && cookie.match(/^isso-/)) {
document.cookie = cookie; document.cookie = cookie;
} }
if (rule in rules && rules[rule].indexOf(xhr.status) === -1) { if (xhr.status >= 500) {
response.reject(xhr.responseText); reject(xhr.body);
} else { } else {
response.resolve({status: xhr.status, body: xhr.responseText}); resolve({status: xhr.status, body: xhr.responseText});
} }
} }
@ -93,11 +65,10 @@ define(["q"], function(Q) {
} }
}; };
} catch (exception) { } catch (exception) {
response.reject(exception.message); (reject || console.log)(exception.message);
} }
xhr.send(data); xhr.send(data);
return response.promise;
}; };
var qs = function(params) { var qs = function(params) {
@ -112,70 +83,104 @@ define(["q"], function(Q) {
}; };
var create = function(tid, data) { var create = function(tid, data) {
return curl("POST", endpoint + "/new?" + qs({uri: tid || location}), JSON.stringify(data)).then( var deferred = Q.defer();
function (rv) { return JSON.parse(rv.body); }); curl("POST", endpoint + "/new?" + qs({uri: tid || location}), JSON.stringify(data),
function (rv) { deferred.resolve(JSON.parse(rv.body)); });
return deferred.promise;
}; };
var modify = function(id, data) { var modify = function(id, data) {
return curl("PUT", endpoint + "/id/" + id, JSON.stringify(data)).then( var deferred = Q.defer();
function (rv) { return JSON.parse(rv.body); }); curl("PUT", endpoint + "/id/" + id, JSON.stringify(data), function (rv) {
if (rv.status === 403) {
deferred.reject("Not authorized to modify this comment!");
} else if (rv.status === 200) {
deferred.resolve(JSON.parse(rv.body));
} else {
deferred.reject(rv.body);
}
});
return deferred.promise;
}; };
var remove = function(id) { var remove = function(id) {
return curl("DELETE", endpoint + "/id/" + id, null).then(function(rv) { var deferred = Q.defer();
curl("DELETE", endpoint + "/id/" + id, null, function(rv) {
if (rv.status === 403) { if (rv.status === 403) {
throw "Not authorized to remove this comment!"; deferred.reject("Not authorized to remove this comment!");
} else if (rv.status === 200) {
deferred.resolve(JSON.parse(rv.body) === null);
} else {
deferred.reject(rv.body);
} }
return JSON.parse(rv.body) === null;
}); });
return deferred.promise;
}; };
var view = function(id, plain) { var view = function(id, plain) {
return curl("GET", endpoint + "/id/" + id + "?" + qs({plain: plain}), null).then(function (rv) { var deferred = Q.defer();
return JSON.parse(rv.body); curl("GET", endpoint + "/id/" + id + "?" + qs({plain: plain}), null,
}); function(rv) { deferred.resolve(JSON.parse(rv.body)); });
return deferred.promise;
}; };
var fetch = function(tid) { var fetch = function(tid) {
var deferred = Q.defer();
return curl("GET", endpoint + "/?" + qs({uri: tid || location}), null).then(function (rv) { curl("GET", endpoint + "/?" + qs({uri: tid || location}), null, function(rv) {
if (rv.status === 200) { if (rv.status === 200) {
return JSON.parse(rv.body); deferred.resolve(JSON.parse(rv.body));
} else if (rv.status === 404) {
deferred.resolve([]);
} else { } else {
return []; deferred.reject(rv.body);
} }
}); });
return deferred.promise;
}; };
var count = function(tid) { var count = function(tid) {
return curl("GET", endpoint + "/count?" + qs({uri: tid || location}), null).then(function(rv) { var deferred = Q.defer();
return JSON.parse(rv.body); curl("GET", endpoint + "/count?" + qs({uri: tid || location}), null, function(rv) {
if (rv.status === 200) {
deferred.resolve(JSON.parse(rv.body));
} else if (rv.status === 404) {
deferred.resolve(0);
} else {
deferred.reject(rv.body);
}
}); });
return deferred.promise;
}; };
var like = function(id) { var like = function(id) {
return curl("POST", endpoint + "/id/" + id + "/like", null).then(function(rv) { var deferred = Q.defer();
return JSON.parse(rv.body); curl("POST", endpoint + "/id/" + id + "/like", null,
}); function(rv) { deferred.resolve(JSON.parse(rv.body)); });
return deferred.promise;
}; };
var dislike = function(id) { var dislike = function(id) {
return curl("POST", endpoint + "/id/" + id + "/dislike", null).then(function(rv) { var deferred = Q.defer();
return JSON.parse(rv.body); curl("POST", endpoint + "/id/" + id + "/dislike", null,
}); function(rv) { deferred.resolve(JSON.parse(rv.body)); });
return deferred.promise;
}; };
var remote_addr = function() { var remote_addr = function() {
return curl("GET", endpoint + "/check-ip", null).then(function(rv) { var deferred = Q.defer();
return rv.body; curl("GET", endpoint + "/check-ip", null, function(rv) {
if (rv.status === 200) {
deferred.resolve(rv.body);
} else {
deferred.reject(rv.body);
}
}); });
return deferred.promise;
}; };
return { return {
endpoint: endpoint, endpoint: endpoint,
salt: salt, salt: salt,
remote_addr: remote_addr, remote_addr: remote_addr,
create: create, create: create,

View File

@ -4,7 +4,7 @@
Inspired by http://codepen.io/gschier/pen/GLvAy Inspired by http://codepen.io/gschier/pen/GLvAy
*/ */
define(["q"], function(Q) { define(["app/lib/promise"], function(Q) {
"use strict"; "use strict";

View File

@ -1,4 +1,4 @@
define(["q", "app/lib/sha1"], function(Q, sha1) { define(["app/lib/promise", "app/lib/sha1"], function(Q, sha1) {
/* /*
* JavaScript implementation of Password-Based Key Derivation Function 2 * JavaScript implementation of Password-Based Key Derivation Function 2
* (PBKDF2) as defined in RFC 2898. * (PBKDF2) as defined in RFC 2898.
@ -191,10 +191,10 @@ define(["q", "app/lib/sha1"], function(Q, sha1) {
Q.when(text, function(text) { Q.when(text, function(text) {
var pbkdf2 = new PBKDF2(text, salt, iterations, size); var pbkdf2 = new PBKDF2(text, salt, iterations, size);
pbkdf2.deriveKey(function(bla) {}, function(rv) { pbkdf2.deriveKey(function() {}, function(rv) {
deferred.resolve(rv); deferred.resolve(rv);
}); });
}) });
return deferred.promise; return deferred.promise;
} }

View File

@ -0,0 +1,57 @@
define(function() {
"use strict";
var stderr = function(text) { console.log(text); };
var Promise = function() {
this.success = [];
this.errors = [];
};
Promise.prototype.then = function(onSuccess, onError) {
this.success.push(onSuccess);
if (onError) {
this.errors.push(onError);
} else {
this.errors.push(stderr);
}
};
var defer = function() {
this.promise = new Promise();
};
defer.prototype = {
promise: Promise,
resolve: function(rv) {
this.promise.success.forEach(function(callback) {
window.setTimeout(function() {
callback(rv);
}, 0);
});
},
reject: function(error) {
this.promise.errors.forEach(function(callback) {
window.setTimeout(function() {
callback(error);
}, 0);
});
}
};
var when = function(obj, func) {
if (obj instanceof Promise) {
return obj.then(func);
} else {
return func(obj);
}
};
return {
defer: function() { return new defer(); },
when: when
};
});

View File

@ -1,6 +1,5 @@
var requirejs = { var requirejs = {
paths: { paths: {
q: "components/q/q",
text : "components/requirejs-text/text", text : "components/requirejs-text/text",
ready: "components/requirejs-domready/domReady" ready: "components/requirejs-domready/domReady"
}, },

View File

@ -26,8 +26,8 @@ require(["ready", "app/config", "app/api", "app/isso", "app/count", "app/dom", "
$("#isso-thread").append(new isso.Postbox(null)); $("#isso-thread").append(new isso.Postbox(null));
$("#isso-thread").append('<div id="isso-root"></div>'); $("#isso-thread").append('<div id="isso-root"></div>');
api.fetch($("#isso-thread").getAttribute("data-isso-id")).then(function(rv) { api.fetch($("#isso-thread").getAttribute("data-isso-id")).then(
function(rv) {
if (! rv.length) { if (! rv.length) {
$("#isso-thread > h4").textContent = Mark.up("{{ i18n-no-comments }}"); $("#isso-thread > h4").textContent = Mark.up("{{ i18n-no-comments }}");
return; return;
@ -37,12 +37,14 @@ require(["ready", "app/config", "app/api", "app/isso", "app/count", "app/dom", "
for (var i=0; i < rv.length; i++) { for (var i=0; i < rv.length; i++) {
isso.insert(rv[i], false); isso.insert(rv[i], false);
} }
}).fail(function(err) {
console.log(err);
}).done(function() {
if (window.location.hash.length > 0) { if (window.location.hash.length > 0) {
$(window.location.hash).scrollIntoView(); $(window.location.hash).scrollIntoView();
} }
}); },
function(err) {
console.log(err);
}
);
}); });
}); });