aboutsummaryrefslogtreecommitdiffstats
path: root/nicetitle/nicetitle.js
blob: 578ab3a487ed44e9e36699aedb882a6c2828c583 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
/*
 * Based on NiceTitle, by Stuart Langridge
 * http://www.kryogenix.org/code/browser/nicetitle/
 */


// Start configuration
var SHOW_LINKS = false; // Set to false to disable showing link URLs
var FOLLOW_MOUSE = true; // Set to false to disable title follows mouse

var MIN_WIDTH = 100; // Min/Max width/height of title
var MAX_WIDTH = 600;
var MIN_HEIGHT = 25;

var SNAP_LENGTH = 25; // Define the length from the edge of the window to snap to
var MOUSE_OFFSET = 15; // Define the distance to place the title from the mouse
// End configuration


// Let the magic begin...
addEvent(window, "load", makeNiceTitles);

// Get script self directory
var src = document.getElementById("nicetitle").src.split("/");
src.pop();
src = src.join("/");

// Pre-load background PNG
(new Image()).src = src + "/ntbg.png";

var XHTMLNS = "http://www.w3.org/1999/xhtml";
var CURRENT_NICE_TITLE;

function makeNiceTitles() {
    if (!document.createElement || !document.getElementsByTagName) return;
    // add namespace methods to HTML DOM; this makes the script work in both
    // HTML and XML contexts.
    if (!document.createElementNS) {
        document.createElementNS = function(ns,elt) {
            return document.createElement(elt);
        }
    }

    if (!document.links) {
        document.links = document.getElementsByTagName("a");
    }
    for (var ti = 0; ti < document.links.length; ti++) {
        var lnk = document.links[ti];
        if (lnk.title) {
            lnk.setAttribute("nicetitle", lnk.title);
            lnk.removeAttribute("title");
            addEvent(lnk, "mouseover", showNiceTitle);
            addEvent(lnk, "mouseover", moveNiceTitle);
            addEvent(lnk, "mouseout", hideNiceTitle);
            addEvent(lnk, "mousemove", moveNiceTitle);
            addEvent(lnk, "mousedown", hideNiceTitle);
            /*
             * Focus and blur events are not quite right. In Mozilla, titles do not show on keyboard focus.
             * This may present an accessibility issue, but it doesn't currently play nice
             * with FOLLOW_MOUSE=true, or mousedown events.
             */
//            addEvent(lnk, "focus", showNiceTitle);
//            addEvent(lnk, "blur", hideNiceTitle);
        }
    }
    var instags = document.getElementsByTagName("ins");
    if (instags) {
        for (var ti = 0; ti < instags.length; ti++) {
            var instag = instags[ti];
            if (instag.dateTime) {
                var strDate = instag.dateTime;
                var dtIns = new Date(
                    strDate.substring(0, 4),
                    parseInt(strDate.substring(4, 6) - 1),
                    strDate.substring(6, 8),
                    strDate.substring(9, 11),
                    strDate.substring(11, 13),
                    strDate.substring(13, 15)
                );
                instag.setAttribute("nicetitle", "Added on " + dtIns.toString());
                addEvent(instag, "mouseover", showNiceTitle);
                addEvent(instag, "mouseover", moveNiceTitle);
                addEvent(instag, "mouseout", hideNiceTitle);
                addEvent(instag, "mousemove", moveNiceTitle);
                addEvent(instag, "mousedown", hideNiceTitle);
//                addEvent(instag, "focus", showNiceTitle);
//                addEvent(instag, "blur", hideNiceTitle);
            }
        }
    }
}

function findPosition(oLink) {
    if (oLink.offsetParent) {
        for (var posX = 0, posY = 0; oLink.offsetParent; oLink = oLink.offsetParent) {
            posX += oLink.offsetLeft;
            posY += oLink.offsetTop;
        }
        return [posX, posY];
    } else {
        return [oLink.x, oLink.y];
    }
}

function get_longest(ary) {
    var l = 0;
    ary.forEach(function(el) {
        if (el.length > l) l = el.length;
    });

    return l;
}

function moveNiceTitle(e) {
    if (!CURRENT_NICE_TITLE) return;
    var d = CURRENT_NICE_TITLE;
    if (e && e.currentTarget && (typeof(e.currentTarget) != "undefined")) {
        var el = e.currentTarget
    }
    else if (window.event && window.event.srcElement) {
        var el = window.event.srcElement
    }

    // Browser size
    var xy = getWindowSize();
    var ww = xy[0];
    var wh = xy[1];

    // Title width and height
    var w = (d.offsetWidth || MIN_WIDTH);
    var h = (d.offsetHeight || MIN_HEIGHT);

    if (FOLLOW_MOUSE) {
        // Mouse position within document (not window)
        var xy = getMousePosition(e);
        var mx = xy[0];
        var my = xy[1];

        // Document scroll position within window
        var xy = getScrollPosition();
        var sx = xy[0];
        var sy = xy[1];

        // Title element position within document
        var x = mx + MOUSE_OFFSET;
        var y = my + MOUSE_OFFSET;
    }
    else {
        // Document scroll position within window
        // Unused
        var sx = 0;
        var sy = 0;

        // Title element position within document
        var elPos = findPosition(el);
        var x = elPos[0];
        var y = elPos[1] + el.offsetHeight + MOUSE_OFFSET;
    }

    // Find out if we've already snapped
    var SNAP_RIGHT = false;
    var SNAP_BOTTOM = false;

    // Snap title to the right side of the window
    if ((x + w + SNAP_LENGTH) >= (ww + sx)) {
        x = ((ww + sx) - w - SNAP_LENGTH);
        SNAP_RIGHT = true;
    }

    // Snap title to the bottom of the window
    if ((y + h + SNAP_LENGTH) >= (wh + sy)) {
        y = ((wh + sy) - h - SNAP_LENGTH);
        SNAP_BOTTOM = true;
    }

    // Ensure mouse can never enter the title in the lower right corner of the window
    if (FOLLOW_MOUSE && SNAP_RIGHT && SNAP_BOTTOM) {
        y = (my - MOUSE_OFFSET - h);
    }
    else if (!FOLLOW_MOUSE && SNAP_BOTTOM) {
        y = elPos[1] - h - MOUSE_OFFSET;
    }

    d.style.left = x + "px";
    d.style.top = y + "px";
}

function showNiceTitle(e) {
    if (CURRENT_NICE_TITLE) hideNiceTitle(CURRENT_NICE_TITLE);
    if (!document.getElementsByTagName) return;
    if (e && e.currentTarget && (typeof(e.currentTarget) != "undefined")) {
        var lnk = e.currentTarget
    }
    else if (window.event && window.event.srcElement) {
        var lnk = window.event.srcElement
    }

    if (!lnk) return;
    if (lnk.nodeName.toUpperCase() != "A") {
        // lnk is not actually the link -- ascend parents until we hit a link
        lnk = getParent(lnk, "A");
    }
    if (!lnk) return;
    var nicetitle = lnk.getAttribute("nicetitle");

    var d = document.createElementNS(XHTMLNS, "div");
    d.style.display = "none";
    d.className = "nicetitle";

    var nicetitle_parts = nicetitle.split("\n");
    nicetitle_parts.forEach(function(textpart) {
        var pat = document.createElementNS(XHTMLNS, "p");
        pat.className = "titletext";
        var tnt = document.createTextNode(textpart);
        pat.appendChild(tnt);
        var brk = document.createElementNS(XHTMLNS, "br");
        pat.appendChild(brk);
        d.appendChild(pat);
    });

    if (lnk.href && SHOW_LINKS) {
        var tnd = document.createTextNode(lnk.href);
        pad = document.createElementNS(XHTMLNS, "p");
        pad.className = "destination";
        pad.appendChild(tnd);
        d.appendChild(pad);
    }

    var l = get_longest(nicetitle_parts);

    // Approximate pixel width of longest line in the title
    var w = ((lnk.href && SHOW_LINKS) ? lnk.href.length : 0) * 6;
    var t = (l ? l : 0) * 8;

    // Use the greatest width: title text, link URL, or MIN_WIDTH. Limited to MAX_WIDTH
    w = ((w > MIN_WIDTH) ? w : MIN_WIDTH);
    w = ((w > t) ? w : t);
    w = ((w > MAX_WIDTH) ? MAX_WIDTH : w);
    d.style.width = w + "px";

    document.getElementsByTagName("body")[0].appendChild(d);
    d.style.display = "block";

    CURRENT_NICE_TITLE = d;
    moveNiceTitle(e);
}

function hideNiceTitle(e) {
    if (!document.getElementsByTagName) return;
    if (CURRENT_NICE_TITLE) {
        document.getElementsByTagName("body")[0].removeChild(CURRENT_NICE_TITLE);
        CURRENT_NICE_TITLE = null;
    }
}

// Add an eventListener to browsers that can do it somehow.
// Originally by the amazing Scott Andrew.
function addEvent(obj, evType, fn) {
    if (obj.addEventListener) {
        obj.addEventListener(evType, fn, false);
        return true;
    } else if (obj.attachEvent) {
        return obj.attachEvent("on" + evType, fn);
    } else {
        return false;
    }
}

function getParent(el, pTagName) {
	if (el == null) return null;
	else if (el.nodeType == 1 && el.tagName.toLowerCase() == pTagName.toLowerCase())
		return el;
	else
		return getParent(el.parentNode, pTagName);
}

function getMousePosition(e) {
    var x = 0;
    var y = 0;

    if (e && (typeof(window.scrollX) != "undefined")) {
        x = e.clientX + window.scrollX;
        y = e.clientY + window.scrollY;
    }
    else if (window.event) {
        x = window.event.clientX + document.documentElement.scrollLeft;
        y = window.event.clientY + document.documentElement.scrollTop;
    }

    return [x, y];
}

function getScrollPosition() {
    var x = 0;
    var y = 0;

    if (window.scrollX && window.scrollY) {
        x = window.scrollX;
        y = window.scrollY;
    }
    else if (document.documentElement.scrollLeft &&
             document.documentElement.scrollTop) {
        x = document.documentElement.scrollLeft;
        y = document.documentElement.scrollTop;
    }

    return [x, y];
}

function getWindowSize() {
    var x = 0;
    var y = 0;

    if (window.innerWidth && window.innerHeight) {
        x = window.innerWidth;
        y = window.innerHeight;
    }
    else if (document.documentElement.clientWidth &&
             document.documentElement.clientHeight) {
        x = document.documentElement.clientWidth;
        y = document.documentElement.clientHeight;
    }

    return [x, y];
}

// IE does not support the Array.forEach() method... Try to approximate it
if (!Array.prototype.forEach) {
    Array.prototype.forEach = function(action, context) {
        var len = this.length;
        for (var i = 0; i < len; i++) {
            if (this[i] != undefined) action(this[i], context);
        }
    };
}

© 2014-2024 Faster IT GmbH | imprint | privacy policy