CWIS Developer Documentation
ItemListUI.php
Go to the documentation of this file.
1 <?PHP
2 #
3 # FILE: ItemListUI.php
4 #
5 # Part of the Collection Workflow Integration System (CWIS)
6 # Copyright 2016 Edward Almasy and Internet Scout Research Group
7 # http://scout.wisc.edu/cwis/
8 #
9 
14 {
15 
16  # ---- PUBLIC INTERFACE --------------------------------------------------
17 
42  public function __construct($Fields, $SchemaId = TransportControlsUI::NO_ITEM_TYPE)
43  {
44  # normalize and save field info
45  if ($SchemaId == TransportControlsUI::NO_ITEM_TYPE)
46  {
47  $this->Fields = $Fields;
48  }
49  else
50  {
51  $this->Fields = array();
52  foreach ($Fields as $FieldId => $FieldInfo)
53  {
54  $CanonicalId = MetadataSchema::GetCanonicalFieldIdentifier($FieldId);
55  $this->Fields[$CanonicalId] = $FieldInfo;
56  }
57  }
58 
59  # set default base link
60  $this->BaseLink = "index.php?P=".$GLOBALS["AF"]->GetPageName();
61 
62  # save schema ID for later use
63  $this->SchemaId = $SchemaId;
64 
65  # set up transport controls
66  foreach ($this->Fields as $FieldId => $FieldInfo)
67  {
68  if (isset($FieldInfo["DefaultSortField"]))
69  {
71  }
72  }
73  $this->TransportUI = new TransportControlsUI($this->SchemaId);
74  $this->TransportUI->ItemsPerPage($this->ItemsPerPage);
75  }
76 
84  public function BaseLink($NewValue = NULL)
85  {
86  if ($NewValue !== NULL)
87  {
88  $this->BaseLink = $NewValue;
89  }
90  return $this->BaseLink;
91  }
92 
99  public function VariablesToPreserve($NewValue = NULL)
100  {
101  if ($NewValue !== NULL)
102  {
103  $this->VariablesToPreserve = $NewValue;
104  }
105  return $this->VariablesToPreserve;
106  }
107 
112  public function GetFullBaseLink()
113  {
114  $Link = $this->BaseLink;
115  foreach ($this->VariablesToPreserve as $VarName)
116  {
117  if (isset($_GET[$VarName]))
118  {
119  $Link .= "&amp;".$VarName."=".urlencode($_GET[$VarName]);
120  }
121  }
122  return $Link;
123  }
124 
130  public function Heading($NewValue = NULL)
131  {
132  if ($NewValue !== NULL)
133  {
134  $this->Heading = $NewValue;
135  }
136  return $this->Heading;
137  }
138 
144  public function ItemsPerPage($NewValue = NULL)
145  {
146  if ($NewValue !== NULL)
147  {
148  $this->ItemsPerPage = $NewValue;
149  $this->TransportUI->ItemsPerPage($this->ItemsPerPage);
150  }
151  return $this->ItemsPerPage;
152  }
153 
161  public function AddTopButton($Label, $Link, $Icon = NULL)
162  {
163  $this->Buttons[] = array(
164  "Label" => $Label,
165  "Link" => $Link,
166  "Icon" => $Icon);
167  }
168 
180  public function AddTopCheckbox($Label, $Checked, $VarName, $Link)
181  {
182  if (strpos($Link, $VarName."=") !== FALSE)
183  {
184  $Link = preg_replace("/(&|&amp;)".preg_quote($VarName)."=[^&]*/",
185  "", $Link);
186  }
187  $this->Buttons[] = array(
188  "Label" => $Label,
189  "Checked" => $Checked,
190  "VarName" => $VarName,
191  "Link" => $Link);
192  }
193 
211  public function AddActionButton(
212  $Label, $Link, $Icon = NULL, $DisplayTestFunc = NULL,
213  $AdditionalAttributes = array())
214  {
215  $this->Actions[] = array(
216  "Label" => $Label,
217  "Link" => $Link,
218  "Icon" => $Icon,
219  "TestFunc" => $DisplayTestFunc,
220  "AddAttribs" => $AdditionalAttributes);
221  }
222 
228  public function NoItemsMessage($NewValue = NULL)
229  {
230  if ($NewValue !== NULL)
231  {
232  $this->NoItemsMsg = $NewValue;
233  }
234  return $this->NoItemsMsg;
235  }
236 
241  public function &TransportUI()
242  {
243  return $this->TransportUI;
244  }
245 
260  public function Display($Items, $TotalItemCount = NULL,
261  $StartingIndex = NULL, $TransportMsg = NULL)
262  {
263  # retrieve context values from transport controls
264  $StartingIndex = $this->TransportUI->StartingIndex($StartingIndex);
265  $SortFieldId = $this->TransportUI->SortField();
266  $ReverseSort = $this->TransportUI->ReverseSortFlag();
267 
268  # display buttons above list
269  $this->DisplayTopButtons();
270 
271  # display heading
272  if (isset($this->Heading) && ($this->Heading !== NULL))
273  {
274  if ($this->Heading == strip_tags($this->Heading))
275  {
276  print "<h1>".$this->Heading."</h1>\n";
277  }
278  else
279  {
280  print $this->Heading."\n";
281  }
282  }
283 
284  # display "no items" message and exit if no items
285  if (count($Items) == 0)
286  {
287  $this->DisplayNoItemsMessage();
288  return;
289  }
290 
291  # begin item table
292  print '<table class="cw-table cw-table-sideheaders cw-table-fullsize
293  cw-table-padded cw-table-striped">';
294 
295  # begin header row
296  print "<thead><tr>";
297 
298  # for each field
299  foreach ($this->Fields as $FieldId => $FieldInfo)
300  {
301  # if header value supplied
302  if (isset($FieldInfo["Heading"]))
303  {
304  # use supplied value
305  $Heading = $FieldInfo["Heading"];
306  }
307  # else if we can get header from schema
308  elseif ($this->SchemaId !== TransportControlsUI::NO_ITEM_TYPE)
309  {
310  # use name of field (with any leading schema name stripped)
311  $Heading = MetadataSchema::GetPrintableFieldName($FieldId);
312  $Heading = preg_replace("/.+\: /", "", $Heading);
313  }
314  # else if field ID appears like it may be a name
315  elseif (is_string($FieldId) && !is_numeric($FieldId))
316  {
317  $Heading = $FieldId;
318  }
319  else
320  {
321  $Heading = "(NO HEADER SET)";
322  }
323 
324  # if sorting is disabled for field
325  if (isset($FieldInfo["NoSorting"]))
326  {
327  # print header
328  print "<th>".$Heading."</th>\n";
329  }
330  else
331  {
332  # build sort link
333  $SortLink = $this->GetFullBaseLink()."&amp;SF=".$FieldId
334  .$this->TransportUI->UrlParameterString(TRUE, array("SF", "RS"));
335 
336  # determine current sort direction
337  if (isset($FieldInfo["DefaultToDescendingSort"]))
338  {
339  $SortAscending = $ReverseSort ? TRUE : FALSE;
340  }
341  else
342  {
343  $SortAscending = $ReverseSort ? FALSE : TRUE;
344  }
345 
346  # set sort direction indicator (if any)
347  if ($FieldId == $SortFieldId)
348  {
349  $DirIndicator = ($SortAscending) ? "&uarr;" : "&darr;";
350  if (!$ReverseSort)
351  {
352  $SortLink .= "&amp;RS=1";
353  }
354  }
355  else
356  {
357  $DirIndicator = "";
358  }
359 
360  # print header
361  print "<th><a href=\"".$SortLink."\">".$Heading."</a>"
362  .$DirIndicator."</th>\n";
363  }
364  }
365 
366  # add action header if needed
367  if (is_array($this->Actions) && count($this->Actions))
368  {
369  print "<th>Actions</th>\n";
370  }
371 
372  # end header row
373  print "</tr></thead>\n";
374 
375  # for each item
376  print "<tbody>\n";
377  foreach ($Items as $ItemId => $Item)
378  {
379  # start row
380  print "<tr>\n";
381 
382  # for each field
383  foreach ($this->Fields as $FieldId => $FieldInfo)
384  {
385  # if there is value function defined for field
386  if (isset($FieldInfo["ValueFunction"]))
387  {
388  # call function for value
389  $Value = $FieldInfo["ValueFunction"]($Item, $FieldId);
390  }
391  else
392  {
393  # if item is associative array
394  if (is_array($Item))
395  {
396  # retrieve value for field (if any) from item
397  $Value = isset($Item[$FieldId])
398  ? $Item[$FieldId] : "";
399  }
400  # else if field ID is item method
401  elseif (method_exists($Item, $FieldId))
402  {
403  # get field value via item method
404  $Value = $Item->$FieldId();
405  }
406  else
407  {
408  # get field value from item via Get()
409  $Values = $Item->Get($FieldId);
410  $Value = is_array($Values) ? array_shift($Values) : $Values;
411  }
412 
413  # if max length specified for field
414  if (isset($FieldInfo["MaxLength"]))
415  {
417  $Value, $FieldInfo["MaxLength"]);
418  }
419 
420  # encode any HTML-significant chars in value
421  if (!isset($FieldInfo["AllowHTML"]))
422  {
423  $Value = htmlspecialchars($Value);
424  }
425  }
426 
427  # get link value (if any)
428  if (isset($FieldInfo["Link"]))
429  {
430  if (method_exists($Item, "Id"))
431  {
432  $Link = preg_replace('/\$ID/', $Item->Id(),
433  $FieldInfo["Link"]);
434  }
435  else
436  {
437  $Link = preg_replace('/\$ID/', $ItemId,
438  $FieldInfo["Link"]);
439  }
440  $LinkStart = '<a href="'.$Link.'">';
441  $LinkEnd = "</a>";
442  }
443  elseif (isset($FieldInfo["LinkFunction"]))
444  {
445  $Link = $FieldInfo["LinkFunction"]($Item);
446  if (!strlen($Link))
447  {
448  $LinkStart = "";
449  $LinkEnd = "";
450  }
451  else
452  {
453  if (method_exists($Item, "Id"))
454  {
455  $Link = preg_replace('/\$ID/', $Item->Id(),
456  $Link);
457  }
458  else
459  {
460  $Link = preg_replace('/\$ID/', $ItemId,
461  $Link);
462  }
463  $LinkStart = '<a href="'.$Link.'">';
464  $LinkEnd = "</a>";
465  }
466  }
467  else
468  {
469  $LinkStart = "";
470  $LinkEnd = "";
471  }
472 
473  # display cell with value
474  print "<td>".$LinkStart.$Value.$LinkEnd."</td>\n";
475  }
476 
477  # add action buttons
478  if (is_array($this->Actions) && count($this->Actions))
479  {
480  print "<td>";
481  $this->DisplayActionButtons($ItemId, $Item);
482  print "</td>\n";
483  }
484 
485  # end row
486  print "</tr>\n";
487  }
488  print "</tbody>\n";
489 
490  # end item table
491  print "</table>\n";
492 
493  # if there are more items than are displayed
494  if ($TotalItemCount > count($Items))
495  {
496  # craft transport control message (if not supplied)
497  if ($TransportMsg === NULL)
498  {
499  $ItemsLabel = ($this->SchemaId !== TransportControlsUI::NO_ITEM_TYPE)
501  $Item->Schema()->ResourceName())
502  : "Items";
503  $TransportMsg = $ItemsLabel
504  ." <b>".($this->TransportUI->StartingIndex() + 1)
505  ."</b> - <b>"
506  .min(($this->TransportUI->StartingIndex() + $this->ItemsPerPage),
507  $TotalItemCount)
508  ."</b> of <b>".$TotalItemCount."</b>";
509  }
510 
511  # display transport controls
512  $this->TransportUI->StartingIndex($StartingIndex);
513  $this->TransportUI->ItemCount($TotalItemCount);
514  $this->TransportUI->PrintControls(
515  $this->SchemaId, $this->GetFullBaseLink(), $TransportMsg);
516  }
517  }
518 
519 
520  # ---- PRIVATE INTERFACE -------------------------------------------------
521 
522  private $Actions;
523  private $BaseLink;
524  private $Buttons;
525  private $Fields;
526  private $Heading;
527  private $ItemsPerPage = 25;
528  private $NoItemsMsg;
529  private $SchemaId;
530  private $TransportUI;
531  private $VariablesToPreserve = array();
532 
536  private function DisplayTopButtons()
537  {
538  if (is_array($this->Buttons) && count($this->Buttons))
539  {
540  print '<span style="float: right; padding-top: 1.5em;">';
541  foreach ($this->Buttons as $Info)
542  {
543  if (isset($Info["Icon"]) && strlen($Info["Icon"]))
544  {
545  $IconFile = $GLOBALS["AF"]->GUIFile($Info["Icon"]);
546  $IconTag = $IconFile
547  ? '<img class="cw-button-icon" src="'
548  .$IconFile.'" alt=""> '
549  : "";
550  $IconButtonClass = " cw-button-iconed";
551  }
552  else
553  {
554  $IconTag = "";
555  $IconButtonClass = "";
556  }
557  if (isset($Info["Checked"]))
558  {
559  $CheckboxState = $Info["Checked"] ? "checked" : "";
560  $OnChangeLinkBase = $Info["Link"]."&amp;".$Info["VarName"]."=";
561  $OnChangeAction = "if (this.checked) {"
562  ." window.location = '".$OnChangeLinkBase."1';"
563  ."} else {"
564  ." window.location = '".$OnChangeLinkBase."0';"
565  ."}";
566  ?> <input type="checkbox" name="<?= $Info["VarName"]
567  ?>" <?= $CheckboxState
568  ?> onchange="<?= $OnChangeAction ?>">
569  <?= $Info["Label"] ?><?PHP
570  }
571  else
572  {
573  ?> <a class="cw-button cw-button-elegant cw-button-constrained<?=
574  $IconButtonClass ?>"
575  href="<?= $Info["Link"] ?>"><?= $IconTag ?><?=
576  htmlspecialchars($Info["Label"]) ?></a><?PHP
577  }
578  }
579  print "</span>";
580  }
581  }
582 
586  private function DisplayNoItemsMessage()
587  {
588  print "<span class=\"cw-itemlist-empty\">";
589  if (strlen($this->NoItemsMsg))
590  {
591  print $this->NoItemsMsg;
592  }
593  elseif ($this->SchemaId !== TransportControlsUI::NO_ITEM_TYPE)
594  {
595  $Schema = new MetadataSchema($this->SchemaId);
596  print "(no ".strtolower(StdLib::Pluralize(
597  $Schema->ResourceName()))." to display)";
598  }
599  else
600  {
601  print "(no items to display)";
602  }
603  print "</span>";
604  }
605 
611  private function DisplayActionButtons($ItemId, $Item)
612  {
613  foreach ($this->Actions as $ActionInfo)
614  {
615  if ($ActionInfo["TestFunc"] !== NULL)
616  {
617  $DisplayButton = $ActionInfo["TestFunc"]($Item);
618  }
619  elseif (method_exists($Item, "UserCanEdit"))
620  {
621  $DisplayButton = $Item->UserCanEdit($GLOBALS["G_User"]);
622  }
623  else
624  {
625  $DisplayButton = TRUE;
626  }
627  if ($DisplayButton)
628  {
629  $ButtonClasses = "cw-button cw-button-elegant"
630  ." cw-button-constrained";
631  $ExtraAttribs = "";
632  foreach ($ActionInfo["AddAttribs"]
633  as $AttribName => $AttribValue)
634  {
635  $AttribValue = htmlspecialchars($AttribValue);
636  if (strtolower($AttribName) == "class")
637  {
638  $ButtonClasses .= " ".$AttribValue;
639  }
640  else
641  {
642  $ExtraAttribs .= " ".$AttribName
643  .'="'.$AttribValue.'"';
644  }
645  }
646  if ($ActionInfo["Icon"])
647  {
648  $IconFile = $GLOBALS["AF"]->GUIFile($ActionInfo["Icon"]);
649  $IconTag = $IconFile
650  ? '<img class="cw-button-icon" src="'
651  .$IconFile.'" alt=""> '
652  : "";
653  $ButtonClasses .= " cw-button-iconed";
654  }
655  else
656  {
657  $IconTag = "";
658  }
659  if (is_callable($ActionInfo["Link"]))
660  {
661  $Link = $ActionInfo["Link"]($Item);
662  }
663  elseif (method_exists($Item, "Id"))
664  {
665  $Link = preg_replace('/\$ID/', $Item->Id(),
666  $ActionInfo["Link"]);
667  }
668  else
669  {
670  $Link = preg_replace('/\$ID/', $ItemId,
671  $ActionInfo["Link"]);
672  }
673  print '<a class="'.$ButtonClasses.'"'.$ExtraAttribs
674  .' href="'.$Link.'">'.$IconTag
675  .htmlspecialchars($ActionInfo["Label"]).'</a>';
676  }
677  }
678  if ($this->SchemaId !== TransportControlsUI::NO_ITEM_TYPE)
679  {
680  $GLOBALS["AF"]->SignalEvent("EVENT_HTML_INSERTION_POINT",
681  array($GLOBALS["AF"]->GetPageName(),
682  "Resource Summary Buttons", array(
683  "Resource" => $Item)));
684  }
685  }
686 }
Metadata schema (in effect a Factory class for MetadataField).
Class to provide a user interface for displaying a list of items.
Definition: ItemListUI.php:13
static GetPrintableFieldName($Field)
Retrieve label for field.
static DefaultSortField($NewValue=NULL)
Get/set default sort field value.
& TransportUI()
Get the transport controls UI component used by the item list.
Definition: ItemListUI.php:241
BaseLink($NewValue=NULL)
Get/set base URL for current page, for any links that need to be constructed.
Definition: ItemListUI.php:84
static GetCanonicalFieldIdentifier($Field, $SchemaId=NULL)
Retrieve canonical identifier for field.
__construct($Fields, $SchemaId=TransportControlsUI::NO_ITEM_TYPE)
Constructor for item list UI class.
Definition: ItemListUI.php:42
static Pluralize($Word)
Pluralize an English word.
Definition: StdLib.php:164
AddTopCheckbox($Label, $Checked, $VarName, $Link)
Add "checkbox" above list.
Definition: ItemListUI.php:180
Display($Items, $TotalItemCount=NULL, $StartingIndex=NULL, $TransportMsg=NULL)
Print list HTML with specified items.
Definition: ItemListUI.php:260
Heading($NewValue=NULL)
Get/set heading text to be printed above list.
Definition: ItemListUI.php:130
ItemsPerPage($NewValue=NULL)
Get/set maximum number of items per page.
Definition: ItemListUI.php:144
Class to provide support for transport controls (used for paging back and forth through a list) in th...
AddTopButton($Label, $Link, $Icon=NULL)
Add "button" above list.
Definition: ItemListUI.php:161
static NeatlyTruncateString($String, $MaxLength, $BreakAnywhere=FALSE)
Attempt to truncate a string as neatly as possible with respect to word breaks, punctuation, and HTML tags.
Definition: StdLib.php:239
VariablesToPreserve($NewValue=NULL)
Get/set list of $_GET variables to preserve by adding them to base link whenever it is used...
Definition: ItemListUI.php:99
AddActionButton($Label, $Link, $Icon=NULL, $DisplayTestFunc=NULL, $AdditionalAttributes=array())
Add action "button" to each item in list.
Definition: ItemListUI.php:211
const NO_ITEM_TYPE
Constant to use when no item types available.
NoItemsMessage($NewValue=NULL)
Get/set message to display when there are no items to list.
Definition: ItemListUI.php:228
GetFullBaseLink()
Get full base link, including any variables to preserve.
Definition: ItemListUI.php:112