reptile7's JavaScript blog
Tuesday, February 25, 2014
 
Retooling the Tool Tip, Part 2
Blog Entry #311

Welcome back to our discussion of the Java Goodies "Tip Box" script. At this point we have created a custom tool tip and temporarily parked it in the lower-left-hand corner of the document body. To refresh your collective memories, here's what we're working with:

#zTip { background-color: yellow; border: 1px solid blue; color: blue; font-size: 8pt; position: absolute; text-align: center; }
...
<div id="zTip">TipBox Script by dignified<br>For use with MSIE4+</div>


• Not mentioned last time: A CSS length lacking a unit identifier is illegal. I have consequently changed the zTip div's border-width from 1 to 1px.

• The tip value's center element markup has been replaced by a text-align:center; style declaration.

Our next task is to move the zTip div to the near vicinity of the Dignified's Domain link:

with (zTip) { style.posTop = y + 14; style.posLeft = window.event.x + 10; ... }

To reposition the div Ryan reached for Microsoft's proprietary posTop and posLeft properties, which we ran into during our Lissa Explains It All odyssey about a year ago; the original CSS 2 became a W3C Recommendation on 12 May 1998, so Ryan could have used top and left for this operation had he wanted to. As noted/intimated in the Starting offsets subsection of Blog Entry #278, the posTop/posLeft properties have a number data type and their values (a) do not include unit identifiers and (b) are calibrated in pixels in the absence of prior top/left settings.

The top edge of the zTip div is placed 14 pixels below the bottom edge of the Dignified's Domain link. The left edge of the zTip div is placed 10 pixels to the right of the cursor's mouseover position. Regarding the posLeft assignment, I recommend that you check out Dottoro's event.x page vis-à-vis Microsoft's event.x page as the latter features an Example employing the Netscape-cum-W3C event model. FYI: Classical JavaScript has an eventObject.x property that might be relevant if we were mousing over a "layer" (an absolutely/relatively positioned element), but again, Netscape 4.x does not recognize window.event as an event object.

In the name of completeness:
As detailed in the previous post, the y coordinate was obtained by adding the Dignified's Domain link's offsetTop and offsetHeight values. As the link does not actually have an offsetParent (Quirksmode's definition of the offsetParent property is the best that I've seen), the browser determines y according to the viewport coordinate system. The zTip div similarly does not have any absolutely/relatively positioned ancestors (its CSS containing block is the initial containing block) and therefore the posTop/posLeft assignments are also relative to the viewport coordinate system.

As shown above, the posTop/posLeft statements are part of a with statement whose object parameter is set to zTip; we previously discussed the with statement in The new document section of Blog Entry #148. Mozilla's current with statement page warns:
Use of the with statement is not recommended, as it may be the source of confusing bugs and compatibility issues.
As for the use of the zTip id value as an object reference for the tool-tip div, Microsoft itself says we shouldn't do that.

We're not done with the with block yet: at no extra charge it attempts to turn on the zTip div's visibility and gives the div a width based on the length of the tip value.

visibility = "visible";
style.width = src.tip.length * 1.5; // <-- (insert this code if you have frames) document.body.offsetWidth - style.posLeft * 2;


Its incorrect syntax notwithstanding, the visibility assignment is redundant because the zTip div is already visible. Moreover, the width assignment, whose right-hand side needs a +"px" term, is unnecessary if you're going to format the tip text with one or more <br>s, as Ryan has done (it's also unnecessary for a short tip string, of course); indeed, upon bounding the div width the tip text may overflow the div, which would look ugly. Finally, I don't know what the // <-- (insert this code ... comment is about - it seems to suggest that in a frames situation the div width should be a function of the document body width and the div's left offset, which makes no sense to me - I'd delete it if I were you.

Now you see it, now you don't

Mousing out from a tooltipped element makes the tool tip go away. Accordingly, an unTip( ) function that
(a) zeroes out the zTip div and
(b) listens for mouseout events
is registered on the document object.

document.onmouseout = unTip; function unTip( ) { var src = event.srcElement; if (src.tip) { zTip.innerHTML = ""; zTip.outerHTML = ""; } }

Any mouseout event in the document content area triggers the unTip( ) function because the mouseout event bubbles up from the srcElement - the element/object to which the event is dispatched, a.k.a. the event target - to the document object. Upon mousing out from the Dignified's Domain link or any other src srcElement with a tip attribute, the unTip( ) function sets the zTip div's innerHTML and outerHTML to empty strings.

