Skip to content

Commit

Permalink
- Implemented promise pattern for async programming
Browse files Browse the repository at this point in the history
- Onload support for CSS
- Refactored template for better async loading using promises
  • Loading branch information
sebdeckers committed Oct 23, 2011
1 parent fc331e6 commit 9a29e59
Show file tree
Hide file tree
Showing 10 changed files with 277 additions and 100 deletions.
73 changes: 48 additions & 25 deletions core/css.js
Original file line number Diff line number Diff line change
@@ -1,35 +1,58 @@
define(function () {
var baseTheme = "themes/base/";
var stylesheets = {};
return {
load: function (file/*, callback*/) {
if (file.substr(file.length - 4) !== ".css") {
file += ".css";
}
if (!(file in stylesheets)) {
var link = document.createElement("link");
link.rel = "stylesheet";
link.type = "text/css";
/* Not supported in Gecko/Webkit
link.addEventListener("load", function (event) {
callback();
link.removeEventListener("load", this);
}, false);
*/
link.href = baseTheme + file;
stylesheets[file] = link;
document.getElementsByTagName("head")[0].appendChild(link);
define(["core/promise"], function (promise) {
var theme = "themes/base/",
extension = ".css",
stylesheets = {},
fixName = function (file) {
if (file.substr(file.length - extension.length) !== extension) {
file += extension;
}
return file;
},
unload: function (file) {
if (file.substr(file.length - 4) !== ".css") {
file += ".css";
}
load = function (file) {
return new promise(function (deferred) {
if (!(file in stylesheets)) {
var link = document.createElement("link");
link.rel = "stylesheet";
/* * /
// Load event on LINK is currently not supported by Gecko/Webkit.
// + https://bugzilla.mozilla.org/show_bug.cgi?id=185236
// + http://code.google.com/p/chromium/issues/detail?id=67522
// + https://bugs.webkit.org/show_bug.cgi?id=38995
link.addEventListener("load", function (event) {
link.removeEventListener("load", this);
deferred.done();
}, false);
/* */
link.href = theme + file;
stylesheets[file] = link;
document.getElementsByTagName("head")[0].appendChild(link);
// Load event workaround
console.log("css load", theme + file);
var img = document.createElement('img');
img.src = theme + file;
img.style.display = "none";
img.addEventListener("error", function () {
console.log("css done", theme + file);
document.body.removeChild(img);
deferred.done();
}, false);
document.body.appendChild(img);
}
});
},
unload = function (file) {
if (file in stylesheets) {
var link = stylesheets[file];
link.parentNode.removeChild(link);
delete stylesheets[file];
}
};
return {
load: function (file) {
return load(fixName(file));
},
unload: function (file) {
return unload(fixName(file));
}
};
});
44 changes: 44 additions & 0 deletions core/promise.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
define(function () {
return function (promisor) {
var callbacks = [],
promises = [],
pending = 0,
unique = parseInt(Math.random() * 1000000),
deferred = {
done: function () {
console.log("promise", unique, "done", pending);
var payload = arguments;
pending--;
if (pending <= 0) {
console.log("promise", unique, "FEUER FREI!", pending);
callbacks.forEach(function (callback) {
callback.apply(this, payload);
});
}
return this;
}
};
if (promisor instanceof Function) {
setTimeout(function () { promisor(deferred); }, 0);
//promisor(deferred);
}
return {
when: function (promise) {
console.log("promise", unique, "when", pending);
if (promises.indexOf(promise) === -1) {
promises.push(promise);
pending++;
promise.then(deferred.done);
}
return this;
},
then: function (success /* , failure, progress */ ) { // TODO
console.log("promise", unique, "then", pending);
if (callbacks.indexOf(success) === -1) {
callbacks.push(success);
}
return this;
}
};
};
});
3 changes: 2 additions & 1 deletion core/session.js
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,8 @@
});

events.subscribe("app.ready", function () {
template({css: "core/signin", source: "signin", container: "body"}, function (html, container) {
template({css: "core/signin", source: "signin", container: "body"})
.then(function (html, container) {
if (settings.session.remember === true
&& settings.session.address.length > 0
&& settings.session.password.length > 0
Expand Down
59 changes: 34 additions & 25 deletions core/template.js
Original file line number Diff line number Diff line change
Expand Up @@ -70,34 +70,43 @@
* (String) html - The parsed HTML output from the template.
* (Element) container - The HTML element that received the HTML output.
*/
define(function () {
define(
["core/promise", "core/css", "libraries/mustache"],
function (promise, css, mustache) {
return function (settings, callback) {
if ("css" in settings) {
require(["core/css"], function (css) {
css.load(settings.css);
});
}
if ("source" in settings) {
if (settings.source.substr(settings.source.length - 9) !== ".html") {
settings.source += ".html";
return new promise(function (templateDeferred) {
var ready = new promise(),
rawHtml = "";
if ("css" in settings) {
ready.when(css.load(settings.css));
}
if ("source" in settings) {
ready.when(new promise(function (sourceDeferred) {
var extension = ".html",
file = settings.source;
if (file.substr(file.length - extension.length) !== extension) {
file += extension;
}
require(["text!templates/" + file], function (source) {
rawHtml = source;
console.log("template source done");
sourceDeferred.done();
});
}));
}
require(
["libraries/mustache", "text!templates/" + settings.source],
function (mustache, source) {
var html = mustache.to_html(source, settings.data);
if ("container" in settings) {
if (typeof settings.container === "string") {
settings.container = document.querySelector(settings.container);
}
if (settings.container) {
settings.container.insertAdjacentHTML(("position" in settings) ? settings.position : "beforeEnd", html);
}
ready.then(function () {
var html = mustache.to_html(rawHtml, settings.data),
where = "position" in settings ? settings.position : "beforeEnd";
if ("container" in settings) {
if (typeof settings.container === "string") {
settings.container = document.querySelector(settings.container);
}
if (callback instanceof Function) {
callback(html, settings.container);
if (settings.container) {
settings.container.insertAdjacentHTML(where, html);
}
}
);
}
}
templateDeferred.done(html, settings.container);
});
});
};
});
3 changes: 2 additions & 1 deletion core/ui/navigation.js
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,8 @@
}
};

"title tooltip callback target url path".split(" ").forEach(function (key) {
"title tooltip callback target url path".split(" ")
.forEach(function (key) {
if (Object.hasOwnProperty.call(descriptor, key)) {
api[key] = descriptor[key];
}
Expand Down
Loading

0 comments on commit 9a29e59

Please sign in to comment.