NOBUG: Fixed file access permissions
[moodle.git] / lib / yuilib / 3.13.0 / console / console.js
blob4158de3d510474455764dbb36c18e9756a589f5d
1 /*
2 YUI 3.13.0 (build 508226d)
3 Copyright 2013 Yahoo! Inc. All rights reserved.
4 Licensed under the BSD License.
5 http://yuilibrary.com/license/
6 */
8 YUI.add('console', function (Y, NAME) {
10 /**
11  * Console creates a visualization for messages logged through calls to a YUI
12  * instance's <code>Y.log( message, category, source )</code> method.  The
13  * debug versions of YUI modules will include logging statements to offer some
14  * insight into the steps executed during that module's operation.  Including
15  * log statements in your code will cause those messages to also appear in the
16  * Console.  Use Console to aid in developing your page or application.
17  *
18  * Entry categories &quot;info&quot;, &quot;warn&quot;, and &quot;error&quot;
19  * are also referred to as the log level, and entries are filtered against the
20  * configured logLevel.
21  *
22  * @module console
23  */
24 var getCN = Y.ClassNameManager.getClassName,
25     CHECKED        = 'checked',
26     CLEAR          = 'clear',
27     CLICK          = 'click',
28     COLLAPSED      = 'collapsed',
29     CONSOLE        = 'console',
30     CONTENT_BOX    = 'contentBox',
31     DISABLED       = 'disabled',
32     ENTRY          = 'entry',
33     ERROR          = 'error',
34     HEIGHT         = 'height',
35     INFO           = 'info',
36     LAST_TIME      = 'lastTime',
37     PAUSE          = 'pause',
38     PAUSED         = 'paused',
39     RESET          = 'reset',
40     START_TIME     = 'startTime',
41     TITLE          = 'title',
42     WARN           = 'warn',
44     DOT = '.',
46     C_BUTTON           = getCN(CONSOLE,'button'),
47     C_CHECKBOX         = getCN(CONSOLE,'checkbox'),
48     C_CLEAR            = getCN(CONSOLE,CLEAR),
49     C_COLLAPSE         = getCN(CONSOLE,'collapse'),
50     C_COLLAPSED        = getCN(CONSOLE,COLLAPSED),
51     C_CONSOLE_CONTROLS = getCN(CONSOLE,'controls'),
52     C_CONSOLE_HD       = getCN(CONSOLE,'hd'),
53     C_CONSOLE_BD       = getCN(CONSOLE,'bd'),
54     C_CONSOLE_FT       = getCN(CONSOLE,'ft'),
55     C_CONSOLE_TITLE    = getCN(CONSOLE,TITLE),
56     C_ENTRY            = getCN(CONSOLE,ENTRY),
57     C_ENTRY_CAT        = getCN(CONSOLE,ENTRY,'cat'),
58     C_ENTRY_CONTENT    = getCN(CONSOLE,ENTRY,'content'),
59     C_ENTRY_META       = getCN(CONSOLE,ENTRY,'meta'),
60     C_ENTRY_SRC        = getCN(CONSOLE,ENTRY,'src'),
61     C_ENTRY_TIME       = getCN(CONSOLE,ENTRY,'time'),
62     C_PAUSE            = getCN(CONSOLE,PAUSE),
63     C_PAUSE_LABEL      = getCN(CONSOLE,PAUSE,'label'),
65     RE_INLINE_SOURCE = /^(\S+)\s/,
66     RE_AMP = /&(?!#?[a-z0-9]+;)/g,
67     RE_GT  = />/g,
68     RE_LT  = /</g,
70     ESC_AMP = '&#38;',
71     ESC_GT  = '&#62;',
72     ESC_LT  = '&#60;',
74     ENTRY_TEMPLATE_STR =
75         '<div class="{entry_class} {cat_class} {src_class}">'+
76             '<p class="{entry_meta_class}">'+
77                 '<span class="{entry_src_class}">'+
78                     '{sourceAndDetail}'+
79                 '</span>'+
80                 '<span class="{entry_cat_class}">'+
81                     '{category}</span>'+
82                 '<span class="{entry_time_class}">'+
83                     ' {totalTime}ms (+{elapsedTime}) {localTime}'+
84                 '</span>'+
85             '</p>'+
86             '<pre class="{entry_content_class}">{message}</pre>'+
87         '</div>',
89     L = Y.Lang,
90     create     = Y.Node.create,
91     isNumber   = L.isNumber,
92     isString   = L.isString,
93     merge      = Y.merge,
94     substitute = Y.Lang.sub;
96 /**
97 A basic console that displays messages logged throughout your application.
99 @class Console
100 @constructor
101 @extends Widget
102 @param [config] {Object} Object literal specifying widget configuration properties.
104 function Console() {
105     Console.superclass.constructor.apply(this,arguments);
108 Y.Console = Y.extend(Console, Y.Widget,
110 // Y.Console prototype
112     /**
113      * Category to prefix all event subscriptions to allow for ease of detach
114      * during destroy.
115      *
116      * @property _evtCat
117      * @type string
118      * @protected
119      */
120     _evtCat : null,
122     /**
123      * Reference to the Node instance containing the header contents.
124      *
125      * @property _head
126      * @type Node
127      * @default null
128      * @protected
129      */
130     _head    : null,
132     /**
133      * Reference to the Node instance that will house the console messages.
134      *
135      * @property _body
136      * @type Node
137      * @default null
138      * @protected
139      */
140     _body    : null,
142     /**
143      * Reference to the Node instance containing the footer contents.
144      *
145      * @property _foot
146      * @type Node
147      * @default null
148      * @protected
149      */
150     _foot    : null,
152     /**
153      * Holds the object API returned from <code>Y.later</code> for the print
154      * loop interval.
155      *
156      * @property _printLoop
157      * @type Object
158      * @default null
159      * @protected
160      */
161     _printLoop : null,
163     /**
164      * Array of normalized message objects awaiting printing.
165      *
166      * @property buffer
167      * @type Array
168      * @default null
169      * @protected
170      */
171     buffer   : null,
173     /**
174      * Wrapper for <code>Y.log</code>.
175      *
176      * @method log
177      * @param arg* {MIXED} (all arguments passed through to <code>Y.log</code>)
178      * @chainable
179      */
180     log : function () {
181         Y.log.apply(Y,arguments);
183         return this;
184     },
186     /**
187      * Clear the console of messages and flush the buffer of pending messages.
188      *
189      * @method clearConsole
190      * @chainable
191      */
192     clearConsole : function () {
193         // TODO: clear event listeners from console contents
194         this._body.empty();
196         this._cancelPrintLoop();
198         this.buffer = [];
200         return this;
201     },
203     /**
204      * Clears the console and resets internal timers.
205      *
206      * @method reset
207      * @chainable
208      */
209     reset : function () {
210         this.fire(RESET);
212         return this;
213     },
215     /**
216      * Collapses the body and footer.
217      *
218      * @method collapse
219      * @chainable
220      */
221     collapse : function () {
222         this.set(COLLAPSED, true);
224         return this;
225     },
227     /**
228      * Expands the body and footer if collapsed.
229      *
230      * @method expand
231      * @chainable
232      */
233     expand : function () {
234         this.set(COLLAPSED, false);
236         return this;
237     },
239     /**
240      * Outputs buffered messages to the console UI.  This is typically called
241      * from a scheduled interval until the buffer is empty (referred to as the
242      * print loop).  The number of buffered messages output to the Console is
243      * limited to the number provided as an argument.  If no limit is passed,
244      * all buffered messages are rendered.
245      *
246      * @method printBuffer
247      * @param limit {Number} (optional) max number of buffered entries to write
248      * @chainable
249      */
250     printBuffer: function (limit) {
251         var messages    = this.buffer,
252             debug       = Y.config.debug,
253             entries     = [],
254             consoleLimit= this.get('consoleLimit'),
255             newestOnTop = this.get('newestOnTop'),
256             anchor      = newestOnTop ? this._body.get('firstChild') : null,
257             i;
259         if (messages.length > consoleLimit) {
260             messages.splice(0, messages.length - consoleLimit);
261         }
263         limit = Math.min(messages.length, (limit || messages.length));
265         // turn off logging system
266         Y.config.debug = false;
268         if (!this.get(PAUSED) && this.get('rendered')) {
270             for (i = 0; i < limit && messages.length; ++i) {
271                 entries[i] = this._createEntryHTML(messages.shift());
272             }
274             if (!messages.length) {
275                 this._cancelPrintLoop();
276             }
278             if (entries.length) {
279                 if (newestOnTop) {
280                     entries.reverse();
281                 }
283                 this._body.insertBefore(create(entries.join('')), anchor);
285                 if (this.get('scrollIntoView')) {
286                     this.scrollToLatest();
287                 }
289                 this._trimOldEntries();
290             }
291         }
293         // restore logging system
294         Y.config.debug = debug;
296         return this;
297     },
300     /**
301      * Constructor code.  Set up the buffer and entry template, publish
302      * internal events, and subscribe to the configured logEvent.
303      *
304      * @method initializer
305      * @protected
306      */
307     initializer : function () {
308         this._evtCat = Y.stamp(this) + '|';
310         this.buffer = [];
312         this.get('logSource').on(this._evtCat +
313             this.get('logEvent'),Y.bind("_onLogEvent",this));
315         /**
316          * Transfers a received message to the print loop buffer.  Default
317          * behavior defined in _defEntryFn.
318          *
319          * @event entry
320          * @param event {Event.Facade} An Event Facade object with the following attribute specific properties added:
321          *  <dl>
322          *      <dt>message</dt>
323          *          <dd>The message data normalized into an object literal (see _normalizeMessage)</dd>
324          *  </dl>
325          * @preventable _defEntryFn
326          */
327         this.publish(ENTRY, { defaultFn: this._defEntryFn });
329         /**
330          * Triggers the reset behavior via the default logic in _defResetFn.
331          *
332          * @event reset
333          * @param event {Event.Facade} Event Facade object
334          * @preventable _defResetFn
335          */
336         this.publish(RESET, { defaultFn: this._defResetFn });
338         this.after('rendered', this._schedulePrint);
339     },
341     /**
342      * Tears down the instance, flushing event subscriptions and purging the UI.
343      *
344      * @method destructor
345      * @protected
346      */
347     destructor : function () {
348         var bb = this.get('boundingBox');
350         this._cancelPrintLoop();
352         this.get('logSource').detach(this._evtCat + '*');
354         bb.purge(true);
355     },
357     /**
358      * Generate the Console UI.
359      *
360      * @method renderUI
361      * @protected
362      */
363     renderUI : function () {
364         this._initHead();
365         this._initBody();
366         this._initFoot();
368         // Apply positioning to the bounding box if appropriate
369         var style = this.get('style');
370         if (style !== 'block') {
371             this.get('boundingBox').addClass(this.getClassName(style));
372         }
373     },
375     /**
376      * Sync the UI state to the current attribute state.
377      *
378      * @method syncUI
379      */
380     syncUI : function () {
381         this._uiUpdatePaused(this.get(PAUSED));
382         this._uiUpdateCollapsed(this.get(COLLAPSED));
383         this._uiSetHeight(this.get(HEIGHT));
384     },
386     /**
387      * Set up event listeners to wire up the UI to the internal state.
388      *
389      * @method bindUI
390      * @protected
391      */
392     bindUI : function () {
393         this.get(CONTENT_BOX).one('button.'+C_COLLAPSE).
394             on(CLICK,this._onCollapseClick,this);
396         this.get(CONTENT_BOX).one('input[type=checkbox].'+C_PAUSE).
397             on(CLICK,this._onPauseClick,this);
399         this.get(CONTENT_BOX).one('button.'+C_CLEAR).
400             on(CLICK,this._onClearClick,this);
402         // Attribute changes
403         this.after(this._evtCat + 'stringsChange',
404             this._afterStringsChange);
405         this.after(this._evtCat + 'pausedChange',
406             this._afterPausedChange);
407         this.after(this._evtCat + 'consoleLimitChange',
408             this._afterConsoleLimitChange);
409         this.after(this._evtCat + 'collapsedChange',
410             this._afterCollapsedChange);
411     },
414     /**
415      * Create the DOM structure for the header elements.
416      *
417      * @method _initHead
418      * @protected
419      */
420     _initHead : function () {
421         var cb   = this.get(CONTENT_BOX),
422             info = merge(Console.CHROME_CLASSES, {
423                         str_collapse : this.get('strings.collapse'),
424                         str_title : this.get('strings.title')
425                     });
427         this._head = create(substitute(Console.HEADER_TEMPLATE,info));
429         cb.insertBefore(this._head,cb.get('firstChild'));
430     },
432     /**
433      * Create the DOM structure for the console body&#8212;where messages are
434      * rendered.
435      *
436      * @method _initBody
437      * @protected
438      */
439     _initBody : function () {
440         this._body = create(substitute(
441                             Console.BODY_TEMPLATE,
442                             Console.CHROME_CLASSES));
444         this.get(CONTENT_BOX).appendChild(this._body);
445     },
447     /**
448      * Create the DOM structure for the footer elements.
449      *
450      * @method _initFoot
451      * @protected
452      */
453     _initFoot : function () {
454         var info = merge(Console.CHROME_CLASSES, {
455                 id_guid   : Y.guid(),
456                 str_pause : this.get('strings.pause'),
457                 str_clear : this.get('strings.clear')
458             });
460         this._foot = create(substitute(Console.FOOTER_TEMPLATE,info));
462         this.get(CONTENT_BOX).appendChild(this._foot);
463     },
465     /**
466      * Determine if incoming log messages are within the configured logLevel
467      * to be buffered for printing.
468      *
469      * @method _isInLogLevel
470      * @protected
471      */
472     _isInLogLevel : function (e) {
473         var cat = e.cat, lvl = this.get('logLevel');
475         if (lvl !== INFO) {
476             cat = cat || INFO;
478             if (isString(cat)) {
479                 cat = cat.toLowerCase();
480             }
482             if ((cat === WARN && lvl === ERROR) ||
483                 (cat === INFO && lvl !== INFO)) {
484                 return false;
485             }
486         }
488         return true;
489     },
491     /**
492      * Create a log entry message from the inputs including the following keys:
493      * <ul>
494      *     <li>time - this moment</li>
495      *     <li>message - leg message</li>
496      *     <li>category - logLevel or custom category for the message</li>
497      *     <li>source - when provided, the widget or util calling Y.log</li>
498      *     <li>sourceAndDetail - same as source but can include instance info</li>
499      *     <li>localTime - readable version of time</li>
500      *     <li>elapsedTime - ms since last entry</li>
501      *     <li>totalTime - ms since Console was instantiated or reset</li>
502      * </ul>
503      *
504      * @method _normalizeMessage
505      * @param e {Event} custom event containing the log message
506      * @return Object the message object
507      * @protected
508      */
509     _normalizeMessage : function (e) {
511         var msg = e.msg,
512             cat = e.cat,
513             src = e.src,
515             m = {
516                 time            : new Date(),
517                 message         : msg,
518                 category        : cat || this.get('defaultCategory'),
519                 sourceAndDetail : src || this.get('defaultSource'),
520                 source          : null,
521                 localTime       : null,
522                 elapsedTime     : null,
523                 totalTime       : null
524             };
526         // Extract m.source "Foo" from m.sourceAndDetail "Foo bar baz"
527         m.source          = RE_INLINE_SOURCE.test(m.sourceAndDetail) ?
528                                 RegExp.$1 : m.sourceAndDetail;
529         m.localTime       = m.time.toLocaleTimeString ?
530                             m.time.toLocaleTimeString() : (m.time + '');
531         m.elapsedTime     = m.time - this.get(LAST_TIME);
532         m.totalTime       = m.time - this.get(START_TIME);
534         this._set(LAST_TIME,m.time);
536         return m;
537     },
539     /**
540      * Sets an interval for buffered messages to be output to the console.
541      *
542      * @method _schedulePrint
543      * @protected
544      */
545     _schedulePrint : function () {
546         if (!this._printLoop && !this.get(PAUSED) && this.get('rendered')) {
547             this._printLoop = Y.later(
548                                 this.get('printTimeout'),
549                                 this, this.printBuffer,
550                                 this.get('printLimit'), true);
551         }
552     },
554     /**
555      * Translates message meta into the markup for a console entry.
556      *
557      * @method _createEntryHTML
558      * @param m {Object} object literal containing normalized message metadata
559      * @return String
560      * @protected
561      */
562     _createEntryHTML : function (m) {
563         m = merge(
564                 this._htmlEscapeMessage(m),
565                 Console.ENTRY_CLASSES,
566                 {
567                     cat_class : this.getClassName(ENTRY,m.category),
568                     src_class : this.getClassName(ENTRY,m.source)
569                 });
571         return this.get('entryTemplate').replace(/\{(\w+)\}/g,
572             function (_,token) {
573                 return token in m ? m[token] : '';
574             });
575     },
577     /**
578      * Scrolls to the most recent entry
579      *
580      * @method scrollToLatest
581      * @chainable
582      */
583     scrollToLatest : function () {
584         var scrollTop = this.get('newestOnTop') ?
585                             0 :
586                             this._body.get('scrollHeight');
588         this._body.set('scrollTop', scrollTop);
589     },
591     /**
592      * Performs HTML escaping on strings in the message object.
593      *
594      * @method _htmlEscapeMessage
595      * @param m {Object} the normalized message object
596      * @return Object the message object with proper escapement
597      * @protected
598      */
599     _htmlEscapeMessage : function (m) {
600         m.message         = this._encodeHTML(m.message);
601         m.source          = this._encodeHTML(m.source);
602         m.sourceAndDetail = this._encodeHTML(m.sourceAndDetail);
603         m.category        = this._encodeHTML(m.category);
605         return m;
606     },
608     /**
609      * Removes the oldest message entries from the UI to maintain the limit
610      * specified in the consoleLimit configuration.
611      *
612      * @method _trimOldEntries
613      * @protected
614      */
615     _trimOldEntries : function () {
616         // Turn off the logging system for the duration of this operation
617         // to prevent an infinite loop
618         Y.config.debug = false;
620         var bd = this._body,
621             limit = this.get('consoleLimit'),
622             debug = Y.config.debug,
623             entries,e,i,l;
625         if (bd) {
626             entries = bd.all(DOT+C_ENTRY);
627             l = entries.size() - limit;
629             if (l > 0) {
630                 if (this.get('newestOnTop')) {
631                     i = limit;
632                     l = entries.size();
633                 } else {
634                     i = 0;
635                 }
637                 this._body.setStyle('display','none');
639                 for (;i < l; ++i) {
640                     e = entries.item(i);
641                     if (e) {
642                         e.remove();
643                     }
644                 }
646                 this._body.setStyle('display','');
647             }
649         }
651         Y.config.debug = debug;
652     },
654     /**
655      * Returns the input string with ampersands (&amp;), &lt, and &gt; encoded
656      * as HTML entities.
657      *
658      * @method _encodeHTML
659      * @param s {String} the raw string
660      * @return String the encoded string
661      * @protected
662      */
663     _encodeHTML : function (s) {
664         return isString(s) ?
665             s.replace(RE_AMP,ESC_AMP).
666               replace(RE_LT, ESC_LT).
667               replace(RE_GT, ESC_GT) :
668             s;
669     },
671     /**
672      * Clears the timeout for printing buffered messages.
673      *
674      * @method _cancelPrintLoop
675      * @protected
676      */
677     _cancelPrintLoop : function () {
678         if (this._printLoop) {
679             this._printLoop.cancel();
680             this._printLoop = null;
681         }
682     },
684     /**
685      * Validates input value for style attribute.  Accepts only values 'inline',
686      * 'block', and 'separate'.
687      *
688      * @method _validateStyle
689      * @param style {String} the proposed value
690      * @return {Boolean} pass/fail
691      * @protected
692      */
693     _validateStyle : function (style) {
694         return style === 'inline' || style === 'block' || style === 'separate';
695     },
697     /**
698      * Event handler for clicking on the Pause checkbox to update the paused
699      * attribute.
700      *
701      * @method _onPauseClick
702      * @param e {Event} DOM event facade for the click event
703      * @protected
704      */
705     _onPauseClick : function (e) {
706         this.set(PAUSED,e.target.get(CHECKED));
707     },
709     /**
710      * Event handler for clicking on the Clear button.  Pass-through to
711      * <code>this.clearConsole()</code>.
712      *
713      * @method _onClearClick
714      * @param e {Event} DOM event facade for the click event
715      * @protected
716      */
717     _onClearClick : function (e) {
718         this.clearConsole();
719     },
721     /**
722      * Event handler for clicking on the Collapse/Expand button. Sets the
723      * &quot;collapsed&quot; attribute accordingly.
724      *
725      * @method _onCollapseClick
726      * @param e {Event} DOM event facade for the click event
727      * @protected
728      */
729     _onCollapseClick : function (e) {
730         this.set(COLLAPSED, !this.get(COLLAPSED));
731     },
734     /**
735      * Validator for logSource attribute.
736      *
737      * @method _validateLogSource
738      * @param v {Object} the desired logSource
739      * @return {Boolean} true if the input is an object with an <code>on</code>
740      *                   method
741      * @protected
742      */
743     _validateLogSource: function (v) {
744         return v && Y.Lang.isFunction(v.on);
745     },
747     /**
748      * Setter method for logLevel attribute.  Acceptable values are
749      * &quot;error&quot, &quot;warn&quot, and &quot;info&quot (case
750      * insensitive).  Other values are treated as &quot;info&quot;.
751      *
752      * @method _setLogLevel
753      * @param v {String} the desired log level
754      * @return String One of Console.LOG_LEVEL_INFO, _WARN, or _ERROR
755      * @protected
756      */
757     _setLogLevel : function (v) {
758         if (isString(v)) {
759             v = v.toLowerCase();
760         }
762         return (v === WARN || v === ERROR) ? v : INFO;
763     },
765     /**
766      * Getter method for useBrowserConsole attribute.  Just a pass through to
767      * the YUI instance configuration setting.
768      *
769      * @method _getUseBrowserConsole
770      * @return {Boolean} or null if logSource is not a YUI instance
771      * @protected
772      */
773     _getUseBrowserConsole: function () {
774         var logSource = this.get('logSource');
775         return logSource instanceof YUI ?
776             logSource.config.useBrowserConsole : null;
777     },
779     /**
780      * Setter method for useBrowserConsole attributes.  Only functional if the
781      * logSource attribute points to a YUI instance.  Passes the value down to
782      * the YUI instance.  NOTE: multiple Console instances cannot maintain
783      * independent useBrowserConsole values, since it is just a pass through to
784      * the YUI instance configuration.
785      *
786      * @method _setUseBrowserConsole
787      * @param v {Boolean} false to disable browser console printing (default)
788      * @return {Boolean} true|false if logSource is a YUI instance
789      * @protected
790      */
791     _setUseBrowserConsole: function (v) {
792         var logSource = this.get('logSource');
793         if (logSource instanceof YUI) {
794             v = !!v;
795             logSource.config.useBrowserConsole = v;
796             return v;
797         } else {
798             return Y.Attribute.INVALID_VALUE;
799         }
800     },
802     /**
803      * Set the height of the Console container.  Set the body height to the
804      * difference between the configured height and the calculated heights of
805      * the header and footer.
806      * Overrides Widget.prototype._uiSetHeight.
807      *
808      * @method _uiSetHeight
809      * @param v {String|Number} the new height
810      * @protected
811      */
812     _uiSetHeight : function (v) {
813         Console.superclass._uiSetHeight.apply(this,arguments);
815         if (this._head && this._foot) {
816             var h = this.get('boundingBox').get('offsetHeight') -
817                     this._head.get('offsetHeight') -
818                     this._foot.get('offsetHeight');
820             this._body.setStyle(HEIGHT,h+'px');
821         }
822     },
824     /**
825      * Over-ride default content box sizing to do nothing, since we're sizing
826      * the body section to fill out height ourselves.
827      *
828      * @method _uiSizeCB
829      * @protected
830      */
831     _uiSizeCB : function() {
832         // Do Nothing. Ideally want to move to Widget-StdMod, which accounts for
833         // _uiSizeCB
834     },
836     /**
837      * Updates the UI if changes are made to any of the strings in the strings
838      * attribute.
839      *
840      * @method _afterStringsChange
841      * @param e {Event} Custom event for the attribute change
842      * @protected
843      */
844     _afterStringsChange : function (e) {
845         var prop   = e.subAttrName ? e.subAttrName.split(DOT)[1] : null,
846             cb     = this.get(CONTENT_BOX),
847             before = e.prevVal,
848             after  = e.newVal;
850         if ((!prop || prop === TITLE) && before.title !== after.title) {
851             cb.all(DOT+C_CONSOLE_TITLE).setHTML(after.title);
852         }
854         if ((!prop || prop === PAUSE) && before.pause !== after.pause) {
855             cb.all(DOT+C_PAUSE_LABEL).setHTML(after.pause);
856         }
858         if ((!prop || prop === CLEAR) && before.clear !== after.clear) {
859             cb.all(DOT+C_CLEAR).set('value',after.clear);
860         }
861     },
863     /**
864      * Updates the UI and schedules or cancels the print loop.
865      *
866      * @method _afterPausedChange
867      * @param e {Event} Custom event for the attribute change
868      * @protected
869      */
870     _afterPausedChange : function (e) {
871         var paused = e.newVal;
873         if (e.src !== Y.Widget.SRC_UI) {
874             this._uiUpdatePaused(paused);
875         }
877         if (!paused) {
878             this._schedulePrint();
879         } else if (this._printLoop) {
880             this._cancelPrintLoop();
881         }
882     },
884     /**
885      * Checks or unchecks the paused checkbox
886      *
887      * @method _uiUpdatePaused
888      * @param on {Boolean} the new checked state
889      * @protected
890      */
891     _uiUpdatePaused : function (on) {
892         var node = this._foot.all('input[type=checkbox].'+C_PAUSE);
894         if (node) {
895             node.set(CHECKED,on);
896         }
897     },
899     /**
900      * Calls this._trimOldEntries() in response to changes in the configured
901      * consoleLimit attribute.
902      *
903      * @method _afterConsoleLimitChange
904      * @param e {Event} Custom event for the attribute change
905      * @protected
906      */
907     _afterConsoleLimitChange : function () {
908         this._trimOldEntries();
909     },
912     /**
913      * Updates the className of the contentBox, which should trigger CSS to
914      * hide or show the body and footer sections depending on the new value.
915      *
916      * @method _afterCollapsedChange
917      * @param e {Event} Custom event for the attribute change
918      * @protected
919      */
920     _afterCollapsedChange : function (e) {
921         this._uiUpdateCollapsed(e.newVal);
922     },
924     /**
925      * Updates the UI to reflect the new Collapsed state
926      *
927      * @method _uiUpdateCollapsed
928      * @param v {Boolean} true for collapsed, false for expanded
929      * @protected
930      */
931     _uiUpdateCollapsed : function (v) {
932         var bb     = this.get('boundingBox'),
933             button = bb.all('button.'+C_COLLAPSE),
934             method = v ? 'addClass' : 'removeClass',
935             str    = this.get('strings.'+(v ? 'expand' : 'collapse'));
937         bb[method](C_COLLAPSED);
939         if (button) {
940             button.setHTML(str);
941         }
943         this._uiSetHeight(v ? this._head.get('offsetHeight'): this.get(HEIGHT));
944     },
946     /**
947      * Makes adjustments to the UI if needed when the Console is hidden or shown
948      *
949      * @method _afterVisibleChange
950      * @param e {Event} the visibleChange event
951      * @protected
952      */
953     _afterVisibleChange : function (e) {
954         Console.superclass._afterVisibleChange.apply(this,arguments);
956         this._uiUpdateFromHideShow(e.newVal);
957     },
959     /**
960      * Recalculates dimensions and updates appropriately when shown
961      *
962      * @method _uiUpdateFromHideShow
963      * @param v {Boolean} true for visible, false for hidden
964      * @protected
965      */
966     _uiUpdateFromHideShow : function (v) {
967         if (v) {
968             this._uiSetHeight(this.get(HEIGHT));
969         }
970     },
972     /**
973      * Responds to log events by normalizing qualifying messages and passing
974      * them along through the entry event for buffering etc.
975      *
976      * @method _onLogEvent
977      * @param msg {String} the log message
978      * @param cat {String} OPTIONAL the category or logLevel of the message
979      * @param src {String} OPTIONAL the source of the message (e.g. widget name)
980      * @protected
981      */
982     _onLogEvent : function (e) {
984         if (!this.get(DISABLED) && this._isInLogLevel(e)) {
986             var debug = Y.config.debug;
988             /* TODO: needed? */
989             Y.config.debug = false;
991             this.fire(ENTRY, {
992                 message : this._normalizeMessage(e)
993             });
995             Y.config.debug = debug;
996         }
997     },
999     /**
1000      * Clears the console, resets the startTime attribute, enables and
1001      * unpauses the widget.
1002      *
1003      * @method _defResetFn
1004      * @protected
1005      */
1006     _defResetFn : function () {
1007         this.clearConsole();
1008         this.set(START_TIME,new Date());
1009         this.set(DISABLED,false);
1010         this.set(PAUSED,false);
1011     },
1013     /**
1014      * Buffers incoming message objects and schedules the printing.
1015      *
1016      * @method _defEntryFn
1017      * @param e {Event} The Custom event carrying the message in its payload
1018      * @protected
1019      */
1020     _defEntryFn : function (e) {
1021         if (e.message) {
1022             this.buffer.push(e.message);
1023             this._schedulePrint();
1024         }
1025     }
1029 // Y.Console static properties
1031     /**
1032      * The identity of the widget.
1033      *
1034      * @property NAME
1035      * @type String
1036      * @static
1037      */
1038     NAME : CONSOLE,
1040     /**
1041      * Static identifier for logLevel configuration setting to allow all
1042      * incoming messages to generate Console entries.
1043      *
1044      * @property LOG_LEVEL_INFO
1045      * @type String
1046      * @static
1047      */
1048     LOG_LEVEL_INFO  : INFO,
1050     /**
1051      * Static identifier for logLevel configuration setting to allow only
1052      * incoming messages of logLevel &quot;warn&quot; or &quot;error&quot;
1053      * to generate Console entries.
1054      *
1055      * @property LOG_LEVEL_WARN
1056      * @type String
1057      * @static
1058      */
1059     LOG_LEVEL_WARN  : WARN,
1061     /**
1062      * Static identifier for logLevel configuration setting to allow only
1063      * incoming messages of logLevel &quot;error&quot; to generate
1064      * Console entries.
1065      *
1066      * @property LOG_LEVEL_ERROR
1067      * @type String
1068      * @static
1069      */
1070     LOG_LEVEL_ERROR : ERROR,
1072     /**
1073      * Map (object) of classNames used to populate the placeholders in the
1074      * Console.ENTRY_TEMPLATE markup when rendering a new Console entry.
1075      *
1076      * <p>By default, the keys contained in the object are:</p>
1077      * <ul>
1078      *    <li>entry_class</li>
1079      *    <li>entry_meta_class</li>
1080      *    <li>entry_cat_class</li>
1081      *    <li>entry_src_class</li>
1082      *    <li>entry_time_class</li>
1083      *    <li>entry_content_class</li>
1084      * </ul>
1085      *
1086      * @property ENTRY_CLASSES
1087      * @type Object
1088      * @static
1089      */
1090     ENTRY_CLASSES   : {
1091         entry_class         : C_ENTRY,
1092         entry_meta_class    : C_ENTRY_META,
1093         entry_cat_class     : C_ENTRY_CAT,
1094         entry_src_class     : C_ENTRY_SRC,
1095         entry_time_class    : C_ENTRY_TIME,
1096         entry_content_class : C_ENTRY_CONTENT
1097     },
1099     /**
1100      * Map (object) of classNames used to populate the placeholders in the
1101      * Console.HEADER_TEMPLATE, Console.BODY_TEMPLATE, and
1102      * Console.FOOTER_TEMPLATE markup when rendering the Console UI.
1103      *
1104      * <p>By default, the keys contained in the object are:</p>
1105      * <ul>
1106      *   <li>console_hd_class</li>
1107      *   <li>console_bd_class</li>
1108      *   <li>console_ft_class</li>
1109      *   <li>console_controls_class</li>
1110      *   <li>console_checkbox_class</li>
1111      *   <li>console_pause_class</li>
1112      *   <li>console_pause_label_class</li>
1113      *   <li>console_button_class</li>
1114      *   <li>console_clear_class</li>
1115      *   <li>console_collapse_class</li>
1116      *   <li>console_title_class</li>
1117      * </ul>
1118      *
1119      * @property CHROME_CLASSES
1120      * @type Object
1121      * @static
1122      */
1123     CHROME_CLASSES  : {
1124         console_hd_class       : C_CONSOLE_HD,
1125         console_bd_class       : C_CONSOLE_BD,
1126         console_ft_class       : C_CONSOLE_FT,
1127         console_controls_class : C_CONSOLE_CONTROLS,
1128         console_checkbox_class : C_CHECKBOX,
1129         console_pause_class    : C_PAUSE,
1130         console_pause_label_class : C_PAUSE_LABEL,
1131         console_button_class   : C_BUTTON,
1132         console_clear_class    : C_CLEAR,
1133         console_collapse_class : C_COLLAPSE,
1134         console_title_class    : C_CONSOLE_TITLE
1135     },
1137     /**
1138      * Markup template used to generate the DOM structure for the header
1139      * section of the Console when it is rendered.  The template includes
1140      * these {placeholder}s:
1141      *
1142      * <ul>
1143      *   <li>console_button_class - contributed by Console.CHROME_CLASSES</li>
1144      *   <li>console_collapse_class - contributed by Console.CHROME_CLASSES</li>
1145      *   <li>console_hd_class - contributed by Console.CHROME_CLASSES</li>
1146      *   <li>console_title_class - contributed by Console.CHROME_CLASSES</li>
1147      *   <li>str_collapse - pulled from attribute strings.collapse</li>
1148      *   <li>str_title - pulled from attribute strings.title</li>
1149      * </ul>
1150      *
1151      * @property HEADER_TEMPLATE
1152      * @type String
1153      * @static
1154      */
1155     HEADER_TEMPLATE :
1156         '<div class="{console_hd_class}">'+
1157             '<h4 class="{console_title_class}">{str_title}</h4>'+
1158             '<button type="button" class="'+
1159                 '{console_button_class} {console_collapse_class}">{str_collapse}'+
1160             '</button>'+
1161         '</div>',
1163     /**
1164      * Markup template used to generate the DOM structure for the Console body
1165      * (where the messages are inserted) when it is rendered.  The template
1166      * includes only the {placeholder} &quot;console_bd_class&quot;, which is
1167      * constributed by Console.CHROME_CLASSES.
1168      *
1169      * @property BODY_TEMPLATE
1170      * @type String
1171      * @static
1172      */
1173     BODY_TEMPLATE : '<div class="{console_bd_class}"></div>',
1175     /**
1176      * Markup template used to generate the DOM structure for the footer
1177      * section of the Console when it is rendered.  The template includes
1178      * many of the {placeholder}s from Console.CHROME_CLASSES as well as:
1179      *
1180      * <ul>
1181      *   <li>id_guid - generated unique id, relates the label and checkbox</li>
1182      *   <li>str_pause - pulled from attribute strings.pause</li>
1183      *   <li>str_clear - pulled from attribute strings.clear</li>
1184      * </ul>
1185      *
1186      * @property FOOTER_TEMPLATE
1187      * @type String
1188      * @static
1189      */
1190     FOOTER_TEMPLATE :
1191         '<div class="{console_ft_class}">'+
1192             '<div class="{console_controls_class}">'+
1193                 '<label class="{console_pause_label_class}"><input type="checkbox" class="{console_checkbox_class} {console_pause_class}" value="1" id="{id_guid}"> {str_pause}</label>' +
1194                 '<button type="button" class="'+
1195                     '{console_button_class} {console_clear_class}">{str_clear}'+
1196                 '</button>'+
1197             '</div>'+
1198         '</div>',
1200     /**
1201      * Default markup template used to create the DOM structure for Console
1202      * entries. The markup contains {placeholder}s for content and classes
1203      * that are replaced via Y.Lang.sub.  The default template contains
1204      * the {placeholder}s identified in Console.ENTRY_CLASSES as well as the
1205      * following placeholders that will be populated by the log entry data:
1206      *
1207      * <ul>
1208      *   <li>cat_class</li>
1209      *   <li>src_class</li>
1210      *   <li>totalTime</li>
1211      *   <li>elapsedTime</li>
1212      *   <li>localTime</li>
1213      *   <li>sourceAndDetail</li>
1214      *   <li>message</li>
1215      * </ul>
1216      *
1217      * @property ENTRY_TEMPLATE
1218      * @type String
1219      * @static
1220      */
1221     ENTRY_TEMPLATE : ENTRY_TEMPLATE_STR,
1223     /**
1224      * Static property used to define the default attribute configuration of
1225      * the Widget.
1226      *
1227      * @property ATTRS
1228      * @Type Object
1229      * @static
1230      */
1231     ATTRS : {
1233         /**
1234          * Name of the custom event that will communicate log messages.
1235          *
1236          * @attribute logEvent
1237          * @type String
1238          * @default "yui:log"
1239          */
1240         logEvent : {
1241             value : 'yui:log',
1242             writeOnce : true,
1243             validator : isString
1244         },
1246         /**
1247          * Object that will emit the log events.  By default the YUI instance.
1248          * To have a single Console capture events from all YUI instances, set
1249          * this to the Y.Global object.
1250          *
1251          * @attribute logSource
1252          * @type EventTarget
1253          * @default Y
1254          */
1255         logSource : {
1256             value : Y,
1257             writeOnce : true,
1258             validator : function (v) {
1259                 return this._validateLogSource(v);
1260             }
1261         },
1263         /**
1264          * Collection of strings used to label elements in the Console UI.
1265          * Default collection contains the following name:value pairs:
1266          *
1267          * <ul>
1268          *   <li>title : &quot;Log Console&quot;</li>
1269          *   <li>pause : &quot;Pause&quot;</li>
1270          *   <li>clear : &quot;Clear&quot;</li>
1271          *   <li>collapse : &quot;Collapse&quot;</li>
1272          *   <li>expand : &quot;Expand&quot;</li>
1273          * </ul>
1274          *
1275          * @attribute strings
1276          * @type Object
1277          */
1278         strings : {
1279             valueFn: function() { return Y.Intl.get("console"); }
1280         },
1282         /**
1283          * Boolean to pause the outputting of new messages to the console.
1284          * When paused, messages will accumulate in the buffer.
1285          *
1286          * @attribute paused
1287          * @type boolean
1288          * @default false
1289          */
1290         paused : {
1291             value : false,
1292             validator : L.isBoolean
1293         },
1295         /**
1296          * If a category is not specified in the Y.log(..) statement, this
1297          * category will be used. Categories &quot;info&quot;,
1298          * &quot;warn&quot;, and &quot;error&quot; are also called log level.
1299          *
1300          * @attribute defaultCategory
1301          * @type String
1302          * @default "info"
1303          */
1304         defaultCategory : {
1305             value : INFO,
1306             validator : isString
1307         },
1309         /**
1310          * If a source is not specified in the Y.log(..) statement, this
1311          * source will be used.
1312          *
1313          * @attribute defaultSource
1314          * @type String
1315          * @default "global"
1316          */
1317         defaultSource   : {
1318             value : 'global',
1319             validator : isString
1320         },
1322         /**
1323          * Markup template used to create the DOM structure for Console entries.
1324          *
1325          * @attribute entryTemplate
1326          * @type String
1327          * @default Console.ENTRY_TEMPLATE
1328          */
1329         entryTemplate : {
1330             value : ENTRY_TEMPLATE_STR,
1331             validator : isString
1332         },
1334         /**
1335          * Minimum entry log level to render into the Console.  The initial
1336          * logLevel value for all Console instances defaults from the
1337          * Y.config.logLevel YUI configuration, or Console.LOG_LEVEL_INFO if
1338          * that configuration is not set.
1339          *
1340          * Possible values are &quot;info&quot;, &quot;warn&quot;,
1341          * &quot;error&quot; (case insensitive), or their corresponding statics
1342          * Console.LOG_LEVEL_INFO and so on.
1343          *
1344          * @attribute logLevel
1345          * @type String
1346          * @default Y.config.logLevel or Console.LOG_LEVEL_INFO
1347          */
1348         logLevel : {
1349             value : Y.config.logLevel || INFO,
1350             setter : function (v) {
1351                 return this._setLogLevel(v);
1352             }
1353         },
1355         /**
1356          * Millisecond timeout between iterations of the print loop, moving
1357          * entries from the buffer to the UI.
1358          *
1359          * @attribute printTimeout
1360          * @type Number
1361          * @default 100
1362          */
1363         printTimeout : {
1364             value : 100,
1365             validator : isNumber
1366         },
1368         /**
1369          * Maximum number of entries printed in each iteration of the print
1370          * loop. This is used to prevent excessive logging locking the page UI.
1371          *
1372          * @attribute printLimit
1373          * @type Number
1374          * @default 50
1375          */
1376         printLimit : {
1377             value : 50,
1378             validator : isNumber
1379         },
1381         /**
1382          * Maximum number of Console entries allowed in the Console body at one
1383          * time.  This is used to keep acquired messages from exploding the
1384          * DOM tree and impacting page performance.
1385          *
1386          * @attribute consoleLimit
1387          * @type Number
1388          * @default 300
1389          */
1390         consoleLimit : {
1391             value : 300,
1392             validator : isNumber
1393         },
1395         /**
1396          * New entries should display at the top of the Console or the bottom?
1397          *
1398          * @attribute newestOnTop
1399          * @type Boolean
1400          * @default true
1401          */
1402         newestOnTop : {
1403             value : true
1404         },
1406         /**
1407          * When new entries are added to the Console UI, should they be
1408          * scrolled into view?
1409          *
1410          * @attribute scrollIntoView
1411          * @type Boolean
1412          * @default true
1413          */
1414         scrollIntoView : {
1415             value : true
1416         },
1418         /**
1419          * The baseline time for this Console instance, used to measure elapsed
1420          * time from the moment the console module is <code>use</code>d to the
1421          * moment each new entry is logged (not rendered).
1422          *
1423          * This value is reset by the instance method myConsole.reset().
1424          *
1425          * @attribute startTime
1426          * @type Date
1427          * @default The moment the console module is <code>use</code>d
1428          */
1429         startTime : {
1430             value : new Date()
1431         },
1433         /**
1434          * The precise time the last entry was logged.  Used to measure elapsed
1435          * time between log messages.
1436          *
1437          * @attribute lastTime
1438          * @type Date
1439          * @default The moment the console module is <code>use</code>d
1440          */
1441         lastTime : {
1442             value : new Date(),
1443             readOnly: true
1444         },
1446         /**
1447          * Controls the collapsed state of the Console
1448          *
1449          * @attribute collapsed
1450          * @type Boolean
1451          * @default false
1452          */
1453         collapsed : {
1454             value : false
1455         },
1457         /**
1458         * String with units, or number, representing the height of the Console,
1459         * inclusive of header and footer. If a number is provided, the default
1460         * unit, defined by Widget's DEF_UNIT, property is used.
1461         *
1462         * @attribute height
1463         * @default "300px"
1464         * @type {String | Number}
1465         */
1466         height: {
1467             value: "300px"
1468         },
1470         /**
1471         * String with units, or number, representing the width of the Console.
1472         * If a number is provided, the default unit, defined by Widget's
1473         * DEF_UNIT, property is used.
1474         *
1475         * @attribute width
1476         * @default "300px"
1477         * @type {String | Number}
1478         */
1479         width: {
1480             value: "300px"
1481         },
1483         /**
1484          * Pass through to the YUI instance useBrowserConsole configuration.
1485          * By default this is set to false, which will disable logging to the
1486          * browser console when a Console instance is created.  If the
1487          * logSource is not a YUI instance, this has no effect.
1488          *
1489          * @attribute useBrowserConsole
1490          * @type {Boolean}
1491          * @default false
1492          */
1493          useBrowserConsole : {
1494             lazyAdd: false,
1495             value: false,
1496             getter : function () {
1497                 return this._getUseBrowserConsole();
1498             },
1499             setter : function (v) {
1500                 return this._setUseBrowserConsole(v);
1501             }
1502          },
1504          /**
1505           * Allows the Console to flow in the document.  Available values are
1506           * 'inline', 'block', and 'separate' (the default).
1507           *
1508           * @attribute style
1509           * @type {String}
1510           * @default 'separate'
1511           */
1512          style : {
1513             value : 'separate',
1514             writeOnce : true,
1515             validator : function (v) {
1516                 return this._validateStyle(v);
1517             }
1518          }
1519     }
1524 }, '3.13.0', {"requires": ["yui-log", "widget"], "skinnable": true, "lang": ["en", "es", "hu", "it", "ja"]});