বিভিন্ন নোড প্রকারের জন্য jstree রাইট ক্লিক ক্লিক করুন প্রসঙ্গমেনু কনফিগার করা


85

আমি কোথাও অনলাইনে একটি উদাহরণ দেখেছি যাতে দেখানো হচ্ছে কীভাবে জাস্ট্রি-র রাইট-ক্লিক প্রসঙ্গ মেনুটির (কনটেক্সটম্যানু প্লাগইন ব্যবহার করে) কাস্টমাইজ করা যায়।

উদাহরণস্বরূপ, আমার ব্যবহারকারীদের "নথিগুলি" মুছতে অনুমতি দিন তবে "ফোল্ডারগুলি" নয় (ফোল্ডারগুলির জন্য প্রসঙ্গ মেনু থেকে "মুছুন" বিকল্পটি লুকিয়ে রেখে)।

এখন আমি সেই উদাহরণটি পাই না। কেউ কি আমাকে সঠিক দিকে নির্দেশ করতে পারে? সরকারী ডকুমেন্টেশন সত্যিই সাহায্য করে না।

সম্পাদনা করুন:

যেহেতু আমি কেবল একটি বা দুটি ছোটখাট পরিবর্তন সহ ডিফল্ট প্রসঙ্গ মেনুটি চাই, তাই আমি পুরো মেনুটি পুনরায় তৈরি না করাই পছন্দ করি (তবে এটির একমাত্র উপায় হলে অবশ্যই আমি করব)। আমি যা করতে চাই তা হ'ল এইরকম:

"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'); 
            }
        }
    }
}

তবে এটি কাজ করে না - তৈরি আইটেমটি সর্বদা অক্ষম থাকে (সতর্কতা কখনই প্রদর্শিত হয় না)।

উত্তর:


145

contextmenuপ্লাগ-ইন ইতিমধ্যে এই জন্য সমর্থন আছে। আপনি যে ডকুমেন্টেশনটির সাথে লিঙ্ক করেছেন:

items: কোনও অবজেক্ট বা কোনও ফাংশন প্রত্যাশা করে, যা কোনও বস্তুকে ফেরত দেবে । যদি কোনও ফাংশন ব্যবহার করা হয় তবে এটি গাছের প্রেক্ষাপটে চালিত হয় এবং একটি যুক্তি গ্রহণ করে - নোড যা ডান ক্লিক করা হয়েছিল।

সুতরাং এর contextmenuসাথে কাজ করার জন্য একটি হার্ড-কোডেড অবজেক্ট দেওয়ার চেয়ে আপনি নিম্নলিখিত ফাংশনটি সরবরাহ করতে পারেন। এটি "ফোল্ডার" নামক শ্রেণীর জন্য ক্লিক করা উপাদানটি পরীক্ষা করে এবং "মুছুন" মেনু আইটেমটি অবজেক্ট থেকে মুছে ফেলে:

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সম্পর্কিত আইটেমটি যুক্ত করে আইটেমটি এর আচরণটি অক্ষম করার সময় প্রদর্শন করার অনুমতি দেয় । এই ক্ষেত্রে আপনি পরিবর্তে বিবৃতি items.deleteItem._disabled = trueমধ্যে ব্যবহার করতে পারেন if

সুস্পষ্ট হওয়া উচিত, তবে 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-আরসি 1 এর 2867 লাইনটি প্রাসঙ্গিক:

str += "<li class='" + (val._class || "") + (val._disabled ? " jstree-contextmenu-disabled " : "") + "'><ins ";

আপনি যা পরীক্ষা করে এটির আগে আপনি কেবল একটি লাইন যুক্ত করতে পারেন $.isFunction(val._disabled)এবং যদি তাই হয় তবে val._disabled = val._disabled()। তারপরে এটি প্যাচ হিসাবে নির্মাতাদের কাছে জমা দিন :)


