jsTree のコンテキストメニューをカスタマイズ

jsTree のプラグイン contextmenu は、デフォルトのままではフォルダとファイルのように、
ある種類のノードの配下にノードを作成することができない
  =ファイルの下に、フォルダ/ファイルは作れてはいけないはずだ。。
つまり、ツリー構造を作成できるのは、フォルダのみでファイルではない。
  ・・・当たり前の規則だが。。。
jsTree デフォルトの contextmenu をそのまま使うと全てに対して、
配下にノードを作成ができてしまう。
だから、フォルダとファイルのようなツリーでコンテキストメニューを用意する場合
、自分でカスタマイズして書いてあげないとならない。

contextmenu 書込みの準備、 "plugins":[ "contextmenu" ], を書いて、
次にコンテキストメニューの設定を書く。
フォルダとファイルの区別は、icon 属性で区別する制御にする。
ノードに任意属性種別を作っても、コピー操作の処理は、
jsTree のコア内部処理でとてもオーバーライドできるような代物ではなく、
任意属性の新しい規則を作ってコピー時にきちんとコピーされるように
するのは非常に厳しい。
→ よって、icon 属性でフォルダとファイルの区別制御をする。
初期データにも↓のとおり、"icon" を書く

$('#treediv').jstree({ 'core':{
      'data':[
         {   "id":1, "icon":"jstree-folder", "text":"Root",
            "children":[
               {   "id":2, "icon":"jstree-file", "text":"AAA" }
            ]
         }
      ],
      "check_callback" : true
   },
   "plugins":[ "contextmenu" ],
   // ここに、contextmenu のカスタマイズを書き込む
  }
});

"plugins":[ "contextmenu" ], の次に書くもの。

"contextmenu":{
   "items":function($node){
      return {
         "createFolder":{
            "separator_before": false,
            "separator_after": false,
            "label": "新規フォルダ作成",
            "_disabled": function(data){
                return $.jstree.reference(data.reference)
                .get_node(data.reference).icon != "jstree-folder";
            },
            "action": function(data){
               var inst = $.jstree.reference(data.reference),
                     obj = inst.get_node(data.reference);
               inst.create_node(obj, { text:'New Folder', 'icon':'jstree-folder' }
                                , "last", function(new_node){
                  try{
                     inst.edit(new_node);
                  }catch(ex){
                     setTimeout(function(){ inst.edit(new_node); },0);
                  }
               });
            }
         },
         "createFile":{
            "separator_before": false,
            "separator_after": false,
            "label": "新規ファイル作成",
            "_disabled": function(data){
               return $.jstree.reference(data.reference)
               .get_node(data.reference).icon != "jstree-folder";
            },
            "action": function(data){
               var inst = $.jstree.reference(data.reference), 
                     obj = inst.get_node(data.reference);
               inst.create_node(obj, { text:'New File', 'icon':'jstree-file' }
                                , "last", function(new_node){
                  try{
                     inst.edit(new_node);
                  }catch(ex){
                     setTimeout(function(){ inst.edit(new_node); },0);
                  }
               });
            }
         },
         "rename":{
            "separator_before": true,
            "separator_after": false,
            "label": "名称の変更",
            "_disabled": false,
            "action": function(data){
               var inst = $.jstree.reference(data.reference),
                     obj = inst.get_node(data.reference);
               inst.edit(obj);
            }
         },
         "remove":{
            "separator_before": false,
            "separator_after": false,
            "label": "削除",
            "_disabled": function(data){
               return $.jstree.reference(data.reference)
               .get_node(data.reference).parent == "#";
            },
            "action": function(data){
               var inst = $.jstree.reference(data.reference),
                           obj = inst.get_node(data.reference);
               if (inst.is_selected(obj)){
                  inst.delete_node(inst.get_selected());
               }else{
                  inst.delete_node(obj);
               }
            }
         },
         "cut":{
            "separator_before": true,
            "separator_after": false,
            "label": "切り取り",
            "_disabled": function(data){
               return $.jstree.reference(data.reference)
               .get_node(data.reference).parent == "#";
            },
            "action": function(data){
               var inst = $.jstree.reference(data.reference),
                     obj = inst.get_node(data.reference);
               if (inst.is_selected(obj)){
                  inst.cut(inst.get_top_selected());
               }else{
                  inst.cut(obj);
               }
            }
         },
         "copy":{
            "separator_before": false,
            "icon": false,
            "separator_after": false,
            "label": "コピー",
            "_disabled": function(data){
               return $.jstree.reference(data.reference)
               .get_node(data.reference).parent == "#";
            },
            "action": function(data){
               var inst = $.jstree.reference(data.reference),
                     obj = inst.get_node(data.reference);
               if (inst.is_selected(obj)){
                  inst.copy(inst.get_top_selected());
               }else{
                  inst.copy(obj);
               }
            }
         },
         "paste":{
            "separator_before": false,
            "separator_after": false,
            "label": "貼り付け",
            "icon": false,
            "_disabled": function(data){
               if ($.jstree.reference(data.reference)
                       .get_node(data.reference).icon != "jstree-folder") return true;
               return !$.jstree.reference(data.reference).can_paste();
            },
            "action": function(data){
               var inst = $.jstree.reference(data.reference),
                     obj = inst.get_node(data.reference);
               inst.paste(obj);
               console.log( obj );
            }
         }
      };
   }
}

f:id:posturan:20180923151147j:plain