[RESOLVED] Timer countdown function alteration

Discussion in 'Scripts, 3rd Party Apps, and Programming' started by olliepop, Sep 25, 2010.

Thread Status:
Not open for further replies.
  1. olliepop

    olliepop Member

    Messages:
    138
    Likes Received:
    0
    Trophy Points:
    16
    Hey everyone - the function discussed in this thread is at the bottom of this post.

    What this function does is countdown the value of an HTML table-cell to zero (minus 1 every second) then stop counting that specific cell when it's finished. This works perfectly, the problem is that when it is called AGAIN for a different table-cell, the previous cell starts reducing its value by 2 every second instead of 1. This function supports the Hour:Minute:Second format.

    So, how would i make this function so that i can call an infinite number of different table cells, and the previous table cells timers would not be affected (they would still countdown 1 per second as they should)?


    Thank you so much. I have been stuck on this problem for 2 weeks and just left my project dormant because of it. This simple problem has struck me from behind and destroyed my passion for the project - please help me get back on track!

    -Ollie



    This is the code which CALLS the function, where $i is 1-5 inclusive, defined by PHP:
    Code:
    timer('ff".$i."', ". rand(1,100) .");
    This is the BODY of the function itself, called by the above command
    Code:
    var running = new Array(50);
    function timer(data, id)
    {
        //clearTimeout(id[data]);
        var id=new Array(50);
        // usage: var id=new Array(50); timer('cq0');
        dat=document.getElementById(data);
        var time=(dat.innerHTML).split(":"); 
        var done=0;
        if(dat.innerHTML == null) {
            done = 1;
            alert('null');
        }
        if (time[2]>0) time[2]--;
        else
        {
            time[2]=59;
            if (time[1]>0) time[1]--;
            else
            {
                time[1]=59;
                if (time[0]>0) time[0]--;
                else { 
                clearTimeout(id[data]); 
                done=1;
                running[data] = 0;
                renderStack();
                }
                
            }
            
        }
        if (!done)
        {
            dat.innerHTML=time[0]+":"+time[1]+":"+time[2];
            id[data]=setTimeout("timer('"+data+"')", 1000);
            running[data] = 1;
        }
    }
    


    ---------- Post added at 08:13 AM ---------- Previous post was at 04:10 AM ----------

    Resolved!
     
    Last edited: Sep 25, 2010
  2. misson

    misson Community Paragon Community Support

    Messages:
    2,572
    Likes Received:
    72
    Trophy Points:
    48
    On an unrelated note, I notice you're ending the double quoted string to concatenate $i. You can interpolate variables directly into double quoted and heredoc strings. The PHP code can thus be made more readable:

    PHP:
    "...
    timer('ff
    $i', " rand(1,100) . ");
    ..."
    Or even:
    PHP:
    $r rand(1,100);
    # or however the JS code is output
    echo <<<EOS
    ...
    timer('ff
    $i', $r);
    ...
    EOS;
    You can make the JS slightly more efficient by using setInterval rather than setTimeout and by using anonymous functions and closures rather than strings containing JS code.
    Code:
    // 'map' is used for added functionality: display countdown timer fields
    Array.prototype.map = function(f) {
        var arr = [];
        for (var i=0; i<this.length; ++i) {
            arr[i] = f(this[i]);
        }
    }
    
    var running = [];
    /* timer: Start counting down time. When done, render the stack (?) and (optionally) invoke an arbitrary function.
     * Arguments:
     * - data: HTML element or element ID. Contains countdown clock.
     * - onDone (optional): function to invoke when countdown finishes.
     */
    function timer(data, onDone) {
        var countdownIval, time, done;
        if (typeof data == 'string') {
            data=document.getElementById(data);
        }
        /* decrTime: Decrement time.
         * Returns 'true' if time is out, 'false' otherwise
         */
        function decrTime() {
            if (time[2]>0) time[2]--;
            else {
                time[2]=59;
                if (time[1]>0) time[1]--;
                else {
                    time[1]=59;
                    if (time[0]>0) time[0]--;
                    else { 
                        return true;
                    }
                }
            }
            return false;
        }
        /* countdown: Count down display 1 second. Self canceling when timer reaches 0,
         *   at which point optional done handler is invoked and stack is rendered.
         * Returns 'true' if not yet done.
         */
        function countdown() {
            done=decrTime();
            data.innerHTML=time.map(function(n) {if (n<10) return '0'+n; return n;}).join(':');
            if (done) {
                clearInterval(countdownIval);
                running[data.id] = 0;
                onDone();
                renderStack();
                return false;
            }
            return true;
        }
        if (data.innerHTML == null) {
            if (console) {
                console.log("countdown "+data.id+"'s content is unexpectedly null.");
            }
        } else {
            time=data.innerHTML.split(":");
            running[data.id] = 1;
            if (countdown()) {
                countdownIval = setInterval(countdown, 1000);
            }
        }
    }
    Or with simpler decrementing:
    Code:
    var running = [];
    /* timer: Start counting down time. When done, render the stack (?) and (optionally) invoke an arbitrary function.
     * Arguments:
     * - data: HTML element or element ID. Contains countdown clock.
     * - onDone (optional): function to invoke when countdown finishes.
     */
    function timer(data, onDone) {
        var countdownIval, time, done;
        if (typeof data == 'string') {
            data=document.getElementById(data);
        }
        /* s2hms: Convert seconds to hours, minutes, seconds.
         * Arguments:
         * - secs: integer representing seconds.
         * Returns string formatted as HH:MM:SS.
         */
        function s2hms(secs) {
            return [secs/3600 , (secs / 60) % 60, secs % 60].map(function(n) {if (n<10) return '0'+n; return n;}).join(':');
        }
        /* countdown: Count down display 1 second. Self canceling when timer reaches 0,
         *   at which point optional done handler is invoked and stack is rendered.
         * Returns 'true' if not yet done.
         */
        function countdown() {
            if (time > 0) {
                --time;
            }
            data.innerHTML=s2hms(time);
            if (time == 0) {
                clearInterval(countdownIval);
                running[data.id] = 0;
                onDone();
                renderStack();
                return false;
            }
            return true;
        }
        if (data.innerHTML == null) {
            if (console) {
                console.log("countdown "+data.id+"'s content is unexpectedly null.");
            }
        } else {
            time = data.innerHTML.split(":");
            time = ((time[0] * 60) + time[1]) * 60 + time[2];
            running[data.id] = 1;
            if (countdown()) {
                countdownIval = setInterval(countdown, 1000);
            }
        }
    }
    Both still need a little more error handling to cover cases where the 'data' element doesn't contain a properly formatted time string, and could potentially use an optional 'time' argument so the 'data' element doesn't need to hold a time string.
     
Thread Status:
Not open for further replies.

Share This Page