ツリーメニュー

[統計] HTMLからXHTMLへの移行を進めていますか?



0   名前: 花子 : 2006/08/08(火) 14:36
ツリー式のメニューについての質問です。
ツリーメニューを一段階開いた後に別のツリーメニューを開くと、
そのとき開いたメニュー以外を閉じることは出来ますか?

■サンプル1
  サンプル1(1)
  サンプル1(2)
■サンプル2
  サンプル2(1)

と、いうメニューがあった場合、最初にサンプル1を開き、
その後サンプル2を開くとサンプル1が閉じるようなものを作りたいのです。
とても分かりにくい説明かと思いますが、宜しくお願いします。


1   名前: Pid : 2006/08/08(火) 14:36
一階層ツリーなら,前回開いたノードをグローバルな変数に保存しておけば簡単だと思います。

多階層ツリーの場合,

(a). 現在ノードが前回ノードの子孫要素でないとき,二つのノードの共通祖先に当たるまで,前回ノードを上方向に探索して閉じていく。
http://hpcgi2.nifty.com/yoshi-m/makehp/q_a/javascript/wforum.cgi?no=2231&mode=msgview

(b). 前回ノードと現在ノードの深さを比較し,前回の方が深ければ,その差分だけ前回ノードを上方向に閉じていく。
http://hpcgi2.nifty.com/yoshi-m/makehp/q_a/javascript/wforum.cgi?no=2234&mode=msgview

などの方法が考えられます。ご自分で図など書いてじっくり考えてみて下さい。

2   名前: 花子 : 2006/08/08(火) 14:36
早速の回答、ありがとうございます。
私がやりたいと思っているのは多層式ツリーです。。
まだHP作成についての知識があまりないので、教えてくださった方法で出来るか
分かりませんが、じっくりと考えてみようと思います。
方法bのURLからいけるページのソースをそのままコピーしてもいいのでしょうか?
それで試してみようかと思います。
難しいようなら、普通のツリーに断念しようと思いますが。

どうも有り難うございました。
思っていたよりも、ずっと早く回答が寄せられ助かりました。

3   名前: 花子 : 2006/08/08(火) 14:36
申し訳ありません。
更に質問してもいいでしょうか?
>(b). 前回ノードと現在ノードの深さを比較し,前回の方が深ければ,その差分だけ前回ノードを上方向に閉じていく。
この方法のURLをコピーして、作成しようとしたのですが……
何段階か展開した後、親の項目1をクリックすると項目1は全て閉じるようにすることは出来ますか?
検索で色々と探して、改造しようとしてみたのですが、JavaScriptに関して知識があまり無いためにうまくいきませんでした。
もし、宜しければどこにどういったものを付け足せばよいのか、教えてもらえないでしょうか?
宜しくお願いします。

4   名前: Pid : 2006/08/08(火) 14:36
スクリプトだけ入れ替えて下さい。

【インストール方法】
・文書の head 要素内でこのスクリプトを呼び出せば,指定した id を持つ ol/ul 要素が自動的に展開式メニューになる(body 要素内を汚さない)。外部スクリプト推奨。

【アンインストール方法】
・スクリプトを削除する。

【その他】
・Shift キーを押しながらマウスボタンを押下すると,押下している間だけメニューが全展開される。
・開いた li 要素には 'tree-menu-opened',閉じた li 要素には 'tree-menu-closed' というクラス名を与えてあるので,スタイル指定はご自由に。


/*@cc_on@*/
if (Function.prototype && Function.prototype.call
&& document.implementation && document.implementation.hasFeature ('HTML', null)
/*@if (@_jscript) && window.attachEvent @else@*/ /* && document.implementation.hasFeature ('CSS', null) */
&& document.implementation.hasFeature ('Events', null) /*@end@*/)