We've worked with the innerHTML property innumerable times but this is our first encounter with the outerHTML property, which when set completely replaces the object, including its start and end tags, quoting Microsoft. By definition, an element's outerHTML includes its innerHTML: it follows that the zTip.innerHTML = ""; statement is superfluous and should be thrown out.

The outerHTML property today has cross-browser support - contra Dottoro, Firefox does in fact support it. Once upon a time the W3C aimed to bring the innerHTML property, the outerHTML property, and the insertAdjacentHTML( ) method into HTML5, but that was then and this is now: the Coding Powers That Be have evidently decided that these members should languish in Nonstandardville.

I am unable to figure out why the script behaves strangely with IE 5.2.3 on my computer so let's just move forward and bring it in line with modern browsers - we'll do that in the next post.

Thursday, February 20, 2014
 
Retooling the Tool Tip, Part 1
Blog Entry #310

Mousing over a renderable body element with a title="Relevant info..." attribute pops up a "tool tip": a small, close-to-the-element box holding the Relevant info... text. Our focus today is a "Tip Box" Scripts that Display Text script that generates custom tool tips.

The Tip Box script was authored by Ryan "Dignified" Detert in November 1998. Joe warns that the script is MSIE 4.0 only and it does in fact contain a bunch of features that Netscape 4.x does not support. On my computer, the script behaves dysfunctionally with IE 5.2.3 and isn't run at all by Firefox, Opera, and Safari. Our task, as always, is to bring the script into the modern era by getting it to work with modern browsers.

The script's demo page is here - if you're an IE user, mouseover the Dignified's Domain link* and see what happens. (Go here for a corresponding demo at a non-https:// page.) At the demo page Joe offers a tipbox/ .zip package that comprises
(1) a complete tipBox.html document for working with the script and
(2) a tipbox.js file that holds tipBox.html's script element code.
Click here to download the package.

*The Dignified's Domain link's href target, http://members.xoom.com/dignified, is supposed to provide commentary on the script but is no longer available.

That which is tooltipped

The following anchor element is the business end of the tipBox.html HTML:

<a href="http://members.xoom.com/dignified/" tip="<center>TipBox Script by dignified<br>For use with MSIE4+</center>">Dignified's Domain</a>

The anchor's noteworthy feature is its tip attribute, which is not standard; the tip value will serve as the (hyper)text for a customized tool tip. For now the browser ignores the tip attribute; per the Notes on invalid documents section of the HTML 4.01 Specification:
If a user agent encounters an attribute it does not recognize, it should ignore the entire attribute specification (i.e., the attribute and its value).
While we're at it...

The to-be-tooltipped anchor's unvisited/active/visited colors are set by the body element's start-tag:

<body bgcolor="white" text="blue" link="red" alink="#00ff00" vlink="red">

Deprecated all, the body attributes will be traded in for style declarations in due course.

The anchor is horizontally centered with a center element, which is immediately preceded by a <base target="_parent"> base element that
(a) if the anchor were clicked and
(b) if we were in a frames situation
would replace the parent frameset with the anchor's href resource.
FYI: The base element should be placed in the document head, and would require a href attribute for a strict validation.

A tip for our tool

Before the document body loads, a toolTip( ) function that listens for mouseover events is registered on the document object:

<script language="JScript"><!--
document.onmouseover = toolTip;
...
</script></head>


IE 4.x allows a direct onmouseover-document association but Netscape 4.x doesn't. (For Netscape 4.x an indirect onmouseover-document association is possible via the captureEvents( ) method, but this being the year 2014, let's not go down that road, shall we?) With IE 4.x, mousing over any element in the document body calls the toolTip( ) function because
(a) IE 4.x supports event bubbling and
(b) the mouseover event bubbles.

The toolTip( ) function begins by setting the window's status property to an empty string:

function toolTip( ) { window.status = ""; ... }

The window.status assignment is irrelevant to tool-tip generation and can be thrown out. Next, the toolTip( ) function gets the object that 'fired' the mouseover event:

var src = event.srcElement;

Netscape 4.x supports neither event as a property of the window object nor the srcElement property. For reasonably complete discussions of the IE and Netscape event models, see WebReference.com's "The Internet Explorer Event Model" and "The Navigator Event Model".

The rest of the toolTip( ) function consists of an if statement that is operative if the src object has a tip property:

if (src.tip) { ... }

The src.tip if condition returns true with IE upon mousing over the Dignified's Domain link. As far as I am aware, IE is the only browser that will automatically convert a nonstandard element attribute to a corresponding object property and is consequently the only browser that can get past the src.tip gate.

