DD: Reordering a List(その2)

さきほどの例(DD: Reordering a List)を見た際、冗長なプログラムと思ったが、以下の画面は、前の例で作成したDDList(
YAHOO.util.DDProxyを継承して作成)をまったく変えずに、タグとStyleのみ変更して作成したもの。
List1の中にList2が入れ子になっているが、これもDrag & Dropで同様の動きをする。
(ただし、「現在の順番」の表示時に、List1にList2の内容が混じってしまう。これは、修正すれば回避可能)

先ほどのようなリストと同様に、以下のような入れ子のリストもよく登場するから、使えるかも。

以下にソースコードの全文を示す。

<HTML>
<HEAD>
<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
<META http-equiv="Content-Style-Type" content="text/css">
<TITLE>Ajax_Sampling</TITLE>
<style type="text/css"> 
div.workarea { padding:10px; float:left }

.div1 {
    border: 2px solid gray;
    padding:2;
}

.div2 {
    border: 1px solid gray;
    padding:2;
}


ul.draglist li {
    margin: 1px;
    cursor: move;
    zoom: 1;
}

li.list1 {
    background-color: #D1E6EC;
    border:1px solid #7EA6B2;
}

li.list2 {
	margin: 10px;
    background-color: #D8D4E2;
    border:1px solid #6B4C86;
}

li.list3 {
    background-color: #D1E6EC;
    border:1px solid #7EA6B2;
}


</style>

<!-- 読み込むjs --> 
<script type="text/javascript" src="scripts/yui/yahoo-dom-event/yahoo-dom-event.js" >
</script> 
<script type="text/javascript" src="scripts/yui/dragdrop/dragdrop-min.js" >
</script> 
<script type="text/javascript" src="scripts/yui/animation/animation-min.js" >
</script> 

<script type="text/javascript">
var Dom = YAHOO.util.Dom;
var Event = YAHOO.util.Event;
var DDM = YAHOO.util.DragDropMgr;

//////////////////////////////////////////////////////////////////////////////
//「現在の順番」表示、「バックグラウンドの消去」の処理。
//////////////////////////////////////////////////////////////////////////////

YAHOO.example.DDApp = {
    init: function() {

        var rows=3,cols=3,i,j;
        for (i=1;i<cols+1;i=i+1) {
            // ul要素はddTargetとしてインスタンス化
            new YAHOO.util.DDTarget("ul"+i);
        }

        for (i=1;i<cols+1;i=i+1) {
            for (j=1;j<rows+1;j=j+1) {
                // ul要素はddListとしてインスタンス化
                new YAHOO.example.DDList("li" + i + "_" + j);
            }
        }

        Event.on("showButton", "click", this.showOrder);
    },
	//「現在の順番」を拾う処理
    showOrder: function() {
    	// この関数は下で使う。
    	var parseList = function(ul, title) {
            var items = ul.getElementsByTagName("li");
            var out = title + ": ";
            for (i=0;i<items.length;i=i+1) {
                out += items[i].id + " ";
            }
            return out;
        };

        var ul1=Dom.get("ul1"), ul2=Dom.get("ul2"),u13=Dom.get("ul3");
        alert(parseList(ul1, "List 1") + "\n" + parseList(ul2, "List 2")
        		 + "\n" + parseList(ul3, "List 3"));

    },

};

//////////////////////////////////////////////////////////////////////////////
// custom drag and drop implementation
//////////////////////////////////////////////////////////////////////////////

// DDProxyを継承して、DDListを作成するための準備。
YAHOO.example.DDList = function(id, sGroup, config) {

	// スーパークラスのコンストラクタの呼び出し。
    YAHOO.example.DDList.superclass.constructor.call(this, id, sGroup, config);

    //this.logger = this.logger || YAHOO;
    var el = this.getDragEl();
    // Domを1/3の透過とする。
    Dom.setStyle(el, "opacity", 0.67); 

    this.goingUp = false;
    this.lastY = 0;
};

