transit
05-13-2009, 12:51 PM
1) Script Title: Smooth Menu
2) Script URL (on DD): http://www.dynamicdrive.com/dynamicindex1/ddsmoothmenu.htm
3) Describe problem: We plan to use the smooth menu for a website we're making, but we've run into a problem in the form of the Acrobat Reader. DHTML menus won't display over the piece of crap plug-in that is Acrobat reader.
So, we've resorted to using IFrame shim to make sure the menu show. Currently, after stripping the animation and shadows from the smooth menu, it only works correctly in IE, the shim size is wrong in Chrome, firefox either works or not, depending of the location of the menu in the markup (can't figure out why) and nothing works in Opera.
The following code is where I'm currently stucked. I must admit that my javascript is very rusty and my knowledge of cross-browser compatibility is limited. So, if anyone has any idea on how to improve / make it fully functional, I'd appreciate the help before I go totally insane!
Claude
var iFrame = null;
var SKIP = "SkipLeftOffset"
var SKIPNOTOP = "SkipLeftOffsetAndTopOffset"
var ddsmoothmenu = {
//Specify full URL to down and right arrow images (23 is padding-right added to top level LIs with drop downs):
arrowimages: { down: ['downarrowclass', 'down.gif', 23], right: ['rightarrowclass', 'right.gif'] },
transition: { overtime: 0, outtime: 0 }, //duration of slide in/ out animation, in milliseconds
shadow: { enabled: false, offsetx: 5, offsety: 5 },
///////Stop configuring beyond here///////////////////////////
detectwebkit: navigator.userAgent.toLowerCase().indexOf("applewebkit") != -1, //detect WebKit browsers (Safari, Chrome etc)
detectie6: document.all && !window.XMLHttpRequest,
getajaxmenu: function($, setting) { //function to fetch external page containing the panel DIVs
var $menucontainer = $('#' + setting.contentsource[0]) //reference empty div on page that will hold menu
$menucontainer.html("Loading Menu...")
$.ajax({
url: setting.contentsource[1], //path to external menu file
async: true,
error: function(ajaxrequest) {
$menucontainer.html('Error fetching content. Server Response: ' + ajaxrequest.responseText)
},
success: function(content) {
$menucontainer.html(content)
ddsmoothmenu.buildmenu($, setting)
}
})
},
buildmenu: function($, setting) {
var smoothmenu = ddsmoothmenu
var $mainmenu = $("#" + setting.mainmenuid + ">ul") //reference main menu UL
$mainmenu.parent().get(0).className = setting.classname || "ddsmoothmenu"
var $headers = $mainmenu.find("ul").parent()
$headers.hover(function(e) { $(this).children('a:eq(0)').addClass('selected') }, function(e) { $(this).children('a:eq(0)').removeClass('selected') })
$headers.each(function(i) { //loop through each LI header
var $curobj = $(this).css({ zIndex: 20000 - i }) //reference current LI header
var $subul = $(this).find('ul:eq(0)').css({ display: 'block' })
this._dimensions = { w: this.offsetWidth, h: this.offsetHeight, subulw: $subul.outerWidth(), subulh: $subul.outerHeight() }
this.istopheader = $curobj.parents("ul").length == 1 ? true : false //is top level header?
$subul.css({ top: this.istopheader && setting.orientation != 'v' ? this._dimensions.h + "px" : 0 })
$curobj.children("a:eq(0)").css(this.istopheader ? { paddingRight: smoothmenu.arrowimages.down[2]} : {}).append( //add arrow images
'<img src="' + (this.istopheader && setting.orientation != 'v' ? smoothmenu.arrowimages.down[1] : smoothmenu.arrowimages.right[1])
+ '" class="' + (this.istopheader && setting.orientation != 'v' ? smoothmenu.arrowimages.down[0] : smoothmenu.arrowimages.right[0])
+ '" style="border:0;" />'
)
$curobj.hover(
function(e) {
var $targetul = $(this).children("ul:eq(0)")
this._offsets = { left: $(this).offset().left, top: $(this).offset().top }
var menuleft = this.istopheader && setting.orientation != 'v' ? 0 : this._dimensions.w
menuleft = (this._offsets.left + menuleft + this._dimensions.subulw > $(window).width()) ? (this.istopheader && setting.orientation != 'v' ? -this._dimensions.subulw + this._dimensions.w : -this._dimensions.w) : menuleft //calculate this sub menu's offsets from its parent
$targetul.css({ left: menuleft + "px", width: this._dimensions.subulw + 'px' })
$targetul.css({ display: 'block' })
var $block = $(this).children("ul")
for (i = 0; i < $block[0].children.length; i = i + 1) {
var $leftOff = getLeftOffset($block[0].children[i]);
var $topOff = getTopOffset($block[0].children[i]);
iFrameMenu($block[0].children[i].id, $leftOff, $topOff, $block[0].children[i].offsetWidth, $block[0].children[i].offsetHeight)
}
},
function(e) {
var $targetul = $(this).children("ul:eq(0)")
$targetul.css({ 'display': 'none', 'visibility': 'visible' })
var $block = $(this).children("ul")
for (i = 0; i < $block[0].children.length; i = i + 1)
hideIFrameMenu($block[0].children[i].id);
}
) //end hover
}) //end $headers.each()
$mainmenu.find("ul").css({ 'display': 'none', 'visibility': 'visible' })
},
init: function(setting) {
if (typeof setting.customtheme == "object" && setting.customtheme.length == 2) { //override default menu colors (default/hover) with custom set?
var mainmenuid = '#' + setting.mainmenuid
var mainselector = (setting.orientation == "v") ? mainmenuid : mainmenuid + ', ' + mainmenuid
document.write('<style type="text/css">\n'
+ mainselector + ' ul li a {background:' + setting.customtheme[0] + ';}\n'
+ mainmenuid + ' ul li a:hover {background:' + setting.customtheme[1] + ';}\n'
+ '</style>')
}
this.shadow.enabled = false
jQuery(document).ready(function($) { //ajax menu?
if (typeof setting.contentsource == "object") { //if external ajax menu
ddsmoothmenu.getajaxmenu($, setting)
}
else { //else if markup menu
ddsmoothmenu.buildmenu($, setting)
}
})
}
}
// Created a iFrame because I want the menu pass over
// a SELECT or/and a IFRAME when the menu is used.
function iFrameMenu(menu, left, top, width, height) {
// Verified if the iFrame has been created.
var iFrameExist = document.getElementById("IFRAME" + menu);
if (!iFrameExist) { //Create the iframe
iFrame = document.createElement("IFRAME");
iFrame.id = "IFRAME" + menu;
iFrame.style.zindex = "1100";
iFrame.frameBorder = "no";
iFrame.scrolling = "no";
iFrame.style.filter = "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)";
iFrame.style.visibility = 'visible';
iFrame.style.display = "";
iFrame.style.position = "absolute";
iFrame.src = 'javascript:new String("<html></html>")';
iFrame.style.left = left + "px";
iFrame.style.top = top + "px";
iFrame.style.width = width;
iFrame.style.height = height;
var e = document.body.firstChild;
document.body.insertBefore(iFrame, e);
}
else { //If has already created, just changes these properties.
menu.iFrame.style.visibility = "visible";
menu.iFrame.style.display = "block";
}
}
// Hide the iFrame created by the JavaScript.
function hideIFrameMenu(menuId) {
var ifr = document.getElementById('IFRAME' + menuId);
if (ifr != null)
ifr.parentNode.removeChild(ifr);
}
//------------------------------------------------------------------
// Returns the x (Left) offset of the OffsetObj object relative to
// the main window.
function getLeftOffset(OffsetObj) {
var x;
var str;
var isThere;
str = OffsetObj.id;
skipIsThere = str.indexOf(SKIP);
//Verify if the string 'SkipLeftOffset' is in the ID. If yes, I don't
// have to calculated it in the getLeftOffset sum.
if (skipIsThere > -1)
x = 0;
else
x = OffsetObj.offsetLeft;
if (OffsetObj.offsetParent != null) {
x += getLeftOffset(OffsetObj.offsetParent);
}
return x;
}
//------------------------------------------------------------------
// Returns the y (Top) offset of the OffsetObj object relative to
// the main window.
function getTopOffset(OffsetObj) {
var y;
var str;
var isThere;
str = OffsetObj.id
skipIsThere = str.indexOf(SKIPNOTOP)
// Verify if the string 'SkipLeftOffsetAndTopOffset' is in the ID.
// If yes, We don't have to calculated it in the getTopOffset sum.
if (skipIsThere > -1)
y = 0;
else
y = OffsetObj.offsetTop;
if (OffsetObj.offsetParent != null)
y += getTopOffset(OffsetObj.offsetParent);
return y;
}
2) Script URL (on DD): http://www.dynamicdrive.com/dynamicindex1/ddsmoothmenu.htm
3) Describe problem: We plan to use the smooth menu for a website we're making, but we've run into a problem in the form of the Acrobat Reader. DHTML menus won't display over the piece of crap plug-in that is Acrobat reader.
So, we've resorted to using IFrame shim to make sure the menu show. Currently, after stripping the animation and shadows from the smooth menu, it only works correctly in IE, the shim size is wrong in Chrome, firefox either works or not, depending of the location of the menu in the markup (can't figure out why) and nothing works in Opera.
The following code is where I'm currently stucked. I must admit that my javascript is very rusty and my knowledge of cross-browser compatibility is limited. So, if anyone has any idea on how to improve / make it fully functional, I'd appreciate the help before I go totally insane!
Claude
var iFrame = null;
var SKIP = "SkipLeftOffset"
var SKIPNOTOP = "SkipLeftOffsetAndTopOffset"
var ddsmoothmenu = {
//Specify full URL to down and right arrow images (23 is padding-right added to top level LIs with drop downs):
arrowimages: { down: ['downarrowclass', 'down.gif', 23], right: ['rightarrowclass', 'right.gif'] },
transition: { overtime: 0, outtime: 0 }, //duration of slide in/ out animation, in milliseconds
shadow: { enabled: false, offsetx: 5, offsety: 5 },
///////Stop configuring beyond here///////////////////////////
detectwebkit: navigator.userAgent.toLowerCase().indexOf("applewebkit") != -1, //detect WebKit browsers (Safari, Chrome etc)
detectie6: document.all && !window.XMLHttpRequest,
getajaxmenu: function($, setting) { //function to fetch external page containing the panel DIVs
var $menucontainer = $('#' + setting.contentsource[0]) //reference empty div on page that will hold menu
$menucontainer.html("Loading Menu...")
$.ajax({
url: setting.contentsource[1], //path to external menu file
async: true,
error: function(ajaxrequest) {
$menucontainer.html('Error fetching content. Server Response: ' + ajaxrequest.responseText)
},
success: function(content) {
$menucontainer.html(content)
ddsmoothmenu.buildmenu($, setting)
}
})
},
buildmenu: function($, setting) {
var smoothmenu = ddsmoothmenu
var $mainmenu = $("#" + setting.mainmenuid + ">ul") //reference main menu UL
$mainmenu.parent().get(0).className = setting.classname || "ddsmoothmenu"
var $headers = $mainmenu.find("ul").parent()
$headers.hover(function(e) { $(this).children('a:eq(0)').addClass('selected') }, function(e) { $(this).children('a:eq(0)').removeClass('selected') })
$headers.each(function(i) { //loop through each LI header
var $curobj = $(this).css({ zIndex: 20000 - i }) //reference current LI header
var $subul = $(this).find('ul:eq(0)').css({ display: 'block' })
this._dimensions = { w: this.offsetWidth, h: this.offsetHeight, subulw: $subul.outerWidth(), subulh: $subul.outerHeight() }
this.istopheader = $curobj.parents("ul").length == 1 ? true : false //is top level header?
$subul.css({ top: this.istopheader && setting.orientation != 'v' ? this._dimensions.h + "px" : 0 })
$curobj.children("a:eq(0)").css(this.istopheader ? { paddingRight: smoothmenu.arrowimages.down[2]} : {}).append( //add arrow images
'<img src="' + (this.istopheader && setting.orientation != 'v' ? smoothmenu.arrowimages.down[1] : smoothmenu.arrowimages.right[1])
+ '" class="' + (this.istopheader && setting.orientation != 'v' ? smoothmenu.arrowimages.down[0] : smoothmenu.arrowimages.right[0])
+ '" style="border:0;" />'
)
$curobj.hover(
function(e) {
var $targetul = $(this).children("ul:eq(0)")
this._offsets = { left: $(this).offset().left, top: $(this).offset().top }
var menuleft = this.istopheader && setting.orientation != 'v' ? 0 : this._dimensions.w
menuleft = (this._offsets.left + menuleft + this._dimensions.subulw > $(window).width()) ? (this.istopheader && setting.orientation != 'v' ? -this._dimensions.subulw + this._dimensions.w : -this._dimensions.w) : menuleft //calculate this sub menu's offsets from its parent
$targetul.css({ left: menuleft + "px", width: this._dimensions.subulw + 'px' })
$targetul.css({ display: 'block' })
var $block = $(this).children("ul")
for (i = 0; i < $block[0].children.length; i = i + 1) {
var $leftOff = getLeftOffset($block[0].children[i]);
var $topOff = getTopOffset($block[0].children[i]);
iFrameMenu($block[0].children[i].id, $leftOff, $topOff, $block[0].children[i].offsetWidth, $block[0].children[i].offsetHeight)
}
},
function(e) {
var $targetul = $(this).children("ul:eq(0)")
$targetul.css({ 'display': 'none', 'visibility': 'visible' })
var $block = $(this).children("ul")
for (i = 0; i < $block[0].children.length; i = i + 1)
hideIFrameMenu($block[0].children[i].id);
}
) //end hover
}) //end $headers.each()
$mainmenu.find("ul").css({ 'display': 'none', 'visibility': 'visible' })
},
init: function(setting) {
if (typeof setting.customtheme == "object" && setting.customtheme.length == 2) { //override default menu colors (default/hover) with custom set?
var mainmenuid = '#' + setting.mainmenuid
var mainselector = (setting.orientation == "v") ? mainmenuid : mainmenuid + ', ' + mainmenuid
document.write('<style type="text/css">\n'
+ mainselector + ' ul li a {background:' + setting.customtheme[0] + ';}\n'
+ mainmenuid + ' ul li a:hover {background:' + setting.customtheme[1] + ';}\n'
+ '</style>')
}
this.shadow.enabled = false
jQuery(document).ready(function($) { //ajax menu?
if (typeof setting.contentsource == "object") { //if external ajax menu
ddsmoothmenu.getajaxmenu($, setting)
}
else { //else if markup menu
ddsmoothmenu.buildmenu($, setting)
}
})
}
}
// Created a iFrame because I want the menu pass over
// a SELECT or/and a IFRAME when the menu is used.
function iFrameMenu(menu, left, top, width, height) {
// Verified if the iFrame has been created.
var iFrameExist = document.getElementById("IFRAME" + menu);
if (!iFrameExist) { //Create the iframe
iFrame = document.createElement("IFRAME");
iFrame.id = "IFRAME" + menu;
iFrame.style.zindex = "1100";
iFrame.frameBorder = "no";
iFrame.scrolling = "no";
iFrame.style.filter = "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)";
iFrame.style.visibility = 'visible';
iFrame.style.display = "";
iFrame.style.position = "absolute";
iFrame.src = 'javascript:new String("<html></html>")';
iFrame.style.left = left + "px";
iFrame.style.top = top + "px";
iFrame.style.width = width;
iFrame.style.height = height;
var e = document.body.firstChild;
document.body.insertBefore(iFrame, e);
}
else { //If has already created, just changes these properties.
menu.iFrame.style.visibility = "visible";
menu.iFrame.style.display = "block";
}
}
// Hide the iFrame created by the JavaScript.
function hideIFrameMenu(menuId) {
var ifr = document.getElementById('IFRAME' + menuId);
if (ifr != null)
ifr.parentNode.removeChild(ifr);
}
//------------------------------------------------------------------
// Returns the x (Left) offset of the OffsetObj object relative to
// the main window.
function getLeftOffset(OffsetObj) {
var x;
var str;
var isThere;
str = OffsetObj.id;
skipIsThere = str.indexOf(SKIP);
//Verify if the string 'SkipLeftOffset' is in the ID. If yes, I don't
// have to calculated it in the getLeftOffset sum.
if (skipIsThere > -1)
x = 0;
else
x = OffsetObj.offsetLeft;
if (OffsetObj.offsetParent != null) {
x += getLeftOffset(OffsetObj.offsetParent);
}
return x;
}
//------------------------------------------------------------------
// Returns the y (Top) offset of the OffsetObj object relative to
// the main window.
function getTopOffset(OffsetObj) {
var y;
var str;
var isThere;
str = OffsetObj.id
skipIsThere = str.indexOf(SKIPNOTOP)
// Verify if the string 'SkipLeftOffsetAndTopOffset' is in the ID.
// If yes, We don't have to calculated it in the getTopOffset sum.
if (skipIsThere > -1)
y = 0;
else
y = OffsetObj.offsetTop;
if (OffsetObj.offsetParent != null)
y += getTopOffset(OffsetObj.offsetParent);
return y;
}