CodeZine(コードジン)

特集ページ一覧

XMLとXSLによるフォルダツリーのドラッグ&ドロップ

XMLとXSLを使った高度なUIデザイン:パート4

  • ブックマーク
  • LINEで送る
  • このエントリーをはてなブックマークに追加
2006/01/19 12:00

この連載では、1回に1つずつ、XMLとXSL(XML用のスタイルシート言語)を使用して高度なユーザーインタフェース(UI)コンポーネントを作成していきます。今回は、第1回に作成したフォルダツリーを発展させ、フォルダツリー内のエンティティをドラッグして別のツリー内にドロップする方法を紹介します。

はじめに

 この連載では、XMLとXSLを使った高度なUIデザインに挑戦します。1回に1つずつ、XMLとXSL(XML用のスタイルシート言語)を使用して高度なユーザーインタフェース(UI)コンポーネントを作成していきます。

 今回は、第1回に作成したフォルダツリーを発展させ、フォルダツリー内のエンティティをドラッグして別のツリー内にドロップする方法を紹介します。

ドラッグ&ドロップコントロール

 今回のドラッグ&ドロップコントロール(DragControl)はクライアント側に存在し、次のように定義されます。

function DragControl() {
  this.entity = null;
  this.target = null;
  this.origin = null;
  this.enabled = false;

  this.beginX = null;
  this.beginY = null;

  this.beginDrag = beginDrag;
  this.endDrag = endDrag;
  this.setTarget = setTarget;
  this.setPosition = setPosition;
  this.move = move;
  this.reset = reset;
}

 このコントロールには、次のメンバが含まれます。

プロパティ

entity

 entityプロパティには、ある場所から別の場所へと移動するオブジェクトへの参照が格納されます。移動は、同じツリー内での移動、または別のツリーへの移動のどちらでも構いません。このプロパティはbeginDrag()メソッド内で設定されます。

target

 targetプロパティには、現在のドラッグ&ドロップ操作のドロップ先への参照が格納されます。ユーザーがマウスポインタを別のエンティティに動かすと、値が変更されます。このプロパティはsetTarget()メソッド内で設定されます。

origin

 originプロパティには、オブジェクトのドラッグ元フォルダへの参照が格納されます。ユーザーがドラッグ先を指定せずにマウスの左ボタンを放した場合は、このフォルダの場所にエンティティが戻されます。originプロパティは、beginDrag()メソッドによって設定されます。

enabled

 ドラッグ&ドロップ操作を実際に開始するのはenabledプロパティです。ユーザーがエンティティを選択した状態でマウスを一定ピクセル数だけドラッグすると、このプロパティがtrueに設定されます。今回のコードでは、開始とみなされるのに必要なドラッグ範囲が5ピクセルになっています。このプロパティの変更はmove()メソッド内で行います。

beginX

 このプロパティには、ドラッグ&ドロップルーチン開始時点のマウスポインタのX座標が入ります。beginXプロパティはbeginDrag()メソッド内で設定されます。

beginY

 このプロパティには、ドラッグ&ドロップルーチン開始時点のマウスポインタのY座標が入ります。beginYプロパティはbeginDrag()メソッド内で設定されます。

メソッド

beginDrag()

 beginDrag()メソッドの定義は次のとおりです。

function beginDrag(obj) {
  if(window.event.button == 1) {

    document.onmousemove =
        function anonymous() { dragControl.move(obj) };

    this.origin = obj.parentNode;
    this.entity = obj;

    this.beginX = window.event.x;
    this.beginY = window.event.y;

    window.event.cancelBubble = true;
  }
}

 このメソッドは、XSL変換(XSLT)スタイルシート内でエンティティに関連付けられています。

図1 beginDrag()メソッドの配置
図1 beginDrag()メソッドの配置

 このメソッドでは、まず、(コンテキストメニュー用に使われる)マウスの右ボタンではなく、左ボタンによってイベントが発生したことを確認します。次に、適切なプロパティ値を設定し、クライアントブラウザ内でのイベント伝播をキャンセルします。

endDrag()

 endDrag()メソッドの定義は次のとおりです。

function endDrag() {
  if(this.entity != null) {
    this.entity.style.position = "static";
    this.entity.style.left = null;
    this.entity.style.top = null;
    this.entity = this.entity.removeNode(true);

    if(this.target != null) {
      dragControl.target.appendChild(this.entity);
      if(this.target.open != "true") {
        clickOnEntity(this.target);
      }
    }
    else {
      this.origin.appendChild(this.entity);
    }

    document.onmousemove = null;
    document.onmouseup = null;

    this.entity = null;
    this.target = null;
    this.enabled = false;
  }
}

 このメソッドは、まずエンティティが選択されていることを確認します。次に、ユーザーが現在ドラッグ先を選択しているかどうかに応じて、エンティティを元の場所に戻すか(ドラッグ先が選択されていない場合)、新しい場所に移動させるか(ドラッグ先が選択されている場合)のいずれかを行います。

 このメソッドは、XSLTスタイルシート内でエンティティに関連付けられています。

