From 5855c8c8b6268265bde06ee716f9dacb0ebd509b Mon Sep 17 00:00:00 2001 From: Ryan Cramer Date: Fri, 24 Feb 2023 10:19:32 -0500 Subject: [PATCH] Implement new getFieldSetups() method in these Fieldtypes: Datetime, File, Image, Options, Page, and Textarea. --- .../Fieldtype/FieldtypeDatetime.module | 39 ++++++ .../FieldtypeFile/FieldtypeFile.module | 22 ++++ .../FieldtypeImage/FieldtypeImage.module | 14 +++ .../FieldtypeOptions/FieldtypeOptions.module | 60 +++++++++- .../SelectableOptionConfig.php | 68 +++++------ wire/modules/Fieldtype/FieldtypePage.module | 14 +++ .../Fieldtype/FieldtypeTextarea.module | 28 +++++ .../InputfieldPage/InputfieldPage.module | 113 +++++++++++++----- 8 files changed, 291 insertions(+), 67 deletions(-) diff --git a/wire/modules/Fieldtype/FieldtypeDatetime.module b/wire/modules/Fieldtype/FieldtypeDatetime.module index 3e318a4f..7e90f705 100644 --- a/wire/modules/Fieldtype/FieldtypeDatetime.module +++ b/wire/modules/Fieldtype/FieldtypeDatetime.module @@ -121,6 +121,45 @@ class FieldtypeDatetime extends Fieldtype { return $inputfield; } + /** + * Get predefined setups for newly created fields of this type + * + * #pw-internal + * #pw-hooker + * + * @return array + * @since 3.0.213 + * + */ + public function ___getFieldSetups() { + return array( + 'datetime' => array( + 'title' => $this->_x('Date and Time', 'datetime-setup'), // label for datetime field setup + 'dateOutputFormat' => $this->_x('j F Y g:i a', 'datetime-setup'), // default date/time output format for datetime (PHP dateformat) + 'dateInputFormat' => $this->_x('Y-m-d', 'datetime-setup'), // default date input format for datetime (PHP dateformat) + 'timeInputFormat' => $this->_x('g:i a', 'datetime-setup'), // default time input format for datetime (PHP dateformat) + 'inputType' => $this->_x('html', 'datetime-setup'), // default input type to use for datetime - one of: html, text, select + 'htmlType' => 'datetime', + ), + 'date' => array( + 'title' => $this->_x('Date', 'date-setup'), // label for date-only fields setup + 'dateOutputFormat' => $this->_x('j F Y', 'date-setup'), // default output format for date (PHP dateformat) + 'dateInputFormat' => $this->_x('Y-m-d', 'date-setup'), // default input format for date (PHP dateformat) + 'timeInputFormat' => '', + 'inputType' => $this->_x('html', 'date-setup'), // default input type to use for date - one of: html, text, select + 'htmlType' => 'date', + ), + 'time' => array( + 'title' => $this->_x('Time', 'time-setup'), // label for time-only field setup + 'dateOutputFormat' => $this->_x('g:i a', 'time-setup'), // default output format for time (PHP dateformat) + 'dateInputFormat' => '', + 'timeInputFormat' => $this->_x('g:i a', 'time-setup'), // default input format for time (PHP dateformat) + 'inputType' => $this->_x('html', 'time-setup'), // default input type to use for time - one of: html, text, select + 'htmlType' => 'time', + ), + ); + } + /** * Sanitize value, per Fieldtype interface * diff --git a/wire/modules/Fieldtype/FieldtypeFile/FieldtypeFile.module b/wire/modules/Fieldtype/FieldtypeFile/FieldtypeFile.module index ebd39bc7..ec93246e 100644 --- a/wire/modules/Fieldtype/FieldtypeFile/FieldtypeFile.module +++ b/wire/modules/Fieldtype/FieldtypeFile/FieldtypeFile.module @@ -187,6 +187,28 @@ class FieldtypeFile extends FieldtypeMulti implements ConfigurableModule, Fieldt return $inputfield; } + /** + * Get setup options and setup functions for new fields + * + * @return array + * @since 3.0.213 + * + */ + public function ___getFieldSetups() { + $setups = parent::___getFieldSetups(); + $setups['single'] = array( + 'title' => $this->_('Single file'), + 'maxFiles' => 1, + 'textformatters' => 'TextformatterEntities', + ); + $setups['multiple'] = array( + 'title' => $this->_('Multiple files'), + 'maxFiles' => 0, + 'textformatters' => 'TextformatterEntities', + ); + return $setups; + } + /** * Get compatible Fieldtypes * diff --git a/wire/modules/Fieldtype/FieldtypeImage/FieldtypeImage.module b/wire/modules/Fieldtype/FieldtypeImage/FieldtypeImage.module index 5784afd7..04eff84b 100644 --- a/wire/modules/Fieldtype/FieldtypeImage/FieldtypeImage.module +++ b/wire/modules/Fieldtype/FieldtypeImage/FieldtypeImage.module @@ -281,6 +281,20 @@ class FieldtypeImage extends FieldtypeFile implements FieldtypeHasFiles, Fieldty if($value instanceof Pageimage) $pageimages->add($value); return $pageimages; } + + /** + * Get setup options and setup functions for new fields + * + * @return array + * @since 3.0.213 + * + */ + public function ___getFieldSetups() { + $setups = parent::___getFieldSetups(); + $setups['single']['title'] = $this->_('Single image'); + $setups['multiple']['title'] = $this->_('Multiple images'); + return $setups; + } /** * Get Inputfields to configure fields using this Fieldtype diff --git a/wire/modules/Fieldtype/FieldtypeOptions/FieldtypeOptions.module b/wire/modules/Fieldtype/FieldtypeOptions/FieldtypeOptions.module index d5286b18..e11d10a9 100644 --- a/wire/modules/Fieldtype/FieldtypeOptions/FieldtypeOptions.module +++ b/wire/modules/Fieldtype/FieldtypeOptions/FieldtypeOptions.module @@ -3,7 +3,7 @@ /** * ProcessWire Select Options Fieldtype * - * ProcessWire 3.x, Copyright 2022 by Ryan Cramer + * ProcessWire 3.x, Copyright 2023 by Ryan Cramer * https://processwire.com * * @property SelectableOptionManager $manager @@ -125,6 +125,20 @@ class FieldtypeOptions extends FieldtypeMulti implements Module { return $inputfield; } + /** + * Get setup options and setup functions for new fields + * + * @return array + * @since 3.0.213 + * + */ + public function ___getFieldSetups() { + $setups = parent::___getFieldSetups(); + $setups = array_merge($setups, $this->getInputfieldClassOptions(true)); + return $setups; + } + + /** * Get Fieldtypes that are known compatible with this one * @@ -598,6 +612,50 @@ class FieldtypeOptions extends FieldtypeMulti implements Module { return $inputfields; } + /** + * Get Inputfield options + * + * #pw-internal + * + * @param bool $getFieldSetups + * @return array + * @since 3.0.213 + * + */ + public function getInputfieldClassOptions($getFieldSetups = false) { + $options = array(); + $modules = $this->wire()->modules; + $labelSingle = $this->_('Single option:'); + $labelMulti = $this->_('Multiple options:'); + $labelSortable = $this->_('Multiple sortable options:'); + + foreach($modules->findByPrefix('Inputfield') as $moduleName) { + $module = $modules->getModule($moduleName, array('noInit' => true)); + if(!$module instanceof InputfieldHasSelectableOptions) continue; + $title = str_replace('Inputfield', '', $moduleName); + if($module instanceof InputfieldHasSortableValue) { + $title = "$labelSortable $title"; + } else if($module instanceof InputfieldSelectMultiple) { + $title = "$labelMulti $title"; + } else { + $title = "$labelSingle $title"; + } + if($getFieldSetups) { + $name = str_replace('Inputfield', '', $moduleName); + $options[$name] = array( + 'title' => $title, + 'inputfieldClass' => $moduleName, + ); + } else { + $options[$moduleName] = $title; + } + } + + asort($options); + + return $options; + } + /** * Given a FieldtypeOptions field id, name or object, return the object * @param $field diff --git a/wire/modules/Fieldtype/FieldtypeOptions/SelectableOptionConfig.php b/wire/modules/Fieldtype/FieldtypeOptions/SelectableOptionConfig.php index a4bfbadb..2541d2c8 100644 --- a/wire/modules/Fieldtype/FieldtypeOptions/SelectableOptionConfig.php +++ b/wire/modules/Fieldtype/FieldtypeOptions/SelectableOptionConfig.php @@ -3,7 +3,7 @@ /** * Inputfields and processing for Select Options Fieldtype * - * ProcessWire 3.x, Copyright 2020 by Ryan Cramer + * ProcessWire 3.x, Copyright 2023 by Ryan Cramer * https://processwire.com * */ @@ -42,6 +42,7 @@ class SelectableOptionConfig extends Wire { * */ public function __construct(Field $field, InputfieldWrapper $inputfields) { + parent::__construct(); $this->field = $field; $fieldtype = $field->type; /** @var FieldtypeOptions $fieldtype */ $this->fieldtype = $fieldtype; @@ -59,25 +60,30 @@ class SelectableOptionConfig extends Wire { * */ protected function process(Inputfield $inputfield) { + + $modules = $this->wire()->modules; + $input = $this->wire()->input; + $user = $this->wire()->user; + $process = $this->wire()->process; + $languages = $this->wire()->languages; + $session = $this->wire()->session; - $value = $this->wire('input')->post('_options'); - $user = $this->wire('user'); /** @var User $user */ - $process = $this->wire('process'); /** @var Process @process */ + $value = $input->post('_options'); if($process != 'ProcessField' || (!$user->isSuperuser() && !$user->hasPermission('field-admin'))) return; $ns = "$this$this->field"; // namespace for session if(!is_null($value)) { // _options has been posted - if($this->manager->useLanguages() && $inputfield->getSetting('useLanguages')) { + if($this->manager->useLanguages() && $inputfield->getSetting('useLanguages') && $languages) { // multi-language $valuesPerLanguage = array(); $changed = false; - foreach($this->wire('languages') as $language) { + foreach($languages as $language) { $key = $language->isDefault() ? "_options" : "_options__$language"; - $valuesPerLanguage[$language->id] = $this->wire('input')->post($key); + $valuesPerLanguage[$language->id] = $input->post($key); $key = $language->isDefault() ? "value" : "value$language"; if($inputfield->$key != $valuesPerLanguage[$language->id]) $changed = true; } @@ -97,11 +103,11 @@ class SelectableOptionConfig extends Wire { $removedOptionIDs = $this->manager->getRemovedOptionIDs(); // identified for removal if(count($removedOptionIDs)) { // stuff in session for next request - $this->wire('session')->set($ns, 'removedOptionIDs', $removedOptionIDs); + $session->set($ns, 'removedOptionIDs', $removedOptionIDs); } - $deleteOptionIDs = $this->wire('input')->post('_delete_options'); - $deleteConfirm = (int) $this->wire('input')->post('_delete_confirm'); + $deleteOptionIDs = $input->post('_delete_options'); + $deleteConfirm = (int) $input->post('_delete_confirm'); if($deleteOptionIDs && $deleteConfirm) { // confirmed deleted if(!ctype_digit(str_replace(',', '', $deleteOptionIDs))) throw new WireException("Invalid deleteOptionIDs"); @@ -113,16 +119,17 @@ class SelectableOptionConfig extends Wire { } else { // options not posted, check if there are any pending session activities - $removedOptionIDs = $this->wire('session')->get($ns, 'removedOptionIDs'); + $removedOptionIDs = $session->get($ns, 'removedOptionIDs'); if(wireCount($removedOptionIDs)) { - - $f = $this->wire('modules')->get('InputfieldHidden'); + /** @var InputfieldHidden $f */ + $f = $modules->get('InputfieldHidden'); $f->attr('name', '_delete_options'); $f->attr('value', implode(',', $removedOptionIDs)); $this->inputfields->prepend($f); // setup for confirmation - $f = $this->wire('modules')->get('InputfieldCheckbox'); + /** @var InputfieldCheckbox $f */ + $f = $modules->get('InputfieldCheckbox'); $f->attr('name', '_delete_confirm'); $f->label = $this->_('Please confirm that you want to delete options'); $f->label2 = $this->_n('Delete this option', 'Delete these options', count($removedOptionIDs)); @@ -131,11 +138,14 @@ class SelectableOptionConfig extends Wire { $delimiter = $this->_('DELETE:') . ' '; $f->description .= $delimiter . $removeOptions->implode("\n$delimiter", 'title'); // collapse other inputfields since we prefer them to focus on this one only for now - foreach($this->inputfields as $i) $i->collapsed = Inputfield::collapsedYes; + foreach($this->inputfields as $i) { + /** @var Inputfield $i */ + $i->collapsed = Inputfield::collapsedYes; + } // add our confirmation field $this->inputfields->prepend($f); // was stuffed in session from previous request, unset it now since this is a one time thing - $this->wire('session')->remove($ns, 'removedOptionIDs'); + $session->remove($ns, 'removedOptionIDs'); } } } @@ -154,37 +164,18 @@ class SelectableOptionConfig extends Wire { $options = $this->manager->getOptions($field); $modules = $this->wire('modules'); - $labelSingle = $this->_('Single value'); - $labelMulti = $this->_('Multiple values'); - $labelSortable = $this->_('Multiple sortable values'); - + /** @var InputfieldSelect $f */ $f = $modules->get('InputfieldSelect'); $f->attr('name', 'inputfieldClass'); $f->label = $this->_('What should be used for input?'); $f->description = $this->_('Depending on what input type you choose, the user will be able to select either a single option or multiple options. Some input types (like AsmSelect) also support user-sortable selections. Some input types also provide more settings on the *Input* tab (visible after you save).'); - - foreach($modules as $module) { - if(strpos($module->className(), 'Inputfield') !== 0) continue; - if($module instanceof ModulePlaceholder) { - $module = $modules->getModule($module->className(), array('noInit' => true)); - } - if($module instanceof InputfieldSelect || $module instanceof InputfieldHasSelectableOptions) { - $name = str_replace('Inputfield', '', $module->className()); - if($module instanceof InputfieldHasSortableValue) { - $name .= " ($labelSortable)"; - } else if($module instanceof InputfieldSelectMultiple) { - $name .= " ($labelMulti)"; - } else { - $name .= " ($labelSingle)"; - } - $f->addOption($module->className(), $name); - } - } + $f->addOptions($this->fieldtype->getInputfieldClassOptions()); $value = $field->get('inputfieldClass'); if(!$value) $value = 'InputfieldSelect'; $f->attr('value', $value); $inputfields->add($f); + /** @var InputfieldTextarea $f */ $f = $modules->get('InputfieldTextarea'); $f->attr('name', '_options'); $f->label = $this->_('What are the selectable options?'); @@ -206,6 +197,7 @@ class SelectableOptionConfig extends Wire { $inputfieldClass = $field->get('inputfieldClass'); if($options->count() && $inputfieldClass && $f = $modules->get($inputfieldClass)) { + /** @var InputfieldSelect $f */ $f->attr('name', 'initValue'); $f->label = $this->_('What options do you want pre-selected? (if any)'); $f->collapsed = Inputfield::collapsedBlank; diff --git a/wire/modules/Fieldtype/FieldtypePage.module b/wire/modules/Fieldtype/FieldtypePage.module index 361befcb..64276359 100644 --- a/wire/modules/Fieldtype/FieldtypePage.module +++ b/wire/modules/Fieldtype/FieldtypePage.module @@ -133,6 +133,20 @@ class FieldtypePage extends FieldtypeMulti implements Module, ConfigurableModule return $inputfield; } + /** + * Get setup options and setup functions for new fields + * + * @return array + * @since 3.0.213 + * + */ + public function ___getFieldSetups() { + $setups = parent::___getFieldSetups(); + /** @var InputfieldPage $f */ + $f = $this->wire()->modules->getModule('InputfieldPage', array('noInit' => true)); + return array_merge($setups, $f->getFieldSetups()); + } + /** * Per the Fieldtype interface, Save the given Field from the given Page to the database * diff --git a/wire/modules/Fieldtype/FieldtypeTextarea.module b/wire/modules/Fieldtype/FieldtypeTextarea.module index 46ad80b2..b8384782 100644 --- a/wire/modules/Fieldtype/FieldtypeTextarea.module +++ b/wire/modules/Fieldtype/FieldtypeTextarea.module @@ -292,6 +292,34 @@ class FieldtypeTextarea extends FieldtypeText { $inputfield->class = $this->className(); return $inputfield; } + + /** + * Get setup options and setup functions for new fields + * + * @return array + * @since 3.0.213 + * + */ + public function ___getFieldSetups() { + $class = $this->className(); + $setups = parent::___getFieldSetups(); + if($class !== 'FieldtypeTextarea' && $class !== 'FieldtypeTextareaLanguage') { + // limit setups options to the base types + return $setups; + } + $setups['default'] = array('title' => 'Textarea'); + $modules = $this->wire()->modules; + $editors = array('CKEditor', 'TinyMCE'); + foreach($editors as $name) { + if($modules->isInstalled("Inputfield$name")) $setups[$name] = array( + 'title' => $name, + 'inputfieldClass' => "Inputfield$name", + 'contentType' => self::contentTypeHTML, + 'textformatters' => array() + ); + } + return $setups; + } /** * Get database schema used by the Field diff --git a/wire/modules/Inputfield/InputfieldPage/InputfieldPage.module b/wire/modules/Inputfield/InputfieldPage/InputfieldPage.module index c2a28a90..bb45ffdc 100644 --- a/wire/modules/Inputfield/InputfieldPage/InputfieldPage.module +++ b/wire/modules/Inputfield/InputfieldPage/InputfieldPage.module @@ -1375,36 +1375,14 @@ class InputfieldPage extends Inputfield implements ConfigurableModule { $field->required = true; $field->icon = 'plug'; $inputfieldSelection = $field; + + $options = $this->getInputfieldOptions(); + $pageListTypes = $options['pageListTypes']; - $singles = array(); - $multiples = array(); - $sortables = array(); - $pageListTypes = array(); - - $inputfieldClasses = $this->inputfieldClasses; - if($this->hasFieldtype) $inputfieldClasses = array_merge(self::$defaultInputfieldClasses, $inputfieldClasses); - - foreach($inputfieldClasses as $class) { - $module = $modules->getModule($class, array('noInit' => true)); - $info = $modules->getModuleInfo($module); - $label = ucfirst((string) $info['title']); - if($module instanceof InputfieldPageListSelection) { - $pageListTypes[] = $class; - } - if($module instanceof InputfieldHasSortableValue) { - $sortables[$class] = $label; - } else if($module instanceof InputfieldHasArrayValue || $module instanceof InputfieldSupportsArrayValue) { - $multiples[$class] = $label; - } else { - $singles[$class] = $label; - } - if($class == 'InputfieldPageAutocomplete') $singles["_$class"] = $label; - } - $multiLabel = $this->_('Multiple page selection'); - $field->addOption($this->_('Single page selection'), $singles); - $field->addOption($multiLabel, $multiples); - $field->addOption($multiLabel . ' (' . $this->_('sortable') . ')', $sortables); + $field->addOption($this->_('Single page selection'), $options['singles']); + $field->addOption($multiLabel, $options['multiples']); + $field->addOption($multiLabel . ' (' . $this->_('sortable') . ')', $options['sortables']); $inputfields->insertBefore($field, $selectablePagesFieldset); if($this->hasFieldtype === false) { @@ -1501,6 +1479,85 @@ class InputfieldPage extends Inputfield implements ConfigurableModule { return $inputfields; } + /** + * Get options available for page selection Inputfields + * + * @return array + * @since 3.0.213 + * + */ + public function getInputfieldOptions() { + $modules = $this->wire()->modules; + + $singles = array(); + $multiples = array(); + $sortables = array(); + $pageListTypes = array(); + + $inputfieldClasses = $this->inputfieldClasses; + if($this->hasFieldtype) $inputfieldClasses = array_merge(self::$defaultInputfieldClasses, $inputfieldClasses); + + foreach($inputfieldClasses as $class) { + $module = $modules->getModule($class, array('noInit' => true)); + $info = $modules->getModuleInfo($module); + $label = ucfirst((string) $info['title']); + if($module instanceof InputfieldPageListSelection) { + $pageListTypes[] = $class; + } + if($module instanceof InputfieldHasSortableValue) { + $sortables[$class] = $label; + } else if($module instanceof InputfieldHasArrayValue || $module instanceof InputfieldSupportsArrayValue) { + $multiples[$class] = $label; + } else { + $singles[$class] = $label; + } + if($class == 'InputfieldPageAutocomplete') $singles["_$class"] = $label; + } + + return array( + 'singles' => $singles, + 'multiples' => $multiples, + 'sortables' => $sortables, + 'pageListTypes' => $pageListTypes, + ); + } + + /** + * Get recommended setups for FieldtypePage/InputfieldPage + * + * @return array + * @since 3.0.213 + * + */ + public function getFieldSetups() { + $setups = array(); + $options = $this->getInputfieldOptions(); + $singleLabel = $this->_('Single page:'); + $multiLabel = $this->_('Multiple pages:'); + $sortLabel = $this->_('Multiple sortable pages:'); + + foreach($options['singles'] as $class => $label) { + $name = str_replace('Inputfield', '', $class); + $setups[$name] = array( + 'title' => "$singleLabel $label", + 'derefAsPage' => FieldtypePage::derefAsPageOrNullPage, + 'inputfield' => $class, + ); + } + + foreach(array_merge($options['multiples'], $options['sortables']) as $class => $label) { + $name = str_replace('Inputfield', '', $class); + $label = isset($options['sortables'][$class]) ? "$sortLabel $label" : "$multiLabel $label"; + $setups[$name] = array( + 'title' => $label, + 'derefAsPage' => FieldtypePage::derefAsPageArray, + 'inputfield' => $class, + ); + } + + return $setups; + } + /** * Get module configuration Inputfields *