RightContext v0.2.5 : A REAL JavaScript Context Menu – Supercharged and on Anabolic Steroids! MMMMM….
CURRENT VERSION: Version 0.2.5 – RightContext is no longer just a right click context menu, and can be triggered by Left, Right clicks, or mouse over events! Thanks for all those who posted feedback – It REALLY helped!
This release also contains all previous fixes (discussed in the comments below), plus conditional display of menu items based on tag values (more in the comments and the docs).
0.2.5 fixes issues reported with Firefox 3.
RightContext is a supercharged right click context menu done in glorious JavaScript. It can be triggered by either a right or left click, or by mouse overs. I created it to answer a few requirements I had of context menus which I could not find anywhere else; mainly provide the *correct* contextualized menu items depending on what was right clicked. So now when you click a name link for example, the context menu can provide you with links relating to the contact’s email, phone, address etc.
RightContext generates unique context menus that are built based on the DOM element clicked using special attributes embedded in the element’s Html. The attributes are custom generated and can be anything.
Menu items can include [tags] referencing those attributes, which will cause them to be transformed to contain the actual values when the menu is constructed (i.e., when an element is right clicked.)
The main features of RightContext are:
- Trigger menus via left or right clicks, or by mouse over events (new in 0.2.4)
- Menu items that link somewhere
- Menu items that perform a custom javascript function
- Menu items that display hard coded text
- Menu items that retrieve text via a remote ‘ajax’ call
- Menu item separators
- Image icons for menu items
- Supports multiple different menus that can be called depending on the element clicked
- All menu items can contain [tags] which are transformed at runtime to the values embedded in the clicked element
- Conditional evaluation of menu items. An item can show or not show depending on a specified condition in the menu template (new in v0.2.3)
- CSS based look and feel
- Unobtrusive standalone javascript: no additional js framework required.
The script is very simple to use. You simply define your menu ‘templates’ and add a ‘context’ attribute (and any additional custom ones you need) to each element you’d like to have a context menu:
context="actionsMenu" attr1="name" attr2="email@email.com" .....
The code is free to use and modify for any purpose. There’s more information and usage instructions in the code itself as comments.
May 15th, 2007 at 4:38 pm
Harel -
I got the code to work. Also, I noticed that onmouseover / onmouseout didn’t work with IE 6, so I changed the code to the following. It works with IE 6, FF2 at least, not sure of the others.
this.bindEvent(‘mouseover’, cell, function(e) {cell.className=”rcMenuItemHover”;});
this.bindEvent(‘mouseout’, cell, function(e) { cell.className=”rcMenuItem”; });
May 23rd, 2007 at 11:30 am
Hi Harel,
I wanted some titles in the contextmenu but I didn’t want them to have a rollover. So, i’ve changed this, maybe you want to have this in your maincode too? I think it’s pretty handy…
this.bindEvent(‘mouseover’, cell, function(e) { this.className=”rcMenuItemHover”;});
to:
if (item["url"]==null) {
this.bindEvent(‘mouseover’, cell, function(e) { this.className=”rcMenuItemHoverTitle”;});
}
else {
this.bindEvent(‘mouseover’, cell, function(e) { this.className=”rcMenuItemHover”;});
}
May 23rd, 2007 at 11:42 am
Also i have deleted this line:
cell.style.cursor = document.all?’hand’:'pointer’;
In this way I can set the cursor via the css-file…
i think it’s way better because the user can set this to whatever he wants without editting the JS-code…
May 23rd, 2007 at 11:59 am
Harel,
Here i am again…
Is het possible to add shadow to the context menu?
There’s a nice script for this at: http://www.webtoolkit.info/css-drop-shadow.html
Thanks in advance!
May 24th, 2007 at 11:43 am
I wanted to use a onclick-handler…this won’t work, what am i doing wrong?
{
type:RightContext.TYPE_MENU,
text:”Re-build menu”,
url:”#”,
onclick:xajax_buildMenu()
}
July 12th, 2007 at 8:01 pm
So there’s a problem in Safari when trying to create onclick event handler(s) with parameters ( i.e. onclick: function() { alert(“What is [a]?”);} ). If a=2, instead of displaying as “What is 2?”, it displays as “What is [a]?”.
The reason this occurs is that the line
itemAction = eval(itemSrc);
is throwing an SyntaxError exception. This is because in Safari, the new keyword is required before function () { …} to evaluate correctly. I guess a fix would be to add the lines:
// …
else if (navigator.appName == “Netscape”) // probably a better way to do this
eval(‘itemAction = new ‘ + itemSrc + ‘;’);
// … else …
July 12th, 2007 at 8:16 pm
Actually nevermind, I’m an idiot, the new keyword makes things worse. Apparently parsing works in safari using the line ” eval(‘itemAction = ‘ + itemSrc); ” but not ” itemAction = eval(itemSrc) “, which seems to only work in ffx. But anyways I just changed:
if (document.all)
eval(‘itemAction = ‘ + itemSrc);
} else { // firefox allows this.
itemAction = eval(itemSrc);
}
to just
eval(‘itemAction = ‘ + itemSrc);
and it seems to work alright now.
July 19th, 2007 at 1:45 pm
Hello! First, many thanks for this script … it’s been a huge help to me! One thing that I’ve tried unsuccessfully to make work, though, is a disabling of the right-click event for anything on the page that isn’t explicitly defined using RightContext. For example, if a user misses one of my links and clicks on the page background, I’d like to disable the browser’s right-click menu. Any suggestions on how to do that? I made an attempt at adding the “body” tag to allowedContexts, added a context attribute to the body tag, and got a menu attached to it, but then only the body tag menu showed up.
July 19th, 2007 at 2:12 pm
Hi Mark,
Try adding this to your document.
document.oncontextmenu = function() { return false; }
I’m not sure it would work 100%. I tested it only briefly but I guess its worth a shot. There are many variations of disabling the right menu for a web page around the web. I assume that if that one does’nt play nicely with RightContext maybe one of the others would. The idea is to disable it completely first and then letting the script reassign the right click to the elements it needs to.
I’m caught up in the process of a major project launch and have little time to maintain anything else at the moment but the second I get some spare time I’ll update a new version with all the notes and comments posted above (I can’t believe there’s so many – its fantastic ;o)
July 24th, 2007 at 6:37 pm
Hi Harel,
Sorry for the late response, but that worked perfectly … many thanks! Best of luck with your projects!
Mark
September 17th, 2007 at 5:06 pm
Harel :
I have the following problem using the menu, I used in a SPAN tag and the atributtes values changing with an ajax calls every 10 secs, but the menu only works before the first change of the atributte ,after the “refresh” of the span nothing happened,the menu does not appear . I tried in IE an Firefox with Windows and Linux and the result is the same. I hope you can help me. Excuse my english, I now is not very good.
Regards from Argentina.
AnÃbal.
September 17th, 2007 at 5:13 pm
Hi Anibal,
Try calling this after you change the attributes to have them reload:
RightContext.attachContextEvents();
let me know if that works.
Harel
September 17th, 2007 at 6:17 pm
Harel , didn’t work. Any ideas ? .
Thanks for the quick reply.
AnÃbal.
September 17th, 2007 at 6:36 pm
This is strange..if I insert an alert(); at the first line of the RightContext.attachContextEvents(); works, the menu appears.
September 18th, 2007 at 3:52 pm
Hi Harel, it´s me again. I still have the problem with the menu..only appears the first time before the reload of the attributes. I don`t know what is doing the “alert()”, but with this..the menu works, of course I need remove the alert, I only use it for debbuging. Any ideas ?.
Thanks in advance.
AnÃbal.
September 18th, 2007 at 4:17 pm
Hmm. Unfortunately I don’t have the time at the moment to debug this myself, but I can perhaps guess that maybe your attribute changing script is calling the attachContextEvents() before its done? and perhaps the alert() is giving just the right time it needs to wrap up?
Try to make sure the call to that functoin happens only after your ajax call is done. As a quick fix, if you need it, you can just put a little timer to wait a second before calling that method. So its this instead of alert():
window.setTimeout(“dummy=1″, 1000);
Obviously the js statement doesn’t really matter here as we only want to stall for a second. As I said though – this is just a quick and dirty *potential* fix until the real problem can be resolved.
Let me know if it works, and sorry I can’ t be too much help right now.
Harel
September 18th, 2007 at 8:18 pm
Harel,didn’t work. Thanks anyway for your time, If I can solve it I will let you know. I keep on trying… thanks again.
Regards.
AnÃbal.
October 5th, 2007 at 12:49 pm
Hi Harel,
first of all, really great script!!
I also had problems with the ie select z-index bug.
Your suggested solution using functions from dynarch’s jsCalendar, is in my opinion not the best way.
It disturbs me, that the lower element are completely invisible.
And so i found a really handy solution by using a iframe (e.g. http://dotnetjunkies.com/WebLog/jking/archive/2003/07/21/488.aspx)
I have adapted three functions in your script, buildMenu, render & killMenu.
* buildMenu, i changed the position of the contextmenu
// this.position (this.contextMenu, this.mousePos.x + this.rightOffset, pos.y+dim.height);
this.position (this.contextMenu, this.mousePos.x + this.rightOffset, this.mousePos.y);
* render, i created a iframe element with exact the same position & dimension as the contextmenu.
…
this.isShowing = true;
if (navigator.appName==”Microsoft Internet Explorer”) {
var mPos = this.findPosition(this.contextMenu);
var mDim = this.getDimensions(this.contextMenu);
var iFrame = document.createElement(“IFRAME”);
this.contextMenu.style.zIndex=this.contextMenu.style.zIndex+2;
iFrame.id=’iframe’;
iFrame.setAttribute(“src”, “”);
iFrame.style.zIndex=iFrame.style.zIndex+1;
iFrame.style.filter=’progid:DXImageTransform.Microsoft.Alpha(style=0,opacity=0)’;
iFrame.style.position=”absolute”;
iFrame.style.left =mPos.x + ‘px’;
iFrame.style.top = mPos.y + ‘px’;
iFrame.style.width =mDim.width +2+ ‘px’;
iFrame.style.height =mDim.height +2+ ‘px’;
document.body.appendChild(iFrame);
}
* killMenu, i removed the iframe
…
document.body.removeChild(rc);
document.body.removeChild(document.getElementById(‘iframe’));
…
Regards,
Andy
October 6th, 2007 at 6:06 pm
Hi Harel,
I wanted to get the rightContext menu for an IFRAME, But this is not working. Is there any workaround to get this to work?
Thanks,
Anurag
October 26th, 2007 at 3:17 pm
hi. i made a change that support using the same tag several times…
// transforms a string based on the provided map
transform: function (str, map) {
var tStr, tmp;
tStr = str;
for (p in map) {
tmp = “[" + p + "]“;
while (tStr.indexOf(tmp) > -1) {
tStr = tStr.replace(tmp, map[p]);
}
}
return tStr;
}
so if you do this.
{type:RightContext.TYPE_MENU,
text:”The second item in the menu. it will show if attr3=Y (and its: [attr3] [attr3])”,
requires: ["attr3", "Y"],
onclick:function() { alert(‘custom 1:[attr3]‘); alert(‘custom 2:[attr3]‘)} }
Without this patch/fix: you will get this
The second item in the menu. it will show if attr3=Y (and its: Y [attr3])
The alerts will be:
custom 1:Y
custom 2:[attr3]
NOTE: I am not the greatest javascripter. So dont know if there is a better way..
Fanno
October 26th, 2007 at 3:49 pm
if (this.isDisplayed(items[m], objMap)) {
this.addMenuItem(items[m], objMap, tbl);
}
should be moved so that this.isDisplayed(items[m], objMap) is check with EVRY item … ( this is insid ::: render: function (caller, name) { … } ) you might only want to display a horisontal line if there is something UNDER it..
// loop the menu items and render each according to its type
for (var m=0; m
October 26th, 2007 at 3:53 pm
beh .. trying again for some reason the post is not added corectly because of the in the what is in X = for (var m=0; mXitems.length; m++)…
this is what should be inside the for loop that go throw the items..
if (this.isDisplayed(items[m], objMap)) {
switch (items[m]["type"]) {
case this.TYPE_MENU:
// add the menu item
this.addMenuItem(items[m], objMap, tbl);
break;
case this.TYPE_TEXT:
// add fixed text
text = this.transform(items[m]["text"], objMap);
cell = this.addTableCell(tbl, “rcMenuItemText”, text);
break;
case this.TYPE_TEXT_EXT:
cell = this.addTableCell(tbl, “rcMenuItemTextExt”);
url = this.transform(items[m]["url"], objMap);
this.request(url, function() { if (RightContext.req.readyState == 4 && RightContext.req.status == 200) { cell.innerHTML = RightContext.req.responseText } });
break;
case this.TYPE_SEPERATOR:
cell = this.addTableCell(tbl);
cell.appendChild(this.getSeparator());
break;
default:
// no default behaviour
break;
}
}
fanno
November 7th, 2007 at 4:00 pm
First I wanted to say that this script has been really useful on my website, and I appreciate the work you put into it.
I just ran into a problem recently though. It seems that passing attributes/variables in the menus no longer works in Safari 3 (both Mac and Win) and the new Beta for Firefox 3.
I was just wondering if you were still working on the script or if I would need to look for a new solution for the future. Thanks…
November 7th, 2007 at 11:15 pm
Greg,
I will re-adapt the script to Firefox3 once its out of beta and properly released. I just don’t have the time to do it right now. As for Safari, I’ll have to let the good mac user folk who commented above to help out with that as I don’t use a mac nor have access to one easily… But I’m sure whatever problem will be resolved.
Obviously – read the above without any guarantees ;o)
November 9th, 2007 at 8:04 pm
Harel,
Great script, the functionality is out of this world, a quick question though.
I am currently using the script from within an iframe, and I would like to use a text item url link back to the parent window. I’ve tried the following but keep getting errors:
url:”[b].htm”, frame:”_top” or url:”[b].htm”, frame:”_parent” but no luck.
Thanks for your help…
December 13th, 2007 at 5:03 pm
I need to know if you can add submenus and, if applicable, how do? Thanks.
January 4th, 2008 at 8:36 am
Hi! Very interesting code, but unfortunately it does not work in my Opera Browser… (Version 9.2.3)
January 4th, 2008 at 8:49 am
Michail,
Once I get my life back and work eases up, I’ll test it (unless someone else is willing to pick it up ;o)
Scroll up the (many) comments above, maybe someone had a fix ?
February 12th, 2008 at 4:08 pm
Hi !
I have just start to play with your right-click-context script
It works fine, but on things are a bit strange
and then I have a question
I dont get the frame:” xxx ” to work
I tried with your example
————————
{type:RightContext.TYPE_MENU,
text:”Search for [y] on Yahoo (in new window)”,
url:”http://search.yahoo.com/search?p=[x]“,
frame:”content”},
————————
but it dont work
and if I set the BASE TARGET=” xxx ” and take away the fram:” xxx ” it still dont work.
Where can I set the property for that the meny is “oriented” against the left side of the window ?
Hope for some help
/Stefan
February 13th, 2008 at 10:00 am
Hello.
I will inform of the content that modifies RightContext(Current Version:0.2.4) a little.
Please forgive me if there is respect where the content is not understood enough ahead of that.
Tag is defined by allowedContexts.
This one content was added though was defined 4 pieces.
["a","div","span","input","th"],
This is because it wants to do the context menu also in the cell of
the table.
GetDimensions was modified as follows by one added thing.
getDimensions: function(obj) {
//var display = obj.getStyle(‘display’);
//if (display != ‘none’ && display != null) // Safari bug
// return {width: element.offsetWidth, height: element.offsetHeight};
// All *Width and *Height properties give 0 on elements with display none,
// so enable the element temporarily
var objStyle = obj.style;
if (objStyle.length)
{
var originalVisibility = objStyle.visibility;
var originalPosition = objStyle.position;
var originalDisplay = objStyle.display;
objStyle.visibility = ‘hidden’;
objStyle.position = ‘absolute’;
objStyle.display = ‘block’;
objStyle.display = originalDisplay;
objStyle.position = originalPosition;
objStyle.visibility = originalVisibility;
}
var originalWidth = obj.clientWidth;
var originalHeight = obj.clientHeight;
return {width: originalWidth, height: originalHeight};
},
To the report above
February 16th, 2008 at 5:43 am
Hello.
The comment of Rightcontext was sent.
Rightcontext.js can be used very significantly.
Because it wanted the function a little more for me, the following
respect is tried.
1.Display of popup on TR.
2.Popup to popup.(Subordinate relation)
HTML under the trial is in the following and do Access, please if it is good.
http://gaudiken.s57.xrea.com/javascript/rightpopup/test2.html
March 31st, 2008 at 7:06 pm
Excellent Script! One question. I want to be able to right click on a record in table format and offer a “delete item” option that will pop up a javascrip confirm asking the user if s/he really wants to delete the item. Is this possible currently, or is there a workaround I can use. Thanks.
April 16th, 2008 at 1:16 pm
Hello!
First of all I would like to thank you for this great script.
I am using it a lot on our management website, however I have the same problem that Anibal has above and with my (limited) JS script knowledge i cannot figure it out.
The problem is that i have a div in my main page. In this page the context menu works perfectly. But i have ajax searchfield which replaces the DIV with another. In this div the right context does not work. Nothing happens. Any idea on what the error may be? My JS console does not repost any errors. Can this be a simple z-index error perhaps. I have no idea.
Thanks!
May 30th, 2008 at 12:32 pm
Great script! Really!
But there is one small issue for me with the mouseover events:
In a calendar view for example, with very small space between the hover-trigger elements there is the timeout with 500 ms and 300 ms too big (i think this is the killbubble event which is causing the troubles).
So the second bubble is shown just for some milliseconds.
Suiteable and tested by me are 10 milliseconds for all those events. (has to be changed for times in code, just do a search for ‘mouseover’ and you’ll find it out where).
greets Clemens
June 18th, 2008 at 9:13 am
Great, great script!!!
But.. Could you fix it for FF3 final? when I (right)click the [tag] is not translated !!!
June 18th, 2008 at 7:23 pm
Hello
I’ve just downloaded Firefox 3 and what a surprise the attributes in the onclick Event don’t work anymore. The IE is still passing the attributes. I have no idea how to fix this.
Thanks and greetings from Switzerland
June 19th, 2008 at 10:34 am
Firefox 3 ships with a default setting to not allow right click events to disable the browser’s context menus.
The setting can be found in Edit -> Preferences -> Content Tab. Click the third advanced button, next to “Enable Javascript” for the javascript settings.
There make sure the checkbox to allow scripts to “Disable or replace the context menu” is ticked.
If anyone knows how to set this one programaticaly, please post here.
July 2nd, 2008 at 1:02 pm
Hi
If you click on your Demo Page (http://www.harelmalka.com/rightcontext/) on one of the names then the onclick Function doesn’t get the attributes. I’ve got the same problem. I’ve allowed everything to JavaScript.
Thanks
July 7th, 2008 at 1:05 pm
Hi
I have the same problem with Firefox 3, the [tag] is not translated, anyone knows hot to fix it.
Thanks
July 7th, 2008 at 3:55 pm
Dominik,
Which name/link is it? It works absolutely fine for me on FF3 on Linux. Which browser and OS are you using?
Harel
July 9th, 2008 at 5:41 pm
Harel,
I use FF3 on Linux and it doesn’t work. I’ve got the same problem in FF3 on Mac and Windows.
July 17th, 2008 at 9:36 pm
Javier is correct. In FF2, the tag (for example “[b]“) is being converted to the variable value. In FF3, it is being passed as a literal.
July 24th, 2008 at 9:02 pm
OK, here’s the situation. When a javascript function is called from a right-click menu item, the “[X]” symbol is being converted to the proper value everywhere EXCEPT at the function call. Hang in there… it looks like we’ve found the answer and a solution to this problem. Our head programmer will be logging on shortly with the fix for ‘The case of FF3 and the strange variable’.
July 25th, 2008 at 2:00 pm
Things are a bit busy around here, so I’m going to post the solution instead of asking Richard to do it. This is what he found in the original code:
itemSrc = item["onclick"].toString();
if (itemSrc.indexOf(‘[')>-1) {
itemSrc = this.transform(itemSrc, objMap);
if (document.all) { // IE's eval won't return a parsed function.. we need to tell it to set it and then eval
eval('itemAction = ' + itemSrc);
} else { // firefox allows this.
itemAction = eval(itemSrc);
}
}
well... it looks like Firefox no longer allows this, so simply use the same code as from the IE branch like so:
itemSrc = item["onclick"].toString();
if (itemSrc.indexOf(‘[‘)>-1) {
itemSrc = this.transform(itemSrc, objMap);
if (document.all) { // IE’s eval won’t return a parsed function.. we need to tell it to set it and then eval
eval(‘itemAction = ‘ + itemSrc);
} else { //now we need to tell Firefox the same thing!
eval(‘itemAction = ‘ + itemSrc);
}
}
This has solved the problem for us. Hope it does the same for the rest of you folks.
August 22nd, 2008 at 11:10 am
Hi! Great code! I wanted to share one little modification I made. When I make a RightContext menu on a big div, nos just a single line (fullscreen actually) the menu was always created at the bottom of the page. I added a few lines and now it’s created near your mouse, and it is still created correctly in case you are too close to the boundaries of the screen. My added code is in bold letters:
repositionMenu: function() {
var mPos = this.findPosition(this.contextMenu);
var mDim = this.getDimensions(this.contextMenu);
var winHeight = window.innerHeight || document.body.clientHeight;
var winWidth = window.innerWidth || document.body.clientWidth;
mPos.y=this.mousePos.y;
if (mPos.y + mDim.height > winHeight-30 ) {
this.position(this.contextMenu, mPos.x, mPos.y – mDim.height);
mPos = this.findPosition(this.contextMenu);
}
else
{
this.position(this.contextMenu, this.mousePos.x, this.mousePos.y);
mPos=this.findPosition(this.contextMenu);
}
if (mPos.x + mDim.width > winWidth – 30 ) {
this.position(this.contextMenu, mPos.x-mDim.width, mPos.y);
}
else
{
this.position(this.contextMenu, this.mousePos.x, mPos.y);
mPos=this.findPosition(this.contextMenu);
}
}
It may have some bugs, I have to say I’m just a begginer with this damned thing called ‘Javascript’
Again: Thank you!!
August 22nd, 2008 at 11:12 am
OOps! Sorry! Mistake with tags! I’ll try once more:
repositionMenu: function() {
var mPos = this.findPosition(this.contextMenu);
var mDim = this.getDimensions(this.contextMenu);
var winHeight = window.innerHeight || document.body.clientHeight;
var winWidth = window.innerWidth || document.body.clientWidth;
mPos.y=this.mousePos.y;
if (mPos.y + mDim.height > winHeight-30 ) {
this.position(this.contextMenu, mPos.x, mPos.y – mDim.height);
mPos = this.findPosition(this.contextMenu);
}
else
{
this.position(this.contextMenu, this.mousePos.x, this.mousePos.y);
mPos=this.findPosition(this.contextMenu);
}
if (mPos.x + mDim.width > winWidth – 30 ) {
this.position(this.contextMenu, mPos.x-mDim.width, mPos.y);
}
else
{
this.position(this.contextMenu, this.mousePos.x, mPos.y);
mPos=this.findPosition(this.contextMenu);
}
}
September 28th, 2008 at 9:11 am
Update:
If you’re getting tags not pass properly for onclick menu items, in particular on FF3, you can update this around line 428:
if (itemSrc.indexOf(‘[‘)>-1) {
itemSrc = this.transform(itemSrc, objMap);
eval(‘itemAction = ‘ + itemSrc);
}
ie – no need for IE/FF conditional here… I know this is a bit of a terse explanation but I will find time soon and collate all the comments into a new revision.
THANKS!
November 16th, 2008 at 4:18 pm
Thanks for the script, I build it into a simple map (made up by a table) I created for a browser game, and it works like a charm!
The only thing that surprised me: Why did you overwrite the “_blank” property to always open in the same frame/tab/window? (may be chanced in the redirect: function)
November 17th, 2008 at 11:43 am
hpy, _blank opens in a new window explicitly, not in the same frame… I don’t remember why I did it exactly like that to be honest. I’m sure I had a good reason at the time (sorry I got into this long term vortex of work and time is not on my side…)
January 11th, 2009 at 2:29 pm
Menu items that retrieve text via a remote ‘ajax’ call
Feature says it can utilize Ajax too, but I haven’t seen any Ajax calls. There is no even an Ajax function in the code. How does Ajax work?
Any demo? thank you