VirtualBox

source: vbox/trunk/src/VBox/ValidationKit/testmanager/htdocs/js/common.js@ 57111

Last change on this file since 57111 was 56295, checked in by vboxsync, 10 years ago

ValidationKit: Updated (C) year.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 26.4 KB
Line 
1/* $Id: common.js 56295 2015-06-09 14:29:55Z vboxsync $ */
2/** @file
3 * Common JavaScript functions
4 */
5
6/*
7 *
8 * Copyright (C) 2012-2015 Oracle Corporation
9 *
10 * This file is part of VirtualBox Open Source Edition (OSE), as
11 * available from http://www.virtualbox.org. This file is free software;
12 * you can redistribute it and/or modify it under the terms of the GNU
13 * General Public License (GPL) as published by the Free Software
14 * Foundation, in version 2 as it comes in the "COPYING" file of the
15 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
16 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
17 *
18 * The contents of this file may alternatively be used under the terms
19 * of the Common Development and Distribution License Version 1.0
20 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
21 * VirtualBox OSE distribution, in which case the provisions of the
22 * CDDL are applicable instead of those of the GPL.
23 *
24 * You may elect to license modified versions of this file under the
25 * terms and conditions of either the GPL or the CDDL or both.
26 */
27
28
29
30/**
31 * Checks if the given value is a decimal integer value.
32 *
33 * @returns true if it is, false if it's isn't.
34 * @param sValue The value to inspect.
35 */
36function isInteger(sValue)
37{
38 if (typeof sValue != 'undefined')
39 {
40 var intRegex = /^\d+$/;
41 if (intRegex.test(sValue))
42 {
43 return true;
44 }
45 }
46 return false;
47}
48
49/**
50 * Removes the element with the specified ID.
51 */
52function removeHtmlNode(sContainerId)
53{
54 var oElement = document.getElementById(sContainerId);
55 if (oElement)
56 {
57 oElement.parentNode.removeChild(oElement);
58 }
59}
60
61/**
62 * Sets the value of the element with id @a sInputId to the keys of aoItems
63 * (comma separated).
64 */
65function setElementValueToKeyList(sInputId, aoItems)
66{
67 var sKey;
68 var oElement = document.getElementById(sInputId);
69 oElement.value = '';
70
71 for (sKey in aoItems)
72 {
73 if (oElement.value.length > 0)
74 {
75 oElement.value += ',';
76 }
77
78 oElement.value += sKey;
79 }
80}
81
82/**
83 * Get the Window.devicePixelRatio in a safe way.
84 *
85 * @returns Floating point ratio. 1.0 means it's a 1:1 ratio.
86 */
87function getDevicePixelRatio()
88{
89 var fpRatio = 1.0;
90 if (window.devicePixelRatio)
91 {
92 fpRatio = window.devicePixelRatio;
93 if (fpRatio < 0.5 || fpRatio > 10.0)
94 fpRatio = 1.0;
95 }
96 return fpRatio;
97}
98
99/**
100 * Tries to figure out the DPI of the device in the X direction.
101 *
102 * @returns DPI on success, null on failure.
103 */
104function getDeviceXDotsPerInch()
105{
106 if (window.deviceXDPI && window.deviceXDPI > 48 && window.deviceXDPI < 2048)
107 {
108 return window.deviceXDPI;
109 }
110 else if (window.devicePixelRatio && window.devicePixelRatio >= 0.5 && window.devicePixelRatio <= 10.0)
111 {
112 cDotsPerInch = Math.round(96 * window.devicePixelRatio);
113 }
114 else
115 {
116 cDotsPerInch = null;
117 }
118 return cDotsPerInch;
119}
120
121/**
122 * Gets the width of the given element (downscaled).
123 *
124 * Useful when using the element to figure the size of a image
125 * or similar.
126 *
127 * @returns Number of pixels. null if oElement is bad.
128 * @param oElement The element (not ID).
129 */
130function getElementWidth(oElement)
131{
132 if (oElement && oElement.offsetWidth)
133 return oElement.offsetWidth;
134 return null;
135}
136
137/** By element ID version of getElementWidth. */
138function getElementWidthById(sElementId)
139{
140 return getElementWidth(document.getElementById(sElementId));
141}
142
143/**
144 * Gets the real unscaled width of the given element.
145 *
146 * Useful when using the element to figure the size of a image
147 * or similar.
148 *
149 * @returns Number of screen pixels. null if oElement is bad.
150 * @param oElement The element (not ID).
151 */
152function getUnscaledElementWidth(oElement)
153{
154 if (oElement && oElement.offsetWidth)
155 return Math.round(oElement.offsetWidth * getDevicePixelRatio());
156 return null;
157}
158
159/** By element ID version of getUnscaledElementWidth. */
160function getUnscaledElementWidthById(sElementId)
161{
162 return getUnscaledElementWidth(document.getElementById(sElementId));
163}
164
165
166/**
167 * Sets the value of an input field element (give by ID).
168 *
169 * @returns Returns success indicator (true/false).
170 * @param sFieldId The field ID (required for updating).
171 * @param sValue The field value.
172 */
173function setInputFieldValue(sFieldId, sValue)
174{
175 var oInputElement = document.getElementById(sFieldId);
176 if (oInputElement)
177 {
178 oInputElement.value = sValue;
179 return true;
180 }
181 return false;
182}
183
184/**
185 * Adds a hidden input field to a form.
186 *
187 * @returns The new input field element.
188 * @param oFormElement The form to append it to.
189 * @param sName The field name.
190 * @param sValue The field value.
191 * @param sFieldId The field ID (optional).
192 */
193function addHiddenInputFieldToForm(oFormElement, sName, sValue, sFieldId)
194{
195 var oNew = document.createElement('input');
196 oNew.type = 'hidden';
197 oNew.name = sName;
198 oNew.value = sValue;
199 if (sFieldId)
200 oNew.id = sFieldId;
201 oFormElement.appendChild(oNew);
202 return oNew;
203}
204
205/** By element ID version of addHiddenInputFieldToForm. */
206function addHiddenInputFieldToFormById(sFormId, sName, sValue, sFieldId)
207{
208 return addHiddenInputFieldToForm(document.getElementById(sFormId), sName, sValue, sFieldId);
209}
210
211/**
212 * Adds or updates a hidden input field to/on a form.
213 *
214 * @returns The new input field element.
215 * @param sFormId The ID of the form to amend.
216 * @param sName The field name.
217 * @param sValue The field value.
218 * @param sFieldId The field ID (required for updating).
219 */
220function addUpdateHiddenInputFieldToFormById(sFormId, sName, sValue, sFieldId)
221{
222 var oInputElement = null;
223 if (sFieldId)
224 {
225 oInputElement = document.getElementById(sFieldId);
226 }
227 if (oInputElement)
228 {
229 oInputElement.name = sName;
230 oInputElement.value = sValue;
231 }
232 else
233 {
234 oInputElement = addHiddenInputFieldToFormById(sFormId, sName, sValue, sFieldId);
235 }
236 return oInputElement;
237}
238
239/**
240 * Adds a width and a dpi input to the given form element if possible to
241 * determine the values.
242 *
243 * This is normally employed in an onlick hook, but then you must specify IDs or
244 * the browser may end up adding it several times.
245 *
246 * @param sFormId The ID of the form to amend.
247 * @param sWidthSrcId The ID of the element to calculate the width
248 * value from.
249 * @param sWidthName The name of the width value.
250 * @param sDpiName The name of the dpi value.
251 */
252function addDynamicGraphInputs(sFormId, sWidthSrcId, sWidthName, sDpiName)
253{
254 var cx = getUnscaledElementWidthById(sWidthSrcId);
255 var cDotsPerInch = getDeviceXDotsPerInch();
256
257 if (cx)
258 {
259 addUpdateHiddenInputFieldToFormById(sFormId, sWidthName, cx, sFormId + '-' + sWidthName + '-id');
260 }
261
262 if (cDotsPerInch)
263 {
264 addUpdateHiddenInputFieldToFormById(sFormId, sDpiName, cDotsPerInch, sFormId + '-' + sDpiName + '-id');
265 }
266
267}
268
269
270/** @name Custom Tooltips
271 * @{
272 */
273
274/** Where we keep tooltip elements when not displayed. */
275var g_dTooltips = {};
276var g_oCurrentTooltip = null;
277var g_idTooltipShowTimer = null;
278var g_idTooltipHideTimer = null;
279var g_cTooltipSvnRevisions = 12;
280
281/**
282 * Cancel showing/replacing/repositing a tooltip.
283 */
284function tooltipResetShowTimer()
285{
286 if (g_idTooltipShowTimer)
287 {
288 clearTimeout(g_idTooltipShowTimer);
289 g_idTooltipShowTimer = null;
290 }
291}
292
293/**
294 * Cancel hiding of the current tooltip.
295 */
296function tooltipResetHideTimer()
297{
298 if (g_idTooltipHideTimer)
299 {
300 clearTimeout(g_idTooltipHideTimer);
301 g_idTooltipHideTimer = null;
302 }
303}
304
305/**
306 * Really hide the tooltip.
307 */
308function tooltipReallyHide()
309{
310 if (g_oCurrentTooltip)
311 {
312 //console.log('tooltipReallyHide: ' + g_oCurrentTooltip);
313 g_oCurrentTooltip.oElm.style.display = 'none';
314 g_oCurrentTooltip = null;
315 }
316}
317
318/**
319 * Schedule the tooltip for hiding.
320 */
321function tooltipHide()
322{
323 function tooltipDelayedHide()
324 {
325 tooltipResetHideTimer();
326 tooltipReallyHide();
327 }
328
329 /*
330 * Cancel any pending show and schedule hiding if necessary.
331 */
332 tooltipResetShowTimer();
333 if (g_oCurrentTooltip && !g_idTooltipHideTimer)
334 {
335 g_idTooltipHideTimer = setTimeout(tooltipDelayedHide, 700);
336 }
337
338 return true;
339}
340
341/**
342 * Function that is repositions the tooltip when it's shown.
343 *
344 * Used directly, via onload, and hackish timers to catch all browsers and
345 * whatnot.
346 *
347 * Will set several tooltip member variables related to position and space.
348 */
349function tooltipRepositionOnLoad()
350{
351 if (g_oCurrentTooltip)
352 {
353 var oRelToRect = g_oCurrentTooltip.oRelToRect;
354 var cxNeeded = g_oCurrentTooltip.oElm.offsetWidth + 8;
355 var cyNeeded = g_oCurrentTooltip.oElm.offsetHeight + 8;
356
357 var yScroll = window.pageYOffset || document.documentElement.scrollTop;
358 var yScrollBottom = yScroll + window.innerHeight;
359 var xScroll = window.pageXOffset || document.documentElement.scrollLeft;
360 var xScrollRight = xScroll + window.innerWidth;
361
362 var cyAbove = Math.max(oRelToRect.top - yScroll, 0);
363 var cyBelow = Math.max(yScrollBottom - oRelToRect.bottom, 0);
364 var cxLeft = Math.max(oRelToRect.left - xScroll, 0);
365 var cxRight = Math.max(xScrollRight - oRelToRect.right, 0);
366
367 var xPos;
368 var yPos;
369
370 /*
371 * Decide where to put the thing.
372 */
373 if (cyNeeded < cyBelow)
374 {
375 yPos = oRelToRect.bottom;
376 g_oCurrentTooltip.cyMax = cyBelow;
377 }
378 else if (cyBelow >= cyAbove)
379 {
380 yPos = yScrollBottom - cyNeeded;
381 g_oCurrentTooltip.cyMax = yScrollBottom - yPos;
382 }
383 else
384 {
385 yPos = oRelToRect.top - cyNeeded;
386 g_oCurrentTooltip.cyMax = yScrollBottom - yPos;
387 }
388 if (yPos < yScroll)
389 {
390 yPos = yScroll;
391 g_oCurrentTooltip.cyMax = yScrollBottom - yPos;
392 }
393 g_oCurrentTooltip.yPos = yPos;
394 g_oCurrentTooltip.yScroll = yScroll;
395 g_oCurrentTooltip.cyMaxUp = yPos - yScroll;
396
397 if (cxNeeded < cxRight || cxNeeded > cxRight)
398 {
399 xPos = oRelToRect.right;
400 g_oCurrentTooltip.cxMax = cxRight;
401 }
402 else
403 {
404 xPos = oRelToRect.left - cxNeeded;
405 g_oCurrentTooltip.cxMax = cxNeeded;
406 }
407 g_oCurrentTooltip.xPos = xPos;
408 g_oCurrentTooltip.xScroll = xScroll;
409
410 g_oCurrentTooltip.oElm.style.top = yPos + 'px';
411 g_oCurrentTooltip.oElm.style.left = xPos + 'px';
412 }
413 return true;
414}
415
416
417/**
418 * Really show the tooltip.
419 *
420 * @param oTooltip The tooltip object.
421 * @param oRelTo What to put the tooltip adjecent to.
422 */
423function tooltipReallyShow(oTooltip, oRelTo)
424{
425 var oRect;
426
427 tooltipResetShowTimer();
428 tooltipResetHideTimer();
429
430 if (g_oCurrentTooltip == oTooltip)
431 {
432 //console.log('moving tooltip');
433 }
434 else if (g_oCurrentTooltip)
435 {
436 //console.log('removing current tooltip and showing new');
437 tooltipReallyHide();
438 }
439 else
440 {
441 //console.log('showing tooltip');
442 }
443
444 oTooltip.oElm.style.display = 'block';
445 oTooltip.oElm.style.position = 'absolute';
446 oRect = oRelTo.getBoundingClientRect();
447 oTooltip.oRelToRect = oRect;
448 oTooltip.oElm.style.left = oRect.right + 'px';
449 oTooltip.oElm.style.top = oRect.bottom + 'px';
450
451 g_oCurrentTooltip = oTooltip;
452
453 /*
454 * This function does the repositioning at some point.
455 */
456 tooltipRepositionOnLoad();
457 if (oTooltip.oElm.onload === null)
458 {
459 oTooltip.oElm.onload = function(){ tooltipRepositionOnLoad(); setTimeout(tooltipRepositionOnLoad, 0); };
460 }
461}
462
463/**
464 * Tooltip onmouseenter handler .
465 */
466function tooltipElementOnMouseEnter()
467{
468 //console.log('tooltipElementOnMouseEnter: arguments.length='+arguments.length+' [0]='+arguments[0]);
469 //console.log('ENT: currentTarget='+arguments[0].currentTarget);
470 tooltipResetShowTimer();
471 tooltipResetHideTimer();
472 return true;
473}
474
475/**
476 * Tooltip onmouseout handler.
477 *
478 * @remarks We only use this and onmouseenter for one tooltip element (iframe
479 * for svn, because chrome is sending onmouseout events after
480 * onmouseneter for the next element, which would confuse this simple
481 * code.
482 */
483function tooltipElementOnMouseOut()
484{
485 //console.log('tooltipElementOnMouseOut: arguments.length='+arguments.length+' [0]='+arguments[0]);
486 //console.log('OUT: currentTarget='+arguments[0].currentTarget);
487 tooltipHide();
488 return true;
489}
490
491/**
492 * iframe.onload hook that repositions and resizes the tooltip.
493 *
494 * This is a little hacky and we're calling it one or three times too many to
495 * work around various browser differences too.
496 */
497function svnHistoryTooltipOnLoad()
498{
499 //console.log('svnHistoryTooltipOnLoad');
500
501 /*
502 * Resize the tooltip to better fit the content.
503 */
504 tooltipRepositionOnLoad(); /* Sets cxMax and cyMax. */
505 if (g_oCurrentTooltip && g_oCurrentTooltip.oIFrame.contentWindow)
506 {
507 var oSubElement = g_oCurrentTooltip.oIFrame;
508 var cxSpace = Math.max(oSubElement.offsetLeft * 2, 0); /* simplified */
509 var cySpace = Math.max(oSubElement.offsetTop * 2, 0); /* simplified */
510 var cxNeeded = oSubElement.contentWindow.document.body.scrollWidth + cxSpace;
511 var cyNeeded = oSubElement.contentWindow.document.body.scrollHeight + cySpace;
512 var cx = Math.min(cxNeeded, g_oCurrentTooltip.cxMax);
513 var cy;
514
515 g_oCurrentTooltip.oElm.width = cx + 'px';
516 oSubElement.width = (cx - cxSpace) + 'px';
517 if (cx >= cxNeeded)
518 {
519 //console.log('svnHistoryTooltipOnLoad: overflowX -> hidden');
520 oSubElement.style.overflowX = 'hidden';
521 }
522 else
523 {
524 oSubElement.style.overflowX = 'scroll';
525 }
526
527 cy = Math.min(cyNeeded, g_oCurrentTooltip.cyMax);
528 if (cyNeeded > g_oCurrentTooltip.cyMax && g_oCurrentTooltip.cyMaxUp > 0)
529 {
530 var cyMove = Math.min(cyNeeded - g_oCurrentTooltip.cyMax, g_oCurrentTooltip.cyMaxUp);
531 g_oCurrentTooltip.cyMax += cyMove;
532 g_oCurrentTooltip.yPos -= cyMove;
533 g_oCurrentTooltip.oElm.style.top = g_oCurrentTooltip.yPos + 'px';
534 cy = Math.min(cyNeeded, g_oCurrentTooltip.cyMax);
535 }
536
537 g_oCurrentTooltip.oElm.height = cy + 'px';
538 oSubElement.height = (cy - cySpace) + 'px';
539 if (cy >= cyNeeded)
540 {
541 //console.log('svnHistoryTooltipOnLoad: overflowY -> hidden');
542 oSubElement.style.overflowY = 'hidden';
543 }
544 else
545 {
546 oSubElement.style.overflowY = 'scroll';
547 }
548
549 //console.log('cyNeeded='+cyNeeded+' cyMax='+g_oCurrentTooltip.cyMax+' cySpace='+cySpace+' cy='+cy);
550 //console.log('oSubElement.offsetTop='+oSubElement.offsetTop);
551 //console.log('svnHistoryTooltipOnLoad: cx='+cx+'cxMax='+g_oCurrentTooltip.cxMax+' cxNeeded='+cxNeeded+' cy='+cy+' cyMax='+g_oCurrentTooltip.cyMax);
552
553 tooltipRepositionOnLoad();
554 }
555 return true;
556}
557
558/**
559 * Calculates the last revision to get when showing a tooltip for @a iRevision.
560 *
561 * A tooltip covers several change log entries, both to limit the number of
562 * tooltips to load and to give context. The exact number is defined by
563 * g_cTooltipSvnRevisions.
564 *
565 * @returns Last revision in a tooltip.
566 * @param iRevision The revision number.
567 */
568function svnHistoryTooltipCalcLastRevision(iRevision)
569{
570 var iFirstRev = Math.floor(iRevision / g_cTooltipSvnRevisions) * g_cTooltipSvnRevisions;
571 return iFirstRev + g_cTooltipSvnRevisions - 1;
572}
573
574/**
575 * Calculates a unique ID for the tooltip element.
576 *
577 * This is also used as dictionary index.
578 *
579 * @returns tooltip ID value (string).
580 * @param sRepository The repository name.
581 * @param iRevision The revision number.
582 */
583function svnHistoryTooltipCalcId(sRepository, iRevision)
584{
585 return 'svnHistoryTooltip_' + sRepository + '_' + svnHistoryTooltipCalcLastRevision(iRevision);
586}
587
588/**
589 * The onmouseenter event handler for creating the tooltip.
590 *
591 * @param oEvt The event.
592 * @param sRepository The repository name.
593 * @param iRevision The revision number.
594 *
595 * @remarks onmouseout must be set to call tooltipHide.
596 */
597function svnHistoryTooltipShow(oEvt, sRepository, iRevision)
598{
599 var sKey = svnHistoryTooltipCalcId(sRepository, iRevision);
600 var oTooltip = g_dTooltips[sKey];
601 var oParent = oEvt.currentTarget;
602 //console.log('svnHistoryTooltipShow ' + sRepository);
603
604 function svnHistoryTooltipDelayedShow()
605 {
606 var oSubElement;
607 var sSrc;
608
609 oTooltip = g_dTooltips[sKey];
610 //console.log('svnHistoryTooltipDelayedShow ' + sRepository + ' ' + oTooltip);
611 if (!oTooltip)
612 {
613 /*
614 * Create a new tooltip element.
615 */
616 //console.log('creating ' + sKey);
617 oTooltip = {};
618 oTooltip.oElm = document.createElement('div');
619 oTooltip.oElm.setAttribute('id', sKey);
620 oTooltip.oElm.setAttribute('class', 'tmvcstooltip');
621 oTooltip.oElm.style.position = 'absolute';
622 oTooltip.oElm.style.zIndex = 6001;
623 oTooltip.xPos = 0;
624 oTooltip.yPos = 0;
625 oTooltip.cxMax = 0;
626 oTooltip.cyMax = 0;
627 oTooltip.cyMaxUp = 0;
628 oTooltip.xScroll = 0;
629 oTooltip.yScroll = 0;
630
631 oSubElement = document.createElement('iframe');
632 oSubElement.setAttribute('id', sKey + '_iframe');
633 oSubElement.setAttribute('style', 'position: relative;"');
634 oSubElement.onload = function() {svnHistoryTooltipOnLoad(); setTimeout(svnHistoryTooltipOnLoad,0);};
635 oSubElement.onmouseenter = tooltipElementOnMouseEnter;
636 oSubElement.onmouseout = tooltipElementOnMouseOut;
637 oTooltip.oElm.appendChild(oSubElement);
638 oTooltip.oIFrame = oSubElement;
639 g_dTooltips[sKey] = oTooltip;
640
641 document.body.appendChild(oTooltip.oElm);
642 }
643 else
644 {
645 oSubElement = oTooltip.oIFrame;
646 }
647
648 oSubElement.setAttribute('src', 'index.py?Action=VcsHistoryTooltip&repo=' + sRepository
649 + '&rev=' + svnHistoryTooltipCalcLastRevision(iRevision)
650 + '&cEntries=' + g_cTooltipSvnRevisions
651 + '#r' + iRevision);
652 tooltipReallyShow(oTooltip, oParent);
653 /* Resize and repositioning hacks. */
654 svnHistoryTooltipOnLoad();
655 setTimeout(svnHistoryTooltipOnLoad, 0);
656 }
657
658 /*
659 * Delay the change.
660 */
661 tooltipResetShowTimer();
662 g_idTooltipShowTimer = setTimeout(svnHistoryTooltipDelayedShow, 512);
663}
664
665/** @} */
666
667
668/** @name Debugging and Introspection
669 * @{
670 */
671
672/**
673 * Python-like dir() implementation.
674 *
675 * @returns Array of names associated with oObj.
676 * @param oObj The object under inspection. If not specified we'll
677 * look at the window object.
678 */
679function pythonlikeDir(oObj, fDeep)
680{
681 var aRet = [];
682 var dTmp = {};
683
684 if (!oObj)
685 {
686 oObj = window;
687 }
688
689 for (var oCur = oObj; oCur; oCur = Object.getPrototypeOf(oCur))
690 {
691 var aThis = Object.getOwnPropertyNames(oCur);
692 for (var i = 0; i < aThis.length; i++)
693 {
694 if (!(aThis[i] in dTmp))
695 {
696 dTmp[aThis[i]] = 1;
697 aRet.push(aThis[i]);
698 }
699 }
700 }
701
702 return aRet;
703}
704
705
706/**
707 * Python-like dir() implementation, shallow version.
708 *
709 * @returns Array of names associated with oObj.
710 * @param oObj The object under inspection. If not specified we'll
711 * look at the window object.
712 */
713function pythonlikeShallowDir(oObj, fDeep)
714{
715 var aRet = [];
716 var dTmp = {};
717
718 if (oObj)
719 {
720 for (var i in oObj)
721 {
722 aRet.push(i);
723 }
724 }
725
726 return aRet;
727}
728
729
730
731function dbgGetObjType(oObj)
732{
733 var sType = typeof oObj;
734 if (sType == "object" && oObj !== null)
735 {
736 if (oObj.constructor && oObj.constructor.name)
737 {
738 sType = oObj.constructor.name;
739 }
740 else
741 {
742 var fnToString = Object.prototype.toString;
743 var sTmp = fnToString.call(oObj);
744 if (sTmp.indexOf('[object ') === 0)
745 {
746 sType = sTmp.substring(8, sTmp.length);
747 }
748 }
749 }
750 return sType;
751}
752
753
754/**
755 * Dumps the given object to the console.
756 *
757 * @param oObj The object under inspection.
758 * @param sPrefix What to prefix the log output with.
759 */
760function dbgDumpObj(oObj, sName, sPrefix)
761{
762 var aMembers;
763 var sType;
764
765 /*
766 * Defaults
767 */
768 if (!oObj)
769 {
770 oObj = window;
771 }
772
773 if (!sPrefix)
774 {
775 if (sName)
776 {
777 sPrefix = sName + ':';
778 }
779 else
780 {
781 sPrefix = 'dbgDumpObj:';
782 }
783 }
784
785 if (!sName)
786 {
787 sName = '';
788 }
789
790 /*
791 * The object itself.
792 */
793 sPrefix = sPrefix + ' ';
794 console.log(sPrefix + sName + ' ' + dbgGetObjType(oObj));
795
796 /*
797 * The members.
798 */
799 sPrefix = sPrefix + ' ';
800 aMembers = pythonlikeDir(oObj);
801 for (i = 0; i < aMembers.length; i++)
802 {
803 console.log(sPrefix + aMembers[i]);
804 }
805
806 return true;
807}
808
809function dbgDumpObjWorker(sType, sName, oObj, sPrefix)
810{
811 var sRet;
812 switch (sType)
813 {
814 case 'function':
815 {
816 sRet = sPrefix + 'function ' + sName + '()' + '\n';
817 break;
818 }
819
820 case 'object':
821 {
822 sRet = sPrefix + 'var ' + sName + '(' + dbgGetObjType(oObj) + ') =';
823 if (oObj !== null)
824 {
825 sRet += '\n';
826 }
827 else
828 {
829 sRet += ' null\n';
830 }
831 break;
832 }
833
834 case 'string':
835 {
836 sRet = sPrefix + 'var ' + sName + '(string, ' + oObj.length + ')';
837 if (oObj.length < 80)
838 {
839 sRet += ' = "' + oObj + '"\n';
840 }
841 else
842 {
843 sRet += '\n';
844 }
845 break;
846 }
847
848 case 'Oops!':
849 sRet = sPrefix + sName + '(??)\n';
850 break;
851
852 default:
853 sRet = sPrefix + 'var ' + sName + '(' + sType + ')\n';
854 break;
855 }
856 return sRet;
857}
858
859
860function dbgObjInArray(aoObjs, oObj)
861{
862 var i = aoObjs.length;
863 while (i > 0)
864 {
865 i--;
866 if (aoObjs[i] === oObj)
867 {
868 return true;
869 }
870 }
871 return false;
872}
873
874function dbgDumpObjTreeWorker(oObj, sPrefix, aParentObjs, cMaxDepth)
875{
876 var sRet = '';
877 var aMembers = pythonlikeShallowDir(oObj);
878 var i;
879
880 for (i = 0; i < aMembers.length; i++)
881 {
882 //var sName = i;
883 var sName = aMembers[i];
884 var oMember;
885 var sType;
886 var oEx;
887
888 try
889 {
890 oMember = oObj[sName];
891 sType = typeof oObj[sName];
892 }
893 catch (oEx)
894 {
895 oMember = null;
896 sType = 'Oops!';
897 }
898
899 //sRet += '[' + i + '/' + aMembers.length + ']';
900 sRet += dbgDumpObjWorker(sType, sName, oMember, sPrefix);
901
902 if ( sType == 'object'
903 && oObj !== null)
904 {
905
906 if (dbgObjInArray(aParentObjs, oMember))
907 {
908 sRet += sPrefix + '! parent recursion\n';
909 }
910 else if ( sName == 'previousSibling'
911 || sName == 'previousElement'
912 || sName == 'lastChild'
913 || sName == 'firstElementChild'
914 || sName == 'lastElementChild'
915 || sName == 'nextElementSibling'
916 || sName == 'prevElementSibling'
917 || sName == 'parentElement'
918 || sName == 'ownerDocument')
919 {
920 sRet += sPrefix + '! potentially dangerous element name\n';
921 }
922 else if (aParentObjs.length >= cMaxDepth)
923 {
924 sRet = sRet.substring(0, sRet.length - 1);
925 sRet += ' <too deep>!\n';
926 }
927 else
928 {
929
930 aParentObjs.push(oMember);
931 if (i + 1 < aMembers.length)
932 {
933 sRet += dbgDumpObjTreeWorker(oMember, sPrefix + '| ', aParentObjs, cMaxDepth);
934 }
935 else
936 {
937 sRet += dbgDumpObjTreeWorker(oMember, sPrefix.substring(0, sPrefix.length - 2) + ' | ', aParentObjs, cMaxDepth);
938 }
939 aParentObjs.pop();
940 }
941 }
942 }
943 return sRet;
944}
945
946/**
947 * Dumps the given object and all it's subobjects to the console.
948 *
949 * @returns String dump of the object.
950 * @param oObj The object under inspection.
951 * @param sName The object name (optional).
952 * @param sPrefix What to prefix the log output with (optional).
953 * @param cMaxDepth The max depth, optional.
954 */
955function dbgDumpObjTree(oObj, sName, sPrefix, cMaxDepth)
956{
957 var sType;
958 var sRet;
959 var oEx;
960
961 /*
962 * Defaults
963 */
964 if (!sPrefix)
965 {
966 sPrefix = '';
967 }
968
969 if (!sName)
970 {
971 sName = '??';
972 }
973
974 if (!cMaxDepth)
975 {
976 cMaxDepth = 2;
977 }
978
979 /*
980 * The object itself.
981 */
982 try
983 {
984 sType = typeof oObj;
985 }
986 catch (oEx)
987 {
988 sType = 'Oops!';
989 }
990 sRet = dbgDumpObjWorker(sType, sName, oObj, sPrefix);
991 if (sType == 'object' && oObj !== null)
992 {
993 var aParentObjs = Array();
994 aParentObjs.push(oObj);
995 sRet += dbgDumpObjTreeWorker(oObj, sPrefix + '| ', aParentObjs, cMaxDepth);
996 }
997
998 return sRet;
999}
1000
1001function dbgLogString(sLongString)
1002{
1003 var aStrings = sLongString.split("\n");
1004 var i;
1005 for (i = 0; i < aStrings.length; i++)
1006 {
1007 console.log(aStrings[i]);
1008 }
1009 console.log('dbgLogString - end - ' + aStrings.length + '/' + sLongString.length);
1010 return true;
1011}
1012
1013function dbgLogObjTree(oObj, sName, sPrefix, cMaxDepth)
1014{
1015 return dbgLogString(dbgDumpObjTree(oObj, sName, sPrefix, cMaxDepth));
1016}
1017
1018/** @} */
1019
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette