summaryrefslogtreecommitdiff
path: root/data/js/dropdown.js
blob: 222a71101fd19fe0c172f243e9ddf9d8b415140f (plain)
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
/* Dropdown widget, used as follows:
 *
 *   ddInit(obj, align, func);
 *
 * Show a dropdown box on mouse-over on 'obj'. 'func' should generate and
 * return the contents of the box as a DOM node, or null to not show a dropdown
 * box at all. The 'align' argument indicates where the box should be shown,
 * relative to the obj:
 *
 *   left:   To the left of obj
 *   bottom: To the bottom of obj
 *   tagmod: Special alignment for tagmod page
 *
 * Other functions:
 *
 *   ddHide();      Hides the box
 *   ddRefresh();   Refreshes the box contents
 */
(function(){
  var box;

  function init(obj, align, contents) {
    obj.dd_align = align;
    obj.dd_contents = contents;
    obj.onmouseover = show;
  }

  function show() {
    if(!box) {
      box = tag('div', {id:'dd_box', 'class':'hidden'});
      addBody(box);
    }
    box.dd_lnk = this;
    document.onmousemove = mouse;
    document.onscroll = hide;
    refresh();
  }

  function hide() {
    if(box) {
      setText(box, '');
      setClass(box, 'hidden', true);
      box.dd_lnk = document.onmousemove = document.onscroll = null;
    }
  }

  function mouse(e) {
    e = e || window.event;
    // Don't hide if the cursor is on the link
    for(var lnk = e.target || e.srcElement; lnk; lnk=lnk.parentNode)
      if(lnk == box.dd_lnk)
        return;

    // Hide if it's 10px outside of the box
    var mouseX = e.pageX || (e.clientX + document.body.scrollLeft + document.documentElement.scrollLeft);
    var mouseY = e.pageY || (e.clientY + document.body.scrollTop  + document.documentElement.scrollTop);
    if(mouseX < box.dd_x-10 || mouseX > box.dd_x+box.offsetWidth+10 || mouseY < box.dd_y-10 || mouseY > box.dd_y+box.offsetHeight+10)
      hide();
  }

  function refresh() {
    if(!box || !box.dd_lnk)
      return hide();
    var lnk = box.dd_lnk;
    var content = lnk.dd_contents(lnk, box);
    if(content == null)
      return hide();
    setContent(box, content);
    setClass(box, 'hidden', false);

    var o = lnk;
    ddx = ddy = 0;
    do {
      ddx += o.offsetLeft;
      ddy += o.offsetTop;
    } while(o = o.offsetParent);

    if(lnk.dd_align == 'left')
      ddx -= box.offsetWidth;
    if(lnk.dd_align == 'tagmod')
      ddx += lnk.offsetWidth-35;
    if(lnk.dd_align == 'bottom')
      ddy += lnk.offsetHeight;
    box.dd_x = ddx;
    box.dd_y = ddy;
    box.style.left = ddx+'px';
    box.style.top = ddy+'px';
  }

  window.ddInit = init;
  window.ddHide = hide;
  window.ddRefresh = refresh;
})();