5   名前: Pid : 2006/08/08(火) 14:36
(function () {
////////////////////////////////////////////////////////////////////////
var TreeMenuConfiguration = {

//_______________________↓ユーザ設定ここから↓_______________________

// ツリーメニュー化したい ol/ul 要素の id 属性値をコンマ区切りで指定。
targetIds : [ 'menu1', 'menu2' ],

// 文書読み込み中にメニューを隠すか(true: 隠す,false: 隠さない)
// ただし,true にすると Opera,Safari で動作しなくなるので注意。
hideMenuWhileLoading : false,

//_______________________↑ユーザ設定ここまで↑_______________________
//
// 以下,改造はご自由に。

secretTreeMenus : { }
};

6   名前: Pid : 2006/08/08(火) 14:36
// TreeMenu main

function TreeMenu (node) {
this.root = node;
this.clone = node.cloneNode (true);
this.previousBranch = null;
this.previousLevel = 1;
}

TreeMenu.prototype.init = function () {
_forEachBranch.call (this, null, 'none', _initBranch);
_forEachBranch.call (this, this.clone, 'block', _initBranch);
_addEventListener.call (document.body, 'mousedown', (function (thisObj) {
return function (e) {
if ((e || window.event).shiftKey && thisObj.root.parentNode) thisObj.root.parentNode.replaceChild (thisObj.clone, thisObj.root);
}
} )(this), true);
_addEventListener.call (document.body, 'mouseup', (function (thisObj) {
return function (e) {
if (thisObj.clone.parentNode && (1 /* Node.ELEMENT_NODE */ == thisObj.clone.parentNode.nodeType)) thisObj.clone.parentNode.replaceChild (thisObj.root, thisObj.clone);
}
} )(this), true);
}
_addEventListener.call (window, 'load', function () {
_forEach.call (TreeMenuConfiguration.targetIds, function (id) {
var node = document.getElementById (id);
if (node) {
var tm = new TreeMenu (node);
tm.init ();
}
if (TreeMenuConfiguration.hideMenuWhileLoading) {
TreeMenuConfiguration.secretTreeMenus[id].showPernmanently ();
delete TreeMenuConfiguration.secretTreeMenus[id];
}
} );
}, false);

7   名前: Pid : 2006/08/08(火) 14:36
// hides menus while loading

function SecretTreeMenu (id) {
this.id = id;
/*@if (@_jscript) this.styleSheet = document.createStyleSheet (); @else@*/
this.srcElement = _createCSSStyleSheet.call (null);
this.styleSheet = document.styleSheets[document.styleSheets.length - 1];
/*@end@*/
this.showing = true;
}

SecretTreeMenu.prototype.hideTemporarily = function () {
if (this.showing) {
var ss = this.styleSheet;
ss./*@if (@_jscript) addRule ('#' + this.id, 'display: none !important;') @else@*/ insertRule ('#' + this.id + ' { display: none !important; }', ss.cssRules.length) /*@end@*/;
this.showing = false;
}
}

SecretTreeMenu.prototype.showPernmanently = function () {
/*@if (@_jscript) this.styleSheet.disabled = true @else@*/
this.srcElement.parentNode.removeChild (this.srcElement) /*@end@*/;
}

if (TreeMenuConfiguration.hideMenuWhileLoading) {
_forEach.call (TreeMenuConfiguration.targetIds, function (id) {
var stm = new SecretTreeMenu (id);
stm.hideTemporarily ();
TreeMenuConfiguration.secretTreeMenus[id] = stm;
} )
}

8   名前: Pid : 2006/08/08(火) 14:36
// methods for TreeMenu

function _isTreeBranch () {
switch (this.nodeName) {
case 'OL' : case 'UL' : return true;
default : return false;
}
}

function _hasTreeBranch () {
return _some.call (this.childNodes, function (node) {
if (_isTreeBranch.call (node)) return true;
} );
}

function _switchBranchDisplay (value) {
this.style.display = value ? value :
(! this.style.display || 'block' == this.style.display) ? 'none' : 'block';
_switchBranchClass.call (this.parentNode, 'block' == this.style.display);
}

function _switchBranchClass (block) {
if (block) this.className = this.className.replace ('tree-menu-closed', 'tree-menu-opened');
else this.className = this.className.replace ('tree-menu-opened', 'tree-menu-closed');
}

function _switchChildBranches (displayValue) {
_forEach.call (this.childNodes, function (node) {
if (_isTreeBranch.call (node)) _switchBranchDisplay.call (node, displayValue);
} );
}

function _scanBranchLevel (root) {
var n = 0;
var tmp = this;
while (tmp != root && (tmp = tmp.parentNode)) ++n;
return n;
}

function _collapseParentBranches (level) {
var tmp = this;
var I = level + 1;
var i = 0;
do if ('LI' == tmp.nodeName) _switchChildBranches.call (tmp, 'none'); while (++i < I && (tmp = tmp.parentNode));
}

9   名前: Pid : 2006/08/08(火) 14:36
function _checkCurrentBranch (currentBranch, currentLevel) {
if (_hasTreeBranch.call (currentBranch)) {
var previousBranch = this.previousBranch;
var previousLevel = this.previousLevel;
var level = previousLevel - currentLevel;
if (! previousBranch) _switchChildBranches.call (currentBranch);
else if (_contains.call (previousBranch, currentBranch)) _switchChildBranches.call (currentBranch);
else if (_contains.call (currentBranch, previousBranch)) _collapseParentBranches.call (previousBranch, level);
else {
_collapseParentBranches.call (previousBranch, level);
_switchChildBranches.call (currentBranch);
}
this.previousBranch = currentBranch;
this.previousLevel = currentLevel;
}
}

function _initBranch (node) {
if ('LI' == node.nodeName) {
node.className += ' tree-menu-closed';
_addEventListener.call (node, 'mousedown', (function (thisObj) {
return function (e) {
/*@if (@_jscript)
var e = window.event;
var currentBranch = e.srcElement;
e.cancelBubble = true;
@else@*/
var currentBranch = e.target;
e.stopPropagation ();
/*@end@*/
! e.shiftKey && _checkCurrentBranch.call (thisObj, currentBranch, _scanBranchLevel.call (currentBranch, thisObj.root));
}
} )(this), false);
}
}

function _forEachBranch (root, displayValue, callback) {
_forEach.call ((root || this.root).childNodes, function (node) {
if (1 /* Node.ELEMENT_NODE */ != node.nodeType) return;
callback && callback.call (this, node);
_switchChildBranches.call (node, displayValue);
node.childNodes.length && _forEachBranch.call (this, node, displayValue, callback);
}, this);
}

10   名前: Pid : 2006/08/08(火) 14:36
// general methods

function _forEach (callback, thisObj) {
var I = this.length;
var i = 0;
do callback.call (thisObj || null, this[i], i, this); while (++i < I);
}

function _some (callback, thisObj) {
var I = this.length;
var i = 0;
do if (callback.call (thisObj || null, this[i], i, this)) return true; while (++i < I);
return false;
}

function _createCSSStyleSheet (title, media) {
var head = document.getElementsByTagName ('head')[0];
var node = document.createElement ('style');
node.type = 'text/css';
node.title = title || null;
node.media = media || null;
return head.appendChild (node);
}

function _addEventListener (type, listener, useCapture) {
this./*@if (@_jscript) attachEvent ('on' + @else@*/ addEventListener (/*@end@*/ type, listener, useCapture);
}

function _contains (node) {
do if (this == node) return true; while (node = node.parentNode);
return null;
}

////////////////////////////////////////////////////////////////////////
} )();


