Menu contestuale alternativo personalizzato


Attenzione: per adesso il menu è uno script da mettere all'interno di ogni pagina dove si vuole visualizzare il menu alternativo. Sto lavorando per produrre uno script esterno da linkare, per evitare di dover riscrivere tutte le volte il codice.


Prima di passare a vedere il codice vero e proprio vi spiego la "filosofia" del menu in quattro passi.
  1. Inibire il menu originale;
  2. Creare un oggetto <div> con dei link: sarà il nostro menu (di default invisibile);
  3. Alla pressione del tasto destro del mouse, rendere l'oggetto <div> visibile e disposto ad accettare l'input (i click sui link);
  4. Premendo il tasto sinistro al di fuori del menu, questo deve scomparire.

Vediamo adesso come implementare il tutto, con uno script che è lo stesso che ho usato per creare il mio:

<body bgcolor="black" text="lime" oncontextmenu="return false">

<!-- Menu contestuale alternativo -->
<style>
.linkmenu{text-decoration:none}
.linkmenu:hover{color:white;background-color:navy;}
</style>
<!-- Ecco il menu -->
<div id="menu" style="border:1px outset red;background:gray;position:absolute;width:130px;visibility:hidden">
<font face="arial">
<h6>

<a href="display.html" target="due" style="width:130px;height:10px" onclick="menu.style.visibility='hidden'" class="linkmenu">Home</a>

<a href="underconstruction.html" target="due" style="width:130px;height:10px" onclick="menu.style.visibility='hidden'" class="linkmenu">News</a>

<a href="noi.html" target="due" style="width:130px;height:10px" onclick="menu.style.visibility='hidden'" class="linkmenu">Noi</a>

<a href="umor.html" target="due" style="width:130px;height:10px" onclick="menu.style.visibility='hidden'" class="linkmenu">Humor</a>

<a href="webdesign.html" target="due" style="width:130px;height:10px" onclick="menu.style.visibility='hidden'" class="linkmenu">Webdesign</a>

<a href="colle.html" target="due" style="width:130px;height:10px" onclick="menu.style.visibility='hidden'" class="linkmenu">Collezioni</a>

<a href="storie.html" target="due" style="width:130px;height:10px" onclick="menu.style.visibility='hidden'" class="linkmenu">Storie</a>

<a href="links.html" target="due" style="width:130px;height:10px" onclick="menu.style.visibility='hidden'" class="linkmenu">Links</a>

<a href="download.html" target="due" style="width:130px;height:10px" onclick="menu.style.visibility='hidden'" class="linkmenu">Download area</a>

<br>

<a href="javascript:mostra_sorgente()" style="width:130px;height:10px" onclick="menu.style.visibility='hidden'" class="linkmenu">Mostra sorgente HTML</a>

<br>

<a href="infomenu.html" target="due" style="width:130px;height:10px" onclick="menu.style.visibility='hidden'" class="linkmenu">Infos su questo menu</a>

<br>

<font face="arial" color="black">
<center style="border:1px solid blue;width:130px"> AlexMfM menu ver. 1.6</center>
</font>
</div>

<!-- Fine del menu -->
<script language="javascript">
document.body.onmousedown = new Function("mostra_menu()");

function mostra_menu()
{
//Catturano le posizioni del click sinistro e destro
var posx;
var posy;
var pos_e1x;
var pos_e1y;


if (event.button==2||event.button==3)
{
posx = event.clientX + document.body.scrollLeft;
posy = event.clientY + document.body.scrollTop;
menu.style.left= posx-3;
menu.style.top= posy-3;
menu.style.visibility='visible';
}
else if (event.button==1)
{
pos_e1x = event.clientX + document.body.scrollLeft;
pos_e1y = event.clientY + document.body.scrollTop;


var pos_box_x = menu.style.left;
var pos_box_y = menu.style.top;
var pos_px = pos_box_x.indexOf('px');
var pos_py = pos_box_y.indexOf('px');

var i=0;
var l=0;
var buffer='';
var estrai='';
var buffer_y='';
var estrai_y='';
for(i=0;i<pos_px;i++)
{
estrai=pos_box_x.charAt(i);
buffer+=estrai;
}
for(l=0;l<pos_py;l++)
{
estrai_y=pos_box_y.charAt(l);
buffer_y+=estrai_y;
}


if( (pos_e1x<buffer) || (pos_e1x-buffer>130) ||(pos_e1y<buffer_y) )
{
menu.style.visibility='hidden';
}
if((pos_e1x>buffer)&&(pos_e1x-buffer<130))
{
return;
}
}
}
function mostra_sorgente()
{
window.location = "view-source:" + window.location.href;
}
</script>
<!-- Fine del menu contestuale alternativo -->
Iniziamo a commentare lo script:
Importante: ricordatevi di mettere l'attributo onContextMenu nel body come mostrato qui a fianco, altrimenti non verrà inibito il menu contestuale del browser!

Si parte 'costruendo' il menu alternativo. Per questo imposto lo stile degli elementi del menu, in modo che non siano sottolineati e che al passaggio del mouse vengano evidenziati (rendendo navy lo sfondo e white la scritta).
Successivamente creo il menu e tutti i link che sono al suo interno. L'oggetto <div> ha id="menu", così da poterci riferire a lui dai vari script o dai link. Vediamo ora due elementi fondamentali di questo menu, un normale (si fa per dire) link e il link che permette di vedere il sorgente (volevo fare tutto fuorché impedire a qualcuno di vedere il sorgente delle mie pagine).

