このセクションでは、ドラッグとドロップの実装例を紹介することにします。
ここでは、パレットの項目をボードにドラッグできる簡単なボードを作ることにします。ユーザーは、特定の型の要素を作るため、パレットにある幾つかの XUL 要素の一つをクリックして、掲示板 (bulletin board) にドラッグできます。
まず、ラッパースクリプトを追加します。
<script src="chrome://global/content/nsDragAndDrop.js"/> <script src="chrome://global/content/nsTransferable.js"/> <script src="chrome://global/content/nsJSSupportsUtils.js"/> <script src="chrome://global/content/nsJSComponentManager.js"/> <script src="dragboard.js"/> |
自分達で書くコードを含む別のスクリプトファイル dragboard.js をインクルードします。
掲示板は、bulletinboard 要素を使って作ることにします。掲示板の幅と高さを設定するため、スタイルプロパティーを幾つか使います。最大サイズも指定します。これによって、新しい要素がドラッグされても、掲示板はリサイズしません。
掲示板は、dragdrop イベントに応答する必要があります。それによって、ユーザーがドラッグすると、要素が作られます。
<bulletinboard id="board"
style="width:300px; height: 300px; max-width: 300px; max-height: 300px"
ondragover="nsDragAndDrop.dragOver(event,boardObserver)"
ondragdrop="nsDragAndDrop.drop(event,boardObserver)">
</bulletinboard>
|
掲示板は、dragdrop イベントと dragdrop イベントに応答するだけで十分です。dragboard.js ファイルに boardObserver を追加しましょう。
次に、ウィンドウの右側にパレットを追加します。これには、新しいボタンを作るためのボタン、チェックボックスを作るためのボタン、その他のテキストボックスを作るためのボタンがあります。このボタンは、draggesture イベントに応答し、ドラッグを開始します。
<box orient="vertical">
<button label="Button"
elem="button" ondraggesture="nsDragAndDrop.startDrag(event,listObserver)"/>
<button label="Check Box"
elem="checkbox" ondraggesture="nsDragAndDrop.startDrag(event,listObserver)"/>
<button label="Text Box"
elem="textbox" ondraggesture="nsDragAndDrop.startDrag(event,listObserver)"/>
</box>
|
nsDragAndDrop オブジェクトは、仕事のほとんどを行なうために呼び出されます。ドラッグされるデータの設定のため、listObserver オブジェクトを作ります。ここで、個々のボタンに追加 elem 属性があることに注意して下さい。これは、自分で作った属性です。XUL はこの処理はせず、無視するだけですが、DOM の getAttribute 関数を使ってその検索ができます。これを行なう必要があるのは、ドラッグによってどの型の要素を作るのかを知るためです。
次に、リスナーオブジェクトを 2 つ定義します。最初は、listObserver です。これには、ドラッグの開始を処理する関数が必要です。
var listObserver = {
onDragStart: function (evt,transferData,action){
var txt=evt.target.getAttribute("elem");
transferData.data=new TransferData();
transferData.data.addDataForFlavour("text/unicode",txt);
}
};
|
関数を一つ定義しました。onDragStart です。これは、必要な時に、nsDragAndDrop が呼び出します。この関数は、ドラッグされるデータを転送オブジェクトに追加します。elem 属性は、ドラッグイベントのターゲットから検索されます。ターゲットは、ドラッグを開始させた要素です。この属性の値は、ドラッグのデータとして使うことにします。
boardObserver には、getSupportedFlavours、onDragOver、onDrop という 3 つの関数が必要です。onDrop 関数は、ドラッグセッションからデータを捉え、適切な型の新しい要素を作ります。
var boardObserver = {
getSupportedFlavours : function () {
var flavours = new FlavourSet();
flavours.appendFlavour("text/unicode");
return flavours;
},
onDragOver: function (evt,flavour,session){},
onDrop: function (evt,dropdata,session){
if (dropdata.data!=""){
var elem=document.createElement(dropdata.data);
evt.target.appendChild(elem);
elem.setAttribute("left",""+evt.pageX);
elem.setAttribute("top",""+evt.pageY);
elem.setAttribute("label",dropdata.data);
}
}
};
|
getSupportedFlavours 関数は、掲示板にドロップできるフレーバーのリストだけを返す必要があります。この場合は、テキストだけを受け入れます。onDragOver 関数には、特別なものは何も必要ありません。そのため、その本体にはコードは追加されていません。
onDrop ハンドラーは、まず、ドラッグセッションに保存される型をもつ新しい要素を作ります。次に、イベントのターゲットである掲示板に新しい要素を追加するため、appendChild を呼び出します。最後に、属性の幾つかを新しい要素に設定します。
掲示板内の要素の位置は、left と top 属性によって決められます。pageX と pageY プロパティーには、ドロップが起こったウィンドウ上のマウスポインターの座標を保存します。これによって、マウスボタンが放された位置に新しい要素を置くことができます。いつでもこのようにできるという訳ではありません。実際には、掲示板に対して相対的なイベントの座標を計算する必要があるからです。ここでは、掲示板は左上にあるので、これは動作します。
label 属性は、ドラッグのデータに設定されます。そのため、ボタンはデフォルトラベルになります。
この例はかなり簡単です。考えられる変更の一つは、テキストの代わりにデータにカスタム型を使うことでしょう。テキストを使う場合の問題は、パレット以外からのドラッグのテキストがたまたま 'button' に設定されているだけで、ボタンが掲示板に作られてしまうことです。カスタム型とは、掲示板がパレット (と、その型がドラッグできるあらゆる場所) からのドラッグだけを受け入れるということです。
最終コードを下に示します。
例 8.7.1
<window title="Widget Dragger" id="test-window"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<script src="chrome://global/content/nsDragAndDrop.js"/>
<script src="chrome://global/content/nsTransferable.js"/>
<script src="chrome://global/content/nsJSSupportsUtils.js"/>
<script src="chrome://global/content/nsJSComponentManager.js"/>
<script src="dragboard.js"/>
<bulletinboard id="board"
style="width:300px; height: 300px; max-width: 300px; max-height: 300px"
ondragover="nsDragAndDrop.dragOver(event,boardObserver)"
ondragdrop="nsDragAndDrop.drop(event,boardObserver)">
</bulletinboard>
<box orient="vertical">
<button label="Button"
elem="button" ondraggesture="nsDragAndDrop.startDrag(event,listObserver)"/>
<button label="Check Box"
elem="checkbox" ondraggesture="nsDragAndDrop.startDrag(event,listObserver)"/>
<button label="Text Box"
elem="textbox" ondraggesture="nsDragAndDrop.startDrag(event,listObserver)"/>
</box>
</window>
|
var listObserver = {
onDragStart: function (evt,transferData,action){
var txt=evt.target.getAttribute("elem");
transferData.data=new TransferData();
transferData.data.addDataForFlavour("text/unicode",txt);
}
};
var boardObserver = {
getSupportedFlavours : function () {
var flavours = new FlavourSet();
flavours.appendFlavour("text/unicode");
return flavours;
},
onDragOver: function (evt,flavour,session){},
onDrop: function (evt,dropdata,session){
if (dropdata.data!=""){
var elem=document.createElement(dropdata.data);
evt.target.appendChild(elem);
elem.setAttribute("left",""+evt.pageX);
elem.setAttribute("top",""+evt.pageY);
elem.setAttribute("label",dropdata.data);
}
}
};
|
(進む) 次は、アウトライナーの作り方を見ることにしましょう。