cvs: pearweb /public_html/css packages_status.css /public_html/javascript sorttable.js /public_html/qa packages_status.php
| From: | Tobias Schlitt | Date: | Sat, 13 Aug 2005 11:14:37 +0000 |
| Subject: | cvs: pearweb /public_html/css packages_status.css /public_html/javascript sorttable.js /public_html/qa packages_status.php | ||
| Groups: | php.pear.cvs php.pear.core | ||
| Request: | Send a blank email to pear-core+get-3509@lists.php.net to get a copy of this message | ||
toby Sat Aug 13 07:14:37 2005 EDT
Added files:
/pearweb/public_html/css packages_status.css
/pearweb/public_html/javascript sorttable.js
/pearweb/public_html/qa packages_status.php
Log:
* Adding QA packages overview, made by Arnaud.
http://cvs.php.net/co.php/pearweb/public_html/css/packages_status.css?r=1.1&p=1 Index: pearweb/public_html/css/packages_status.css +++ pearweb/public_html/css/packages_status.css /* Parts of the code borrowed from csszengarden.com, hicksdesign.co.uk */ html { margin: 0px; padding: 0px; padding-left: 2%;} body { font-size: 13px; font-family: "Lucida Grande","Lucida Sans Unicode",geneva,verdana,sans-serif; color: #525252; background-color: #fff; margin: 0px; padding: 0px;} #pageHeader h1 { font-size: 18px; } #pageHeader h2 { font-size: 14px; } table { border : 1px solid #330033; margin: 0px; padding: 0px; margin-top: 5px; margin-bottom: 20px; } table th { color: #000; border-bottom: 1px solid #000; } td { padding: 2px; border-left: dashed 1px #669999; border-right: dashed 1px #669999; } table caption { color: #000; font-size: 90%; } ..old table { background-color: #BEBDFF; } ..old caption { color: #F00; } #footer { font-size: 9px; } em { font-weight: bold; } http://cvs.php.net/co.php/pearweb/public_html/javascript/sorttable.js?r=1.1&p=1 Index: pearweb/public_html/javascript/sorttable.js +++ pearweb/public_html/javascript/sorttable.js addEvent(window, "load", sortables_init); var SORT_COLUMN_INDEX; function sortables_init() { // Find all tables with class sortable and make them sortable if (!document.getElementsByTagName) return; tbls = document.getElementsByTagName("table"); for (ti=0;ti<tbls.length;ti++) { thisTbl = tbls[ti]; if (((' '+thisTbl.className+' ').indexOf("sortable") != -1) && (thisTbl.id)) { //initTable(thisTbl.id); ts_makeSortable(thisTbl); } } } function ts_makeSortable(table) { if (table.rows && table.rows.length > 0) { var firstRow = table.rows[0]; } if (!firstRow) return; // We have a first row: assume it's the header, and make its contents clickable links for (var i=0;i<firstRow.cells.length;i++) { var cell = firstRow.cells[i]; var txt = ts_getInnerText(cell); cell.innerHTML = '<a href="#" class="sortheader" onclick="ts_resortTable(this);return false;">'+txt+'<span class="sortarrow"> </span></a>'; } } function ts_getInnerText(el) { if (typeof el == "string") return el; if (typeof el == "undefined") { return el }; if (el.innerText) return el.innerText; //Not needed but it is faster var str = ""; var cs = el.childNodes; var l = cs.length; for (var i = 0; i < l; i++) { switch (cs[i].nodeType) { case 1: //ELEMENT_NODE str += ts_getInnerText(cs[i]); break; case 3: //TEXT_NODE str += cs[i].nodeValue; break; } } return str; } function ts_resortTable(lnk) { // get the span var span; for (var ci=0;ci<lnk.childNodes.length;ci++) { if (lnk.childNodes[ci].tagName && lnk.childNodes[ci].tagName.toLowerCase() == 'span') span = lnk.childNodes[ci]; } var spantext = ts_getInnerText(span); var td = lnk.parentNode; var column = td.cellIndex; var table = getParent(td,'TABLE'); // Work out a type for the column if (table.rows.length <= 1) return; var itm = ts_getInnerText(table.rows[1].cells[column]); sortfn = ts_sort_caseinsensitive; if (itm.match(/^\d\d[\/-]\d\d[\/-]\d\d\d\d$/)) sortfn = ts_sort_date; if (itm.match(/^\d\d[\/-]\d\d[\/-]\d\d$/)) sortfn = ts_sort_date; if (itm.match(/^[£$]/)) sortfn = ts_sort_currency; if (itm.match(/^[\d\.]+$/)) sortfn = ts_sort_numeric; SORT_COLUMN_INDEX = column; var firstRow = new Array(); var newRows = new Array(); for (i=0;i<table.rows[0].length;i++) { firstRow[i] = table.rows[0][i]; } for (j=1;j<table.rows.length;j++) { newRows[j-1] = table.rows[j]; } newRows.sort(sortfn); if (span.getAttribute("sortdir") == 'down') { ARROW = ' ↑'; newRows.reverse(); span.setAttribute('sortdir','up'); } else { ARROW = ' ↓'; span.setAttribute('sortdir','down'); } // We appendChild rows that already exist to the tbody, so it moves them rather than creating new ones // don't do sortbottom rows for (i=0;i<newRows.length;i++) { if (!newRows[i].className || (newRows[i].className && (newRows[i].className.indexOf('sortbottom') == -1))) table.tBodies[0].appendChild(newRows[i]);} // do sortbottom rows only for (i=0;i<newRows.length;i++) { if (newRows[i].className && (newRows[i].className.indexOf('sortbottom') != -1)) table.tBodies[0].appendChild(newRows[i]);} // Delete any other arrows there may be showing var allspans = document.getElementsByTagName("span"); for (var ci=0;ci<allspans.length;ci++) { if (allspans[ci].className == 'sortarrow') { if (getParent(allspans[ci],"table") == getParent(lnk,"table")) { // in the same table as us? allspans[ci].innerHTML = ' '; } } } span.innerHTML = ARROW; } function getParent(el, pTagName) { if (el == null) return null; else if (el.nodeType == 1 && el.tagName.toLowerCase() == pTagName.toLowerCase()) // Gecko bug, supposed to be uppercase return el; else return getParent(el.parentNode, pTagName); } function ts_sort_date(a,b) { // y2k notes: two digit years less than 50 are treated as 20XX, greater than 50 are treated as 19XX aa = ts_getInnerText(a.cells[SORT_COLUMN_INDEX]); bb = ts_getInnerText(b.cells[SORT_COLUMN_INDEX]); if (aa.length == 10) { dt1 = aa.substr(6,4)+aa.substr(3,2)+aa.substr(0,2); } else { yr = aa.substr(6,2); if (parseInt(yr) < 50) { yr = '20'+yr; } else { yr = '19'+yr; } dt1 = yr+aa.substr(3,2)+aa.substr(0,2); } if (bb.length == 10) { dt2 = bb.substr(6,4)+bb.substr(3,2)+bb.substr(0,2); } else { yr = bb.substr(6,2); if (parseInt(yr) < 50) { yr = '20'+yr; } else { yr = '19'+yr; } dt2 = yr+bb.substr(3,2)+bb.substr(0,2); } if (dt1==dt2) return 0; if (dt1<dt2) return -1; return 1; } function ts_sort_currency(a,b) { aa = ts_getInnerText(a.cells[SORT_COLUMN_INDEX]).replace(/[^0-9.]/g,''); bb = ts_getInnerText(b.cells[SORT_COLUMN_INDEX]).replace(/[^0-9.]/g,''); return parseFloat(aa) - parseFloat(bb); } function ts_sort_numeric(a,b) { aa = parseFloat(ts_getInnerText(a.cells[SORT_COLUMN_INDEX])); if (isNaN(aa)) aa = 0; bb = parseFloat(ts_getInnerText(b.cells[SORT_COLUMN_INDEX])); if (isNaN(bb)) bb = 0; return aa-bb; } function ts_sort_caseinsensitive(a,b) { aa = ts_getInnerText(a.cells[SORT_COLUMN_INDEX]).toLowerCase(); bb = ts_getInnerText(b.cells[SORT_COLUMN_INDEX]).toLowerCase(); if (aa==bb) return 0; if (aa<bb) return -1; return 1; } function ts_sort_default(a,b) { aa = ts_getInnerText(a.cells[SORT_COLUMN_INDEX]); bb = ts_getInnerText(b.cells[SORT_COLUMN_INDEX]); if (aa==bb) return 0; if (aa<bb) return -1; return 1; } function addEvent(elm, evType, fn, useCapture) // addEvent and removeEvent // cross-browser event handling for IE5+, NS6 and Mozilla // By Scott Andrew { if (elm.addEventListener){ elm.addEventListener(evType, fn, useCapture); return true; } else if (elm.attachEvent){ var r = elm.attachEvent("on"+evType, fn); return r; } else { alert("Handler could not be removed"); } } http://cvs.php.net/co.php/pearweb/public_html/qa/packages_status.php?r=1.1&p=1 Index: pearweb/public_html/qa/packages_status.php +++ pearweb/public_html/qa/packages_status.php <?php /* +----------------------------------------------------------------------+ | PEAR Web site version 1.0 | +----------------------------------------------------------------------+ | Copyright (c) 2001-2005 The PHP Group | +----------------------------------------------------------------------+ | This source file is subject to version 2.02 of the PHP license, | | that is bundled with this package in the file LICENSE, and is | | available at through the world-wide-web at | | http://www.php.net/license/2_02.txt. | | If you did not receive a copy of the PHP license and are unable to | | obtain it through the world-wide-web, please send a note to | | license@php.net so we can mail you a copy immediately. | +----------------------------------------------------------------------+ | Authors: Arnaud Limbourg <arnaud@limbourg.com> | +----------------------------------------------------------------------+ $Id: packages_status.php,v 1.1 2005/08/13 11:14:37 toby Exp $ */ /** * This page will show a list of packages with latest * release information along with bug count and any other info * that may be used to identify unmaintained packages */ auth_require('pear.qa'); require 'HTML/Table.php'; $extra_style = '/css/packages_status.css'; // Sortable tables http://www.kryogenix.org/code/browser/sorttable/ $extra_header = ' <script src="/javascript/sorttable.js"></script> '; // Deactivate sidebar navigation, don't know if I got this right // $SIDEBAR_DATA = '-'; response_header('Quality Assurance Initiative - Packages status', $extra_style, $extra_header); $pck = new package(); $packages = $pck->listAll(false, false, false); if (PEAR::isError($packages)) { report_error('Cannot list packages'); response_footer(); exit(); } $total_packages_nbr = $studied_packages_nbr = 0; $states = array('snapshot', 'devel', 'alpha', 'beta', 'stable'); $tables = array(); $time_scale = 15552000; // how much time elapsed since last release, in seconds foreach ($states as $state) { $tables[$state]['old'] = new HTML_Table( array( 'id' => 'old' . $state, 'cellspacing' => 0, 'class' => 'sortable' ) ); $tables[$state]['old']->setCaption( 'Packages with state <em>' . $state . '</em> which have not been released in ' . $time_scale / 86400 . ' days' ); $tables[$state]['old']->setHeaderContents(0, 0, 'Package'); $tables[$state]['old']->setHeaderContents(0, 1, 'Version'); $tables[$state]['old']->setHeaderContents(0, 2, 'Date'); $tables[$state]['old']->setHeaderContents(0, 3, '# bugs'); $tables[$state]['new'] = new HTML_Table( array( 'id' => 'new' . $state, 'cellspacing' => 0, 'class' => 'sortable' ) ); $tables[$state]['new']->setCaption( 'Packages with state <em>' . $state . '</em> with a release in the past ' . $time_scale / 86400 . ' days' ); $tables[$state]['new']->setHeaderContents(0, 0, 'Package'); $tables[$state]['new']->setHeaderContents(0, 1, 'Version'); $tables[$state]['new']->setHeaderContents(0, 2, 'Date'); $tables[$state]['new']->setHeaderContents(0, 3, '# bugs'); } foreach ($packages as $package => $pck_data) { $total_packages_nbr++; $latest_release = $pck->getRecent(1, $package); if (PEAR::isError($latest_release) || count($latest_release) == 0) { continue; } $release_date = strtotime($latest_release[0]['releasedate']); $status = 'new'; if (time() - $time_scale > $release_date) { $status = 'old'; } $tables[$latest_release[0]['state']][$status]->addRow( array( make_link('/package/' . $package, $package, '', 'title=' . $package), $latest_release[0]['version'], date('d F Y', $release_date), $bugcount = bugcount($package) ) ); $studied_packages_nbr++; } $html = ''; foreach ($tables as $state => $table) { if ($table['old']->getRowCount() > 1) { $html .= '<div class="old">' . $table['old']->toHtml() . '</div>'; } if ($table['new']->getRowCount() > 1) { $html .= '<div id="new">' . $table['new']->toHtml() . '</div>' . "\n"; } } $out = ' <div id="container"> <div id="pageHeader"> <h1>Summary</h1> <div id="subtitle"> <h2>Number of packages in PEAR: {{TOTAL_PACKAGES_NUMBER}}</h2> <h2>Number of packages studied here : {{STUDIED_PACKAGES_NUMBER}}</h2> </div> </div> <div id="details"> {{TABLES}} </div> <div id="footer"> Page last updated on: {{UPDATE_DATE}} </div> </div> '; $search = array( '{{TOTAL_PACKAGES_NUMBER}}', '{{STUDIED_PACKAGES_NUMBER}}', '{{TABLES}}', '{{UPDATE_DATE}}', ); $replace = array( $total_packages_nbr, $studied_packages_nbr, $html, date('d F Y \a\t H:i:s') ); $out = str_replace($search, $replace, $out); echo $out; response_footer(); /** * Count number of bugs for a package * * @string package name * @return int number of bugs */ function bugcount($package) { global $dbh; $query = " SELECT COUNT(*) FROM bugdb WHERE package_name=" . $dbh->quoteSmart($package); $count = $dbh->getOne($query); if (PEAR::isError($count)) { return 0; } return (int) $count; } ?>
http://cvs.php.net/co.php/pearweb/public_html/css/packages_status.css?r=1.1&p=1 Index: pearweb/public_html/css/packages_status.css +++ pearweb/public_html/css/packages_status.css /* Parts of the code borrowed from csszengarden.com, hicksdesign.co.uk */ html { margin: 0px; padding: 0px; padding-left: 2%;} body { font-size: 13px; font-family: "Lucida Grande","Lucida Sans Unicode",geneva,verdana,sans-serif; color: #525252; background-color: #fff; margin: 0px; padding: 0px;} #pageHeader h1 { font-size: 18px; } #pageHeader h2 { font-size: 14px; } table { border : 1px solid #330033; margin: 0px; padding: 0px; margin-top: 5px; margin-bottom: 20px; } table th { color: #000; border-bottom: 1px solid #000; } td { padding: 2px; border-left: dashed 1px #669999; border-right: dashed 1px #669999; } table caption { color: #000; font-size: 90%; } ..old table { background-color: #BEBDFF; } ..old caption { color: #F00; } #footer { font-size: 9px; } em { font-weight: bold; } http://cvs.php.net/co.php/pearweb/public_html/javascript/sorttable.js?r=1.1&p=1 Index: pearweb/public_html/javascript/sorttable.js +++ pearweb/public_html/javascript/sorttable.js addEvent(window, "load", sortables_init); var SORT_COLUMN_INDEX; function sortables_init() { // Find all tables with class sortable and make them sortable if (!document.getElementsByTagName) return; tbls = document.getElementsByTagName("table"); for (ti=0;ti<tbls.length;ti++) { thisTbl = tbls[ti]; if (((' '+thisTbl.className+' ').indexOf("sortable") != -1) && (thisTbl.id)) { //initTable(thisTbl.id); ts_makeSortable(thisTbl); } } } function ts_makeSortable(table) { if (table.rows && table.rows.length > 0) { var firstRow = table.rows[0]; } if (!firstRow) return; // We have a first row: assume it's the header, and make its contents clickable links for (var i=0;i<firstRow.cells.length;i++) { var cell = firstRow.cells[i]; var txt = ts_getInnerText(cell); cell.innerHTML = '<a href="#" class="sortheader" onclick="ts_resortTable(this);return false;">'+txt+'<span class="sortarrow"> </span></a>'; } } function ts_getInnerText(el) { if (typeof el == "string") return el; if (typeof el == "undefined") { return el }; if (el.innerText) return el.innerText; //Not needed but it is faster var str = ""; var cs = el.childNodes; var l = cs.length; for (var i = 0; i < l; i++) { switch (cs[i].nodeType) { case 1: //ELEMENT_NODE str += ts_getInnerText(cs[i]); break; case 3: //TEXT_NODE str += cs[i].nodeValue; break; } } return str; } function ts_resortTable(lnk) { // get the span var span; for (var ci=0;ci<lnk.childNodes.length;ci++) { if (lnk.childNodes[ci].tagName && lnk.childNodes[ci].tagName.toLowerCase() == 'span') span = lnk.childNodes[ci]; } var spantext = ts_getInnerText(span); var td = lnk.parentNode; var column = td.cellIndex; var table = getParent(td,'TABLE'); // Work out a type for the column if (table.rows.length <= 1) return; var itm = ts_getInnerText(table.rows[1].cells[column]); sortfn = ts_sort_caseinsensitive; if (itm.match(/^\d\d[\/-]\d\d[\/-]\d\d\d\d$/)) sortfn = ts_sort_date; if (itm.match(/^\d\d[\/-]\d\d[\/-]\d\d$/)) sortfn = ts_sort_date; if (itm.match(/^[£$]/)) sortfn = ts_sort_currency; if (itm.match(/^[\d\.]+$/)) sortfn = ts_sort_numeric; SORT_COLUMN_INDEX = column; var firstRow = new Array(); var newRows = new Array(); for (i=0;i<table.rows[0].length;i++) { firstRow[i] = table.rows[0][i]; } for (j=1;j<table.rows.length;j++) { newRows[j-1] = table.rows[j]; } newRows.sort(sortfn); if (span.getAttribute("sortdir") == 'down') { ARROW = ' ↑'; newRows.reverse(); span.setAttribute('sortdir','up'); } else { ARROW = ' ↓'; span.setAttribute('sortdir','down'); } // We appendChild rows that already exist to the tbody, so it moves them rather than creating new ones // don't do sortbottom rows for (i=0;i<newRows.length;i++) { if (!newRows[i].className || (newRows[i].className && (newRows[i].className.indexOf('sortbottom') == -1))) table.tBodies[0].appendChild(newRows[i]);} // do sortbottom rows only for (i=0;i<newRows.length;i++) { if (newRows[i].className && (newRows[i].className.indexOf('sortbottom') != -1)) table.tBodies[0].appendChild(newRows[i]);} // Delete any other arrows there may be showing var allspans = document.getElementsByTagName("span"); for (var ci=0;ci<allspans.length;ci++) { if (allspans[ci].className == 'sortarrow') { if (getParent(allspans[ci],"table") == getParent(lnk,"table")) { // in the same table as us? allspans[ci].innerHTML = ' '; } } } span.innerHTML = ARROW; } function getParent(el, pTagName) { if (el == null) return null; else if (el.nodeType == 1 && el.tagName.toLowerCase() == pTagName.toLowerCase()) // Gecko bug, supposed to be uppercase return el; else return getParent(el.parentNode, pTagName); } function ts_sort_date(a,b) { // y2k notes: two digit years less than 50 are treated as 20XX, greater than 50 are treated as 19XX aa = ts_getInnerText(a.cells[SORT_COLUMN_INDEX]); bb = ts_getInnerText(b.cells[SORT_COLUMN_INDEX]); if (aa.length == 10) { dt1 = aa.substr(6,4)+aa.substr(3,2)+aa.substr(0,2); } else { yr = aa.substr(6,2); if (parseInt(yr) < 50) { yr = '20'+yr; } else { yr = '19'+yr; } dt1 = yr+aa.substr(3,2)+aa.substr(0,2); } if (bb.length == 10) { dt2 = bb.substr(6,4)+bb.substr(3,2)+bb.substr(0,2); } else { yr = bb.substr(6,2); if (parseInt(yr) < 50) { yr = '20'+yr; } else { yr = '19'+yr; } dt2 = yr+bb.substr(3,2)+bb.substr(0,2); } if (dt1==dt2) return 0; if (dt1<dt2) return -1; return 1; } function ts_sort_currency(a,b) { aa = ts_getInnerText(a.cells[SORT_COLUMN_INDEX]).replace(/[^0-9.]/g,''); bb = ts_getInnerText(b.cells[SORT_COLUMN_INDEX]).replace(/[^0-9.]/g,''); return parseFloat(aa) - parseFloat(bb); } function ts_sort_numeric(a,b) { aa = parseFloat(ts_getInnerText(a.cells[SORT_COLUMN_INDEX])); if (isNaN(aa)) aa = 0; bb = parseFloat(ts_getInnerText(b.cells[SORT_COLUMN_INDEX])); if (isNaN(bb)) bb = 0; return aa-bb; } function ts_sort_caseinsensitive(a,b) { aa = ts_getInnerText(a.cells[SORT_COLUMN_INDEX]).toLowerCase(); bb = ts_getInnerText(b.cells[SORT_COLUMN_INDEX]).toLowerCase(); if (aa==bb) return 0; if (aa<bb) return -1; return 1; } function ts_sort_default(a,b) { aa = ts_getInnerText(a.cells[SORT_COLUMN_INDEX]); bb = ts_getInnerText(b.cells[SORT_COLUMN_INDEX]); if (aa==bb) return 0; if (aa<bb) return -1; return 1; } function addEvent(elm, evType, fn, useCapture) // addEvent and removeEvent // cross-browser event handling for IE5+, NS6 and Mozilla // By Scott Andrew { if (elm.addEventListener){ elm.addEventListener(evType, fn, useCapture); return true; } else if (elm.attachEvent){ var r = elm.attachEvent("on"+evType, fn); return r; } else { alert("Handler could not be removed"); } } http://cvs.php.net/co.php/pearweb/public_html/qa/packages_status.php?r=1.1&p=1 Index: pearweb/public_html/qa/packages_status.php +++ pearweb/public_html/qa/packages_status.php <?php /* +----------------------------------------------------------------------+ | PEAR Web site version 1.0 | +----------------------------------------------------------------------+ | Copyright (c) 2001-2005 The PHP Group | +----------------------------------------------------------------------+ | This source file is subject to version 2.02 of the PHP license, | | that is bundled with this package in the file LICENSE, and is | | available at through the world-wide-web at | | http://www.php.net/license/2_02.txt. | | If you did not receive a copy of the PHP license and are unable to | | obtain it through the world-wide-web, please send a note to | | license@php.net so we can mail you a copy immediately. | +----------------------------------------------------------------------+ | Authors: Arnaud Limbourg <arnaud@limbourg.com> | +----------------------------------------------------------------------+ $Id: packages_status.php,v 1.1 2005/08/13 11:14:37 toby Exp $ */ /** * This page will show a list of packages with latest * release information along with bug count and any other info * that may be used to identify unmaintained packages */ auth_require('pear.qa'); require 'HTML/Table.php'; $extra_style = '/css/packages_status.css'; // Sortable tables http://www.kryogenix.org/code/browser/sorttable/ $extra_header = ' <script src="/javascript/sorttable.js"></script> '; // Deactivate sidebar navigation, don't know if I got this right // $SIDEBAR_DATA = '-'; response_header('Quality Assurance Initiative - Packages status', $extra_style, $extra_header); $pck = new package(); $packages = $pck->listAll(false, false, false); if (PEAR::isError($packages)) { report_error('Cannot list packages'); response_footer(); exit(); } $total_packages_nbr = $studied_packages_nbr = 0; $states = array('snapshot', 'devel', 'alpha', 'beta', 'stable'); $tables = array(); $time_scale = 15552000; // how much time elapsed since last release, in seconds foreach ($states as $state) { $tables[$state]['old'] = new HTML_Table( array( 'id' => 'old' . $state, 'cellspacing' => 0, 'class' => 'sortable' ) ); $tables[$state]['old']->setCaption( 'Packages with state <em>' . $state . '</em> which have not been released in ' . $time_scale / 86400 . ' days' ); $tables[$state]['old']->setHeaderContents(0, 0, 'Package'); $tables[$state]['old']->setHeaderContents(0, 1, 'Version'); $tables[$state]['old']->setHeaderContents(0, 2, 'Date'); $tables[$state]['old']->setHeaderContents(0, 3, '# bugs'); $tables[$state]['new'] = new HTML_Table( array( 'id' => 'new' . $state, 'cellspacing' => 0, 'class' => 'sortable' ) ); $tables[$state]['new']->setCaption( 'Packages with state <em>' . $state . '</em> with a release in the past ' . $time_scale / 86400 . ' days' ); $tables[$state]['new']->setHeaderContents(0, 0, 'Package'); $tables[$state]['new']->setHeaderContents(0, 1, 'Version'); $tables[$state]['new']->setHeaderContents(0, 2, 'Date'); $tables[$state]['new']->setHeaderContents(0, 3, '# bugs'); } foreach ($packages as $package => $pck_data) { $total_packages_nbr++; $latest_release = $pck->getRecent(1, $package); if (PEAR::isError($latest_release) || count($latest_release) == 0) { continue; } $release_date = strtotime($latest_release[0]['releasedate']); $status = 'new'; if (time() - $time_scale > $release_date) { $status = 'old'; } $tables[$latest_release[0]['state']][$status]->addRow( array( make_link('/package/' . $package, $package, '', 'title=' . $package), $latest_release[0]['version'], date('d F Y', $release_date), $bugcount = bugcount($package) ) ); $studied_packages_nbr++; } $html = ''; foreach ($tables as $state => $table) { if ($table['old']->getRowCount() > 1) { $html .= '<div class="old">' . $table['old']->toHtml() . '</div>'; } if ($table['new']->getRowCount() > 1) { $html .= '<div id="new">' . $table['new']->toHtml() . '</div>' . "\n"; } } $out = ' <div id="container"> <div id="pageHeader"> <h1>Summary</h1> <div id="subtitle"> <h2>Number of packages in PEAR: {{TOTAL_PACKAGES_NUMBER}}</h2> <h2>Number of packages studied here : {{STUDIED_PACKAGES_NUMBER}}</h2> </div> </div> <div id="details"> {{TABLES}} </div> <div id="footer"> Page last updated on: {{UPDATE_DATE}} </div> </div> '; $search = array( '{{TOTAL_PACKAGES_NUMBER}}', '{{STUDIED_PACKAGES_NUMBER}}', '{{TABLES}}', '{{UPDATE_DATE}}', ); $replace = array( $total_packages_nbr, $studied_packages_nbr, $html, date('d F Y \a\t H:i:s') ); $out = str_replace($search, $replace, $out); echo $out; response_footer(); /** * Count number of bugs for a package * * @string package name * @return int number of bugs */ function bugcount($package) { global $dbh; $query = " SELECT COUNT(*) FROM bugdb WHERE package_name=" . $dbh->quoteSmart($package); $count = $dbh->getOne($query); if (PEAR::isError($count)) { return 0; } return (int) $count; } ?>