ধন্যবাদ আমি ভেবেছিলাম যে আমি একবারে একটি সমাধান কেবলমাত্র ডিফল্ট থেকে পরিবর্তনের প্রয়োজন (কেবল স্ক্র্যাচ থেকে পুরো মেনুটি পুনরায় তৈরি করার চেয়ে) পরিবর্তনের সাথে জড়িত একটি সমাধান দেখেছি। অনুগ্রহের মেয়াদ শেষ হওয়ার আগে আর কোনও সমাধান না হলে আমি এই উত্তরটি গ্রহণ করব।
এমজিওউইন

@ এমজিওউয়েন, ধারণাগতভাবে আমি "ডিফল্ট" পরিবর্তন করছি , তবে হ্যাঁ আপনি ঠিক বলেছেন যে প্রতিবার ফাংশনটি বলা হওয়ার পরে এই বস্তুটি পুনরায় তৈরি হবে। তবে, ডিফল্টটিকে প্রথমে ক্লোন করা প্রয়োজন, অন্যথায় ডিফল্টটি নিজেই সংশোধন করা হয় (এবং এটিকে মূল অবস্থায় ফিরিয়ে আনতে আপনার আরও জটিল যুক্তির প্রয়োজন হবে)। একটি বিকল্প আমি মনে করতে পারেন সরানো হয় var itemsফাংশন তাই তার শুধুমাত্র একবার নির্মিত বাইরে, এবং ফাংশন থেকে আইটেমগুলি একটি নির্বাচন আসতে যেমন return {renameItem: items.renameItem};বাreturn {renameItem: items.renameItem, deleteItem: items.deleteItem};
ডেভিড তাং

আমি শেষটি বিশেষত পছন্দ করি যেখানে আপনি jstree উত্সটি পরিবর্তন করেন। আমি এটি চেষ্টা করেছি এবং এটি কাজ করে, "_ অক্ষম" (আমার উদাহরণে) বরাদ্দ করা ফাংশনটি চালিত হয়। তবে এটি সাহায্য করে না কারণ আমি ফাংশনের সুযোগ থেকে নোড অ্যাক্সেস করতে পারছি না (নোডের ধরণের মাধ্যমে নোড ফিল্টার করার জন্য আমার কমপক্ষে এটির rel বৈশিষ্ট্য প্রয়োজন)। আমি জেস্ট্রি সোর্স কোড থেকে যে ভেরিয়েবলগুলি পাস করতে পারছিলাম তা পরীক্ষা করার চেষ্টা করেছি তবে নোডটি খুঁজে পেল না। কোন ধারনা?
এমজিওউইন

@ এমজিওউইন, দেখে মনে হচ্ছে এটি <a>যে উপাদানটিতে ক্লিক করা হয়েছিল সেগুলি সঞ্চয় করা আছে $.vakata.context.tgt। তাই দেখার চেষ্টা করুন $.vakata.context.tgt.attr("rel")
ডেভিড টাং

4
জাস্ট্রি .8.০.৮ এ: if ($(node).hasClass("folder")) কাজ হয়নি। তবে এটি করেছে: if (node.children.length > 0) { items.deleteItem._disabled = true; }
রায়ান ভেটটিজ

19

বিভিন্ন নোড প্রকারের সাথে প্রয়োগ করা:

$('#jstree').jstree({
    'contextmenu' : {
        'items' : customMenu
    },
    'plugins' : ['contextmenu', 'types'],
    'types' : {
        '#' : { /* options */ },
        'level_1' : { /* options */ },
        'level_2' : { /* options */ }
        // etc...
    }
});

এবং কাস্টমমেনু ফাংশন:

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;
}

সুন্দর কাজ করে।


4
আমি এই উত্তরটিকে প্রাধান্য দিচ্ছি কারণ এটি typejQuery ব্যবহার করে প্রাপ্ত সিএসএস শ্রেণির চেয়ে বৈশিষ্ট্যের উপর নির্ভর করে ।
বেনি বোত্তেমা