※連投すみません。適宜インデント・改行を入れて下さい。

11   名前: 花子 : 2006/08/08(火) 14:36
返信が遅くなってしまい、申し訳ありません。
回答、有り難うございます。頼ってしまいっぱなしでスイマセン。

あれから、もうちょっと自分でも頑張ってみようと思い調べてみたところ、
http://himajin.moo.jp/
のツリーメニュー2段階というものがあったので試してみました。

<html><head>
<META HTTP-EQUIV="Content-type" CONTENT="text/html; charset=Shift_JIS">
<TITLE>ツリーメニューU(2段階)</TITLE>
<style type=text/css><!--
.sub div{display:none;}
--></style>
<script language=JavaScript ><!--
chMenu=0;subMenu=0;
function subopen(tName){
tMenu=(document.all)?document.all(tName).style:document.getElementById(tName).style;
if(tName.substring(0, 3)!="sub"){
if(chMenu)chMenu.display="none";
if(subMenu){subMenu.display="none";subMenu=0;}
if(chMenu==tMenu){chMenu=0;}
else{chMenu=tMenu;
tMenu.display="block";}
}else{
if(subMenu)subMenu.display="none";
if(subMenu==tMenu){subMenu=0;}
else{subMenu=tMenu;
tMenu.display="block";}
}
}/* himajin.moo.jp */
// --></script>

</head>