図2 endDrag()メソッドの配置
図2 endDrag()メソッドの配置

setTarget()

 setTarget()メソッドの定義は次のとおりです。

function setTarget(obj) {
  if(this.entity != null && this.entity != obj) {
      this.target = obj;
  }
  window.event.cancelBubble = true;
}

 このメソッドは、まず現在のエンティティが存在すること、およびこの選択中のエンティティが移動先のエンティティでないことを確認します。次に、DragControltargetプロパティを設定します。その後、DragControlはクライアントブラウザ内でのイベント伝播をキャンセルします。

 このメソッドは、XSLTスタイルシート内でエンティティに関連付けられています。

図3 setTarget()メソッドの配置
図3 setTarget()メソッドの配置

setPosition()

 setPosition()メソッドの定義は次のとおりです。

function setPosition() {
  this.entity.style.left = window.event.x;
  this.entity.style.top = window.event.y - 10;
}

 このメソッドは、選択されているエンティティのXおよびY座標を、単純に現在のマウスイベントのXおよびY座標に書き換えます。このメソッドはmove()メソッド内から呼び出されます。

 このメソッドは、サンプルの「tree.js」ファイル内でエンティティに関連付けられています。

図4 setPosition()メソッドの配置
図4 setPosition()メソッドの配置

move()

 move()メソッドの定義は次のとおりです。

function move(obj) {
  if(window.event.x < this.beginX - 5 ||
     window.event.x > this.beginX + 5 ||
     window.event.y < this.beginY -5 ||
     window.event.y > this.beginY + 5 &&
     this.enabled == false) {
    obj.style.position = "absolute";
    obj.style.filter = "alpha(opacity='60')";
    this.setPosition();
    this.enabled = true;

    obj = obj.removeNode(true);
    document.body.appendChild(obj);
    document.onmouseup =
        function anonymous() { dragControl.endDrag() };
  }
  else if(this.enabled == true) {
    this.setPosition();
  }
}

 このメソッドは、まず、ユーザーが実際にエンティティを(X軸/Y軸、正/負を問わず)いずれかの方向に少なくとも5ピクセル以上ドラッグしていることを確認します。次に、このエンティティを現在のツリーから取り出してドキュメント本体に移動させます。エンティティが常にマウスカーソルの隣に表示されるようにするために、このメソッドをドキュメントオブジェクトのonmousemoveイベントを介して継続的に呼び出す必要があります。

 このメソッドは、サンプルの「tree.js」ファイル内でエンティティに関連付けられています。

図5 move()メソッドの配置
図5 move()メソッドの配置

reset()

 reset()メソッドの定義は次のとおりです。

function reset() {
  document.onmouseup = null;
  document.onmousemove = null;

  this.entity = null;
  this.origin = null;
  this.target = null;
}

 このメソッドは、ドキュメントおよびDragControlオブジェクトのクリーンアップだけを行います。ドラッグ&ドロップが完了またはキャンセルされると、必ずこのメソッドが呼び出されます。

 このメソッドは、XSLTスタイルシート内でエンティティに関連付けられています。

図6 reset()メソッドの配置
図6 reset()メソッドの配置

 それでは、フォルダツリーのドラッグ&ドロップコントロールのライブデモを見てみましょう。このデモには2つのツリーがあり、その下に、順序を示す「One」から「Six」までのタイトルを持つエンティティが用意されています。「One」の下に「Two」、「Two」の下に「Three」というようにそれぞれがネストされるようにドラッグしてみてください。図7に示すように、「One」というエンティティをTree1からTree2にドラッグすると、先ほど番号順に並べた(ネストさせた)「One」以下のすべてのエンティティもそれにならってTree1からTree2に移動します。

図7 ツリーからツリーへのドラッグ&ドロップ
図7 ツリーからツリーへのドラッグ&ドロップ

終わりに

 本稿の内容が、Webアプリケーションインタフェースの質的向上に役立てば幸いです。質問・コメント・提案があれば、筆者紹介にあるアドレスまで遠慮なくメールをお送りください。

本連載のその他の記事



  • ブックマーク
  • LINEで送る
  • このエントリーをはてなブックマークに追加

あなたにオススメ

著者プロフィール

  • Joe Slovinski(Joe Slovinski)

    1993年以来、Webアプリケーションの開発に継続的に携わる。本稿で紹介したコードについてのお問い合わせはJoe Slovinskiまで。

  • japan.internet.com(ジャパンインターネットコム)

    japan.internet.com は、1999年9月にオープンした、日本初のネットビジネス専門ニュースサイト。月間2億以上のページビューを誇る米国 Jupitermedia Corporation (Nasdaq: JUPM) のニュースサイト internet.com や EarthWeb.c...

バックナンバー

連載:japan.internet.com翻訳記事

もっと読む

All contents copyright © 2005-2021 Shoeisha Co., Ltd. All rights reserved. ver.1.5