diff --git a/README.md b/README.md index 6de3361..5891890 100644 --- a/README.md +++ b/README.md @@ -10,6 +10,10 @@ The jQuery Console plugin allows you to easily create a non-interactive console --- +## Live Demo + +A live demo of this project can be found at https://eatonciaran.github.io/jquery-console/ + ## Usage Initialise the console by attaching it to a `div` tag. `options` is optional. @@ -27,19 +31,36 @@ myConsole.log("message"); ## Options +### defaultLevel +Integer or string. Set the default severity level of messaages. If an integer it needs to be a valid index of the levels +array and if it's a string the value needs to be found in that array. + +### fadeoutTime +Integer to set how long in milliseconds messages take to fadeout when `timeout` is being used. Default: `400`. + ### history -Integer to set how many messages to retain. Default: `10000`. +Integer to set how many messages to retain. Set to `0` to retain everything (Not recommended). Default: `10000`. + +### levels +Array of severity levels. Modifying this is only useful if the number of default severities is insufficient for your CSS needs. +Default `["emergency", "alert", "critical", "error", "warning", "notice", "info", "debug"]` ### msgDirection -String to denote whether messages are appended to the top or bottom. Default: `"down"` +String to denote whether messages are appended to the top or bottom. Default: `"down"`. * `"down"`: append to the bottom * `"up"`: append to the top ### showTimestamp -Boolean flag indicating whether the timestamp the message was logged should be shown. Default: `true` +Boolean to enable displaying of message timestamps. Default: `true`. + +### tagOddEven +Boolean to enable messages being tagged odd or even to allow alternating message styling. Default `false`. ### timeout -Integer to set how long in milliseconds until messages are deleted. Setting to `0` results in no timeout. Default: `0` +Integer to set how long in milliseconds until messages are deleted. Set to `0` for no timeout. Default: `0`. + +### timestampOnLeft +Boolean to control whether timestamp appears on the left or the right of the message. Default: `false`. --- @@ -48,7 +69,7 @@ Integer to set how long in milliseconds until messages are deleted. Setting to ` ### log Logs message to the assigned console. Takes 2 parameters: * `msg`: String representing the message to be logged. Required. -* `level`: Can either be an integer or string representing the desired visual style. Default: `6` +* `level`: Can either be an integer or string representing the desired visual style / severity. Default determined by the option `defaultLevel`. Assuming the option `levels` is default the following values are accepted: | Integer | String | | ------- | ------------- | diff --git a/demos/index.html b/demos/index.html index 836a097..fa9bc81 100644 --- a/demos/index.html +++ b/demos/index.html @@ -4,8 +4,8 @@ - - + + jQuery Console Plugin @@ -30,10 +30,13 @@

New messages placed at the bottom and limited history of 15 messages

No timestamp and messages timeout after 3 seconds

+ +

Odd even tagging, timestamp on left side

