SCRIPTING:

Brooke Banx
UNDERLINE CONTENTS IN WEB PAGES OR PORTIONS OF WEBPAGES BY HIGHLIGHTING TEXT RANGES SELECTED WITH MOUSE MOVEMENTS
This script implements what I consider, possibly, one of the most useful and yet missing features for a web page: underlining portions of its textual contents that you have selected with your mouse, as if the page would have been a book upon which you stress lines via a pencil.
In this way you can locate at a glance sections of a long page that you may have a particular interest in - which is particularly useful if you mean to study the document.

You can apply this feature to the whole document or to single portions of it. You can apply this feature to web pages saved for offline perusal too. You can also extract the highlighted texts for printing purposes.
August 2005
{ @ }
The model above is Brooke Banx
LOADS OF BROOKE BANX ON THE NET


WHAT THE SCRIPT DOES
The important thing this script achieves, its caveats, and why I invented it.


INTERNET EXPLORER only script - read further on why

The objective of this script is to enable any web page, by just including the script in it, to get portions of its texts underlined once you have selected them with your mouse - and, upon request, to extract all the highlighted texts too, in order to save them .

Please place your mouse somewhere on this line, then keeping the left button down drag to select some text, then release the mouse button and see.
It is going to be self evident, both as a feature and as far as its utility is concerned - user that do not have Internet Explorer may

a Tom Wesselmann painting
A Tom Wesselmann painting
Particularly when dealing with a page having significant textual contents, highlighting the portions you have interest in can be an extremely effective way, and an immensely useful one, to come back to them at a glance in case the page is something you feel like studying.
As a matter of fact, I wished such a script were available a few days ago when reading a long page about RSS which I could not print (by the way, this script is an ecologist: may make you save paper) and yet which, the more I was reading it, the more I felt like it was necessary to highlight a few portions of it so to come back to them at a second time and chew on its strongest and most relevant parts.
I felt like studying it, that is: but how to go back and locate the parts that I deemed important and more fit to integrate my current knowledge, if the length of the document made any such backward perusal a nightmare? A good page was going to be spoiled by the lack of this feature.
And so I did the script.

Actually, this feature can be thought of as the online equivalent of underlining text portions in a traditional paper book with a pencil so to make them stack out in case you want to retrieve them at a second time or at a second perusal. I think that students may find this rather familiar.

It is true that, under a purist point of view so to call it, some may feel underlining a book like a defilement: yet there are many persons who do not feel so (my case) and who, besides, find underlining an useful cognitive support gesture to enhance apprehending.

The utility of this feature proves itself true when we verify that, despite a few caveats of some significance, yet you still find the feature as a precious add on. Of course, a first practical caveat is that once closed the browser window also the selections disappear (although as hinted you can save the selections, though not the whole page with them on). Yet this is no reason enough not to enable this type of feature: in fact, for instance, a couple of hours devoted to a session of study of one single web page you have real interest in, can be enough and you may get a significant cognitive boost or memorizing improvement by having this underlining feature available.

a Jean-Michel Basquiat painting
A Jean-Michel Basquiat painting

It is my contention that this capability should have been made available on every single online document by default and since the beginning of the web and as a standard, though by necessity not via the partial methods I was compelled to contrive in order to implement it nowadays with a gamut of scripting options that, though numerous, still seem absurdly insufficient to grant it to us adequately.

The reason it is not a default and the reason we lack scripting behaviours clearly meant to address it, is that -to date and regardless of how many new Document Object Models get developed by the w3 consortium- we still miss (because, apparently, no one ever even thought of this) any selection range methods electively suited to accomplish this type of task.

