Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
seleniumhq
GitHub Repository: seleniumhq/selenium
Path: blob/trunk/third_party/closure/goog/debug/fancywindow.js
2868 views
1
// Copyright 2006 The Closure Library Authors. All Rights Reserved.
2
//
3
// Licensed under the Apache License, Version 2.0 (the "License");
4
// you may not use this file except in compliance with the License.
5
// You may obtain a copy of the License at
6
//
7
// http://www.apache.org/licenses/LICENSE-2.0
8
//
9
// Unless required by applicable law or agreed to in writing, software
10
// distributed under the License is distributed on an "AS-IS" BASIS,
11
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
// See the License for the specific language governing permissions and
13
// limitations under the License.
14
15
/**
16
* @fileoverview Definition of the FancyWindow class. Please minimize
17
* dependencies this file has on other closure classes as any dependency it
18
* takes won't be able to use the logging infrastructure.
19
*
20
* This is a pretty hacky implementation, aimed at making debugging of large
21
* applications more manageable.
22
*
23
* @see ../demos/debug.html
24
*/
25
26
27
goog.provide('goog.debug.FancyWindow');
28
29
goog.require('goog.array');
30
goog.require('goog.asserts');
31
goog.require('goog.debug.DebugWindow');
32
goog.require('goog.debug.LogManager');
33
goog.require('goog.debug.Logger');
34
goog.require('goog.dom.DomHelper');
35
goog.require('goog.dom.TagName');
36
goog.require('goog.dom.safe');
37
goog.require('goog.html.SafeHtml');
38
goog.require('goog.html.SafeStyleSheet');
39
goog.require('goog.object');
40
goog.require('goog.string');
41
goog.require('goog.string.Const');
42
goog.require('goog.userAgent');
43
44
45
46
// TODO(mlourenco): Introduce goog.scope for goog.html.SafeHtml once b/12014412
47
// is fixed.
48
/**
49
* Provides a Fancy extension to the DebugWindow class. Allows filtering based
50
* on loggers and levels.
51
*
52
* @param {string=} opt_identifier Idenitifier for this logging class.
53
* @param {string=} opt_prefix Prefix pre-pended to messages.
54
* @constructor
55
* @extends {goog.debug.DebugWindow}
56
*/
57
goog.debug.FancyWindow = function(opt_identifier, opt_prefix) {
58
this.readOptionsFromLocalStorage_();
59
goog.debug.FancyWindow.base(this, 'constructor', opt_identifier, opt_prefix);
60
/** @private {goog.dom.DomHelper} */
61
this.dh_ = null;
62
};
63
goog.inherits(goog.debug.FancyWindow, goog.debug.DebugWindow);
64
65
66
/**
67
* Constant indicating if we are able to use localStorage to persist filters
68
* @type {boolean}
69
*/
70
goog.debug.FancyWindow.HAS_LOCAL_STORE = (function() {
71
72
try {
73
return !!window['localStorage'].getItem;
74
} catch (e) {
75
}
76
return false;
77
})();
78
79
80
/**
81
* Constant defining the prefix to use when storing log levels
82
* @type {string}
83
*/
84
goog.debug.FancyWindow.LOCAL_STORE_PREFIX = 'fancywindow.sel.';
85
86
87
/** @override */
88
goog.debug.FancyWindow.prototype.writeBufferToLog = function() {
89
this.lastCall = goog.now();
90
if (this.hasActiveWindow()) {
91
var logel = /** @type {!HTMLElement} */ (this.dh_.getElement('log'));
92
93
// Work out if scrolling is needed before we add the content
94
var scroll =
95
logel.scrollHeight - (logel.scrollTop + logel.offsetHeight) <= 100;
96
97
for (var i = 0; i < this.outputBuffer.length; i++) {
98
var div = this.dh_.createDom(goog.dom.TagName.DIV, 'logmsg');
99
goog.dom.safe.setInnerHtml(div, this.outputBuffer[i]);
100
logel.appendChild(div);
101
}
102
this.outputBuffer.length = 0;
103
this.resizeStuff_();
104
105
if (scroll) {
106
logel.scrollTop = logel.scrollHeight;
107
}
108
}
109
};
110
111
112
/** @override */
113
goog.debug.FancyWindow.prototype.writeInitialDocument = function() {
114
if (!this.hasActiveWindow()) {
115
return;
116
}
117
118
var doc = this.win.document;
119
doc.open();
120
goog.dom.safe.documentWrite(doc, this.getHtml_());
121
doc.close();
122
123
(goog.userAgent.IE ? doc.body : this.win).onresize =
124
goog.bind(this.resizeStuff_, this);
125
126
// Create a dom helper for the logging window
127
this.dh_ = new goog.dom.DomHelper(doc);
128
129
// Don't use events system to reduce dependencies
130
this.dh_.getElement('openbutton').onclick =
131
goog.bind(this.openOptions_, this);
132
this.dh_.getElement('closebutton').onclick =
133
goog.bind(this.closeOptions_, this);
134
this.dh_.getElement('clearbutton').onclick = goog.bind(this.clear, this);
135
this.dh_.getElement('exitbutton').onclick = goog.bind(this.exit_, this);
136
137
this.writeSavedMessages();
138
};
139
140
141
/**
142
* Show the options menu.
143
* @return {boolean} false.
144
* @private
145
*/
146
goog.debug.FancyWindow.prototype.openOptions_ = function() {
147
var el = goog.asserts.assert(this.dh_.getElement('optionsarea'));
148
goog.dom.safe.setInnerHtml(el, goog.html.SafeHtml.EMPTY);
149
150
var loggers = goog.debug.FancyWindow.getLoggers_();
151
var dh = this.dh_;
152
for (var i = 0; i < loggers.length; i++) {
153
var logger = loggers[i];
154
var curlevel = logger.getLevel() ? logger.getLevel().name : 'INHERIT';
155
var div = dh.createDom(
156
goog.dom.TagName.DIV, {},
157
this.getDropDown_('sel' + logger.getName(), curlevel),
158
dh.createDom(goog.dom.TagName.SPAN, {}, logger.getName() || '(root)'));
159
el.appendChild(div);
160
}
161
162
this.dh_.getElement('options').style.display = 'block';
163
return false;
164
};
165
166
167
/**
168
* Make a drop down for the log levels.
169
* @param {string} id Logger id.
170
* @param {string} selected What log level is currently selected.
171
* @return {Element} The newly created 'select' DOM element.
172
* @private
173
*/
174
goog.debug.FancyWindow.prototype.getDropDown_ = function(id, selected) {
175
var dh = this.dh_;
176
var sel = dh.createDom(goog.dom.TagName.SELECT, {'id': id});
177
var levels = goog.debug.Logger.Level.PREDEFINED_LEVELS;
178
for (var i = 0; i < levels.length; i++) {
179
var level = levels[i];
180
var option = dh.createDom(goog.dom.TagName.OPTION, {}, level.name);
181
if (selected == level.name) {
182
option.selected = true;
183
}
184
sel.appendChild(option);
185
}
186
sel.appendChild(
187
dh.createDom(
188
goog.dom.TagName.OPTION, {'selected': selected == 'INHERIT'},
189
'INHERIT'));
190
return sel;
191
};
192
193
194
/**
195
* Close the options menu.
196
* @return {boolean} The value false.
197
* @private
198
*/
199
goog.debug.FancyWindow.prototype.closeOptions_ = function() {
200
this.dh_.getElement('options').style.display = 'none';
201
var loggers = goog.debug.FancyWindow.getLoggers_();
202
var dh = this.dh_;
203
for (var i = 0; i < loggers.length; i++) {
204
var logger = loggers[i];
205
var sel = /** @type {!HTMLSelectElement} */ (
206
dh.getElement('sel' + logger.getName()));
207
var level = sel.options[sel.selectedIndex].text;
208
if (level == 'INHERIT') {
209
logger.setLevel(null);
210
} else {
211
logger.setLevel(goog.debug.Logger.Level.getPredefinedLevel(level));
212
}
213
}
214
this.writeOptionsToLocalStorage_();
215
return false;
216
};
217
218
219
/**
220
* Resizes the log elements
221
* @private
222
*/
223
goog.debug.FancyWindow.prototype.resizeStuff_ = function() {
224
var dh = this.dh_;
225
var logel = /** @type {!HTMLElement} */ (dh.getElement('log'));
226
var headel = /** @type {!HTMLElement} */ (dh.getElement('head'));
227
logel.style.top = headel.offsetHeight + 'px';
228
logel.style.height = (dh.getDocument().body.offsetHeight -
229
headel.offsetHeight - (goog.userAgent.IE ? 4 : 0)) +
230
'px';
231
};
232
233
234
/**
235
* Handles the user clicking the exit button, disabled the debug window and
236
* closes the popup.
237
* @param {Event} e Event object.
238
* @private
239
*/
240
goog.debug.FancyWindow.prototype.exit_ = function(e) {
241
this.setEnabled(false);
242
if (this.win) {
243
this.win.close();
244
}
245
};
246
247
248
/** @override */
249
goog.debug.FancyWindow.prototype.getStyleRules = function() {
250
var baseRules = goog.debug.FancyWindow.base(this, 'getStyleRules');
251
var extraRules = goog.html.SafeStyleSheet.fromConstant(
252
goog.string.Const.from(
253
'html,body{height:100%;width:100%;margin:0px;padding:0px;' +
254
'background-color:#FFF;overflow:hidden}' +
255
'*{}' +
256
'.logmsg{border-bottom:1px solid #CCC;padding:2px;font:90% monospace}' +
257
'#head{position:absolute;width:100%;font:x-small arial;' +
258
'border-bottom:2px solid #999;background-color:#EEE;}' +
259
'#head p{margin:0px 5px;}' +
260
'#log{position:absolute;width:100%;background-color:#FFF;}' +
261
'#options{position:absolute;right:0px;width:50%;height:100%;' +
262
'border-left:1px solid #999;background-color:#DDD;display:none;' +
263
'padding-left: 5px;font:normal small arial;overflow:auto;}' +
264
'#openbutton,#closebutton{text-decoration:underline;color:#00F;cursor:' +
265
'pointer;position:absolute;top:0px;right:5px;font:x-small arial;}' +
266
'#clearbutton{text-decoration:underline;color:#00F;cursor:' +
267
'pointer;position:absolute;top:0px;right:80px;font:x-small arial;}' +
268
'#exitbutton{text-decoration:underline;color:#00F;cursor:' +
269
'pointer;position:absolute;top:0px;right:50px;font:x-small arial;}' +
270
'select{font:x-small arial;margin-right:10px;}' +
271
'hr{border:0;height:5px;background-color:#8c8;color:#8c8;}'));
272
return goog.html.SafeStyleSheet.concat(baseRules, extraRules);
273
};
274
275
276
/**
277
* Return the default HTML for the debug window
278
* @return {!goog.html.SafeHtml} Html.
279
* @private
280
*/
281
goog.debug.FancyWindow.prototype.getHtml_ = function() {
282
var SafeHtml = goog.html.SafeHtml;
283
var head = SafeHtml.create(
284
'head', {},
285
SafeHtml.concat(
286
SafeHtml.create('title', {}, 'Logging: ' + this.identifier),
287
SafeHtml.createStyle(this.getStyleRules())));
288
289
var body = SafeHtml.create(
290
'body', {},
291
SafeHtml.concat(
292
SafeHtml.create(
293
'div',
294
{'id': 'log', 'style': goog.string.Const.from('overflow:auto')}),
295
SafeHtml.create(
296
'div', {'id': 'head'},
297
SafeHtml.concat(
298
SafeHtml.create(
299
'p', {},
300
SafeHtml.create('b', {}, 'Logging: ' + this.identifier)),
301
SafeHtml.create('p', {}, this.welcomeMessage),
302
SafeHtml.create('span', {'id': 'clearbutton'}, 'clear'),
303
SafeHtml.create('span', {'id': 'exitbutton'}, 'exit'),
304
SafeHtml.create('span', {'id': 'openbutton'}, 'options'))),
305
SafeHtml.create(
306
'div', {'id': 'options'},
307
SafeHtml.concat(
308
SafeHtml.create(
309
'big', {}, SafeHtml.create('b', {}, 'Options:')),
310
SafeHtml.create('div', {'id': 'optionsarea'}),
311
SafeHtml.create(
312
'span', {'id': 'closebutton'}, 'save and close')))));
313
314
return SafeHtml.create('html', {}, SafeHtml.concat(head, body));
315
};
316
317
318
/**
319
* Write logger levels to localStorage if possible.
320
* @private
321
*/
322
goog.debug.FancyWindow.prototype.writeOptionsToLocalStorage_ = function() {
323
if (!goog.debug.FancyWindow.HAS_LOCAL_STORE) {
324
return;
325
}
326
var loggers = goog.debug.FancyWindow.getLoggers_();
327
var storedKeys = goog.debug.FancyWindow.getStoredKeys_();
328
for (var i = 0; i < loggers.length; i++) {
329
var key = goog.debug.FancyWindow.LOCAL_STORE_PREFIX + loggers[i].getName();
330
var level = loggers[i].getLevel();
331
if (key in storedKeys) {
332
if (!level) {
333
window.localStorage.removeItem(key);
334
} else if (window.localStorage.getItem(key) != level.name) {
335
window.localStorage.setItem(key, level.name);
336
}
337
} else if (level) {
338
window.localStorage.setItem(key, level.name);
339
}
340
}
341
};
342
343
344
/**
345
* Sync logger levels with any values stored in localStorage.
346
* @private
347
*/
348
goog.debug.FancyWindow.prototype.readOptionsFromLocalStorage_ = function() {
349
if (!goog.debug.FancyWindow.HAS_LOCAL_STORE) {
350
return;
351
}
352
var storedKeys = goog.debug.FancyWindow.getStoredKeys_();
353
for (var key in storedKeys) {
354
var loggerName = key.replace(goog.debug.FancyWindow.LOCAL_STORE_PREFIX, '');
355
var logger = goog.debug.LogManager.getLogger(loggerName);
356
var curLevel = logger.getLevel();
357
var storedLevel = window.localStorage.getItem(key).toString();
358
if (!curLevel || curLevel.toString() != storedLevel) {
359
logger.setLevel(goog.debug.Logger.Level.getPredefinedLevel(storedLevel));
360
}
361
}
362
};
363
364
365
/**
366
* Helper function to create a list of locally stored keys. Used to avoid
367
* expensive localStorage.getItem() calls.
368
* @return {!Object} List of keys.
369
* @private
370
*/
371
goog.debug.FancyWindow.getStoredKeys_ = function() {
372
var storedKeys = {};
373
for (var i = 0, len = window.localStorage.length; i < len; i++) {
374
var key = window.localStorage.key(i);
375
if (key != null &&
376
goog.string.startsWith(
377
key, goog.debug.FancyWindow.LOCAL_STORE_PREFIX)) {
378
storedKeys[key] = true;
379
}
380
}
381
return storedKeys;
382
};
383
384
385
/**
386
* Gets a sorted array of all the loggers registered.
387
* @return {!Array<!goog.debug.Logger>} Array of logger instances.
388
* @private
389
*/
390
goog.debug.FancyWindow.getLoggers_ = function() {
391
var loggers = goog.object.getValues(goog.debug.LogManager.getLoggers());
392
393
/**
394
* @param {!goog.debug.Logger} a
395
* @param {!goog.debug.Logger} b
396
* @return {number}
397
*/
398
var loggerSort = function(a, b) {
399
return goog.array.defaultCompare(a.getName(), b.getName());
400
};
401
goog.array.sort(loggers, loggerSort);
402
return loggers;
403
};
404
405