<BODY>
<table><tr><td width=200 valign=top >
<br><br>
<table cellspacing=0 cellpadding=0>
<tr><td class="main" onClick="subopen('menu1')">メニュー
</td></tr><tr>
<td class="sub"><div ID="menu1">
<a href="JavaScript:subopen('submenu1_1')">子メニュー1</a><BR>
<div ID="submenu1_1">
<LI>SリンクT<BR>
<LI>SリンクU<BR>
</div>
<a href="JavaScript:subopen('submenu1_2')">子メニュー2</a><BR>
<div ID="submenu1_2">
<LI>SリンクT<BR>
<LI>SリンクU<BR>
</div>
<a href="JavaScript:subopen('submenu1_3')">子メニュー3</a><BR>
<div ID="submenu1_3">
<LI>SリンクT<BR>
<LI>SリンクU<BR>
</div>
<a href="JavaScript:subopen('submenu1_4')">子メニュー4</a><BR>
<div ID="submenu1_4">
<LI>SリンクT<BR>
<LI>SリンクU<BR>
</div>
</div></td></tr></table>
</body>
</html>

このようにしてみたのですが、教えてもらった方法におとる部分はありますか?
もし、質問したくせに別の方法を使って気分を害されたなら申し訳ありません。

12   名前: Pid : 2006/08/08(火) 14:36
> 質問したくせに別の方法を使って気分を害されたなら

いえ,そんなことは全然ないのでお気になさらずに (^^)。ご自分で使いやすいものを選択して下さい。ついでに以下も紹介してみます。

http://inspire.server101.com/js/xc/
http://kapu.iwoky.jp/rcug/popupmenu2.htm
http://www2.ocn.ne.jp/%7Eyoochan/decoration/JavaScript/sample/DHTML_samp13.htm

http://www8.plala.or.jp/MaghMell/js/folded_list.html
http://mugi.cc/js/tree/tree.htm
http://www.din.or.jp/~hagi3/JavaScript/JSTips/Std/fmenu.htm
http://www.tohoho-web.com/how2/tec2.htm#treeMenu

http://javascript.cooldev.com/scripts/cooltree/


>>11 をお使いになるのなら,以下の点を修正して下さい。

・head 要素内に <meta http-equiv="Content-Script-Type" content="text/javascript"> を追加。
(タグ内にイベント属性を書く時は必要)

・script 要素の language="JavaScript" を削除,type="text/javascript" を追加。
(script 要素には type 属性が必須,language 属性は廃止予定)

・関数 subopen の直後を var tMenu = (document.getElementById) ? document.getElementById(tName).style : document.all(tName).style; に修正。
(変数は var 宣言しておくこと,優先順位の高いものから評価すること)

・関数 subopen の最後に return false; を追加。
(以下で要素本来のイベントを抑制するのに使う)

・a 要素開始タグを <a onclick="return subopen('submenu1_1');" onkeyup="return this.onclick();"> に修正。
(マウスが使えない環境でもキー操作できるようにする,もし IE で :hover などのスタイルを指定したければ,href="#" でも付け足しておくと良い)

・非スクリプト環境ではメニューが開かず悲惨なことになりますので,必ず,noscript 要素などで別のナビゲーションを用意して下さい。

HTML が間違っているのは配布元の責任ではありませんね (^^;)。なお細かい注意ですが,全角ローマ数字は機種依存文字ですので,Web 上での使用は控えて下さい(Unicode なら構いませんが)。

13   名前: 花子 : 2006/08/08(火) 14:36
回答、有り難うございます。
他の方法まで紹介してもらえ、本当に有り難うございます!
ローマ字についてのご指摘、ありがとうございました。
メニューの書き換えをするときは、しっかり直しておこうとおもいます。
初めから最後までお世話になりっぱなしなのですね;;

申し訳ないのですが、私はJavaScriptについて無知なためか、
>・関数 subopen の直後を var tMenu = (document.getElementById) ? document.getElementById(tName).style : document.all(tName).style; に修正。
(変数は var 宣言しておくこと,優先順位の高いものから評価すること)

>・関数 subopen の最後に return false; を追加。
(以下で要素本来のイベントを抑制するのに使う)

>・非スクリプト環境ではメニューが開かず悲惨なことになりますので,必ず,noscript 要素などで別のナビゲーションを用意して下さい。

