public function table_html($listname, $options = array()) { global $Conf; if (!$this->_prepare()) { return null; } if (isset($options["fold"])) { foreach ($options["fold"] as $n => $v) { $this->viewmap->{$n} = $v; } } if (isset($options["table_id"])) { $this->viewmap->table_id = $options["table_id"]; } // need tags for row coloring if ($this->contact->can_view_tags(null)) { $this->qopts["tags"] = 1; } $this->table_type = $listname; // get column list, check sort $field_list = $this->_list_columns($listname); if (!$field_list) { Conf::msg_error("There is no paper list query named “" . htmlspecialchars($listname) . "”."); return null; } $field_list = $this->_columns($field_list, true); $body_attr = $this->row_attr; $rows = $this->_rows($field_list); if ($rows === null) { return null; } // return IDs if requested if (empty($rows)) { if ($altq = $this->search->alternate_query()) { $altqh = htmlspecialchars($altq); $url = $this->search->url_site_relative_raw($altq); if (substr($url, 0, 5) == "search") { $altqh = "<a href=\"" . htmlspecialchars(Navigation::siteurl() . $url) . "\">" . $altqh . "</a>"; } return "No matching papers. Did you mean “{$altqh}”?"; } else { return "No matching papers"; } } // get field array $fieldDef = array(); $ncol = $titlecol = 0; // folds: au:1, anonau:2, fullrow:3, aufull:4, force:5, rownum:6, [fields] $next_fold = 7; foreach ($field_list as $fdef) { if ($fdef->view != Column::VIEW_NONE) { $fieldDef[] = $fdef; } if ($fdef->view != Column::VIEW_NONE && $fdef->foldable) { $fdef->foldable = $next_fold; ++$next_fold; } if ($fdef->name == "title") { $titlecol = $ncol; } if ($fdef->view == Column::VIEW_COLUMN && !$fdef->is_folded) { ++$ncol; } } // count non-callout columns $skipcallout = 0; foreach ($fieldDef as $fdef) { if ($fdef->name != "id" && !isset($fdef->is_selector)) { break; } else { ++$skipcallout; } } // create render state $rstate = new PaperListRenderState($ncol, $titlecol, $skipcallout); // collect row data $body = array(); $lastheading = !empty($this->search->groupmap) ? -1 : -2; $need_render = false; foreach ($rows as $row) { ++$this->count; if ($lastheading > -2) { $lastheading = $this->_check_heading($this->_row_thenval($row), $rstate, $rows, $lastheading, $body); } $body[] = $this->_row_text($rstate, $row, $fieldDef); if ($this->need_render && !$need_render) { $Conf->footerScript('$(plinfo.render_needed)', 'plist_render_needed'); $need_render = true; } if ($this->need_render && $this->count % 16 == 15) { $body[count($body) - 1] .= " <script>plinfo.render_needed()</script>\n"; $this->need_render = false; } } if ($lastheading > -2 && $this->search->is_order_anno) { while ($lastheading + 1 < count($this->search->groupmap)) { $lastheading = $this->_check_heading($lastheading + 1, $rstate, $rows, $lastheading, $body); } } // header cells $colhead = ""; $url = $this->search->url_site_relative_raw(); if (!defval($options, "noheader")) { $colhead .= " <thead class=\"pltable\">\n <tr class=\"pl_headrow\">"; $ord = 0; $titleextra = $this->_make_title_header_extra($rstate, $fieldDef, get($options, "header_links")); foreach ($fieldDef as $fdef) { if ($fdef->view != Column::VIEW_COLUMN || $fdef->is_folded) { continue; } $colhead .= "<th class=\"pl " . $fdef->className; if ($fdef->foldable) { $colhead .= " fx" . $fdef->foldable; } $colhead .= "\">"; if ($fdef->has_content) { $colhead .= $this->_field_title($fdef, $ord); } if ($titleextra && $fdef->className == "pl_title") { $colhead .= $titleextra; $titleextra = false; } $colhead .= "</th>"; ++$ord; } $colhead .= "</tr>\n"; if ($this->search->is_order_anno) { $colhead .= " <tr class=\"pl_headrow pl_annorow\" data-anno-tag=\"{$this->search->is_order_anno}\">"; if ($rstate->titlecol) { $colhead .= "<td colspan=\"{$rstate->titlecol}\"></td>"; } $colhead .= "<td colspan=\"" . ($rstate->ncol - $rstate->titlecol) . "\"><a href=\"#\" onclick=\"return plinfo_tags.edit_anno(this)\">Annotate order</a></td></tr>\n"; } $colhead .= " </thead>\n"; } // table skeleton including fold classes $foldclasses = array(); if ($this->foldable) { $foldclasses = $this->_analyze_folds($rstate, $fieldDef); } $enter = ""; if (self::$include_stash) { $enter .= Ht::take_stash(); } $enter .= "<table class=\"pltable plt_" . htmlspecialchars($listname); if (defval($options, "class")) { $enter .= " " . $options["class"]; } if ($this->listNumber) { $enter .= " has_hotcrp_list"; } if (!empty($foldclasses)) { $enter .= " " . join(" ", $foldclasses); } if ($this->viewmap->table_id) { $enter .= "\" id=\"" . $this->viewmap->table_id; } if (defval($options, "attributes")) { foreach ($options["attributes"] as $n => $v) { $enter .= "\" {$n}=\"" . htmlspecialchars($v); } } if ($this->search->is_order_anno) { $enter .= "\" data-order-tag=\"{$this->search->is_order_anno}"; } foreach ($body_attr as $k => $v) { $enter .= "\" {$k}=\"" . htmlspecialchars($v); } if ($this->listNumber) { $enter .= '" data-hotcrp-list="' . $this->listNumber; } $enter .= "\" data-fold=\"true\">\n"; $exit = "</table>"; // maybe make columns, maybe not $tbody_class = "pltable"; if ($this->viewmap->columns && !empty($rstate->ids) && $this->_column_split($rstate, $colhead, $body)) { $enter = '<div class="plsplit_col_ctr_ctr"><div class="plsplit_col_ctr">' . $enter; $exit = $exit . "</div></div>"; $ncol = $rstate->split_ncol; $tbody_class = "pltable_split"; } else { $enter .= $colhead; $tbody_class .= $rstate->hascolors ? " pltable_colored" : ""; } // footer $foot = ""; if ($this->viewmap->statistics && !$this->viewmap->columns) { $foot .= $this->_statistics_rows($rstate, $fieldDef); } if ($fieldDef[0] instanceof SelectorPaperColumn && !defval($options, "nofooter")) { $foot .= $this->_footer($ncol, get_s($options, "footer_extra")); } if ($foot) { $enter .= ' <tfoot' . ($rstate->hascolors ? ' class="pltable_colored"' : "") . ">\n" . $foot . " </tfoot>\n"; } // body $enter .= " <tbody class=\"{$tbody_class}\">\n"; // header scripts to set up delegations if ($this->_header_script) { $enter .= ' <script>' . $this->_header_script . "</script>\n"; } // session variable to remember the list if ($this->listNumber) { $sl = $this->search->create_session_list_object($rstate->ids, self::_listDescription($listname), $this->sortdef()); if (isset($this->qreq->sort)) { $url .= (strpos($url, "?") ? "&" : "?") . "sort=" . urlencode($this->qreq->sort); } $sl->url = $url; if (get($options, "list_properties")) { foreach ($options["list_properties"] as $k => $v) { $sl->{$k} = $v; } } SessionList::change($this->listNumber, $sl); } foreach ($fieldDef as $fdef) { if ($fdef->has_content) { $this->any[$fdef->name] = true; } } if ($rstate->has_openau) { $this->any->openau = true; } if ($rstate->has_anonau) { $this->any->anonau = true; } $this->ids = $rstate->ids; return $enter . join("", $body) . " </tbody>\n" . $exit; }
function table_html($listname, $url, $listtitle = "", $foldsession = null) { global $Conf, $contactListFields; // PC tags $listquery = $listname; $queryOptions = array(); if (str_starts_with($listname, "#")) { $queryOptions["where"] = "(u.contactTags like " . Dbl::utf8ci("'% " . sqlq_for_like(substr($listname, 1)) . "#%'") . ")"; $listquery = "pc"; } // get paper list if (!($baseFieldId = $this->listFields($listquery))) { Conf::msg_error("There is no people list query named “" . htmlspecialchars($listquery) . "”."); return null; } $this->limit = array_shift($baseFieldId); // get field array $fieldDef = array(); $acceptable_fields = array(); $this->any = (object) array("sel" => false); $ncol = 0; foreach ($baseFieldId as $fid) { if ($this->selector($fid, $queryOptions) === false) { continue; } if (!($fieldDef[$fid] = @$contactListFields[$fid])) { $fieldDef[$fid] = $contactListFields[self::FIELD_SCORE]; } $acceptable_fields[$fid] = true; if ($fieldDef[$fid][1] == 1) { $ncol++; } } // run query $rows = $this->_rows($queryOptions); if (!$rows || count($rows) == 0) { return "No matching people"; } // list number if ($this->listNumber === true) { $this->listNumber = SessionList::allocate("u/" . $this->limit); $this->contactLinkArgs .= "&ls=" . $this->listNumber; } // sort rows if (!@$acceptable_fields[$this->sortField]) { $this->sortField = null; } $srows = $this->_sort($rows); // count non-callout columns $firstcallout = $lastcallout = null; $n = 0; foreach ($fieldDef as $fieldId => $fdef) { if ($fdef[1] == 1) { if ($firstcallout === null && $fieldId < self::FIELD_SELECTOR) { $firstcallout = $n; } if ($fieldId < self::FIELD_SCORE) { $lastcallout = $n + 1; } ++$n; } } $firstcallout = $firstcallout ? $firstcallout : 0; $lastcallout = ($lastcallout ? $lastcallout : $ncol) - $firstcallout; // collect row data $this->count = 0; $show_colors = $this->contact->isPC; $anyData = array(); $body = ''; $extrainfo = $hascolors = false; $ids = array(); foreach ($srows as $row) { if (($this->limit == "resub" || $this->limit == "extsub") && $row->numReviewsSubmitted == 0) { continue; } $trclass = "k" . $this->count % 2; if ($show_colors && ($m = $row->viewable_color_classes($this->contact))) { if (TagInfo::classes_have_colors($m)) { $trclass = $m; $hascolors = true; } else { $trclass .= " {$m}"; } } if ($row->disabled && $this->contact->isPC) { $trclass .= " graytext"; } $this->count++; $ids[] = (int) $row->contactId; // First create the expanded callout row $tt = ""; foreach ($fieldDef as $fieldId => $fdef) { if ($fdef[1] >= 2 && ($d = $this->content($fieldId, $row)) !== "") { $tt .= "<div"; //$t .= " <tr class=\"pl_$fdef[0] pl_callout $trclass"; if ($fdef[1] >= 3) { $tt .= " class=\"fx" . ($fdef[1] - 2) . "\""; } $tt .= '><em class="plx">' . $this->header($fieldId, -1, $row) . ":</em> " . $d . "</div>"; } } if ($tt !== "") { $x = " <tr class=\"plx {$trclass}\">"; if ($firstcallout > 0) { $x .= "<td colspan=\"{$firstcallout}\"></td>"; } $tt = $x . "<td class=\"plx\" colspan=\"" . ($lastcallout - $firstcallout) . "\">" . $tt . "</td></tr>\n"; } // Now the normal row $t = " <tr class=\"pl {$trclass}\">\n"; $n = 0; foreach ($fieldDef as $fieldId => $fdef) { if ($fdef[1] == 1) { $c = $this->content($fieldId, $row); $t .= " <td class=\"pl pl_{$fdef['0']}\""; if ($n >= $lastcallout && $tt != "") { $t .= " rowspan=\"2\""; } $t .= ">" . $c . "</td>\n"; if ($c != "") { $anyData[$fieldId] = 1; } ++$n; } } $t .= " </tr>\n"; $body .= $t . $tt; } $foldclasses = array(); foreach (self::$folds as $k => $fold) { if (@$this->have_folds[$fold] !== null) { $this->have_folds[$fold] = strpos(displayOptionsSet("uldisplay"), " {$fold} ") !== false; $foldclasses[] = "fold" . ($k + 1) . ($this->have_folds[$fold] ? "o" : "c"); } } $x = "<table id=\"foldul\" class=\"pltable pltable_full plt_" . htmlspecialchars($listquery); if ($foldclasses) { $x .= " " . join(" ", $foldclasses); } if ($foldclasses && $foldsession) { $x .= "\" data-fold-session=\"{$foldsession}"; } $x .= "\">\n"; if ($this->showHeader) { $x .= " <thead class=\"pltable\">\n <tr class=\"pl_headrow\">\n"; $ord = 0; if ($this->sortable && $url) { $sortUrl = htmlspecialchars($url) . (strpos($url, "?") ? "&" : "?") . "sort="; $q = '<a class="pl_sort" rel="nofollow" href="' . $sortUrl; foreach ($fieldDef as $fieldId => $fdef) { if ($fdef[1] != 1) { continue; } else { if (!isset($anyData[$fieldId])) { $x .= " <th class=\"pl pl_{$fdef['0']}\"></th>\n"; continue; } } $x .= " <th class=\"pl pl_{$fdef['0']}\">"; $ftext = $this->header($fieldId, $ord++); if ($this->sortField == null && $fieldId == 1) { $this->sortField = $fieldId; } if ($fieldId == $this->sortField) { $x .= '<a class="pl_sort_def' . ($this->reverseSort ? "_rev" : "") . '" rel="nofollow" href="' . $sortUrl . $fieldId . ($this->reverseSort ? "N" : "R") . '">' . $ftext . "</a>"; } else { if ($fdef[2]) { $x .= $q . $fieldId . "\">" . $ftext . "</a>"; } else { $x .= $ftext; } } $x .= "</th>\n"; } } else { foreach ($fieldDef as $fieldId => $fdef) { if ($fdef[1] == 1 && isset($anyData[$fieldId])) { $x .= " <th class=\"pl pl_{$fdef['0']}\">" . $this->header($fieldId, $ord++) . "</th>\n"; } else { if ($fdef[1] == 1) { $x .= " <th class=\"pl pl_{$fdef['0']}\"></th>\n"; } } } } $x .= " </tr></thead>\n"; } reset($fieldDef); if (key($fieldDef) == self::FIELD_SELECTOR) { $x .= $this->footer($ncol, $hascolors); } $x .= "<tbody class=\"pltable" . ($hascolors ? " pltable_colored" : "") . "\">" . $body . "</tbody></table>"; if ($this->listNumber) { $l = SessionList::create("u/" . $listname, $ids, $listtitle ? $listtitle : "Users", hoturl_site_relative_raw("users", ["t" => $listname])); SessionList::change($this->listNumber, $l); } return $x; }