Missing cursor on form fields with Control.Modal (Firefox BUG)
bump... anyone else encounter this problem ?
Posted August 21st, 2007 at 11:28am by jocmaff
Jeremy,
I'm getting this too, and as you point out, overriding the overlay positioning to absolute brings back the cursor.
This bug has been in Firefox for as long as I can remember. Apparently it's now been fixed. There are some workarounds posted on various forums, which you can find with some Googling, but none of them are pretty.
If a workaround could be cleanly built into Control.Modal, that would be swell, but in the meantime it's something I've learned to live with as my apps are corporate internal and userbase is 100% IE (I just use FF with Firebug for dev/debug).
Ben
Posted August 23rd, 2007 at 4:52am by bbodien
I modified Control.Modal 2.2.2 so that it uses absolutly positioned overlays... Flash and the cursor should work in iframes with this one:
if(typeof(Control) == "undefined") Control = {}; Control.Modal = Class.create(); Object.extend(Control.Modal,{ loaded: false, loading: false, loadingTimeout: false, overlay: false, container: false, current: false, ie: false, effects: { containerFade: false, containerAppear: false, overlayFade: false, overlayAppear: false }, targetRegexp: /#(.+)$/, imgRegexp: /.(jpe?g|gif|png|tiff?)$/, overlayStyles: { position: 'absolute', top: 0, left: 0, zIndex: 9998 }, overlayIEStyles: { position: 'absolute', top: 0, left: 0, zIndex: 9998 }, disableHoverClose: false, load: function(){ if(!Control.Modal.loaded){ Control.Modal.loaded = true; Control.Modal.ie = !(typeof document.body.style.maxHeight != 'undefined'); Control.Modal.overlay = $(document.createElement('div')); Control.Modal.overlay.id = 'modaloverlay'; Object.extend(Control.Modal.overlay.style,Control.Modal['overlay' + (Control.Modal.ie ? 'IE' : '') + 'Styles']); Control.Modal.overlay.hide(); Control.Modal.container = $(document.createElement('div')); Control.Modal.container.id = 'modalcontainer'; Control.Modal.container.hide(); Control.Modal.loading = $(document.createElement('div')); Control.Modal.loading.id = 'modalloading'; Control.Modal.loading.hide(); var bodytag = document.getElementsByTagName('body')[0]; bodytag.appendChild(Control.Modal.overlay); bodytag.appendChild(Control.Modal.container); bodytag.appendChild(Control.Modal.loading); Control.Modal.container.observe('mouseout',function(event){ if(!Control.Modal.disableHoverClose && Control.Modal.current && Control.Modal.current.options.hover && !Position.within(Control.Modal.container,Event.pointerX(event),Event.pointerY(event))) Control.Modal.close(); }); } }, open: function(contents,options){ options = options || {}; if(!options.contents) options.contents = contents; var modalinstance = new Control.Modal(false,options); modalinstance.open(); return modalinstance; }, close: function(force){ if(typeof(force) != 'boolean') force = false; if(Control.Modal.current) Control.Modal.current.close(force); }, attachEvents: function(){ Event.observe(window,'load',Control.Modal.load); Event.observe(window,'unload',Event.unloadCache,false); }, center: function(element){ if(!element.absolutized){ element.setStyle({ position: 'absolute' }); element.absolutized = true; } var dimensions = element.getDimensions(); Position.prepare(); var offsetleft = (Position.deltaX + Math.floor((Control.Modal.getWindowWidth() - dimensions.width) / 2)); var offsettop = (Position.deltaY + ((Control.Modal.getWindowHeight() > dimensions.height) ? Math.floor((Control.Modal.getWindowHeight() - dimensions.height) / 2) : 0)); element.setStyle({ top: ((dimensions.height <= Control.Modal.getDocumentHeight()) ? ((offsettop != null && offsettop > 0) ? offsettop : '0') + 'px' : 0), left: ((dimensions.width <= Control.Modal.getDocumentWidth()) ? ((offsetleft != null && offsetleft > 0) ? offsetleft : '0') + 'px' : 0) }); }, getWindowWidth: function(){ var width = self.innerWidth; // Safari var mode = document.compatMode;
if (mode || Control.Modal.ie) { // IE, Gecko, Opera
width = (mode == 'CSS1Compat') ?
document.documentElement.clientWidth : // Standards
document.body.clientWidth; // Quirks
}
return width;
},
getWindowHeight: function(){
var height = self.innerHeight; // Safari, Opera
var mode = document.compatMode;
if ( (mode || Control.Modal.ie) ) { // IE, Gecko
height = (mode == 'CSS1Compat') ?
document.documentElement.clientHeight : // Standards
document.body.clientHeight; // Quirks
}
return height;
},
getDocumentWidth: function(){
var scrollWidth = (document.compatMode != 'CSS1Compat') ? document.body.scrollWidth : document.documentElement.scrollWidth;
var w = Math.max(scrollWidth, this.getWindowWidth());
return w;
},
getDocumentHeight: function(){
var scrollHeight = (document.compatMode != 'CSS1Compat') ? document.body.scrollHeight : document.documentElement.scrollHeight;
var h = Math.max(scrollHeight, this.getWindowHeight());
return h;
},
onKeyDown: function(event){
if(event.keyCode == Event.KEY_ESC)
Control.Modal.close();
}
}); Object.extend(Control.Modal.prototype,{ mode: '', html: false, href: '', element: false, src: false, imageLoaded: false, ajaxRequest: false, initialize: function(element,options){ this.element = $(element); this.options = { beforeOpen: Prototype.emptyFunction, afterOpen: Prototype.emptyFunction, beforeClose: Prototype.emptyFunction, afterClose: Prototype.emptyFunction, onSuccess: Prototype.emptyFunction, onFailure: Prototype.emptyFunction, onException: Prototype.emptyFunction, beforeImageLoad: Prototype.emptyFunction, afterImageLoad: Prototype.emptyFunction, autoOpenIfLinked: true, contents: false, loading: false, //display loading indicator fade: false, fadeDuration: 0.75, image: false, imageCloseOnClick: true, hover: false, iframe: false, iframeTemplate: new Template(''), evalScripts: true, //for Ajax, define here instead of in requestOptions requestOptions: {}, //for Ajax.Request overlayDisplay: true, overlayClassName: '', overlayCloseOnClick: true, containerClassName: '', opacity: 0.3, zIndex: 9998, width: null, height: null, offsetLeft: 0, //for use with 'relative' offsetTop: 0, //for use with 'relative' position: 'absolute' //'absolute' or 'relative' }; Object.extend(this.options,options || {}); var targetmatch = false; var imagematch = false; if(this.element){ targetmatch = Control.Modal.targetRegexp.exec(this.element.href); imagematch = Control.Modal.imgRegexp.exec(this.element.href); } if(this.options.position == 'mouse') this.options.hover = true; if(this.options.contents){ this.mode = 'contents'; }else if(this.options.image || imagematch){ this.mode = 'image'; this.src = this.element.href; }else if(targetmatch){ this.mode = 'named'; var x = $(targetmatch[1]); this.html = x.innerHTML; x.remove(); this.href = targetmatch[1]; }else{ this.mode = (this.options.iframe) ? 'iframe' : 'ajax'; this.href = this.element.href; } if(this.element){ if(this.options.hover){ this.element.observe('mouseover',this.open.bind(this)); this.element.observe('mouseout',function(event){ if(!Position.within(Control.Modal.container,Event.pointerX(event),Event.pointerY(event))) this.close(); }.bindAsEventListener(this)); }else{ this.element.onclick = function(event){ this.open(); Event.stop(event); return false; }.bindAsEventListener(this); } } var targets = Control.Modal.targetRegexp.exec(window.location); this.position = function(event){ if(this.options.position == 'absolute') Control.Modal.center(Control.Modal.container); else{ var xy = (event && this.options.position == 'mouse' ? [Event.pointerX(event),Event.pointerY(event)] : Position.cumulativeOffset(this.element)); Control.Modal.container.setStyle({ position: 'absolute', top: xy[1] + (typeof(this.options.offsetTop) == 'function' ? this.options.offsetTop() : this.options.offsetTop) + 'px', left: xy[0] + (typeof(this.options.offsetLeft) == 'function' ? this.options.offsetLeft() : this.options.offsetLeft) + 'px' }); } Control.Modal.overlay.setStyle({ height: Control.Modal.getDocumentHeight() + 'px', width: Control.Modal.getDocumentWidth() + 'px' }); }.bind(this); if(this.mode == 'named' && this.options.autoOpenIfLinked && targets && targets[1] && targets[1] == this.href) this.open(); }, showLoadingIndicator: function(){ if(this.options.loading){ Control.Modal.loadingTimeout = window.setTimeout(function(){ var modalimage = $('modalimage'); if(modalimage) modalimage.hide(); Control.Modal.loading.style.zIndex = this.options.zIndex + 1; Control.Modal.loading.update(''); Control.Modal.loading.show(); Control.Modal.center(Control.Modal.loading); }.bind(this),250); } }, hideLoadingIndicator: function(){ if(this.options.loading){ if(Control.Modal.loadingTimeout) window.clearTimeout(Control.Modal.loadingTimeout); var modalimage = $('modalimage'); if(modalimage) modalimage.show(); Control.Modal.loading.hide(); } }, open: function(force){ if(!force && this.notify('beforeOpen') === false) return; if(!Control.Modal.loaded) Control.Modal.load(); Control.Modal.close(); if(!this.options.hover) Event.observe($(document.getElementsByTagName('body')[0]),'keydown',Control.Modal.onKeyDown); Control.Modal.current = this; if(!this.options.hover) Control.Modal.overlay.setStyle({ zIndex: this.options.zIndex, opacity: this.options.opacity }); Control.Modal.container.setStyle({ zIndex: this.options.zIndex + 1, width: (this.options.width ? (typeof(this.options.width) == 'function' ? this.options.width() : this.options.width) + 'px' : null), height: (this.options.height ? (typeof(this.options.height) == 'function' ? this.options.height() : this.options.height) + 'px' : null) }); if(Control.Modal.ie && !this.options.hover){ $A(document.getElementsByTagName('select')).each(function(select){ select.style.visibility = 'hidden'; }); } Control.Modal.overlay.addClassName(this.options.overlayClassName); Control.Modal.container.addClassName(this.options.containerClassName); switch(this.mode){ case 'image': this.imageLoaded = false; this.notify('beforeImageLoad'); this.showLoadingIndicator(); var img = document.createElement('img'); img.onload = function(img){ this.hideLoadingIndicator(); this.update([img]); if(this.options.imageCloseOnClick) $(img).observe('click',Control.Modal.close); this.position(); this.notify('afterImageLoad'); img.onload = null; }.bind(this,img); img.src = this.src; img.id = 'modalimage'; break; case 'ajax': this.notify('beforeLoad'); var options = { method: 'post', onSuccess: function(request){ this.hideLoadingIndicator(); this.update(request.responseText); this.notify('onSuccess',request); this.ajaxRequest = false; }.bind(this), onFailure: function(){ this.notify('onFailure'); }.bind(this), onException: function(){ this.notify('onException'); }.bind(this) }; Object.extend(options,this.options.requestOptions); this.showLoadingIndicator(); this.ajaxRequest = new Ajax.Request(this.href,options); break; case 'iframe': this.update(this.options.iframeTemplate.evaluate({href: this.href, id: 'modaliframe'})); break; case 'contents': this.update((typeof(this.options.contents) == 'function' ? this.options.contents() : this.options.contents)); break; case 'named': this.update(this.html); break; } if(!this.options.hover){ if(this.options.overlayCloseOnClick && this.options.overlayDisplay) Control.Modal.overlay.observe('click',Control.Modal.close); if(this.options.overlayDisplay){ if(this.options.fade){ if(Control.Modal.effects.overlayFade) Control.Modal.effects.overlayFade.cancel(); Control.Modal.effects.overlayAppear = new Effect.Appear(Control.Modal.overlay,{ queue: { position: 'front', scope: 'Control.Modal' }, to: this.options.opacity, duration: this.options.fadeDuration / 2 }); }else Control.Modal.overlay.show(); } } if(this.options.position == 'mouse'){ this.mouseHoverListener = this.position.bindAsEventListener(this); this.element.observe('mousemove',this.mouseHoverListener); } this.notify('afterOpen'); }, update: function(html){ if(typeof(html) == 'string') Control.Modal.container.update(html); else{ Control.Modal.container.update(''); (html.each) ? html.each(function(node){ Control.Modal.container.appendChild(node); }) : Control.Modal.container.appendChild(node); } if(this.options.fade){ if(Control.Modal.effects.containerFade) Control.Modal.effects.containerFade.cancel(); Control.Modal.effects.containerAppear = new Effect.Appear(Control.Modal.container,{ queue: { position: 'end', scope: 'Control.Modal' }, to: 1, duration: this.options.fadeDuration / 2 }); }else Control.Modal.container.show(); this.position(); Event.observe(window,'resize',this.position,false); Event.observe(window,'scroll',this.position,false); }, close: function(force){ if(!force && this.notify('beforeClose') === false) return; if(this.ajaxRequest) this.ajaxRequest.transport.abort(); this.hideLoadingIndicator(); if(this.mode == 'image'){ var modalimage = $('modalimage'); if(this.options.imageCloseOnClick && modalimage) modalimage.stopObserving('click',Control.Modal.close); } if(Control.Modal.ie && !this.options.hover){ $A(document.getElementsByTagName('select')).each(function(select){ select.style.visibility = 'visible'; }); } if(!this.options.hover) Event.stopObserving(window,'keyup',Control.Modal.onKeyDown); Control.Modal.current = false; Event.stopObserving(window,'resize',this.position,false); Event.stopObserving(window,'scroll',this.position,false); if(!this.options.hover){ if(this.options.overlayCloseOnClick && this.options.overlayDisplay) Control.Modal.overlay.stopObserving('click',Control.Modal.close); if(this.options.overlayDisplay){ if(this.options.fade){ if(Control.Modal.effects.overlayAppear) Control.Modal.effects.overlayAppear.cancel(); Control.Modal.effects.overlayFade = new Effect.Fade(Control.Modal.overlay,{ queue: { position: 'end', scope: 'Control.Modal' }, from: this.options.opacity, to: 0, duration: this.options.fadeDuration / 2 }); }else Control.Modal.overlay.hide(); } } if(this.options.fade){ if(Control.Modal.effects.containerAppear) Control.Modal.effects.containerAppear.cancel(); Control.Modal.effects.containerFade = new Effect.Fade(Control.Modal.container,{ queue: { position: 'front', scope: 'Control.Modal' }, from: 1, to: 0, duration: this.options.fadeDuration / 2, afterFinish: function(){ Control.Modal.container.update(''); this.resetClassNameAndStyles(); }.bind(this) }); }else{ Control.Modal.container.hide(); Control.Modal.container.update(''); this.resetClassNameAndStyles(); } if(this.options.position == 'mouse') this.element.stopObserving('mousemove',this.mouseHoverListener); this.notify('afterClose'); }, resetClassNameAndStyles: function(){ Control.Modal.overlay.removeClassName(this.options.overlayClassName); Control.Modal.container.removeClassName(this.options.containerClassName); Control.Modal.container.setStyle({ height: null, width: null, top: null, left: null }); }, notify: function(eventname){ try{ if(this.options[eventname]) return [this.options[eventname].apply(this.options[eventname],$A(arguments).slice(1))]; }catch(e){ if(e != $break) throw e; else return false; } } }); if(typeof(Object.Event) != 'undefined') Object.Event.extend(Control.Modal); Control.Modal.attachEvents();
Posted September 3rd, 2007 at 7:39am by Scorp1on
Hi Jeremy,
First of all, thank you very much for your efforts and great work. I will definetely use your code to my new project.
I have exactly the same problem and unfortunately I cannot see your solution code correctly on the last response.
I could workaround the problem by swapping input field styles but still, users are used to see the cursor where it should be.
Thanks
Tony
Posted September 3rd, 2007 at 6:50pm by tony
I did employ the absolute positioning fix too and it worked....because as of FF 2.0.0.6 this bug is NOT fixed. Here is how I implemented it:
clicking the button div also launches the modal window.
here is the javascript function I called fixAbsentCursor:
function fixAbsentCursor() { $('modal_overlay').style.position = 'absolute'; }
this worked out great for me.
Posted September 4th, 2007 at 10:40pm by kleetus
Firefox has a bug where form elements don't display the cursor when the form elements are overlapping certain divs with certain styles.
Sample here of missing cursor when focused:
The modal_overlay div has position: relative. If you change this to absolute with something like firebug (just as an example the cursor is again viewable)
This bug also exists with overflow styling and I think a couple others. This is a know bug against Firefox and something with how it renders the cursor.
Any good fixes for Control.Modal that we know of ?
thanks, jeremy
Posted August 8th, 2007 at 6:33pm by jocmaff