« 197Xsに参加してみたよ | メイン | MovableType4 へアップグレード »

IE6 で Redmine0.6 の右クリックコンテキストメニューのサブメニューを表示させる

Redmineのユーザグループに投げられた下記の問題。

 

IE6利用時に、Redmine0.6 の問題リストで右クリックしたときに表示されるコンテキストメニューのサブメニュー表示されない。

 

原因を探っていて、分かったことが色々あったので書いておきます。

 

・右クリックのコンテキストメニューの階層構造は、CSSで制御されている。

・li:hover という属性で、その下のulタグがdisplay:block;に切り替わる仕組み。

・でも、~IE6では、a タグ以外に :hover 属性が効かない

・そこで、Redmine では、csshover.htc を読み込んで、a タグ以外にも:hover が効くようにしている。

・でも出ない。

・コンテキストメニューは、右クリック時に、Ajax で動的に取得される

・csshover.htc の中にはjavascript が書いてあって、documentonready つまり、ドキュメントがすべて表示された段階で、parseStylesheets()という関数が実行されている。

・つまり、li:hover してほしいHTMLElementがページ表示時にページ内にいないので、読み込んでいるcsshover.htcがコンテキストメニューの部分に対して意味をなしていない。

・ということで、コンテキストメニューがサーバから取得され、ページ内に表示された段階で、parseStylesheets()を実行できれば良い。

 

で、対応方法は以下の通り。

 

/public/stylesheets/csshover.htc

の27行目(コメント行から下)すべてを

/public/javascripts/context_menu.js

の最終行より下に、コピー。

そして、同じ context_menu.js の 42行目にある


new Ajax.Updater({success:'context-menu'}, '../../issues/
context_menu/' + id, {asynchronous:true, evalScripts:true,
onComplete:function(request){Effect.Appear('context-menu', {duration:0.20});}})

 

を、


new Ajax.Updater({success:'context-menu'}, '../../issues/context_menu/' + id,
 {asynchronous:true, evalScripts:true,onComplete:function(request){
 Effect.Appear('context-menu', {duration: 0.20});
 parseStylesheets();
}})

に書き換えます。

 

ただし、この方法だと、コンテキストメニューが表示される毎にparseStylesheets()関数が実行されて、あまりいけてないです。


csshover.htcの中身は、CSSをチェックして、:hover と書いているところを探し、そのクラスが適用されているページ内のHTML Elementにonmouseover とonmouseout のイベントをattach しているだけ。

コンテキストメニューの構造は分かっているので、じゃあ、べた書きでイベントをattach するようにしたのが以下のソース。


new Ajax.Updater({success:'context-menu'}, '../../issues/context_menu/' + id, {asynchronous:true, evalScripts:true, onComplete:function(request){
  Effect.Appear('context-menu', {duration: 0.20});
  if(!navigator.userAgent.match(/MSIE/) || window.XMLHttpRequest) return;
  try{
    var uls = $('context-menu').getElementsByTagName('ul');
    uls[0].id = 'context-menu-base-ul';
    uls[1].id = 'context-menu-sub-ul_0';
    uls[2].id = 'context-menu-sub-ul_1';
    uls[3].id = 'context-menu-sub-ul_2';
    var lis = $('context-menu').getElementsByTagName('li');
    for(var i = 0,j = 0,len = lis.length;i<len;i++){
      if(lis[i].className.indexOf('folder') >= 0){
        lis[i].id = 'context-menu-folder_' + j;
        j++;
      }
    }
    var menuShow = function(event){
      var li = Event.findElement(event, 'li');
      li.style.zIndex='10';
      $('context-menu-sub-ul_'+li.id.split('_')[1]).style.display='block';
    }
    var menuHide = function(event){
      var li = Event.findElement(event, 'li');
      li.style.zIndex='0';
      $('context-menu-sub-ul_'+li.id.split('_')[1]).style.display='none';
    }
    $('context-menu-sub-ul_0','context-menu-sub-ul_1','context-menu-sub-ul_2','context-menu-folder_0','context-menu-folder_1','context-menu-folder_2').each(function(obj) {
      Event.observe(obj, "mouseover", menuShow, false);
    });
    $('context-menu-sub-ul_0','context-menu-sub-ul_1','context-menu-sub-ul_2','context-menu-folder_0','context-menu-folder_1','context-menu-folder_2').each(function(obj) {
      Event.observe(obj, "mouseout", menuHide, false);
    });
  }catch(e){
  }
}
});


べたべーたですが、これでIE6でも右クリックメニューのサブメニューが表示されるようになりました。