'action': function () { /* action */ }দ্বিতীয় স্নিপেটে আপনি কী কোডটি প্রবেশ করছেন ? আপনি যদি "স্বাভাবিক" কার্যকারিতা এবং মেনু আইটেমগুলি ব্যবহার করতে চান তবে কেবল তার মধ্যে একটি মুছে ফেলুন (উদাহরণস্বরূপ মুছে ফেলুন তবে নাম পরিবর্তন করুন এবং তৈরি করুন)? আমার দৃষ্টিতে ওপি যেভাবেই জিজ্ঞাসা করেছিল। মুছে ফেলার মতো আপনি যদি অন্য কোনও আইটেম সরান তবে অবশ্যই পুনর্নামকরণ এবং তৈরির মতো জিনিসের জন্য আপনার পুনরায় লেখার কার্যকারিতা দরকার নেই?
অ্যান্ডি

আমি নিশ্চিত না যে আমি আপনার প্রশ্নটি বুঝতে পেরেছি। আপনি সামগ্রীর itemsতালিকাতে পুরো কনটেক্সট মেনু (যেমন, মুছুন, পুনঃনামকরণ এবং তৈরি করুন) এর জন্য সমস্ত কার্যকারিতা সংজ্ঞায়িত করছেন , তারপরে আপনি ফাংশনের node.typeশেষে প্রদত্ত কোনও আইটেমটি অপসারণ করবেন তা নির্দিষ্ট করে দিন customMenu। যখন ব্যবহারকারী প্রদত্ত একটি নোডে ক্লিক করে type, প্রসঙ্গ মেনুটি customMenuফাংশনের শেষে শর্তসাপেক্ষে সরানো সমস্ত আইটেমকে তালিকাভুক্ত করে। আপনি কোনও কার্যকারিতা পুনরায় লিখছেন না (যদি না তিন বছর আগে এই উত্তরটির পরে জাস্ট্রি পরিবর্তিত না হয় তবে এটি আর প্রাসঙ্গিক নাও হতে পারে)।
18:40

12

সব পরিষ্কার করার জন্য।

এর পরিবর্তে:

$("#xxx").jstree({
    'plugins' : 'contextmenu',
    'contextmenu' : {
        'items' : { ... bla bla bla ...}
    }
});

এটা ব্যবহার কর:

$("#xxx").jstree({
    'plugins' : 'contextmenu',
    'contextmenu' : {
        'items' : customMenu
    }
});

5

ধরণের সাথে কাজ করার জন্য প্রস্তাবিত সমাধানটি কিছুটা আলাদাভাবে মানিয়ে নিয়েছি যদিও এটি অন্য কারও পক্ষে সহায়তা করতে পারে:

যেখানে # {$ আইডি_আর [$ কে]} হ'ল ডিভ কনটেইনারটির রেফারেন্স ... আমার ক্ষেত্রে আমি অনেক গাছ ব্যবহার করি তাই এই কোডটি ব্রাউজারের আউটপুট হবে তবে আপনি ধারণা পাবেন .. মূলত আমি সমস্ত চাই প্রসঙ্গ মেনু বিকল্পগুলি কেবল ড্রাইভ নোডে 'তৈরি করুন' এবং 'পেস্ট করুন'। স্পষ্টতই পরে সেই অপারেশনগুলির সঠিক বাঁধাইয়ের সাথে:

<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},

2

বিটিডব্লিউ: আপনি যদি কেবল বিদ্যমান প্রসঙ্গ মেনু থেকে বিকল্পগুলি সরাতে চান - এটি আমার পক্ষে কাজ করেছে:

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;
}


1

আপনার প্রসঙ্গ মেনুটিকে গতিশীল অক্ষম করার জন্য আপনার প্রয়োজন অনুসারে @ Box9 কোডটি পরিবর্তন করতে পারেন:

