modalContent plugin is not modal

classic Classic list List threaded Threaded
11 messages Options
Reply | Threaded
Open this post in threaded view
|

modalContent plugin is not modal

Tim Saker
(From ticket #501: http://jquery.com/dev/bugs/bug/501/)

I've demonstrated this in IE 7 and FF 1.5. There are 2 issues that violate modality:

1) The page elements are still keyboard traversable. This is a big problem because users can invoke any of the controls that accept keyboard events by tabbing to them to obtain input focus.

2) If you are on a page that is taller than the viewport (requires vertical scrolling), the modal overlay does not extend to the bottom of the page - it only covers what's currently visible so that when you sroll down the rest of the page is uncovered and available for mouse events.
Reply | Threaded
Open this post in threaded view
|

Re: modalContent plugin is not modal

Tim Saker
I've actually completed a solution to these problems prior to this post.  The solution involves updates to both the modalContent plugin and it's dependency, dimensions.js.  I just need to finish polishing the changes to conform to the plugin guidelines.

Tim Saker wrote
(From ticket #501: http://jquery.com/dev/bugs/bug/501/)

I've demonstrated this in IE 7 and FF 1.5. There are 2 issues that violate modality:

1) The page elements are still keyboard traversable. This is a big problem because users can invoke any of the controls that accept keyboard events by tabbing to them to obtain input focus.

2) If you are on a page that is taller than the viewport (requires vertical scrolling), the modal overlay does not extend to the bottom of the page - it only covers what's currently visible so that when you sroll down the rest of the page is uncovered and available for mouse events.
Reply | Threaded
Open this post in threaded view
|

Re: modalContent plugin is not modal

Jörn Zaefferer
Tim Saker schrieb:
> I've actually completed a solution to these problems prior to this post.  The
> solution involves updates to both the modalContent plugin and it's
> dependency, dimensions.js.  I just need to finish polishing the changes to
> conform to the plugin guidelines.
>  
Just release 'em when they are polished enough :-)

--
Jörn Zaefferer

http://bassistance.de


_______________________________________________
jQuery mailing list
[hidden email]
http://jquery.com/discuss/
Reply | Threaded
Open this post in threaded view
|

Re: modalContent plugin is not modal

Tim Saker

Jörn Zaefferer wrote
Tim Saker schrieb:
> I've actually completed a solution to these problems prior to this post.  The
> solution involves updates to both the modalContent plugin and it's
> dependency, dimensions.js.  I just need to finish polishing the changes to
> conform to the plugin guidelines.
>  
Just release 'em when they are polished enough :-)

--
Jörn Zaefferer

http://bassistance.de


_______________________________________________
jQuery mailing list
discuss@jquery.com
http://jquery.com/discuss/
As things turned out I didn't make any changes to the dimensions.js dependency, although there _is_ one minor problem with obtaining a document's full height which could probably stand to be fixed.  I'll just address this in a separate post.

So, here is the modalContent plugin 0.9 enhanced for keyboard modality.  There are basically 3 changes from the original functionality:

  1) Keyboard events are now only permitted on visible elements belonging to the modal layer (child elements). Attempting to place focus on any other page element will cause focus to be transferred back to the first (ordinal) visible child element of the modal layer.

  2) The modal overlay shading now covers the entire height of the document except for a small band at the bottom, which is the height of a scrollbar (a separate thread to be opened on this problem with dimension.js).

  3) I removed the code that disables and reenables the scrollbars.  This is just a suggestion really, realizing it could be one of those little things that causes fellow developers to become unnecessary foes ;=).  Personally, I found it an annoying behaviour to remove a visible scrollbar causing the page elements to shift right upon modal popup, then back after closure. If the intent was to prevent scrolling it doesn't anyway since you can still page down with the keyboard. Maybe it should be a boolean option passed in the function signature?

Note that I'm just posting the changes here to solicit public awareness and input.  I will attempt to notify the original author, Gavin Roy, in hopes that the changes will make it into a next release.


jquery-modalContent-0.9.x.js
----------------------------------------
/**
 * modalContent jQuery Plugin
 *
 * @version   0.9.x
 * @since     2006-12-19
 * @copyright Copyright (c) 2006 Glyphix Studio, Inc. http://www.glyphix.com
 * @author    Gavin M. Roy <gmr@glyphix.com>
 * @license   MIT http://www.opensource.org/licenses/mit-license.php
 * @requires  >= jQuery 1.0.3 http://jquery.com/
 * @requires  dimensions.js http://jquery.com/dev/svn/trunk/plugins/dimensions/dimensions.js?format=raw
 *
 * Call modalContent() on a DOM object and it will make a centered modal box over a div overlay preventing access to the page.
 * Create an element (anchor/img/etc) with the class "close" in your content to close the modal box on click.
 */

/**
 * modalContent
 * @param content string to display in the content box
 * @param css obj of css attributes
 * @param animation (fade, slide, show)
 * @param speed (valid animation speeds slow, medium, fast or # in ms)
 */
jQuery.modalContent = function(content, css, animation, speed) {

  // if we already ahve a modalContent, remove it
  if ( $('#modalBackdrop') ) $('#modalBackdrop').remove();
  if ( $('#modalContent') ) $('#modalContent').remove();

  // position code lifted from http://www.quirksmode.org/viewport/compatibility.html
  if (self.pageYOffset) { // all except Explorer
  var wt = self.pageYOffset;
  } else if (document.documentElement && document.documentElement.scrollTop) { // Explorer 6 Strict
          var wt = document.documentElement.scrollTop;
  } else if (document.body) { // all other Explorers
          var wt = document.body.scrollTop;
  }

  // Get our dimensions
  var docHeight = $(document).outerHeight();
  var winHeight = $(window).height();
  var winWidth = $(window).innerWidth();
  if( docHeight < winHeight ) docHeight = winHeight;

  // Create our divs
  $('body').append('<div id="modalBackdrop" style="z-index: 1000; display: none;"></div><div id="modalContent" style="z-index: 1001; position: absolute;">' + $(content).html() + '</div>');

  // Keyboard and focus event handler ensures focus stays on modal elements only
  modalEventHandler = function( event ) {
    target = null;
    if( event ) { //Mozilla
        target = event.target;
    }
    else { //IE
        event = window.event;
        target = event.srcElement;
    }
    if( $(target).filter('*:visible').parents('#modalContent').size() ) {
      // allow the event only if target is a visible child node of #modalContent
      return true;
    }
    $('#modalContent .focus').get(0).focus();
    return false;
  }
  $('body').bind( 'focus', modalEventHandler );
  $('body').bind( 'keypress', modalEventHandler );

  // Create our content div, get the dimensions, and hide it
  var modalContent = $('#modalContent').top('-1000px');
  var mdcTop = wt + ( winHeight / 2 ) - (  modalContent.outerHeight() / 2);
  var mdcLeft = ( winWidth / 2 ) - ( modalContent.outerWidth() / 2);
  modalContent.hide();

  // Apply our css and positioning, then show
  if ( animation == 'fade' )
  {
    $('#modalBackdrop').top(wt).css(css).height(docHeight + 'px').width(winWidth + 'px').show();
     modalContent.top(mdcTop + 'px').left(mdcLeft + 'px').fadeIn(speed);
  } else {
    if ( animation == 'slide' )
    {
      $('#modalBackdrop').top(wt).css(css).height(docHeight + 'px').width(winWidth + 'px').show();
      modalContent.hide().top(mdcTop + 'px').left(mdcLeft + 'px').slideDown(speed);
    } else {
      if ( animation == 'show')
      {
        $('#modalBackdrop').top(wt).css(css).height(docHeight + 'px').width(winWidth + 'px').show();
        modalContent.top(mdcTop + 'px').left(mdcLeft + 'px').show();
      }
    }
  }

  // Bind a click for closing the modalContent
  $('#modalContent .close').click(function(){close(); return false});

  // Close the open modal content and backdrop
  function close() {
    $(window).unbind('resize');
    $('body').unbind( 'focus', modalEventHandler );
    $('body').unbind( 'keypress', modalEventHandler );

    if ( animation == 'fade' ) {
      $('#modalContent').fadeOut(speed,function(){$('#modalBackdrop').fadeOut(speed, function(){$(this).remove();});$(this).remove();});
    } else {
      if ( animation == 'slide' ) {
        $('#modalContent').slideUp(speed,function(){$('#modalBackdrop').slideUp(speed, function(){$(this).remove();});$(this).remove();});
      } else {
        $('#modalContent').remove();$('#modalBackdrop').remove();
      }
    }
  };

  // Move and resize the modalBackdrop and modalContent on resize of the window
  $(window).resize(function(){
    // Get our heights
    var docHeight = $(document).outerHeight();
    var winHeight = $(window).height();
    var winWidth = $(window).width();
    if( docHeight < winHeight ) docHeight = winHeight;

    // Get where we should move content to
    var modalContent = $('#modalContent');
    var mdcTop = ( winHeight / 2 ) - (  modalContent.outerHeight() / 2);
    var mdcLeft = ( winWidth / 2 ) - ( modalContent.outerWidth() / 2);

    // Apply the changes
    $('#modalBackdrop').height(docHeight + 'px').width(winWidth + 'px').show();
    modalContent.top(mdcTop + 'px').left(mdcLeft + 'px').show();
  });

  $('#modalContent .focus').focus();
};

/**
 * jQuery function init
 */
jQuery.fn.modalContent = function(css, animation, speed)
{
  // If our animation isn't set, make it just show/pop
  if (!animation) { var animation = 'show'; } else {
    // If our animation isn't "fade" then it always is show
    if ( ( animation != 'fade' ) && ( animation != 'slide') ) animation = 'show';
  }
  if ( !speed ) var speed = 'fast';

  // Build our base attributes and allow them to be overriden
  css = jQuery.extend({
    position: 'absolute',
    left: '0px',
    margin: '0px',
    background: '#000',
    opacity: '.55'
  }, css);

  // jQuery mojo
  this.each(function(){
    $(this).hide();
    new jQuery.modalContent($(this), css, animation, speed);
  });

  // return this object
  return this;
};

/**
 * unmodalContent
 * @param animation (fade, slide, show)
 * @param speed (valid animation speeds slow, medium, fast or # in ms)
 */
jQuery.fn.unmodalContent = function(animation, speed)
{
  // If our animation isn't set, make it just show/pop
  if (!animation) { var animation = 'show'; } else {
    // If our animation isn't "fade" then it always is show
    if ( ( animation != 'fade' ) && ( animation != 'slide') ) animation = 'show';
  }
  // Set a speed if we dont have one
  if ( !speed ) var speed = 'fast';

  // Unbind the resize we bound
  $(window).unbind('resize');
  $('body').unbind( 'focus', modalEventHandler );
  $('body').unbind( 'keypress', modalEventHandler );

  // jQuery magic loop through the instances and run the animations or removal.
  this.each(function(){
    if ( animation == 'fade' ) {
      $('#modalContent').fadeOut(speed,function(){$('#modalBackdrop').fadeOut(speed, function(){$(this).remove();});$(this).remove();});
    } else {
      if ( animation == 'slide' ) {
        $('#modalContent').slideUp(speed,function(){$('#modalBackdrop').slideUp(speed, function(){$(this).remove();});$(this).remove();});
      } else {
        $('#modalContent').remove();$('#modalBackdrop').remove();
      }
    }
  });
};
Reply | Threaded
Open this post in threaded view
|

Re: modalContent plugin is not modal

Jörn Zaefferer

> Note that I'm just posting the changes here to solicit public awareness and
> input.  I will attempt to notify the original author, Gavin Roy, in hopes
> that the changes will make it into a next release.
>  
I'd really prefer that. But the same I get find a need for the plugin,
the mail would be long lost and forgotten.

--
Jörn Zaefferer

http://bassistance.de


_______________________________________________
jQuery mailing list
[hidden email]
http://jquery.com/discuss/
Reply | Threaded
Open this post in threaded view
|

Re: modalContent plugin is not modal

Tim Saker
UPDATE: Gavin has reponded to me by email, privately.  We should see a new release of the ModalContent plugin before long.

Jörn Zaefferer wrote
> Note that I'm just posting the changes here to solicit public awareness and
> input.  I will attempt to notify the original author, Gavin Roy, in hopes
> that the changes will make it into a next release.
>  
I'd really prefer that. But the same I get find a need for the plugin,
the mail would be long lost and forgotten.

--
Jörn Zaefferer

http://bassistance.de


_______________________________________________
jQuery mailing list
discuss@jquery.com
http://jquery.com/discuss/
Reply | Threaded
Open this post in threaded view
|

