123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403 |
- // Copyright 2006 The Closure Library Authors. All Rights Reserved.
- //
- // Licensed under the Apache License, Version 2.0 (the "License");
- // you may not use this file except in compliance with the License.
- // You may obtain a copy of the License at
- //
- // http://www.apache.org/licenses/LICENSE-2.0
- //
- // Unless required by applicable law or agreed to in writing, software
- // distributed under the License is distributed on an "AS-IS" BASIS,
- // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- // See the License for the specific language governing permissions and
- // limitations under the License.
- /**
- * @fileoverview Definition of the FancyWindow class. Please minimize
- * dependencies this file has on other closure classes as any dependency it
- * takes won't be able to use the logging infrastructure.
- *
- * This is a pretty hacky implementation, aimed at making debugging of large
- * applications more manageable.
- *
- * @see ../demos/debug.html
- */
- goog.provide('goog.debug.FancyWindow');
- goog.require('goog.array');
- goog.require('goog.asserts');
- goog.require('goog.debug.DebugWindow');
- goog.require('goog.debug.LogManager');
- goog.require('goog.debug.Logger');
- goog.require('goog.dom.DomHelper');
- goog.require('goog.dom.TagName');
- goog.require('goog.dom.safe');
- goog.require('goog.html.SafeHtml');
- goog.require('goog.html.SafeStyleSheet');
- goog.require('goog.object');
- goog.require('goog.string');
- goog.require('goog.string.Const');
- goog.require('goog.userAgent');
- // TODO(mlourenco): Introduce goog.scope for goog.html.SafeHtml once b/12014412
- // is fixed.
- /**
- * Provides a Fancy extension to the DebugWindow class. Allows filtering based
- * on loggers and levels.
- *
- * @param {string=} opt_identifier Idenitifier for this logging class.
- * @param {string=} opt_prefix Prefix pre-pended to messages.
- * @constructor
- * @extends {goog.debug.DebugWindow}
- */
- goog.debug.FancyWindow = function(opt_identifier, opt_prefix) {
- this.readOptionsFromLocalStorage_();
- goog.debug.FancyWindow.base(this, 'constructor', opt_identifier, opt_prefix);
- /** @private {goog.dom.DomHelper} */
- this.dh_ = null;
- };
- goog.inherits(goog.debug.FancyWindow, goog.debug.DebugWindow);
- /**
- * Constant indicating if we are able to use localStorage to persist filters
- * @type {boolean}
- */
- goog.debug.FancyWindow.HAS_LOCAL_STORE = (function() {
- try {
- return !!window['localStorage'].getItem;
- } catch (e) {
- }
- return false;
- })();
- /**
- * Constant defining the prefix to use when storing log levels
- * @type {string}
- */
- goog.debug.FancyWindow.LOCAL_STORE_PREFIX = 'fancywindow.sel.';
- /** @override */
- goog.debug.FancyWindow.prototype.writeBufferToLog = function() {
- this.lastCall = goog.now();
- if (this.hasActiveWindow()) {
- var logel = /** @type {!HTMLElement} */ (this.dh_.getElement('log'));
- // Work out if scrolling is needed before we add the content
- var scroll =
- logel.scrollHeight - (logel.scrollTop + logel.offsetHeight) <= 100;
- for (var i = 0; i < this.outputBuffer.length; i++) {
- var div = this.dh_.createDom(goog.dom.TagName.DIV, 'logmsg');
- goog.dom.safe.setInnerHtml(div, this.outputBuffer[i]);
- logel.appendChild(div);
- }
- this.outputBuffer.length = 0;
- this.resizeStuff_();
- if (scroll) {
- logel.scrollTop = logel.scrollHeight;
- }
- }
- };
- /** @override */
- goog.debug.FancyWindow.prototype.writeInitialDocument = function() {
- if (!this.hasActiveWindow()) {
- return;
- }
- var doc = this.win.document;
- doc.open();
- goog.dom.safe.documentWrite(doc, this.getHtml_());
- doc.close();
- (goog.userAgent.IE ? doc.body : this.win).onresize =
- goog.bind(this.resizeStuff_, this);
- // Create a dom helper for the logging window
- this.dh_ = new goog.dom.DomHelper(doc);
- // Don't use events system to reduce dependencies
- this.dh_.getElement('openbutton').onclick =
- goog.bind(this.openOptions_, this);
- this.dh_.getElement('closebutton').onclick =
- goog.bind(this.closeOptions_, this);
- this.dh_.getElement('clearbutton').onclick = goog.bind(this.clear, this);
- this.dh_.getElement('exitbutton').onclick = goog.bind(this.exit_, this);
- this.writeSavedMessages();
- };
- /**
- * Show the options menu.
- * @return {boolean} false.
- * @private
- */
- goog.debug.FancyWindow.prototype.openOptions_ = function() {
- var el = goog.asserts.assert(this.dh_.getElement('optionsarea'));
- goog.dom.safe.setInnerHtml(el, goog.html.SafeHtml.EMPTY);
- var loggers = goog.debug.FancyWindow.getLoggers_();
- var dh = this.dh_;
- for (var i = 0; i < loggers.length; i++) {
- var logger = loggers[i];
- var curlevel = logger.getLevel() ? logger.getLevel().name : 'INHERIT';
- var div = dh.createDom(
- goog.dom.TagName.DIV, {},
- this.getDropDown_('sel' + logger.getName(), curlevel),
- dh.createDom(goog.dom.TagName.SPAN, {}, logger.getName() || '(root)'));
- el.appendChild(div);
- }
- this.dh_.getElement('options').style.display = 'block';
- return false;
- };
- /**
- * Make a drop down for the log levels.
- * @param {string} id Logger id.
- * @param {string} selected What log level is currently selected.
- * @return {Element} The newly created 'select' DOM element.
- * @private
- */
- goog.debug.FancyWindow.prototype.getDropDown_ = function(id, selected) {
- var dh = this.dh_;
- var sel = dh.createDom(goog.dom.TagName.SELECT, {'id': id});
- var levels = goog.debug.Logger.Level.PREDEFINED_LEVELS;
- for (var i = 0; i < levels.length; i++) {
- var level = levels[i];
- var option = dh.createDom(goog.dom.TagName.OPTION, {}, level.name);
- if (selected == level.name) {
- option.selected = true;
- }
- sel.appendChild(option);
- }
- sel.appendChild(
- dh.createDom(
- goog.dom.TagName.OPTION, {'selected': selected == 'INHERIT'},
- 'INHERIT'));
- return sel;
- };
- /**
- * Close the options menu.
- * @return {boolean} The value false.
- * @private
- */
- goog.debug.FancyWindow.prototype.closeOptions_ = function() {
- this.dh_.getElement('options').style.display = 'none';
- var loggers = goog.debug.FancyWindow.getLoggers_();
- var dh = this.dh_;
- for (var i = 0; i < loggers.length; i++) {
- var logger = loggers[i];
- var sel = /** @type {!HTMLSelectElement} */ (
- dh.getElement('sel' + logger.getName()));
- var level = sel.options[sel.selectedIndex].text;
- if (level == 'INHERIT') {
- logger.setLevel(null);
- } else {
- logger.setLevel(goog.debug.Logger.Level.getPredefinedLevel(level));
- }
- }
- this.writeOptionsToLocalStorage_();
- return false;
- };
- /**
- * Resizes the log elements
- * @private
- */
- goog.debug.FancyWindow.prototype.resizeStuff_ = function() {
- var dh = this.dh_;
- var logel = /** @type {!HTMLElement} */ (dh.getElement('log'));
- var headel = /** @type {!HTMLElement} */ (dh.getElement('head'));
- logel.style.top = headel.offsetHeight + 'px';
- logel.style.height = (dh.getDocument().body.offsetHeight -
- headel.offsetHeight - (goog.userAgent.IE ? 4 : 0)) +
- 'px';
- };
- /**
- * Handles the user clicking the exit button, disabled the debug window and
- * closes the popup.
- * @param {Event} e Event object.
- * @private
- */
- goog.debug.FancyWindow.prototype.exit_ = function(e) {
- this.setEnabled(false);
- if (this.win) {
- this.win.close();
- }
- };
- /** @override */
- goog.debug.FancyWindow.prototype.getStyleRules = function() {
- var baseRules = goog.debug.FancyWindow.base(this, 'getStyleRules');
- var extraRules = goog.html.SafeStyleSheet.fromConstant(
- goog.string.Const.from(
- 'html,body{height:100%;width:100%;margin:0px;padding:0px;' +
- 'background-color:#FFF;overflow:hidden}' +
- '*{}' +
- '.logmsg{border-bottom:1px solid #CCC;padding:2px;font:90% monospace}' +
- '#head{position:absolute;width:100%;font:x-small arial;' +
- 'border-bottom:2px solid #999;background-color:#EEE;}' +
- '#head p{margin:0px 5px;}' +
- '#log{position:absolute;width:100%;background-color:#FFF;}' +
- '#options{position:absolute;right:0px;width:50%;height:100%;' +
- 'border-left:1px solid #999;background-color:#DDD;display:none;' +
- 'padding-left: 5px;font:normal small arial;overflow:auto;}' +
- '#openbutton,#closebutton{text-decoration:underline;color:#00F;cursor:' +
- 'pointer;position:absolute;top:0px;right:5px;font:x-small arial;}' +
- '#clearbutton{text-decoration:underline;color:#00F;cursor:' +
- 'pointer;position:absolute;top:0px;right:80px;font:x-small arial;}' +
- '#exitbutton{text-decoration:underline;color:#00F;cursor:' +
- 'pointer;position:absolute;top:0px;right:50px;font:x-small arial;}' +
- 'select{font:x-small arial;margin-right:10px;}' +
- 'hr{border:0;height:5px;background-color:#8c8;color:#8c8;}'));
- return goog.html.SafeStyleSheet.concat(baseRules, extraRules);
- };
- /**
- * Return the default HTML for the debug window
- * @return {!goog.html.SafeHtml} Html.
- * @private
- */
- goog.debug.FancyWindow.prototype.getHtml_ = function() {
- var SafeHtml = goog.html.SafeHtml;
- var head = SafeHtml.create(
- 'head', {},
- SafeHtml.concat(
- SafeHtml.create('title', {}, 'Logging: ' + this.identifier),
- SafeHtml.createStyle(this.getStyleRules())));
- var body = SafeHtml.create(
- 'body', {},
- SafeHtml.concat(
- SafeHtml.create(
- 'div',
- {'id': 'log', 'style': goog.string.Const.from('overflow:auto')}),
- SafeHtml.create(
- 'div', {'id': 'head'},
- SafeHtml.concat(
- SafeHtml.create(
- 'p', {},
- SafeHtml.create('b', {}, 'Logging: ' + this.identifier)),
- SafeHtml.create('p', {}, this.welcomeMessage),
- SafeHtml.create('span', {'id': 'clearbutton'}, 'clear'),
- SafeHtml.create('span', {'id': 'exitbutton'}, 'exit'),
- SafeHtml.create('span', {'id': 'openbutton'}, 'options'))),
- SafeHtml.create(
- 'div', {'id': 'options'},
- SafeHtml.concat(
- SafeHtml.create(
- 'big', {}, SafeHtml.create('b', {}, 'Options:')),
- SafeHtml.create('div', {'id': 'optionsarea'}),
- SafeHtml.create(
- 'span', {'id': 'closebutton'}, 'save and close')))));
- return SafeHtml.create('html', {}, SafeHtml.concat(head, body));
- };
- /**
- * Write logger levels to localStorage if possible.
- * @private
- */
- goog.debug.FancyWindow.prototype.writeOptionsToLocalStorage_ = function() {
- if (!goog.debug.FancyWindow.HAS_LOCAL_STORE) {
- return;
- }
- var loggers = goog.debug.FancyWindow.getLoggers_();
- var storedKeys = goog.debug.FancyWindow.getStoredKeys_();
- for (var i = 0; i < loggers.length; i++) {
- var key = goog.debug.FancyWindow.LOCAL_STORE_PREFIX + loggers[i].getName();
- var level = loggers[i].getLevel();
- if (key in storedKeys) {
- if (!level) {
- window.localStorage.removeItem(key);
- } else if (window.localStorage.getItem(key) != level.name) {
- window.localStorage.setItem(key, level.name);
- }
- } else if (level) {
- window.localStorage.setItem(key, level.name);
- }
- }
- };
- /**
- * Sync logger levels with any values stored in localStorage.
- * @private
- */
- goog.debug.FancyWindow.prototype.readOptionsFromLocalStorage_ = function() {
- if (!goog.debug.FancyWindow.HAS_LOCAL_STORE) {
- return;
- }
- var storedKeys = goog.debug.FancyWindow.getStoredKeys_();
- for (var key in storedKeys) {
- var loggerName = key.replace(goog.debug.FancyWindow.LOCAL_STORE_PREFIX, '');
- var logger = goog.debug.LogManager.getLogger(loggerName);
- var curLevel = logger.getLevel();
- var storedLevel = window.localStorage.getItem(key).toString();
- if (!curLevel || curLevel.toString() != storedLevel) {
- logger.setLevel(goog.debug.Logger.Level.getPredefinedLevel(storedLevel));
- }
- }
- };
- /**
- * Helper function to create a list of locally stored keys. Used to avoid
- * expensive localStorage.getItem() calls.
- * @return {!Object} List of keys.
- * @private
- */
- goog.debug.FancyWindow.getStoredKeys_ = function() {
- var storedKeys = {};
- for (var i = 0, len = window.localStorage.length; i < len; i++) {
- var key = window.localStorage.key(i);
- if (key != null &&
- goog.string.startsWith(
- key, goog.debug.FancyWindow.LOCAL_STORE_PREFIX)) {
- storedKeys[key] = true;
- }
- }
- return storedKeys;
- };
- /**
- * Gets a sorted array of all the loggers registered.
- * @return {!Array<!goog.debug.Logger>} Array of logger instances.
- * @private
- */
- goog.debug.FancyWindow.getLoggers_ = function() {
- var loggers = goog.object.getValues(goog.debug.LogManager.getLoggers());
- /**
- * @param {!goog.debug.Logger} a
- * @param {!goog.debug.Logger} b
- * @return {number}
- */
- var loggerSort = function(a, b) {
- return goog.array.defaultCompare(a.getName(), b.getName());
- };
- goog.array.sort(loggers, loggerSort);
- return loggers;
- };
|