Un link 'normale' si presenta nel seguente modo: normale tag con riferimento alla pagina da aprire e il frame dove aprirla, uno style che imposta le dimensioni dell'elemento del menu a 130x10 pixel, un onclick che nasconde il menu (dopo che abbiamo cliccato, bisogna che il menu scompaia!) e poi gli applichiamo la classe che abbiamo creato dentro <style> per evidenziarlo al passaggio del mouse.

Il link che mostra il sorgente è come quello 'normale' solamente che differisce nella parte dell'indirizzo della pagina da aprire: qui rimanda ad un metodo javascript che verrà creato più sotto.

Infine c'è una semplice parte di testo con la scritta 'AlexMfM menu ver.1.6

Qui finisce la parte 'fisica' del menu, ed inizia lo script che gestisce la comparsa del menu alla pressione del tasto destro del mouse ed alle coordinate della pressione.

Lo script inizia richiamando la funzione mostra_menu() alla pressione di uno qualsiasi dei pulsanti del mouse (sarà il metodo stesso a farsi carico di riconoscere quale pulsante è stato premuto).

La funzione inizia dichiarando 4 variabili che andranno a contenere le coordinate del click del tasto destro (posx e posy) e del tasto sinistro (pos_e1x e pos_e1y).
Successivamente si fa un test su quale bottone è stato premuto: nel caso sia il secondo o terzo bottone (corrisponde al tasto destro per i mouse a due o tre tasti), si assegna a posx il valore della coordinata X dell'evento all'interno del canvas (l'area visibile della pagina) addizionata con lo scroll sinistro e a posy il valore della coordinata Y dell'evento sempre all'interno del canvas addizionata con lo scroll dall'alto (vedi nota più sotto).
Successivamente vengono assegnate queste coordinate all'angolo superiore sinistro del menu (in realtà non si assegnano proprio le coordinate precise, ma le coordinate meno tre, in modo da avere il puntatore leggermente dentro il menu, ma questo è solo un dettaglio che può anche essere ignorato).
Infine si rende il menu visibile.

-------------------- NOTA
Come viene assegnato un valore a posx e posy.
Prendiamo ad esempio soltanto posy tanto per posx vale lo stesso regionamento.
Se si usa solamente event.clientY tutto funziona bene fino a che non si fa uno scroll della pagina. Con questo metodo infatti si hanno le coordinate del cursore rispetto all'angolo superiore sinistro attualmente visibile della pagina. Quindi, ponendo una altezza di 500 pixel per l'area visibile di una pagina, dopo tre scroll della pagina cliccando in alto nella parte attualmente visibile ci troveremo sicuramente ad avere una coordinata Y maggiore di 500 (in assoluto). Però per il metodo event.clientY ci troviamo in alto nella parte visibile, quindi sicuramente meno di 500 (poniamo 10 px).
A questo punto quando viene impostata questo valore al menu, esso viene posizionato ai 10 px dall'inizio della pagina, ma questo avviene assolutamente, quindi a 10 px dall'inizio del tag body!!! E spesso in questo modo il menu non lo si riesce a vedere perché torna in cima alla pagina, mentre magari noi siamo alla fine.
Per ovviare a questo inconvenienete si aggiunge a questo valore quello di document.body.scrollTop ed il gioco è fatto, in quanto si dice al browser di quanto ci siamo spostati dall'inizio della pagina.

Se avete pensato di usare event.offsetX ed event.offsetY mi dispiace ma va bene soltanto a metà, nel senso che fino a che la pagina non ha elementi come tabelle o <div> tutto è ok, mentre se ci sono tali elementi, il browser usa come origine delle coordinate l'angolo superiore sinistro di tali elementi, creando lo stesso problema di event.clientY da solo
--------------------

L'if successivo si occupa della gestione del tasto destro: prende le coordinate del click e quelle dell'angolo superiore sinistro del menu. Dato che quest'ultime sono una stringa formata da un numero e da px, si creano due variabili (interi) che prendono il valore di indice dell'inizio della stringa px all'interno delle variabili pos_box_x e pos_box_y.
Con due successivi cicli for si estraggono i valori numerici da tali stringhe (i e l sono i contatori per i cicli, buffer e buffer_y sono le variabili dove finiranno i nuovi valori delle coordinate, ed estrai e estrai_y sono le variabli che estraggono un carattere alla volta dalla stringa che contiene anche il px.
Quando si sono ottenuti i valori puramente numerici di click e menu, si confrontano: se la x del click ha valore minore del lato sinistro del menu oppure valore maggiore del lato destro (lato sinistro + 130) oppure la y è minore del lato in alto (per quello in basso non c'è ancora il controllo!!! Piccolo bug, ma è dovuto al fatto che non assegno una altezza predefinita al menu!!!), il menu viene fatto scomparire, altrimenti, se si è all'interno del menu non accade nulla (per modo di dire, nel senso che al menu non accade nulla ma se si clicca su di esso si fa quello che è previsto dall'link).

La funzione mostra_sorgente() mostra il sorgente come se si facesse click sulla voce HTML del menu del browser (apre Notepad o l'editor associato al browser).


Piccola nota aggiunta con l'upgrade da AlexMfM Menu ver 1.7 a AlexMfM Menu ver 1.8: con gli attributi display='none' e display='inline' al posto di visibility='hidden' e visibility='visible' si elimina il fastidioso problema dello 'scatto' della scrollbar alla visualizzazione del menu.
Con visibility infatti gli oggetti vengono soltanto resi visibili o invisibili, mentre con display, gli oggetti ci sono ma non occupano spazio!!!