aboutsummaryrefslogtreecommitdiff
path: root/finder_menu.js
blob: 99c47428074238baec62d6e0feb0333257f53c92 (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
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
/*
 * ul2finder
 * written by Christian Heilmann (http://icant.co.uk)
 * support for closing the finder items added by Silvio (s1lv10 at uol.com.br)
 * turns the nested list with the ID "finder" into a dynamic list
 * uses the CSS classes defined in the variables
 */
function ul2finder()
{
  // Define variables used and classes to be applied/removed
  var i,uls,als,finder;
  var parentClass='parent';
  var showClass='shown';
  var hideClass='hidden';
  var openClass='open';
  window.finderOpened = new Object();
  window.finderHook   = new Object();

  // check if our finder list exists, if not, stop all activities
  finder=document.getElementById('finder');
  if(!finder){return;}

  // add the class domenabled to the body
  cssjs('add',document.body,'domenabled');

  // loop through all lists inside finder, position and hide them 
  // by applying the class hidden
  uls=finder.getElementsByTagName('ul');
  for(i=0;i<uls.length;i++)
  {
    cssjs('add',uls[i],hideClass);
  }	

  // loop through all links of inside finder
  lis=finder.getElementsByTagName('li');
  for(i=0;i<lis.length;i++)
  {
    // if the li containing the link has no nested list, skip this one
    if(!lis[i].getElementsByTagName('ul')[0])
    {
      continue;
    }

    // adjust the link
    var newa=document.createElement('a');
    newa.href='#';
    newa.appendChild(document.createTextNode(lis[i].firstChild.nodeValue));
    lis[i].replaceChild(newa,lis[i].firstChild);

    // otherwise apply the parent class
    cssjs('add',newa,parentClass);

    // setup the link
    ref = lis[i].getElementsByTagName('a')[0];
    ref.id = 'finder-' + i;
    window.finderOpened[ref.id] = false;

    // if the user clicks on the link
    ref.onclick=function()
    {
      // loop through all lists inside finder
      parentUls = this.parentNode.getElementsByTagName('ul');
      for(var i=0;i<uls.length;i++)
      {
        // hide unconnected or closing elements
        if (!connected(parentUls[0],uls[i]) || window.finderOpened[this.id] == true)
        {
          ref = uls[i].parentNode.getElementsByTagName('a')[0];
          if (ref != this && !isparent(uls[i],parentUls[0])) {
            changelink('close', ref);
            cssjs('remove',uls[i],showClass);
          }
        }
      }	

      // open or close a given finder tab
      if (window.finderOpened[this.id] == false) {
        // change properites
        changelink('open',this);
        cssjs('add',parentUls[0],showClass);

        // make the child menu appear at the same level of the parent
        $(parentUls[0]).css('top', $(this).position().top + 'px');

        // execute open hook
        if (window.finderHook['open'] !== undefined) {
          window.finderHook.open(this);
        }
      } else {
        if (window.finderHook['close'] !== undefined) {
          window.finderHook.close(this);
        }
        changelink('close',this);
        for(var u=0;u<parentUls.length;u++) {
          cssjs('remove',parentUls[u],showClass);
        }
      }

      // don't follow the real HREF of the link
      return false;
    }
  }	

  /*
   * changelink
   * written by Silvio (s1lv10 at uol.com.br)
   * changes the state of a given finder link
   */
  function changelink(action,ref) {
    var state = false;
    switch (action) {
      case 'open':
        state = true;
        classParent = 'remove';
        classOpen = 'add';
        break;
      case 'close':
        classParent = 'add';
        classOpen = 'remove';
        break;
    }
    window.finderOpened[ref.id] = state;
    cssjs(classParent,ref,parentClass);
    cssjs(classOpen,ref,openClass);
    cssjs(classParent,ref.parentNode,'li-'+parentClass);
    cssjs(classOpen,ref.parentNode,'li-'+openClass);
  }

  /*
   * isparent
   * written by Silvio (s1lv10 at uol.com.br)
   * checks if an element is parent of another via DOM using jQuery
   * inspired by http://stackoverflow.com/questions/245241/jquery-ancestors-using-jquery-objects
   */
  function isparent(par,child) {
    if ($(child).parents().index(par) >= 0) {
      return true;
    }
    return false;
  }

  /*
   * connected
   * written by Silvio (s1lv10 at uol.com.br)
   * checks if two elements are connect via DOM, either by one being
   * child of parent of the another.
   */
  function connected(a,b) {
    if (a == b) {
      return true;
    } else if (isparent(a,b) || isparent(b,a)) {
      return true;
    }
    return false;
  }

  /*
   * cssjs
   * written by Christian Heilmann (http://icant.co.uk)
   * eases the dynamic application of CSS classes via DOM
   * parameters: action a, object o and class names c1 and c2 (c2 optional)
   * actions: swap exchanges c1 and c2 in object o
   *			add adds class c1 to object o
   *			remove removes class c1 from object o
   *			check tests if class c1 is applied to object o
   * example:	cssjs('swap',document.getElementById('foo'),'bar','baz');
   */
  function cssjs(a,o,c1,c2)
  {
    switch (a){
      case 'swap':
        o.className=!cssjs('check',o,c1)?o.className.replace(c2,c1):o.className.replace(c1,c2);
        break;
      case 'add':
        if(!cssjs('check',o,c1)){o.className+=o.className?' '+c1:c1;}
        break;
      case 'remove':
        var rep=o.className.match(' '+c1)?' '+c1:c1;
        o.className=o.className.replace(rep,'');
        break;
      case 'check':
        return new RegExp('\\b'+c1+'\\b').test(o.className)
          break;
    }
  }
}

Drupal.behaviors.finderMenu = function() {
  $('#finder:not(.finder-menu-processed)').addClass('finder-menu-processed').each(function() {
      ul2finder();

      // Remove hidden class, used to hide finder if no js is available.
      $('#finder').removeClass('finder-degraded');
      });
};