1/**
2 * This class centralize the pfc' Graphic User Interface manipulations
3 * (depends on prototype library)
4 * @author Stephane Gully
5 */
6var pfcGui = Class.create();
7pfcGui.prototype = {
8
9  initialize: function()
10  {
11//    this.builder = new pfcGuiBuilder();
12    this.current_tab    = '';
13    this.current_tab_id = '';
14    this.tabs       = Array();
15    this.tabids     = Array();
16    this.tabtypes   = Array();
17    this.chatcontent   = $H();
18    this.onlinecontent = $H();
19    this.scrollpos     = $H();
20    this.elttoscroll   = $H();
21    this.windownotifynb = 0;
22  },
23
24  /**
25   * Scroll down the message list area by elttoscroll height
26   * - elttoscroll is a message DOM element which has been appended to the tabid's message list
27   * - this.elttoscroll is an array containing the list of messages that will be scrolled
28   *   when the corresponding tab will be shown (see setTabById bellow).
29   *   It is necessary to keep in cache the list of hidden (because the tab is inactive) messages
30   *   because the 'scrollTop' javascript attribute
31   *   will not work if the element (tab content) is hidden.
32   */
33  scrollDown: function(tabid, elttoscroll)
34  {
35    // check the wanted tabid is the current active one
36    if (this.getTabId() != tabid)
37    {
38      // no it's not the current active one so just cache the elttoscroll in the famouse this.elttoscroll array
39      if (!this.elttoscroll.get(tabid)) this.elttoscroll.set(tabid, Array());
40      this.elttoscroll.get(tabid).push(elttoscroll);
41      return;
42    }
43    // the wanted tab is active so just scroll down the tab content element
44    // by elttoscroll element height (use 'offsetHeight' attribute)
45    var content = this.getChatContentFromTabId(tabid);
46
47    // the next line seems to help with IE6 scroll on the first load
48    // http://sourceforge.net/tracker/index.php?func=detail&aid=1568264&group_id=158880&atid=809601
49    var dudVar = content.scrollTop;
50    content.scrollTop += elttoscroll.offsetHeight+2;
51    this.scrollpos.set(tabid, content.scrollTop);
52  },
53
54  isCreated: function(tabid)
55  {
56    /*
57    for (var i = 0; i < this.tabids.length ; i++)
58    {
59      if (this.tabids[i] == tabid) return true;
60    }
61    return false;
62    */
63    return (indexOf(this.tabids, tabid) >= 0);
64  },
65
66  setTabById: function(tabid)
67  {
68    var className = (!is_ie7 && !is_ie6) ? 'class' : 'className';
69
70    // first of all save the scroll pos of the visible tab
71    var content = this.getChatContentFromTabId(this.current_tab_id);
72    this.scrollpos.set(this.current_tab_id, content.scrollTop);
73
74    // start without selected tabs
75    this.current_tab     = '';
76    this.current_tab_id  = '';
77    var tab_to_show = null;
78    // try to fine the tab to select and select it!
79    for (var i=0; i<this.tabids.length; i++)
80    {
81      var tabtitle   = $('pfc_channel_title'+this.tabids[i]);
82      var tabcontent = $('pfc_channel_content'+this.tabids[i]);
83      if (this.tabids[i] == tabid)
84      {
85        // select the tab
86        tabtitle.setAttribute(className, 'selected');
87        //Element.addClassName(tabtitle, 'selected');
88        tab_to_show = tabcontent;
89        this.current_tab     = this.tabs[i];
90        this.current_tab_id  = tabid;
91      }
92      else
93      {
94        // unselect the tab
95        tabtitle.setAttribute(className, '');
96        //Element.removeClassName(tabtitle, 'selected');
97        tabcontent.style.display = 'none';
98      }
99    }
100
101    // show the new selected tab
102    tab_to_show.style.display = 'block';
103
104    // restore the scroll pos
105    var content = this.getChatContentFromTabId(tabid);
106    content.scrollTop = this.scrollpos.get(tabid);
107
108    // scroll the new posted message
109    if (this.elttoscroll.get(tabid) &&
110        this.elttoscroll.get(tabid).length > 0)
111    {
112      // on by one
113      for (var i=0; i<this.elttoscroll.get(tabid).length; i++)
114        this.scrollDown(tabid,this.elttoscroll.get(tabid)[i]);
115      // empty the cached element list because it has been scrolled
116      this.elttoscroll.set(tabid, Array());
117    }
118
119    this.unnotifyTab(tabid);
120  },
121
122  getTabId: function()
123  {
124    return this.current_tab_id;
125  },
126
127  getChatContentFromTabId: function(tabid)
128  {
129    var className = (!is_ie7 && !is_ie6) ? 'class' : 'className';
130
131    // return the chat content if it exists
132    var cc = this.chatcontent.get(tabid);
133    if (cc) return cc;
134
135    // if the chat content doesn't exists yet, just create a cached one
136    cc = document.createElement('div');
137    cc.setAttribute('id', 'pfc_chat_'+tabid);
138    cc.setAttribute(className, 'pfc_chat');
139
140    //    Element.addClassName(cc, 'pfc_chat');
141    cc.style.display = "block"; // needed by IE6 to show the online div at startup (first loaded page)
142    //    cc.style.marginLeft = "5px";
143
144    this.chatcontent.set(tabid,cc);
145    return cc;
146  },
147  getOnlineContentFromTabId: function(tabid)
148  {
149    var className = (!is_ie7 && !is_ie6) ? 'class' : 'className';
150
151    // return the online content if it exists
152    var oc = this.onlinecontent.get(tabid);
153    if (oc) return oc;
154
155    oc = document.createElement('div');
156    oc.setAttribute('id', 'pfc_online_'+tabid);
157    oc.setAttribute(className, 'pfc_online');
158    //Element.addClassName(oc, 'pfc_online');
159    // I set the border style here because seting it in the CSS is not taken in account
160    //    oc.style.borderLeft = "1px solid #555";
161    oc.style.display = "block"; // needed by IE6 to show the online div at startup (first loaded page)
162
163    this.onlinecontent.set(tabid,oc);
164    return oc;
165  },
166
167  removeTabById: function(tabid)
168  {
169    // remove the widgets
170    var tabparent_t = $('pfc_channels_list');
171    var tabparent_c = $('pfc_channels_content');
172    var tab_t = $('pfc_channel_title'+tabid);
173    var tab_c = $('pfc_channel_content'+tabid);
174    tabparent_t.removeChild(tab_t);
175    tabparent_c.removeChild(tab_c);
176
177    // empty the chat div content
178    var div_chat = this.getChatContentFromTabId(tabid);
179    div_chat.innerHTML = ''; // do not use ".update('')" or ".remove()" because it do not works on IE6
180
181    // remove the tab from the list
182    var tabpos = indexOf(this.tabids, tabid);
183    var name = this.tabs[tabpos];
184    this.tabids     = without(this.tabids, this.tabids[tabpos]);
185    this.tabs       = without(this.tabs, this.tabs[tabpos]);
186    this.tabtypes   = without(this.tabtypes, this.tabtypes[tabpos]);
187    tabpos = indexOf(this.tabids, this.getTabId());
188    if (tabpos<0) tabpos = 0;
189    if (this.tabids[tabpos])
190      this.setTabById(this.tabids[tabpos]);
191    return name;
192  },
193
194  /*
195  removeTabByName: function(name)
196  {
197    var tabid = _to_utf8(name).md5();
198    var ret = this.removeTabById(tabid);
199    if (ret == name)
200      return tabid;
201    else
202      return 0;
203  },
204  */
205
206  createTab: function(name, tabid, type)
207  {
208    var className = (!is_ie7 && !is_ie6) ? 'class' : 'className';
209
210    // do not create empty tabs
211    if(name == '') return;
212    if(tabid == '') return;
213
214    // do not create twice a the same tab
215    if (this.isCreated(tabid)) return;
216
217    //    var tabid = _to_utf8(name).md5();
218    //alert(name+'='+tabid);
219    this.tabs.push(name);
220    this.tabids.push(tabid);
221    this.tabtypes.push(type);
222
223    //alert(this.tabs.toString());
224
225    var li_title = document.createElement('li');
226    li_title.setAttribute('id', 'pfc_channel_title'+tabid);
227
228    var li_div = document.createElement('div');
229    li_div.setAttribute('id', 'pfc_tabdiv'+tabid);
230    li_title.appendChild(li_div);
231
232    var a1 = document.createElement('a');
233    a1.setAttribute(className, 'pfc_tabtitle');
234    a1.setAttribute('href', '#');
235    a1.pfc_tabid = tabid;
236    a1.onclick = function(){pfc.gui.setTabById(this.pfc_tabid); return false;}
237    li_div.appendChild(a1);
238
239    if (pfc_displaytabimage)
240    {
241      var img = document.createElement('img');
242      img.setAttribute('id', 'pfc_tabimg'+tabid);
243      if (type == 'ch')
244        img.setAttribute('src', pfc.res.getFileUrl('images/ch.gif'));
245      if (type == 'pv')
246        img.setAttribute('src', pfc.res.getFileUrl('images/pv.gif'));
247      a1.appendChild(img);
248    }
249
250    // on ajoute le nom du channel
251    a1.appendChild(document.createTextNode(name));
252
253    if (pfc_displaytabclosebutton || type == 'pv')
254    {
255      var a2 = document.createElement('a');
256      a2.pfc_tabid = tabid;
257      a2.pfc_tabname = name;
258      a2.pfc_tabtype = type;
259      a2.onclick = function(){
260        var msg = (type == 'pv' ? 'Are you sure you want to close this tab ?' :
261                                  'Do you really want to leave this room ?');
262        var res = confirm(pfc.res.getLabel(msg));
263        if (res == true)
264          pfc.sendRequest('/leave',this.pfc_tabid);
265        return false;
266      }
267      a2.alt   = pfc.res.getLabel('Close this tab');
268      a2.title = a2.alt;
269      a2.setAttribute(className, 'pfc_tabclose');
270      var img = document.createElement('img');
271      img.setAttribute('src', pfc.res.getFileUrl('images/tab_remove.gif'));
272      a2.appendChild(img);
273      li_div.appendChild(a2);
274    }
275
276    var div_content = document.createElement('div');
277    div_content.setAttribute('id', 'pfc_channel_content'+tabid);
278    //    Element.addClassName(div_content, 'pfc_content');
279    div_content.setAttribute(className, 'pfc_content');
280    div_content.style.display = 'none';
281
282    var div_chat    = this.getChatContentFromTabId(tabid);
283    var div_online  = this.getOnlineContentFromTabId(tabid);
284    div_content.appendChild(div_chat);
285    div_content.appendChild(div_online);
286
287    $('pfc_channels_list').appendChild(li_title);
288    $('pfc_channels_content').appendChild(div_content);
289
290    // force the height of the chat/online zone in pixel in order fix blank screens on IE6
291    div_chat.style.height   = ($('pfc_channels_content').offsetHeight-1)+'px';
292    div_online.style.height = ($('pfc_channels_content').offsetHeight-1)+'px';
293
294    return tabid;
295  },
296
297  /**
298   * This function change the window title in order to catch the attention
299   */
300  notifyWindow: function()
301  {
302    this.windownotifynb += 1;
303    var rx = new RegExp('^\\[[0-9]+\\](.*)','ig');
304    document.title = document.title.replace(rx,'$1');
305    document.title = '['+this.windownotifynb+']'+document.title;
306
307    // play the sound
308    var soundcontainer = document.getElementById('pfc_sound_container');
309    if (pfc.issoundenable)
310    {
311      var flash = '<object style="visibility:hidden" classid="clsid:D27CDB6E-AE6D-11CF-96B8-444553540000" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0" width="0" height="0">';
312      flash += '<param name="movie" value="' + pfc.res.getFileUrl('sound.swf') + '">';
313      flash += '<param name="quality" value="High">';
314      flash += '<embed style="visibility:hidden" src="' + pfc.res.getFileUrl('sound.swf') + '" pluginspage="http://www.macromedia.com/go/getflashplayer" type="application/x-shockwave-flash" width="0" height="0" />';
315      flash += '</object>';
316      soundcontainer.innerHTML = flash;
317    }
318  },
319  unnotifyWindow: function()
320  {
321    this.windownotifynb = 0;
322    var rx = new RegExp('^\\[[0-9]+\\](.*)','ig');
323    document.title = document.title.replace(rx,'$1');
324
325    // stop the sound
326    var soundcontainer = document.getElementById('pfc_sound_container');
327    if (pfc.issoundenable)
328      soundcontainer.innerHTML = '';
329  },
330
331  /**
332   * This function change the tab icon in order to catch the attention
333   */
334  notifyTab: function(tabid)
335  {
336    var className = (!is_ie7 && !is_ie6) ? 'class' : 'className';
337
338    // first of all be sure the tab highlighting is cleared
339    this.unnotifyTab(tabid);
340
341    var tabpos = indexOf(this.tabids, tabid);
342    var tabtype = this.tabtypes[tabpos];
343
344    // handle the tab's image modification
345    var img = $('pfc_tabimg'+tabid);
346    if (img)
347    {
348      if (tabtype == 'ch')
349        img.src = pfc.res.getFileUrl('images/ch-active.gif');
350      if (tabtype == 'pv')
351        img.src = pfc.res.getFileUrl('images/pv-active.gif');
352    }
353
354    // handle the blicking effect
355    var div = $('pfc_tabdiv'+tabid);
356    if (div)
357    {
358      if (div.blinkstat == true)
359      {
360        div.setAttribute(className, 'pfc_tabblink1');
361      }
362      else
363      {
364        div.setAttribute(className, 'pfc_tabblink2');
365      }
366      div.blinkstat = !div.blinkstat;
367      div.blinktimeout = setTimeout('pfc.gui.notifyTab(\''+tabid+'\');', 500);
368    }
369  },
370
371  /**
372   * This function restore the tab icon to its default value
373   */
374  unnotifyTab: function(tabid)
375  {
376    var className = (!is_ie7 && !is_ie6) ? 'class' : 'className';
377
378    var tabpos = indexOf(this.tabids, tabid);
379    var tabtype = this.tabtypes[tabpos];
380
381    // restore the tab's image
382    var img = $('pfc_tabimg'+tabid);
383    if (img)
384    {
385      if (tabtype == 'ch')
386        img.src = pfc.res.getFileUrl('images/ch.gif');
387      if (tabtype == 'pv')
388        img.src = pfc.res.getFileUrl('images/pv.gif');
389    }
390
391    // stop the blinking effect
392    var div = $('pfc_tabdiv'+tabid);
393    if (div)
394    {
395      div.removeAttribute(className);
396      clearTimeout(div.blinktimeout);
397    }
398  },
399
400  loadSmileyBox: function()
401  {
402    var container = $('pfc_smileys');
403    var smileys = pfc.res.getSmileyReverseHash();//getSmileyHash();
404    var sl = smileys.keys();
405    pfc.res.sortSmileyKeys(); // Sort smiley keys once.
406    for(var i = 0; i < sl.length; i++)
407    {
408      s_url    = sl[i];
409      s_symbol = smileys.get(sl[i]);
410      s_symbol = s_symbol.unescapeHTML();
411      // Replace &quot; with " for IE and Webkit browsers.
412      // The prototype.js version 1.5.1.1 unescapeHTML() function does not do this.
413      if (is_ie || is_webkit)
414        s_symbol = s_symbol.replace(/&quot;/g,'"');
415
416      var img = document.createElement('img');
417      img.setAttribute('src', s_url);
418      img.setAttribute('alt', s_symbol);
419      img.setAttribute('title', s_symbol);
420      img.s_symbol = s_symbol;
421      img.onclick = function(){ pfc.insertSmiley(this.s_symbol); }
422      container.appendChild(img);
423      container.appendChild(document.createTextNode(' ')); // so smileys will wrap fine if lot of smiles in theme.
424    }
425  },
426
427  loadBBCodeColorList: function()
428  {
429    var className = (!is_ie7 && !is_ie6) ? 'class' : 'className';
430
431    // color list
432    var clist = $('pfc_colorlist');
433    var clist_v = pfc_bbcode_color_list;
434    for (var i=0 ; i<clist_v.length ; i++)
435    {
436      var bbc = clist_v[i];
437      var elt = document.createElement('img');
438      elt.bbc = bbc;
439      elt.setAttribute(className, 'pfc_color');
440      elt.setAttribute('id', 'pfc_color_'+bbc);
441      elt.style.backgroundColor = '#'+bbc;
442      elt.setAttribute('src', pfc.res.getFileUrl('images/color_transparent.gif'));
443      elt.setAttribute('alt', bbc);
444      elt.onclick = function(){ pfc.switch_text_color(this.bbc); }
445      clist.appendChild(elt);
446    }
447  }
448};
449