Link to home
Start Free TrialLog in
Avatar of naryan109
naryan109Flag for United Kingdom of Great Britain and Northern Ireland

asked on

Script looping when no element is present on page

In this script towards the bottom is the 'blink' function.  The problem with it is that if the element with id 'blink' is not on the page (which it won't be until user add item to basket) then the script keeps looping ad infinitum whilst it looks for the element.  How could I modify the code so that it gives up after one loop if the element's not there?


var floatingMenu =
{
    hasInner: typeof(window.innerWidth) == 'number',
    hasElement: typeof(document.documentElement) == 'object'
        && typeof(document.documentElement.clientWidth) == 'number'
};

var floatingArray =
[
];

floatingMenu.add = function(obj, options)
{
    var name;
    var menu;

    if (typeof(obj) === "string")
        name = obj;
    else
        menu = obj;
        

    if (options == undefined)
    {
        floatingArray.push( 
            {
                id: name,
                menu: menu,

                targetLeft: 0,
                targetTop: 0,

                snap: true
            });
    }
    else
    {
        floatingArray.push( 
            {
                id: name,
                menu: menu,

                targetLeft: options.targetLeft,
                targetRight: options.targetRight,
                targetTop: options.targetTop,
                targetBottom: options.targetBottom,

                centerX: options.centerX,
                centerY: options.centerY,

                prohibitXMovement: options.prohibitXMovement,
                prohibitYMovement: options.prohibitYMovement,

                snap: options.snap,
                ignoreParentDimensions: options.ignoreParentDimensions,

                scrollContainer: options.scrollContainer,
                scrollContainerId: options.scrollContainerId
            });
    }
};

floatingMenu.findSingle = function(item)
{
    if (item.id)
        item.menu = document.getElementById(item.id);

    if (item.scrollContainerId)
        item.scrollContainer = document.getElementById(item.scrollContainerId);
};

floatingMenu.move = function (item)
{
    if (!item.prohibitXMovement)
    {
        item.menu.style.left = item.nextX + 'px';
        item.menu.style.right = '';
    }

    if (!item.prohibitYMovement)
    {
        item.menu.style.top = item.nextY + 'px';
        item.menu.style.bottom = '';
    }
};

floatingMenu.scrollLeft = function(item)
{
    if (item.scrollContainer)
        return item.scrollContainer.scrollLeft;

    var w = window;

    // Find top window scroll parameters if we're IFRAMEd
    while (w != w.parent)
        w = w.parent;

    return this.hasInner
        ? w.pageXOffset  
        : this.hasElement  
          ? w.document.documentElement.scrollLeft  
          : w.document.body.scrollLeft;
};

floatingMenu.scrollTop = function(item)
{
    if (item.scrollContainer)
        return item.scrollContainer.scrollTop;

    var w = window;

    // Find top window scroll parameters if we're IFRAMEd
    while (w != w.parent)
        w = w.parent;

    return this.hasInner
        ? w.pageYOffset
        : this.hasElement
          ? w.document.documentElement.scrollTop
          : w.document.body.scrollTop;
};

floatingMenu.windowWidth = function()
{
    return this.hasElement
        ? document.documentElement.clientWidth
        : document.body.clientWidth;
};

floatingMenu.windowHeight = function()
{
    if (floatingMenu.hasElement && floatingMenu.hasInner)
    {
        // Handle Opera 8 problems
        return document.documentElement.clientHeight > window.innerHeight
            ? window.innerHeight
            : document.documentElement.clientHeight
    }
    else
    {
        return floatingMenu.hasElement
            ? document.documentElement.clientHeight
            : document.body.clientHeight;
    }
};

floatingMenu.documentHeight = function()
{
    var innerHeight = this.hasInner
        ? window.innerHeight
        : 0;

    var body = document.body,
        html = document.documentElement;

    return Math.max(
        body.scrollHeight,
        body.offsetHeight, 
        html.clientHeight,
        html.scrollHeight,
        html.offsetHeight,
        innerHeight);
};

floatingMenu.documentWidth = function()
{
    var innerWidth = this.hasInner
        ? window.innerWidth
        : 0;

    var body = document.body,
        html = document.documentElement;

    return Math.max(
        body.scrollWidth,
        body.offsetWidth, 
        html.clientWidth,
        html.scrollWidth,
        html.offsetWidth,
        innerWidth);
};

floatingMenu.calculateCornerX = function(item)
{
    var offsetWidth = item.menu.offsetWidth;

    if (item.centerX)
        return this.scrollLeft(item) + (this.windowWidth() - offsetWidth)/2;

    var result = this.scrollLeft(item) - item.parentLeft;
    if (item.targetLeft == undefined)
    {
        result += this.windowWidth() - item.targetRight - offsetWidth;
    }
    else
    {
        result += item.targetLeft;
    }
        
    if (document.body != item.menu.parentNode
        && result + offsetWidth >= item.confinedWidthReserve)
    {
        result = item.confinedWidthReserve - offsetWidth;
    }

    if (result < 0)
        result = 0;

    return result;
};

floatingMenu.calculateCornerY = function(item)
{
    var offsetHeight = item.menu.offsetHeight;

    if (item.centerY)
        return this.scrollTop(item) + (this.windowHeight() - offsetHeight)/2;

    var result = this.scrollTop(item) - item.parentTop;
    if (item.targetTop === undefined)
    {
        result += this.windowHeight() - item.targetBottom - offsetHeight;
    }
    else
    {
        result += item.targetTop;
    }

    if (document.body != item.menu.parentNode
        && result + offsetHeight >= item.confinedHeightReserve)
    {
        result = item.confinedHeightReserve - offsetHeight;
    }

    if (result < 0)
        result = 0;
        
    return result;
};

floatingMenu.computeParent = function(item)
{
    if (item.ignoreParentDimensions)
    {
        item.confinedHeightReserve = this.documentHeight();
        item.confinedWidthReserver = this.documentWidth();
        item.parentLeft = 0;  
        item.parentTop = 0;  
        return;
    }

    var parentNode = item.menu.parentNode;
    var parentOffsets = this.offsets(parentNode, item);
    item.parentLeft = parentOffsets.left;
    item.parentTop = parentOffsets.top;

    item.confinedWidthReserve = parentNode.clientWidth;

    // We could have absolutely-positioned DIV wrapped
    // inside relatively-positioned. Then parent might not
    // have any height. Try to find parent that has
    // and try to find whats left of its height for us.
    var obj = parentNode;
    while (obj.clientHeight < item.menu.offsetHeight)
    {
        obj = obj.parentNode;
    }

    var hasHeightOffsets = this.offsets(obj, item);

    item.confinedHeightReserve = obj.clientHeight
        - (parentOffsets.top - hasHeightOffsets.top);
};

floatingMenu.offsets = function(obj, item)
{
    var result =
    {
        left: 0,
        top: 0
    };

    if (obj === item.scrollContainer)
        return;

    while (obj.offsetParent && obj.offsetParent != item.scrollContainer)
    {  
        result.left += obj.offsetLeft;  
        result.top += obj.offsetTop;  
        obj = obj.offsetParent;
    }  

    if (window == window.parent)
        return result;

    // we're IFRAMEd
    var iframes = window.parent.document.body.getElementsByTagName("IFRAME");
    for (var i = 0; i < iframes.length; i++)
    {
        if (iframes[i].contentWindow != window)
           continue;

        obj = iframes[i];
        while (obj.offsetParent)  
        {  
            result.left += obj.offsetLeft;  
            result.top += obj.offsetTop;  
            obj = obj.offsetParent;
        }  
    }

    return result;
};

floatingMenu.doFloatSingle = function(item)
{
    this.findSingle(item);

    var stepX, stepY;

    this.computeParent(item);

    var cornerX = this.calculateCornerX(item);

    var stepX = (cornerX - item.nextX) * .07;
    if (Math.abs(stepX) < .5 && item.snap
        || Math.abs(cornerX - item.nextX) == 1)
    {
        stepX = cornerX - item.nextX;
    }

    var cornerY = this.calculateCornerY(item);

    var stepY = (cornerY - item.nextY) * .07;
    if (Math.abs(stepY) < .5 && item.snap
        || Math.abs(cornerY - item.nextY) == 1)
    {
        stepY = cornerY - item.nextY;
    }

    if (Math.abs(stepX) > 0 ||
        Math.abs(stepY) > 0)
    {
        item.nextX += stepX;
        item.nextY += stepY;
        this.move(item);
    }
};

floatingMenu.fixTargets = function()
{
};

floatingMenu.fixTarget = function(item)
{
};

floatingMenu.doFloat = function()
{
    this.fixTargets();
    for (var i=0; i < floatingArray.length; i++)
    {
        this.fixTarget(floatingArray[i]);
        this.doFloatSingle(floatingArray[i]);
    }
    setTimeout('floatingMenu.doFloat()', 20);
};


floatingMenu.insertEvent = function(element, listener, handler)
{
    var oldHandler = element[listener];
    element[listener] = function (e)
        {
            e = (e) ? e : window.event;
            var result = handler(e);
            return (oldHandler != undefined) 
                && (oldHandler(e) == true)
                && (result == true);
        };
};

floatingMenu.init = function()
{
    floatingMenu.fixTargets();

    for (var i=0; i < floatingArray.length; i++)
    {
        floatingMenu.initSingleMenu(floatingArray[i]);
    }

    setTimeout('floatingMenu.doFloat()', 100);
    timer = setInterval('blink()', 200);            // activate blink function
};

var i = 1,timer;
function blink() {
 if (i<10) {
        if (i%2 == 0) { 
              document.getElementById('blink').style.backgroundColor = '#D9789F';
         } else {
              document.getElementById('blink').style.backgroundColor = '#FFFFFF';
         }
 } else {
      document.getElementById('blink').style.backgroundColor = '#FFFFFF';
      clearInterval(timer);
  }
 i++;
}


// Some browsers init scrollbars only after
// full document load.
floatingMenu.initSingleMenu = function(item)
{
    this.findSingle(item);
    this.computeParent(item);
    this.fixTarget(item);
    item.nextX = this.calculateCornerX(item);
    item.nextY = this.calculateCornerY(item);
    this.move(item);
};

floatingMenu.insertEvent(window, 'onload', floatingMenu.init);

Open in new window

Avatar of sjklein42
sjklein42
Flag of United States of America image

I think that what is happening is that the execution of Blink is aborted by the error triggered by the missing ID, and the i++ is not executed.

My quick and dirty solution is to move the i++ to the beginning of the function, so it is done even if the ID is missing.

Change the initial value for i to zero to make up for the changed order.

var i = 0,timer;
function blink() {
 i++;
 if (i<10) {
        if (i%2 == 0) { 
              document.getElementById('blink').style.backgroundColor = '#D9789F';
         } else {
              document.getElementById('blink').style.backgroundColor = '#FFFFFF';
         }
 } else {
      document.getElementById('blink').style.backgroundColor = '#FFFFFF';
      clearInterval(timer);
  }
}

Open in new window

Avatar of naryan109

ASKER

I've tried it, but unfortunately it doesn't seem of fixed the problem - the line of code below keeps repeating endlessly.

 
document.getElementById('blink').style.backgroundColor = '#FFFFFF';

Open in new window

Try moving the definition of the timer variable several lines up, to before you first refer to it, at least before line 383.

If that doesn't help, put an "alert(i)" right before the repeating 'blink' line so we can see why it isn't properly incrementing and controlling the loop.
I've just moved the line: "var i = 0,timer;" to line 382.  The same problem occurred so I put the alert in as below.  The dialogues demonstrate that "i" is incrementing as each dialogue has the next incrementing number.

function blink() {
 i++;
 if (i<0) {
        if (i%2 == 0) { 
              document.getElementById('blink').style.backgroundColor = '#D9789F';
         } else {

			  document.getElementById('blink').style.backgroundColor = '#FFFFFF';
         }
 } else {
		alert(i)
		document.getElementById('blink').style.backgroundColor = '#FFFFFF';
      clearInterval(timer);
  }
}

Open in new window

Moving "i++" to earlier in the script also stopped the script from working, so I've moved it back for now.
You are incrementing i, but checking it against zero on line 3!  So it will always be greater than zero!

What happened to this code?  You changed the 10 to zero!

 if (i<10) {

Open in new window

That was a mistake.  I realised what I had done and changed it back.  The script is thus now:

var i = 0,timer;
function blink() {
 if (i<10) {
        if (i%2 == 0) { 
              document.getElementById('blink').style.backgroundColor = '#D9789F';
         } else {
              document.getElementById('blink').style.backgroundColor = '#FFFFFF';
         }
 } else {
	  document.getElementById('blink').style.backgroundColor = '#FFFFFF';
      clearInterval(timer);
  }
   i++;
}

Open in new window

ASKER CERTIFIED SOLUTION
Avatar of sjklein42
sjklein42
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Of course.  That makes sense and indeed it works.  Thank you for your help!  I'm learning javascript so this has been useful, thanks.