+
- + diff --git a/demos/css/main.css b/demos/main.css similarity index 100% rename from demos/css/main.css rename to demos/main.css diff --git a/dist/jquery.console.min.css b/dist/jquery.console.min.css new file mode 100644 index 0000000..1422b45 --- /dev/null +++ b/dist/jquery.console.min.css @@ -0,0 +1 @@ +.jquery-console{border:1px solid #444;height:10em;overflow-y:scroll;margin:1em}.jquery-console-entry{text-align:left;color:#444;padding:0 .5em 0 .5em}.jquery-console-msg{display:inline-block;word-break:break-all;text-align:left;width:100%}.jquery-console-msg-ts{float:left;width:90%}.jquery-console-timestamp{display:inline-block;text-align:right;width:10%}.jquery-console-msg-ts-left{float:right;width:94%}.jquery-console-timestamp-left{display:inline-block;text-align:left;width:5%}.jquery-console-odd{background-color:#d6d6d6}.jquery-console-even{background-color:#fff}.jquery-console-lvl-debug{color:#868686}.jquery-console-lvl-info{color:#444}.jquery-console-lvl-notice{color:#009300}.jquery-console-lvl-warning{color:#009393}.jquery-console-lvl-error{color:#00007f}.jquery-console-lvl-critical{color:#fc7f00}.jquery-console-lvl-alert{color:#7f0000}.jquery-console-lvl-emergency{background-color:#000;color:#fff} \ No newline at end of file diff --git a/dist/jquery.console.min.js b/dist/jquery.console.min.js new file mode 100644 index 0000000..e379dcb --- /dev/null +++ b/dist/jquery.console.min.js @@ -0,0 +1,18 @@ +/** + * jQuery Console + * + * @file A jQuery plugin to create a non-interactive console within a page. + * + * @author Ciarán Eaton + * @version: 1.1.0 + * Project repository: https://github.com/EatonCiaran/jquery-console + * + * Known to work with jQuery v3.x.x + * + * @license Licensed under GPLv3 + * https://github.com/EatonCiaran/jquery-console#license + * + * @copyright Copyright 2021 Ciarán Eaton + * + */ +!function($){$.fn.console=function(options){if(options.defaultLevel){let levels=settings.levels;if(options.levels&&(levels=options.levels),"number"==typeof options.defaultLevel&&(options.defaultLevel<0||options.defaultLevel>levels.length))throw"Invalid index value for defaultLevel: "+options.defaultLevel;throw"string"!=typeof options.defaultLevel||levels.contains(options.defaultLevel)?"Invalid type for defaultLevel: "+typeof options.defaultLevel:"Invalid name for defaultLevel: "+options.defaultLevel}let settings=$.extend({showTimestamp:!0,timestampOnLeft:!1,msgDirection:"down",history:1e4,timeout:0,fadeOutTime:400,levels:["emergency","alert","critical","error","warning","notice","info","debug"],defaultLevel:6,tagOddEven:!1},options),flags={scrollbarMoved:!1,odd:!0},$this=$(this);return this.each((function(){$this.addClass("jquery-console")})),this._getCssLevel=function(level){function getName(val,arr){return"number"==typeof val&&val>=0&&val");$("").appendTo($msgEntry);let c_level=this._getCssLevel(level);$msgEntry.addClass(c_level),settings.tagOddEven&&(flags.odd?($msgEntry.addClass("jquery-console-odd"),$msgEntry.addClass(c_level+"-odd")):($msgEntry.addClass("jquery-console-even"),$msgEntry.addClass(c_level+"-even")),flags.odd=!flags.odd);let $msg=$msgEntry.children(".jquery-console-msg");if($msg.text(msg),settings.showTimestamp){let timestamp=new Date;timestamp=timestamp.toLocaleTimeString(),$("").appendTo($msgEntry),$msgEntry.children(".jquery-console-timestamp").text(timestamp),settings.timestampOnLeft?($msg.addClass("jquery-console-msg-ts-left"),$msgEntry.children(".jquery-console-timestamp").addClass("jquery-console-timestamp-left")):$msg.addClass("jquery-console-msg-ts")}return $msgEntry},this._adjustHeight=function($msgEntry){let $meg=$msgEntry.children(".jquery-console-msg");$msgEntry.height($meg.height())},this._insertMsg=function($msgEntry){if("up"==settings.msgDirection)$msgEntry.prependTo(this);else{flags.scrollbarMoved=!1;let h=$this.prop("scrollHeight")-$this.prop("clientHeight");$this.scrollTop()!=h&&(flags.scrollbarMoved=!0),$msgEntry.appendTo(this)}},this._cullHistory=function(){if(0==settings.history)return;let queueSize;$this.children(".jquery-console-entry").length>settings.history&&("up"==settings.msgDirection?$this.children(".jquery-console-entry").last().remove():$this.children(".jquery-console-entry").first().remove())},this._attachTimeout=function($msgEntry){if(settings.timeout>0){let timeout=settings.timeout,fadeout=settings.fadeOutTime;$msgEntry.delay(timeout).fadeOut(fadeout,(function(){$(this).remove()}))}},this.log=function(msg,level){let $msgEntry=this._createEntry(msg,level);this._insertMsg($msgEntry),this._attachTimeout($msgEntry),this._cullHistory(),this._setScrollBar(),this._adjustHeight($msgEntry)},this}}(jQuery); \ No newline at end of file diff --git a/src/jquery.console.css b/src/jquery.console.css index 42831f4..d91d83f 100644 --- a/src/jquery.console.css +++ b/src/jquery.console.css @@ -11,6 +11,7 @@ padding: 0 0.5em 0 0.5em; } +/* message content */ .jquery-console-msg { display: inline-block; word-break: break-all; @@ -18,7 +19,8 @@ width: 100%; } -.jquery-console-msg-nots { +/* timestamped message */ +.jquery-console-msg-ts { float: left; width: 90%; } @@ -29,8 +31,27 @@ width: 10%; } +/* timestamp on the left */ +.jquery-console-msg-ts-left { + float: right; + width: 94%; +} +.jquery-console-timestamp-left { + display: inline-block; + text-align: left; + width: 5%; +} + +.jquery-console-odd { + background-color: #d6d6d6; +} + +.jquery-console-even { + background-color: #FFFFFF; +} + .jquery-console-lvl-debug { - color: #D2D2D2; + color: #868686; } .jquery-console-lvl-info { diff --git a/src/jquery.console.js b/src/jquery.console.js index 76b6291..953490a 100644 --- a/src/jquery.console.js +++ b/src/jquery.console.js @@ -1,168 +1,258 @@ -/*! +/** * jQuery Console - * version: 1.0.0 - * Known to work with jQuery v3.x.x + * + * @file A jQuery plugin to create a non-interactive console within a page. + * + * @author Ciarán Eaton + * @version: 1.1.0 * Project repository: https://github.com/EatonCiaran/jquery-console * - * Copyright 2021 Ciarán Eaton + * Known to work with jQuery v3.x.x * - * Licensed under GPLv3 + * @license Licensed under GPLv3 * https://github.com/EatonCiaran/jquery-console#license * + * @copyright Copyright 2021 Ciarán Eaton + * */ -(function ( $ ) { - $.fn.console = function( options ) { - var settings = $.extend({ - showTimestamp: true, - msgDirection: "down", - history: 10000, - timeout: 0 - }, options ); - - var flags = { - scrollbarMoved: false // denote if user has positioned scrollbar - } - var $this = $( this ); - - this.each(function() { - $this.addClass( "jquery-console" ); - }); - - this._getCssLevel = function( level ) { - /* - Takes a level in the form of integer in the range 0-7 - or string of a valid level and Returns a string representing - that level's CSS labal. - */ - - var levels = [ - "emergency", "alert", "critical", "error", - "warning", "notice", "info", "debug" - ]; - var css_base = "jquery-console-lvl-"; - var index = 6; // Default level - - // If level is a number check its a valid index - if ( level >= 0 && level < levels.length ) { - index = level; - } - - // If level is a string validate it - for (var i = 0; i < levels.length; i++) { - if ( level == levels[i] ) { - index = i; - } - } - - return css_base + levels[index]; - }; - - this._setScrollBar = function() { - /* - Set scrollbar position based on message direction and if - user has moved the scrollbar - */ - - if ( settings.msgDirection == "down" && !flags.scrollbarMoved) { - var h = $this.prop("scrollHeight"); - var c = $this.prop("clientHeight"); - $this.scrollTop( h-c ); - } - } - - this._createEntry = function( msg, level ) { - // Create skeleton - var $newElement = $( "
" ); - $( "" ).appendTo( $newElement ); - - // Add CSS for Severity Level - var c_level = this._getCssLevel(level); - $newElement.addClass(c_level); - - // Add message - var $msgElement = $newElement.children( ".jquery-console-msg" ); - $msgElement.text( msg ); - - // Add timestamp - if ( settings.showTimestamp ) { - var d = new Date(); - d = d.toLocaleTimeString(); - - $msgElement.addClass( "jquery-console-msg-nots" ); - - $( "" ).appendTo( $newElement ); - $newElement.children( ".jquery-console-timestamp" ).text( d ); - } - - return $newElement; - }; - - this._adjustHeight = function( $newElement ) { - var $msgElement = $newElement.children( ".jquery-console-msg" ); - $newElement.height( $msgElement.height() ); - }; - - this._insertMsg = function( $newElement ) { - if ( settings.msgDirection == "up" ) { - $newElement.prependTo( this ); // Insert at the top - } - else { - // Set flag if scrollbar was moved by user. - flags.scrollbarMoved = false; - var h = $this.prop("scrollHeight") - $this.prop("clientHeight"); - if ( $this.scrollTop() != h ) { - flags.scrollbarMoved = true; - } - - $newElement.appendTo( this ); // Insert at the bottom +(function ($) { + $.fn.console = function (options) { + // validate options + if (options.defaultLevel) { + let levels = settings.levels; + if (options.levels) { + levels = options.levels; + } + + if (typeof (options.defaultLevel) == "number") { + if (options.defaultLevel < 0 || options.defaultLevel > levels.length) { + throw "Invalid index value for defaultLevel: " + options.defaultLevel; + } + } + if (typeof (options.defaultLevel) == "string" && !levels.contains(options.defaultLevel)) { + throw "Invalid name for defaultLevel: " + options.defaultLevel; + } + else { + throw "Invalid type for defaultLevel: " + typeof (options.defaultLevel); + } } - }; - - this._kullHistory = function() { - /* - Delete old messages if history size exceeded. - */ - - if ( settings.history == 0 ) { - return; // Do nothing + + // default settings + let settings = $.extend({ + showTimestamp: true, // Display timestamp or not + timestampOnLeft: false, // Display timestamp on the left or right + msgDirection: "down", // Control whether messages are added to the top or bototm of the stack + history: 10000, // Number of messages to keep + timeout: 0, // Time in ms beofre message is deleted + fadeOutTime: 400, // Time in ms it takes for the animation of timeout message removal to complete + levels: [ // Severity levels + "emergency", "alert", "critical", "error", + "warning", "notice", "info", "debug" + ], + defaultLevel: 6, // Default severity level of a message + tagOddEven: false, // Tagging of odd and even entries to aid styling + }, options); + + // internal flags to denote state + let flags = { + scrollbarMoved: false, // denote if user has positioned scrollbar + odd: true // track whether next message is odd or even. } - - var queueSize = $this.children(".jquery-console-entry").length; - if ( queueSize > settings.history ) { - if ( settings.msgDirection == "up" ) { - $this.children(".jquery-console-entry").last().remove(); - } - else { - $this.children(".jquery-console-entry").first().remove(); - } + + // setup + let $this = $(this); + this.each(function () { + $this.addClass("jquery-console"); + }); + + /** + * Returns the CSS label for a given severity level. + * @param {int or string} level Severity level of the message. Can either be an index into + * or value from settings.levels + * @returns {string} + */ + this._getCssLevel = function (level) { + function getName(val, arr) { + // if level is a number and a valid index + if (typeof (val) == "number" && val >= 0 && val < arr.length) { + return arr[val]; + } + // if level is a string and a valid value + else if (typeof (val) == "string" && arr.includes(val)) { + return val; + } + return false; + } + + const css_base = "jquery-console-lvl-"; + let level_name = getName(0, settings.levels); // default + + let name = getName(level, settings.levels); + if (name) { + level_name = name; + } + else if (typeof(level) == "undefined") { + level_name = getName(settings.defaultLevel, settings.levels); // override default with custom default + } + // else anything other than being undefined is bad. Default level will be used eitherway + else { + console.log("jQuery Console: Invalid severity level. Level: " + level); + } + + return css_base + level_name; + }; + + /** + * Force scrollbar to the bottom position if message direction is down, thus preventing the bar + * auto scrolling up when messages are added. + */ + this._setScrollBar = function () { + if (settings.msgDirection == "down" && !flags.scrollbarMoved) { + let h = $this.prop("scrollHeight"); + let c = $this.prop("clientHeight"); + $this.scrollTop(h - c); + } } - }; - - this._attachTimeout = function( $msgElement ) { - if ( settings.timeout > 0 ) { - $msgElement.delay( settings.timeout ).fadeOut( 400, function() { - $( this ).remove(); - }); + + /** + * Rteurns message wrapped in HTML. + * @param {string} msg The content of the message + * @param {int or string} level Severity level of the message. Can either be an index into + * or value from settings.levels + * @returns {selector} + */ + this._createEntry = function (msg, level) { + // create skeleton + let $msgEntry = $("
"); + $("").appendTo($msgEntry); + + // add CSS for Severity Level + let c_level = this._getCssLevel(level); + $msgEntry.addClass(c_level); + + // if feature enabled, add CSS tags to denote odd even ness + if (settings.tagOddEven) { + if (flags.odd) { + $msgEntry.addClass("jquery-console-odd"); + $msgEntry.addClass(c_level + "-odd"); + } + else { + $msgEntry.addClass("jquery-console-even"); + $msgEntry.addClass(c_level + "-even"); + } + flags.odd = !flags.odd; + } + + // add message + let $msg = $msgEntry.children(".jquery-console-msg"); + $msg.text(msg); + + // add timestamp + if (settings.showTimestamp) { + let timestamp = new Date(); + timestamp = timestamp.toLocaleTimeString(); + + $("").appendTo($msgEntry); + $msgEntry.children(".jquery-console-timestamp").text(timestamp); + + // tag the message content to it's styled to accomate the timestamp + if (settings.timestampOnLeft) { + $msg.addClass("jquery-console-msg-ts-left"); + $msgEntry.children(".jquery-console-timestamp").addClass("jquery-console-timestamp-left"); + } + else { + $msg.addClass("jquery-console-msg-ts"); + } + } + + return $msgEntry; + }; + + /** + * Sets message entry's height to the content's height. + * @param {selector} $msgEntry Selector of message entry + */ + this._adjustHeight = function ($msgEntry) { + let $meg = $msgEntry.children(".jquery-console-msg"); + $msgEntry.height($meg.height()); + }; + + /** + * Inserts message entry into the DOM + * @param {selector} $msgEntry The message entry to be inserted + */ + this._insertMsg = function ($msgEntry) { + + if (settings.msgDirection == "up") { + $msgEntry.prependTo(this); // Insert at the top + } + else { + // consdier the scrollbar user moved if it's not at the bottom position + flags.scrollbarMoved = false; + let h = $this.prop("scrollHeight") - $this.prop("clientHeight"); + if ($this.scrollTop() != h) { + flags.scrollbarMoved = true; + } + + $msgEntry.appendTo(this); // Insert at the bottom + } + }; + + /** + * Delete old messages if history size exceeded. + * @returns None + */ + this._cullHistory = function () { + if (settings.history == 0) { + return; // Do nothing + } + + let queueSize = $this.children(".jquery-console-entry").length; + if (queueSize > settings.history) { + if (settings.msgDirection == "up") { + $this.children(".jquery-console-entry").last().remove(); + } + else { + $this.children(".jquery-console-entry").first().remove(); + } + } + }; + + /** + * Attach timeout event to messages if timeout is set. + * @param {selector} $msgEntry Selector of the message entry + */ + this._attachTimeout = function ($msgEntry) { + if (settings.timeout > 0) { + let timeout = settings.timeout; + let fadeout = settings.fadeOutTime; + + // after delay, fadeout the message then remove. + $msgEntry.delay(timeout).fadeOut(fadeout, function () { + $(this).remove(); + }); + } + }; + + /** + * Log message entry to jquery-console panel + * @param {string} msg The content of the message + * @param {int or string} level Severity level of the message. Can either be an index into + * or value from settings.levels + */ + this.log = function (msg, level) { + // Create + let $msgEntry = this._createEntry(msg, level); // Create HTML + this._insertMsg($msgEntry); // Insert to DOM + + // Finalise and cleanup + this._attachTimeout($msgEntry); // Attach a timeout to the message + this._cullHistory(); // Delete old history + this._setScrollBar(); // Set Scrollbar position + this._adjustHeight($msgEntry); // Correct the message height } - }; - - this.log = function( msg, level ) { - /* - Add message entry to jquery-console panel - */ - - // Create - var $newElement = this._createEntry( msg, level ); // Create HTML - this._insertMsg( $newElement ); // Insert to DOM - - // Cleanup - this._attachTimeout( $newElement ); // Attach a timeout to the message - this._kullHistory(); // Delete old history - this._setScrollBar(); // Set Scrollbar position - this._adjustHeight( $newElement ); // Correct the message height - } - - return this; + + return this; }; - }( jQuery )); \ No newline at end of file +}(jQuery)); \ No newline at end of file