2010-12-30 12 views
72

मैंने कहीं ऑनलाइन उदाहरण देखा है कि जेस्ट्री के राइट-क्लिक संदर्भ मेनू (contextmenu प्लगइन का उपयोग करके) की उपस्थिति को कैसे अनुकूलित किया जाए।jstree को कॉन्फ़िगर करना अलग-अलग नोड प्रकारों के लिए संदर्भमेनू पर राइट-क्लिक करें

उदाहरण के लिए, मेरे उपयोगकर्ताओं को "दस्तावेज़" को हटाने की अनुमति दें, लेकिन "फ़ोल्डर्स" नहीं (फ़ोल्डरों के संदर्भ मेनू से "हटाएं" विकल्प छिपाकर)।

अब मुझे वह उदाहरण नहीं मिल रहा है। क्या कोई मुझे सही दिशा दिखा सकता है? आधिकारिक documentation वास्तव में मदद नहीं की थी।

संपादित करें:

जब से मैं केवल एक या दो मामूली परिवर्तन के साथ डिफ़ॉल्ट संदर्भ मेनू चाहते हैं, मैं पूरी मेनू पुन: नहीं करना चाहते (हालांकि निश्चित रूप मैं करूँगा अगर यह एक ही रास्ता है)। मुझे क्या करना चाहते हैं कुछ इस तरह है:

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

लेकिन यह काम नहीं करता है - बनाने के मद बस हमेशा अक्षम है (चेतावनी कभी नहीं दिखाई देता है)।

उत्तर

120

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 का उपयोग कर सकते हैं।

स्पष्ट होना चाहिए, लेकिन इसके बजाय क्या आपने पहले की customMenu समारोह के साथ प्लगइन आरंभ करने के लिए याद रखें:

$("#tree").jstree({plugins: ["contextmenu"], contextmenu: {items: customMenu}}); 
//                 ^
// ___________________________________________________________________| 

संपादित करें: आप नहीं चाहते हैं मेनू फिर से बनाना प्रत्येक राइट-क्लिक पर, आप डिलीट मेनू आइटम के लिए एक्शन हैंडलर में तर्क डाल सकते हैं।

"label": "Delete", 
"action": function (obj) { 
    if ($(this._get_node(obj)).hasClass("folder") return; // cancel action 
} 

संपादित फिर से: jsTree स्रोत कोड को देखने के बाद, यह ContextMenu हर बार यह दिखाया गया है फिर से बनाया जा रहा है वैसे भी तरह लग रहा है (show() और parse() कार्यों देखें), तो मैं मेरे पहले समाधान के साथ कोई समस्या नहीं दिख रही है।

हालांकि, मुझे _disabled के मान के रूप में एक फ़ंक्शन के साथ, जो सुझाव आप सुझा रहे हैं उसे पसंद करते हैं।पता लगाने के लिए एक संभावित मार्ग अपनी खुद की एक disabled: function() {...} पर समारोह का मूल्यांकन करता है और _disabled में परिणाम संग्रहीत करता है कि के साथ अपने parse() समारोह रैप करने के लिए, मूल parse() कॉल करने से पहले है।

यह मुश्किल नहीं होगा या तो अपने स्रोत कोड सीधे संशोधित करने के लिए। संस्करण 1.0-RC1 रेखा 2867 प्रासंगिक एक है:

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

आप बस इस एक कि $.isFunction(val._disabled) की जाँच करता है से पहले एक पंक्ति जोड़ सकते हैं, और यदि हां, val._disabled = val._disabled()। फिर एक पैच के रूप में रचनाकारों में जमा करें :)

+0

धन्यवाद। मैंने सोचा कि मैंने एक बार एक समाधान देखा जो डिफ़ॉल्ट रूप से बदलने की आवश्यकता है (पूरे मेनू को स्क्रैच से पुनर्निर्मित करने के बजाय)। यदि बक्षीस की समयसीमा समाप्त होने से पहले कोई बेहतर समाधान नहीं है तो मैं इस जवाब को स्वीकार करूंगा। – MGOwen

+0