Re: modalContent plugin is not modal

malsup
> UPDATE: Gavin has reponded to me by email, privately.  We should see a new
> release of the ModalContent plugin before long.

Cool.  Thanks, Tim.  Did you test the event handling with Opera?  I'm
working on something similar and I'm having trouble squashing events
(like TAB, arrow keys) in Opera.  Anyone know the secret?

Mike

_______________________________________________
jQuery mailing list
[hidden email]
http://jquery.com/discuss/
Reply | Threaded
Open this post in threaded view
|

Re: modalContent plugin is not modal

Klaus Hartl
Mike Alsup schrieb:
>> UPDATE: Gavin has reponded to me by email, privately.  We should see a new
>> release of the ModalContent plugin before long.
>
> Cool.  Thanks, Tim.  Did you test the event handling with Opera?  I'm
> working on something similar and I'm having trouble squashing events
> (like TAB, arrow keys) in Opera.  Anyone know the secret?
>
> Mike

Mike, in which events are you trying to intercept these keys? I found a
few inconsistencies regarding this.

For tab and return for example I had to use keypress to make it work in
Opera. See the autocomplete ("Where") here: http://plazes.com/plazes/


-- Klaus

_______________________________________________
jQuery mailing list
[hidden email]
http://jquery.com/discuss/
Reply | Threaded
Open this post in threaded view
|

Re: modalContent plugin is not modal

AHeimlich
Also on the subject of intercepting keys in Opera:

http://www.opera.com/support/tutorials/nomouse/index.dml#nav


On 12/20/06, Klaus Hartl <[hidden email]> wrote:
Mike Alsup schrieb:
>> UPDATE: Gavin has reponded to me by email, privately.  We should see a new
>> release of the ModalContent plugin before long.
>
> Cool.  Thanks, Tim.  Did you test the event handling with Opera?  I'm
> working on something similar and I'm having trouble squashing events
> (like TAB, arrow keys) in Opera.  Anyone know the secret?
>
> Mike

Mike, in which events are you trying to intercept these keys? I found a
few inconsistencies regarding this.

For tab and return for example I had to use keypress to make it work in
Opera. See the autocomplete ("Where") here: <a href="http://plazes.com/plazes/" target="_blank" onclick="return top.js.OpenExtLink(window,event,this)"> http://plazes.com/plazes/


-- Klaus

_______________________________________________
jQuery mailing list
[hidden email]
<a href="http://jquery.com/discuss/" target="_blank" onclick="return top.js.OpenExtLink(window,event,this)">http://jquery.com/discuss/



--
Aaron Heimlich
Web Developer
[hidden email]
<a href="http://aheimlich.freepgs.com" target="_blank" onclick="return top.js.OpenExtLink(window,event,this)">http://aheimlich.freepgs.com
_______________________________________________
jQuery mailing list
[hidden email]
http://jquery.com/discuss/
Reply | Threaded
Open this post in threaded view
|

Re: modalContent plugin is not modal

malsup
In reply to this post by Klaus Hartl
> Mike, in which events are you trying to intercept these keys? I found a
> few inconsistencies regarding this.

Hi Klaus,

Just for testing I setup a handler to reject all keypress/keydown
events like this:

var f = function() { return false; };
$().bind('keypress', f).bind('keydown', f);

In Opera, it sort of works.  I can't type into input fields but I can
still TAB around and I can use arrow keys on select controls.  I can
even delete text from an input control.  I tried stopPropagation on
the event too w/o success.  In IE and FF the key events are snuffed as
expected.

Mike

_______________________________________________
jQuery mailing list
[hidden email]
http://jquery.com/discuss/
Reply | Threaded
Open this post in threaded view
|

Re: modalContent plugin is not modal

Tim Saker
In reply to this post by malsup
Sorry, I did not test outside of FF and IE.

malsup wrote
> UPDATE: Gavin has reponded to me by email, privately.  We should see a new
> release of the ModalContent plugin before long.

Cool.  Thanks, Tim.  Did you test the event handling with Opera?  I'm
working on something similar and I'm having trouble squashing events
(like TAB, arrow keys) in Opera.  Anyone know the secret?

Mike

_______________________________________________
jQuery mailing list
discuss@jquery.com
http://jquery.com/discuss/