We have several options for selections [see Mozilla DOM2/DOM3 selection scripting, or Internet Explorer Selection scripting or Internet Explorer textRange and getClientRects page], but none of those selection properties and methods seem to have been ever envisioned in order to meet this exact type of purpose we're after here; and this although, by all accounts, creating html or css formats for the mouse highlighted texts would have seemed such obvious an exigency that more expeditious attention should have already been lent to it rather than to processes like surroundContents(newParent) - whereof method, as that link declares adding no further details, would have been invented to attain the following:
Reparents the contents of the Range to the given node and inserts the node at the position of the start of the Range.
When you understand what that apparent short circuiting definition means, and what the "reparenting" of a range is, and why we needed to have that intention or purpose addressed promptly whereas other purposes like the one I worked upon here needed not to be addressed as soon as well, email me.

As far as i see it, and it may well be I fail to understand it for my own intellectual shortcomings, that surroundContents method might grab a node that (for instance) a mouseDown event allowed to sort out; once such a node is grabbed, via such surroundContents method one might hold it firm in the void, apply new css style to it, and redispatch it to where it was if one is cautious enough to do it by allocating first in such place a new third node to perform as a "reparenting" bag or enveloper.

a Tom Wesselmann painting
A Tom Wesselmann painting

Alas, if that is what it meant (that documentation is really too scanty), then this is not what we needed.
For we want to act after a logic that is not an Html nodes driven logic (which currently seems so upbeat and trusted) whereas if an user selects a portion of text within a node the whole range of the node is uplifted.
We do not want this.
Rather, we want to apply styles to subportions of the node, being sure we do not break any markup nesting in the process in case such subportions span halfway throughout more nodes.
When we arrive at such a problem, a node driven logics where if I want a slice of the slice I may get the whole cake, seemed to me (and i repeat, I may be wrong - I am aware of this) exactly the one I had to forsake.

Which brought me to the Internet Explorer text selections box model, which seemed more suited and direct, particularly if I meant, as I did, to keep an eye upon the exigency not to violate the correct nesting format of the document html nodes by meddling with nodes and flipping around ranges extracted after the end user's whim - that is: nodes broken up at random!
Internet Explorer allowed me to derive page screen positions and exact sizes of all the text selections.
If Mozilla allowed that too, I didn't see that so blame me, as long as you also acknowledge you won't find to date many other scripts (if any, actually) that succeeded, at least with one browser, to do such naturally desirable a thing: underlining text in web documents via end user mouse inputs.

a Tom Wesselmann painting
A Tom Wesselmann painting

The main difficulty I am referring to, and which may be accountable for this type of feature having never been enabled first, is the following.

a Roy Lichtenstein painting
A Roy Lichtenstein painting
Once you select a text in a page with your mouse, you have an offset start point of your selection and, of course, an offset end point of it.

Now, there is no way from this selection to translate these offsets coordinates as they are onto the screen into their equivalent offsets as they are placed within the source code.

For instance, if you highlight with your mouse this, it is possible to retrieve the offsets onto the screen where the onmousedown event (beginning of selection) occurred and it is possible to have the offsets of where onto the screen the onmouseup event (end of selection) occurred.
Yet, grabbing the source code it is not possible to determine where in it such screen offsets find their source code row line and source code line char matches.

No way, to date. And I do not think that the w3c, so busy doing much more important things like deprecating innerHTML, would ever listen to the ideas or exigencies of an obscure end front developer like me.

If such an equivalence and transposition would have been possible to plot out, it would have been possible, theoretically at least, to nest into a precisely pinpointed source code location, a new dom node belonging to a specified css class, and apply thus to the selected screen text the whole properties of such class.

a William Bouguereau painting
A William Bouguereau painting: Une Vocation
Yet, this, even if possible, would end up clashing against another exigency: a selection of text on screen spans, by its very same nature, throughout manifold html tags in the source code: by inserting then a node, it could happen to break up the well formatted nature of the source code by including in it a tag nesting error whose consequences could be unpredictable - from none, till a disfigurement of the page caused by the involuntary premature closing of a previous tag which mistakes the closure of the newly added encapsulating tag pair (meant to apply the highlighting) as the closure of another different tag of the same type previously open at another level of the page and not meant to be closed yet.

