# jQuery KontextMenü



## MsWord (5. März 2013)

Hallo,

für ein Projekt möchte ich etwas mit einem ContextMenu machen.
Gefunden habe ich viele aber keines welches variable genug ist.
Denn ich habe eine liste die ich mit PHP ausgeben lasse und mit dem
ContextMenu soll jeder Eintrag einzeln dann angeschaut, bearbeitet 
und gelöscht werden können. Jedes Element erhält dazu die id aus der DB.

1. Ich bekomme das nur so hin das es nur bei dem obersten Ausgabe funktioniert. 

2. Wenn ich auf einen Link im KontextMenü klicke dann führt er diesen nicht aus, 
sondern es verschwindet nur das KontextMenü.


Dieses Menu gefiel mir nur leider ist es nicht variable (variable bezogen auf 1.) genug:
Context Menu Demo


Weiß jemand wo ich ein gutes finden könnte oder wie man das so umschreiben kann das es so funktioniert?
Ich habe leider nur Anfänger Kenntnisse in Javascript.

Vielen Dank schon mal im Voraus!


----------



## Parantatatam (6. März 2013)

Hallo MsWord,

also eigentlich ist diese Sache mit den Kontextmenüs relativ einfach: du überwachst, ob jemand versucht ein Kontextmenü zu öffnen, und wenn das passiert, dann ermittelst du die Position der Maus und positionierst dann dort ein Kontextmenü. Und von dem überwachst du einfach Mausklicks. Mit HTML5 sollte das einfacher werden, jedoch werden Kontextmenüs nativ bisher (soweit ich weiß) nur in den Nightly Builds von Firefox unterstützt. Daher habe ich dir mal kurz was zusammen gebastelt und hoffe, dass es dir etwas hilft:

http://jsfiddle.net/MeiKatz/8kUJT/


----------



## MsWord (6. März 2013)

Ja, vielen Dank!
Helfen tut es mir schonmal 
ich habe auch schon etwas damit rum probiert...
aber irgendwie bekomme ich das nicht hin wenn ich jetzt da mehre divs hinein packe,
das das context menu die id (die in dem div eingetragen ist) von dem Div benutzt und daraus dann die links zum (öffnen, z.B. "?a=open&id=1", beabeiten und löschen) generiert.

Ich hoffe das war jetzt nicht zu blöd beschrieben?


----------



## Parantatatam (6. März 2013)

Ich habe es mal ein wenig modifiziert: http://jsfiddle.net/MeiKatz/8kUJT/6/


----------



## MsWord (6. März 2013)

Ja, cool... 
Danke dir, sowas habe ich gesucht!
Wenn ich das als Link benutzen möchte muss ich doch nur statt alert() das so schreiben: location.href='' oder?

Funktioniert 
http://marlight-music.de/test3/test2

Vielen vielen vielen Dank!
In keinem anderen Forum war keiner fähig mir eine so passende Antwort zugeben.


----------



## Parantatatam (6. März 2013)

Das liegt daran, dass du das Framework jQuery nicht einbindest. Konkret müsste der Skriptteil so aussehen:

```
<script type="text/javascript" src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<script type="text/javascript">
$(function () {
  var $current = null;
  
  $("[contextmenu] tr").on("contextmenu", function (e) {
    $current     = $(this);
    var contextmenu  = $(this).parents("table").attr("contextmenu");
    var $contextmenu = $("#" + contextmenu);
    
    if ($contextmenu.length == 0) {
      return;
    }
    
    e.preventDefault();
    e.stopPropagation();
    
    $contextmenu.show();
    $contextmenu.css({
      "top" : (e.pageY - 18) + "px",
      "left": e.pageX + "px"
    });
    
    return false;
  });
  
  $(".contextmenu li").on("click", function () {
    alert("action=" + $(this).data("type") + "&id=" + $current.data("id"));
  });
  
  $("body").on("click", function () {
    $(".contextmenu").hide(); 
  });
});
</script>
```


----------



## MsWord (6. März 2013)

Ja, ist mir etwas zu spät aufgefallen.
Aber nochmal riesen Danke!


----------



## MsWord (17. März 2013)

Hallo,

ich habe das Script etwas angepasst.
Nur habe ich dabei etwas kaputt gemacht, aber leider weiß ich net wie ich das im geänderten zustand zum laufen bekomme?!
Hier ist das Veränderte Script:

```
$(function(){
var $current = null;

$("[contextmenu2]").on("contextmenu", function (e) {
    $current     = $(this);
    var contextmenu  = $(this).attr("contextmenu2");
    var $contextmenu = $("#" + contextmenu);
    
    if ($contextmenu.length == 0) {
        return;
    }
    
    console.log(this);
    
    e.preventDefault();
    e.stopPropagation();
    
    $contextmenu.show();

        
    $contextmenu.css({
        "top" : e.pageY + "px",
        "left" : e.pageX + "px",
        "bottom" : "",
        "right" : ""
    });
    
    if(e.pageY > (window.innerHeight-200)){
     $contextmenu.css({
        "bottom" : (window.innerHeight-e.pageY) + "px",
        "top" : ""
     });
    }
    
    if(e.pageX > (window.innerWidth-200)){
     $contextmenu.css({
        "right": (window.innerWidth-e.pageX) + "px",
        "left" : ""
     });
    }
    
    
    return false;
});

$(".contextmenu li").on("click", function () {
  location.href=("?action=" + $(this).data("type") + "&id=" + $current.data("id"));
});

$("body").on("click", function () {
   $(".contextmenu").hide(); 
});
});
```

Hier bei funktioniert die Location funktion nicht mehr. 
Das Menü wird noch richtig angezeigt nur wenn ich auf ein menü klicke gehts nur weg
und führt nicht mehr diesen Link aus.

Meine Ausgabe sieht so aus:

```
<div id="log"></div>
<table  class="[...]" width="100%" border="0" cellpadding="0" cellspacing="0">	 
<tr contextmenu2="standart" data-id="153" class="verhindert">
	 	<td width="40.5%" class="gign"><strong>test</strong><br></td>
	 	<td width="25.3%" class="gign">13.05.2013 um 20:00</td>
	 	<td class="gign">sasa</td>
	 	<td width="12%" class="[cl4]">[buttons]</td>
	 </tr>
	 <tr contextmenu2="public" data-id="157" class="gig">
	 	<td width="40.5%" class="gign">test</td>
	 	<td width="25.3%" class="gign">19.05.2013 um 20:00</td>
	 	<td class="gign">assa</td>
	 	<td width="12%" class="[cl4]">[buttons]</td>
	 </tr>
</table>
<ul class="contextmenu" id="standart">
    <li data-type="open" class="folder">&ouml;ffnen</li>
    <li data-type="edit" class="edit">bearbeiten</li>
    <li data-type="delete" class="delete">l&ouml;schen</li>
</ul>
<ul class="contextmenu" id="public">
    <li data-type="open" class="folder">&ouml;ffnen</li>
    <li data-type="edit" class="edit">bearbeiten</li>
    <li data-type="public" class="public">ver&ouml;ffentlichen</li>
    <li data-type="delete" class="delete">l&ouml;schen</li>
</ul>
<ul class="contextmenu" id="gig">
    <li data-type="open" class="folder">&ouml;ffnen</li>
    <li data-type="edit" class="edit">bearbeiten</li>
    <li data-type="change" class="change">Zum Gig umwandeln</li>
    <li data-type="delete" class="delete">l&ouml;schen</li>
</ul>
```

Wie muss ich das jetzt in diesem Teil ändern damit das funktioniert?

```
$(".contextmenu li").on("click", function () {
  location.href=("?action=" + $(this).data("type") + "&id=" + $current.data("id"));
});

$("body").on("click", function () {
   $(".contextmenu").hide(); 
});
```


----------



## Parantatatam (17. März 2013)

Es muss wohl eher window.location.href sein.


----------



## MsWord (17. März 2013)

fehler habe ich gefunden... 
Aber noch etwas anderes...
Wenn ich jetzt an zwei verschiedenen punkten rechtsklick mache, habe ich auch zwei menü's.
Natürlich 2 verschiedene menü's aber was muss ich ändern damit er mir immer alle anderen offenen menüs schließt wenn ich rechtsklicke?


----------



## Parantatatam (17. März 2013)

```
$("[contextmenu2]").on("contextmenu", function (e) {
    $('.contextmenu').hide();
    $current     = $(this);
    var contextmenu  = $(this).attr("contextmenu2");
    var $contextmenu = $("#" + contextmenu);
    
    // ...
```


----------



## MsWord (18. März 2013)

Vielen Dank!


----------



## MsWord (24. April 2013)

Hallo,

ich habe ein merkwürdiges Problem wo mir bis jetzt noch keiner weiterhelfen konnte 
Mein Problem:
Ich lade die Liste via jQuery (Script s.u.) rein, diese Liste soll jetzt aber mit dem Contextmenu noch funktionieren. Funktionieren tut es teilweise auch :/ 
Bei dem normalen laden der Seite wo dann auch das jQuery-Script die Seite hinein lädt, funktioniert es nicht, erst wenn man eine Eingabe in das Suchfeld getätigt hat (dabei wird die Seite neu vom jQuery-Script geladen mit den neuen Ergebnissen).

Hoffe es war verständlich 
Wenn sich einer das Problem live ansehen möchte dann kann ich auch ihm Zugang zu meinem System verschaffen, aber das dann nur via PN.

Was ich noch vergessen hab, das ganze ist mit einem Template-System ("Smarty") aufgebaut.
Wenn ich einfach den HTML Code von dem Original kopiere dann funktioniert es, nur im Template-System nicht 

jQuery Script:


