tschichold.js | |
---|---|
tschichold.js tschichold Created by Garbrand van der Molen on 2011-12-24. Copyright 2011 Garbrand. All rights reserved. | |
TschicholdTheoretical page layout brought to the digital age. | var Tschichold = function(selector, target, registry) { |
Defaults | registry = registry || $({});
target = target || 'body';
|
Cache jQuery selectors | var $body = $('body')
, $buffer
, $pread
, $next
, $prev
, $text
, $page
, $pageA
, $pageB;
|
Model | var model = {
height: null, // Integer height
text: null, // Cached copy of the text
linesPerPage: null, // Integer linesPerPage of the text
pageHeight: null,
linesInText: null, // Number of lines the text would take at the current page size
page: null, // Current page
textheight: null, // Total height of all the text
lineHeight: null
};
|
View | var view = {
template: {
spread: function() { |
Template for the spread | return '<div class="spread"></div>';
},
page: function(id) { |
Template for two pages in a spread | return $('<div />', {
id: 'page' + id,
'class': 'page'
});
},
buffer: function() { |
Template for the off-screen text buffer | return $('<div id="tschichold-buffer"></div>');
},
thumb: function(id, label) { |
Decode the entities in | var text = $("<div/>").html(label).text();
return $('<div />', {
id: 'tschichold-thumb-' + id,
text: decodeURI(text),
"class": 'thumb ' + id
});
}
},
createBuffer: function(text) {
$buffer = view.template.buffer();
$buffer.css({
'width': '33%',
'margin-left': '-200%'
}).html(text);
$body.append($buffer);
return $buffer;
},
createSpread: function(callback) { |
Append the spread and the pages to the target | $spread = $(view.template.spread());
$prev = view.template.thumb('prev', '‹ Previous');
$next = view.template.thumb('next', 'Next ›');
$pageA = view.template.page('A');
$pageB = view.template.page('B');
$spread.append($pageA, $pageB, $prev, $next).appendTo(target);
callback();
},
calculateHeight: function() { |
Calculate what the height should be in integer line-heights
Sets var | model.height = $pageA.height();
model.lineHeight = parseFloat($body.css('line-height').slice(0, -2));
var lines = Math.floor(model.height / model.lineHeight);
|
TODO: change linesPerPage to pageHeight, add a new variable to hold actual linesPerPage | return model.linesPerPage = lines * model.lineHeight;
},
resetPageHeight: function() { |
Reset the page height in percentages | $pageA.add($pageB).css({bottom: '22.22%', height: 'auto'});
},
setPageHeight: function(height) { |
Set the page height (in pixels) | return $('.page').css({bottom: 'auto', height: height});
},
adjustHeight: function() { |
Reset the spread dimensions to percentages, then re-calculate the pixel dimensions to make the spread integer line-heights | view.resetPageHeight();
view.calculateHeight();
view.setPageHeight(model.linesPerPage);
},
setText: function(text) { |
Set the initial text to the page | $buffer.append(text);
$pageA.add($pageB).append(text.clone());
},
flowText: function() { |
Flow the text across the pages, according to the page we are on | $pageA.find('.text').css('margin-top', 0);
$pageB.find('.text').css('margin-top', -1 * model.linesPerPage);
return $text = $('.text');
},
calculateNumberOfPages: function() { |
Get the number of lines in the buffer at the current dimensions TODO: recheck this on resize TODO: seems we're setting the line-height in hard pixels | var lines = Math.ceil($buffer.height()/model.lineHeight);
console.log(lines, model.linesPerPage/model.lineHeight);
}
};
|
Events | var events = {
resize: function() { |
Recalculate the height to fit integer line-heights, the reflow the text Throttle this function, as it can send an overwhelming amount of events | var scroll = false
, interval;
$(window).resize(function(){
scroll = true;
});
interval = setInterval(function() {
if(scroll) {
scroll = false;
view.adjustHeight();
view.flowText();
view.calculateNumberOfPages();
}
}, 250);
|
Return the interval id so we can use this to call | return interval;
},
next: function() {
$next.click(function() {
$text.animate({'margin-top': '-='+model.linesPerPage*2}, 0);
});
},
prev: function() {
$prev.click(function() {
$text.animate({'margin-top': '+='+model.linesPerPage*2}, 0);
});
},
doneRendering: function() {
registry.trigger('done');
}
};
|
Controller | var controller = {
init: function() { |
Initialize | model.textheight = $(selector).height();
model.text = $(selector).clone();
$(selector).remove();
|
Setup | view.createBuffer(model.text);
view.createSpread(function() { |
Appending to the DOM takes a moment, do the other DOM operations in this callback | view.setText(model.text);
view.adjustHeight();
view.flowText();
view.calculateNumberOfPages();
events.doneRendering();
});
|
Events | events.resize();
events.next();
events.prev();
}
};
|
API | var api = {
production: function() {
return {
init: controller.init
};
},
testing: function() {
return {
model: model,
view: view,
controller: controller,
events: events,
api: api.production()
};
}
};
|
If we run in the context of QUnit, return the test API | return (typeof QUnit == 'undefined') ? api.production() : api.testing();
};
|