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