Skip to content

Commit

Permalink
Persistent proportional font-sizing with Formatting#setFontScale.
Browse files Browse the repository at this point in the history
Additionally, you can now pass a float multiplier into Reader
initialisation options with 'fontScale'.
  • Loading branch information
joseph committed Feb 10, 2012
1 parent 3a79afe commit 2402da9
Show file tree
Hide file tree
Showing 4 changed files with 149 additions and 18 deletions.
95 changes: 92 additions & 3 deletions src/core/formatting.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ Monocle.Formatting = function (reader, optStyles, optScale) {


function initialize() {
p.fontScale = optScale;
clampStylesheets(optStyles);
p.reader.listen('monocle:componentmodify', persistOnComponentChange);
}
Expand All @@ -36,6 +37,7 @@ Monocle.Formatting = function (reader, optStyles, optScale) {
function persistOnComponentChange(evt) {
var doc = evt.m['document'];
doc.documentElement.id = p.reader.properties.systemId;
adjustFontScaleForDoc(doc, p.fontScale);
for (var i = 0; i < p.stylesheets.length; ++i) {
if (p.stylesheets[i]) {
addPageStylesheet(doc, i);
Expand All @@ -59,9 +61,7 @@ Monocle.Formatting = function (reader, optStyles, optScale) {

var i = 0, cmpt = null;
while (cmpt = p.reader.dom.find('component', i++)) {
if (cmpt.contentDocument) {
addPageStylesheet(cmpt.contentDocument, sheetIndex);
}
}
return sheetIndex;
}, restorePlace);
Expand Down Expand Up @@ -122,7 +122,7 @@ Monocle.Formatting = function (reader, optStyles, optScale) {
function changingStylesheet(callback, restorePlace) {
restorePlace = (restorePlace === false) ? false : true;
if (restorePlace) {
p.reader.dispatchEvent("monocle:stylesheetchanging", {});
dispatchChanging();
}
var result = callback();
if (restorePlace) {
Expand All @@ -135,6 +135,11 @@ Monocle.Formatting = function (reader, optStyles, optScale) {
}


function dispatchChanging() {
p.reader.dispatchEvent("monocle:stylesheetchanging", {});
}


function dispatchChange() {
p.reader.dispatchEvent("monocle:stylesheetchange", {});
}
Expand Down Expand Up @@ -175,9 +180,93 @@ Monocle.Formatting = function (reader, optStyles, optScale) {
}


/* FONT SCALING */

function setFontScale(scale, restorePlace) {
p.fontScale = scale;
if (restorePlace) {
dispatchChanging();
}
var i = 0, cmpt = null;
while (cmpt = p.reader.dom.find('component', i++)) {
adjustFontScaleForDoc(cmpt.contentDocument, scale);
}
if (restorePlace) {
p.reader.recalculateDimensions(true);
dispatchChange();
} else {
p.reader.recalculateDimensions(false);
}
}


function adjustFontScaleForDoc(doc, scale) {
var elems = doc.getElementsByTagName('*');
if (scale) {
scale = parseFloat(scale);
if (!doc.pfsSwept) {
sweepElements(doc, elems);
}

// Iterate over each element, applying scale to the original
// font-size. If a proportional font sizing is already applied to
// the element, update existing cssText, otherwise append new cssText.
//
for (var j = 0, jj = elems.length; j < jj; ++j) {
var newFs = fsProperty(elems[j].pfsOriginal, scale);
if (elems[j].pfsApplied) {
replaceFontSizeInStyle(elems[j], newFs);
} else {
elems[j].style.cssText += newFs;
}
elems[j].pfsApplied = scale;
}
} else if (doc.pfsSwept) {
// Iterate over each element, removing proportional font-sizing flag
// and property from cssText.
for (var j = 0, jj = elems.length; j < jj; ++j) {
if (elems[j].pfsApplied) {
var oprop = elems[j].pfsOriginalProp;
var opropDec = oprop ? 'font-size: '+oprop+' ! important;' : '';
replaceFontSizeInStyle(elems[j], opropDec);
elems[j].pfsApplied = null;
}
}

// Establish new baselines in case classes have changed.
sweepElements(doc, elems);
}
}


function sweepElements(doc, elems) {
// Iterate over each element, looking at its font size and storing
// the original value against the element.
for (var i = 0, ii = elems.length; i < ii; ++i) {
var currStyle = doc.defaultView.getComputedStyle(elems[i], null);
var fs = parseFloat(currStyle.getPropertyValue('font-size'));
elems[i].pfsOriginal = fs;
elems[i].pfsOriginalProp = elems[i].style.fontSize;
}
doc.pfsSwept = true;
}


function fsProperty(orig, scale) {
return 'font-size: '+(orig*scale)+'px ! important;';
}


function replaceFontSizeInStyle(elem, newProp) {
var lastFs = /font-size:[^;]/
elem.style.cssText = elem.style.cssText.replace(lastFs, newProp);
}


API.addPageStyles = addPageStyles;
API.updatePageStyles = updatePageStyles;
API.removePageStyles = removePageStyles;
API.setFontScale = setFontScale;

initialize();

Expand Down
3 changes: 3 additions & 0 deletions src/core/reader.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@
// stylesheet: A string of CSS rules to apply to the contents of each
// component loaded into the reader.
//
// fontScale: a float to multiply against the default font-size of each
// element in each component.
//
// place: A book locus for the page to open to when the reader is
// initialized. (See comments at Book#pageNumberAt for more about
// the locus option).
Expand Down
6 changes: 2 additions & 4 deletions src/core/selection.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,8 @@ Monocle.Selection = function (reader) {

function pollSelection() {
var index = 0, frame = null;
while (frame = reader.dom.find('component', index)) {
while (frame = reader.dom.find('component', index++)) {
pollSelectionOnWindow(frame.contentWindow, index);
index += 1;
}
}

Expand Down Expand Up @@ -60,9 +59,8 @@ Monocle.Selection = function (reader) {
//
function deselect() {
var index = 0, frame = null;
while (frame = reader.dom.find('component', index)) {
while (frame = reader.dom.find('component', index++)) {
deselectOnWindow(frame.contentWindow);
index += 1;
}
}

Expand Down
63 changes: 52 additions & 11 deletions test/formatting/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -25,16 +25,34 @@

<script type="text/javascript" src="../../dist/scripts/monocore.js"></script>
<script type="text/javascript">
Monocle.DEBUG = true;

// Initialize the reader element.
Monocle.Events.listen(window, 'load', function () {
window.reader = Monocle.Reader(
'reader',
Monocle.bookDataFromIds(['part1', 'part2']),
{ stylesheet: "body { color: #090; }" }
);
});
(function () {
function init() {
var bd = Monocle.bookDataFromIds(['part1', 'part2']);
var opts = { stylesheet: 'body { color: #090; }' };
window.reader = Monocle.Reader('reader', bd, opts, readerLoaded);
}


function readerLoaded() {
var sSel = document.getElementById('sizeSelect');
sSel.addEventListener('change', function (evt) {
reader.formatting.setFontScale(parseFloat(sSel.value), true);
});

var cSel = document.getElementById('colorSelect');
cSel.addEventListener('change', function (evt) {
reader.formatting.updatePageStyles(
reader.formatting.properties.initialStyles,
'body { color: '+cSel.value+'; }',
true
);
});
}


Monocle.DEBUG = true;
Monocle.Events.listen(window, 'load', init);
})();
</script>

</head>
Expand All @@ -48,8 +66,31 @@ <h1>Formatting</h1>
turns the component's body text <span style="color: #090;">green</span>.
</p>

<div id="reader"></div>
<p>
Font-scale:
<select id="sizeSelect">
<option value="">&mdash;</option>
<option value="0.1">10%</option>
<option value="0.5">50%</option>
<option value="0.8">80%</option>
<option value="1.0">100%</option>
<option value="1.1">110%</option>
<option value="1.3">130%</option>
<option value="1.6">160%</option>
<option value="2.0">200%</option>
<option value="2.5">250%</option>
<option value="4.0">400%</option>
<option value="8.0">800%</option>
</select>

Color:
<select id="colorSelect">
<option value="#090">Green</option>
<option value="#009">Blue</option>
</select>
</p>

<div id="reader"></div>

<div id="part1">
<p>
Expand Down

0 comments on commit 2402da9

Please sign in to comment.