//DDProxyを継承して、DDListを作成する。
//thisは、DDListのインスタンスをあらわす。
YAHOO.extend(YAHOO.example.DDList, YAHOO.util.DDProxy, {

	// startDragのoverride
    startDrag: function(x, y) {
		// this.logger.log(this.id + " startDrag");

		// ドラッグされるProxyElementを取得
        var dragEl = this.getDragEl();
		// ドラッグされる元のElementを取得
        var clickEl = this.getEl();
        // 元のエレメントは、非表示にする。
        Dom.setStyle(clickEl, "visibility", "hidden");

		// ProxyElementに、元のエレメントの要素を追加。
        dragEl.innerHTML = clickEl.innerHTML;
		// ProxyElementに、元のエレメントのスタイルをコピー。
        Dom.setStyle(dragEl, "color", Dom.getStyle(clickEl, "color"));
        Dom.setStyle(dragEl, "backgroundColor", Dom.getStyle(clickEl, "backgroundColor"));
        Dom.setStyle(dragEl, "border", "2px solid gray");
    },

	// endDragのoverride
	// startDragされて、Dropされずに、Mouseupされた場合に元に戻す処理。
    endDrag: function(e) {
    	// thisは、DDListのインスタンスをあらわす。
		// DDListはli要素についてインスタンス化される。
		
    	// ドラッグさている元Elementを取得
        var srcEl = this.getEl();
		// ドラッグされているProxyElementを取得
        var proxy = this.getDragEl();

		// ProxyElementをみせて、元Elementの位置を取得して
		// Anim(Motion)で戻る。
        Dom.setStyle(proxy, "visibility", "");
        var a = new YAHOO.util.Motion( 
            proxy, { 
                points: { 
                    to: Dom.getXY(srcEl)
                }
            }, 
            0.2, 
            YAHOO.util.Easing.easeOut 
        )
        var proxyid = proxy.id;
        // 元エレメントのID
        var thisid = this.id;

		// 上のMotionが終わったら、proxyを消して、元のエレメントを見せる。
        a.onComplete.subscribe(function() {
                Dom.setStyle(proxyid, "visibility", "hidden");
                Dom.setStyle(thisid, "visibility", "");
            });
		//Motionの発火
		a.animate();
    },

    // onDragOverで挿入が行われていることに注意。
   	// (注)idは、Dragされた要素が、落っことされた要素のid	
    onDragDrop: function(e, id) {

    	// DDM.interactionInfo.dropはonDragDropでinteractions Pointを
    	// 意味する。(APIドキュメント)
		// 1回のInteractionが行われたら。
		// ただしい移動(挿入、移動)後はinteraction情報がクリアされる。
		// 以下の条件を満たすのは、liがUL(のドロップゾーン)にinteractする場合。
		// これ以外は、endDragで戻してしまう。
		if (DDM.interactionInfo.drop.length === 1) {

        	// Interact(Drop)したときのカーソルポジション
        	// ※PointはYAHOO.util.Point(PointはRegionのサブクラス)
            var pt = DDM.interactionInfo.point; 

        	// Interact(Drop)したときの元要素の領域
        	// ※RegionはYAHOO.util.Regionのサブクラスと思われる。
            var region = DDM.interactionInfo.sourceRegion; 

			// regionがpointを含まなければ、子要素として追加。
            if (!region.intersect(pt)) {
                //Dropされた場所の要素を取得。(ULを拾っている)
                var destEl = Dom.get(id);
                //Drag and Dropされたオブジェクト
                var destDD = DDM.getDDById(id);
                //this.getElで取れるのは、移動元のelement
                //移動元のエレメントをDropされたElementの最後の子要素にする。
                destEl.appendChild(this.getEl());
                destDD.isEmpty = false;
				//DDの座標のリセット(Interaction情報のクリア)
                DDM.refreshCache();
            }

        }
    },

    // Drag中の処理。
    onDrag: function(e) {

		// y軸方向の移動量
    	var y = Event.getPageY(e);
		
        if (y < this.lastY) {
            // goingUpはプロパティーとして定義されていることに注意
            this.goingUp = true;
        } else if (y > this.lastY) {
            this.goingUp = false;
        }

		// lastYもプロパティーとして定義されていることに注意
        this.lastY = y;
    },

   	// (注)idは、DragOverされた要素のid	
	// DragOverされたら、挿入してしまう。
   	onDragOver: function(e, id) {
    
		// ドラッグされた元要素のelementの取得
    	var srcEl = this.getEl();
		// ドラッグオーバーされた要素のelementの取得
        var destEl = Dom.get(id);

        // li要素にドラッグオーバーされたら、以下の処理。
        if (destEl.nodeName.toLowerCase() == "li") {
            var orig_p = srcEl.parentNode;
            var p = destEl.parentNode;

			// このDDListのインスタンスが上を向いて動いていれば、前に挿入
			// goingUpは、onDragで計ってある。
			if (this.goingUp) {
                p.insertBefore(srcEl, destEl); // insert above
   			// そうでなければ、後に挿入
            } else {
                p.insertBefore(srcEl, destEl.nextSibling); // insert below
            }
			//DDの座標のリセット(Interaction情報のクリア)
            DDM.refreshCache();
        }
    }
});

Event.onDOMReady(YAHOO.example.DDApp.init, YAHOO.example.DDApp, true);

</script>
</HEAD>

<BODY>
<div class="workarea">
  <div class="div1">
  <h3>List1</h3>
  <ul id="ul1" class="draglist">
    <li class="list1" id="li1_1">list 1, item 1</li>
    <li class="list1" id="li1_2">list 1, item 2</li>
  	  <div  class="div2">
      <h3>List2</h3>
      <ul id="ul2" class="draglist">
        <li class="list2" id="li2_1">list 2, item 1</li>
        <li class="list2" id="li2_2">list 2, item 2</li>
        <li class="list2" id="li2_3">list 2, item 3</li>
      </ul>
      </div>
    <li class="list1" id="li1_3">list 1, item 3</li>
  </ul>
  </div>
  <div class="div1">
  <h3>List3</h3>
  <ul id="ul3" class="draglist">
    <li class="list3" id="li3_1">list 3, item 1</li>
    <li class="list3" id="li3_2">list 3, item 2</li>
    <li class="list3" id="li3_3">list 3, item 3</li>
  </ul>
  </div>
</div>

<div id="user_actions">
  <input type="button" id="showButton" value="現在の順番" />
</div>
</BODY>
</HTML>