Page Notes Guide and Reference

Created by  Jim Williams  © 2004-2009
version 0900316

1. What Page Notes Do

Overview, content of this web page

This article describes — and demonstrates — a proposed Page Notes language extension to HTML.  The proposed page notes have the following characteristics:

  • They are described by note links, where the link destination is an annotation.  They're miniature hyperlinks used for small pieces of information.

  • The annotation is combined with a note skin to form a page note. Note-specific javaScript isn't needed for page notes.  And the full power of HTML is available for specifying annotations and note skins.

  • The page note is displayed when the cursor pauses over a link source.
    This contrasts with the behavior of popup windows, which are frequently not under the viewer's control.

  • The positioning of page notes is flexible and highly automated. Page notes may be placed either above or below the link source.  They may be aligned with the link source or with its containing line, block, or page note — or even the mouse.  Imagine: The yellow page note follows the cursor over the aqua-on-red paragraph that is its link source.

  • Annotations may themselves contain link sources, leading to a stack of page notes with each level in the stack serving a different purpose. For example, consider a stack serving the following purposes:

    1. Demonstration   

    2. Motivation   

    3. Clarification   

    4. Illustration   

    5. Recapitulation   

    6. Rationale   

    7. Conclusion (implementation constraint)

Sections 2-5 of this page provide information on how to use the Page Notes mechanism.  Section 2 introduces the HTML and CSS portions of the Page Notes language extension and explains how page notes work.  Section 3 describes a programmatic interface for Page Notes.  Section 4 provides the example note skins used in this article.  Section 5 describes some sample web pages illustrating the advantageous use page notes. 

Sections 6-8 are largely geared towards those who may choose to standardize and implement the Page Notes mechanism.  Section 6 contains a short glossary whose entries are used to annotate initial occurrences of key terms.  Section 7 presents technical requirements that motivate the design of the Page Notes language extension.  Section 8 discusses the Page Notes reference implementation and explains how to compile documents to display correctly in both Firefox and Internet Explorer.  Finally, Appendix A discusses image annotations.


2. Using Page Notes in a Web Page

— with details

The page-note mechanism is illustrated by the following diagram, which also doubles as a linked outline for this section:

The link source is annotated with nref and nskin attributes, which point to an annotation and a note skin, respectively.  When the mouse pauses over the link source, it triggers a mouse stay event and, in response, Page Notes instantiates the note skin with the annotation and displays the page note.  As discussed below in Section 3, the onmousestay event mechanism is part of the Page Notes reference implementation.

2.1  Mark the Link Source.

Mark the link source with the Id of the note skin, a reference to the annotation, and style attributes that will help distinguish the link source from surrounding material.  In the following example, the link source is "mouse stay event":

<span          
nref="#mousestay"
style="
    nskin:skin-gold;
    color:#905500; cursor: default; active:{color:#DD8800};
mouse stay event </span>         

.  .  .  .  .  .  . 

<span id="mousestay">Actions performed when the mouse stops on a designated element in a web page.</span>This is the annotation for the link source.

2.1.1 The element tag

Any HTML element may be used as the link source for an annotation.  In particular, Area tags are used for annotating mapped images  [ caveat:  See Section 8.1 ].  As explained below, the <a> tag needs to be used with restraint, due to a potential conflicts between the hover and active attributes.

2.1.2 Specifying annotations, the values of nref

The nref attribute describes the annotation for the page note [ caveat see Section 8.1 ].  If the nref attribute is omitted, the note skin itself will be displayed as the page note.  Setting nref = "pending" causes Page Notes to activate the link source without posting a page note.

As with most HTML attributes, nrefs may be given as styles.  In particular, a default annotation may be assigned in a style sheet and then overridden with inline styles.  For reasons of standards compatibility, assignments made in style sheets may not be overridden with inline attribute assignments.

An nref can be any of the following:

  1. an Id selector designating an annotation, as in the above example.
  2. an expression whose value is a general Id selector, as for example, in a term definition or an augmented href.

  3. an expression whose value is a document element, as in the elided text example.

Annotations may be found via table look up.  In the following simple example, the annotation is found from the text of the link source; where this refers to the link source under the cursor:

