/**
* 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 Logger class that takes the results array, and outputs each
* of the result in HTML format. Uses CSS styles defined in test.css.
* This class renders two tables primarily. The first table that is rendered is
* a progress table where tests are listed and as they finish the table is
* updated to reflect the status of the tests, the second table rendered are the
* actual results of the tests with all its internal assertions and
* sub-results.
* Both tables look alike the only difference is that they use different styles
* to display, as mentioned above styles are taken from the tests.css file.
* The first table: Progress report
* The first table displays the header and all the id's of the tests along with
* an area for the tests to report it's status.
* This table uses little styles but still look a lot alike than its complete
* counterpart (see below).
* The tests usually reports a change in its status by using callbacks that will
* look for specific div elements using its Id's thus allowing change in the
* contents of the DIVs.
* The second table: Results report
* This table looks similar to the first one with notable differences.
* One and maybe the most important is that it has all the result information
* for each tests, this information is displayed as tables that has more data
* than the progress table.
* The second difference is the use of styles to display this table, in fact an
* effective way to know if this table is displayed and not it's counterpart is
* to look for the 'header' style class since when this style is present in the
* rendered div it means that the results have been rendered.
* The information rendered by this logger varies from result to result,
* successful tests only displays the id, name and actual result, while
* failures and warnings displays the id, name, actual and expected results; if
* there is an exception the result is marked as failed and also the exception
* is logged in a special format that allows better readability of them.
* Information results (log messages) will display their id and the data
* logged.
* Also for each test a mini-summary is presented, this contains the outcomes of
* the sub-results.
* At the top level there is a summary along with links to the failed tests.
*/
/**
* Creates a new HtmlLogger to render tests results as HTML in a given element.
* @param {element} outputDiv The element where the output will be logged.
* @param {string} headerMessage A message to be printed in the header of the
* test area.
* @param {TestSuiteDirectory} testSuiteDirectory to be executed
* @constructor
*/
function HtmlLogger(outputDiv, headerMessage, testSuiteDirectory) {
this.outputDiv = outputDiv;
this.headerMessage = headerMessage;
this.testSuiteDirectory = testSuiteDirectory;
this.directoryPassed = true;
this.summaryResult = 0;
this.statusClassName = ['pass', 'unv', 'warn', 'fail'];
this.priorityFailInfo = {};
this.priorityFailInfo[Test.PRIORITY.P4] = [];
this.priorityFailInfo[Test.PRIORITY.P3] = [];
this.priorityFailInfo[Test.PRIORITY.P2] = [];
this.priorityFailInfo[Test.PRIORITY.P1] = [];
this.priorityFailInfo[Test.PRIORITY.P0] = [];
}
/**
* Creates table for each test which will be filled when the result is
* available.
* @param {Test} test to be displayed
* @return {string} HTML table for the test
*/
HtmlLogger.prototype.createTestTableEntry = function(test) {
return '
' +
'
';
};
/**
* Returns new HTML results summary table
* @param {string} suiteId locator for suite
* @return {string} HTML table for test suite summary tabulation
*/
HtmlLogger.prototype.createSuiteSummaryTable = function(suiteId) {
return '
' +
'
Passed
Failed
Warnings
Unverified
' +
'
Total
' +
'
0
' +
'
0
' +
'
0
' +
'
0
' +
'
0
';
};
/**
* Prepares the report format. This report is shown when tests are launched
* and as tests begin to finish it is updated with other details.
* As test completes results are added (hidden initially) and summary table
* is updated.
*/
HtmlLogger.prototype.logTestGrid = function() {
var html = [];
var hidden = this.testSuiteDirectory.suites.length > 1;
// header
if (this.headerMessage) {
html.push('
');
html.push('
' + this.headerMessage);
html.push('
' +
'Note: Please ignore any flash or messages that appear. ' +
'They are generated from our tests.' +
'
');
html.push('');
var allResults = [];
var failCases = 0;
var totalCases = 0;
for (var i = 0; i < this.testSuiteDirectory.suites.length; i++) {
var suiteId = this.testSuiteDirectory.suites[i].id;
var tests = this.testSuiteDirectory.suites[i].tests;
var suiteName = this.testSuiteDirectory.suites[i].name;
// generate results body for suite
var htmlBody = [];
var manualTests = 0;
for (var j = 0; j < tests.length; j++) {
if (tests[j].manual) {
manualTests += 1;
}
htmlBody.push(this.createTestTableEntry(tests[j]));
}
// Suite Summary
html.push('
');
// test suites
html.push(htmlBody.join(''));
// close suite summary
html.push('
');
}
// footer - json script
html.push('
' +
'
');
html.push('');
html.push('
');
html.push('');
html.push('
Results:
');
html.push('');
html.push('
Baseline Results:
');
html.push('
');
this.outputDiv.innerHTML = html.join('');
if (self.gadgets && gadgets.window && gadgets.window.adjustHeight) {
// Do this only if dynamic height is supported. This is useful when it's
// run inside the orkut container, for example.
gadgets.window.adjustHeight();
}
};
/**
* Displays form to set required fields for restful testing.
* @param finishCallback
*/
HtmlLogger.prototype.restfulPreTestDialog = function(finishCallback) {
if (Config.ready || Config.baseUrl != null && Config.securityToken != null) {
Config.ready = true;
this.logTestGrid();
finishCallback();
return;
}
HtmlLoggerUtils.logger = this;
HtmlLoggerUtils.callback = finishCallback;
var html = [];
html.push('
');
html.push('Enter details to continue testing.
');
if (Config.baseUrl == null) {
html.push('
Base URL:
' +
'' +
'
');
}
if (Config.securityToken == null) {
html.push('
');
this.outputDiv.innerHTML = html.join('');
};
/**
* Sets up the config file for restful testing. Displays test grid and calls
* callback.
*/
HtmlLogger.prototype.handleRestfulPreTestConfig = function() {
var baseUrl = document.getElementById('baseUrl');
baseUrl = baseUrl ? baseUrl.value : Config.baseUrl;
var tokenPrefix = document.getElementById('tokenPrefix');
tokenPrefix = tokenPrefix ? tokenPrefix.value : Config.tokenPrefix;
var securityToken = document.getElementById('securityToken');
securityToken = securityToken ? tokenPrefix + '=' + securityToken.value
: Config.securityToken;
Config.saveUrls(baseUrl, securityToken);
this.logTestGrid();
HtmlLoggerUtils.callback();
};
/**
* Updates result for the executed test. This method is called to log result
* each time test is executed. It performs following tasks
* 1. It creates entry for the test
* 2. Notes if the test result is different from golden result
* 3. It adds bugs link for known bugs for the test
* 4. Adds buttons to re-run and expand/collapse sub-results
*
* @param {ResultGroup} result of the test executed
*/
HtmlLogger.prototype.updateTestResult = function(result) {
var tableElem = document.getElementById('table_' + result.test.id);
var newRowLoc = tableElem.rows.length;
tableElem.insertRow(newRowLoc);
var newRow = tableElem.rows[newRowLoc];
newRow.style.display = 'table-row';
var changeStatus = (result.delta) ? 'broken' : 'fixed';
var className = 'category';
className += result.delta ? ('-changed-' + changeStatus) : '';
newRow.className = className;
var time = result.startTime && result.finishtime ?
' [' + (result.finishtime - result.startTime) + ' ms] ' : '';
var isStableTest = Assert.arrayContains(result.tags, 'stable');
var entry = [];
entry.push('
');
entry.push('');
entry.push('[' + result.id + '] [' +
(result.test.priority ? result.test.priority : Test.PRIORITY.P2) +
' ]:: ');
entry.push(' ');
entry.push(result.name);
entry.push(': ');
if (result.severity < Result.severity.PASS) {
result.severity = Result.severity.UNVERIFIED;
}
entry.push('' + Result.severity.getString(result.severity) + '');
if (result.delta) {
entry.push('[CHANGED FROM LAST RUN]');
}
entry.push(time);
// Display if the test is marked as stable.
if (result.tags && result.tags.length > 0) {
if (isStableTest) {
entry.push(' Stable Test');
}
}
// Display test result roll up.
var total = result.getTotal();
if (Config.internal && Config.internal == true) {
// Display test case associated bugs links.
if (result.bugs && result.bugs.length > 0) {
entry.push(' Bugs: ');
for (var i = 0; i < result.bugs.length; i++) {
entry.push('' + result.bugs[i] + ' ');
}
}
}
var hidden = !result.delta && total.warnings == 0 && total.failed == 0;
// Add Run Again button.
entry.push(' ');
entry.push('');
entry.push('
');
newRow.innerHTML = entry.join('');
for (var j = result.verifications.length - 1; j >= 0; j--) {
this.addVerifications(result.verifications[j], result.test.id, hidden);
}
if (result.test.description) {
this.addDescription(result.test, hidden);
}
};
/**
* Creates one HTML table row for the test description
* @param {TestCase} test testcase whose description to be printed
* @param {boolean} hidden whether the row to be displayed in the beginning
*/
HtmlLogger.prototype.addDescription = function(test, hidden) {
var tableElem = document.getElementById('table_' + test.id);
tableElem.insertRow(1);
var newRow = tableElem.rows[1];
if (hidden) {
newRow.style.display = 'none';
}
newRow.className = 'verification';
newRow.innerHTML = '
' +
'Description> ' + test.description + '
';
};
/**
* Creates one HTML row for the result object (ResultValidation).
* @param {ResultValidation} result to convert to HTML
* @param {string} testId id of the test case
* @param {boolean} hidden whether the row should be hidden or displayed.
* If set to true, the row will have display style none
*/
HtmlLogger.prototype.addVerifications = function(result, testId, hidden) {
var tableElem = document.getElementById('table_' + testId);
tableElem.insertRow(1);
var newRow = tableElem.rows[1];
if (hidden) {
newRow.style.display = 'none';
}
var changeStatus = (result.delta) ? 'broken' : 'fixed';
var className = 'verification';
className += result.delta ? ('-changed-' + changeStatus) : '';
newRow.className = className;
var time = result.startTime && result.finishtime ?
' [' + (result.finishtime - result.startTime) + ' ms] ' : '';
var actualValue = (typeof(result.actual) == 'object') ?
Helper.getString(result.actual) : result.actual;
var expectedValue = (typeof(result.expected) == 'object') ?
Helper.getString(result.expected) : result.expected;
var entry = [];
entry.push('
');
newRow.innerHTML = entry.join('');
};
/**
* Updates test summary table for the test suite and gadget
* @param {ResultGroup} result of the test
*/
HtmlLogger.prototype.updateSuiteSummary = function(result) {
var resultText;
if (result.severity == Result.severity.UNVERIFIED) {
resultText = Result.severity.getString(result.severity).substr(0, 3);
} else {
resultText = Result.severity.getString(result.severity).substr(0, 4);
}
var total = 0;
var found = false;
var failCount = 0;
var passCount = 0;
var unvCount = 0;
var warnCount = 0;
for (var i = 0; i < this.testSuiteDirectory.suites.length; i++) {
var suite = this.testSuiteDirectory.suites[i];
var resultElem = document.getElementById(suite.id + '_' + resultText);
var suiteTotalElem = document.getElementById(suite.id + '_TOT');
var suiteTotal = 0;
for (var j = 0; j < suite.tests.length; j++) {
if (suite.tests[j].id == result.test.id) {
var resCount = parseInt(resultElem.innerHTML, 10);
resultElem.innerHTML = ++resCount;
suiteTotal = parseInt(suiteTotalElem.innerHTML, 10);
suiteTotalElem.innerHTML = ++suiteTotal;
found = true;
break;
} else if (found) {
break;
}
}
// calculate counts for final summary
var counterElem = document.getElementById(suite.id + '_PASS');
passCount += parseInt(counterElem.innerHTML);
counterElem = document.getElementById(suite.id + '_FAIL');
failCount += parseInt(counterElem.innerHTML);
counterElem = document.getElementById(suite.id + '_WARN');
warnCount += parseInt(counterElem.innerHTML);
counterElem = document.getElementById(suite.id + '_UNV');
unvCount += parseInt(counterElem.innerHTML);
total += parseInt(suiteTotalElem.innerHTML);
}
// Update final summary;
var counterLocation = document.getElementById('TOTAL_PASS');
counterLocation.innerHTML = passCount;
counterLocation = document.getElementById('TOTAL_FAIL');
counterLocation.innerHTML = failCount;
counterLocation = document.getElementById('TOTAL_WARN');
counterLocation.innerHTML = warnCount;
counterLocation = document.getElementById('TOTAL_UNV');
counterLocation.innerHTML = unvCount;
counterLocation = document.getElementById('TOTAL_TOT');
counterLocation.innerHTML = total;
};
/**
* Updates the priority table with the details of priority tests.
* @param {Array} priorityFailInfo information of failed cases on per
* priority basis
* @param {status} status of the test execution
*/
HtmlLogger.prototype.updatePriorityTable = function(priorityFailInfo, status) {
var priorityDescription = {};
priorityDescription[Test.PRIORITY.P4] =
'Visual cosmetic bugs. Or something like that. Lowest priority bug.' +
'You can fix when you have nothing else to do.';
priorityDescription[Test.PRIORITY.P3] =
'But that causes some irritation but you can live with it most of the' +
' time.';
priorityDescription[Test.PRIORITY.P2] =
'Functional nice to have breaks. i.e Exceptions for undefined behavior';
priorityDescription[Test.PRIORITY.P1] =
'Important bugs not exactly falling in the P0s. But have negative impact';
priorityDescription[Test.PRIORITY.P0] =
'You are not doing something stated in the spec. You are not spec' +
' compliant';
var prioritySummary = document.getElementById('priority-summary');
for (var priority in priorityFailInfo) {
if (priorityFailInfo[priority].length > 0) {
var priorityDesc = [];
for (var i = 0; i < priorityFailInfo[priority].length; ++i) {
priorityDesc.push(priorityFailInfo[priority][i].name + ' :: ' +
priorityFailInfo[priority][i].id);
}
prioritySummary.insertRow(0);
var row = prioritySummary.rows[0];
row.innerHTML = '
' + priority + '
' +
'
' + priorityDescription[priority] + '
' +
'
' + priorityFailInfo[priority].length +
'
' +
priorityDesc.join(' ') + '
';
}
}
if (prioritySummary.rows.length > 0) {
prioritySummary.insertRow(0);
var row = prioritySummary.rows[0];
row.innerHTML = '
Priority
' +
'
Description
' +
'
Failures
' +
'
Info
';
prioritySummary.className = status;
}
var priorityInfoDiv = document.getElementById('priority-fail-info');
priorityInfoDiv.innerHTML = gadgets.json.stringify(priorityFailInfo);
};
/**
* Adds error links for failed, unverified and warning results for each
* suite. It will also make sure that suite button caption is correct.
*
* @param {Array.} resultSets array of resultSets each resultSet
* maps to testSuite in a directory
*/
HtmlLogger.prototype.updateSuitesHeader = function(resultSets) {
var suiteResult = 0;
for (var i = 0; i < resultSets.length; i++) {
var id = resultSets[i].id;
var failText = '';
var warnText = '';
var unvText = '';
var warn = 0;
var unv = 0;
var fail = 0;
for (var j = 0; j < resultSets[i].results.length; j++) {
var result = resultSets[i].results[j];
switch(result.severity) {
case Result.severity.UNVERIFIED:
unvText += '' +
result.test.id + ', ';
unv++;
break;
case Result.severity.FAIL:
var link = '' +
result.test.id + ', '
failText += link;
fail++;
this.priorityFailInfo[
result.test.priority ? result.test.priority : Test.PRIORITY.P2
].push({ name: resultSets[i].name, id: result.id });
break;
case Result.severity.WARNING:
warnText += '' +
result.test.id + ', ';
warn++;
break;
}
}
suiteResult = (fail > 0) ? 3 : (warn > 0) ? 2 : (unv > 0) ? 1 : 0;
if (suiteResult > this.summaryResult) {
this.summaryResult = suiteResult;
}
var suiteTitle = document.getElementById(id + '_title');
suiteTitle.className = this.statusClassName[suiteResult];
var suiteTable = document.getElementById(id + '_table');
suiteTable.className = this.statusClassName[suiteResult];
var elem = document.getElementById(id + '_error_links');
elem.innerHTML =
(fail ? 'Failed: ' + failText : '') +
(warn ? ' Warnings: ' + warnText : '') +
(unv ? ' Unverifieds: ' + unvText : '');
}
};
/**
* Updates main summary table after all tests are run
*
* @param {Array.} resultSets array of resultSets each resultSet
* maps to testSuite in a directory
*/
HtmlLogger.prototype.updateSummaryHeader = function(resultSets) {
this.updatePriorityTable(this.priorityFailInfo,
this.statusClassName[this.summaryResult]);
if (resultSets.length == 1) {
var suite_summary_row =
document.getElementById(resultSets[0].id + '_summary_row');
suite_summary_row.style.display = 'none';
}
var summary = document.getElementById('summary');
summary.className = 'gadget-' + this.statusClassName[this.summaryResult];
var summaryTable = document.getElementById('TOTAL_table');
summaryTable.className = this.statusClassName[this.summaryResult];
var executionStatus = document.getElementById('execution-status');
if (this.testSuiteDirectory.suites.length === 1) {
executionStatus.innerHTML = '';
} else {
executionStatus.innerHTML = 'Finished';
executionStatus.className = '';
}
};
/**
* Will convert results in simple Array and puts it in jason box for you to save
* it as golden results. Golden results will be used as benchmark for later
* test results.
* @param {Array.} resultSets The array of resultSets
* @param {Object} goldenResults Jason representation of results
*/
HtmlLogger.prototype.updateResultBoxes = function(resultSets, goldenResults, context) {
// golden results hidden box
var goldenBoxHidden = document.getElementById('testArea');
goldenBoxHidden.innerHTML = Helper.getString(
Helper.convertResultsToMapExcludeVerifications(resultSets));
HtmlLoggerUtils.setResultCollection(resultSets);
// visible golden results
var goldenBoxVisible = document.getElementById('goldenArea');
goldenBoxVisible.innerHTML = Helper.stringify(goldenResults);
XmlLoggerUtils.setResultSet(resultSets);
XmlLoggerUtils.setContainer(testRunner.getContext().getContainer().name);
XmlLoggerUtils.setContext(context);
var elem = document.getElementById('xml-link');
elem.style.display = "inline";
if (self.gadgets && gadgets.window && gadgets.window.adjustHeight) {
// Do this only if dynamic height is supported. This is useful when it's
// run inside the orkut container, for example.
gadgets.window.adjustHeight();
}
};
/**
* HtmlLoggerUtils namespace.
* This namespace holds many functions to aid the generated HTML from the
* HtmlLogger class, contains methods to collapse/expand results, store result
* json information for external calls, and handlers for the buttons generated
* by the HtmlLogger.
*/
var HtmlLoggerUtils = function() {};
/** Text for collapse all button displayed at suite summary level */
HtmlLoggerUtils.COLLAPSE_ALL_TEXT = 'Collapse all sub results';
/** Text for expand all button displayed at suite summary level */
HtmlLoggerUtils.EXPAND_ALL_TEXT = 'Expand all sub results';
/**
* Toggles the visibility of the sub-results of a single result in result table,
* changes the text of the button that triggered this action
* (parameter 'element') and finally if possible adjusts
* the height of the gadget.
* This function searches for the parent table container of each result then
* for every TR inside other than the result header, will change it display
* property to 'none' or 'table-row' as necessary.
* Additionally at the end of the function if gadgets.window.adjustHeight
* function is available it will be called to readjust the height of the gadget.
* @param {Element} element The button that triggered the collapse/expand event.
*/
HtmlLoggerUtils.toggleHideSubResult = function(element) {
// Change the button value accordingly
if (element.tagName == 'INPUT') {
if (element.value == 'Collapse') {
element.value = 'Expand';
} else {
element.value = 'Collapse';
}
}
var displayStyle;
if (element.value == 'Expand') {
displayStyle = 'none';
} else {
displayStyle = 'table-row';
}
// Find the table container
while (element.tagName != 'TABLE') {
element = element.parentNode;
}
// Find the contained elements to be hidden (the inner table)
var tables = element.getElementsByTagName('TR');
for (var i = 0; tables && i < tables.length; i++) {
if (tables[i].className == 'verification') {
tables[i].style.display = displayStyle;
}
}
if (self.gadgets && gadgets.window && gadgets.window.adjustHeight) {
// Do this only if dynamic height is supported. This is useful when it's
// run inside the orkut container, for example.
gadgets.window.adjustHeight();
}
};
/**
* Toggles the visibility of the sub-results for all tests in a suite,
* changes the text of the button that triggered this action
* (parameter 'element') and finally if possible adjusts the height of the
* gadget.
* This function searches for the parent row container of all results then
* for every INPUT element in that row container, will check if it needs to be
* toggled and call HtmlLoggerUtils.toggleHideSubResults.
* Additionally at the end of the function if gadgets.window.adjustHeight
* function is available it will be called to readjust the height of the gadget.
* @param {Element} element The button that triggered the collapse/expand event.
*/
HtmlLoggerUtils.toggleHideAllSubResults = function(element) {
// Change the button value accordingly
if (element.tagName == 'INPUT') {
if (element.value == HtmlLoggerUtils.COLLAPSE_ALL_TEXT) {
element.value = HtmlLoggerUtils.EXPAND_ALL_TEXT;
} else {
element.value = HtmlLoggerUtils.COLLAPSE_ALL_TEXT;
}
}
var caption = element.value;
// Find the table container
while (element.tagName != 'TR' || element.className != 'test-summary') {
element = element.parentNode;
}
// Find the contained elements to be hidden (the inner table)
var inputs = element.getElementsByTagName('INPUT');
for (var i = 0; inputs && i < inputs.length; i++) {
if (inputs[i].value == 'Expand' &&
caption == HtmlLoggerUtils.COLLAPSE_ALL_TEXT) {
HtmlLoggerUtils.toggleHideSubResult(inputs[i]);
} else if (inputs[i].value == 'Collapse' &&
caption == HtmlLoggerUtils.EXPAND_ALL_TEXT) {
HtmlLoggerUtils.toggleHideSubResult(inputs[i]);
}
}
if (self.gadgets && gadgets.window && gadgets.window.adjustHeight) {
// Do this only if dynamic height is supported. This is useful when it's
// run inside the orkut container, for example.
gadgets.window.adjustHeight();
}
};
/**
* Toggles the visibility of results for all tests in a suite. It hides/shows
* detailis of results of suite. It also toggles the name of the button that
* triggered this action (parameter 'element') and finally if possible adjusts
* the height of the gadget.
* This function searches for the parent table container for suite then
* for every TR with class name 'test-summary', will change its display
* property to 'none' or 'table-row' as necessary.
* Additionally at the end of the function if gadgets.window.adjustHeight
* function is available it will be called to readjust the height of the gadget.
* @param {Element} element The button that triggered the collapse/expand event.
*/
HtmlLoggerUtils.toggleHideTestSuiteResults = function(element) {
// Change the button value accordingly
if (element.tagName == 'INPUT') {
if (element.value == 'Collapse') {
element.value = 'Expand';
} else {
element.value = 'Collapse';
}
}
// Find the table container
while (element.tagName != 'TABLE' || element.className != 'suitesummary') {
element = element.parentNode;
}
// Find the contained elements to be hidden (the inner table)
var tables = element.getElementsByTagName('TR');
for (var i = 0; tables && i < tables.length; i++) {
if (tables[i].className == 'test-summary') {
if (tables[i].style.display == 'none') {
tables[i].style.display = 'table-row';
} else {
tables[i].style.display = 'none';
}
}
}
if (self.gadgets && gadgets.window && gadgets.window.adjustHeight) {
// Do this only if dynamic height is supported. This is useful when it's
// run inside the orkut container, for example.
gadgets.window.adjustHeight();
}
};
/**
* Toggles the visibility of details of all test suites. It hides/shows details
* of results of all suites. It also toggles the name of the button that
* triggered this action (parameter 'element') and finally if possible adjusts
* the height of the gadget.
* This function finds all elements with class name 'suitesummary',
* will change display property to 'none' or 'table-row' as necessary for all
* matching elements.
* Additionally at the end of the function if gadgets.window.adjustHeight
* function is available it will be called to readjust the height of the gadget.
* @param {Element} element The button that triggered the collapse/expand event.
*/
HtmlLoggerUtils.toggleHideTestSuites = function(element) {
// Change the button value accordingly
if (element.tagName == 'INPUT') {
if (element.value == 'Collapse') {
element.value = 'Expand';
} else {
element.value = 'Collapse';
}
}
// Find the contained elements to be hidden (the inner table)
var tables = document.getElementsByTagName('TABLE');
for (var i = 0; tables && i < tables.length; i++) {
if (tables[i].className == 'suitesummary') {
if (tables[i].style.display == 'none') {
tables[i].style.display = 'table-row';
} else {
tables[i].style.display = 'none';
}
}
}
if (self.gadgets && gadgets.window && gadgets.window.adjustHeight) {
// Do this only if dynamic height is supported. This is useful when it's
// run inside the orkut container, for example.
gadgets.window.adjustHeight();
}
};
/**
* Stores the results for external static access.
* @type {Array.