/[drupal]/contributions/modules/indexpage/indexpage.module
ViewVC logotype

Contents of /contributions/modules/indexpage/indexpage.module

Parent Directory Parent Directory | Revision Log Revision Log | View Revision Graph Revision Graph


Revision 1.12 - (show annotations) (download) (as text)
Mon Sep 21 21:29:06 2009 UTC (2 months ago) by nancyw
Branch: MAIN
CVS Tags: HEAD
Changes since 1.11: +68 -41 lines
File MIME type: text/x-php
Much closer to fully working
1 <?php
2 // $Id: indexpage.module,v 1.11 2009/07/21 14:25:57 nancyw Exp $
3
4 /**
5 * @file
6 * This module displays customizable index pages for each node type, with
7 * alphabetical, taxonomy, and user filters.
8 *
9 * Licensed under the terms of the GNU General Public License:
10 * http://www.opensource.org/licenses/gpl-license.php
11 *
12 * @version 1.0
13 * @author Carlos A. Paramio (carlos.paramio@interactors.coop)
14 *
15 * @version 1.2
16 * Updated for 4.7 forms, node list, and plugged SQL injection holes
17 * @author Khalid Baheyeldin http://2bits.com
18 *
19 * @version 1.3
20 * Updated for 5.x, 6.x.
21 * @author Nancy Wichmann http://nanwich.info
22 *
23 * @version 1.4
24 * Updated for 5.x, 6.x - added user filters, faster page build.
25 * @author Nancy Wichmann http://nanwich.info
26 */
27
28 /**
29 * Implementation of hook_help().
30 */
31 function indexpage_help($path, $args) {
32 switch ($path) {
33 case 'admin/help#indexpage':
34 return t('Displays index pages for each node type, with alphabetical, taxonomy, and user filters.');
35 break;
36 }
37 }
38
39 /**
40 * Implementation of hook_theme().
41 */
42 function indexpage_theme($path, $args) {
43 return array(
44 'indexpage_term' => array(
45 'arguments' => array('term', 'type'),
46 ),
47 );
48 }
49
50 /**
51 * Implementation of hook_permission().
52 */
53 function indexpage_permission() {
54 return array(
55 'access indexpage' => array(
56 'title' => t('Access the IndexPage reports'),
57 'description' => t('Display a customizable index page for each node type.'),
58 ),
59 );
60 }
61
62 /**
63 * Implementation of hook_menu().
64 */
65 function indexpage_menu() {
66 global $user;
67 $items = array();
68 $items['indexpage'] = array(
69 'title' => 'Index page',
70 'page callback' => 'indexpage_page',
71 'page arguments' => array(1, 2, 3),
72 'access arguments' => array('access indexpage'),
73 'type' => MENU_NORMAL_ITEM,
74 );
75
76 $items['admin/settings/indexpage'] = array(
77 'title' => 'IndexPage',
78 'description' => 'IndexPage settings.',
79 'page callback' => 'drupal_get_form',
80 'page arguments' => array('indexpage_admin_settings'),
81 'access arguments' => array('administer site configuration'),
82 'type' => MENU_NORMAL_ITEM,
83 );
84
85
86 return $items;
87 }
88
89 function indexpage_page($type, $op = NULL, $uid = NULL) {
90 drupal_add_css(drupal_get_path('module', 'indexpage') . '/indexpage.css');
91
92 global $user;
93 $output = NULL;
94
95 // Is this the overview index?
96 if (!$type) {
97 $output .= '<div class="content">';
98 $output .= nl2br(variable_get('indexpage_description', ''));
99 $items = array();
100 $types = node_type_get_names();
101 foreach ($types as $type => $name) {
102 $count = db_query("SELECT COUNT(nid) FROM {node} WHERE type = :type", array(':type' => $type))->fetchfield();
103 if (variable_get('indexpage_' . $type . '_enable', 1)) {
104 $title = t('Index page for !s (!count)',
105 array(
106 '!s' => check_plain(variable_get('indexpage_' . $type . '_name', $type)),
107 '!count' => $count,
108 )
109 );
110 $items[] = l($title, drupal_get_path_alias('indexpage/' . $type));
111 }
112 }
113
114 $output .= theme('item_list', $items) . '</div>';
115
116 if (user_access('administer site configuration')) {
117 $links['indexpage-settings'] = array(
118 'title' => t('Indexpage settings'),
119 'href' => 'admin/settings/indexpage',
120 'attributes' => array('title' => t('Change the Indexpage settings'), 'rel' => 'nofollow'),
121 'query' => drupal_get_destination(),
122 );
123 }
124
125 $output .= theme('links', $links, array('class' => 'links inline'));
126 $output .= '</div>';
127
128 return $output;
129 }
130 else {
131 // Do the index for a specific type.
132 $sql = _indexpage_check_status("SELECT 1 FROM {node} n WHERE n.type = :type");
133 $exist_type = (bool) db_query_range($sql, 0, 1, array(':type' => $type))->fetchField();
134 if (!$exist_type) {
135 return t('ERROR: There are no items of the !type type.', array('!type' => $type));
136 }
137 if (variable_get('indexpage_' . $type . '_enable', 1)) {
138 if (empty($op) && $op !== '0') { // ???? empty AND == ?
139 $unpublished = @db_query("SELECT COUNT(n.nid) FROM {node} n WHERE n.type = :type AND n.status = 0", array(':type' => $type))->fetchfield();
140 return indexpage_page_index($type, $exist_type, $unpublished);
141 }
142 else {
143 return indexpage_page_list($type, $op, $uid);
144 }
145 }
146 else {
147 return t('ERROR: The index page for that type is disabled.');
148 }
149 }
150 }
151
152 function indexpage_page_index($type, $count = 0, $unpub_count = 0) {
153 $stuff = explode('-', $type);
154 $type = $stuff[0];
155
156 $name = check_plain(variable_get('indexpage_' . $type . '_name', $type));
157 $show_count = variable_get('indexpage_show_count', TRUE);
158 $show_users = variable_get('indexpage_show_users', FALSE);
159 $show_untagged = variable_get('indexpage_show_untagged', TRUE);
160 $suppress_unused = variable_get('indexpage_suppress_unused', FALSE);
161 $show_description = variable_get('indexpage_show_description', FALSE);
162 $list_format = variable_get('indexpage_list_format', 'list');
163 $links = array();
164
165 drupal_set_title(t('Index Page for !type', array('!type' => $name)));
166
167 $output = '<div class="indexpage_index indexpage_' . $type . '">';
168
169 // Get node info.
170 $node_opts = variable_get('node_options_' . $type, array());
171 if (($where = array_search(t('status'), $node_opts)) !== FALSE) {
172 $node_opts[$where] = t('published');
173 }
174
175 if ($description = variable_get('indexpage_' . $type . '_page_text', NULL)) {
176 $output .= '<div class="indexpage_description">' . $description . '</div>';
177 }
178
179 if ($show_count) {
180 $count_msg = format_plural($count, 'There is one !type node', 'There are @count !type nodes',
181 array('!type' => $name));
182 if ($unpub_count) {
183 $count_msg .= format_plural($unpub_count, ', of which one is unpublished.', ', of which @count are unpublished.');
184 }
185 else {
186 $count_msg .= '.';
187 }
188 $output .= '<p>' . $count_msg . ' ' . t('This content type uses these options: !opts.', array('!opts' => implode(', ', $node_opts))) . '</p>';
189 }
190
191 // Index by letter block.
192 if (variable_get('indexpage_' . $type . '_alphaindex', 1)) {
193 $output .= '<div class="indexpage-node-index">';
194 $output .= '<h3>' . t('Alphabetical index') . '</h3>';
195 $output .= '<p><em>' . t('Click a letter to see the titles of content beginning with that letter.') . '</em></p>';
196 $output .= '<p>';
197 // Note: this doesn't work well with non-English.
198 $range = drupal_map_assoc(range('A', 'Z'));
199 foreach ($range as $letter) {
200 $sql = _indexpage_check_status("SELECT 1 FROM {node} n WHERE n.type=:type AND LOWER(n.title) LIKE :letter");
201 $found_letter = (bool) db_query_range($sql, 0, 1, array(':type' => $type, ':letter' => drupal_strtolower($letter) . '%'))->fetchfield();
202 if ($found_letter) {
203 $range[$letter] = l($letter, drupal_get_path_alias("indexpage/$type/$letter"), array('attributes' => array('title' => "$name content beginning with '$letter'")));
204 }
205 }
206
207 $sql = _indexpage_check_status("SELECT COUNT(n.nid) FROM {node} n WHERE n.type=:type AND (n.title REGEXP '^[^[:alpha:]].*$')");
208 if (db_query($sql, array(':type' => $type))->fetchfield() > 0) {
209 $range['#'] = l('#', drupal_get_path_alias("indexpage/$type/_"), array('attributes' => array('title' => "$name content beginning with a non-alphabetic character")));
210 }
211
212 $range['all'] = l(t('all'), drupal_get_path_alias("indexpage/$type/all"), array('attributes' => array('title' => "All $name content")));
213
214 $output .= implode(' | ', $range) . '</p></div>';
215 }
216
217 // Index by users section.
218 if ($show_users) {
219 $rows = array();
220 $sql = _indexpage_check_status("SELECT n.uid, COUNT(n.uid) as count FROM {node} n WHERE n.type=:type GROUP BY n.uid");
221 $users = db_query($sql, array(':type' => $type));
222 while ($u = db_fetch_object($users)) {
223 $account = user_load_multiple(array($u->uid));
224 $rows[] = array(
225 theme('username', $account, array('picture' => TRUE, 'homepage' => FALSE)),
226 l($u->count, "indexpage/$type/user/$u->uid", array('attributes' => array('title' => t('Show the content this user contributed')))),
227 );
228 }
229 if ($rows) {
230 $header = array(t('User Name'), t('Count'));
231 $fieldset = array(
232 '#title' => t('Users who have created !name content', array('!name' => $name)),
233 '#description' => t('User names link to the user profile; the counts link to a list of titles by that user.'),
234 '#collapsible' => TRUE,
235 '#collapsed' => (count($rows) > variable_get('indexpage_maxresults', 10)),
236 '#value' => theme('table', $header, $rows),
237 );
238 $output .= '<div class="indexpage-users">' . theme('fieldset', $fieldset) . '</div>';
239 }
240 }
241
242
243 // Index by taxonomy terms section.
244 $voc_list = array();
245 if (variable_get('indexpage_' . $type . '_vocfilter', 1)) {
246 $vocs = db_query("SELECT v.name, v.vid FROM {taxonomy_vocabulary} v LEFT JOIN {taxonomy_vocabulary_node_type} t ON t.vid=v.vid WHERE t.type=:type", array(':type' => $type));
247 foreach ($vocs as $voc) {
248 $term_list = array();
249 $voc_list[$voc->vid] = check_plain($voc->name);
250 $output .= '<div class="indexpage-filter-' . $voc->vid . '">';
251 $voc_count = 0;
252
253 $terms = taxonomy_get_tree($voc->vid);
254 foreach ($terms as $term) {
255 $sql = _indexpage_check_status("SELECT COUNT(n.nid) FROM {node} n LEFT JOIN {taxonomy_term_node} t on t.nid=n.nid AND t.vid=n.vid WHERE type=:type AND t.tid=:tid");
256 $term->node_count = $how_many = db_query($sql, array(':type' => $type, ':tid' => $term->tid))->fetchfield();
257 $voc_count += $how_many;
258 if ($how_many || !$suppress_unused) {
259 $term_list[] = theme('indexpage_term', $term, $type);
260 }
261 }
262
263 if ($term_list) {
264 if ($list_format == 'list') {
265 $stuff = theme('item_list', $term_list, NULL, 'ul', array('class' => 'indexpage_term_list'));
266 }
267 else {
268 $header = array();
269 if ($show_description) {
270 $header = array(
271 t('Category'),
272 t('Description'),
273 );
274 }
275 $stuff = theme('table', $header, $term_list, array('class' => 'indexpage_term_list'));
276 }
277 }
278 else {
279 $stuff = '<p>' . t('None found') . '</p>';
280 }
281 $fieldset = array(
282 '#title' => t('List by !s Categories', array('!s' => $voc->name)) . ($show_count ? ' (' . $voc_count . ')' : NULL),
283 '#description' => t('Terms (categories) that have content will link to a list of titles tagged with that term.'),
284 '#collapsible' => TRUE,
285 '#collapsed' => (count($term_list) > variable_get('indexpage_maxresults', 10)),
286 '#value' => $stuff,
287 '#prefix' => '<div class="indexpage_category indexpage_category_' . $voc->vid . '">',
288 '#suffix' => '</div>',
289 );
290 $output .= theme('fieldset', $fieldset) . '</div>';
291 }
292
293 // Handle unclassified.
294 if ($show_untagged) {
295 $sql = _indexpage_check_status("SELECT COUNT(n.nid) FROM {node} n LEFT JOIN {taxonomy_term_node} t on n.nid=t.nid WHERE type=:type AND t.tid IS NULL");
296 $how_many = db_query($sql, array(':type' => $type))->fetchfield();
297 if ($how_many > 0) {
298 $title = format_plural($how_many, 'There is one unclassified !type node.', 'There are @count unclassified !type nodes.',
299 array('!type' => $name));
300 $output .= '<p>' . l($title, drupal_get_path_alias("indexpage/$type/0")) . '</p>';
301 }
302 $sql = _indexpage_check_status("SELECT n.nid, v.name FROM {node} n JOIN {taxonomy_term_node} tn ON tn.nid=n.nid JOIN {taxonomy_term_data} td ON td.tid=tn.tid JOIN {taxonomy_vocabulary} v ON v.vid=td.vid LEFT JOIN {taxonomy_vocabulary_node_type} nt ON nt.vid=v.vid AND nt.type=n.type WHERE n.type=:type AND nt.type IS NULL");
303 $misclassed = db_query($sql, array(':type' => $type));
304 $voc_names = array();
305 $how_many = 0;
306 foreach ($misclassed as $row) {
307 $voc_names[] = decode_entities(check_plain($row->name));
308 ++$how_many;
309 }
310 if ($voc_names) {
311 $voc_names = array_unique($voc_names);
312 $output .= '<p>' . t('There are !count !type nodes improperly classified in %vocs.', array('!count' => $how_many, '!type' => $type_name, '%vocs' => implode(', ', $voc_names))) . '</p>';
313 }
314 }
315 }
316
317 // Operations for this node type.
318 $output .= '<h3>' . t('Operations') . '</h3>';
319 $dest = drupal_get_destination();
320
321 if (user_access("create $type") || user_access("create $type content")) {
322 $links['indexpage-create'] = array(
323 'title' => t('Create a new entry'),
324 'href' => 'node/add/' . $type,
325 'attributes' => array('title' => t('Create a new !type node.', array('!type' => $type)), 'rel' => 'nofollow'),
326 'query' => $dest,
327 );
328 }
329
330 if (user_access('administer content types')) {
331 $links['indexpage-content-type'] = array(
332 'title' => t('Edit !type', array('!type' => $type)),
333 'href' => 'admin/content/types/' . $type,
334 'attributes' => array('title' => t('Edit the !type content type', array('!type' => $type)), 'rel' => 'nofollow'),
335 'query' => $dest,
336 );
337 }
338
339 if (user_access('administer taxonomy')) {
340 foreach ($voc_list as $vid => $name) {
341 $links['indexpage-vocabulary-' . $vid] = array(
342 'title' => t('Edit !type vocabulary', array('!type' => $name)),
343 'href' => 'admin/content/taxonomy/edit/vocabulary/' . $vid,
344 'attributes' => array('title' => t('Edit the !type vocabulary.', array('!type' => $name)), 'rel' => 'nofollow'),
345 'query' => $dest,
346 );
347 }
348 }
349
350 if (user_access('administer site configuration')) {
351 $links['indexpage-settings'] = array(
352 'title' => t('Indexpage settings'),
353 'href' => 'admin/settings/indexpage',
354 'attributes' => array('title' => t('Change the Indexpage settings'), 'rel' => 'nofollow'),
355 'query' => $dest,
356 );
357 }
358
359 $output .= theme('links', $links, array('class' => 'links inline'));
360
361 return $output . '</div>';
362 }
363
364 function theme_indexpage_term($term, $type) {
365 static $show_count, $show_description, $list_format;
366 if (!isset($show_count)) {
367 $show_count = variable_get('indexpage_show_count', TRUE);
368 $show_description = variable_get('indexpage_show_description', FALSE);
369 $list_format = variable_get('indexpage_list_format', 'list');
370 }
371 $item = str_repeat('&ndash; ', $term->depth);
372 if ($term->node_count) {
373 $item .= l($term->name, drupal_get_path_alias("indexpage/$type/$term->tid")) . ($show_count ? ' (' . $term->node_count . ')' : NULL);
374 }
375 else {
376 $item .= check_plain($term->name);
377 }
378 switch ($list_format) {
379 case 'list':
380 $item .= $show_description ? (' &mdash; ' . $term->description) : NULL;
381 break;
382
383 case 'table':
384 $item = array($item);
385 if ($show_description) {
386 $item[] = $term->description;
387 }
388 break;
389 }
390 return $item;
391 }
392
393 function _indexpage_check_status($query) {
394 // Must have 'admin nodes' permission to see unpublished.
395 if (!user_access('administer nodes')) {
396 $query .= ' AND n.status = 1';
397 }
398 // return db_rewrite_sql($query);
399 return $query;
400 }
401
402 function indexpage_page_list($type, $filter, $uid = NULL) {
403 static $acct = array();
404 $name = check_plain(variable_get('indexpage_' . $type . '_name', $type));
405
406 $breadcrumb = drupal_get_breadcrumb();
407 $breadcrumb[] = l(t('Index page for !s', array('!s' => $name)), drupal_get_path_alias('indexpage/' . $type));
408 drupal_set_breadcrumb($breadcrumb);
409
410 $output = '<div class="indexpage_results">';
411 $args = array(':type' => $type);
412 if (is_numeric($filter)) {
413 // Filter by vocabulary term.
414 $sql = "SELECT n.*, r.teaser FROM {node} n LEFT JOIN {taxonomy_term_node} t ON t.nid=n.nid AND t.vid=n.vid INNER JOIN {node_revision} r ON r.nid=n.nid AND r.vid=n.vid WHERE type=':type' AND t.tid :filter ";
415 $args[':filter'] = $filter == 0 ? 'IS NULL' : '=' . $filter;
416
417 if ($filter) {
418 $term = taxonomy_term_load($filter);
419 $term_name = check_plain($term->name);
420 }
421 else {
422 $term_name = t('no terms');
423 }
424 drupal_set_title(t('!type nodes classified with !term', array('!type' => $name, '!term' => $term_name)));
425 }
426 else {
427 switch ($filter) {
428 case 'all':
429 // All nodes of this type wanted.
430 $sql = "SELECT n.*, r.teaser FROM {node} n INNER JOIN {node_revision} r ON r.nid=n.nid AND r.vid=n.vid WHERE n.type=':type'";
431 drupal_set_title(t('All !type nodes', array('!type' => $name)));
432 break;
433
434 case '_':
435 // Filter by non_alpha.
436 $sql = "SELECT n.*, r.teaser FROM {node} n INNER JOIN {node_revision} r ON r.nid=n.nid AND r.vid=n.vid WHERE n.type=':type' AND (n.title REGEXP '^[^[:alpha:]].*$')";
437 drupal_set_title(t('!type nodes beginning with non-alphabetical', array('!type' => $name)));
438 break;
439
440 case 'user':
441 // Filter by user.
442 $sql = "SELECT n.*, r.teaser FROM {node} n INNER JOIN {node_revision} r ON r.nid=n.nid AND r.vid=n.vid WHERE n.type=':type' AND n.uid = :uid";
443 $args[':uid'] = $uid;
444 $account = user_load($uid);
445 drupal_set_title(t('!type nodes created by !user', array('!type' => $name, '!user' => theme('username', $account, array('plain' => TRUE)))));
446 break;
447
448 default:
449 // Filter by letter.
450 $sql = "SELECT n.*, r.teaser FROM {node} n INNER JOIN {node_revision} r ON r.nid=n.nid AND r.vid=n.vid WHERE n.type=':type' AND LOWER(n.title) LIKE ':letter%'";
451 $args[':letter'] = drupal_strtolower($filter);
452 drupal_set_title(t('!type nodes beginning with "!term"', array('!type' => $name, '!term' => $filter)));
453 break;
454 }
455 }
456
457 $sql = _indexpage_check_status($sql);
458
459 $show_fields = array_merge(array('title' => 1), variable_get('indexpage_fields', array()));
460 $show_fields = array_filter($show_fields);
461 $weight_avail = module_exists('weight');
462
463 $fields = array(
464 'title' => array('data' => t('Title'), 'field' => 'title', 'sort' => 'asc', 'class' => 'left'),
465 'type' => array('data' => t('Type'), 'field' => 'type', 'class' => 'center'),
466 'language' => array('data' => t('Language'), 'field' => 'language', 'class' => 'center'),
467 'uid' => array('data' => t('Author'), 'field' => 'uid', 'class' => 'left'),
468 'authors' => array('data' => t('Authors / Editors'), 'field' => 'uid', 'class' => 'left'),
469 'terms' => array('data' => t('Terms'), /*'field' => 'taxonomy',*/ 'class' => 'left'),
470 'created' => array('data' => t('Created'), 'field' => 'created', 'class' => 'center'),
471 'changed' => array('data' => t('Updated'), 'field' => 'changed', 'class' => 'center'),
472 'status' => array('data' => t('Published'), 'field' => 'status', 'class' => 'center'),
473 'promote' => array('data' => t('Promoted'), 'field' => 'promote', 'class' => 'center'),
474 'sticky' => array('data' => t('Sticky'), 'field' => 'sticky', 'class' => 'center'),
475 );
476 if ($weight_avail) {
477 $fields['weight'] = array('data' => t('Weight'), /*'field' => 'node_weight',*/ 'class' => 'center');
478 }
479
480 $max_results = variable_get('indexpage_maxresults', 10);
481 $tooltip = variable_get('indexpage_teaser_tooltip', TRUE);
482
483 $header = array();
484 foreach ($show_fields as $key => $value) {
485 $header[] = $fields[$key];
486 }
487 $rows = array();
488
489 // $sql .= tablesort_sql($header);
490 // Have to do this crap until they update pager_query.
491 $search = array_keys($args);
492 $replace = array_values($args);
493 $sql = str_replace($search, $replace, $sql);
494 $result = pager_query($sql, $max_results, 0, NULL, $args);
495
496 while ($node = db_fetch_object($result)) {
497 $line = array();
498 if ($weight_avail) {
499 _weight_decode($node);
500 }
501
502 foreach ($show_fields as $key => $value) {
503 switch ($key) {
504 case 'terms':
505 // $field_value = $node->taxonomy;
506 break;
507 case 'weight':
508 $field_value = $node->node_weight;
509 break;
510 default:
511 $field_value = $node->{$fields[$key]['field']};
512 }
513 $field_align = $fields[$key]['class'];
514 switch ($key) {
515 case 'title':
516 if ($tooltip) {
517 $title = strip_tags($node->teaser);
518 }
519 else {
520 $title = check_plain($field_value);
521 }
522 $field_value = l($node->title, drupal_get_path_alias('node/' . $node->nid), array('attributes' => array('title' => $title)));
523 break;
524
525 case 'changed':
526 case 'created':
527 $field_value = format_date($field_value, 'custom', variable_get('date_format_short', 'm/d/Y - H:i'));
528 break;
529
530 case 'promote':
531 case 'status':
532 case 'sticky':
533 $field_value = $field_value > 0 ? t('Yes') : t('No');
534 break;
535
536 case 'uid':
537 $account = user_load($node->uid);
538 $field_value = theme('username', $account);
539 break;
540
541 case 'terms':
542 $items = array();
543 $terms = db_query("SELECT td.name FROM {taxonomy_term_node} tn JOIN {taxonomy_term_data} td ON td.tid=tn.tid WHERE tn.nid=:nid ORDER BY td.name", array(':nid' => $node->nid));
544 while ($name = db_result($terms)) {
545 $items[] = check_plain($name);
546 }
547 if ($items) {
548 $items = array_unique($items);
549 }
550 else {
551 $items[] = t('- none -');
552 }
553 if (count($items) > 1) {
554 $field_value = decode_entities(theme('item_list', $items));
555 }
556 else {
557 $field_value = $items[0];
558 }
559 break;
560
561 case 'authors':
562 $items = array();
563 $uids = array($node->uid);
564 $revs = db_query("SELECT DISTINCT(r.uid) FROM {node_revision} r WHERE r.nid=:nid ORDER by r.vid DESC", array(':nid' => $node->nid));
565 while ($rev_uid = db_result($revs)) {
566 $uids[] = $rev_uid;
567 }
568 $uids = array_unique($uids);
569 foreach ($uids as $uid) {
570 if (!isset($acct[$uid])) {
571 $acct[$uid] = user_load($uid);
572 }
573 $items[] = theme('username', $acct[$uid]);
574 }
575 $field_value = theme('item_list', $items);
576 break;
577 }
578 $line[] = array('data' => $field_value, 'align' => $field_align);
579 }
580 $rows[] = $line;
581 }
582
583 if (!$rows) {
584 $rows[] = array(array('data' => t('There are no results.'), 'colspan' => 20));
585 }
586
587 $output .= theme('table', $header, $rows) . theme('pager');
588 return $output . '</div>';
589 }

  ViewVC Help
Powered by ViewVC 1.1.2