2

I'm using this jquery plugin. The instantiation of the menu looks like this:

$.contextMenu({
    selector:'.disposition-menu',
    zIndex: 120,

    callback: function(key, options) {
        var stepID = $(this).closest('.card').attr("id").substring(5);
        handle_disposition(key,stepID);

    },
    items: {
        "pin": {name: "Pin to top"},
        "unpin": {name:"Unpin"},
        "complete": {name: "Mark step completed"},
        "remove": {name: "Remove step from Map"},
   },
   events: {
       show: function(){}, //this is where I'm lost
       hide: function(){} //this is where I'm lost
   },
    trigger: 'hover'
}); 

The 'handle disposition' function interacts with php and the database to record the '.card' as pinned or unpinned in the database so that it appears properly when the page is reloaded. The HTML is a bootstrap 4 card like this:

<div class="card" >
    <div class="card-header ">
        <table class="title-table">
            <tr>
                <td>...</td>
                <td>...</td>
                <td>...</td>
                <td class="disposition-menu">&vellip;</td>
            </tr>
        </table>
    </div>

    <div class="card-body">
        ...{body content}
    </div>
</div>

What I am trying to do is toggle between the pin and unpin menu items. Only one of these should appear on the menu at a time. If the item is already "pinned" (i.e. flagged in database, and represented by a data attribute in the '.card' html) then "Unpin" should appear...and vice versa. Similarly as soon as the "Pin..." is clicked on the menu, the menu should immediately be changed to hide the "Pin" item and expose the "Unpin" item and vice versa

I've looked at the documentation for the plugin, but I'm a bit of a newbie when it comes to using functions after the keys with colons (eg selector: ) and callbacks. The plugin apparently has a "visible:" key, and also "show:" and "hide:" keys (used as per this issue, but I'm at a loss as to how to string these elements together to accomplish my objective.

2 Answers 2

2

Use build:

https://swisnl.github.io/jQuery-contextMenu/docs.html#build

If the build callback is found at registration, the menu is not built right away. The menu creation is delayed to the point where the menu is actually called to show.

$.contextMenu({
  selector: ".menu",
  build: function($trigger) {
    var options = {
      callback: function(key, options) {
        var m = "clicked: " + key;
        alert(m);
      },
      items: {}
    };

    if ($trigger.hasClass('pin')) {
      options.items.unpin = {name: "unpin"};
    } else {
      options.items.pin = {name: "pin"};
    }

    return options;
  }
});
.menu{
    width: 100px;
    padding: 10px;
    background: red;
    margin: 10px;
    color: #FFF;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<link href="https://cdnjs.cloudflare.com/ajax/libs/jquery-contextmenu/2.9.0/jquery.contextMenu.css" rel="stylesheet"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-contextmenu/2.9.0/jquery.contextMenu.min.js"></script>

<div class="menu pin">Pin</div>
<div class="menu">Unpin</div>

Example on demand:

https://swisnl.github.io/jQuery-contextMenu/demo/dynamic-create.html

Edit:

$.contextMenu({
  selector: ".disposition-menu",
  build: function($trigger) {
    var options = {
      callback: function(key, options) {
        if(key == "pin")
            $trigger.removeClass("unpin").addClass("pin");
        else if(key == "unpin")
            $trigger.removeClass("pin").addClass("unpin");
      },
      items: {}
    };

    if ($trigger.hasClass('pin')) {
      options.items.unpin = {name: "unpin"};
    } else {
      options.items.pin = {name: "pin"};
    }

    return options;
  }
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<link href="https://cdnjs.cloudflare.com/ajax/libs/jquery-contextmenu/2.9.0/jquery.contextMenu.css" rel="stylesheet"/>
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" rel="stylesheet"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-contextmenu/2.9.0/jquery.contextMenu.min.js"></script>
<div class="card" >
    <div class="card-header ">
        <table class="title-table">
            <tr>
                <td>...</td>
                <td>...</td>
                <td>...</td>
                <td class="disposition-menu">&vellip;</td>
            </tr>
        </table>
    </div>

    <div class="card-body">
        ...{body content}
    </div>
</div>

Sign up to request clarification or add additional context in comments.

4 Comments

Great. This points me in the right direction. In the HTML, however, there is only one element <td class="disposition-menu">&vellip;</td>. So, the pin and unpin have to toggle to that same element, not two separate ones. Can you clarify how your code works in that condition? I've added the HTML to my question for clarity. Also the code snippet doesn't do anything.
Also, if I'm reading the documentation correctly, $trigger is the event that reveals the menu. In my case, I don't want the menu to change every time it is shown, only when the pin or unpinmenu item is clicked.
Adding classes to disposition-menu and build the context dynamically based on these classes on right click is the key here, please find the edited answer above.
There is no right-click in my context. Not sure what you are referring to.
0

Here's how I solved the problem of "menu item swapping". Thanks to @ahed-kabalan for pointing me in the right direction.

The HTML didn't change from my question posted above. Here it is again for convenience:

<div class="card" >
    <div class="card-header ">
        <table class="title-table">
            <tr>
                <td>...</td>
                <td>...</td>
                <td>...</td>
                <td class="disposition-menu">&vellip;</td>
            </tr>
        </table>
    </div>

    <div class="card-body">
        ...{body content}
    </div>
</div>

The JS was modified to trigger a callback when the specific menu item was clicked and uses the visible key. This solution includes menu items that are modified when clicked and those that aren't affected. The menu appears when on hover, and the callbacks are only triggered on menu item selection. The unpin item is set to visible: false as a default - i.e. only the pin option will appear in the menu initially. Since build is really focused on building an entirely new menu, it wasn't necessary in my case. The JS now looks like this:

$.contextMenu({
    selector:'.disposition-menu',
    zIndex: 120,
    callback: function(key, options) {
        
        var stepID = $(this).closest('.card').attr("id").substring(5);
        alert(stepID);
        handle_disposition(key,stepID);
        
    },
    items: {
        "pin": {name: "Pin to top",
            callback: function(key, opt) {
                opt.items['pin'].visible = false;
                opt.items['unpin'].visible = true;
            }
        },
        "unpin": {name:"Unpin",
            callback: function(key, opt) {
                opt.items['pin'].visible = true;
                opt.items['unpin'].visible = false;
            }
        },
        "complete": {name: "Mark step completed"},
        "remove": {name: "Remove step from Map"}
   },
   trigger: 'hover'
});

Hope others will find this useful!

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.