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 
46  public function __construct($Heading, $Fields, $ItemsPerPage, $BaseLink,
48  {
49  # normalize and save field info
50  if ($SchemaId == TransportControlsUI::NO_ITEM_TYPE)
51  {
52  $this->Fields = $Fields;
53  }
54  else
55  {
56  $this->Fields = array();
57  foreach ($Fields as $FieldId => $FieldInfo)
58  {
59  $CanonicalId = MetadataSchema::GetCanonicalFieldIdentifier($FieldId);
60  $this->Fields[$CanonicalId] = $FieldInfo;
61  }
62  }
63 
64  # save other supplied settings for later use
65  $this->BaseLink = $BaseLink;
66  $this->Heading = $Heading;
67  $this->ItemsPerPage = $ItemsPerPage;
68  $this->SchemaId = $SchemaId;
69 
70  # set up transport controls
71  foreach ($this->Fields as $FieldId => $FieldInfo)
72  {
73  if (isset($FieldInfo["DefaultSortField"]))
74  {
76  }
77  }
78  $this->TransportUI = new TransportControlsUI(
79  $this->SchemaId, $this->ItemsPerPage);
80  }
81 
89  public function AddTopButton($Label, $Link, $Icon = NULL)
90  {
91  $this->Buttons[] = array(
92  "Label" => $Label,
93  "Link" => $Link,
94  "Icon" => $Icon);
95  }
96 
108  public function AddTopCheckbox($Label, $Checked, $VarName, $Link)
109  {
110  if (strpos($Link, $VarName."=") !== FALSE)
111  {
112  $Link = preg_replace("/(&|&amp;)".preg_quote($VarName)."=[^&]*/",
113  "", $Link);
114  }
115  $this->Buttons[] = array(
116  "Label" => $Label,
117  "Checked" => $Checked,
118  "VarName" => $VarName,
119  "Link" => $Link);
120  }
121 
139  public function AddActionButton(
140  $Label, $Link, $Icon = NULL, $DisplayTestFunc = NULL,
141  $AdditionalAttributes = array())
142  {
143  $this->Actions[] = array(
144  "Label" => $Label,
145  "Link" => $Link,
146  "Icon" => $Icon,
147  "TestFunc" => $DisplayTestFunc,
148  "AddAttribs" => $AdditionalAttributes);
149  }
150 
156  public function NoItemsMessage($NewValue = NULL)
157  {
158  if ($NewValue !== NULL)
159  {
160  $this->NoItemsMsg = $NewValue;
161  }
162  return $this->NoItemsMsg;
163  }
164 
169  public function &TransportUI()
170  {
171  return $this->TransportUI;
172  }
173 
188  public function Display($Items, $TotalItemCount = NULL,
189  $StartingIndex = NULL, $TransportMsg = NULL)
190  {
191  # retrieve context values from transport controls
192  $StartingIndex = $this->TransportUI->StartingIndex($StartingIndex);
193  $SortFieldId = $this->TransportUI->SortField();
194  $ReverseSort = $this->TransportUI->ReverseSortFlag();
195 
196  # display buttons above list
197  $this->DisplayTopButtons();
198 
199  # display heading
200  if ($this->Heading !== NULL)
201  {
202  if ($this->Heading == strip_tags($this->Heading))
203  {
204  print "<h1>".$this->Heading."</h1>\n";
205  }
206  else
207  {
208  print $this->Heading."\n";
209  }
210  }
211 
212  # display "no items" message and exit if no items
213  if (count($Items) == 0)
214  {
215  $this->DisplayNoItemsMessage();
216  return;
217  }
218 
219  # begin item table
220  print '<table class="cw-table cw-table-sideheaders cw-table-fullsize
221  cw-table-padded cw-table-striped">';
222 
223  # begin header row
224  print "<thead><tr>";
225 
226  # for each field
227  foreach ($this->Fields as $FieldId => $FieldInfo)
228  {
229  # if header value supplied
230  if (isset($FieldInfo["Heading"]))
231  {
232  # use supplied value
233  $Heading = $FieldInfo["Heading"];
234  }
235  # else if we can get header from schema
236  elseif ($this->SchemaId !== TransportControlsUI::NO_ITEM_TYPE)
237  {
238  # use name of field (with any leading schema name stripped)
239  $Heading = MetadataSchema::GetPrintableFieldName($FieldId);
240  $Heading = preg_replace("/.+\: /", "", $Heading);
241  }
242  # else if field ID appears like it may be a name
243  elseif (is_string($FieldId) && !is_numeric($FieldId))
244  {
245  $Heading = $FieldId;
246  }
247  else
248  {
249  $Heading = "(NO HEADER SET)";
250  }
251 
252  # if sorting is disabled for field
253  if (isset($FieldInfo["NoSorting"]))
254  {
255  # print header
256  print "<th>".$Heading."</th>\n";
257  }
258  else
259  {
260  # build sort link
261  $SortLink = $this->BaseLink."&amp;SF=".$FieldId
262  .$this->TransportUI->UrlParameterString(TRUE, array("SF", "RS"));
263 
264  # determine current sort direction
265  if (isset($FieldInfo["DefaultToDescendingSort"]))
266  {
267  $SortAscending = $ReverseSort ? TRUE : FALSE;
268  }
269  else
270  {
271  $SortAscending = $ReverseSort ? FALSE : TRUE;
272  }
273 
274  # set sort direction indicator (if any)
275  if ($FieldId == $SortFieldId)
276  {
277  $DirIndicator = ($SortAscending) ? "&uarr;" : "&darr;";
278  if (!$ReverseSort)
279  {
280  $SortLink .= "&amp;RS=1";
281  }
282  }
283  else
284  {
285  $DirIndicator = "";
286  }
287 
288  # print header
289  print "<th><a href=\"".$SortLink."\">".$Heading."</a>"
290  .$DirIndicator."</th>\n";
291  }
292  }
293 
294  # add action header if needed
295  if (is_array($this->Actions) && count($this->Actions))
296  {
297  print "<th>Actions</th>\n";
298  }
299 
300  # end header row
301  print "</tr></thead>\n";
302 
303  # for each item
304  print "<tbody>\n";
305  foreach ($Items as $ItemId => $Item)
306  {
307  # start row
308  print "<tr>\n";
309 
310  # for each field
311  foreach ($this->Fields as $FieldId => $FieldInfo)
312  {
313  # if there is value function defined for field
314  if (isset($FieldInfo["ValueFunction"]))
315  {
316  # call function for value
317  $Value = $FieldInfo["ValueFunction"]($Item, $FieldId);
318  }
319  else
320  {
321  # if item is associative array
322  if (is_array($Item))
323  {
324  # retrieve value for field (if any) from item
325  $Value = isset($Item[$FieldId])
326  ? $Item[$FieldId] : "";
327  }
328  # else if field ID is item method
329  elseif (method_exists($Item, $FieldId))
330  {
331  # get field value via item method
332  $Value = $Item->$FieldId();
333  }
334  else
335  {
336  # get field value from item via Get()
337  $Values = $Item->Get($FieldId);
338  $Value = is_array($Values) ? array_shift($Values) : $Values;
339  }
340 
341  # if max length specified for field
342  if (isset($FieldInfo["MaxLength"]))
343  {
345  $Value, $FieldInfo["MaxLength"]);
346  }
347 
348  # encode any HTML-significant chars in value
349  if (!isset($FieldInfo["AllowHTML"]))
350  {
351  $Value = htmlspecialchars($Value);
352  }
353  }
354 
355  # get link value (if any)
356  if (isset($FieldInfo["Link"]))
357  {
358  if (method_exists($Item, "Id"))
359  {
360  $Link = preg_replace('/\$ID/', $Item->Id(),
361  $FieldInfo["Link"]);
362  }
363  else
364  {
365  $Link = preg_replace('/\$ID/', $ItemId,
366  $FieldInfo["Link"]);
367  }
368  $LinkStart = '<a href="'.$Link.'">';
369  $LinkEnd = "</a>";
370  }
371  elseif (isset($FieldInfo["LinkFunction"]))
372  {
373  $Link = $FieldInfo["LinkFunction"]($Item);
374  if (!strlen($Link))
375  {
376  $LinkStart = "";
377  $LinkEnd = "";
378  }
379  else
380  {
381  if (method_exists($Item, "Id"))
382  {
383  $Link = preg_replace('/\$ID/', $Item->Id(),
384  $Link);
385  }
386  else
387  {
388  $Link = preg_replace('/\$ID/', $ItemId,
389  $Link);
390  }
391  $LinkStart = '<a href="'.$Link.'">';
392  $LinkEnd = "</a>";
393  }
394  }
395  else
396  {
397  $LinkStart = "";
398  $LinkEnd = "";
399  }
400 
401  # display cell with value
402  print "<td>".$LinkStart.$Value.$LinkEnd."</td>\n";
403  }
404 
405  # add action buttons
406  if (is_array($this->Actions) && count($this->Actions))
407  {
408  print "<td>";
409  $this->DisplayActionButtons($ItemId, $Item);
410  print "</td>\n";
411  }
412 
413  # end row
414  print "</tr>\n";
415  }
416  print "</tbody>\n";
417 
418  # end item table
419  print "</table>\n";
420 
421  # if there are more items than are displayed
422  if ($TotalItemCount > count($Items))
423  {
424  # craft transport control message (if not supplied)
425  if ($TransportMsg === NULL)
426  {
427  $ItemsLabel = ($this->SchemaId !== TransportControlsUI::NO_ITEM_TYPE)
429  $Item->Schema()->ResourceName())
430  : "Items";
431  $TransportMsg = $ItemsLabel
432  ." <b>".($this->TransportUI->StartingIndex() + 1)
433  ."</b> - <b>"
434  .min(($this->TransportUI->StartingIndex() + $this->ItemsPerPage),
435  $TotalItemCount)
436  ."</b> of <b>".$TotalItemCount."</b>";
437  }
438 
439  # display transport controls
440  $this->TransportUI->StartingIndex($StartingIndex);
441  $this->TransportUI->ItemCount($TotalItemCount);
442  $this->TransportUI->PrintControls(
443  $this->SchemaId, $this->BaseLink, $TransportMsg);
444  }
445  }
446 
447 
448  # ---- PRIVATE INTERFACE -------------------------------------------------
449 
450  private $Actions;
451  private $BaseLink;
452  private $Buttons;
453  private $Fields;
454  private $Heading;
455  private $ItemsPerPage;
456  private $NoItemsMsg;
457  private $SchemaId;
458  private $TransportUI;
459 
463  private function DisplayTopButtons()
464  {
465  if (is_array($this->Buttons) && count($this->Buttons))
466  {
467  print '<span style="float: right; padding-top: 1.5em;">';
468  foreach ($this->Buttons as $Info)
469  {
470  if (isset($Info["Icon"]) && strlen($Info["Icon"]))
471  {
472  $IconFile = $GLOBALS["AF"]->GUIFile($Info["Icon"]);
473  $IconTag = $IconFile
474  ? '<img class="cw-button-icon" src="'
475  .$IconFile.'" alt=""> '
476  : "";
477  $IconButtonClass = " cw-button-iconed";
478  }
479  else
480  {
481  $IconTag = "";
482  $IconButtonClass = "";
483  }
484  if (isset($Info["Checked"]))
485  {
486  $CheckboxState = $Info["Checked"] ? "checked" : "";
487  $OnChangeLinkBase = $Info["Link"]."&amp;".$Info["VarName"]."=";
488  $OnChangeAction = "if (this.checked) {"
489  ." window.location = '".$OnChangeLinkBase."1';"
490  ."} else {"
491  ." window.location = '".$OnChangeLinkBase."0';"
492  ."}";
493  ?> <input type="checkbox" name="<?= $Info["VarName"]
494  ?>" <?= $CheckboxState
495  ?> onchange="<?= $OnChangeAction ?>">
496  <?= $Info["Label"] ?><?PHP
497  }
498  else
499  {
500  ?> <a class="cw-button cw-button-elegant cw-button-constrained<?=
501  $IconButtonClass ?>"
502  href="<?= $Info["Link"] ?>"><?= $IconTag ?><?=
503  htmlspecialchars($Info["Label"]) ?></a><?PHP
504  }
505  }
506  print "</span>";
507  }
508  }
509 
513  private function DisplayNoItemsMessage()
514  {
515  print "<span class=\"cw-itemlist-empty\">";
516  if (strlen($this->NoItemsMsg))
517  {
518  print $this->NoItemsMsg;
519  }
520  elseif ($this->SchemaId !== TransportControlsUI::NO_ITEM_TYPE)
521  {
522  $Schema = new MetadataSchema($this->SchemaId);
523  print "(no ".strtolower(StdLib::Pluralize(
524  $Schema->ResourceName()))." to display)";
525  }
526  else
527  {
528  print "(no items to display)";
529  }
530  print "</span>";
531  }
532 
538  private function DisplayActionButtons($ItemId, $Item)
539  {
540  foreach ($this->Actions as $ActionInfo)
541  {
542  if ($ActionInfo["TestFunc"] !== NULL)
543  {
544  $DisplayButton = $ActionInfo["TestFunc"]($Item);
545  }
546  elseif (method_exists($Item, "UserCanEdit"))
547  {
548  $DisplayButton = $Item->UserCanEdit($GLOBALS["G_User"]);
549  }
550  else
551  {
552  $DisplayButton = TRUE;
553  }
554  if ($DisplayButton)
555  {
556  $ButtonClasses = "cw-button cw-button-elegant"
557  ." cw-button-constrained";
558  $ExtraAttribs = "";
559  foreach ($ActionInfo["AddAttribs"]
560  as $AttribName => $AttribValue)
561  {
562  $AttribValue = htmlspecialchars($AttribValue);
563  if (strtolower($AttribName) == "class")
564  {
565  $ButtonClasses .= " ".$AttribValue;
566  }
567  else
568  {
569  $ExtraAttribs .= " ".$AttribName
570  .'="'.$AttribValue.'"';
571  }
572  }
573  if ($ActionInfo["Icon"])
574  {
575  $IconFile = $GLOBALS["AF"]->GUIFile($ActionInfo["Icon"]);
576  $IconTag = $IconFile
577  ? '<img class="cw-button-icon" src="'
578  .$IconFile.'" alt=""> '
579  : "";
580  $ButtonClasses .= " cw-button-iconed";
581  }
582  else
583  {
584  $IconTag = "";
585  }
586  if (is_callable($ActionInfo["Link"]))
587  {
588  $Link = $ActionInfo["Link"]($Item);
589  }
590  elseif (method_exists($Item, "Id"))
591  {
592  $Link = preg_replace('/\$ID/', $Item->Id(),
593  $ActionInfo["Link"]);
594  }
595  else
596  {
597  $Link = preg_replace('/\$ID/', $ItemId,
598  $ActionInfo["Link"]);
599  }
600  print '<a class="'.$ButtonClasses.'"'.$ExtraAttribs
601  .' href="'.$Link.'">'.$IconTag
602  .htmlspecialchars($ActionInfo["Label"]).'</a>';
603  }
604  }
605  if ($this->SchemaId !== TransportControlsUI::NO_ITEM_TYPE)
606  {
607  $GLOBALS["AF"]->SignalEvent("EVENT_HTML_INSERTION_POINT",
608  array($GLOBALS["AF"]->GetPageName(),
609  "Resource Summary Buttons", array(
610  "Resource" => $Item)));
611  }
612  }
613 }
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:169
__construct($Heading, $Fields, $ItemsPerPage, $BaseLink, $SchemaId=TransportControlsUI::NO_ITEM_TYPE)
Constructor for item list UI class.
Definition: ItemListUI.php:46
static GetCanonicalFieldIdentifier($Field, $SchemaId=NULL)
Retrieve canonical identifier for field.
static Pluralize($Word)
Pluralize an English word.
Definition: StdLib.php:162
AddTopCheckbox($Label, $Checked, $VarName, $Link)
Add "checkbox" above list.
Definition: ItemListUI.php:108
Display($Items, $TotalItemCount=NULL, $StartingIndex=NULL, $TransportMsg=NULL)
Print list HTML with specified items.
Definition: ItemListUI.php:188
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:89
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:237
AddActionButton($Label, $Link, $Icon=NULL, $DisplayTestFunc=NULL, $AdditionalAttributes=array())
Add action "button" to each item in list.
Definition: ItemListUI.php:139
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:156