function customMenu(node) {

  ............
  ................
   // Disable  the "delete" menu item  
   // Original // delete items.deleteItem; 
   if ( node[0].attributes.yyz.value == 'notdelete'  ) {


       items.deleteItem._disabled = true;
    }   

}  

আপনার এক্সএমএল বা জেএসএন ডেটাতে আপনাকে একটি xyz যুক্ত করতে হবে


1

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 অবজেক্ট নয়।


1

ডেভিড এর প্রতিক্রিয়া সূক্ষ্ম এবং দক্ষ বলে মনে হচ্ছে। আমি সমাধানটির আরও একটি প্রকরণ পেয়েছি যেখানে আপনি বিভিন্ন নোডকে আলাদা করতে a_attr বৈশিষ্ট্যটি ব্যবহার করতে পারেন এবং এর ভিত্তিতে আপনি বিভিন্ন প্রসঙ্গ মেনু তৈরি করতে পারেন।

নীচের উদাহরণে, আমি দুটি ধরণের নোড ফোল্ডার এবং ফাইল ব্যবহার করেছি। আমি গ্লাইফিকন ব্যবহার করেও বিভিন্ন আইকন ব্যবহার করেছি। ফাইল টাইপ নোডের জন্য, আপনি কেবল নাম পরিবর্তন করতে এবং সরানোর জন্য প্রসঙ্গ মেনু পেতে পারেন। ফোল্ডারের জন্য, সমস্ত বিকল্প রয়েছে, ফাইল তৈরি করুন, ফোল্ডার তৈরি করুন, নাম পরিবর্তন করুন, সরান।

সম্পূর্ণ কোড স্নিপেটের জন্য, আপনি https://everyething.com/Example-of-jsTree-with-different-context-menu-for-differences-node-type দেখতে পারেন

 $('#SimpleJSTree').jstree({
                "core": {
                    "check_callback": true,
                    'data': jsondata

                },
                "plugins": ["contextmenu"],
                "contextmenu": {
                    "items": function ($node) {
                        var tree = $("#SimpleJSTree").jstree(true);
                        if($node.a_attr.type === 'file')
                            return getFileContextMenu($node, tree);
                        else
                            return getFolderContextMenu($node, tree);                        
                    }
                }
            });

প্রাথমিক জসন ডেটা নীচে হিসাবে রয়েছে, যেখানে নোড টাইপটি a_attr এর মধ্যে উল্লেখ করা হয়েছে।

var jsondata = [
                           { "id": "ajson1", "parent": "#", "text": "Simple root node", icon: 'glyphicon glyphicon-folder-open', "a_attr": {type:'folder'} },
                           { "id": "ajson2", "parent": "#", "text": "Root node 2", icon: 'glyphicon glyphicon-folder-open', "a_attr": {type:'folder'} },
                           { "id": "ajson3", "parent": "ajson2", "text": "Child 1", icon: 'glyphicon glyphicon-folder-open', "a_attr": {type:'folder'} },
                           { "id": "ajson4", "parent": "ajson2", "text": "Child 2", icon: 'glyphicon glyphicon-folder-open', "a_attr": {type:'folder'} },
            ];

কনটেক্সট মেনু আইটেমের অংশ হিসাবে একটি ফাইল তৈরি করতে এবং ফোল্ডারটি নীচে অনুরূপ কোডটি ফাইল ক্রিয়া হিসাবে ব্যবহার করে।

action: function (obj) {
                                $node = tree.create_node($node, { text: 'New File', icon: 'glyphicon glyphicon-file', a_attr:{type:'file'} });
                                tree.deselect_all();
                                tree.select_node($node);
                            }

ফোল্ডার ক্রিয়া হিসাবে:

action: function (obj) {
                                $node = tree.create_node($node, { text: 'New Folder', icon:'glyphicon glyphicon-folder-open', a_attr:{type:'folder'} });
                                tree.deselect_all();
                                tree.select_node($node);
                            }
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.