function smf_StatsCenter(oOptions) { this.opt = oOptions; this.oTable = null; this.oYears = {}; this.bIsLoading = false; this.init(); } smf_StatsCenter.prototype.init = function () { this.oTable = document.getElementById(this.opt.sTableId); // Is the table actually present? if (typeof(this.oTable) != 'object') return; // Find all months and years defined in the table. var aRows = this.oTable.getElementsByTagName('tr'); var aResults = []; var sYearId = null; var oCurYear = null; var sMonthId = null; var oCurMonth = null; for (var i = 0, n = aRows.length; i < n; i++) { // Check if the current row represents a year. if ((aResults = this.opt.reYearPattern.exec(aRows[i].id)) != null) { // The id is part of the pattern match. sYearId = aResults[1]; // Setup the object that'll have the state information of the year. this.oYears[sYearId] = { oCollapseImage: document.getElementById(this.opt.sYearImageIdPrefix + sYearId), oMonths: {} }; // Create a shortcut, makes things more readable. oCurYear = this.oYears[sYearId]; // Use the collapse image to determine the current state. oCurYear.bIsCollapsed = oCurYear.oCollapseImage.src.indexOf(this.opt.sYearImageCollapsed) >= 0; // Setup the toggle element for the year. oCurYear.oToggle = new smc_Toggle({ bToggleEnabled: true, bCurrentlyCollapsed: oCurYear.bIsCollapsed, instanceRef: this, sYearId: sYearId, funcOnBeforeCollapse: function () { this.opt.instanceRef.onBeforeCollapseYear(this); }, aSwappableContainers: [ ], aSwapImages: [ { sId: this.opt.sYearImageIdPrefix + sYearId, srcExpanded: smf_images_url + '/' + this.opt.sYearImageExpanded, altExpanded: '-', srcCollapsed: smf_images_url + '/' + this.opt.sYearImageCollapsed, altCollapsed: '+' } ], aSwapLinks: [ { sId: this.opt.sYearLinkIdPrefix + sYearId, msgExpanded: sYearId, msgCollapsed: sYearId } ] }); } // Or maybe the current row represents a month. else if ((aResults = this.opt.reMonthPattern.exec(aRows[i].id)) != null) { // Set the id to the matched pattern. sMonthId = aResults[1]; // Initialize the month as a child object of the year. oCurYear.oMonths[sMonthId] = { oCollapseImage: document.getElementById(this.opt.sMonthImageIdPrefix + sMonthId) }; // Create a shortcut to the current month. oCurMonth = oCurYear.oMonths[sMonthId]; // Determine whether the month is currently collapsed or expanded.. oCurMonth.bIsCollapsed = oCurMonth.oCollapseImage.src.indexOf(this.opt.sMonthImageCollapsed) >= 0; var sLinkText = getInnerHTML(document.getElementById(this.opt.sMonthLinkIdPrefix + sMonthId)); // Setup the toggle element for the month. oCurMonth.oToggle = new smc_Toggle({ bToggleEnabled: true, bCurrentlyCollapsed: oCurMonth.bIsCollapsed, instanceRef: this, sMonthId: sMonthId, funcOnBeforeCollapse: function () { this.opt.instanceRef.onBeforeCollapseMonth(this); }, funcOnBeforeExpand: function () { this.opt.instanceRef.onBeforeExpandMonth(this); }, aSwappableContainers: [ ], aSwapImages: [ { sId: this.opt.sMonthImageIdPrefix + sMonthId, srcExpanded: smf_images_url + '/' + this.opt.sMonthImageExpanded, altExpanded: '-', srcCollapsed: smf_images_url + '/' + this.opt.sMonthImageCollapsed, altCollapsed: '+' } ], aSwapLinks: [ { sId: this.opt.sMonthLinkIdPrefix + sMonthId, msgExpanded: sLinkText, msgCollapsed: sLinkText } ] }); oCurYear.oToggle.opt.aSwappableContainers[oCurYear.oToggle.opt.aSwappableContainers.length] = aRows[i].id; } else if((aResults = this.opt.reDayPattern.exec(aRows[i].id)) != null) { oCurMonth.oToggle.opt.aSwappableContainers[oCurMonth.oToggle.opt.aSwappableContainers.length] = aRows[i].id; oCurYear.oToggle.opt.aSwappableContainers[oCurYear.oToggle.opt.aSwappableContainers.length] = aRows[i].id; } } // Collapse all collapsed years! for (i = 0; i < this.opt.aCollapsedYears.length; i++) this.oYears[this.opt.aCollapsedYears[i]].oToggle.toggle(); } smf_StatsCenter.prototype.onBeforeCollapseYear = function (oToggle) { // Tell SMF that all underlying months have disappeared. for (var sMonth in this.oYears[oToggle.opt.sYearId].oMonths) if (this.oYears[oToggle.opt.sYearId].oMonths[sMonth].oToggle.opt.aSwappableContainers.length > 0) this.oYears[oToggle.opt.sYearId].oMonths[sMonth].oToggle.changeState(true); } smf_StatsCenter.prototype.onBeforeCollapseMonth = function (oToggle) { if (!oToggle.bCollapsed) { // Tell SMF that it the state has changed. getXMLDocument(smf_prepareScriptUrl(smf_scripturl) + 'action=stats;collapse=' + oToggle.opt.sMonthId + ';xml'); // Remove the month rows from the year toggle. var aNewContainers = []; var oYearToggle = this.oYears[oToggle.opt.sMonthId.substr(0, 4)].oToggle; for (var i = 0, n = oYearToggle.opt.aSwappableContainers.length; i < n; i++) if (!in_array(oYearToggle.opt.aSwappableContainers[i], oToggle.opt.aSwappableContainers)) aNewContainers[aNewContainers.length] = oYearToggle.opt.aSwappableContainers[i]; oYearToggle.opt.aSwappableContainers = aNewContainers; } } smf_StatsCenter.prototype.onBeforeExpandMonth = function (oToggle) { // Ignore if we're still loading the previous batch. if (this.bIsLoading) return; if (oToggle.opt.aSwappableContainers.length == 0) { // A complicated way to call getXMLDocument, but stay in scope. this.tmpMethod = getXMLDocument; this.oXmlRequestHandle = this.tmpMethod(smf_prepareScriptUrl(smf_scripturl) + 'action=stats;expand=' + oToggle.opt.sMonthId + ';xml', this.onDocReceived); delete this.tmpMethod; if ('ajax_indicator' in window) ajax_indicator(true); this.bIsLoading = true; } // Silently let SMF know this one is expanded. else getXMLDocument(smf_prepareScriptUrl(smf_scripturl) + 'action=stats;expand=' + oToggle.opt.sMonthId + ';xml'); } smf_StatsCenter.prototype.onDocReceived = function (oXMLDoc) { // Loop through all the months we got from the XML. var aMonthNodes = oXMLDoc.getElementsByTagName('month'); for (var iMonthIndex = 0, iNumMonths = aMonthNodes.length; iMonthIndex < iNumMonths; iMonthIndex++) { var sMonthId = aMonthNodes[iMonthIndex].getAttribute('id'); var iStart = document.getElementById('tr_month_' + sMonthId).rowIndex + 1; var sYearId = sMonthId.substr(0, 4); // Within the current months, check out all the days. var aDayNodes = aMonthNodes[iMonthIndex].getElementsByTagName('day'); for (var iDayIndex = 0, iNumDays = aDayNodes.length; iDayIndex < iNumDays; iDayIndex++) { var oCurRow = this.oTable.insertRow(iStart + iDayIndex); oCurRow.className = this.opt.sDayRowClassname; oCurRow.id = this.opt.sDayRowIdPrefix + aDayNodes[iDayIndex].getAttribute('date'); for (var iCellIndex = 0, iNumCells = this.opt.aDataCells.length; iCellIndex < iNumCells; iCellIndex++) { var oCurCell = oCurRow.insertCell(-1); if (this.opt.aDataCells[iCellIndex] == 'date') oCurCell.style.paddingLeft = '6ex'; else oCurCell.style.textAlign = 'center'; var sCurData = aDayNodes[iDayIndex].getAttribute(this.opt.aDataCells[iCellIndex]); oCurCell.appendChild(document.createTextNode(sCurData)); } // Add these day rows to the toggle objects in case of collapse. this.oYears[sYearId].oMonths[sMonthId].oToggle.opt.aSwappableContainers[this.oYears[sYearId].oMonths[sMonthId].oToggle.opt.aSwappableContainers.length] = oCurRow.id; this.oYears[sYearId].oToggle.opt.aSwappableContainers[this.oYears[sYearId].oToggle.opt.aSwappableContainers.length] = oCurRow.id; } } this.bIsLoading = false; if (typeof(window.ajax_indicator) == 'function') ajax_indicator(false); }