Jstreeの右クリックコンテキストメニューの外観をカスタマイズする方法を示すオンラインの例を見ました(contextmenuプラグインを使用)。
たとえば、ユーザーが「ドキュメント」を削除できるようにしますが、「フォルダー」は削除できません(フォルダーのコンテキストメニューから[削除]オプションを非表示にします)。
今、私はその例を見つけることができません。誰かが私を正しい方向に向けることができますか?公式の ドキュメント は実際には役に立ちませんでした。
編集:
1つまたは2つの小さな変更だけでデフォルトのコンテキストメニューが必要なので、メニュー全体を再作成しないことをお勧めします(もちろん、それが唯一の方法である場合はそうします)。私がやりたいのは次のようなものです:
"contextmenu" : {
items: {
"ccp" : false,
"create" : {
// The item label
"label" : "Create",
// The function to execute upon a click
"action": function (obj) { this.create(obj); },
"_disabled": function (obj) {
alert("obj=" + obj);
return "default" != obj.attr('rel');
}
}
}
}
ただし、機能しません。作成アイテムは常に無効になっています(アラートは表示されません)。
contextmenu
プラグインはすでにこれをサポートしています。リンクしたドキュメントから:
items
:オブジェクトまたはオブジェクトを返す関数が必要です。関数が使用される場合、その関数はツリーのコンテキストで起動され、1つの引数(右クリックされたノード)を受け取ります。
そのため、contextmenu
にハードコーディングされたオブジェクトを指定する代わりに、次の関数を提供できます。 「folder」という名前のクラスでクリックされた要素を確認し、「delete」メニュー項目をオブジェクトから削除して削除します。
function customMenu(node) {
// The default set of all items
var items = {
renameItem: { // The "rename" menu item
label: "Rename",
action: function () {...}
},
deleteItem: { // The "delete" menu item
label: "Delete",
action: function () {...}
}
};
if ($(node).hasClass("folder")) {
// Delete the "delete" menu item
delete items.deleteItem;
}
return items;
}
上記は削除オプションを完全に隠しますが、プラグインは関連するアイテムに_disabled: true
を追加することで、その動作を無効にしながらアイテムを表示することもできます。この場合、代わりにif
ステートメント内でitems.deleteItem._disabled = true
を使用できます。
当然のことですが、以前に持っていたものではなく、customMenu
関数を使用してプラグインを初期化することを忘れないでください。
$("#tree").jstree({plugins: ["contextmenu"], contextmenu: {items: customMenu}});
// ^
// ___________________________________________________________________|
編集:右クリックごとにメニューを再作成したくない場合は、削除メニュー項目自体のアクションハンドラーにロジックを配置できます。
"label": "Delete",
"action": function (obj) {
if ($(this._get_node(obj)).hasClass("folder") return; // cancel action
}
もう一度編集: jsTreeソースコードを見ると、とにかく表示されるたびにコンテキストメニューが再作成されているように見える(show()
およびparse()
関数を参照)ので、私の最初の解決策の問題。
ただし、_disabled
の値として関数を使用して、あなたが提案している表記法が好きです。探索する可能性のあるパスは、元のparse()
を呼び出す前に、disabled: function () {...}
で関数を評価し、_disabled
に結果を保存する独自のparse()
関数をラップすることです。
ソースコードを直接変更することも難しくありません。バージョン1.0-rc1の行2867は関連するものです。
str += "<li class='" + (val._class || "") + (val._disabled ? " jstree-contextmenu-disabled " : "") + "'><ins ";
この前に$.isFunction(val._disabled)
をチェックする行を追加することができます。追加する場合はval._disabled = val._disabled()
を追加します。その後、パッチとして作成者に提出してください:)
さまざまなノードタイプで実装されます。
$('#jstree').jstree({
'contextmenu' : {
'items' : customMenu
},
'plugins' : ['contextmenu', 'types'],
'types' : {
'#' : { /* options */ },
'level_1' : { /* options */ },
'level_2' : { /* options */ }
// etc...
}
});
そして、customMenu関数:
function customMenu(node)
{
var items = {
'item1' : {
'label' : 'item1',
'action' : function () { /* action */ }
},
'item2' : {
'label' : 'item2',
'action' : function () { /* action */ }
}
}
if (node.type === 'level_1') {
delete items.item2;
} else if (node.type === 'level_2') {
delete items.item1;
}
return items;
}
美しく機能します。
すべてをクリアします。
これの代わりに:
$("#xxx").jstree({
'plugins' : 'contextmenu',
'contextmenu' : {
'items' : { ... bla bla bla ...}
}
});
これを使って:
$("#xxx").jstree({
'plugins' : 'contextmenu',
'contextmenu' : {
'items' : customMenu
}
});
私は提案されたソリューションを少し異なる方法で型を扱うために適応させましたが、おそらく他の誰かを助けることができます:
ここで、#{$ id_arr [$ k]}はdivコンテナへの参照です...私の場合、多くのツリーを使用しているので、このコードはすべてブラウザへの出力になりますが、アイデアは得られます。コンテキストメニューオプション。ただし、ドライブノードの「作成」および「貼り付け」のみ。明らかに、これらの操作への正しいバインディングを後で行います。
<div id="$id_arr[$k]" class="jstree_container"></div>
</div>
</li>
<!-- JavaScript neccessary for this tree : {$value} -->
<script type="text/javascript" >
jQuery.noConflict();
jQuery(function ($) {
// This is for the context menu to bind with operations on the right clicked node
function customMenu(node) {
// The default set of all items
var control;
var items = {
createItem: {
label: "Create",
action: function (node) { return { createItem: this.create(node) }; }
},
renameItem: {
label: "Rename",
action: function (node) { return { renameItem: this.rename(node) }; }
},
deleteItem: {
label: "Delete",
action: function (node) { return { deleteItem: this.remove(node) }; },
"separator_after": true
},
copyItem: {
label: "Copy",
action: function (node) { $(node).addClass("copy"); return { copyItem: this.copy(node) }; }
},
cutItem: {
label: "Cut",
action: function (node) { $(node).addClass("cut"); return { cutItem: this.cut(node) }; }
},
pasteItem: {
label: "Paste",
action: function (node) { $(node).addClass("paste"); return { pasteItem: this.paste(node) }; }
}
};
// We go over all the selected items as the context menu only takes action on the one that is right clicked
$.jstree._reference("#{$id_arr[$k]}").get_selected(false, true).each(function (index, element) {
if ($(element).attr("id") != $(node).attr("id")) {
// Let's deselect all nodes that are unrelated to the context menu -- selected but are not the one right clicked
$("#{$id_arr[$k]}").jstree("deselect_node", '#' + $(element).attr("id"));
}
});
//if any previous click has the class for copy or cut
$("#{$id_arr[$k]}").find("li").each(function (index, element) {
if ($(element) != $(node)) {
if ($(element).hasClass("copy") || $(element).hasClass("cut")) control = 1;
}
else if ($(node).hasClass("cut") || $(node).hasClass("copy")) {
control = 0;
}
});
//only remove the class for cut or copy if the current operation is to paste
if ($(node).hasClass("paste")) {
control = 0;
// Let's loop through all elements and try to find if the paste operation was done already
$("#{$id_arr[$k]}").find("li").each(function (index, element) {
if ($(element).hasClass("copy")) $(this).removeClass("copy");
if ($(element).hasClass("cut")) $(this).removeClass("cut");
if ($(element).hasClass("paste")) $(this).removeClass("paste");
});
}
switch (control) {
//Remove the paste item from the context menu
case 0:
switch ($(node).attr("rel")) {
case "drive":
delete items.renameItem;
delete items.deleteItem;
delete items.cutItem;
delete items.copyItem;
delete items.pasteItem;
break;
case "default":
delete items.pasteItem;
break;
}
break;
//Remove the paste item from the context menu only on the node that has either copy or cut added class
case 1:
if ($(node).hasClass("cut") || $(node).hasClass("copy")) {
switch ($(node).attr("rel")) {
case "drive":
delete items.renameItem;
delete items.deleteItem;
delete items.cutItem;
delete items.copyItem;
delete items.pasteItem;
break;
case "default":
delete items.pasteItem;
break;
}
}
else //Re-enable it on the clicked node that does not have the cut or copy class
{
switch ($(node).attr("rel")) {
case "drive":
delete items.renameItem;
delete items.deleteItem;
delete items.cutItem;
delete items.copyItem;
break;
}
}
break;
//initial state don't show the paste option on any node
default: switch ($(node).attr("rel")) {
case "drive":
delete items.renameItem;
delete items.deleteItem;
delete items.cutItem;
delete items.copyItem;
delete items.pasteItem;
break;
case "default":
delete items.pasteItem;
break;
}
break;
}
return items;
$("#{$id_arr[$k]}").jstree({
// List of active plugins used
"plugins" : [ "themes","json_data", "ui", "crrm" , "hotkeys" , "types" , "dnd", "contextmenu"],
"contextmenu" : { "items" : customMenu , "select_node": true},
Btw:既存のコンテキストメニューからオプションを削除するだけの場合-これは私のために働いた:
function customMenu(node)
{
var items = $.jstree.defaults.contextmenu.items(node);
if (node.type === 'root') {
delete items.create;
delete items.rename;
delete items.remove;
delete items.ccp;
}
return items;
}
jsTree 3.0.9の時点で、私は次のようなものを使用する必要がありました
var currentNode = treeElem.jstree('get_node', node, true);
if (currentNode.hasClass("folder")) {
// Delete the "delete" menu item
delete items.deleteItem;
}
提供されるnode
オブジェクトはjQueryオブジェクトではないためです。
コンテキストメニューの動的な無効化の要件に合わせて、@ Box9コードを次のように変更できます。
function customMenu(node) {
............
................
// Disable the "delete" menu item
// Original // delete items.deleteItem;
if ( node[0].attributes.yyz.value == 'notdelete' ) {
items.deleteItem._disabled = true;
}
}
XMLまたはJSOnデータに1つの属性「xyz」を追加する必要があります