@MGOwen, अवधारणात्मक रूप से मैं * हूं * "डिफ़ॉल्ट" को संशोधित कर रहा हूं, लेकिन हाँ आप सही हैं कि जब भी फ़ंक्शन कहा जाता है तो ऑब्जेक्ट फिर से बनाया जाता है। हालांकि, डिफ़ॉल्ट को पहले क्लोन करने की आवश्यकता है, अन्यथा डिफ़ॉल्ट रूप से संशोधित किया गया है (और इसे मूल स्थिति में वापस लाने के लिए आपको अधिक जटिल तर्क की आवश्यकता होगी)। एक विकल्प जिसे मैं सोच सकता हूं कि 'var items' को फ़ंक्शन के बाहर ले जाना है, इसलिए यह केवल एक बार बनाया गया है, और फ़ंक्शन से आइटम्स का चयन वापस कर सकता है, उदा। 'वापसी {renameItem: items.renameItem};' या 'वापसी {renameItem: items.renameItem, deleteItem: items.deleteItem};' –

+0

मुझे पसंद है कि पिछले एक विशेष रूप से है, जहां आप jstree स्रोत को संशोधित। मैंने कोशिश की और यह काम करता है, "_disabled" (मेरे उदाहरण में) को सौंपा गया कार्य चलता है।लेकिन, यह मदद नहीं करता है क्योंकि मैं फ़ंक्शन के दायरे से नोड तक पहुंच नहीं सकता (मुझे कम से कम नोड प्रकार द्वारा नोड्स फ़िल्टर करने के लिए इसकी विशेषता विशेषता है)। मैंने उन चरों का निरीक्षण करने की कोशिश की जिन्हें मैं jstree स्रोत कोड से पास कर सकता था लेकिन नोड नहीं मिला। कोई विचार? – MGOwen

12

सब कुछ साफ़ करने के लिए।

इसके बजाय इस बात का

:

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

उपयोग करें:

$("#xxx").jstree({ 
    'plugins' : 'contextmenu', 
    'contextmenu' : { 
     'items' : customMenu 
    } 
}); 
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; 
    } 

} 

आप अपने XML या JSON डेटा में एक विशेषता "xyz" को जोड़ने की जरूरत है

4

मैं अलग तरह से हालांकि प्रकार के साथ एक सा काम करने के लिए सुझाव दिया समाधान ढाल लिया है, शायद यह किसी और में मदद कर सकते हैं:

कहाँ # {$ 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}, 
0

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 वस्तु नहीं है की जरूरत है।

16

अलग नोड प्रकार के साथ लागू किया:

$('#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; 
} 

वर्क्स खूबसूरती से।

+1

मैं यह उत्तर पसंद करता हूं क्योंकि यह jQuery का उपयोग करके प्राप्त सीएसएस वर्ग की बजाय 'टाइप' विशेषता पर निर्भर करता है। –

+0

आप "कार्रवाई 'के अंदर क्या कोड डाल रहे हैं: फ़ंक्शन() {/ * action * /}' दूसरे स्निपेट में? क्या होगा यदि आप "सामान्य" कार्यक्षमता और मेनू आइटम का उपयोग करना चाहते हैं, लेकिन बस उनमें से एक को हटा दें (उदा। हटाएं हटाएं लेकिन नाम बदलें और बनाएं)? मेरे विचार में, यह वही है जो ओपी वैसे भी पूछ रहा था। निश्चित रूप से आपको नाम बदलने जैसी चीजों के लिए कार्यक्षमता दोबारा लिखने की आवश्यकता नहीं है और अगर आप हटाए गए किसी अन्य आइटम को हटाते हैं तो बनाएँ? – Andy

+0

मुझे यकीन नहीं है कि मैं आपका प्रश्न समझता हूं। आप ऑब्जेक्ट्स की 'आइटम' सूची में पूर्ण संदर्भ मेनू (उदाहरण के लिए, हटाएं, नाम बदलें और बनाएं) के लिए सभी कार्यक्षमताओं को परिभाषित कर रहे हैं, फिर आप अंत में दिए गए 'node.type' के लिए इनमें से कौन सा आइटम निकालना चाहते हैं 'customMenu' फ़ंक्शन का। जब उपयोगकर्ता दिए गए 'टाइप' के नोड पर क्लिक करता है, तो संदर्भ मेनू' कस्टममेनू 'फ़ंक्शन के अंत में सशर्त में हटाए गए सभी आइटमों को सूचीबद्ध करेगा। आप किसी भी कार्यक्षमता को फिर से लिख नहीं रहे हैं (जब तक तीन साल पहले इस उत्तर के बाद जेस्ट्री बदल नहीं गया है, इस मामले में यह अब प्रासंगिक नहीं हो सकता है)। – stacked

संबंधित मुद्दे