diff --git a/js/ui/cordova/www/js/Logger.js b/js/ui/cordova/www/js/Logger.js new file mode 100644 index 0000000..a47ada1 --- /dev/null +++ b/js/ui/cordova/www/js/Logger.js @@ -0,0 +1,430 @@ +/////////////////////////////////////////////////////////////////////////////// +// Logger.js +// ========= +// singleton log class (module pattern) +// +// This class creates a drawable tab at the bottom of web browser. You can slide +// up/down by clicking the tab. You can toggle on/off programmatically by +// calling Logger.toggle(), or Logger.show() and Logger.hide() respectively. +// It can be completely hidden by calling Logger.hide(). To get it back, call +// Logger.show(). It can be also enabled/disabled by Logger.enable()/disable(). +// When it is disabled, a message with log() won't be written to logger. +// When you need to purge all previous messages, use Logger.clear(). +// +// Use log() utility function to print a message to the log window. +// e.g.: log("Hello") : print Hello +// log(123) : print 123 +// log() : print a blank line without time stamp +// +// History: +// 1.14: Added toggle() to draw logger window up/down. +// Added open()/close() to slide up/down. +// Changed show()/hide() for visibility. +// Changed tab size smaller. +// 1.13: Added the class name along with version. +// 1.12: Removed width and added margin-left for msgDiv. +// 1.11: Added clear() function. +// 1.10: Added enable()/disable() functions. +// 1.09: Added z-index attribute on the logger container. +// 1.08: Use requestAnimationFrame() for animations. +// 1.07: Wrap a message if it is longer than the window width. +// 1.06: Print "undefined" or "null" if msg is undefined or null value. +// 1.05: Added time stamp for log() (with no param). +// 1.04: Modified handling undefined type of msg. +// 1.03: Fixed the error when msg is undefined. +// 1.02: Added sliding animation easy in/out using cosine. +// 1.01: Changed "display:none" to visibility:hidden for logDiv. +// Supported IE v8 without transparent background. +// 1.00: First public release. +// +// AUTHOR: Song Ho Ahn (song.ahn@gmail.com) +// CREATED: 2011-02-15 +// UPDATED: 2016-07-11 +// +// Copyright 2011. Song Ho Ahn +/////////////////////////////////////////////////////////////////////////////// + +// Smme Globals + + +/////////////////////////////////////////////////////////////////////////////// +// utility function to print message with timestamp to log +// e.g.: log("Hello") : print Hello +// log(123) : print 123 +// log() : print a blank line +function log(msg) +{ + if(arguments.length == 0) + Logger.print(""); // print a blank line + else + Logger.print(msg); +}; + +function getTime() +{ + var now = new Date(); + var hour = "0" + now.getHours(); + hour = hour.substring(hour.length-2); + var minute = "0" + now.getMinutes(); + minute = minute.substring(minute.length-2); + var second = "0" + now.getSeconds(); + second = second.substring(second.length-2); + return hour + ":" + minute + ":" + second; +}; +function getDate() +{ + var now = new Date(); + var year = "" + now.getFullYear(); + var month = "0" + (now.getMonth()+1); + month = month.substring(month.length-2); + var date = "0" + now.getDate(); + date = date.substring(date.length-2); + return year + "-" + month + "-" + date; +}; + + +/////////////////////////////////////////////////////////////////////////////// +var Logger = (function() +{ + "use strict"; + + /////////////////////////////////////////////////////////////////////////// + // private members + /////////////////////////////////////////////////////////////////////////// + var version = "1.14"; + var containerDiv = null; + var tabDiv = null; + var logDiv = null; + var visible = true; // flag for visibility + var opened = false; // flag for toggle on/off + var enabled = true; // does not accept log messages any more if it is false + var logHeight = 300; // 204 + 2*padding + border-top + var tabHeight = 42; // 16 + padding-top + border-top + // for animation + var animTime = 0; + var animDuration = 200; // ms + var animFrameTime= 16; // ms + + /////////////////////////////////////////////////////////////////////////// + // get time and date as string with a trailing space + /////////////////////////////////////////////////////////////////////////// + // return available requestAnimationFrame(), otherwise, fallback to setTimeOut + var getRequestAnimationFrameFunction = function() + { + var requestAnimationFrame = window.requestAnimationFrame || + window.mozRequestAnimationFrame || + window.msRequestAnimationFrame || + window.oRequestAnimationFrame || + window.webkitRequestAnimationFrame; + if(requestAnimationFrame) + return function(callback){ return requestAnimationFrame(callback); }; + else + return function(callback){ return setTimeout(callback, 16); }; + }; + + + + /////////////////////////////////////////////////////////////////////////// + // public members + /////////////////////////////////////////////////////////////////////////// + var self = + { + /////////////////////////////////////////////////////////////////////// + // create a div for log and attach it to document + init: function() + { + // avoid redundant call + if(containerDiv) + return true; + + // check if DOM is ready + if(!document || !document.createElement || !document.body || !document.body.appendChild) + return false; + + // constants + var CONTAINER_DIV = "loggerContainer"; + var TAB_DIV = "loggerTab"; + var LOG_DIV = "logger"; + var Z_INDEX = 9999; + + // create logger DOM element + containerDiv = document.getElementById(CONTAINER_DIV); + if(!containerDiv) + { + // container + containerDiv = document.createElement("div"); + containerDiv.id = CONTAINER_DIV; + containerDiv.setAttribute("style", "width:100%; " + + "height: " + logHeight + "px; " + + "margin-left: -50%; " + + "padding:0; " + + "position:fixed; " + + "left:50%; " + + "z-index:" + Z_INDEX + ";"); + containerDiv.style.bottom = "" + (-logHeight) + "px"; // hide it initially + + // tab + tabDiv = document.createElement("div"); + tabDiv.id = TAB_DIV; + tabDiv.appendChild(document.createTextNode("LOG")); + cssHeight = "height:" + (tabHeight - 6) + "px; "; // subtract padding-top and border-top + tabDiv.setAttribute("style", "width:45px; " + + cssHeight + + "overflow:hidden; " + + "font:bold 10px verdana,helvetica,sans-serif;" + + "color:#fff; " + + "position:absolute; " + + "right:20px; " + + "top:" + -tabHeight + "px; " + + "margin:0; padding:5px 0 0 0; " + + "text-align:center; " + + "border:1px solid #aaa; " + + "border-bottom:none; " + + "background:#333; " + + "background:rgba(0,0,0,0.8); " + + "-webkit-border-top-right-radius:8px; " + + "-webkit-border-top-left-radius:8px; " + + "-khtml-border-radius-topright:8px; " + + "-khtml-border-radius-topleft:8px; " + + "-moz-border-radius-topright:8px; " + + "-moz-border-radius-topleft:8px; " + + "border-top-right-radius:8px; " + + "border-top-left-radius:8px; "); + // add mouse event handlers + tabDiv.onmouseover = function() + { + this.style.cursor = "pointer"; + this.style.textShadow = "0 0 1px #fff, 0 0 2px #0f0, 0 0 6px #0f0"; + }; + tabDiv.onmouseout = function() + { + this.style.cursor = "auto"; + this.style.textShadow = "none"; + }; + tabDiv.onclick = function() + { + Logger.toggle(); + }; + + // log message + logDiv = document.createElement("div"); + logDiv.id = LOG_DIV; + var cssHeight = "height:" + (logHeight - 11) + "px; "; // subtract paddings and border-top + logDiv.setAttribute("style", "font:12px monospace; " + + cssHeight + + "color:#fff; " + + "overflow-x:hidden; " + + "overflow-y:scroll; " + + "visibility:hidden; " + + "position:relative; " + + "bottom:0px; " + + "margin:0px; " + + "padding:5px; " + + "background:#333; " + + "background:rgba(0, 0, 0, 0.8); " + + "border-top:1px solid #aaa; "); + + // style for log message + var span = document.createElement("span"); // for coloring text + span.style.color = "#afa"; + span.style.fontWeight = "bold"; + + // the first message in log + var msg = "===== Log Started at " + + getDate() + ", " + getTime() + ", " + + "(Logger version " + version + ") " + + "====="; + + span.appendChild(document.createTextNode(msg)); + logDiv.appendChild(span); + logDiv.appendChild(document.createElement("br")); // blank line + logDiv.appendChild(document.createElement("br")); // blank line + + // add divs to document + containerDiv.appendChild(tabDiv); + containerDiv.appendChild(logDiv); + document.body.appendChild(containerDiv); + } + + return true; + }, + /////////////////////////////////////////////////////////////////////// + // print log message to logDiv + print: function(msg) + { + // ignore message if it is disabled + if(!enabled) + return; + + // check if this object is initialized + if(!containerDiv) + { + var ready = this.init(); + if(!ready) + return; + } + + var msgDefined = true; + + // convert non-string type to string + if(typeof msg == "undefined") // print "undefined" if param is not defined + { + msg = "undefined"; + msgDefined = false; + } + else if(msg === null) // print "null" if param has null value + { + msg = "null"; + msgDefined = false; + } + else + { + msg += ""; // for "object", "function", "boolean", "number" types + } + + var lines = msg.split(/\r\n|\r|\n/); + for(var i in lines) + { + // format time and put the text node to inline element + var timeDiv = document.createElement("div"); // color for time + timeDiv.setAttribute("style", "color:#999;" + + "float:left;"); + + var timeNode = document.createTextNode(getTime() + "\u00a0"); + timeDiv.appendChild(timeNode); + + // create message span + var msgDiv = document.createElement("div"); + msgDiv.setAttribute("style", "word-wrap:break-word;" + // wrap msg + "margin-left:6.0em;"); // margin-left = 9 * ? + if(!msgDefined) + msgDiv.style.color = "#afa"; // override color if msg is not defined + + // put message into a text node + var line = lines[i].replace(/ /g, "\u00a0"); + var msgNode = document.createTextNode(line); + msgDiv.appendChild(msgNode); + + // new line div with clearing css float property + var newLineDiv = document.createElement("div"); + newLineDiv.setAttribute("style", "clear:both;"); + + logDiv.appendChild(timeDiv); // add time + logDiv.appendChild(msgDiv); // add message + logDiv.appendChild(newLineDiv); // add message + + logDiv.scrollTop = logDiv.scrollHeight; // scroll to last line + } + }, + /////////////////////////////////////////////////////////////////////// + // slide log container up and down + toggle: function() + { + if(opened) // if opened, close the window + this.close(); + else // if closed, open the window + this.open(); + }, + open: function() + { + if(!this.init()) return; + if(!visible) return; + if(opened) return; + + logDiv.style.visibility = "visible"; + animTime = Date.now(); + var requestAnimationFrame = getRequestAnimationFrameFunction(); + requestAnimationFrame(slideUp); + function slideUp() + { + var duration = Date.now() - animTime; + if(duration >= animDuration) + { + containerDiv.style.bottom = 0; + opened = true; + return; + } + var y = Math.round(-logHeight * (1 - 0.5 * (1 - Math.cos(Math.PI * duration / animDuration)))); + containerDiv.style.bottom = "" + y + "px"; + requestAnimationFrame(slideUp); + } + }, + close: function() + { + if(!this.init()) return; + if(!visible) return; + if(!opened) return; + + animTime = Date.now(); + var requestAnimationFrame = getRequestAnimationFrameFunction(); + requestAnimationFrame(slideDown); + function slideDown() + { + var duration = Date.now() - animTime; + if(duration >= animDuration) + { + containerDiv.style.bottom = "" + -logHeight + "px"; + logDiv.style.visibility = "hidden"; + opened = false; + return; + } + var y = Math.round(-logHeight * 0.5 * (1 - Math.cos(Math.PI * duration / animDuration))); + containerDiv.style.bottom = "" + y + "px"; + requestAnimationFrame(slideDown); + } + }, + /////////////////////////////////////////////////////////////////////// + // show/hide the logger window and tab + show: function() + { + if(!this.init()) + return; + + containerDiv.style.display = "block"; + visible = true; + }, + hide: function() + { + if(!this.init()) + return; + + containerDiv.style.display = "none"; + visible = false; + }, + /////////////////////////////////////////////////////////////////////// + // when Logger is enabled (default), log() method will write its message + // to the console ("logDiv") + enable: function() + { + if(!this.init()) + return; + + enabled = true; + tabDiv.style.color = "#fff"; + logDiv.style.color = "#fff"; + }, + /////////////////////////////////////////////////////////////////////// + // when it is diabled, subsequent log() calls will be ignored and + // the message won't be written on "logDiv". + // "LOG" tab and log text are grayed out to indicate it is disabled. + disable: function() + { + if(!this.init()) + return; + + enabled = false; + tabDiv.style.color = "#444"; + logDiv.style.color = "#444"; + }, + /////////////////////////////////////////////////////////////////////// + // clear all messages from logDiv + clear: function() + { + if(!this.init()) + return; + + logDiv.innerHTML = ""; + } + }; + return self; +})();