これを、どこをどう変えればいいのか分かりません。
調べてみたのですが、なかなか探し出せませんでした。
まずはJavaSvriptについてから勉強するべきなのかもしれませんが、そうすると随分先になってしまうかと思うので…
もし宜しければ、教えていただけないでしょうか?
こんなに親切に教えていただいているのに、申し訳ありません。


14   名前: Pid : 2006/08/08(火) 14:36  ID:7ZLUWR5F
もう解決されたと思いますが一応。

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
    <meta http-equiv="Content-Script-Type" content="text/javascript">
    <title>ツリーメニュー(2 段階)</title>
    <script type="text/javascript">

function subopen  (tName) {
  var tMenu = subopen.get (tName).style;
  
  if (tName.substring (0, 3) != "sub") {
    with (subopen) {
      if (chMenu) chMenu.display = "none";
      if (subMenu) { subMenu.display = "none"; subMenu = null; }
      if (chMenu == tMenu) chMenu = null;
      else { chMenu = tMenu; tMenu.display = "block"; }
    }
  } else {
    with (subopen) {
      if (subMenu) subMenu.display = "none";
      if (subMenu == tMenu) subMenu = null;
      else { subMenu = tMenu; tMenu.display = "block"; }
    }
  }
  
  return false;
}

subopen.chMenu = null;
subopen.subMenu = null;
subopen.get = (document.getElementById)
    ? function (id) {
        return document.getElementById (id);
    }
    : function (id) {
        return document.all (id);
    }

// スクリプトが動作する場合のみスタイル適用
subopen.init = function () {
  document.write ('\u003Cstyle type="text/css">.sub { display: none; }\u003C/style>');
}

subopen.init ();

</script>

<h1>ツリーメニュー展開</h1>

<ul>
  <li><a href="#" onclick="return subopen ('menu1');" onkeyup="return this.onclick ();">メニュー</a>
    <ul id="menu1" class="sub">
      <li><a href="#" onclick="return subopen ('submenu1_1');" onkeyup="return this.onclick ();">子メニュー1</a>
        <ul id="submenu1_1">
          <li>S リンク I</li>
          <li>S リンク II</li>
        </ul>
      </li>
      <li><a href="#" onclick="return subopen ('submenu1_2');" onkeyup="return this.onclick ();">子メニュー2</a>
        <ul id="submenu1_2">
          <li>S リンク I</li>
          <li>S リンク II</li>
        </ul>
      </li>
    </ul>
  </li>
</ul>


15   名前: 琴美 : 2006/08/08(火) 14:36  ID:GCG7qoMp
有り難うございました!!
変に改造すると、作動しなくなってしまうので諦めようと思っていたので助かりました。
これを期にJavaScriptも勉強しなければと思います。
この度は迷惑をかけて申し訳ありませんでした。
色々と親切に教えてくださり有り難う御座いました。
本当に助かりました。

16   名前: 花子 : 2006/08/08(火) 14:36  ID:GCG7qoMp
申し訳ありません。
上のコメントは私、花子の書いたものです。
他の掲示板で使っていたものを使ってしまいました。
掲示板がリニューアルされ、編集のやり方がわからなかったもので、ここでお詫び申し上げます。
すいませんでした。

17   名前: 青木 : 2006/08/08(火) 14:36  ID:m4oTyBsh
はじめまして。
私も、花子さんと似たようなのを探してここにたどり着いたのですが、
例えばこれ(↓)を使ったときに、一番最初のメニューがなくて、いきなり子メニューが並んでるようにはできないでしょうか?

<html><head>
<META HTTP-EQUIV="Content-type" CONTENT="text/html; charset=Shift_JIS">
<TITLE>ツリーメニューU(2段階)</TITLE>
<style type=text/css><!--
.sub div{display:none;}
--></style>
<script language=JavaScript ><!--
chMenu=0;subMenu=0;
function subopen(tName){
tMenu=(document.all)?document.all(tName).style:document.getElementById(tName).style;
if(tName.substring(0, 3)!="sub"){
if(chMenu)chMenu.display="none";
if(subMenu){subMenu.display="none";subMenu=0;}
if(chMenu==tMenu){chMenu=0;}
else{chMenu=tMenu;
tMenu.display="block";}
}else{
if(subMenu)subMenu.display="none";
if(subMenu==tMenu){subMenu=0;}
else{subMenu=tMenu;
tMenu.display="block";}
}
}/* himajin.moo.jp */
// --></script>