The if statement first adds src.offsetTop and src.offsetHeight to get the y-axis coordinate of the bottom of the Dignified's Domain link (more precisely, the bottom of the link's border box) and assigns the sum to a y variable:

var y = src.offsetTop + src.offsetHeight; // Set top of tip to bottom of src

Go here for concise definitions of the offsetTop and offsetHeight properties; Netscape support for these properties began with Netscape 6. Contra the // Set top of tip to bottom of src comment, the top edge of the custom tool tip will not be set at y but slightly below that.

The y assignment is followed by the script's key operation: an insertAdjacentHTML( ) command that creates and displays the custom tool tip.

document.body.insertAdjacentHTML("beforeEnd",
"<div id='zTip' style='visibility: visible; z-index: 10; background-color: #ffffff; position: absolute; font-Size: 8pt; border: 1 solid blue; color: blue; background-color: yellow'>"
+ src.tip + "</div>");


The almost-self-explanatory insertAdjacentHTML( ) method is somewhat like the DOM's Node.insertBefore( ), Node.firstChild, Node.appendChild( ), and Node.nextSibling members all rolled into one. It takes two parameters:
(1) a where first parameter that specifies a location at which to insert some HTML and
(2) an html second parameter that specifies the HTML to be inserted.
Implemented by Microsoft, the insertAdjacentHTML( ) method is today supported by IE, Google Chrome, Opera, and Safari, but not by Mozilla's browsers.

The preceding command's calling object is the document.body object and its where parameter is set to beforeEnd, meaning that the html HTML is placed at the very end of the document body, as though we were executing a document.body.appendChild(html) command.

The command's html argument defines a div element container for the custom tool tip. The div is charged with the src anchor's tip value, has an id='zTip' identifier, and is given various styles.

Style notes

• The visibility:visible; declaration can be thrown out as visible is the initial value of the visibility property.

• The div's background-color is set twice, first to white and then to yellow; as determined by the CSS cascading order, the latter is what we see.

• The div is absolutely positioned but not given top and left settings; as a result, the div is (per the beforeEnd insertAdjacentHTML( ) setting) vertically placed just below the document body's concluding center element

<center>&lt;a href="http://members.xoom.com/dignified/" tip="Please Click Here"&gt;Click Here&lt;/a&gt;<p>
<!-- There's no </center> in the source. -->


and is given a normal-flow left (margin-left:8px;) position.

• The z-index:10; declaration can also be removed: more specifically, a z-index setting is unnecessary unless the div is moved to a position at which there's another absolutely positioned element that itself has a "positive stack level", i.e., whose z-index > 0, which is possible but unlikely.

Before moving on:
The insertAdjacentHTML( ) method has an afterBegin where value that puts the html HTML at the very beginning of an element (just before its firstChild). We could have used afterBegin in place of beforeEnd for the insertAdjacentHTML( ) command given that the zTip div is absolutely positioned and thereby removed from the normal flow of the document anyway.

We'll continue our deconstruction of the Tip Box script in the following entry.

Tuesday, February 11, 2014
 
Does Anybody Really Know What Time It Was?
Blog Entry #309

It's been a couple of months since the last reptile7's JavaScript blog entry so let me get back into the groove with something simple. In today's post we'll check over the Scripts that Display Text collection's "Full Date Since…" script, which was authored by Jay Reed in February 1999. The Full Date Since… script prints out for the user two time-related pieces of information, namely,
(1) the time at which the user arrived at the current page and
(2) the time at which the current page was last modified.
You can access the Full Date Since… script here and see its effect here.

The script

In February 1999 the current versions of IE* and Netscape were IE 4.x and Netscape 4.x, respectively. (*Beta versions of IE 5 had been released and a final IE 5 version was out a month later.) A complete separation of structure, presentation, and behavior was possible with IE 4.x but not with Netscape 4.x, so to accommodate users of the latter browser(s) Jay formulated the Full Date Since… code as a single all-encompassing script element:

<script language="javascript"><!--
/* Written by Jay Reed Mental8383@yahoo.com, Mental8300@aol.com
Permission to use granted to all who keep this text enclosed
http://come.to/reed */
document.write("<b><font size='3' color='navy'> You have been here since:<br><tt><font size='3' color='red'> " + Date( ) + " </font></b><br>");
document.write("<b></font><font size='3' color='navy'></tt>Page last updated:<br><tt></font><font size='3' color='red'> ");
document.write(document.lastModified);
document.write(" </font></b></tt>");
//-- end Date --></script>


Time outputs

