Count Down/Up

The app’s HTML code

The following app does the following:

  1. reads the app’s configuration and applies the required CSS for background color, font color, font family, font style, font-weight
  2. resizes text to fit the available window
  3. gets and displays time every second

We also include a “js” folder with the jQuery library for easier HTML DOM manipulation.

Count Down/Up index.htmlExpand source

<!DOCTYPE html>
<html>
<head>
<title>Countdown Clock</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<style type="text/css">
html, body {
	background-color: transparent;
	font-family: tahoma;
	font-size: 90%;
	height: 100%;
	width: 100%;
}

* {
	margin: 0;
	padding: 0;
}


#countbox1 {
	height: 100%;
	text-align: center;
	white-space: nowrap;
}


</style>
<script src="js/jquery.min.js"></script>
<script src="js/moment.min.js"></script>
<script src="js/moment-timezone-with-data.min.js"></script>

<script language="javascript" type="text/javascript">
	
	

    /*function that starts the clock*/
	function countdown() {
    	
		var now = moment().tz(window.widget_timezone);
		var timeToCompare = null;
		
		if(now < window.event_end){
			timeToCompare = window.event_end
		}	
		
        if(timeToCompare){
            timeDiff = timeToCompare - now

            var d="",h="",m="",s="";

            var amount = Math.floor(timeDiff/1000);//kill the "milliseconds" so just secs
            d=Math.floor(amount/86400);//days
            amount=amount%86400;
            h=Math.floor(amount/3600);//hours
            amount=amount%3600;
            m=Math.floor(amount/60);//minutes
            amount=amount%60;
            s=Math.floor(amount);//seconds

            s = checkTime(s);
            m = checkTime(m);
            h = checkTime(h);

            if(d != 0){
                $('#countbox1>span').text(d + "d " + h + ":" + m + ":" + s);
                if (!window.days){                
                    $('#countbox1').textfill({
                        maxFontPixels : $('#countbox1').height()
                    })
                    window.days = true
                }
            }
            else if(h != 0){
                $('#countbox1>span').text(h + ":" + m + ":" + s);
                if (!window.hours){                
                    $('#countbox1').textfill({
                        maxFontPixels : $('#countbox1').height()
                    })
                    window.hours = true
                }
            }
            else{
                $('#countbox1>span').text(m + ":" + s);
                if (!window.minutes){                
                    $('#countbox1').textfill({
                        maxFontPixels : $('#countbox1').height()
                    })
                    window.minutes = true
                }
            }
        }else{
            $('#countbox1>span').text(window.end_text);
            $('#countbox1').textfill({
                maxFontPixels : $('#countbox1').height()
            })	
            return;
        }
        

		if (window.t) {
			clearTimeout(window.t)
		}
		/*repeat after one second*/
		window.t = setTimeout(countdown, 1000);
		
	}
	
	function countup() {
	
        var now = moment().tz(window.widget_timezone);
		var timeToCompare = null
		
		if(now > window.event_start){
			timeToCompare = window.event_start
		}

		if(timeToCompare){
			timeDiff = now - timeToCompare
			
			var d="",h="",m="",s="";

			var amount = Math.floor(timeDiff/1000);//kill the "milliseconds" so just secs
	        d=Math.floor(amount/86400);//days
	        amount=amount%86400;
	        h=Math.floor(amount/3600);//hours
	        amount=amount%3600;
	        m=Math.floor(amount/60);//minutes
	        amount=amount%60;
	        s=Math.floor(amount);//seconds
            
            m = checkTime(m);
            s = checkTime(s);
            h = checkTime(h);

			if(d != 0){
                $('#countbox1>span').text(d + "d " + h + ":" + m + ":" + s);
                if (!window.days){                
                    $('#countbox1').textfill({
                        maxFontPixels : $('#countbox1').height()
                    })
                    window.days = true
                }
			}
			else if(h != 0){
                $('#countbox1>span').text(h + ":" + m + ":" + s);
                if (!window.hours){                
                    $('#countbox1').textfill({
                        maxFontPixels : $('#countbox1').height()
                    })
                    window.hours = true
                }
			}
			else{
                $('#countbox1>span').text(m + ":" + s);			  
                if (!window.minutes){                
                    $('#countbox1').textfill({
                        maxFontPixels : $('#countbox1').height()
                    })
                    window.minutes = true
                }
			}
		}else{            
			$('#countbox1>span').text(window.start_text);
		}
        
        
		if (window.t) {
			clearTimeout(window.t)
		}
		/*repeat after one second*/
		window.t = setTimeout(countup, 1000);
	}

    /*function that appends a zero to single digit numbers*/
	function checkTime(i) {
		if (i < 10) {
			i = "0" + i
		}
		; // add zero in front of numbers < 10
		return i;
	}
		//function that starts the widget

	function init_widget(config) {
		if (!config) {
			console.log("no json configuration found");
			return;
		}

		/*apply css based on configuration*/
		
		if ("bgcolor" in config) {
			window.bgcolor = hexToRGBA(config.bgcolor)
			if (window.bgcolor) {
				$('body').css('background-color', window.bgcolor)
			}
		}
		if ("color" in config) {
			window.color = hexToRGBA(config.color)
			if (window.color) {
                $('#countbox1').css('color', window.color)
			}
		}
		
		window.widget_timezone = moment.tz.guess();
		
		if ('fontfamily' in config) {
			$('#countbox1').css('font-family', config['fontfamily'])
		}

		if ('fontstyle' in config) {
			$('#countbox1').css('font-style', config['fontstyle'])
		}

		if ('fontweight' in config) {
			$('#countbox1').css('font-weight', config['fontweight'])
		}

		if ("event_start" in config) {
	        window.event_start = moment(config.event_start,"YYYY-MM-DD[T]HH:mm:ss")
	    }
		else{
			window.event_start = moment()
		}
		if ("event_end" in config) {
            window.event_end =  moment(config.event_end,"YYYY-MM-DD[T]HH:mm:ss")
        }
		else{
			window.event_end = moment()
		}
		if("count_type" in config){
            if(config['count_type'] == 'Count-up'){
                window.count_up = true
            }
            else{
                window.count_up = false
            }
		}
		if("end_text" in config){
			window.end_text = config['end_text']
		}else{
			window.end_text = ""
		}
		if("start_text" in config){
			window.start_text = config['start_text']
		}else{
			window.start_text = ""
		}
		
		window.minutes = false
		window.hours = false
		window.days = false
	}

	function start_widget() {
        var now = moment().tz(window.widget_timezone);
		var timeToCompare = null
	
        if(window.count_up){            
            if(now > window.event_start){
                timeToCompare = window.event_start
            }
            
            if(!timeToCompare){            
                $('#countbox1>span').text(window.start_text);
            }
            countup()
        }else{
            countdown()
        }
        
        $('#countbox1').show()        		        
        /*resize text*/
		$('#countbox1').textfill({
			maxFontPixels : $('#countbox1').height()
		})	
	}

	function stop_widget() {
		if (window.t) {
            clearTimeout(window.t)
        }
	}
	
	/*test function to test while developing*/
	function test_widget() {
		init_widget({
			bgcolor : "black",
			color : "white",
			fontfamily : "arial",
			fontstyle : "normal",
			fontweight : "bold",
			event_end:"2018-06-29T11:40:50.000Z",
			event_start:"2018-06-29T09:37:00.000Z",
			count_type: "Count-down",
			start_text: "Starting",
			end_text: "Ending"
        });

		start_widget()
	}
	
	
    /*function that turns an rgba hex to rgba css*/
	function hexToRGBA(hex) {
		var r = parseInt(hex.substr(0, 2), 16);
		var g = parseInt(hex.substr(2, 2), 16);
		var b = parseInt(hex.substr(4, 2), 16);
		var a = Math.round((parseInt(hex.substr(6, 2), 16) / 255) * 100);

		a = a / 100;

		var rgba = 'rgba(' + r + ',' + g + ',' + b + ',' + a + ')';
		return rgba;
	}

	/*function to resize text so that it fits to its container*/
	(function($) {
		$.fn.textfill = function(options) {
			var fontSize = options.maxFontPixels;
			var ourText = $('span:first', this);
			var maxHeight = $(this).height();
			var maxWidth = $(this).width();
			var textHeight;
			var textWidth;
			while(true) {
				ourText.css('font-size', fontSize);
				textHeight = ourText.height();
				textWidth = ourText.width();
				//console.log(textHeight +' -- '+ maxHeight)
				//console.log(textWidth +' -- '+ maxWidth)

                if(fontSize < 5){
                    break;
                }

				if(textHeight > maxHeight){
					fontSize = fontSize - Math.ceil(fontSize*(1-(maxHeight/textHeight)))
					continue;
				}
				if(textWidth > maxWidth){
					fontSize = fontSize - Math.ceil(fontSize*(1-(maxWidth/textWidth)))
                    continue;
				}
				break;

			}

			window.fontsize = fontSize;
			return this;
		}
	})(jQuery);
	
	
