refactoring, use Handlebars instead of jQuery objects, updated toolbar styles

This commit is contained in:
Bala Clark 2013-05-02 22:26:33 +02:00
parent fa5e67d9cf
commit ad2ad4f379
23 changed files with 1151 additions and 267 deletions

View file

@ -11,6 +11,9 @@
- full browser test - IE9 / FF3.6+ / Chrome / Safari / Opera
- don't inlcude the closure compiler, expect it (or similar) to be installed instead
- fix Makefile (handlebars is not compiling properly..)
- fonts for left / right navigation, remove all sprites / images completely
Nice 2 have:
- lint
- jump to page?
@ -23,6 +26,8 @@
- really need to speed up enhancements, try to use webworkers
- refactor so we are not using all these loose shared variables and other nastyness
- use custom event emitters instead of hacky code
- properly bind "this" so we don't have to keep using "self"
- allow toolbar to be sticky
*/
/**
@ -56,6 +61,7 @@ function merge(a, b) {
* @returns {ComicBookException}
*/
var ComicBookException = {
INVALID_ACTION: "invalid action",
INVALID_PAGE: "invalid page",
INVALID_PAGE_TYPE: "invalid page type",
UNDEFINED_CONTROL: "undefined control",
@ -159,6 +165,7 @@ function ComicBook(id, srcs, opts) {
* @see #ComicBook.prototype.enhance
*/
function init() {
// setup canvas
canvas = document.getElementById(canvas_id);
context = canvas.getContext("2d");
@ -170,199 +177,47 @@ function ComicBook(id, srcs, opts) {
}
// add page controls
// TODO: add IE event listeners too.
canvas.addEventListener("click", self.navigation, false);
window.addEventListener("keydown", self.navigation, false);
window.addEventListener("hashchange", checkHash, false);
//setInterval(function() { checkHash(); }, 300); // TODO: enable this when there is no onhashchange event
}
/**
* User controls
*
* TODO: save current values
*/
ComicBook.prototype.control = {
status: $(document.createElement("div"))
.attr("id", "cb-status")
.addClass("cb-control cb-always-on")
.append(
$(document.createElement("div"))
.attr("id", "cb-progress-bar")
.progressbar()
),
toolbar: $(document.createElement("div"))
.attr("id", "cb-toolbar")
.addClass("cb-control")
.append(
$(document.createElement("button"))
.attr("title", "close the toolbar")
.addClass("cb-close")
.click(function(){
self.toggleToolbar();
})
)
.append(
$(document.createElement("button"))
.attr("title", "switch between dual and single page modes")
.addClass("cb-layout " + options.displayMode)
.click(function(){
self.toggleLayout();
})
)
.append(
$(document.createElement("button"))
.attr("title", "tweak the page colors")
.addClass("cb-color cb-menu-button")
.click(function(){
self.toggleControl("color");
})
)
.append(
$(document.createElement("button"))
.attr("title", "zoom out")
.addClass("cb-zoom-out")
.click(function(){
self.zoom(scale - 0.1);
})
)
.append(
$(document.createElement("button"))
.attr("title", "zoom in")
.addClass("cb-zoom-in")
.click(function(){
self.zoom(scale + 0.1);
})
)
.append(
$(document.createElement("button"))
.attr("title", "fit to page width")
.addClass("cb-fit-width")
.click(function(){
options.zoomMode = "fitWidth"
self.drawPage();
})
)
.append(
$(document.createElement("p"))
.attr("id", "cb-comic-info")
.append("<span id='cb-current-page'></span> / " + srcs.length)
),
/**
* Image enhancements
*/
color: $(document.createElement("div"))
.attr("id", "cb-color")
.addClass("cb-control")
.append("<label for='cb-sharpen'>Brightness</label>")
.append(
$("<div id='cb-brightness' class='cb-option'></div>").slider({
value: 0,
step: 10,
min: -1000,
max: 1000,
change: function(event, ui) {
self.enhance.brightness({ brightness: ui.value });
}
})
)
.append("<label for='cb-sharpen'>Contrast</label>")
.append(
$("<div id='cb-contrast' class='cb-option'></div>").slider({
value: 0,
step: 0.001,
min: 0,
max: 1,
change: function(event, ui) {
self.enhance.brightness({ contrast: ui.value });
}
})
)
.append("<label for='cb-sharpen'>Sharpen</label>")
.append(
$("<div id='cb-sharpen' class='cb-option'></div>").slider({
value: 0,
step: 0.001,
min: 0,
max: 1,
change: function(event, ui) {
self.enhance.sharpen({ amount: ui.value });
}
})
)
.append(
$(document.createElement("div")).addClass("cb-option")
.append("<input type='checkbox' id='cb-desaturate' /> <label for='cb-desaturate'>Desaturate</label>")
.append("<button id='cb-reset'>reset</button>")
),
/**
* Page navigation
*/
navigation: {
left: $(document.createElement("div"))
.addClass("cb-control cb-navigate cb-always-on left")
.click(function(e){
self.drawPrevPage();
}),
right: $(document.createElement("div"))
.addClass("cb-control cb-navigate cb-always-on right")
.click(function(e) {
self.drawNextPage();
})
},
loadingOverlay: $(document.createElement("div"))
.attr("id", "cb-loading-overlay")
.addClass("cb-control")
};
ComicBook.prototype.renderControls = function() {
$(canvas)
.before(this.getControl("loadingOverlay"))
.before(this.getControl("status"))
.after(this.getControl("toolbar"))
.after(this.getControl("navigation").left)
.after(this.getControl("navigation").right)
.after(this.getControl("color").hide());
var controls = {};
$(".cb-menu-button").click(function(e) {
$(this).toggleClass("active");
$.each(Handlebars.templates, function (name, template) {
var $template = $(template().trim());
controls[name] = $template;
$template.find('*').andSelf().filter("[data-action][data-trigger]").each(function () {
var $this = $(this);
var trigger = $this.data('trigger');
var action = $this.data('action');
// trigger a direct method if exists
if (typeof self[$this.data('action')] === "function") {
$this.on(trigger, self[action]);
}
// throw an event to be caught outside if the app code
$this.on(trigger, function (e) {
$(self).trigger(trigger, e);
});
});
$(canvas).before($template);
});
$("#cb-desaturate").click(function(){
if ($(this).is(":checked")) {
self.enhance.desaturate();
} else {
self.enhance.resaturate();
}
});
$("#cb-reset").click(function() {
// TODO: improve performance here.
$("#cb-brightness").slider("value", 0);
$("#cb-contrast").slider("value", 0);
$("#cb-saturation").slider("value", 0);
$("#cb-sharpen").slider("value", 0);
var desaturate = $("#cb-desaturate");
desaturate.attr("checked", false);
self.enhance.reset();
});
this.controls = controls;
};
ComicBook.prototype.getControl = function(control) {
if (typeof this.control[control] === "undefined") {
throw ComicBookException.UNDEFINED_CONTROL+' '+control;
if (typeof this.controls[control] !== "object") {
throw ComicBookException.UNDEFINED_CONTROL + ' ' + control;
}
return this.control[control];
return this.controls[control];
};
ComicBook.prototype.showControl = function(control) {
@ -377,23 +232,16 @@ function ComicBook(id, srcs, opts) {
this.getControl(control).toggle().toggleClass("open");
};
ComicBook.prototype.toggleToolbar = function() {
if ($("#cb-toolbar").is(":visible")) {
$(".cb-control").not(".cb-always-on").hide();
} else {
$("#cb-toolbar, .cb-control.open").show();
}
};
ComicBook.prototype.toggleLayout = function() {
if (options.displayMode === "double") {
$("#cb-toolbar .cb-layout").removeClass("double");
options.displayMode = "single";
} else {
$("#cb-toolbar .cb-layout").removeClass("single");
options.displayMode = "double";
}
$("#cb-toolbar .cb-layout").addClass(options.displayMode);
var $control = self.getControl("toolbar").find("[data-action=toggleLayout]");
var displayMode = (options.displayMode === "single") ? "double" : "single";
$control.removeClass(options.displayMode);
$control.addClass(displayMode);
options.displayMode = displayMode;
self.drawPage();
};
@ -424,8 +272,7 @@ function ComicBook(id, srcs, opts) {
init();
// resize navigation controls
$(".cb-control.cb-navigate").outerHeight(window.innerHeight);
$("#cb-toolbar").outerWidth(windowWidth());
$(".navigate").outerHeight(window.innerHeight);
$("#cb-loading-overlay").outerWidth(windowWidth()).height(window.innerHeight);
// preload images if needed
@ -447,6 +294,19 @@ function ComicBook(id, srcs, opts) {
if (typeof this.getPage(pointer) === "object") { this.drawPage(); }
};
ComicBook.prototype.zoomIn = function () {
self.zoom(scale + 0.1);
};
ComicBook.prototype.zoomOut = function () {
self.zoom(scale - 0.1);
};
ComicBook.prototype.fitWidth = function () {
options.zoomMode = "fitWidth"
ComicBook.prototype.drawPage();
};
/**
* Preload all images, draw the page only after a given number have been loaded.
*
@ -470,7 +330,7 @@ function ComicBook(id, srcs, opts) {
pages[i] = this;
loaded.push(i);
$("#cb-progress-bar").progressbar("value", Math.floor((loaded.length / no_pages) * 100));
$("#cb-progress-bar .progressbar-value").css("width", Math.floor((loaded.length / no_pages) * 100) + "%");
// double page mode needs an extra page added
var buffer = (options.displayMode === "double" && pointer < srcs.length-1) ? 1 : 0;
@ -662,7 +522,11 @@ function ComicBook(id, srcs, opts) {
var current_page = (options.displayMode === "double" && pointer+2 <= srcs.length)
? (pointer+1) + "-" + (pointer+2) : pointer+1
$("#cb-current-page").text(current_page);
this.getControl('toolbar')
.find("#current-page").text(current_page)
.end()
.find("#page-count").text(srcs.length);
// revert page mode back to double if it was auto switched for a double page spread
if (is_double_page_spread) { options.displayMode = "double"; }
@ -671,21 +535,18 @@ function ComicBook(id, srcs, opts) {
$("button.cb-fit-width").attr("disabled", (options.zoomMode === "fitWidth"));
// disable prev/next buttons if not needed
$(".cb-navigate").show();
$(".navigate").show();
if (pointer === 0) {
$(".cb-navigate.left").hide();
$(".cb-navigate.right").show();
$(".navigate-left").hide();
$(".navigate-right").show();
}
if (pointer === srcs.length-1 || (typeof page2 === "object" && pointer === srcs.length-2)) {
$(".cb-navigate.left").show();
$(".cb-navigate.right").hide();
$(".navigate-left").show();
$(".navigate-right").hide();
}
// user callback
if (typeof options.afterDrawPage === "function") {
options.afterDrawPage(pointer + 1);
}
$(this).trigger("navigate");
// update hash location
if (getHash() !== pointer) {
@ -706,7 +567,7 @@ function ComicBook(id, srcs, opts) {
var page;
try {
page = this.getPage(pointer+1);
page = self.getPage(pointer+1);
} catch (e) {}
if (!page) { return false; }
@ -714,7 +575,7 @@ function ComicBook(id, srcs, opts) {
if (pointer + 1 < pages.length) {
pointer += (options.displayMode === "single" || is_double_page_spread) ? 1 : 2;
try {
this.drawPage();
self.drawPage();
} catch (e) {}
}
};
@ -729,7 +590,7 @@ function ComicBook(id, srcs, opts) {
var page;
try {
page = this.getPage(pointer-1);
page = self.getPage(pointer-1);
} catch (e) {}
if (!page) { return false; }
@ -738,10 +599,35 @@ function ComicBook(id, srcs, opts) {
if (pointer > 0) {
pointer -= (options.displayMode === "single" || is_double_page_spread) ? 1 : 2;
this.drawPage();
self.drawPage();
}
};
ComicBook.prototype.brightness = function () {
self.enhance.brightness({ brightness: $(this).val() });
}
ComicBook.prototype.contrast = function () {
self.enhance.brightness({ contrast: $(this).val() });
}
ComicBook.prototype.sharpen = function () {
self.enhance.sharpen({ amount: $(this).val() });
}
ComicBook.prototype.desaturate = function () {
if ($(this).is(":checked")) {
self.enhance.desaturate();
} else {
self.enhance.resaturate();
}
};
ComicBook.prototype.resetEnhancements = function () {
self.enhance.reset();
};
/**
* Apply image enhancements to the canvas.
*
@ -802,11 +688,8 @@ function ComicBook(id, srcs, opts) {
* Force black and white
*/
desaturate: function () {
options.enhance.desaturate = {};
Pixastic.process(canvas, "desaturate", { average : false });
init();
},
@ -855,9 +738,7 @@ function ComicBook(id, srcs, opts) {
var side = false;
switch (e.type) {
case "click":
self.toggleToolbar();
break;
case "keydown":
// navigation
@ -872,6 +753,7 @@ function ComicBook(id, srcs, opts) {
self.toggleLayout();
}
break;
default:
throw ComicBookException.INVALID_NAVIGATION_EVENT+' '+e.type;
}