734 lines
22 KiB
Text
734 lines
22 KiB
Text
|
<?php namespace ProcessWire;
|
||
|
|
||
|
/**
|
||
|
* ProcessWire Page Table Inputfield
|
||
|
*
|
||
|
* Concept by Antti Peisa
|
||
|
* Code by Ryan Cramer
|
||
|
* Sponsored by Avoine
|
||
|
*
|
||
|
* ProcessWire 3.x, Copyright 2023 by Ryan Cramer
|
||
|
* https://processwire.com
|
||
|
*
|
||
|
* @todo add renderValue support (perhaps delegating to Fieldtype::markupValue), likewise for repeaters.
|
||
|
*
|
||
|
* @property int $parent_id
|
||
|
* @property int $template_id
|
||
|
* @property string $columns
|
||
|
* @property string $nameFormat
|
||
|
* @property int|bool $noclose
|
||
|
* @property string $blankLabel
|
||
|
*
|
||
|
* @method string renderTable(array $columns)
|
||
|
*
|
||
|
*/
|
||
|
|
||
|
class InputfieldPageTable extends Inputfield {
|
||
|
|
||
|
public static function getModuleInfo() {
|
||
|
return array(
|
||
|
'title' => __('ProFields: Page Table', __FILE__), // Module Title
|
||
|
'summary' => __('Inputfield to accompany FieldtypePageTable', __FILE__), // Module Summary
|
||
|
'version' => 14,
|
||
|
'requires' => 'FieldtypePageTable'
|
||
|
);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Labels for native fields, indexed by native field name
|
||
|
*
|
||
|
* @var array
|
||
|
*
|
||
|
*/
|
||
|
protected $nativeLabels = array();
|
||
|
|
||
|
/**
|
||
|
* Array of Template objects used for each row
|
||
|
*
|
||
|
* @var array
|
||
|
*
|
||
|
*/
|
||
|
protected $rowTemplates = array();
|
||
|
|
||
|
/**
|
||
|
* Possible orphan pages that may be added (set by the Fieldtype)
|
||
|
*
|
||
|
* @var PageArray|null
|
||
|
*
|
||
|
*/
|
||
|
protected $orphans = null;
|
||
|
|
||
|
/**
|
||
|
* Whether or not a separate "edit" column is needed
|
||
|
*
|
||
|
* @var bool
|
||
|
*
|
||
|
*/
|
||
|
protected $needsEditColumn = false;
|
||
|
|
||
|
/**
|
||
|
* True when in renderValue mode
|
||
|
*
|
||
|
* @var bool
|
||
|
*
|
||
|
*/
|
||
|
protected $renderValueMode = false;
|
||
|
|
||
|
/**
|
||
|
* Initialize and establish default values
|
||
|
*
|
||
|
*/
|
||
|
public function init() {
|
||
|
|
||
|
// fieldtype and inputfield config settings
|
||
|
$this->set('parent_id', 0);
|
||
|
$this->set('template_id', 0); // placeholder only
|
||
|
$this->set('columns', '');
|
||
|
$this->set('nameFormat', '');
|
||
|
$this->set('noclose', 0);
|
||
|
$this->set('blankLabel', $this->_('[blank]'));
|
||
|
|
||
|
// local settings
|
||
|
$this->nativeLabels = array(
|
||
|
'id' => $this->_x('ID', 'th'),
|
||
|
'name' => $this->_x('Name', 'th'),
|
||
|
'created' => $this->_x('Created', 'th'),
|
||
|
'modified' => $this->_x('Modified', 'th'),
|
||
|
'published' => $this->_x('Published', 'th'),
|
||
|
'modifiedUser' => $this->_x('Modified By', 'th'),
|
||
|
'createdUser' => $this->_x('Created By', 'th'),
|
||
|
'url' => $this->_x('URL', 'th'),
|
||
|
'path' => $this->_x('Path', 'th'),
|
||
|
'template' => $this->_x('Template', 'th'),
|
||
|
'parent' => $this->_x('Parent', 'th'),
|
||
|
'numChildren' => $this->_x('Children', 'th'),
|
||
|
'status' => $this->_x('Status', 'th'),
|
||
|
);
|
||
|
|
||
|
parent::init();
|
||
|
}
|
||
|
|
||
|
public function renderReady(Inputfield $parent = null, $renderValueMode = false) {
|
||
|
$this->addClass('InputfieldNoFocus', 'wrapClass');
|
||
|
$jQueryUI = $this->wire()->modules->get('JqueryUI'); /** @var JqueryUI $jQueryUI */
|
||
|
$jQueryUI->use('modal');
|
||
|
return parent::renderReady($parent, $renderValueMode);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Render the PageTable Inputfield
|
||
|
*
|
||
|
* @return string
|
||
|
*
|
||
|
*/
|
||
|
public function ___render() {
|
||
|
|
||
|
$sanitizer = $this->wire()->sanitizer;
|
||
|
$modules = $this->wire()->modules;
|
||
|
$process = $this->wire()->process;
|
||
|
$config = $this->wire()->config;
|
||
|
$input = $this->wire()->input;
|
||
|
|
||
|
// make sure we've got enough info to generate a table
|
||
|
$errors = array();
|
||
|
if(!count($this->rowTemplates)) $errors[] = $this->_('Please configure this field with a template selection before using it.');
|
||
|
if(!$this->columns) $errors[] = $this->_('Please enter one or more columns in your field settings before using this field.');
|
||
|
if(count($errors)) return "<p class='ui-state-error'>" . implode('<br />', $errors) . "</p>";
|
||
|
|
||
|
// determine what columns we'll show in the table
|
||
|
$columnsString = $this->columns ? $this->columns : $this->getConfigDefaultColumns();
|
||
|
$columns = array();
|
||
|
|
||
|
foreach(explode("\n", $columnsString) as $column) {
|
||
|
$width = 0;
|
||
|
if(strpos($column, '=') !== false) list($column, $width) = explode('=', $column);
|
||
|
$column = trim($column);
|
||
|
$width = (int) $width;
|
||
|
$columns[$column] = $width;
|
||
|
}
|
||
|
|
||
|
// render the table
|
||
|
$out = $this->renderTable($columns);
|
||
|
if($this->renderValueMode) return $out;
|
||
|
|
||
|
$editID = (int) $input->get('id');
|
||
|
if(!$editID && $process instanceof WirePageEditor) $editID = $process->getPage()->id;
|
||
|
$parentID = $this->parent_id ? $this->parent_id : $editID;
|
||
|
|
||
|
// render the 'Add New' buttons for each template
|
||
|
$btn = '';
|
||
|
foreach($this->rowTemplates as $template) {
|
||
|
/** @var Template $template */
|
||
|
/** @var InputfieldButton $button */
|
||
|
$button = $modules->get('InputfieldButton');
|
||
|
$button->icon = 'plus-circle';
|
||
|
$button->value = count($this->rowTemplates) == 1 ? $this->_x('Add New', 'button') : $template->getLabel();
|
||
|
|
||
|
$url = $config->urls->admin . "page/add/?modal=1&template_id=$template->id&parent_id=$parentID&context=PageTable";
|
||
|
if($this->nameFormat) $url .= "&name_format=" . $sanitizer->entities($this->nameFormat);
|
||
|
$btn .= "<span class='InputfieldPageTableAdd' data-url='$url'>" . $button->render() . "</span>";
|
||
|
}
|
||
|
|
||
|
if(count($this->rowTemplates) > 1) $btn = "<small>$btn</small>";
|
||
|
$out .= "<div class='InputfieldPageTableButtons ui-helper-clearfix'>$btn</div>";
|
||
|
|
||
|
if(!$input->get('InputfieldPageTableField')) {
|
||
|
$url = "./?id=$editID&InputfieldPageTableField=$this->name";
|
||
|
$out = "<div class='InputfieldPageTableContainer' data-url='$url' data-noclose='$this->noclose'>$out</div>";
|
||
|
// input for sorting purposes
|
||
|
$value = $sanitizer->entities($this->attr('value'));
|
||
|
$name = $sanitizer->entities($this->attr('name'));
|
||
|
$out .= "<input type='hidden' name='$name' class='InputfieldPageTableSort' value='$value' />";
|
||
|
$out .= "<input type='hidden' name='{$name}__delete' class='InputfieldPageTableDelete' value='' />";
|
||
|
|
||
|
if($this->orphans && count($this->orphans)) {
|
||
|
$out .= "<p class='InputfieldPageTableOrphans'>";
|
||
|
$out .= "<span>" . $this->_('Children were found that may be added to this table. Check the box next to any you would like to add.') . "</span> ";
|
||
|
if(count($this->orphans) > 1) {
|
||
|
$out .= "<br /><a class='InputfieldPageTableOrphansAll' href='#'>" . $this->_('Select all') . "</a> ";
|
||
|
}
|
||
|
foreach($this->orphans as $item) {
|
||
|
$label = $item->title;
|
||
|
if(!strlen($label)) $label = $item->name;
|
||
|
$out .= "<label><input type='checkbox' name='{$this->name}__add_orphan[]' value='$item->id' /> <span class='detail'>$label</span></label>";
|
||
|
}
|
||
|
$out .= "</p>";
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return $out;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Render non-editable value
|
||
|
*
|
||
|
* @return string
|
||
|
*
|
||
|
*/
|
||
|
public function ___renderValue() {
|
||
|
$this->renderValueMode = true;
|
||
|
$out = $this->render();
|
||
|
$this->renderValueMode = false;
|
||
|
return $out;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Render the outputted PageTable <table>
|
||
|
*
|
||
|
* @param array $columns Array of column name => width percent
|
||
|
* @return string
|
||
|
*
|
||
|
*/
|
||
|
protected function ___renderTable(array $columns) {
|
||
|
$fields = $this->wire()->fields;
|
||
|
|
||
|
$this->needsEditColumn = false;
|
||
|
/** @var PageArray $value */
|
||
|
$value = $this->attr('value');
|
||
|
$this->wire()->modules->get('MarkupAdminDataTable'); // for styles
|
||
|
if(!count($value)) return ''; // if nothing in the value, just return blank
|
||
|
// $template = $this->template_id ? $this->wire('templates')->get((int) $this->template_id) : null;
|
||
|
$template = count($this->rowTemplates) > 0 ? reset($this->rowTemplates) : null;
|
||
|
$fieldsByCol = array();
|
||
|
$labelsByCol = array();
|
||
|
|
||
|
// populate $fieldsByCol and $labelsByCol
|
||
|
foreach($columns as $column => $width) {
|
||
|
|
||
|
$field = null;
|
||
|
$fieldName = $column;
|
||
|
$label = '';
|
||
|
|
||
|
// check if field contains field.subfield
|
||
|
if(strpos($column, '.') !== false) {
|
||
|
$parentField = null;
|
||
|
list($parentFieldName, $fieldName) = explode('.', $column);
|
||
|
|
||
|
if($template) $parentField = $template->fieldgroup->getFieldContext($parentFieldName);
|
||
|
if(!$parentField) $parentField = $fields->get($parentFieldName);
|
||
|
|
||
|
if($parentField) {
|
||
|
$label = $parentField->getLabel();
|
||
|
|
||
|
} else if(isset($this->nativeLabels[$parentFieldName])) {
|
||
|
$label = $this->nativeLabels[$parentFieldName];
|
||
|
|
||
|
} else {
|
||
|
$label = $parentFieldName;
|
||
|
}
|
||
|
|
||
|
$label .= " > ";
|
||
|
}
|
||
|
|
||
|
if($template) $field = $template->fieldgroup->getFieldContext($fieldName);
|
||
|
if(!$field) $field = $fields->get($fieldName);
|
||
|
|
||
|
if($field) {
|
||
|
$label .= $field->getLabel();
|
||
|
$fieldsByCol[$column] = $field;
|
||
|
|
||
|
} else if(isset($this->nativeLabels[$fieldName])) {
|
||
|
$label .= $this->nativeLabels[$fieldName];
|
||
|
|
||
|
} else {
|
||
|
$label .= $column;
|
||
|
}
|
||
|
|
||
|
$labelsByCol[$column] = $label;
|
||
|
}
|
||
|
|
||
|
$out = $this->renderTableBody($value, $columns, $fieldsByCol); // render order intentional
|
||
|
$out = $this->renderTableHead($columns, $labelsByCol) . $out;
|
||
|
|
||
|
return $out;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Render the table head, from <table> to </thead>
|
||
|
*
|
||
|
* @param array $columns
|
||
|
* @param array $labels
|
||
|
* @return string
|
||
|
*
|
||
|
*/
|
||
|
protected function renderTableHead(array $columns, array $labels) {
|
||
|
|
||
|
/** @var MarkupAdminDataTable $module */
|
||
|
$module = $this->wire()->modules->get('MarkupAdminDataTable');
|
||
|
$sanitizer = $this->wire()->sanitizer;
|
||
|
$classes = array();
|
||
|
foreach(array('class', 'addClass', 'responsiveClass', 'responsiveAltClass') as $key) {
|
||
|
$value = $module->settings($key);
|
||
|
if(!empty($value)) $classes[] = $value;
|
||
|
}
|
||
|
$tableClass = implode(' ', $classes);
|
||
|
|
||
|
$out = "<table class='$tableClass'><thead><tr>";
|
||
|
|
||
|
if($this->needsEditColumn) $out .= "<th> </th>";
|
||
|
|
||
|
foreach($columns as $column => $width) {
|
||
|
$attr = $width ? " style='width: $width%'" : '';
|
||
|
$label = $labels[$column];
|
||
|
$out .= "<th$attr>" . $sanitizer->entities($label) . "</th>";
|
||
|
}
|
||
|
|
||
|
if(!$this->renderValueMode) $out .= "<th> </th>";
|
||
|
$out .= "</tr></thead>";
|
||
|
|
||
|
return $out;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Render the table body, from <tbody> to </table>
|
||
|
*
|
||
|
* @param PageArray $items
|
||
|
* @param array $columns
|
||
|
* @param array $fields
|
||
|
* @return string
|
||
|
*
|
||
|
*/
|
||
|
protected function renderTableBody(PageArray $items, array $columns, array $fields) {
|
||
|
$rows = array();
|
||
|
|
||
|
foreach($items as $key => $item) {
|
||
|
/** @var Page $item */
|
||
|
$of = $item->of();
|
||
|
$item->of(true);
|
||
|
$rows[$key] = $this->renderTableRow($item, $columns, $fields);
|
||
|
$item->of($of);
|
||
|
}
|
||
|
|
||
|
if($this->needsEditColumn) {
|
||
|
foreach($rows as $key => $row) {
|
||
|
list($s1, $s2) = explode('>', $row, 2);
|
||
|
$item = $items[$key];
|
||
|
$rows[$key] = "$s1><td>" . $this->renderItemLink($item, wireIconMarkup('edit')) . "</td>$s2";
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return "<tbody>" . implode("", $rows) . "</tbody></table>";
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Render an individual table row <tr> for a given PageTable item
|
||
|
*
|
||
|
* @param Page $item
|
||
|
* @param array $columns
|
||
|
* @param array $fields
|
||
|
* @return string
|
||
|
*
|
||
|
*/
|
||
|
protected function renderTableRow(Page $item, array $columns, array $fields) {
|
||
|
|
||
|
$out = '';
|
||
|
$n = 0;
|
||
|
|
||
|
foreach($columns as $column => $width) {
|
||
|
$linkURL = ($n++ && !$this->renderValueMode ? '' : $this->getItemEditURL($item));
|
||
|
$out .= $this->renderTableCol($item, $fields, $column, $width, $linkURL);
|
||
|
}
|
||
|
|
||
|
// append a delete column/link
|
||
|
if(!$this->renderValueMode) {
|
||
|
$a = "<a class='InputfieldPageTableDelete' href='#'>" . wireIconMarkup('trash-o') . "</a>";
|
||
|
if(!$item->deletable()) $a = " ";
|
||
|
$out .= "<td>$a</td>";
|
||
|
}
|
||
|
|
||
|
// wrap the row in a <tr>
|
||
|
$class = '';
|
||
|
if($item->hasStatus(Page::statusUnpublished)) $class .= 'PageListStatusUnpublished ';
|
||
|
if($item->hasStatus(Page::statusHidden)) $class .= 'PageListStatusHidden ';
|
||
|
if($item->isTrash()) $class .= 'PageListStatusTrash';
|
||
|
if($class) $class = " class='" . trim($class) . "'";
|
||
|
|
||
|
return "<tr data-id='$item->id'$class>$out</tr>";
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Render an individual <td> for a table row
|
||
|
*
|
||
|
* @param Page $item
|
||
|
* @param array $fields
|
||
|
* @param $column
|
||
|
* @param $width
|
||
|
* @param string $linkURL
|
||
|
* @return string
|
||
|
*
|
||
|
*/
|
||
|
protected function renderTableCol(Page $item, array $fields, $column, $width, $linkURL = '') {
|
||
|
$out = $this->getItemValue($item, $fields, $column);
|
||
|
if($linkURL && !$this->renderValueMode) {
|
||
|
if(stripos($out, '<a ') !== false || stripos($out, '<li') !== false || !strlen($out)) {
|
||
|
// table will need a separate edit column since this item doesn't work as a link
|
||
|
$this->needsEditColumn = true;
|
||
|
if(!strlen($out)) $out = "<span class='detail'>$this->blankLabel</span>";
|
||
|
} else {
|
||
|
$out = $this->renderItemLink($item, $out, $linkURL);
|
||
|
}
|
||
|
}
|
||
|
$attr = $width ? " style='width: $width%'" : '';
|
||
|
return "<td$attr>$out</td>";
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Get the value for the given Page field identified by $column
|
||
|
*
|
||
|
* @param Page $item
|
||
|
* @param array $fields
|
||
|
* @param $column
|
||
|
* @return mixed|object|string
|
||
|
*
|
||
|
*/
|
||
|
protected function getItemValue(Page $item, array $fields, $column) {
|
||
|
|
||
|
$fieldName = $column;
|
||
|
$subfieldName = '';
|
||
|
|
||
|
if(strpos($column, '.') !== false) {
|
||
|
list($fieldName, $subfieldName) = explode('.', $column);
|
||
|
}
|
||
|
|
||
|
if(isset($fields[$column])) {
|
||
|
// custom
|
||
|
$field = $fields[$column]; /** @var Field $field */
|
||
|
$v = $item->getFormatted($fieldName);
|
||
|
$value = (string) $field->type->markupValue($item, $field, $v, $subfieldName);
|
||
|
|
||
|
} else {
|
||
|
// native
|
||
|
$value = $item->get($fieldName);
|
||
|
if(is_object($value) && $subfieldName) {
|
||
|
$value = $this->objectToString($value, $subfieldName);
|
||
|
$fieldName = $subfieldName;
|
||
|
}
|
||
|
if($fieldName == 'modified' || $fieldName == 'created' || $fieldName == 'published') {
|
||
|
$value = wireDate($this->_('Y-m-d H:i'), (int) $value); // Date format for created/modified/published
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return $value;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Render an item edit link surrounded by the given output
|
||
|
*
|
||
|
* @param Page $item
|
||
|
* @param string $out
|
||
|
* @param string $url Optional
|
||
|
* @return string
|
||
|
*
|
||
|
*/
|
||
|
protected function renderItemLink(Page $item, $out, $url = '') {
|
||
|
if(!$url) $url = $this->getItemEditURL($item);
|
||
|
return "<a class='InputfieldPageTableEdit' data-url='$url' href='$url'>$out</a>";
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Get an item edit URL
|
||
|
*
|
||
|
* @param Page $item
|
||
|
* @return string
|
||
|
*
|
||
|
*/
|
||
|
protected function getItemEditURL(Page $item) {
|
||
|
return $this->wire()->config->urls->admin . "page/edit/?id=$item->id&modal=1&context=PageTable";
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Convert an object to a string for rendering in a table
|
||
|
*
|
||
|
* @param $object
|
||
|
* @param string $property Property to display from the object (default=title|name)
|
||
|
* @return string
|
||
|
*
|
||
|
*/
|
||
|
protected function objectToString($object, $property = '') {
|
||
|
|
||
|
if($object instanceof WireArray) {
|
||
|
if(!$property) $property = 'title|name';
|
||
|
if($property == 'count') {
|
||
|
$value = $object->count();
|
||
|
} else {
|
||
|
$value = $object->implode("\n", $property);
|
||
|
}
|
||
|
|
||
|
} else if($property) {
|
||
|
$value = $object->$property;
|
||
|
if(is_object($value)) $value = $this->objectToString($value);
|
||
|
} else {
|
||
|
$value = (string) $object;
|
||
|
}
|
||
|
|
||
|
$value = $this->wire()->sanitizer->entities(strip_tags($value));
|
||
|
$value = nl2br($value);
|
||
|
|
||
|
return $value;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Process input submitted to a PageTable Inputfield
|
||
|
*
|
||
|
* @param WireInputData $input
|
||
|
* @return $this
|
||
|
*
|
||
|
*/
|
||
|
public function ___processInput(WireInputData $input) {
|
||
|
|
||
|
$pages = $this->wire()->pages;
|
||
|
|
||
|
$name = $this->attr('name');
|
||
|
$deleteName = $name . '__delete';
|
||
|
$deleteIDs = explode('|', $input->$deleteName);
|
||
|
$ids = explode('|', $input->$name);
|
||
|
$value = $this->attr('value'); /** @var PageArray $value */
|
||
|
$sorted = $pages->newPageArray();
|
||
|
$changed = false;
|
||
|
|
||
|
// trash items that have been deleted
|
||
|
foreach($deleteIDs as $id) {
|
||
|
foreach($value as $item) {
|
||
|
/** @var Page $item */
|
||
|
if($id != $item->id) continue;
|
||
|
if(!$item->deleteable()) continue;
|
||
|
$value->remove($item);
|
||
|
$pages->trash($item);
|
||
|
$changed = true;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
foreach($ids as $id) {
|
||
|
if(in_array($id, $deleteIDs)) continue;
|
||
|
foreach($value as $item) {
|
||
|
if($id == $item->id) $sorted->add($item);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// add in new items that may have been added after a sort
|
||
|
foreach($value as $item) {
|
||
|
if(!in_array($item->id, $ids)) $sorted->add($item);
|
||
|
}
|
||
|
|
||
|
// check for orphans that may have been added
|
||
|
$orphanInputName = $name . '__add_orphan';
|
||
|
$orphanIDs = $input->$orphanInputName;
|
||
|
if(is_array($orphanIDs) && count($orphanIDs) && $this->orphans) {
|
||
|
$numOrphansAdded = 0;
|
||
|
foreach($orphanIDs as $orphanID) {
|
||
|
foreach($this->orphans as $orphan) {
|
||
|
if($orphan->id == $orphanID) {
|
||
|
$sorted->add($orphan);
|
||
|
$numOrphansAdded++;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
if($numOrphansAdded) {
|
||
|
$this->message(sprintf($this->_('Added %d existing page(s) to table'), $numOrphansAdded) . " ($this->name)");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if("$value" != "$sorted") $changed = true;
|
||
|
|
||
|
if($changed) {
|
||
|
$this->setAttribute('value', $sorted);
|
||
|
$this->trackChange('value');
|
||
|
}
|
||
|
|
||
|
// check if we need to setup a name format for any pages
|
||
|
foreach($value as $n => $item) {
|
||
|
$name = $pages->setupPageName($item, array('format' => $this->nameFormat));
|
||
|
if($name) {
|
||
|
$this->message("Auto assigned name '$name' to item #" . ($n+1), Notice::debug);
|
||
|
$item->save();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return $this;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Set a property to this Inputfield
|
||
|
*
|
||
|
* @param string $key
|
||
|
* @param mixed $value
|
||
|
* @return $this
|
||
|
*
|
||
|
*/
|
||
|
public function set($key, $value) {
|
||
|
if($key === 'template_id' && $value) {
|
||
|
// convert template_id to $this->rowTemplates array
|
||
|
$templates = $this->wire()->templates;
|
||
|
if(!is_array($value)) $value = array($value);
|
||
|
foreach($value as $id) {
|
||
|
$template = $templates->get($id);
|
||
|
if($template) $this->rowTemplates[$id] = $template;
|
||
|
}
|
||
|
return $this;
|
||
|
} else {
|
||
|
return parent::set($key, $value);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Set an attribute to the Inputfield
|
||
|
*
|
||
|
* In this case we capture set to the 'value' attribute to make sure it can only be a PageArray
|
||
|
*
|
||
|
* @param array|string $key
|
||
|
* @param int|string $value
|
||
|
* @return $this
|
||
|
* @throws WireException
|
||
|
*
|
||
|
*/
|
||
|
public function setAttribute($key, $value) {
|
||
|
if($key == 'value') {
|
||
|
if($value === null) $value = $this->wire()->pages->newPageArray();
|
||
|
if(!$value instanceof PageArray) {
|
||
|
throw new WireException('This Inputfield only accepts a PageArray for its value attribute.');
|
||
|
}
|
||
|
}
|
||
|
return parent::setAttribute($key, $value);
|
||
|
}
|
||
|
|
||
|
public function setOrphans(PageArray $orphans) {
|
||
|
$this->orphans = $orphans;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Determine a default set of columns for the PageTable based on the fields defined in the defined template
|
||
|
*
|
||
|
* @return string of newline separated field names
|
||
|
*
|
||
|
*/
|
||
|
protected function getConfigDefaultColumns() {
|
||
|
$out = '';
|
||
|
if(!count($this->rowTemplates)) return $out;
|
||
|
|
||
|
$fieldCounts = array();
|
||
|
foreach($this->rowTemplates as $template) {
|
||
|
foreach($template->fieldgroup as $field) {
|
||
|
if(!isset($fieldCounts[$field->name])) {
|
||
|
$fieldCounts[$field->name] = 1;
|
||
|
} else {
|
||
|
$fieldCounts[$field->name]++;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// sort most used to least used
|
||
|
if(count($this->rowTemplates) > 1) arsort($fieldCounts);
|
||
|
|
||
|
$n = 0;
|
||
|
foreach(array_keys($fieldCounts) as $fieldName) {
|
||
|
$out .= $fieldName . "\n";
|
||
|
if(++$n >= 5) break;
|
||
|
}
|
||
|
return trim($out);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Get field configuration for input tab
|
||
|
*
|
||
|
* @return InputfieldWrapper
|
||
|
*
|
||
|
*/
|
||
|
public function ___getConfigInputfields() {
|
||
|
$inputfields = parent::___getConfigInputfields();
|
||
|
|
||
|
$f = $inputfields->InputfieldTextarea;
|
||
|
$f->attr('name', 'columns');
|
||
|
$f->label = $this->_('Table fields to display in admin');
|
||
|
$f->description =
|
||
|
$this->_('Enter the names of the fields (1 per line) that you want to display as columns in the table.') . ' ' .
|
||
|
$this->_('To specify a column width for the field, specify "field_name=30" where "30" is the width (in percent) of the column.') . ' ' .
|
||
|
$this->_('When specifying widths, make the total of all columns add up to 100.');
|
||
|
$f->notes =
|
||
|
$this->_('You may specify any native or custom field.') . ' ' .
|
||
|
$this->_('You may also use subfields (field.subfield) with fields that contain multiple properties, like page references.') . ' ';
|
||
|
$columns = $this->columns ? $this->columns : $this->getConfigDefaultColumns();
|
||
|
$f->attr('value', $columns);
|
||
|
|
||
|
if(count($this->rowTemplates)) {
|
||
|
$options = array();
|
||
|
foreach($this->rowTemplates as $template) {
|
||
|
foreach($template->fieldgroup as $item) $options[$item->name] = $item->name;
|
||
|
}
|
||
|
$f->notes .= $this->_('Custom fields assigned to your selected templates include the following:') . ' **';
|
||
|
$f->notes .= implode(', ', $options) . '**';
|
||
|
} else {
|
||
|
$f->notes .= $this->_('To see a list of possible custom fields here, select a template on the Details tab, Save, and come back here.');
|
||
|
}
|
||
|
|
||
|
$inputfields->add($f);
|
||
|
|
||
|
$f = $inputfields->InputfieldText;
|
||
|
$f->attr('name', 'nameFormat');
|
||
|
$f->attr('value', $this->nameFormat);
|
||
|
$f->label = $this->_('Automatic Page Name Format');
|
||
|
$f->description =
|
||
|
$this->_('When populated, pages will be created automatically using this name format whenever a user clicks the "Add New" button.') . ' ' . // page name format description 1
|
||
|
$this->_('If left blank, the user will be asked to enter a name for the page before it is created.'); // page name format description 2
|
||
|
$f->notes =
|
||
|
sprintf(
|
||
|
$this->_('If the name format contains any non-alphanumeric characters, it is considered to be a [PHP date](%s) format.'),
|
||
|
'https://www.php.net/manual/en/datetime.format.php'
|
||
|
). ' ' .
|
||
|
$this->_('If it contains only alphanumeric characters then it will be used directly, with a number appended to the end (when necessary) to ensure uniqueness.'); // page name format notes
|
||
|
$f->notes .= ' ' . $this->_('Example: **Ymd:His** is a good name format for date/time based page names.');
|
||
|
$f->collapsed = Inputfield::collapsedBlank;
|
||
|
$inputfields->add($f);
|
||
|
|
||
|
$f = $inputfields->InputfieldRadios;
|
||
|
$f->attr('name', 'noclose');
|
||
|
$f->label = $this->_('Modal edit window behavior');
|
||
|
$f->addOption(0, $this->_('Automatically close on save (default)'));
|
||
|
$f->addOption(1, $this->_('Keep window open, close manually'));
|
||
|
$f->attr('value', (int) $this->noclose);
|
||
|
if(!$this->noclose) $f->collapsed = Inputfield::collapsedYes;
|
||
|
$inputfields->add($f);
|
||
|
|
||
|
return $inputfields;
|
||
|
}
|
||
|
}
|