2 Copyright (c) 2008, Yahoo! Inc. All rights reserved.
3 Code licensed under the BSD License:
4 http://developer.yahoo.net/yui/license.txt
7 /****************************************************************************/
8 /****************************************************************************/
9 /****************************************************************************/
12 * The LogMsg class defines a single log message.
16 * @param oConfigs {Object} Object literal of configuration params.
18 YAHOO.widget.LogMsg = function(oConfigs) {
44 * Log source. The first word passed in as the source argument.
52 * Log source detail. The remainder of the string passed in as the source argument, not
53 * including the first word (if any).
55 * @property sourceDetail
58 this.sourceDetail = null;
60 if (oConfigs && (oConfigs.constructor == Object)) {
61 for(var param in oConfigs) {
62 this[param] = oConfigs[param];
67 /****************************************************************************/
68 /****************************************************************************/
69 /****************************************************************************/
72 * The LogWriter class provides a mechanism to log messages through
73 * YAHOO.widget.Logger from a named source.
77 * @param sSource {String} Source of LogWriter instance.
79 YAHOO.widget.LogWriter = function(sSource) {
81 YAHOO.log("Could not instantiate LogWriter due to invalid source.",
82 "error", "LogWriter");
85 this._source = sSource;
88 /////////////////////////////////////////////////////////////////////////////
92 /////////////////////////////////////////////////////////////////////////////
95 * Public accessor to the unique name of the LogWriter instance.
98 * @return {String} Unique name of the LogWriter instance.
100 YAHOO.widget.LogWriter.prototype.toString = function() {
101 return "LogWriter " + this._sSource;
105 * Logs a message attached to the source of the LogWriter.
108 * @param sMsg {String} The log message.
109 * @param sCategory {String} Category name.
111 YAHOO.widget.LogWriter.prototype.log = function(sMsg, sCategory) {
112 YAHOO.widget.Logger.log(sMsg, sCategory, this._source);
116 * Public accessor to get the source name.
119 * @return {String} The LogWriter source.
121 YAHOO.widget.LogWriter.prototype.getSource = function() {
122 return this._sSource;
126 * Public accessor to set the source name.
129 * @param sSource {String} Source of LogWriter instance.
131 YAHOO.widget.LogWriter.prototype.setSource = function(sSource) {
133 YAHOO.log("Could not set source due to invalid source.", "error", this.toString());
137 this._sSource = sSource;
141 /////////////////////////////////////////////////////////////////////////////
143 // Private member variables
145 /////////////////////////////////////////////////////////////////////////////
148 * Source of the LogWriter instance.
154 YAHOO.widget.LogWriter.prototype._source = null;
159 /****************************************************************************/
160 /****************************************************************************/
161 /****************************************************************************/
164 * The LogReader class provides UI to read messages logged to YAHOO.widget.Logger.
168 * @param elContainer {HTMLElement} (optional) DOM element reference of an existing DIV.
169 * @param elContainer {String} (optional) String ID of an existing DIV.
170 * @param oConfigs {Object} (optional) Object literal of configuration params.
172 YAHOO.widget.LogReader = function(elContainer, oConfigs) {
173 this._sName = YAHOO.widget.LogReader._index;
174 YAHOO.widget.LogReader._index++;
177 this._buffer = []; // output buffer
178 this._filterCheckboxes = {}; // pointers to checkboxes
179 this._lastTime = YAHOO.widget.Logger.getStartTime(); // timestamp of last log message to console
181 // Parse config vars here
182 if (oConfigs && (oConfigs.constructor == Object)) {
183 for(var param in oConfigs) {
184 this[param] = oConfigs[param];
188 this._initContainerEl(elContainer);
189 if(!this._elContainer) {
190 YAHOO.log("Could not instantiate LogReader due to an invalid container element " +
191 elContainer, "error", this.toString());
195 this._initHeaderEl();
196 this._initConsoleEl();
197 this._initFooterEl();
199 this._initDragDrop();
201 this._initCategories();
204 // Subscribe to Logger custom events
205 YAHOO.widget.Logger.newLogEvent.subscribe(this._onNewLog, this);
206 YAHOO.widget.Logger.logResetEvent.subscribe(this._onReset, this);
208 YAHOO.widget.Logger.categoryCreateEvent.subscribe(this._onCategoryCreate, this);
209 YAHOO.widget.Logger.sourceCreateEvent.subscribe(this._onSourceCreate, this);
212 YAHOO.log("LogReader initialized", null, this.toString());
215 /////////////////////////////////////////////////////////////////////////////
217 // Static member variables
219 /////////////////////////////////////////////////////////////////////////////
220 YAHOO.lang.augmentObject(YAHOO.widget.LogReader, {
222 * Internal class member to index multiple LogReader instances.
224 * @property _memberName
233 * Node template for the log entries
234 * @property ENTRY_TEMPLATE
236 * @type {HTMLElement}
237 * @default PRE.yui-log-entry element
239 ENTRY_TEMPLATE : (function () {
240 var t = document.createElement('pre');
241 YAHOO.util.Dom.addClass(t,'yui-log-entry');
246 * Template used for innerHTML of verbose entry output.
247 * @property VERBOSE_TEMPLATE
249 * @default "<span class='{category}'>{label}</span>{totalTime}ms (+{elapsedTime}) {localTime}:</p><p>{sourceAndDetail}</p><p>{message}</p>"
251 VERBOSE_TEMPLATE : "<span class='{category}'>{label}</span>{totalTime}ms (+{elapsedTime}) {localTime}:</p><p>{sourceAndDetail}</p><p>{message}</p>",
254 * Template used for innerHTML of compact entry output.
255 * @property BASIC_TEMPLATE
257 * @default "<p><span class='{category}'>{label}</span>{totalTime}ms (+{elapsedTime}) {localTime}: {sourceAndDetail}: {message}</p>"
259 BASIC_TEMPLATE : "<p><span class='{category}'>{label}</span>{totalTime}ms (+{elapsedTime}) {localTime}: {sourceAndDetail}: {message}</p>"
262 /////////////////////////////////////////////////////////////////////////////
264 // Public member variables
266 /////////////////////////////////////////////////////////////////////////////
268 YAHOO.widget.LogReader.prototype = {
270 * Whether or not LogReader is enabled to output log messages.
272 * @property logReaderEnabled
276 logReaderEnabled : true,
279 * Public member to access CSS width of the LogReader container.
287 * Public member to access CSS height of the LogReader container.
295 * Public member to access CSS top position of the LogReader container.
303 * Public member to access CSS left position of the LogReader container.
311 * Public member to access CSS right position of the LogReader container.
319 * Public member to access CSS bottom position of the LogReader container.
327 * Public member to access CSS font size of the LogReader container.
335 * Whether or not the footer UI is enabled for the LogReader.
337 * @property footerEnabled
341 footerEnabled : true,
344 * Whether or not output is verbose (more readable). Setting to true will make
345 * output more compact (less readable).
347 * @property verboseOutput
351 verboseOutput : true,
354 * Custom output format for log messages. Defaults to null, which falls
355 * back to verboseOutput param deciding between LogReader.VERBOSE_TEMPLATE
356 * and LogReader.BASIC_TEMPLATE. Use bracketed place holders to mark where
357 * message info should go. Available place holder names include:
361 * <li>sourceAndDetail</li>
364 * <li>elapsedTime</li>
368 * @property entryFormat
375 * Whether or not newest message is printed on top.
377 * @property newestOnTop
383 * Output timeout buffer in milliseconds.
385 * @property outputBuffer
392 * Maximum number of messages a LogReader console will display.
394 * @property thresholdMax
401 * When a LogReader console reaches its thresholdMax, it will clear out messages
402 * and print out the latest thresholdMin number of messages.
404 * @property thresholdMin
411 * True when LogReader is in a collapsed state, false otherwise.
413 * @property isCollapsed
420 * True when LogReader is in a paused state, false otherwise.
429 * Enables draggable LogReader if DragDrop Utility is present.
431 * @property draggable
437 /////////////////////////////////////////////////////////////////////////////
441 /////////////////////////////////////////////////////////////////////////////
444 * Public accessor to the unique name of the LogReader instance.
447 * @return {String} Unique name of the LogReader instance.
449 toString : function() {
450 return "LogReader instance" + this._sName;
453 * Pauses output of log messages. While paused, log messages are not lost, but
454 * get saved to a buffer and then output upon resume of LogReader.
459 this.isPaused = true;
460 this._btnPause.value = "Resume";
461 this._timeout = null;
462 this.logReaderEnabled = false;
466 * Resumes output of log messages, including outputting any log messages that
467 * have been saved to buffer while paused.
471 resume : function() {
472 this.isPaused = false;
473 this._btnPause.value = "Pause";
474 this.logReaderEnabled = true;
479 * Hides UI of LogReader. Logging functionality is not disrupted.
484 this._elContainer.style.display = "none";
488 * Shows UI of LogReader. Logging functionality is not disrupted.
493 this._elContainer.style.display = "block";
497 * Collapses UI of LogReader. Logging functionality is not disrupted.
501 collapse : function() {
502 this._elConsole.style.display = "none";
504 this._elFt.style.display = "none";
506 this._btnCollapse.value = "Expand";
507 this.isCollapsed = true;
511 * Expands UI of LogReader. Logging functionality is not disrupted.
515 expand : function() {
516 this._elConsole.style.display = "block";
518 this._elFt.style.display = "block";
520 this._btnCollapse.value = "Collapse";
521 this.isCollapsed = false;
525 * Returns related checkbox element for given filter (i.e., category or source).
527 * @method getCheckbox
528 * @param {String} Category or source name.
529 * @return {Array} Array of all filter checkboxes.
531 getCheckbox : function(filter) {
532 return this._filterCheckboxes[filter];
536 * Returns array of enabled categories.
538 * @method getCategories
539 * @return {String[]} Array of enabled categories.
541 getCategories : function() {
542 return this._categoryFilters;
546 * Shows log messages associated with given category.
548 * @method showCategory
549 * @param {String} Category name.
551 showCategory : function(sCategory) {
552 var filtersArray = this._categoryFilters;
553 // Don't do anything if category is already enabled
554 // Use Array.indexOf if available...
555 if(filtersArray.indexOf) {
556 if(filtersArray.indexOf(sCategory) > -1) {
560 // ...or do it the old-fashioned way
562 for(var i=0; i<filtersArray.length; i++) {
563 if(filtersArray[i] === sCategory){
569 this._categoryFilters.push(sCategory);
571 var elCheckbox = this.getCheckbox(sCategory);
573 elCheckbox.checked = true;
578 * Hides log messages associated with given category.
580 * @method hideCategory
581 * @param {String} Category name.
583 hideCategory : function(sCategory) {
584 var filtersArray = this._categoryFilters;
585 for(var i=0; i<filtersArray.length; i++) {
586 if(sCategory == filtersArray[i]) {
587 filtersArray.splice(i, 1);
592 var elCheckbox = this.getCheckbox(sCategory);
594 elCheckbox.checked = false;
599 * Returns array of enabled sources.
602 * @return {Array} Array of enabled sources.
604 getSources : function() {
605 return this._sourceFilters;
609 * Shows log messages associated with given source.
612 * @param {String} Source name.
614 showSource : function(sSource) {
615 var filtersArray = this._sourceFilters;
616 // Don't do anything if category is already enabled
617 // Use Array.indexOf if available...
618 if(filtersArray.indexOf) {
619 if(filtersArray.indexOf(sSource) > -1) {
623 // ...or do it the old-fashioned way
625 for(var i=0; i<filtersArray.length; i++) {
626 if(sSource == filtersArray[i]){
631 filtersArray.push(sSource);
633 var elCheckbox = this.getCheckbox(sSource);
635 elCheckbox.checked = true;
640 * Hides log messages associated with given source.
643 * @param {String} Source name.
645 hideSource : function(sSource) {
646 var filtersArray = this._sourceFilters;
647 for(var i=0; i<filtersArray.length; i++) {
648 if(sSource == filtersArray[i]) {
649 filtersArray.splice(i, 1);
654 var elCheckbox = this.getCheckbox(sSource);
656 elCheckbox.checked = false;
661 * Does not delete any log messages, but clears all printed log messages from
662 * the console. Log messages will be printed out again if user re-filters. The
663 * static method YAHOO.widget.Logger.reset() should be called in order to
664 * actually delete log messages.
666 * @method clearConsole
668 clearConsole : function() {
669 // Clear the buffer of any pending messages
670 this._timeout = null;
672 this._consoleMsgCount = 0;
674 var elConsole = this._elConsole;
675 elConsole.innerHTML = '';
679 * Updates title to given string.
682 * @param sTitle {String} New title.
684 setTitle : function(sTitle) {
685 this._title.innerHTML = this.html2Text(sTitle);
689 * Gets timestamp of the last log.
691 * @method getLastTime
692 * @return {Date} Timestamp of the last log.
694 getLastTime : function() {
695 return this._lastTime;
698 formatMsg : function (entry) {
699 var Static = YAHOO.widget.LogReader,
700 entryFormat = this.entryFormat || (this.verboseOutput ?
701 Static.VERBOSE_TEMPLATE : Static.BASIC_TEMPLATE),
703 category : entry.category,
705 // Label for color-coded display
706 label : entry.category.substring(0,4).toUpperCase(),
708 sourceAndDetail : entry.sourceDetail ?
709 entry.source + " " + entry.sourceDetail :
712 // Escape HTML entities in the log message itself for output
714 message : this.html2Text(entry.msg || entry.message || '')
718 if (entry.time && entry.time.getTime) {
719 info.localTime = entry.time.toLocaleTimeString ?
720 entry.time.toLocaleTimeString() :
721 entry.time.toString();
723 // Calculate the elapsed time to be from the last item that
724 // passed through the filter, not the absolute previous item
726 info.elapsedTime = entry.time.getTime() - this.getLastTime();
728 info.totalTime = entry.time.getTime() -
729 YAHOO.widget.Logger.getStartTime();
732 var msg = Static.ENTRY_TEMPLATE.cloneNode(true);
733 if (this.verboseOutput) {
734 msg.className += ' yui-log-verbose';
737 msg.innerHTML = YAHOO.lang.substitute(entryFormat, info);
743 * Converts input chars "<", ">", and "&" to HTML entities.
746 * @param sHtml {String} String to convert.
749 html2Text : function(sHtml) {
752 return sHtml.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
757 /////////////////////////////////////////////////////////////////////////////
759 // Private member variables
761 /////////////////////////////////////////////////////////////////////////////
764 * Name of LogReader instance.
774 * A class member shared by all LogReaders if a container needs to be
775 * created during instantiation. Will be null if a container element never needs to
776 * be created on the fly, such as when the implementer passes in their own element.
778 * @property _elDefaultContainer
782 //YAHOO.widget.LogReader._elDefaultContainer = null;
785 * Buffer of log message objects for batch output.
794 * Number of log messages output to console.
796 * @property _consoleMsgCount
801 _consoleMsgCount : 0,
804 * Date of last output log message.
806 * @property _lastTime
813 * Batched output timeout ID.
822 * Hash of filters and their related checkbox elements.
824 * @property _filterCheckboxes
828 _filterCheckboxes : null,
831 * Array of filters for log message categories.
833 * @property _categoryFilters
837 _categoryFilters : null,
840 * Array of filters for log message sources.
842 * @property _sourceFilters
846 _sourceFilters : null,
849 * LogReader container element.
851 * @property _elContainer
858 * LogReader header element.
867 * LogReader collapse element.
869 * @property _elCollapse
876 * LogReader collapse button element.
878 * @property _btnCollapse
885 * LogReader title header element.
894 * LogReader console element.
896 * @property _elConsole
903 * LogReader footer element.
912 * LogReader buttons container element.
921 * Container element for LogReader category filter checkboxes.
923 * @property _elCategoryFilters
927 _elCategoryFilters : null,
930 * Container element for LogReader source filter checkboxes.
932 * @property _elSourceFilters
936 _elSourceFilters : null,
939 * LogReader pause button element.
941 * @property _btnPause
948 * Clear button element.
950 * @property _btnClear
956 /////////////////////////////////////////////////////////////////////////////
960 /////////////////////////////////////////////////////////////////////////////
963 * Initializes the primary container element.
965 * @method _initContainerEl
966 * @param elContainer {HTMLElement} Container element by reference or string ID.
969 _initContainerEl : function(elContainer) {
970 // Validate container
971 elContainer = YAHOO.util.Dom.get(elContainer);
972 // Attach to existing container...
973 if(elContainer && elContainer.tagName && (elContainer.tagName.toLowerCase() == "div")) {
974 this._elContainer = elContainer;
975 YAHOO.util.Dom.addClass(this._elContainer,"yui-log");
977 // ...or create container from scratch
979 this._elContainer = document.body.appendChild(document.createElement("div"));
980 //this._elContainer.id = "yui-log" + this._sName;
981 YAHOO.util.Dom.addClass(this._elContainer,"yui-log");
982 YAHOO.util.Dom.addClass(this._elContainer,"yui-log-container");
984 //YAHOO.widget.LogReader._elDefaultContainer = this._elContainer;
986 // If implementer has provided container values, trust and set those
987 var containerStyle = this._elContainer.style;
989 containerStyle.width = this.width;
992 containerStyle.right = this.right;
995 containerStyle.top = this.top;
998 containerStyle.left = this.left;
999 containerStyle.right = "auto";
1002 containerStyle.bottom = this.bottom;
1003 containerStyle.top = "auto";
1006 containerStyle.fontSize = this.fontSize;
1009 if(navigator.userAgent.toLowerCase().indexOf("opera") != -1) {
1010 document.body.style += '';
1016 * Initializes the header element.
1018 * @method _initHeaderEl
1021 _initHeaderEl : function() {
1026 // Unhook DOM events
1027 YAHOO.util.Event.purgeElement(this._elHd, true);
1029 // Remove DOM elements
1030 this._elHd.innerHTML = "";
1034 this._elHd = this._elContainer.appendChild(document.createElement("div"));
1035 this._elHd.id = "yui-log-hd" + this._sName;
1036 this._elHd.className = "yui-log-hd";
1038 this._elCollapse = this._elHd.appendChild(document.createElement("div"));
1039 this._elCollapse.className = "yui-log-btns";
1041 this._btnCollapse = document.createElement("input");
1042 this._btnCollapse.type = "button";
1043 //this._btnCollapse.style.fontSize =
1044 // YAHOO.util.Dom.getStyle(this._elContainer,"fontSize");
1045 this._btnCollapse.className = "yui-log-button";
1046 this._btnCollapse.value = "Collapse";
1047 this._btnCollapse = this._elCollapse.appendChild(this._btnCollapse);
1048 YAHOO.util.Event.addListener(
1049 oSelf._btnCollapse,'click',oSelf._onClickCollapseBtn,oSelf);
1051 this._title = this._elHd.appendChild(document.createElement("h4"));
1052 this._title.innerHTML = "Logger Console";
1056 * Initializes the console element.
1058 * @method _initConsoleEl
1061 _initConsoleEl : function() {
1063 if(this._elConsole) {
1064 // Unhook DOM events
1065 YAHOO.util.Event.purgeElement(this._elConsole, true);
1067 // Remove DOM elements
1068 this._elConsole.innerHTML = "";
1072 this._elConsole = this._elContainer.appendChild(document.createElement("div"));
1073 this._elConsole.className = "yui-log-bd";
1075 // If implementer has provided console, trust and set those
1077 this._elConsole.style.height = this.height;
1082 * Initializes the footer element.
1084 * @method _initFooterEl
1087 _initFooterEl : function() {
1090 // Don't create footer elements if footer is disabled
1091 if(this.footerEnabled) {
1094 // Unhook DOM events
1095 YAHOO.util.Event.purgeElement(this._elFt, true);
1097 // Remove DOM elements
1098 this._elFt.innerHTML = "";
1101 this._elFt = this._elContainer.appendChild(document.createElement("div"));
1102 this._elFt.className = "yui-log-ft";
1104 this._elBtns = this._elFt.appendChild(document.createElement("div"));
1105 this._elBtns.className = "yui-log-btns";
1107 this._btnPause = document.createElement("input");
1108 this._btnPause.type = "button";
1109 //this._btnPause.style.fontSize =
1110 // YAHOO.util.Dom.getStyle(this._elContainer,"fontSize");
1111 this._btnPause.className = "yui-log-button";
1112 this._btnPause.value = "Pause";
1113 this._btnPause = this._elBtns.appendChild(this._btnPause);
1114 YAHOO.util.Event.addListener(
1115 oSelf._btnPause,'click',oSelf._onClickPauseBtn,oSelf);
1117 this._btnClear = document.createElement("input");
1118 this._btnClear.type = "button";
1119 //this._btnClear.style.fontSize =
1120 // YAHOO.util.Dom.getStyle(this._elContainer,"fontSize");
1121 this._btnClear.className = "yui-log-button";
1122 this._btnClear.value = "Clear";
1123 this._btnClear = this._elBtns.appendChild(this._btnClear);
1124 YAHOO.util.Event.addListener(
1125 oSelf._btnClear,'click',oSelf._onClickClearBtn,oSelf);
1127 this._elCategoryFilters = this._elFt.appendChild(document.createElement("div"));
1128 this._elCategoryFilters.className = "yui-log-categoryfilters";
1129 this._elSourceFilters = this._elFt.appendChild(document.createElement("div"));
1130 this._elSourceFilters.className = "yui-log-sourcefilters";
1135 * Initializes Drag and Drop on the header element.
1137 * @method _initDragDrop
1140 _initDragDrop : function() {
1141 // If Drag and Drop utility is available...
1142 // ...and draggable is true...
1143 // ...then make the header draggable
1144 if(YAHOO.util.DD && this.draggable && this._elHd) {
1145 var ylog_dd = new YAHOO.util.DD(this._elContainer);
1146 ylog_dd.setHandleElId(this._elHd.id);
1147 //TODO: use class name
1148 this._elHd.style.cursor = "move";
1153 * Initializes category filters.
1155 * @method _initCategories
1158 _initCategories : function() {
1159 // Initialize category filters
1160 this._categoryFilters = [];
1161 var aInitialCategories = YAHOO.widget.Logger.categories;
1163 for(var j=0; j < aInitialCategories.length; j++) {
1164 var sCategory = aInitialCategories[j];
1166 // Add category to the internal array of filters
1167 this._categoryFilters.push(sCategory);
1169 // Add checkbox element if UI is enabled
1170 if(this._elCategoryFilters) {
1171 this._createCategoryCheckbox(sCategory);
1177 * Initializes source filters.
1179 * @method _initSources
1182 _initSources : function() {
1183 // Initialize source filters
1184 this._sourceFilters = [];
1185 var aInitialSources = YAHOO.widget.Logger.sources;
1187 for(var j=0; j < aInitialSources.length; j++) {
1188 var sSource = aInitialSources[j];
1190 // Add source to the internal array of filters
1191 this._sourceFilters.push(sSource);
1193 // Add checkbox element if UI is enabled
1194 if(this._elSourceFilters) {
1195 this._createSourceCheckbox(sSource);
1201 * Creates the UI for a category filter in the LogReader footer element.
1203 * @method _createCategoryCheckbox
1204 * @param sCategory {String} Category name.
1207 _createCategoryCheckbox : function(sCategory) {
1211 var elParent = this._elCategoryFilters;
1212 var elFilter = elParent.appendChild(document.createElement("span"));
1213 elFilter.className = "yui-log-filtergrp";
1215 // Append el at the end so IE 5.5 can set "type" attribute
1216 // and THEN set checked property
1217 var chkCategory = document.createElement("input");
1218 chkCategory.id = "yui-log-filter-" + sCategory + this._sName;
1219 chkCategory.className = "yui-log-filter-" + sCategory;
1220 chkCategory.type = "checkbox";
1221 chkCategory.category = sCategory;
1222 chkCategory = elFilter.appendChild(chkCategory);
1223 chkCategory.checked = true;
1225 // Subscribe to the click event
1226 YAHOO.util.Event.addListener(chkCategory,'click',oSelf._onCheckCategory,oSelf);
1228 // Create and class the text label
1229 var lblCategory = elFilter.appendChild(document.createElement("label"));
1230 lblCategory.htmlFor = chkCategory.id;
1231 lblCategory.className = sCategory;
1232 lblCategory.innerHTML = sCategory;
1234 this._filterCheckboxes[sCategory] = chkCategory;
1239 * Creates a checkbox in the LogReader footer element to filter by source.
1241 * @method _createSourceCheckbox
1242 * @param sSource {String} Source name.
1245 _createSourceCheckbox : function(sSource) {
1249 var elParent = this._elSourceFilters;
1250 var elFilter = elParent.appendChild(document.createElement("span"));
1251 elFilter.className = "yui-log-filtergrp";
1253 // Append el at the end so IE 5.5 can set "type" attribute
1254 // and THEN set checked property
1255 var chkSource = document.createElement("input");
1256 chkSource.id = "yui-log-filter" + sSource + this._sName;
1257 chkSource.className = "yui-log-filter" + sSource;
1258 chkSource.type = "checkbox";
1259 chkSource.source = sSource;
1260 chkSource = elFilter.appendChild(chkSource);
1261 chkSource.checked = true;
1263 // Subscribe to the click event
1264 YAHOO.util.Event.addListener(chkSource,'click',oSelf._onCheckSource,oSelf);
1266 // Create and class the text label
1267 var lblSource = elFilter.appendChild(document.createElement("label"));
1268 lblSource.htmlFor = chkSource.id;
1269 lblSource.className = sSource;
1270 lblSource.innerHTML = sSource;
1272 this._filterCheckboxes[sSource] = chkSource;
1277 * Reprints all log messages in the stack through filters.
1279 * @method _filterLogs
1282 _filterLogs : function() {
1283 // Reprint stack with new filters
1284 if (this._elConsole !== null) {
1285 this.clearConsole();
1286 this._printToConsole(YAHOO.widget.Logger.getStack());
1291 * Sends buffer of log messages to output and clears buffer.
1293 * @method _printBuffer
1296 _printBuffer : function() {
1297 this._timeout = null;
1299 if(this._elConsole !== null) {
1300 var thresholdMax = this.thresholdMax;
1301 thresholdMax = (thresholdMax && !isNaN(thresholdMax)) ? thresholdMax : 500;
1302 if(this._consoleMsgCount < thresholdMax) {
1304 for (var i=0; i<this._buffer.length; i++) {
1305 entries[i] = this._buffer[i];
1308 this._printToConsole(entries);
1314 if(!this.newestOnTop) {
1315 this._elConsole.scrollTop = this._elConsole.scrollHeight;
1321 * Cycles through an array of log messages, and outputs each one to the console
1322 * if its category has not been filtered out.
1324 * @method _printToConsole
1325 * @param aEntries {Object[]} Array of LogMsg objects to output to console.
1328 _printToConsole : function(aEntries) {
1329 // Manage the number of messages displayed in the console
1330 var entriesLen = aEntries.length,
1331 df = document.createDocumentFragment(),
1333 thresholdMin = this.thresholdMin,
1334 sourceFiltersLen = this._sourceFilters.length,
1335 categoryFiltersLen = this._categoryFilters.length,
1339 if(isNaN(thresholdMin) || (thresholdMin > this.thresholdMax)) {
1342 entriesStartIndex = (entriesLen > thresholdMin) ? (entriesLen - thresholdMin) : 0;
1344 // Iterate through all log entries
1345 for(i=entriesStartIndex; i<entriesLen; i++) {
1346 // Print only the ones that filter through
1347 var okToPrint = false;
1348 var okToFilterCats = false;
1350 // Get log message details
1351 var entry = aEntries[i];
1352 var source = entry.source;
1353 var category = entry.category;
1355 for(j=0; j<sourceFiltersLen; j++) {
1356 if(source == this._sourceFilters[j]) {
1357 okToFilterCats = true;
1361 if(okToFilterCats) {
1362 for(j=0; j<categoryFiltersLen; j++) {
1363 if(category == this._categoryFilters[j]) {
1370 msg = this.formatMsg(entry);
1371 if (typeof msg === 'string') {
1372 msgHTML[msgHTML.length] = msg;
1374 df.insertBefore(msg, this.newestOnTop ?
1375 df.firstChild || null : null);
1377 this._consoleMsgCount++;
1378 this._lastTime = entry.time.getTime();
1382 if (msgHTML.length) {
1383 msgHTML.splice(0,0,this._elConsole.innerHTML);
1384 this._elConsole.innerHTML = this.newestOnTop ?
1385 msgHTML.reverse().join('') :
1387 } else if (df.firstChild) {
1388 this._elConsole.insertBefore(df, this.newestOnTop ?
1389 this._elConsole.firstChild || null : null);
1393 /////////////////////////////////////////////////////////////////////////////
1395 // Private event handlers
1397 /////////////////////////////////////////////////////////////////////////////
1400 * Handles Logger's categoryCreateEvent.
1402 * @method _onCategoryCreate
1403 * @param sType {String} The event.
1404 * @param aArgs {Object[]} Data passed from event firer.
1405 * @param oSelf {Object} The LogReader instance.
1408 _onCategoryCreate : function(sType, aArgs, oSelf) {
1409 var category = aArgs[0];
1411 // Add category to the internal array of filters
1412 oSelf._categoryFilters.push(category);
1415 oSelf._createCategoryCheckbox(category);
1420 * Handles Logger's sourceCreateEvent.
1422 * @method _onSourceCreate
1423 * @param sType {String} The event.
1424 * @param aArgs {Object[]} Data passed from event firer.
1425 * @param oSelf {Object} The LogReader instance.
1428 _onSourceCreate : function(sType, aArgs, oSelf) {
1429 var source = aArgs[0];
1431 // Add source to the internal array of filters
1432 oSelf._sourceFilters.push(source);
1435 oSelf._createSourceCheckbox(source);
1440 * Handles check events on the category filter checkboxes.
1442 * @method _onCheckCategory
1443 * @param v {HTMLEvent} The click event.
1444 * @param oSelf {Object} The LogReader instance.
1447 _onCheckCategory : function(v, oSelf) {
1448 var category = this.category;
1450 oSelf.hideCategory(category);
1453 oSelf.showCategory(category);
1458 * Handles check events on the category filter checkboxes.
1460 * @method _onCheckSource
1461 * @param v {HTMLEvent} The click event.
1462 * @param oSelf {Object} The LogReader instance.
1465 _onCheckSource : function(v, oSelf) {
1466 var source = this.source;
1468 oSelf.hideSource(source);
1471 oSelf.showSource(source);
1476 * Handles click events on the collapse button.
1478 * @method _onClickCollapseBtn
1479 * @param v {HTMLEvent} The click event.
1480 * @param oSelf {Object} The LogReader instance
1483 _onClickCollapseBtn : function(v, oSelf) {
1484 if(!oSelf.isCollapsed) {
1493 * Handles click events on the pause button.
1495 * @method _onClickPauseBtn
1496 * @param v {HTMLEvent} The click event.
1497 * @param oSelf {Object} The LogReader instance.
1500 _onClickPauseBtn : function(v, oSelf) {
1501 if(!oSelf.isPaused) {
1510 * Handles click events on the clear button.
1512 * @method _onClickClearBtn
1513 * @param v {HTMLEvent} The click event.
1514 * @param oSelf {Object} The LogReader instance.
1517 _onClickClearBtn : function(v, oSelf) {
1518 oSelf.clearConsole();
1522 * Handles Logger's newLogEvent.
1525 * @param sType {String} The event.
1526 * @param aArgs {Object[]} Data passed from event firer.
1527 * @param oSelf {Object} The LogReader instance.
1530 _onNewLog : function(sType, aArgs, oSelf) {
1531 var logEntry = aArgs[0];
1532 oSelf._buffer.push(logEntry);
1534 if (oSelf.logReaderEnabled === true && oSelf._timeout === null) {
1535 oSelf._timeout = setTimeout(function(){oSelf._printBuffer();}, oSelf.outputBuffer);
1540 * Handles Logger's resetEvent.
1543 * @param sType {String} The event.
1544 * @param aArgs {Object[]} Data passed from event firer.
1545 * @param oSelf {Object} The LogReader instance.
1548 _onReset : function(sType, aArgs, oSelf) {
1549 oSelf._filterLogs();
1554 * The Logger widget provides a simple way to read or write log messages in
1555 * JavaScript code. Integration with the YUI Library's debug builds allow
1556 * implementers to access under-the-hood events, errors, and debugging messages.
1557 * Output may be read through a LogReader console and/or output to a browser
1561 * @requires yahoo, event, dom
1562 * @optional dragdrop
1563 * @namespace YAHOO.widget
1564 * @title Logger Widget
1567 /****************************************************************************/
1568 /****************************************************************************/
1569 /****************************************************************************/
1572 if(!YAHOO.widget.Logger) {
1574 * The singleton Logger class provides core log management functionality. Saves
1575 * logs written through the global YAHOO.log function or written by a LogWriter
1576 * instance. Provides access to logs for reading by a LogReader instance or
1577 * native browser console such as the Firebug extension to Firefox or Safari's
1578 * JavaScript console through integration with the console.log() method.
1583 YAHOO.widget.Logger = {
1584 // Initialize properties
1585 loggerEnabled: true,
1586 _browserConsoleEnabled: false,
1587 categories: ["info","warn","error","time","window"],
1588 sources: ["global"],
1589 _stack: [], // holds all log msgs
1590 maxStackEntries: 2500,
1591 _startTime: new Date().getTime(), // static start timestamp
1592 _lastTime: null, // timestamp of last logged message
1593 _windowErrorsHandled: false,
1594 _origOnWindowError: null
1597 /////////////////////////////////////////////////////////////////////////////
1599 // Public properties
1601 /////////////////////////////////////////////////////////////////////////////
1603 * True if Logger is enabled, false otherwise.
1605 * @property loggerEnabled
1612 * Array of categories.
1614 * @property categories
1617 * @default ["info","warn","error","time","window"]
1626 * @default ["global"]
1630 * Upper limit on size of internal stack.
1632 * @property maxStackEntries
1638 /////////////////////////////////////////////////////////////////////////////
1640 // Private properties
1642 /////////////////////////////////////////////////////////////////////////////
1644 * Internal property to track whether output to browser console is enabled.
1646 * @property _browserConsoleEnabled
1654 * Array to hold all log messages.
1662 * Static timestamp of Logger initialization.
1664 * @property _startTime
1670 * Timestamp of last logged message.
1672 * @property _lastTime
1677 /////////////////////////////////////////////////////////////////////////////
1681 /////////////////////////////////////////////////////////////////////////////
1683 * Saves a log message to the stack and fires newLogEvent. If the log message is
1684 * assigned to an unknown category, creates a new category. If the log message is
1685 * from an unknown source, creates a new source. If browser console is enabled,
1686 * outputs the log message to browser console.
1689 * @param sMsg {String} The log message.
1690 * @param sCategory {String} Category of log message, or null.
1691 * @param sSource {String} Source of LogWriter, or null if global.
1693 YAHOO.widget.Logger.log = function(sMsg, sCategory, sSource) {
1694 if(this.loggerEnabled) {
1696 sCategory = "info"; // default category
1699 sCategory = sCategory.toLocaleLowerCase();
1700 if(this._isNewCategory(sCategory)) {
1701 this._createNewCategory(sCategory);
1704 var sClass = "global"; // default source
1707 var spaceIndex = sSource.indexOf(" ");
1708 if(spaceIndex > 0) {
1709 // Substring until first space
1710 sClass = sSource.substring(0,spaceIndex);
1711 // The rest of the source
1712 sDetail = sSource.substring(spaceIndex,sSource.length);
1717 if(this._isNewSource(sClass)) {
1718 this._createNewSource(sClass);
1722 var timestamp = new Date();
1723 var logEntry = new YAHOO.widget.LogMsg({
1726 category: sCategory,
1728 sourceDetail: sDetail
1731 var stack = this._stack;
1732 var maxStackEntries = this.maxStackEntries;
1733 if(maxStackEntries && !isNaN(maxStackEntries) &&
1734 (stack.length >= maxStackEntries)) {
1737 stack.push(logEntry);
1738 this.newLogEvent.fire(logEntry);
1740 if(this._browserConsoleEnabled) {
1741 this._printToBrowserConsole(logEntry);
1751 * Resets internal stack and startTime, enables Logger, and fires logResetEvent.
1755 YAHOO.widget.Logger.reset = function() {
1757 this._startTime = new Date().getTime();
1758 this.loggerEnabled = true;
1759 this.log("Logger reset");
1760 this.logResetEvent.fire();
1764 * Public accessor to internal stack of log message objects.
1767 * @return {Object[]} Array of log message objects.
1769 YAHOO.widget.Logger.getStack = function() {
1774 * Public accessor to internal start time.
1776 * @method getStartTime
1777 * @return {Date} Internal date of when Logger singleton was initialized.
1779 YAHOO.widget.Logger.getStartTime = function() {
1780 return this._startTime;
1784 * Disables output to the browser's global console.log() function, which is used
1785 * by the Firebug extension to Firefox as well as Safari.
1787 * @method disableBrowserConsole
1789 YAHOO.widget.Logger.disableBrowserConsole = function() {
1790 YAHOO.log("Logger output to the function console.log() has been disabled.");
1791 this._browserConsoleEnabled = false;
1795 * Enables output to the browser's global console.log() function, which is used
1796 * by the Firebug extension to Firefox as well as Safari.
1798 * @method enableBrowserConsole
1800 YAHOO.widget.Logger.enableBrowserConsole = function() {
1801 this._browserConsoleEnabled = true;
1802 YAHOO.log("Logger output to the function console.log() has been enabled.");
1806 * Surpresses native JavaScript errors and outputs to console. By default,
1807 * Logger does not handle JavaScript window error events.
1808 * NB: Not all browsers support the window.onerror event.
1810 * @method handleWindowErrors
1812 YAHOO.widget.Logger.handleWindowErrors = function() {
1813 if(!YAHOO.widget.Logger._windowErrorsHandled) {
1814 // Save any previously defined handler to call
1816 YAHOO.widget.Logger._origOnWindowError = window.onerror;
1818 window.onerror = YAHOO.widget.Logger._onWindowError;
1819 YAHOO.widget.Logger._windowErrorsHandled = true;
1820 YAHOO.log("Logger handling of window.onerror has been enabled.");
1823 YAHOO.log("Logger handling of window.onerror had already been enabled.");
1828 * Unsurpresses native JavaScript errors. By default,
1829 * Logger does not handle JavaScript window error events.
1830 * NB: Not all browsers support the window.onerror event.
1832 * @method unhandleWindowErrors
1834 YAHOO.widget.Logger.unhandleWindowErrors = function() {
1835 if(YAHOO.widget.Logger._windowErrorsHandled) {
1836 // Revert to any previously defined handler to call
1837 if(YAHOO.widget.Logger._origOnWindowError) {
1838 window.onerror = YAHOO.widget.Logger._origOnWindowError;
1839 YAHOO.widget.Logger._origOnWindowError = null;
1842 window.onerror = null;
1844 YAHOO.widget.Logger._windowErrorsHandled = false;
1845 YAHOO.log("Logger handling of window.onerror has been disabled.");
1848 YAHOO.log("Logger handling of window.onerror had already been disabled.");
1852 /////////////////////////////////////////////////////////////////////////////
1856 /////////////////////////////////////////////////////////////////////////////
1859 * Fired when a new category has been created.
1861 * @event categoryCreateEvent
1862 * @param sCategory {String} Category name.
1864 YAHOO.widget.Logger.categoryCreateEvent =
1865 new YAHOO.util.CustomEvent("categoryCreate", this, true);
1868 * Fired when a new source has been named.
1870 * @event sourceCreateEvent
1871 * @param sSource {String} Source name.
1873 YAHOO.widget.Logger.sourceCreateEvent =
1874 new YAHOO.util.CustomEvent("sourceCreate", this, true);
1877 * Fired when a new log message has been created.
1879 * @event newLogEvent
1880 * @param sMsg {String} Log message.
1882 YAHOO.widget.Logger.newLogEvent = new YAHOO.util.CustomEvent("newLog", this, true);
1885 * Fired when the Logger has been reset has been created.
1887 * @event logResetEvent
1889 YAHOO.widget.Logger.logResetEvent = new YAHOO.util.CustomEvent("logReset", this, true);
1891 /////////////////////////////////////////////////////////////////////////////
1895 /////////////////////////////////////////////////////////////////////////////
1898 * Creates a new category of log messages and fires categoryCreateEvent.
1900 * @method _createNewCategory
1901 * @param sCategory {String} Category name.
1904 YAHOO.widget.Logger._createNewCategory = function(sCategory) {
1905 this.categories.push(sCategory);
1906 this.categoryCreateEvent.fire(sCategory);
1910 * Checks to see if a category has already been created.
1912 * @method _isNewCategory
1913 * @param sCategory {String} Category name.
1914 * @return {Boolean} Returns true if category is unknown, else returns false.
1917 YAHOO.widget.Logger._isNewCategory = function(sCategory) {
1918 for(var i=0; i < this.categories.length; i++) {
1919 if(sCategory == this.categories[i]) {
1927 * Creates a new source of log messages and fires sourceCreateEvent.
1929 * @method _createNewSource
1930 * @param sSource {String} Source name.
1933 YAHOO.widget.Logger._createNewSource = function(sSource) {
1934 this.sources.push(sSource);
1935 this.sourceCreateEvent.fire(sSource);
1939 * Checks to see if a source already exists.
1941 * @method _isNewSource
1942 * @param sSource {String} Source name.
1943 * @return {Boolean} Returns true if source is unknown, else returns false.
1946 YAHOO.widget.Logger._isNewSource = function(sSource) {
1948 for(var i=0; i < this.sources.length; i++) {
1949 if(sSource == this.sources[i]) {
1958 * Outputs a log message to global console.log() function.
1960 * @method _printToBrowserConsole
1961 * @param oEntry {Object} Log entry object.
1964 YAHOO.widget.Logger._printToBrowserConsole = function(oEntry) {
1965 if(window.console && console.log) {
1966 var category = oEntry.category;
1967 var label = oEntry.category.substring(0,4).toUpperCase();
1969 var time = oEntry.time;
1971 if (time.toLocaleTimeString) {
1972 localTime = time.toLocaleTimeString();
1975 localTime = time.toString();
1978 var msecs = time.getTime();
1979 var elapsedTime = (YAHOO.widget.Logger._lastTime) ?
1980 (msecs - YAHOO.widget.Logger._lastTime) : 0;
1981 YAHOO.widget.Logger._lastTime = msecs;
1985 elapsedTime + "ms): " +
1986 oEntry.source + ": ";
1988 console.log(output, oEntry.msg);
1992 /////////////////////////////////////////////////////////////////////////////
1994 // Private event handlers
1996 /////////////////////////////////////////////////////////////////////////////
1999 * Handles logging of messages due to window error events.
2001 * @method _onWindowError
2002 * @param sMsg {String} The error message.
2003 * @param sUrl {String} URL of the error.
2004 * @param sLine {String} Line number of the error.
2007 YAHOO.widget.Logger._onWindowError = function(sMsg,sUrl,sLine) {
2008 // Logger is not in scope of this event handler
2010 YAHOO.widget.Logger.log(sMsg+' ('+sUrl+', line '+sLine+')', "window");
2011 if(YAHOO.widget.Logger._origOnWindowError) {
2012 YAHOO.widget.Logger._origOnWindowError();
2020 /////////////////////////////////////////////////////////////////////////////
2024 /////////////////////////////////////////////////////////////////////////////
2026 YAHOO.widget.Logger.log("Logger initialized");
2030 YAHOO.register("logger", YAHOO.widget.Logger, {version: "2.5.2", build: "1076"});