I was asked many years ago to produce a script that could emulate the browsing of a book for a site whose owners wanted its whole contents to be browsed like
pages of a book.
I confess that I dismissed the request with some sense of annoyance: the
misconceptions that led many persons to believe that since a PC screen could be a cathodic tube and therefore it had or was expected to behave like a TV set and perform animations as if it were gathering broadcasting waves (whence the
Flash paradigm), were seemingly finding a match in the idea of more literate persons that since on a PC screen you also read text, then such text had to be browsed like those
paper books we are used to read text in.
This failure to understand the specific nature of the
medium (without having now to call in Mc Luhan) was as absurd to me as expecting a book showing animations or a TV image being browsed.
Moreover, I have never been inclined to write
frill codes for effects whose purpose is not instrumental to a serious purpose. Perhaps this is why on Unitedscripters you can find a way to use javascript, power javascript, that you won't find elsewhere.
Then, many years later, I came across
this very nice example, which though it provides no codes (or at least I have not been able to spot them), gave to me the right stimulation to develop this application. That script emulates the browsing of a book composed of images by resizing their width and height.
It then came to my mind that I had to
correct my old perception, arguably
slightly polluted by a wrong "emotional" side: in the
DHTML era, browsing not just images but whole
layers containing
whatever type of
HTML might be more than just a caprice: in fact, if the information on a page is ample, it might be not so inconvenient an idea to arrange it as a book that the surfer can browse. For instance, in the example I provide, browsing a few Shakespeare's sonnets seems to be a
web experience
significantly enhanced if those sonnets are given
each its own layer and presented
each upon request, adding to it the browsing effect.
As it is my custom, I provided the class I developed for this purpose with as many options and features as possible. Yet it became so long, despite the considerable amount of planning that I devoted to it (I just do not fling myself into coding without first writing down what I am going to tackle and envisioning a few solutions) that I eventually had to drop a couple of options.
So there are two things that you can
not do, and I do like to account for shortcomings, I just consider it the decent thing to do and a
good fingerprint to be seen:
-
A Richard Estes painting (that's not a photo)
|
You cannot change your mind while browsing a page, as you could do with a book, and go backward while the browsing effect is still on: you have to wait for a page being fully flipped before going back or forward.
It is possible to argue that it could have been easy to include this feature so to provide the application with an ultra realistic book browsing effect (say like those paintings that you can't tell from a photo of the same thing), but my experience as a scripter proves to me that when at coding it just does not exist over there such a thing whose qualification is: simple. A simple thing: long time since last time.
Like Raymond Chandler wrote in a short story of his own:«Safe. A word that in my business we never use.»
Simple: a word that when we code seriously we never use.
Of course, feel free to implement it, but once done come back to me and say to me how "simple" that was and how that felt. The way this class is structured, anyway, won't easily allow for that, and this is its only real limit - which I acknowledge as you can see.
- The class includes methods meant to manipulate the available pages: these are methods whose names seem to me rather self explicative:
addLayers, removeLayer, moveLayer, swapLayers, insertLayer.
Now, if the book is undergoing a browsing process (that is: a page is currently being flipped), you can use none of the methods above mentioned (even if called in, they would return boolean false): it would have been fully and entirely within my skills and capabilities to arrange things so that a book could have undergone such methods also on the fly and to suit it so that the new situation would have been immediately reproduced. Yet this would have meant including possibly 200 more lines of codes, or maybe more; so I decided not to add this feature and to inhibit any further action once a flipping of a page has been triggered and is not finished yet.
- When a page is being flipped, a theoretical option came up to my mind: start showing the next page in the line while the previous one was still being flipped, rather than awaiting for the former to be fully flipped before starting showing the incoming next one.
I bailed out of that: it would have "simply" required to add a few extra specific methods, which the code of this class definitely would allow to include, but since you're going to complain with me about my codes for they are long, I guess somebody this round might complain that it's not extra long enough.
- The same reasoning as above applies to the possibility of triggering a consecutive browsing of more pages: the class code is structured so that per each page you want to browse (though you can suddenly jump to a specified page skipping all the browsing process that could have been in within), you have to issue the specific command (say click a button): one page, one command.
Arranging for additional methods that would perform a specified consecutive browsing of x pages after one single command, is definitely within the possibilities of the class as it is, but it would have required adding even more code too.
- All the rest, you can do. I have taken care of that.
A Keith Haring painting
|
Once described what the class cannot do, and since all the rest it can do, I specify now what are the caveats you have to be aware of and that are meant as guidelines you have to keep in mind if you want this class to work properly:
-
The initialization of the class is very easy, as you will see shortly.
Yet since the class uses some dhtml properties such as offsetWidth, offsetHeight that the browser will calculate only when the page html body tags pair has got fully loaded and thereby all of its offsets will be available for those calculations, you will initialize your class soon before closing the tag, and not earlier.
You are point, ok?
- Your book pages are layers. You must nest all these layers within an encapsulating layer.
You can place or move this latter wherever you want, but your layers performing as pages of a book must be encapsulated within this container.
An encapsulating layer, to be such, must have a css style position declared, either as absolute or as relative: say sort of, minimal syntax example:
<div id="pageX" style="background-color:#ffffff;">an encapsulated page</div>
<div id="pageY" style="background-color:#ff00ff;">another encapsulated page</div>
Such a span html tag encapsulating other layers would perform like sort of a pin that nails all the pages by their uppermost left corner: the class will position all the pages within such encapsulating layer with top and left coordinates equal to zero.
This is cool actually, because you can move around your whole book, if you want, by manipulating just this one single container.
-
Your encapsulated layers performing as pages, should have a css
background-color property set, or the background would be assumed as being transparent, and from one page above you could see through throughout all the pages below it! That would confuse you, I'm telling you.
- All your layers acting as pages must have unique IDs assigned:
<div id="anID_here">layer contents blah blah</div>
-
Since the book starts closed, you may probably want to allow either on the left of the encapsulating layer or on its top (depending on whether your book is going to be browsed like a standard book or a notepad, respectively), for some leeway or space so that when the book opens it won't hide possible critical data to the eyes of the user.
Also, remember that layers will never be able to cover form menus by overlapping them (an html limitation actually, not a class issue).
-
A Keith Haring painting
|
A browsers issue.
Criss crossed css overflow property issue; in Internet Explorer if the css overflow property is set to "hidden", namely it is instructed that the contained html must be invisible if it exceeds the assigned layer width and height, it will happen the following: Internet Explorer will start clipping the layer as if its width and height wouldn't be the visible and declared ones, but the whole width and height that would have been necessary to make visible in order to accommodate the... whole contents of the layer. Therefore a clipping process might appear as not starting for a while, namely for all the time Internet Explorer needs to clip the... already hidden and not showing layer portion.
Conversely, if the overflow property is set to "visible" (that is, the layer will outstretch to accommodate all the contents even if they exceed its declared width and height) and you have declared such layer width and height via css, Netscape (even its version 8) would not show the contents as belonging inside the layer if they outrange it, but you will see the "exceeding" parts as if they were seemingly pouring out. Beware, some even dare call it the "right" way to do things (because it is Netscape, and as such imagined as the fantastic opposer of the evil capitalism incarnation that many undoubtedly see in Microsoft). I call it just the way it is and by its proper name: a bug like any other, and with this name I have no problem at dealing with it.
Not setting the width and height of the layers via css may not suffice to solve this Netscape oddity.
Morale: be sure that the contents of your layer do not exceed too much the layer visible area, namely that its width and height are declared and are ample enough to accommodate all the contents of each given layer.
By the way, it is not paramount that all the layers belonging to your book share the same width and height: if they won't, the only thing that will happen is that your book would, probably, look ugly or funny, but that will not hinder this application logics and functionalities.
Also beware: Netscape even in its version 8 may show ghost layers flickering around if the overflow properties are set to auto or to scroll (its rendering engine is apparently too slow, and so Netscape reveals traces of what it is probably doing in the background: it seems that those overflow values burden its engine). Internet Explorer won't cause problems with that.
It is not true, by the way, that only layers whose css overflow property is set to hidden can be clipped (this class uses clipping css procedures): even those with scrollbars (namely with the css property overflow set either to "auto" or to "scroll") can be effectively clipped.
Conversely, it seems to me that layers whose css position has not been set either to relative or possibily to absolute, those yeah they can't be clipped. I at times wonder whether it's me who lives in Wonderland or whether it's the offical high profiled documentations that occasionally enjoy a ride in Wonderland.
Just for the record, previous scripts that dealt with clipping are here and here. But the clipping (private) methods that I feature in this current script may look somewhat more interesting if you're a scripter and you want to devote some time to check the codes.
A Robert Williams painting
|
As for the rest, this class code has several nice features. Yet for being complete, I want to account for two circumstances, the only ones, when I had to twist and torture the codes a bit.
The class stores the layers acting as pages in an
array. Makes
sound sense.
When browsing a book instance created with this class, I opted out any approach that would have implied a rearrangement in the order of the entries of this array that stores the layers acting as pages; that is, I decided not to make this array perform like a stack or a queue that would get rearranged so to reflect the forward or backward ongoing browsing process: in fact, that would have not solved the basic problem namely that when browsing a book page (virtual books too!) you
still have to account for as many as
three pages and not just the one that is going to be flipped; in fact you have to account for:
- The page that must be flipped off.
- The next page in the line which has to be flipped on (in).
- The page that must show up beneath the one just flipped off.
Thus, I decided that an
index that kept track of the positions of the involved entries in the class array that stores the pages, was enough. No need to meddle with the actual array.
So, rather than pushing popping shifting or unshifting the array entries, I stored at each forward or backward motion a new tiny array (of course of
three entries) in a class property named:
this.currentSlice
where the indexes of the three mentioned pages (layers) were temporarily stored.
This seems more efficient than popping or shifting and then
still (this "
still" is the whole point) having to keep track of those
three entries.
A Robert Indiana painting
|
Yet I eventually discovered the following that I didn't envision at first, upon testing a couple of bad exceptions: when reached the end of a forward browsing and then going backward, if after the first backward you instructed to go forward once again (which may well happen after all), the
currentSlice reported indexes that should have no longer been dealt with as any previous default "all forward" process; in other terms, I discovered exceptions when dealing with actions performed on the
boundaries of the book.
I
tormented the code a bit to accommodate that, because when at programming, exceptions discovered at a second time have always the gait of afterthoughts.
This process can be sensed in the class methods named:
this.forward
this.backward
and in the creation of the following few methods
specific for those exceptions:
this.forwardLR3
this.forwardTB3
this.backwardLR3
this.backwardTB3
The name of these latest methods are less cryptic than you may think: TB stands for processes that involve the
vertical axis (
Top Bottom), and LR for process that involve the
horizontal axis (
Left Right): the number
3 derives from the fact I firstly realized about this problem when testing a book with only 3 pages. With a book like that, the
reached boundary exceptions, as I called them and as I mentioned them, recurred nearly continuously.
So the methods were originally thought to
fix this exception, and only at a second moment I realized this exception occurred also when playing around backward and forward at the
end of a book.
I do not like
fixes at all: but after all it's also true that you can tell me when was the last time that you did
not see even several
millions paid big IT corporation engineers being forced to release their own
fixes.
We then have the zIndex issue.
The css property
z-index determines the visibility of a layer when it is on a
stack of layers: which is precisely our case, the case of the pages
piled up in a book.
When you are to browse pages as piled
layers, you necessarily have to reassign higher
z indexes to the
three involved layers, or the animation may occur but
not be visible at all because the layers may reside
beneath the stack namely below the bulk of the preceding ones.
So zIndexes, being an entirely
css based issue (and
not an application or programming problem) had to be dealt with necessarily; and
then, additionally, I also had to
reset them
once finished a page flipping, unless you want to go on escalating upon the zIndexes forever (an option, actually).
A Keith Haring painting
|
Thus there are some tasks where the only way to prove that a layer was indeed affected, was to move its stack on top, namely to reassign its zIndex as
the highest in the lot.
Moreover, given that and therefore before that, it was necessary,
prior to starting any action, to reassign all the
original zIndexes to
all the layers as a
safety measure (lest leaving around some missing layer with an exceedingly high zIndex and which might jeopardize at some time the
correct vision of a process that none the less was going on
properly).
I think that computers, though notoriously stupid, are
really good indeed at
one thing at least:
looping. Looping, namely performing
quickly repetitive actions in kind of a dull or obtuse manner, is any computer's daily bread.
Thus, to solve this zIndex minor problem, I did
not consider an issue that
outside timeouts (that is, outside
animations) the class could
loop all the layers acting as pages, so to reassign to them their default zIndexes.
If your books include a few dozens or also hundreds of pages, that is going to be just fine.
Of course, if you plan to provide as a browse-able
DHTML book the whole
Encyclopedia Britannica, I might advice against using a dhtml class for that, and suggest to get the actual volumes.
Keeping track of the latest layers whose zIndexes got increased, so to reset the defaults to these latest ones only, would have been possible, undoubtedly.
But, then, it would also have needed including more coding and
storing more data (about the
previously browsed pages), still opening some margin to unpredictable exceptions; and this all, just in order to accommodate
not a real
programming shortcoming but just a way
css works: that is, the application would have done its duty also if a layer would have not appeared as being manipulated, and yet it would, just because it got a z-index that conceals it under other unaffected layers.
So, zIndexes necessarily had to been dealt with, and yet as a
purely and entirely css issue, not as an apllication flaw or fault; and, indeed, I would have liked a default browser engines approach such that if a layer is involved in an action and no adverse instruction is
given, such layer gets automatically assigned the highest
z-index: among the
several weird things browsers do, this would have
not been the weirdest of them all.
Here are your codes, and then the details about how to start a book of your own using this class codex (beware, Netscape or Mozilla may compact them beyond recognition. I suggest to you to use Internet Explorer to view these codes).
The initialization of the class is as follows, and it requires you add as first argument, and as the only truly necessary one, the very
same name of the variable you are initializing as a String (namely in between quotes); such variable name placeholder, in our case, will be "foo"; do not forget to put before it the keyword var, namely:
var foo = new book("foo");
Do not capitalize book, unless you change the class name.
Theoretically, the class name passed as a String parameter could also be an Object, but I have not tested this.
After the first argument, other arguments are optional; therefore the arguments overview is:
- bookName: String: the name of the initialized variable, as a string (namely in between quotes).
- direction: if zero, opens the book horizontally; if passed as 1 opens it vertically (say "notepad" mode).
- amount: a number, defaults to 5 (pixels). It is the amount of the page (layer) that will be clipped at each iteration upon browsing.
- speed: a number, defaults to 10 (milliseconds): the speed of the clipping of the amount at each iteration upon browsing.
- overflow: a String, defaults to «visible»; accepts only the following possible values (and still defaults to visible if other):
visible, hidden, auto, scroll.
Applies such overflow css properties to each added layer.
After initialized, you need to add the layers that compose your book. You can add layers at any time, though the most obvious thing is to add all of them soon. The class methods that you can use are detailed later on, but you may need knowing this one soon:
foo.
which takes in as arguments the IDs of the layers as String, listed either as a list or passed as an array or as a mix of list and arrays. So:
var foo = new book("foo");
foo.("layerID1", "layerID2", "layerID3", "layerID4", "layerID5", "layerID6" /*etc...*/);
Of course, all the added layers have to
exist in the
html code and have their given ids and, as said earlier, should be encapsulated in a container layer which must have a declared position either as
absolute or as
relative.
Still before detailing the class methods, it may be added that to flip pages forward and back you just issue simply looking commands like:
foo.();
foo.();