The alternative workaround would have been climbing up the nodes ladder so to encapsulate with the new highlighting tag pair the closest parent node: but then, what if this closest parent node is the body tag itself, or any other tag far away uphill the page? We would have ended up encapsulating the whole page till the end offset of the selection: you select a line, and the script might have finished highlighting all the text before it and till it included.
Which, of course, is no longer what was meant in the least.

The only viable solutions to my eyes is then to dispatch a newly created tag to the selection. If such tag background is set to transparent, it would be possible at least to do two things:
  • Arrange with a few tricks an underline in it (my solution was: applying a css border bottom).
  • Retrieve, via methods that at least Internet Explorer supports, the html text of the selection, write it onto the tag, and superimpose this new node to the selections thus allowing, for instance, also a background color without obscuring the underlined selected text.
    This would still import potential wrong nesting issues, but being these confined to a layer absolutely positioned and appended to the body tag (if no body tag exists the script will exit), are less prone to cause disfigurements at all. Under a purist point of view this procedure is anathema, of course: including in a newly created tag some inner html which might allow for tags that may not be closed (yet).
    But I am one of those guys who always believed that css is like the sabbath: made for men, and not men made for it.

    Anyway this feature was dropped: so you won't have to fear it, and I report it here only as an educational hint about what type of new methods a future DOM might include.
Which leads us to the last important caveat: in order for this script to work, the exact size of the selection box must be available via scripting: it must be available line by line, per each line knowing its left and top coordinates and width and height coordinates, and this can be done with the precision which only methods electively built in for this purpose can lend: which till today tantamount to, as far as I see: only via Internet Explorer.
Maybe one day the w3c will make a decision, and consider a few of the Microsoft invented scripting properties what they should be not because we love or hate Microsoft but simply because they are indeed useful (see this nice example of what Internet Explorer allows): standards.

a Tom Wesselmann painting
A Tom Wesselmann painting

Of course, the script also uses some DOM1 and DOM2 standard methods: and yet they do not suffice to achieve this purpose.

a Matthew Ritchie painting
A Matthew Ritchie painting
The fact this script will thus work only on Internet Explorer is anyway not an issue.
I always developed cross browser scripts without exceptions but precisely this one, this whole site is factual evidence of it, and this spells how I feel about this problem: scripts should always be cross browser or not to be. You were not the only one to feel so, rest assured.

Yet in this case, if you like the page portions highlighting feature upon mouse selections, what would be your problem with viewing a page with Internet Explorer for a little while rather than with Opera or Mozilla or whatever else (to quote a few alternative popular and good browsers), when what you care about is the contents of the page to study and not an ideological stance to worship as a taboo?

Css is made for men and not men for css, and also web pages and browsers are made for men and not for themselves and their own sake. Use what you need, browser or whatever, rather than being used by what you do not need just in order to show compliance with the absolutism of a too often misunderstood ideal.

And who wants to be friends with a forcibly anti patriarchal ideal which prowls the earth for its metaphors to attack, and which being so often and so openly biased, cannot have anything ideal in it any longer?
Any serene person would see that the anti Internet Explorer bias has clearly exceeded its declared motives, and thus must have been driven by more profound psychological reasons. The ideal that fosters violence or promotes hate, promotes mind obfuscation, and as such is not an ideal but it is the plain violence it attempts to instill and teach.


CODES AND INITIALIZATION
The codes and the technical details to implement this script on any page and onto whichever portions of it

a Keith Haring painting
A Keith Haring painting


a Edward Ruscha painting
A Edward Ruscha painting

Here are the details about how to activate this script on a webpage.

First of all, you must assign to it a given name which is rangeMaster; such name cannot be changed because the script relies on javascript event handlers and these cannot retrieve any longer the reference to the class that invokes them if such class hasn't a precise name.
So the initialization of the script looks like:

var rangeMaster = new rangeManager();

Exactly like that, and not different.

Also, which is paramount, no such call should be made before the element you mean to affect has been loaded into the page; so the safer procedure is to initialize this class at the bottom of the page, ideally soon before or soon after closing the body tag.