.pop-def {  nref: "#" + this.innerHTML;
nskin:skin-gold; placement:above;
font: bold 12pt serif; color:#BB0055  }

   . . . . . .
<a class="pop-def">πατερ</a>

   . . . . . .
πατερ - <span id="πατερ">father, forefather, ancestor</span>

father, forefather, ancestor
The same <a> element can be both a page note reference and a traditional hyperlink, allowing the reader to peek at the content of the hyperlink's destination anchor before clicking on the link:

.peek { nref:getIdSelector(this);
    nskin:skin-gold; placement:above };

   . . . . . .

function getIdSelector(anchr)
{ gets the Id selector portion of a local href }

. . . . . .

<a class="peek" href="#section2">See Section 2.</a>

   . . . . . .

<h2 id="section2">2. How Page Notes Work</h2>

[ details ]

In this example, if you set .peek.active, then you probably want a.peek:hover to be the same as .peek

Why?  In the reference implementation, the hover event occurs before the page note is activated and terminates before the page note is deactivated.  Upon deactivation, the Page Note script "restores" the link source to the state it was in at the time the page note was activated ....

You can specify that the annotation immediately follow the link source as a span of hidden text.  This is a convenient way of dealing with elided text:

.elided { nref:this.nextSibling;
nskin:skin-green-left; placement:above source-line; color:#00FF22; }

   . . . . . .

was caught with <span class="elided"> ...  Damaged original  </span><span class="hide"> Damaged original  </span>

2.1.3 Link Styles

CSS class names may be used in place of inline styles in the usual way.

2.1.4 The note skin

The nskin attribute specifies the note skin to be used and largely determines the format of the page note.  In principle, any HTML object may be used as a note skin. 

If the nskin attribute is omitted, a default skin is used instead.  Setting nskin="pending" will cause Page Notes to activate the link source without posting a page note. 

2.1.5 Styles for link sources

Typically, additional style attributes are included in order to distinguish the link source from surrounding text.

Attributes that apply only while the link source is active (that is, while the page note is displayed) may be given by the optional active attribute.  The value of the active attribute is an arbitrary style-rules list.  (Note that arbitrary style lists are allowed as attribute values under the W3C's draft CSS3 syntax CSS3 module: Syntax, Section 4.3.2, "Style sheets," W3C Working Draft 13, August 2003.)

2.2  Provide the annotation.

In the above example, the associated annotation is the the anchor whose Id is "mousestay":

<p><b>Mouse Stay Event:</b> <span id="mousestay">Actions performed whenever the mouse pauses over a designated element in a web page.</span>

If the annotation is to be displayed only in a page note, hide it with the attribute style="display:none".   This works because the outer tag and any accompanying attributes are discarded when the annotation is displayed.  That is, only the inner HTML of the annotation is displayed in the page note.

Only the id attribute is supported  (not the name attribute).

2.3  Design a note skin.

Design a note skin for the page note, for example:

This particular note skin is one of the examples from Section 4.  It consists of an outer div element (dotted line), some structural material (bronze square, cream background), and a variable, the HTML element <var><b>Enhance</b> quality, appearance, and understanding</var>

For ease of discussion, let us consider a couple of especially simple examples:

<div id="small-menu-box" style="width:330; display:none;">

<table style="border-collapse: collapse"
  border="1" bordercolor="#7B6600" bgcolor="#FFFFF4">
  <tr style="font-size: 9pt; font-family: san-serif">

<td><var> small-menu-box </var>

</table>

</div>  

<div id="small-menu-div" style="width:330; display:none;

border: 1px solid #808C90; padding:3;
font-size: 9pt; font-family: san-serif;
background-color: #
FFFFF4">

<var> small-menu-div </var>

</div>  

2.3.1 Function of the outer div element

The outer div for the note skin determines its width and is interpreted directly by the Page Note mechanism. 

The width of the page note is determined from width information in the outer div of the note skin and from its placement.  First, a maximum note width is calculated as follows:

  1. If no width information is given, a default maximum width is the width of the associated source container [ see below ].

  2. If a specific width is given (e.g., as style=width:300pt"), this is taken as the maximum width of the page note.  If the width is given as a percent, it is treated as a percent of the default maximum width.

  3. If the maximum width is less than minNoteWidth (whose default value is 30px), it is adjusted upwards to minNoteWidth.

Finally, the note skin is instantiated with the annotation, and its actual width is adjusted downward to the maximum note width, if necessary.  One could argue that the name of this note-width attribute should have been max-width.  But the implementation uses width attributes in calculating the note-width, not max-width attributes.

The outer div for a skin contains the id referenced by the nskin attribute.
Specifying width in the containing div allows the width of the table to shrink if there is insufficient content to fill the box. 
Specifying width in the containing div when the structure is the div itself leads to a fixed-width box. 
The display:none attribute in the outer div just hides the skin.  When the page note is displayed, any display, visibility, position, top, or left attributes in the skin's outer div are overridden in the process of displaying the page note.  Other attributes in the outer div are carried over into the page note.

2.3.2 Specifying the layout of the note skin

Often, a skin's structural material is just a one-cell table or more simply, just a formatted div element, as in the two especially simple examples above.

In the first of these examples, the structure is specified via a table tags, including border, background color, and default font characteristics.  In the second, these attributes are contained in the outer div itself.

2.3.3 Skin variables

HTML variables in the skin show how the annotation is to be used when the note is instantiated. 

If only one variable is present in the note skin, it is replaced with the annotation's inner HTML when the note is instantiated.  If there are several variables, they are replaced with the elements of the annotation's child list  [ example ].  Variables may be numbered in order to control their order of instantiation [ example ].

The 2for1 note skin in Section 4 of this document illustrates the use of two variables:

<span style="nskin:2for1; color:#3333CC" nref="#multivariate">
Like to see an example? </span>

 . . . . . .

<p id="multivariate" style="display:none">

<span><!-- Child 0: --> Why multivariate skins? </span><span>
     <!-- Child 1: --> <font color = "#990088">
So titles and text bodies can have different formats! </font></span>

The greek-and-english skin in Section 4 illustrates the use of numbered variables by taking a definition in which the Greek term appears first, and displaying it in a page note in which the English is above the Greek:

<span style="nskin:greek-and-english; color:#3333CC"
nref="#multivariate2">
father </span>

 . . . . . .

<p id="multivariate2" style="display:none">

<span style="font-weight: bold; font-size: 12pt;
font-family: symbol; color:#BB0055">
<!-- Child 0: -->
πατερ </span><span>
<!-- Child 1: -->
father, forefather, ancestor </span>

Why multivariate skins?    So titles and text bodies can have different formats.    

πατερ father forefather, ancestor   

2.4  Provide placement information.

Optionally, provide placement information on where to display the page note.  For example, we could specify that the note appear above its link source:

<span          
nref="#mousestay"
style="
    nskin:skin-gold;
    color:#905500; active:{color:#DD8800};
    placement:above"
mouse stay event </span>         

The arguments of the optional placement style attribute specify horizontal and vertical placement relative to a source container.  These attributes may be specified in any order:

placement: [indent m ][above|below [ n ]][source container];

Page notes are aligned with the left edge of the source container, with an optional  indent  m  offset.  Positive values move the page note  m  pixels to the right.

Vertical placement is determined as follows:

above  

above the source container, if there is sufficient room, otherwise below.

below  

below the source container, if there is sufficient room.  This is the default.   

n  

vertical offset; positive values move the page note away from the source container.

The placement of a page note may be any given relative to any of the following containers:

source

the link source itself; this is the default

source-line

line containing the link source

source-block 

smallest block element containing the link source

source-row 

table row containing the link source

note-line  

source line, extended to the left edge of the containing page note

note

page note containing the link source

cursor 

locations of the cursor as the cursor moves and pauses over the link source

2.5  Invoke the Page Notes mechanism.

This section explains what the Page Notes JavaScript does when you embed it in your Web page.  Page Notes maintains a stack of active links and their associated page notes, with one level for each active link, as in the following diagram:

To actually use the script, it suffices to upload it to same folder as your web page and include the following line in your page header.  However, this version of the script is written to work only in Internet Explorer version 5.5 or in later versions of Internet Explorer operating in "quirks" mode.  (In other words, don't include a complete doc type at the beginning of the HTML file.)

     

Page Notes handles the mousestay event in such a way as to achieve the following results:

  1. If the cursor is not over a link source or an already displayed page note, the stack is empty.
  2. If the cursor is over a link source, then that link source and its associated page note are at the top of the stack. 
  3. If it is over a nested pair of link sources, then the inner link source is directly above of the outer link source.
  4. If the cursor is over an already displayed page note, then that page note remains in the stack.  If the cursor is not also over a link source, then that page note is at the top of the stack.

3. Programmatic Interface

Extending the Page Notes mechanism

User scripts may be used to calculate nrefs and to dynamically modify page notes.  User routines may interact with the Page Notes mechanism via the following interfaces:

  • The onmousestay event object
  • Event handlers for onmousestay
  • Page Note interface functions

3.1 User-supplied default nref attributes

The algorithmic specification of nrefs allows for a wide variety of table lookup functions to be used in specifying nrefs.  The getIdSelector function mentioned in Section 2.1 is a relevant example.

function getIdSelector(anchr) 
{ 
      var anno = anchr.getAttribute('href'); 
      if (anno.slice(0,1) == "#") return anno; 
      // Possibly, we have a local href with a nonlocal name: 
      var re = "^" + document.location.href.replace(/#.*/, ""); 
      var docHref = new RegExp(re); 
      var selId = anchr.replace(docHref, ""); 
      if (selId.slice(0,1) == "#") return selId; 
      return ""; 
}  

3.2 The onmousestay Event Object

The event object created by the onmousestay event includes the following components [ details ]

Primary event components
  .target html element under the cursor when the mouse pauses
  .noteLink note link associated with the link source under the cursor
  .outerLink corresponding outer link in the case of nested link sources
  .pageX,.pageY cursor position when the mouse paused
  .inHref
  .errorFlag
whether the mouse paused on an href
whether an error has occurred
Other nEvent components
  .parentNote the page note containing the link source
This is the target object from the last mouse-move event before the mouse pauses.  For Internet Explorer, .target coincides with the .srcElement object from this event. [ cf. MSDN description: ] MSDN Home >>> srcElement Property

There can be at most one posted page note containing an active link source.  This is true for a constructed page note because the note's only ancestor is the body element.  In the reference implementation at least, this is also true for a positioned page note because the reference implementation does not support nested note skins.

The outerLink field is null except in the case where there is a nexted pair of link sources.  These noteLink and outerLink objects contain the following fields:
 
  .source  inner or outer link source under the cursor; .source contains nEvent.srcElement as a sub-object.
  .anno associated note-link destination; specified by an nref attribute
  .skin associated note skin; specified by an nskin attribute
  .note the resulting page note, if posted
In MSIE, the position of the cursor at the time of the mousestay event is (nEvent.pageX, nEvent.clientY).

The inHref and errorFlag values are used to solve a problem concerning the content of the status bar. 

It seems that IE is not above writing "Done" in the status bar after posting a page note.  Then IE won't own up to what it did, claiming that window.status is empty!  If inHref and errorFlag are both false, Page Notes corrects the annoyance by explicitly clearing window.status

If you want to write to window.status, be sure to set errorFlag.  If you want to do error recovery, clear both window.status and errorFlag when you're done.

If there are two note link sources under the cursor, the mouse stay event fires twice, first for the inner link source, and again for the outer link source. 

3.3 onmousestay Event Handlers

Event handlers for onmousestay are created in the same way as other event handlers. However, because the Page Notes reference implementation is itself a script, there are constraints on whose script runs first [ details ].

There various scripts have to run in this order:

  1. The prior-to-load portion of pageNotes.js

  2. Your prior-to-load scripts

  3. The onload event handler for pageNotes.js

  4. Your onload event handler, if present.

[ more ]
It suffices to include the following code fragment in the main body of your script:

var pnPriorOnload = window.onload;
window.onload = pvtOnloadHandler;

// Call the Page Notes onload event, if appropriate:
function pvtOnloadHandler()
{
      try { pnPriorOnload();}
      catch(e){ Alert("pageNotes.js failed to load properly") };


 . . . . . .

}

You can set an onmousestay event handler on the window object.  If your event handler returns false, that will cancel any further actions, preventing subsequent removal of old page notes, activation of new link sources, and posting of new page notes.  A simple use of this fact is to preserve posted page notes while the user mouses over to the scroll bar (e.g., because a page note is too large to fit on the screen).

When coordinating event handlers, it is useful to know the order of invocation: Whenever an onmousedown or onmouseclick event happens, an onmousestay event happens immediately before that, and again immediately before an onmouseup event [ caveat ].  Finally, the onmousestay event for an object happens after the corresponding onmouseover event.  The onmousestay event occurs after it's event object is set but before any page note activations. 

When the the cursor gets close to the right hand side of the screen, the browser stops tracking the cursor.  The following event handler returns false in this case, thereby canceling the removal of page notes:

window.onmousestay = mayHandleMouseStay;
function mayHandleMouseStay()
{
    var marginRight = parseInt(
        cascadedStyle(document.body, "marginRight"));
    var cancelMin = document.body.clientWidth - marginRight;
    if (nEvent.cursor.pageX < cancelMin) return true
    else return false
}

Activate this Example

The document body's default right hand margin is 10px in IE and 8px in Firefox.

3.4 Dynamic page note modification

The effect of dynamically modifying a page note depends on how it was created. When a constructed page note is displayed, a fresh copy of the page note is created by the instantiation mechanism.  Modifying the displayed page note will not affect either the annotation or the note skin, and the modification will be lost after the page note display has been taken down.

If there is no annotation, that is, if the nref attribute is missing, then the skin itself is used as the page note; it is not copied but simply moved directly into place.  In modifying one of these positioned page notes, you are modifying the note skin itself, and the change will be visible the next time the note is displayed.  The above preserve posted notes example illustrates the use of positioned page notes.

3.5 Page Note Interface Functions 

Page Notes makes the following functions available for use in writing application scripts:

displayPageNote Activates the note-link source and displays the note  
activateLinkSource  Activates the note-link source
instantiate Instantiates the the note skin with the annotation
cascadedStyleExtends MSIE's currentStyle
The displayPageNote(srcId) and activateLinkSource(srcId) functions take the Id of the HTML element to be displayed or activated.  For example, the onload event handler for this page contains the following sequence:

displayPageNote("documentTitle");
activateLinkSource("section1");
activateLinkSource("section2");

The function call, instantiate(node, skin, annotation), copies skin to node and replaces the variables in skin with the inner HTML of annotation (in the case of a one-variable skin) or replaces each variable with the corresponding child of annotation (in the case of a multi-variable skin). 

The function call cascadedStyle(elem, attr) returns the same result as Internet Explorer's elem.currentStyle(attr), except that attr may be un-camelized, and there is a consistency check between style-attribute information and inline attribute information.

For example, {placement:above} is inconsistent with placement="below" because the style sheet rule overrides the more local inline designation, contrary to the usual convention that local information overrides remote information.

One easy use of these functions is to display key page notes when the web page is loaded.


4. Sample Note Skins

The green skins are box-less.  Gray's width is 100%.  Gold has a maximum width.  Red is indented.  Blue is unconstrained.  The red-and-gold is multivariate.

skin-green (unspecified width, right justified, no border, line raised 3px):

 

Create new ideas, products, and realities

skin-green-title (unspecified width, centered text, no border):

Create new ideas, products, and realities

skin-green-left (unspecified width, line raised 3px):

Create new ideas, products, and realities

skin-gray (table version, width is 100%):

Validate with evidence, proof, data, and details.

skin-gray-div (div version, width is unspecified):

Validate with evidence, proof, data, and details.

skin-gold (max width is 310):

Enhance quality, appearance, understanding, and appreciation.

gold-veil (semi-transparent background):

Enhance quality, appearance, understanding, and appreciation.

skin-red (indented):

Attract patrons, clients, followers, and allies.

skin-blue (no specified width):

Respond to discrepancy, error, malice, and false consensus.

2for1 (no specified widths, indented):

Combine desire and reward
  In the same note 

greek-and-english (numbered variables):

1. English definition
0. Greek word

small-menu-box (max width is 330):

small-menu-box

small-menu-div (width is 330):

small-menu-div

 


5.  Sample Web Pages

Where the rubber meets the road

A few applications have been developed in order to illustrate skillful use of the Page Notes mechanism and reference implementation.

5.1 This Reference Manual

This manual illustrates all of the basic Page Note functions and doubles as an initial test suite for the reference implementation.  It's opening paragraph constitutes an advertisement for, and demonstration of the key Page Note features.  The bulk of the material in this manual is hidden in the annotations, thereby making it easy for the reader to scan topics and retrieve needed information, and thus justifying the claim that this page serves simultaneously as a guide and a reference document.

5.2 Translations of the Lord's Prayer

The first real application for page notes involved online translation of an ancient Greek text.  In The Lord's PrayersThe Lord's Prayers, each translated English word is annotated with the Greek word that it translates and with alternate English translations.  In addition, phrases and sentences are often annotated with comments on the consequences of the chosen translation.  The application script for this page uses Page Notes to implement annotated drop-down menus and uses dynamic style sheets to control the content of the lexical annotations.  These techniques are further discussed in the page's Programming Notes. Lord's Prayers Programming Techniques These pages have not been compiled for Firefox and display correctly only in Internet Explorer.


6. Glossary

Sample link destinations used in this document

The items in this brief glossary have been formatted in several different ways, in order to show how variations in destination style affect the appearance of the resulting page note.
 

Fragment URL

A URL ending with "#" followed by an identifier denoting an anchor in the document named by the URL.

—  cf W3C: HTML 4.0 Specification   

Hyperlink

A link providing direct access from one distinctively marked place in a hypertext document to another in the same or a different document.

 cf Merriam Webster  

Mouse Click Event:  Actions performed in response to depressing and releasing a mouse button.        —  cf Dictionary.com

Mouseover EventActions performed whenever the mouse passes over a designated element in a web page.          cf Webopedia

Mouse Stay Event

Actions performed when the mouse stops on a designated element in a web page.

Note Skin:

A template used to separate layout from content.  Skins provide size, shape, color, texture, and other layout characteristics.

Onload Event:  Actions performed immediately after the browser loads a document.      cf Microsoft Developer Network

Page Note

The appropriately formatted display of an annotation on an HTML element. 

Popup (or Pop-Up):

A window or other display superimposed over the content of a browser window. 

 cf TheFreeDictionary  

SetTimeout Method:  Initiates action after a specified number of milliseconds has elapsed.      cf Microsoft Developer Network


7. Page Note Technical Criteria

Without requirements, language design is easy — and worthless.

This section lists eighteen key design requirements behind the Page Notes mechanism.  These requirements assume a basic model in which there is mechanism for associating a link source with an annotation and for the controlled display of the annotation in the form of a page note.

7.1 Content Requirements

  1. Styles for Active Link Sources 

    Arbitrary inline styles are available for highlighting active link sources, where an active link source is one that is currently associated with a displayed page note.

  2. Generality of Link Sources

    Any visible HTML element may be used as a link source.  Link sources may be nested. 

  3. Annotation Locations 

    The annotation referenced in a note link may be in a different file from the note link, as for example, in a file of definitions or bibliographic entries. 

  4. Multiple Link Sources with the Same Annotation

    The same annotation can be displayed by several link sources.

  5. Page Note Formats

    Page note formatting supports background, borders, margins, and boiler-plate text formatted using arbitrary CSS and/or HTML attributes.

  6. Page Note Format Sources

    The formatting of the displayed page may be controlled via attributes from the link source and its associated annotation.

  7. Define-Once, Use-Many Styling

    Styles for link sources, annotations, and page notes may be defined once (e.g., via CSS) and then used for multiple link sources, annotations, and page notes, respectively.

  8. Absence of Extraneous Graphical or Stylistic Features

    Window dressings, including menus, toolbars, scroll bars, and ISP icons, are limited to those chosen and intended by the web developer.  

7.3 Note Activation and Display Requirements

  1. Page Note Stacking

    Displayed page notes may themselves contain explorable note-link sources, independently of whether their display is contiguous with their associated link source.

  2. Ease of Display

    Page Notes are displayed and taken down with a minimum of reader effort, as the reader's attention moves to and away from a link source. 

  3. Cursor Movements

    The cursor may be moved from an active link source to its displayed page note in order to explore active content in the displayed note. 

  4. Absence of Spurious Note Displays
    Displays are not triggered by events which are not reasonably within the reader's control.  In particular, displays are not triggered by accidental mouseovers while the mouse is being dragged across a page. 
  5. Note Positioning Capabilities
    Page notes may be positioned above, below, left, or right of nearby objects such as the cursor, their associated link source, containing source block, or containing page note.  In particular, the displayed page note need not be contiguous with its associated link source.
  6. Preserving Note Visibility  
    The display mechanism is able to override specified note positioning when necessary in order to preserve visibility of the displayed note.  In particular, when nested link sources are activated, the resulting page notes need not overlap inappropriately.
  7. Programmatic Interface

    It is feasible to write scripts which are cognizant of displayed page notes and which integrate smoothly with the page-note display mechanism.

7.4 General Requirements

  1. Compatibility With Existing Conventions

    There is no need to learn new techniques for specifying effects that, in essence, are already defined elsewhere (e.g., in CSS, HTML).

  2. Notational Efficiency

    The notation is both efficient and convenient, even for heavily annotated passages, even when the number of annotations exceeds the number of words.

  3. Ease of Learning

    The basic page note mechanism is simple, intuitive, and easily learned.

  4. Documentation and Implementation

    Complete documentation is publicly available, as is a demonstrable reference implementation.  A browser-independent implementation is feasible without major changes to existing browsers.

7.5 Observations on the requirements

Requirement 2 on the generality of link sources is what motivates Appendix A on the annotation of images.

Of the well-known cursor-related events, mouseovers are clearly superior to mouse clicks in the satisfaction of Requirement 10 on ease of display.  Notice, however, that events such as onmousemove and onmouseover are not directly feasible for triggering displays, due to an apparent conflict between Requirement 11 on cursor movements, and Requirement 13 on page note positioning.

Currently, the defined programmatic interface allows for page note display without an associated mouse stay.  Thought needs to be given as to how this feature may be constrained (or eliminated) in order ensure Requirement 12 on the absence of spurious page note displays.

Requirement 14 on preserving note visibility is not intended to override normal web-developer responsibilities, e.g., regarding physical display width.

Requirement 3 on the location of annotations is something of a challenge to implement well.  Speed clearly favors the case where there is only one or a few annotation files that can be loaded once and used repeatedly for different annotations.


8.  Reference Implementation

No spaghetti code here.

The page notes in this document are displayed without any use of note-specific script.  Their behavior is entirely the result of the the reference implementation of the proposed language extension. 

Section 8.1 lists known discrepancies between the the reference implementation and the language extension as currently proposed.  Section 8.2 presents additional features of the reference implementation that may be useful in writing scripts.  Sections 8.3 through 8.5 present the design of the reference implementation.  Finally, Section 8.6 presents the compilation step used to get around the fact that Firefox doesn't support new user-supplied style attributes.

8.1  Constraints imposed by the reference implementation

Constraints on Link Sources & Styles
  1. The cursor placement attribute
    If a source link is given the cursor placement attribute, then its associated page note may not contain any source links.  Rationale:  To allow otherwise raises the possibility of a fixed-position note that lies above a moving note, which is both hard to implement and of questionable value.
  2. Nested link sources
    Nesting of link sources is limited to two levels.  Rationale:  the corresponding page notes need to be displayed in such a way as not to obscure each other.  Thus, one can be displayed above the link source, and another below the link source.  There's no place to put the third level.
  3. Note skins as link sources
    A note skin must not actually be a link source itself.  Rationale:  You can get the same effect by, e.g., wrapping an extra div around the skin and making what's inside the link source.
  4. Quotation marks in active style rules
    The reference implementation does not support the use of single quotes in the active style rule. Thus, background-image:url(' ... ') doesn't work, but background-image:url(" ... ") does.
  5. Specialized text formats
    Specialized text formats carry obvious implications for the placement of page notes.  Here are some examples not considered in the reference implementation:
    • Right-to-left text flow.  In this case, the page note should be aligned relative to the right end of the link source, and the indent attribute should specify pixels to the left of the right end of the link source.

    • Vertical link sources.  Vertically oriented link sources occur in languages such as Chinese and in many images.  In these cases, it is appropriate to place an annotation to the left or right of the link source, rather than above or below.  Doing so requires an extension of the placement attribute.

    • Individual words in a paragraph.  This is clearly doable, but no support is included in the current implementation.

    • Formulas from math and physics.  Of the various common approaches to presenting formulas in HTML, only images are supported in the reference implementation.  A goal here is to annotate individual terms and symbols.

    • SVG notation.  The goal is to mark specific spatial objects as link sources.

Constraints on Annotations and Note Skins
  1. Using nrefs to denote annotations in other documents

    Only local nrefs are supported in the current  implementation.  However, the design envisions the use of nrefs to specify elements in arbitrary documents, not just the current document.  It is anticipated that the "url" operator may be extended to use arbitrary fragment URLs for denoting elements, as in the following example:

    nref: url(../reference/glossary.htm#pageNote)

  2. Conflicts between inline and style-based nrefs

    If a user attempts to override an nref style rule with a local inline declaration, the reference implementation honors the user intent but issues an error message.  Consider the following example:

    <style>
         .newStuff { nref: #addedInTranslation }
    </style>

    <span class="newStuff" nref="#specialMention">totally</span> huge

    The specialMention annotation will display, but the status bar will read as follows:  Error.  Replace 'nref="#specialMention"' with inline style declaration.

  3. Image annotations
    There are some HTML-related restrictions on the annotation of images; see Appendix A.
  4. Nested note skins
    The reference implementation does not support nested note skins. Rationale:  In the applications considered, the need for this didn't turn up.  One can get around the restriction by making a copy of the inner note skin.
  5. Units of measurement
    The reference implementation assumes that all note-skin measurements are in pixels, as opposed to points, inches, em-quads, etc.
Constraints on Event Handling
  1. Event ordering
    By definition, an onmousestay event precedes the onmousedown event.  But in the reference implementation, the timing of the onmousestay event relative to other events is more an artifact of how the human hand works than of the actual javaScript code.
  2. Onmousestay events
    Onmousestay event handlers are only supported for the window object and then only when the mouse is over a link source.  However, the event detects all link surces under the cursor at the time of the event. 
  3. Interaction with onmousemove events
    Handling of onmousemove events is untested and may be problematic.
  4. The event object as a parameter
    Ideally, one would want to pass the event object as a parameter.  This would be easy to do for the particular case of the onmousestay event, but other mouse-related event handlers (e.g., onclick) need the additional screen-state information provided by the onmousestay event.  The reference implementation has no way of augmenting these predefined events, so the compromise is to make the information available in a global nEvent variable. 
  5. Use of zIndexes
    The Page Notes script assumes that user scripts do not alter zIndexes on active links and posted notes.

8.2 User-Visible Script Names

The Page Notes reference implementation sets default values for the following global values; user scripts are free to modify these parameters, with the exception of maxNoteStackDepth:

MSIE true if the browser is Internete Explorer
linkStackMax = 7; number of page notes that can be posted at once
minNoteWidth = 30;  minimum width for page notes of unspecified width
mousePauseTolerance = 50; number of milliseconds before next mouse pause
firstMousePause = 500; when to start tracking the mouse

Firefox and Internet Explorer require different "fudge factors" for lining up displayed page notes. This discrepancy is not easily diagnosed on the basis of supported browser functionality.

Increase the linkStackMax parameter if you have lots of page notes showing at once. This can happen if they are heavily nested or if they are popping up under program control.

The minNoteWidth parameter keeps page notes from becoming too narrow.  This could happen if you use a skin with an unspecified width (e.g., skin-gray in this document) and your link source is close to the right margin.

The mouse stay event is implemented by repeatedly observing whether the mouse has moved — every mousePauseTolerance milliseconds.   Set this parameter too small and your web page will think the mouse has paused when it hasn't.  Set it too large and your page notes will be slow to pop up.

The firstMousePause parameter specifies how long to wait before tracking the mouse.  Set it too small and your programmed initial page notes won't be displayed.  Set it too large and the user will notice that the page notes don't work right away.

It is possible to inadvertently set these parameters, even by simply using them as id's for document elements.   In principle, you could inadvertently set Page Note's unadvertised global variables as well, but they all end with the special sequence "PNjgw".   In the following design discussion, we will omit this suffix for reasons of readability; so for example, the design element linkStack is implemented as the global variable linkStackPNjgw.

8.3 The Level Stack

The Page Notes onload event handler allocates space for a level stack in the form of an array, linkStack.

The global variable, linkStackTop, marks the top of the stack.   Each level in the stack corresponds to an nEvent containing the four fields of nEvent.noteLink.  In the case of nested link sources, one level holds nEvent.outerLink, and the level above holds nEvent.noteLink. 

We say that the level stack is quiescent if it is not being worked on (by the functions removeOldPageNotes and activateNotesAndSources).  When the level stack is quiescent, each link source and its associated page note satisfy the following criteria:

  • linkStack[i].note is the page note associated with linkStack[i].source (or null, if the link has a pending note skin)

  • if linkStack[i].source is an inner link source, then linkStack[i-1].source is the corresponding outer link source

  • if linkStack[i].source is not an inner link source then linkStack[i-1].note is its containing page note if such is posted.

Each node in the document body is marked according to the role it plays in the link stack in the following way:

  • If node is neither a page note nor a link source, then

node.howOccurs is "" or is undefined and
node.currentStyle.zIndex = 0

  • If node is a posted page note, then

node.howOccurs = "note", and
node = linkStack[node.currentStyle.zIndex].note

  • If node is an active link source, then

node.howOccurs = "source", and
node = linkStack[node.currentStyle.zIndex].source

8.4 Implementation of the onmousestay event handler

The Page Notes script uses the onload and onmousemove events to implement the onmousestay event that triggers the posting of page notes.  The onmousestay event approximates the event object used by standard event handlers by placing state information in an nEvent object.  Using a global variable rather than passing a parameter is an artifact of the reference implementation.  In this section we specify what the event handler does, leaving the lower-level details to the reader's imagination.

Given the information in Section 8.3 on where the cursor is relative to the links and notes currently in the event stack, we can now specify what is to be true when the mouse stay event handler has handled an onmousestay event.  Let currentLink be nEvent.noteLink, and let outerLink be nEvent.outter link; we have the following:

Case 1.  The cursor is not over either a link source or an existing page note.

currentLink and outerLink are null, and
linkStackTop == 0

Case 2.  The cursor is over a posted page note but not over a link source.

currentLink.source is null,
currentLink.note is the posted page note, and
linkStack[linkStackTop].note == currentLevel.note

Case 3.  The cursor is over a link source.

currentLink.source is the link source, and
linkStack[linkStackTop].source == currentLevel.source

Case 3.  The cursor is over a nested pair of link sources.

as above, plus outerLevel.source is the outer link source

The mouse stay event handler, ehMouseStay(), accomplishes its purpose by

  1. Filling in the fields in nEvent,
  2. Dispensing with link activations and page notes that are no longer needed,
  3. Handling new link activations and new page notes.
8.4.1 Filling in the event fields

In addition to setting fields in the event object, nEvent, the function getContext figures out how much of the existing event stack to preserve.  Specifically, it defines a minimum preserveTo value representing the level above which the stack is to be pruned.

Case 1.  Not over either a link source or a posted page note.  Sets preserveTo = 0

Case 2.  The cursor is over a page note but not over a link source.  In this case, the page note is already posted, so the page note has a positive zIndex.  Sets  preserveTo is the zIndex.  Copies context information from linkStack[linkStackTop] into nEvent.

Case 3. The cursor is over a posted link source.  Sets preserveTo to the zIndex of the link source.  Adjusts preserveTo down one notch if the link source has the "cursor" placement attribute (so that the associated note can be taken down and reposted in the current cursor position).  Copies context information from linkStack[linkStackTop] into nEvent, also from linkStack[linkStackTop-1] in the case of nested link sources.

Case 4.  The cursor is over an inactive link source.  Collects context information for the new link source from its .nref, .nskin, and .placement attributes.  If neither of the above cases apply, sets preserveTo to 0.

The first time getEventContext encounters a link source, it compiles the .active placement attribute and stores it in .source.activeStyle; it also stores associated information needed to deactivate an active link source in .source.inactiveStyle.

8.4.2  Dispensing with unneeded link activations and page notes

The requirement for removeOldNotesAndSourcesis to dispense with link activations, page notes and stack elements above the preserveTo level.  In so doing, removeOldNotesAndSources sets the node.howOccurs fields to the empty string and sets associated zIndexes to 0, and sets linkStackTop to preserveTo.

8.4.3  Handling new link activations and new page notes

In the case where there is a new link source to work with, activateNotesAndSources activates the new source link and posts the associated page note if appropriate.  This involves the following tasks:

  1. Activate the link source, set its .howOccurs field, and push nEvent.noteLink onto the link stack.

  2. Do one of the following, depending on whether the nref attribute is present:

    1. Get a blank note from the note pool (see below)

    2. Instead use the note skin as the page note

  3. Calculate the intended width of the page note

  4. In case 2a above, fill in the blank page note by instantiating a copy of the note skin with a copy of the annotation.

  5. Horizontally reposition the page note if necessary, by lowering the width or by moving its left end.

  6. Vertically position the page note.

  7. Set the .howOccurs field for the posted page note.

In the case where there are new nested link sources, activateNotesAndSources is called twice, once for each note.

8.5 The Page Note Pool

There is an easily solved problem with constructed page notes - they have to be part of the document body in order to work right.  This means that when the program gets done working with them, the don't automatically get garbage collected, because the body still knows where they are. 

The chosen solution is to add a fixed pool of page-note nodes to the body during the onload event and then allocate and deallocate the nodes as needed.  Thus, we have the following low-level pool-management functions:

  • allocateNotePool() - creates the initial pool of nodes that will become the root elements of the constructed page notes (all eight of them).

  • allocatePoolNote() - returns a fresh element from the note pool.

  • deallocatePoolNote(note) - deallocates the note (by erasing the note's inner HTML and its css attributes) and returns it to the pool.

8.6 Compiling Attributes for Firefox

Firefox allows new user-supplied inline properties.  The following is a Firefox supported alternative to the introductory example in this manual:

    <a nref="#mousestay"
   nskin="skin-gold"
   active="{color:#DD8800}"
   placement="above"
   style="color:#905500; cursor: default">
mouse stay event </a>

The Page Notes script is set up to use either style attributes or inline attributes (or both, if they're consistent).  Consequently, we can get the necessary Page Notes attributes into Firefox via a "compilation" step that copies relevant style attributes to inline attributes.  To compile this manual, for example, one can do the following:

  • Create a new document with the same doc type and head element

  • Open the uncompiled version of this document in Internet Explorer
  • To perform actual compilation, click here and wait for the text to appear:

  • Do a "select all" and a "copy"

  • Paste the result into the new document.

  • Remove the eight extra div's at the end of the document.
  • Save the new document under a different name in the same directory.

The above compilation step produces a document that displays properly in both Firefox and Internet Explorer. 

In theory, Internet Explorer is not necessary for this compilation step.  Any HTML editor that supports user-supplied style attributes could easily be extended to provide the above compilation as part of its support for page notes.

The chief disadvantage of needing a compilation step is that the compiled form is not directly maintainable. This is because the compilation step systematically replicates a good deal of information from the style sheet pagenotes.css.  If one didn't need style sheets, one could work directly with the compiled form.


Appendix A.  Image Annotations

Annotating in two dimensions.

The current reference implementation has two failings with regard to annotating graphical images.  Page note positioning has to be based on cursor position, as opposed, for example, to the location of an annotated area within the image.  Another problem is that there is no way to nest link sources.  In particular, it is not possible to annotate an image and at the same time one of its image areas.

Positioning relative to an annotated area.  It's easy to conceptualize positioning a page note above, below, before, or after an annotated area.  To this end, we define the bounding rectangle for an area to be the smallest rectangle containing that area.  Computing the bounding rectangle from an area's coords property is straightforward - if the coordinates are given relative to the upper left corner of the image.  To get from these relative coordinates to document-related coordinates, it is necessary to know the position of the image.  In other words, we need to get from an area in a map back to the image being mapped. 

Unfortunately, there seems to be no easy way to do this in javaScript, even though the browser clearly knows which image is being mapped.  A workaround would be to ask the user to mark the mapped image with a currentImage property.  Specifically, ask the user to provide an Id for the image and have the map point back to that image.  This of course means that only one image can use a given map, but that is the norm anyway.

Nested link sources.  Unlike linear text, in which there is only an above or a below, an image area can potentially be surrounded on all sides by annotations.  As a result, there is a legitimate cause to provide multiple annotations for a given image area. The approach used for text, namely to have nexted link sources doesn't work for images because one can't have nested area tags.  Some experimentation is needed to find a good workaround.