</head>

<BODY>
<table><tr><td width=200 valign=top >
<br><br>
<table cellspacing=0 cellpadding=0>
<tr><td class="main" onClick="subopen('menu1')">メニュー
</td></tr><tr>
<td class="sub"><div ID="menu1">
<a href="JavaScript:subopen('submenu1_1')">子メニュー1</a><BR>
<div ID="submenu1_1">
<LI>SリンクT<BR>
<LI>SリンクU<BR>
</div>
<a href="JavaScript:subopen('submenu1_2')">子メニュー2</a><BR>
<div ID="submenu1_2">
<LI>SリンクT<BR>
<LI>SリンクU<BR>
</div>
<a href="JavaScript:subopen('submenu1_3')">子メニュー3</a><BR>
<div ID="submenu1_3">
<LI>SリンクT<BR>
<LI>SリンクU<BR>
</div>
<a href="JavaScript:subopen('submenu1_4')">子メニュー4</a><BR>
<div ID="submenu1_4">
<LI>SリンクT<BR>
<LI>SリンクU<BR>
</div>
</div></td></tr></table>
</body>
</html>

18   名前: 青木 : 2006/08/08(火) 14:36  ID:m4oTyBsh
はじめまして。
私も、花子さんと似たようなのを探してここにたどり着いたのですが、
↓のようにしたときに、メニューではなく、いきなり子メニューが並んでるようにはできないでしょうか?
<html><head>
<META HTTP-EQUIV="Content-type" CONTENT="text/html; charset=Shift_JIS">
<TITLE>ツリーメニューU(2段階)</TITLE>
<style type=text/css><!--
.sub div{display:none;}
--></style>
<script language=JavaScript ><!--
chMenu=0;subMenu=0;
function subopen(tName){
tMenu=(document.all)?document.all(tName).style:document.getElementById(tName).style;
if(tName.substring(0, 3)!="sub"){
if(chMenu)chMenu.display="none";
if(subMenu){subMenu.display="none";subMenu=0;}
if(chMenu==tMenu){chMenu=0;}
else{chMenu=tMenu;
tMenu.display="block";}
}else{
if(subMenu)subMenu.display="none";
if(subMenu==tMenu){subMenu=0;}
else{subMenu=tMenu;
tMenu.display="block";}
}
}/* himajin.moo.jp */
// --></script>

</head>

<BODY>
<table><tr><td width=200 valign=top >
<br><br>
<table cellspacing=0 cellpadding=0>
<tr><td class="main" onClick="subopen('menu1')">メニュー
</td></tr><tr>
<td class="sub"><div ID="menu1">
<a href="JavaScript:subopen('submenu1_1')">子メニュー1</a><BR>
<div ID="submenu1_1">
<LI>SリンクT<BR>
<LI>SリンクU<BR>
</div>
<a href="JavaScript:subopen('submenu1_2')">子メニュー2</a><BR>
<div ID="submenu1_2">
<LI>SリンクT<BR>
<LI>SリンクU<BR>
</div>
<a href="JavaScript:subopen('submenu1_3')">子メニュー3</a><BR>
<div ID="submenu1_3">
<LI>SリンクT<BR>
<LI>SリンクU<BR>
</div>
<a href="JavaScript:subopen('submenu1_4')">子メニュー4</a><BR>
<div ID="submenu1_4">
<LI>SリンクT<BR>
<LI>SリンクU<BR>
</div>
</div></td></tr></table>
</body>
</html>


19   名前: m035 ◆Wpzr1YKOiq : 2006/08/08(火) 14:36  [URL]  ID:4KIacXXc
>>18
面倒だと思わずに、新しいスレッドを立てて質問しましょう。

以下一応回答。
CSS部分を消せば最初から表示された状態に出来るかと思います。
それと、<script language=JavaScript >は<script type="text/javascript">に。

20   名前: 青木 : 2006/08/08(火) 14:36  ID:m4oTyBsh
すいません;
繋げた方がいいかなと思ってしまいました><;
次回気をつけます。

そして素早い回答ありがとうございました!
なんとかがんばってやってみます!

一覧へ戻る