```
function liste(url) 
{ 
    var str = './js/ttttttt.tt.ttttttttt.php?search='; 
    url = str + url; 

    $.get(url, onSuccess); 
     
    //So sollte man das eher nicht machen. Lieber bestimmte Element per JavaScript einfach ein- bzw. ausblenden. 
    //Oder wenigstens mit Klassen/IDs arbeiten. 
    $("#gigliste").html("<div style=\'width:70px; height: 70px; margin: auto; margin-top: 100px; border-radius: 60px; background: rgba(2, 1, 0, 0.9);\'><img class='loading' style='width:80px; margin-top: -5px; margin-left: -5px;' height='80px' src='./img/loadings/loading.gif' /></div>"); 
     
    return false; 
} 


//Wird aufgerufen, wenn Daten empfangen wurden, welche dann der Funktion als Paramerter übergeben wird. 
function onSuccess(data) 
{ 
    $('#liste').html(data); 
}
```


----------



## Parantatatam (24. April 2013)

Um ehrlich zu sein: dein Quelltext hilft nicht. Daher würde ich dich bitten, dass du mir mal per PN die Zugangsdaten schickst.


----------



## Parantatatam (27. April 2013)

Also abgesehen davon, dass du an deinen Skripten noch einiges zu verbessern hast (beispielsweise nicht jQuery-Syntax und Standard-JavaScript-Selektor-Syntax mischen), glaube ich den Fehler gefunden zu haben: wenn du mal in deinen Quelltext siehst, dann wird dir auffallen, dass du die Datei für das Kontextmenü *nach* den anderen Skripten einbindest, dieses jedoch schon davor benötigt wird. Wenn du die Datei also schon eingebunden hast, wenn du deinen AJAX-Request absetzt, dann sollte alles so funktionieren, wie du es möchtest. Ansonsten möchte ich mein eigenes Skript noch etwas ausbessern, so dass es besser läuft mit AJAX:

```
$(function () {
  var $current = null;
  
  $('body')
  .delegate('[contextmenu2]', 'contextmenu', function (e) {
    $('.contextmenu').hide();
   
    $current         = $(this);
    var contextmenu  = $(this).attr('contextmenu2');
    var $contextmenu = $('#' + contextmenu);
    
    if ($contextmenu.length == 0) {
        return;
    }
    
    e.preventDefault();
    e.stopPropagation();
    
    $contextmenu.show();
    
    $contextmenu.css({
        'top' : e.pageY + 'px',
        'left' : e.pageX + 'px',
        'bottom' : null,
        'right' : null
    });
    
    if (e.pageY > (window.innerHeight - 200)) {
      $contextmenu.css({
        'bottom' : (window.innerHeight - e.pageY) + 'px',
        'top' : null
      });
    }
    
    if (e.pageX > (window.innerWidth - 200)) {
      $contextmenu.css({
        'right': (window.innerWidth - e.pageX) + 'px',
        'left' : null
     });
   }
    
    return false;
  })
  
  .delegate('.contextmenu li', 'click', function () {
    window.location.href = '?action=' + $(this).data('type') + $(this).data('page') + '&id=' + $current.data('id');
  })
   
  .on('click', function () {
    $('.contextmenu').hide();
  })
  
  .on('keydown', function (e) {
    if (e.which == 27) {
      $('.contextmenu').hide();
    }
  });
});
```

Nachtrag: Ich habe mein Skript noch etwas ausgebessert, so dass es jetzt (bis auf das Aussehen) einem nativen Kontextmenü sehr nahe kommt: wenn ein Kontextmenü offen ist und versucht wird, erneut ein Kontextmenü zu öffnen, wird das bestehende ausgeblendet, jedoch kein neues geöffnet. Dafür muss man ein zweites Mal ein Kontextmenü an der entsprechenden Stelle öffnen. Ansonsten kann man sich in dem Kontextmenü auch anhand der Pfeiltasten bewegen und eine Option mit der Eingabetaste auswählen, wobei der Wert übergeben und das Kontextmenü geschlossen wird. Und noch eine Sache, die jedoch schon in dem oben stehenden Skript neu implementiert wurde: man kann das Kontextmenü jetzt auch mit der Escape-Taste verlassen. Die aktuelle Version findet man hier: http://jsfiddle.net/MeiKatz/8kUJT/11/

Nachtrag II: Momentan arbeite ich an einem Kontextmenü-Plugin für jQuery, so dass man dann Kontextmenüs wie folgt erstellen kann:


```
$('table').contextmenu(function () {
  this; // enthält das ausgewählte Listen-Element aus dem Kontextmenü
});
```


----------



## Parantatatam (29. April 2013)

So. Ich hatte im letzten Beitrag angekündigt, dass ich für dieses Problem ein Plugin schreiben würde: es ist fertig. Jedoch heißt es nicht mehr *contextmenu*, da dies bereits von jQuery verwendet wird. Es heißt jetzt *actions* und kann hier gefunden werden: http://jsbin.com/axinab/11/edit#live,javascript


----------