Then, you may decide which parts of the page have to get the underlining feature enabled onto them.
You can do it by a class method named enable which takes in one mandatory argument. Such argument is a String and can be either (preferably) the ID assigned to a tag (layer); if the script detects no layer on the page with such id, it will assume it is a tag name and therefore will attempt to fetch the first tag with such name. In such fashion you can enable the script also onto the whole page rather than just on portions of it by passing to this method as its mandatory argument the string: "body".
Thus, two possible further enabling might be:

rangeMaster.enable("aLayerIDhere");
//or
rangeMaster.enable("body");


Of course, if you enable the feature on the body tag, then all the elements onto the page will be fit to be underlined. By default the script disallows considering as valid selections form elements tags such as drop down menus or input fields or textareas.

The method enable allows for a second optional argument, still a String type.
If you pass it, it must be css commands: these will override the script underlining layers default css (which is: "background:transparent; border-bottom:#ee0000 3px solid; zIndex:10;") and assign to the specified enabled element that type of css you passed as second argument to be applied onto the layer that will be dispatched above the selection (for as we saw in the first part, we cannot nest, for manifold reasons, tags inside the source code; so we have to superimpose ad hoc layers onto the selections).
Instance:

rangeMaster.enable("aLayerIDhere", "border-bottom:#770000 3px solid; zIndex:10;");

Since the layers meant to perform the underlining will be put above the selected texts, the script will force the background of the underlining layers to: transparent.
Although the underlining feature is refined enough, you may find rather useful specifying for your enabled layers also a css line-height property so to be sure the underlining has enough margins to appear nifty in all circumstances. On this page for instance has been applied a line height of 20px.


AVAILABLE CLASS METHODS
A few methods to play around with the class

The javascript class hasn't many methods available as public.
Anyway before detailing the ones that are available, keep in mind that this class enables event handlers. These event handlers are confined to the layers upon which the feature is enabled, but of course if you enable the script onto the whole page, then the whole page onMouseDown, onMouseMove and onMouseUp events will be affected.
With a bit of savvy editing though, if you have some little knowledge of javascript, you might nest these class event handlers commands within previously defined page event handlers so to have them without interfering yet with the previously defined ones.
For instance if the affected layer has already some foofoo enabled event handler for, say, the mouse down event, you could put at the end of its code (or in any other suitable place of its code) a command such as:
rangeMaster.mouseDown();
In fact the class event handlers are:
  • rangeMaster.mouseDown();
  • rangeMaster.mouseMove();
  • rangeMaster.mouseUp();
  • rangeMaster.remove();
    This latter affects the onDblClick event: in fact, if you put the mouse pointer onto the line of an underlined text and you double click it, the applied underlining will disappear (right onto the line, the mouse pointer must appear as an arrow hovering onto the underlining line if you want to perform on it a double click that will successfully erase it).

    Nesting this latter into a previously defined event handler for the double click event though will imply a caveat namely that you pass to it an argument, which has to be the very same you passed as first when enabling such page element.
That simple (and case sensitive as usual with javascript, of course).
The other few public methods available to the class are:

a Tom Wesselmann painting
A Tom Wesselmann painting
  • setCss: takes two arguments, the same you passed for enabling the layer you mean to affect, and a second one which is css text: it will apply this new css text as the one to use upon the enabled element. Useful to switch css properties if needed.
    Instance:

    rangeMaster.setCss("aLayerIDhere", "border:#000000 1px solid;")
  • disable: takes one argument, the same you passed for enabling the layer you mean to affect. It will disable the underlining feature upon it - and beware, this will positively erase also whatever defined event handler for mouse down, up, move onto the affected page element.
    To restore the underlining feature again on such disabled layer, call on it enable again.
  • external: this method fill fire a javascript prompt . From such prompt you can copy the string it provides.
    Such string is a script tag with a few commands in it plus a few html tags in a dedicated form tag pair, the all linking to this website rangeManager js class.

    If you include such string at the end of a page you have saved offline, when loading it from your hard disk (and provided you are still connected to the internet of course) it will enable after a few seconds such page to be underlined.
    Somewhat cool, isn't it?
  • extract: this method will return a string with all the currently underlined texts, plus the date and the web address. Such string could for instance be dispatched to a textarea.
    If you have underlined something in this page, you can test it:

  • Here you can perform a few tests. Though the script is, in this page, enabled by default on all the elements, you can still enable independent elements: the ones below have an id named the one fooid and the other fooid2 and even scrollbars so you will see that the script can work smoothly in all circumstances - though as said only on Internet Explorer, which as we saw does not make the script any less useful, for its intention is to provide a feature whose quality of being cross browser is not indispensable in this case.

    a Paul McCormack painting
    A Paul McCormack painting
    As a matter of fact this example allows us to make one last and yet very important specification: if in your page you have scrollable layers (which not all pages include, rather the contrary), these should always be initialized by their own specific call to rangeMaster.enable.
    Though said as last, keep this in mind as a relevant point
    .

    More particularly, if you have scrollable layers in your page (besides the whole page itself of course) which you want to have the underlining feature enabled on, then you should not enable the feature on the whole page (boyd tag) but rather page element by page element, or you should enable the page and the scrollable layers too, being sure that no element with this feature enabled is encapsulated within another element with the feature enabled as well (which would be pointless by the way) or the event handlers would criss cross and conflict.

    If you have underlining enabled on the whole page and you also have page nested scrollable layers but you have not enabled this class onto each of them autonomously too, the underlined sections of the latter would scroll as well upon scrolling the layers!
    Though in some circumstances this might be a feature to exploit, I may perhaps suggest to you to enable always item by item, page sector by page sector, assigning ids, rather than the whole page, whenever you have scrollable layers inside the document.

    rangeMaster.("fooid");

    or re-enable on whole page rangeMaster.("body");

    Executive Mansion,

    Washington, November 21, 1864.

    Dear Madam,

    I have been shown in the files of the War Department a statement of the Adjutant General of Massachusetts that you are the mother of five sons who have died gloriously on the field of battle.

    I feel how weak and fruitless must be any word of mine which should attempt to beguile you from the grief of a loss so overwhelming. But I cannot refrain from tendering you the consolation that may be found in the thanks of the Republic they died to save.

    I pray that our Heavenly Father may assuage the anguish of your bereavement, and leave you only the cherished memory of the loved and lost, and the solemn pride that must be yours to have laid so costly a sacrifice upon the altar of freedom.

    Yours, very sincerely and respectfully,

    A. Lincoln


    rangeMaster.("fooid2");

    or re-enable on whole page rangeMaster.("body");

    Four score and seven years ago our fathers brought forth on this continent, a new nation, conceived in Liberty, and dedicated to the proposition that all men are created equal.

    Now we are engaged in a great civil war, testing whether that nation, or any nation so conceived and so dedicated, can long endure. We are met on a great battle-field of that war. We have come to dedicate a portion of that field, as a final resting place for those who here gave their lives that that nation might live. It is altogether fitting and proper that we should do this.

    But, in a larger sense, we can not dedicate -- we can not consecrate -- we can not hallow -- this ground. The brave men, living and dead, who struggled here, have consecrated it, far above our poor power to add or detract. The world will little note, nor long remember what we say here, but it can never forget what they did here. It is for us the living, rather, to be dedicated here to the unfinished work which they who fought here have thus far so nobly advanced. It is rather for us to be here dedicated to the great task remaining before us -- that from these honored dead we take increased devotion to that cause for which they gave the last full measure of devotion -- that we here highly resolve that these dead shall not have died in vain -- that this nation, under God, shall have a new birth of freedom -- and that government of the people, by the people, for the people, shall not perish from the earth.

a Tom Wesselmann painting
A Tom Wesselmann painting