</script>
</head>

<body>
	<div id="countbox1" hidden>
        <span>N/A</span>
	</div>
</body>
</html>

The app’s JSON Schema

we need the declare a schema for the required configuration fields:

  1. bgcolor: a color picker field that defines the widget’s background color.
  2. color: a color picker field that defines the widget’s font color.
  3. fontfamily: a select field with the available fonts
  4. fontstyle: a select field with the available font styles (normal, italic …)
  5. fontweight: a select field with the available font weight (normal, bold …)
  6. count_type: an option filed with the available Count types (Down/Up)
  7. start_text: a text field writing a before start message
  8. event_start: a time selector when the event will start
  9. end_text: a text field displaying an after end message
  10. event_end: a time selector when the event will end

 

Count Down/Up schema.jsonExpand source

{
  "fields": [
    "bgcolor",
    "color",
    "fontfamily",
    "fontstyle",
    "fontweight",
    "count_type",
    "start_text",
    "event_start",
    "end_text",
    "event_end"
  ],
  "meta": {
    "details": "A simple timer that either counts up from an event or down to a deadline. The size of the timer gets automatically adjusted to the layout zone. Options include color and font customization.",
    "description": "A simple timer that either counts up from an event or down to a deadline. The size adjusts to the provided area.",
    "name": "Counter up/down"
  },
  "data": {
    "count_type": "Count-down",
    "fontstyle": "<%=general_normal%>",
    "fontfamily": "Arial",
    "color": "white",
    "bgcolor": "black",
    "fontweight": "<%=general_normal%>"
  },
  "schema": {
    "count_type": {
      "title": "<%=countupdown_counter_type%>",
      "type": "Select",
      "options": [
        {
          "options": [
            "Count-down",
            "Count-up"
          ],
          "hides": [
            {
              "fields": [
                "event_start",
                "start_text"
              ]
            },
            {
              "fields": [
                "event_end",
                "end_text"
              ]
            }
          ],
          "shows": [
            {
              "fields": [
                "event_end",
                "end_text"
              ]
            },
            {
              "fields": [
                "event_start",
                "start_text"
              ]
            }
          ]
        }
      ],
      "validators": [
        "required"
      ]
    },
    "fontstyle": {
      "title": "<%=general_font_style%>",
      "type": "Select",
      "options": [
        "<%=general_normal%>",
        "<%=general_italic%>",
        "<%=general_oblique%>"
      ],
      "validators": [
        "required"
      ]
    },
    "end_text": {
      "type": "Text",
      "title": "<%=countupdown_text_after_end%>"
    },
    "color": {
      "type": "SpectrumColorPicker",
      "title": "<%=general_font_color%>"
    },
    "event_end": {
      "yearStart": 2000,
      "minsInterval": 1,
      "type": "DateTime",
      "yearEnd": 2030,
      "title": "<%=countupdown_event_end%>"
    },
    "event_start": {
      "yearStart": 2000,
      "minsInterval": 1,
      "type": "DateTime",
      "yearEnd": 2030,
      "title": "<%=countupdown_event_start%>"
    },
    "bgcolor": {
      "type": "SpectrumColorPicker",
      "title": "<%=general_background_color%>"
    },
    "start_text": {
      "type": "Text",
      "title": "<%=countupdown_text_before_start%>"
    },
    "fontfamily": {
      "title": "<%=general_font_family%>",
      "type": "Select",
      "options": [
        "Arial",
        "Courier",
        "Comic Sans MS",
        "Georgia",
        "Times New Roman",
        "Trebuchet MS",
        "Verdana"
      ],
      "validators": [
        "required"
      ]
    },
    "fontweight": {
      "title": "<%=general_font_weight%>",
      "type": "Select",
      "options": [
        "<%=general_normal%>",
        "<%=general_bold%>",
        "<%=general_bolder%>",
        "<%=general_lighter%>"
      ],
      "validators": [
        "required"
      ]
    }
  }
}

Complete ZIP Package

In the upload app page, we create a new app, upload the attached zip file and enter the schema given above. After that, we can create apps with the desired styling/configuration.

You can download the complete ZIP file for the App from here:


countdonwup.zip

For any questions, you may have, reach out and our development team can help you out.