Arrival

We get the You have been here since: time (and a bit more) by simply writing Date( ) to the page. Mozilla explains:
Calling [JavaScript's Date] as a regular function (i.e., without the new operator) will return a string rather than a Date object.
With Firefox, Opera, and Safari on my computer, the Date( ) output has the following format:

Fri Feb 07 2014 13:00:00 GMT-0800 (PST)

If you just want to display the time without the date at the beginning or the time zone stuff at the end, then you can trim the Date( ) string with the String object's substring( ) method, i.e., Date( ).substring(16, 24).

More modernly but less consistently, a new Date( ).toLocaleTimeString( ) command will also give us a time string.
• Firefox's toLocaleTimeString( ) return is based on a 24-hour clock: 13:00:00
• Opera's toLocaleTimeString( ) return is based on a 12-hour clock and includes an AM/PM designator: 1:00:00 PM
• Safari's toLocaleTimeString( ) return is based on a 12-hour clock and includes AM/PM and time zone designators: 1:00:00 PM PST

Modification

We (attempt to) get the Page last updated: time by reading the lastModified property of the document object. Specification-wise, document.lastModified goes back to JavaScript 1.0, currently has a DOM Level 0 status, and is being brought into HTML5. We very briefly discussed document.lastModified way back in Blog Entry #13 but haven't seen it since.

In order for document.lastModified to provide the document's last modification date and time, the server must be configured to include an HTTP Last-Modified header when it serves the page. In the absence of a Last-Modified header the W3C declares that document.lastModified must return the current date and time
(a) in the form MM/DD/YYYY hh:mm:ss and
(b) in the user's local time zone.
Upon testing these criteria at several high profile Web pages* that are not served with a Last-Modified header, I find that Firefox complies with both (a) and (b) whereas Opera and Safari comply with (a) but give a UTC time (and presumably date) for (b).

*http://www.google.com/, http://www.yahoo.com/, http://www.msn.com/, and http://www.nytimes.com/, whose HTTP headers were determined via Rex Swain's HTTP Viewer.

Style

Excepting the br elements, the document.write( ) parameter markup
(1) serves a purely presentational purpose (an argument can be made that the <br>s also serve a presentational purpose) and
(2) is improperly nested (or would be improperly nested, if we were writing the markup normally and not scriptically).

The font and tt elements are defined in the "Alignment, font styles, and horizontal rules" chapter of the HTML 4.01 Specification. The font element was deprecated by HTML 4 but the tt element wasn't; both elements appear in HTML5's Non-conforming features section: Elements in [this] list are entirely obsolete, and must not be used by authors.

According to the CSS 2.1 Specification, a size='3' font element attribute should map onto a font-size:medium; style declaration, and that's what I observe on my computer. As medium is the initial value of the font-size property we can just throw out the size='3' attributes without replacing them with anything. The color='navy' and color='red' font element attributes can and should be respectively replaced by color:navy; and color:red; style declarations.

The tt element renders [its text content] as teletype or monospaced text. (Do you know what a teletype is? I didn't, and had to go look it up.) The tt markup can be traded in for a font-family:Courier,monospace; declaration.

You can keep the b elements if you want - they're legit in both HTML 4.x and HTML5 - but in the name of clutter reduction I myself would exchange them for a font-weight:bold; declaration.

Structure

HTML features a samp element for designating sample output from programs, scripts, etc. and that would be appropriate for marking up the aforediscussed time outputs. The browsers on my computer render samp text in a monospace font, so you could probably lose the font-family:Courier,monospace; tt replacement depending on how important it is to you.

The time outputs can be loaded into the samps via a window.onload-triggered function:

window.onload = function ( ) { document.getElementById("sinceSamp").innerHTML = Date( ).substring(16, 24); document.getElementById("updateSamp").innerHTML = document.lastModified; }
...
You have been here since:<br>
<samp id="sinceSamp"></samp><br>
Page last updated:<br>
<samp id="updateSamp"></samp>


The body element has a block-type content model in the X/HTML Strict DTDs and a flow-type content model in the X/HTML Transitional DTDs so the widget as a whole should be placed in a div element if you're going to strictly validate the container document; an outer div is unnecessary for a transitional validation or for no validation at all but still makes sense from a semantic viewpoint.

Demo

You have been here since:

Page last updated:


FYI: The http://reptile7.blogspot.com/2014/02/does-anybody-really-know-what-time-it.html page does return a Last-Modified header.


Powered by Blogger

Actually, reptile7's JavaScript blog is powered by Café La Llave. ;-)