Skip to main content

Search and Top Navigation

#5694 closed bug (fixed)

Opened June 06, 2010 04:50PM UTC

Closed June 28, 2010 02:37AM UTC

Last modified November 19, 2010 06:25PM UTC

Invalid reference in UI Resizable hack for Opera

Reported by: jquery-dev Owned by:
Priority: critical Milestone: 1.8.3
Component: ui.resizable Version: 1.8.1
Keywords: Cc:
Blocked by: Blocking:
Description

There is an error in the resizable.alsoResize() method, in a section that is specific to Opera...

$.ui.plugin.add("resizable", "alsoResize", { 
    ... 
    stop: function(event, ui){ 
        var self = $(this).data("resizable"); 

        //Opera fixing relative position 
        if (self._revertToRelativePosition && $.browser.opera) { 
            self._revertToRelativePosition = false; 
            el.css({ position: 'relative' }); 
        }

        $(this).removeData("resizable-alsoresize-start"); 
    }

The reference 'el' does not exist, so Opera bombs out with...

Uncaught exception: ReferenceError: Undefined variable: el
    el.css({ position: 'relative' });

It ''seems'' this is because the code in this method was copied from the method above it, where el ''is'' defined within a loop:

resize: function(event, ui){
    ...
    _alsoResize = function(exp, c) {
        $(exp).each(function() {
            var el = $(this), ...;
            ...
            //Opera fixing relative position
            if (/relative/.test(el.css('position')) && $.browser.opera) {
                self._revertToRelativePosition = true;
                el.css({ position: 'absolute', top: 'auto', left: 'auto' });
            }

            el.css(style);
        });

In the stop() method, el cannot be assigned to $(this) because that is the outer dialog element and it is the dialog content-element that needs to be reset. So this hack works specifically for the dialog widget...

    var el = $(this).children(".ui-dialog-content");

But obviously this needs to be generic - targeting the same element(s) targeted in the resize method, because that is what it is supposed to 'undo'.

This error also existed in version 1.7.2. It has probably been missed for so long because it occurs only under these conditions:.

  • $.browser.opera = true, and
  • self._revertToRelativePosition = true

The revertToRelativePosition flag is set when the alsoResize target element has position=relative, which Opera ''temporarily'' changes to absolute.

Having a resizable element with position:relative is not unusual, and since resizable is used by many other widgets (I discovered it in Dialog), this represents a serious bug in Opera.

Attachments (0)
Change History (8)

Changed June 08, 2010 04:00PM UTC by jquery-dev comment:1

I resolved the bug above. In addition to fixing this ''and'' the other bug I reported (http://dev.jqueryui.com/ticket/5695), I also found the Opera hack logic incomplete. The previous code would 'reset' an element's position from absolute to relative even if it was ''originally'' absolute. Now each element's original position is save in start().

This revised code is a complete fix for all issues. I may also submit this directly to the repository, but am also posting it here to complete this ticket...

$.ui.plugin.add("resizable", "alsoResize", {

	start: function (event, ui) {
		var self = $(this).data("resizable"), o = self.options;

		var _store = function (exp) {
			$(exp).each(function() {
				var el = $(this);
				el.data("resizable-alsoresize", {
					width: parseInt(el.width(), 10), height: parseInt(el.height(), 10),
					left: parseInt(el.css('left'), 10), top: parseInt(el.css('top'), 10),
					position: el.css('position') // to reset Opera on stop()
				});
			});
		};

		if (typeof(o.alsoResize) == 'object' && !o.alsoResize.parentNode) {
			if (o.alsoResize.length) { o.alsoResize = o.alsoResize[0];	_store(o.alsoResize); }
			else { $.each(o.alsoResize, function (exp) { _store(exp); }); }
		}else{
			_store(o.alsoResize);
		}
	},

	resize: function (event, ui) {
		var self = $(this).data("resizable"), o = self.options, os = self.originalSize, op = self.originalPosition;

		var delta = {
			height: (self.size.height - os.height) || 0, width: (self.size.width - os.width) || 0,
			top: (self.position.top - op.top) || 0, left: (self.position.left - op.left) || 0
		},

		_alsoResize = function (exp, c) {
			$(exp).each(function() {
				var el = $(this), start = $(this).data("resizable-alsoresize"), style = {}, 
					css = c && c.length ? c : el.parents(ui.originalElement[0]).length ? ['width', 'height'] : ['width', 'height', 'top', 'left'];

				$.each(css, function (i, prop) {
					var sum = (start[prop]||0) + (delta[prop]||0);
					if (sum && sum >= 0)
						style[prop] = sum || null;
				});

				// Opera fixing relative position
				if ($.browser.opera && /relative/.test(el.css('position'))) {
					self._revertToRelativePosition = true;
					el.css({ position: 'absolute', top: 'auto', left: 'auto' });
				}

				el.css(style);
			});
		};

		if (typeof(o.alsoResize) == 'object' && !o.alsoResize.nodeType) {
			$.each(o.alsoResize, function (exp, c) { _alsoResize(exp, c); });
		}else{
			_alsoResize(o.alsoResize);
		}
	},

	stop: function (event, ui) {
		var self = $(this).data("resizable");

		_reset = function (exp) {
			$(exp).each(function() {
				var el = $(this);
				// reset position for Opera - no need to verify it was changed
				el.css({ position: el.data("resizable-alsoresize").position });
			});
		}

		if (self._revertToRelativePosition) {
			self._revertToRelativePosition = false;
			if (typeof(o.alsoResize) == 'object' && !o.alsoResize.nodeType) {
				$.each(o.alsoResize, function (exp) { _reset(exp); });
			}else{
				_reset(o.alsoResize);
			}
		}

		$(this).removeData("resizable-alsoresize");
	}
});

Changed June 09, 2010 09:54PM UTC by jquery-dev comment:2

Changed June 10, 2010 01:37AM UTC by scottgonzalez comment:3

milestone: TBD1.9
resolution: → fixed
status: newclosed

Fixed in a78d5ee.

Changed June 25, 2010 03:26PM UTC by eXtreme comment:4

resolution: fixed
status: closedreopened

Again, code (to stop function) was copied without checking. Opera returns an error in line:

if (typeof(o.alsoResize) == 'object' && !o.alsoResize.nodeType)

Of course because there is no "o" variable. That "stop" function misses "var o = self.options;"

Changed June 25, 2010 03:27PM UTC by eXtreme comment:5

Changed June 28, 2010 02:37AM UTC by scottgonzalez comment:6

resolution: → fixed
status: reopenedclosed

Fixed in 7d24c1a. Thanks eXtreme.

Changed August 04, 2010 01:18AM UTC by scottgonzalez comment:7

milestone: 1.91.8.3

Changed November 19, 2010 06:25PM UTC by eXtreme comment:8

Resizable: Adding missing variable initialization. Fixes #5694 - Invalid reference in UI Resizable hack for Opera.

Changeset: 7d24c1a57ffcfa461dc48f6024b33e548179c491