Posted at

コンポーネントのデータをコピペする方法

More than 3 years have passed since last update.

Sencha Ext JS には AbstractClipboard というクラスがあり、それを拡張して、コンポーネントのデータをコピペするプラグインを作ることができます。

以下、Sencha のブログで紹介された、タグフィールドでコピペできるようにする例です。


コンポーネントのデータをコピペする方法

by Alex Volfson

ユーザーからコンポーネントのデータをコピペする方法を聞かれます。多くのコンポーネントには複雑なインタラクションモデルがあるので、システムデフォルトのコピーでは動作するとは限りません。クリップボードプラグインを使うのは難しそうに見えますが、タグフィールド コンポーネントに実装する方法をご覧に入れましょう。選択されたタグだけをコピペするにはどうしたらいいかを説明します。

Ext.plugin.AbstractClipboard はデフォルトで2つのメソッドを期待します。1つ目は getTextData で、コンポーネントからシステムのクリップボードにコピーしたいデータを特定するためのものです。

2つ目のメソッドは putTextData で、こちらはコンポーネントがペーストされたときに処理する動作を指定します。

以上を念頭に、AbstractClipboard を拡張して tagfield コンポーネント用に動作するようにしたのが次のコードです。

Ext.define('myApp.plugins.TagsClipboard', {

extend: 'Ext.plugin.AbstractClipboard',
alias: 'plugin.tagclipboard',

separator:", ", //システムのクリップボードにコピーされる時に値を区切る記号を定義します

/*
* コピー/切り抜きでクリップボードへのデータの送り方を定義します
*/

getTextData:function(){
var cmp=this.getCmp(); // これはタグフィールド
var selected = cmp.selectionModel.getSelected(); // 選択されているものを取得
var str = "";
for (var x = 0, len = selected.items.length; x < len; x++) {
str += selected.items[x].get(cmp.displayField) + this.separator
}
str = str.slice(0, - this.separator.length);
return str;
},

/*
* ペーストをコンポーネントが処理する方法を定義します
*/

putTextData:function(data,format){
var arrayValues = data.split(this.separator);
var cmp= this.getCmp(),rec, records=[];
// それぞれの文字列を照合して後で setValue を使います
for(var x=0, len=arrayValues.length; x<len; x++){
rec=cmp.getStore().findRecord(cmp.displayField,arrayValues[x],0,false,false,true);
if (rec) {
records.push(rec);
}
}

var combined = records.concat(cmp.getValueRecords());// 既存のレコードとまとめます

cmp.setValue(combined);

return data;
},

privates:{

finishInit: function (comp) {
var me = this;

me.keyMap = new Ext.util.KeyMap({
target: me.getTarget(comp),
//ignoreInputFields: true, // このためにオーバーライドしています
binding: [{
ctrl: true, key: 'x', fn: me.onCut, scope: me
}, {
ctrl: true, key: 'c', fn: me.onCopy, scope: me
}, {
ctrl: true, key: 'v', fn: me.onPaste, scope: me
}]
});

++me.shared.counter;

comp.on({
destroy: 'destroy',
scope: me
});
},
}

})


訳注: 上記に finishInit がありますが、これは AbstractClipboard に元々あるメソッドでそれをオーバーライドしています。AbstractClipboard では、KeyMap の ignoreInputFields を true に設定していますが、多義フィールドは入力フィールドなので、このままだとキーイベントを拾うことができません。そこで、 ignoreInputFields: true としているわけです。


さらに finishinit 内でペーストのリスナーを削除して、ブラウザーに処理させてもいいでしょう。そうした場合の唯一の問題は、タグフィールドが一つのタグしか処理できないことだけです。クリップボードに複数のタグがある場合は、コンポーネントはそれを処理する方法を知りません。これで残りは、このプラグインをtagfield コンポーネントに追加するだけです。

       var shows = Ext.create('Ext.data.Store', {

fields: ['id', 'show'],
data: [{
id: 0,
show: 'Battlestar Galactica'
}, ...]
});

Ext.create('Ext.form.field.Tag', {
plugins:[{ptype:'tagclipboard',separator:' && '}],
fieldLabel: 'Select a Show',
store: shows,
displayField: 'show',
valueField: 'id',
queryMode: 'local',
filterPickList: true,

});

プラグインのインスタンス毎にセパレーターを定義できます。それでは、コピペを楽しんでください。


元ネタ: Top Support Tips | Sencha