countdown.js revision 5c02ac1a9c1b504631c0a3d2b6e737b5d738bae1
15c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu// Copyright 2014 The Chromium Authors. All rights reserved. 25c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu// Use of this source code is governed by a BSD-style license that can be 35c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu// found in the LICENSE file. 45c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 55c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu/** 65c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * @fileoverview Provides a countdown-based timer. 75c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * @author juanlang@google.com (Juan Lang) 85c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu */ 95c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu'use strict'; 105c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 115c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu/** 125c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * A countdown timer. 135c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * @interface 145c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu */ 155c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liufunction Countdown() {} 165c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 175c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu/** 185c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * Sets a new timeout for this timer. 195c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * @param {number} timeoutMillis how long, in milliseconds, the countdown lasts. 205c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * @param {Function=} cb called back when the countdown expires. 215c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * @return {boolean} whether the timeout could be set. 225c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu */ 235c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo LiuCountdown.prototype.setTimeout = function(timeoutMillis, cb) {}; 245c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 255c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu/** Clears this timer's timeout. */ 265c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo LiuCountdown.prototype.clearTimeout = function() {}; 275c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 285c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu/** 295c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * @return {number} how many milliseconds are remaining until the timer expires. 305c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu */ 315c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo LiuCountdown.prototype.millisecondsUntilExpired = function() {}; 325c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 335c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu/** @return {boolean} whether the timer has expired. */ 345c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo LiuCountdown.prototype.expired = function() {}; 355c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 365c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu/** 375c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * Constructs a new clone of this timer, while overriding its callback. 385c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * @param {Function=} cb callback for new timer. 395c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * @return {!Countdown} new clone. 405c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu */ 415c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo LiuCountdown.prototype.clone = function(cb) {}; 425c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 435c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu/** 445c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * Constructs a new timer. The timer has a very limited resolution, and does 455c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * not attempt to be millisecond accurate. Its intended use is as a 465c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * low-precision timer that pauses while debugging. 475c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * @param {number=} timeoutMillis how long, in milliseconds, the countdown 485c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * lasts. 495c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * @param {Function=} cb called back when the countdown expires. 505c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * @constructor 515c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * @implements {Countdown} 525c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu */ 535c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liufunction CountdownTimer(timeoutMillis, cb) { 545c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu this.remainingMillis = 0; 555c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu this.setTimeout(timeoutMillis || 0, cb); 565c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu} 575c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 585c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo LiuCountdownTimer.TIMER_INTERVAL_MILLIS = 200; 595c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 605c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu/** 615c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * Sets a new timeout for this timer. Only possible if the timer is not 625c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * currently active. 635c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * @param {number} timeoutMillis how long, in milliseconds, the countdown lasts. 645c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * @param {Function=} cb called back when the countdown expires. 655c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * @return {boolean} whether the timeout could be set. 665c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu */ 675c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo LiuCountdownTimer.prototype.setTimeout = function(timeoutMillis, cb) { 685c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu if (this.timeoutId) 695c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu return false; 705c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu if (!timeoutMillis || timeoutMillis < 0) 715c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu return false; 725c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu this.remainingMillis = timeoutMillis; 735c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu this.cb = cb; 745c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu if (this.remainingMillis > CountdownTimer.TIMER_INTERVAL_MILLIS) { 755c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu this.timeoutId = 765c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu window.setInterval(this.timerTick.bind(this), 775c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu CountdownTimer.TIMER_INTERVAL_MILLIS); 785c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu } else { 795c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu // Set a one-shot timer for the last interval. 805c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu this.timeoutId = 815c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu window.setTimeout(this.timerTick.bind(this), this.remainingMillis); 825c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu } 835c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu return true; 845c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu}; 855c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 865c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu/** Clears this timer's timeout. */ 875c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo LiuCountdownTimer.prototype.clearTimeout = function() { 885c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu if (this.timeoutId) { 895c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu window.clearTimeout(this.timeoutId); 905c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu this.timeoutId = undefined; 915c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu } 925c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu}; 935c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 945c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu/** 955c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * @return {number} how many milliseconds are remaining until the timer expires. 965c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu */ 975c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo LiuCountdownTimer.prototype.millisecondsUntilExpired = function() { 985c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu return this.remainingMillis > 0 ? this.remainingMillis : 0; 995c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu}; 1005c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 1015c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu/** @return {boolean} whether the timer has expired. */ 1025c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo LiuCountdownTimer.prototype.expired = function() { 1035c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu return this.remainingMillis <= 0; 1045c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu}; 1055c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 1065c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu/** 1075c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * Constructs a new clone of this timer, while overriding its callback. 1085c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * @param {Function=} cb callback for new timer. 1095c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * @return {!Countdown} new clone. 1105c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu */ 1115c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo LiuCountdownTimer.prototype.clone = function(cb) { 1125c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu return new CountdownTimer(this.remainingMillis, cb); 1135c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu}; 1145c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 1155c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu/** Timer callback. */ 1165c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo LiuCountdownTimer.prototype.timerTick = function() { 1175c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu this.remainingMillis -= CountdownTimer.TIMER_INTERVAL_MILLIS; 1185c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu if (this.expired()) { 1195c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu window.clearTimeout(this.timeoutId); 1205c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu this.timeoutId = undefined; 1215c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu if (this.cb) { 1225c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu this.cb(); 1235c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu } 1245c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu } 1255c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu}; 126