diff --git a/CHANGELOG.md b/CHANGELOG.md index c2de3f89..0c3c05f5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -46,7 +46,7 @@ - Added the “Parse embeds” field setting. ([#409](https://github.com/craftcms/ckeditor/pull/409)) - Added the “Show toolbar buttons for entry types with icons” field settings. ([#413](https://github.com/craftcms/ckeditor/pull/413)) - Fixed an error that occurred when copy/pasting a nested entry from a top-level element’s CKEditor field into a nested element’s CKEditor field. ([#408](https://github.com/craftcms/ckeditor/issues/408)) -- Fixed an error that could occur when generating a GraphQL introspection schema, if a CKEditor field’s GraphQL Mode setting was set to “Full data”. ([#414](https://github.com/craftcms/ckeditor/issues/414)) +- Fixed an error that could occur when generating a GraphQL introspection schema, if a CKEditor field’s GraphQL Mode setting was set to “Full data”. ([#414](https://github.com/craftcms/ckeditor/issues/414)) ## 4.8.0 - 2025-04-30 diff --git a/src/CkeConfig.php b/src/CkeConfig.php index 8fc3ca2a..c8f828dd 100644 --- a/src/CkeConfig.php +++ b/src/CkeConfig.php @@ -11,6 +11,9 @@ use craft\base\Actionable; use craft\base\Chippable; use craft\base\Model; +use craft\ckeditor\helpers\CkeditorConfig; +use craft\ckeditor\models\EntryType as CkeEntryType; +use craft\helpers\Cp; use craft\helpers\Json; use Illuminate\Support\Collection; use yii\base\InvalidArgumentException; @@ -82,6 +85,13 @@ public static function get(int|string $id): ?static */ public ?string $css = null; + /** + * @var CkeEntryType[] The field’s available entry types + * @see getEntryTypes() + * @see setEntryTypes() + */ + private array $_entryTypes = []; + public function __construct($config = []) { if (isset($config['toolbar']) && is_array($config['toolbar'])) { @@ -118,6 +128,10 @@ public function __construct($config = []) } } + if (isset($config['entryTypes']) && $config['entryTypes'] === '') { + $config['entryTypes'] = []; + } + unset($config['listPlugin']); parent::__construct($config); @@ -305,6 +319,78 @@ function(string $attribute, ?array $params, Validator $validator) { }, 'when' => fn() => isset($this->_json), ], + ['entryTypes', function(string $attribute, ?array $params, Validator $validator) { + // ensure that each selected entry type has at least one of: withText, withIcon + foreach ($this->$attribute as $entryType) { + if (!$entryType->withIcon && !$entryType->withText) { + $validator->addError($this, $attribute, Craft::t('ckeditor', 'Each entry type must either have an icon or text.')); + } + } + }], ]; } + + /** + * Returns the available entry types. + * + * @return CkeEntryType[] + * @since 5.0.0 + */ + public function getEntryTypes(): array + { + return $this->_entryTypes; + } + + /** + * Sets the available entry types. + * + * @param array $entryTypes The entry types, or their IDs or UUIDs + * @since 5.0.0 + */ + public function setEntryTypes(array $entryTypes): void + { + // normalize the $entryTypes; when saving the config, it'll be an array of json strings, like so: + foreach ($entryTypes as &$entryType) { + if (is_string($entryType)) { + try { + $entryType = Json::decode($entryType); + } catch (InvalidArgumentException) { + // do nothing? + } + } + } + unset($entryType); + + foreach ($entryTypes as $entryType) { + /** @var array $entryType */ + $this->_entryTypes[] = CkeditorConfig::getCkeEntryType($entryType); + } + } + + /** + * Returns entry type options in form of an array with 'label' and 'value' keys for each option. + * + * @return array + * @since 5.0.0 + */ + public function getEntryTypeOptions(): array + { + $entryTypeOptions = []; + + foreach ($this->getEntryTypes() as $entryType) { + $entryTypeOptions[] = [ + 'color' => $entryType->getColor()?->value, + 'expanded' => $entryType['expanded'] ?? false, + 'icon' => $entryType->icon ? Cp::iconSvg($entryType->icon) : null, + 'label' => Craft::t('site', $entryType->name), + 'uid' => $entryType->uid, + 'value' => $entryType->id, + 'withColor' => $entryType['withColor'] ?? true, + 'withIcon' => $entryType['withIcon'] ?? true, + 'withText' => $entryType['withText'] ?? true, + ]; + } + + return $entryTypeOptions; + } } diff --git a/src/CkeConfigs.php b/src/CkeConfigs.php index aa0d0049..cb925917 100644 --- a/src/CkeConfigs.php +++ b/src/CkeConfigs.php @@ -8,6 +8,7 @@ namespace craft\ckeditor; use Craft; +use craft\models\EntryType; use yii\base\Component; use yii\base\InvalidArgumentException; @@ -40,7 +41,7 @@ public function getAll(): array /** * @throws InvalidArgumentException if $uid is invalid */ - public function getByUid(string $uid): CkeConfig + public function getByUid(string $uid, bool $forToolbarEditor = false): CkeConfig { $config = Craft::$app->getProjectConfig()->get($this->_pcPath($uid)); @@ -48,7 +49,7 @@ public function getByUid(string $uid): CkeConfig throw new InvalidArgumentException("Invalid CKEditor config UUID: $uid"); } - $config = $this->_adjustConfig($config); + $config = $this->_adjustConfig($config, $forToolbarEditor); return new CkeConfig($config + ['uid' => $uid]); } @@ -70,6 +71,10 @@ public function save(CkeConfig $ckeConfig, bool $runValidation = true): bool 'options' => $ckeConfig->options, 'js' => $ckeConfig->js, 'css' => $ckeConfig->css, + 'entryTypes' => array_map( + fn(EntryType $entryType) => $entryType->getUsageConfig(), + $ckeConfig->getEntryTypes(), + ), ], fn($item) => $item !== null)); return true; @@ -91,7 +96,7 @@ private function _pcPath(string $uid): string * @param array $config * @return array */ - private function _adjustConfig(array $config): array + private function _adjustConfig(array $config, bool $forToolbarEditor = false): array { // rewrite anchor toolbar item to bookmark $key = array_search('anchor', $config['toolbar']); @@ -99,6 +104,20 @@ private function _adjustConfig(array $config): array $config['toolbar'][$key] = 'bookmark'; } + // rewrite createEntry into per-entry-type buttons + if (!$forToolbarEditor && in_array('createEntry', $config['toolbar'])) { + if (!empty($config['entryTypes'])) { + // ensure the dropdown option is after the individual buttons + $key = array_search('createEntry', $config['toolbar']); + unset($config['toolbar'][$key]); + // create toolbar items for individual entry types + foreach ($config['entryTypes'] as $entryType) { + $config['toolbar'][] = 'createEntry-' . $entryType['uid']; + } + $config['toolbar'][] = 'createEntry'; + } + } + return $config; } } diff --git a/src/Field.php b/src/Field.php index e8766d99..29df3872 100644 --- a/src/Field.php +++ b/src/Field.php @@ -53,7 +53,6 @@ use craft\htmlfield\HtmlFieldData; use craft\i18n\Locale; use craft\models\CategoryGroup; -use craft\models\EntryType; use craft\models\ImageTransform; use craft\models\Section; use craft\models\Volume; @@ -453,26 +452,6 @@ private static function adjustFieldValues( */ public bool $fullGraphqlData = true; - /** - * @var string|null The “New entry” button label. - * @since 4.0.0 - * @deprecated in 4.8.0 - */ - public ?string $createButtonLabel = null; - - /** - * @var bool Whether entry types with icons should be shown as separate buttons in the toolbar. - * @since 4.9.0 - */ - public bool $expandEntryButtons = false; - - /** - * @var EntryType[] The field’s available entry types - * @see getEntryTypes() - * @see setEntryTypes() - */ - private array $_entryTypes = []; - /** * @inheritdoc */ @@ -483,6 +462,9 @@ public function __construct($config = []) $config['removeInlineStyles'], $config['removeEmptyTags'], $config['removeNbsp'], + $config['createButtonLabel'], + $config['entryTypes'], + $config['expandEntryButtons'], ); if (isset($config['enableSourceEditingForNonAdmins'])) { @@ -501,10 +483,6 @@ public function __construct($config = []) unset($config['limitUnit'], $config['fieldLimit']); } - if (isset($config['entryTypes']) && $config['entryTypes'] === '') { - $config['entryTypes'] = []; - } - if (isset($config['graphqlMode'])) { $config['fullGraphqlData'] = ArrayHelper::remove($config, 'graphqlMode') === 'full'; } @@ -620,6 +598,7 @@ public function settingsAttributes(): array /** * @inheritdoc */ + public function getUriFormatForElement(NestedElementInterface $element): ?string { return null; @@ -756,37 +735,12 @@ public function getSettingsHtml(): ?string ]); } - /** - * Returns the available entry types. - * - * @return EntryType[] - */ - public function getEntryTypes(): array - { - return $this->_entryTypes; - } - - /** - * Sets the available entry types. - * - * @param array $entryTypes The entry types, or their IDs or UUIDs - */ - public function setEntryTypes(array $entryTypes): void - { - $entriesService = Craft::$app->getEntries(); - - $this->_entryTypes = array_values(array_filter(array_map( - fn($entryType) => $entriesService->getEntryType($entryType), - $entryTypes, - ))); - } - /** * @inheritdoc */ public function getFieldLayoutProviders(): array { - return $this->getEntryTypes(); + return $this->_ckeConfig()->getEntryTypes(); } /** @@ -801,11 +755,8 @@ public function getSettings(): array $settings['removeInlineStyles'], $settings['removeEmptyTags'], $settings['removeNbsp'], - ); - - $settings['entryTypes'] = array_map( - fn(EntryType $entryType) => $entryType->getUsageConfig(), - $this->getEntryTypes(), + $settings['entryTypes'], + $settings['createButtonLabel'], ); return $settings; @@ -1026,7 +977,8 @@ private function _inputHtml(mixed $value, ?ElementInterface $element, bool $stat $toolbar = array_merge($ckeConfig->toolbar); if (!$element?->id) { - ArrayHelper::removeValue($toolbar, 'createEntry'); + // remove all toolbar items that start with 'createEntry' + $toolbar = array_filter($toolbar, fn($item) => !str_starts_with($item, 'createEntry')); } if (!$this->isSourceEditingAllowed(Craft::$app->getUser()->getIdentity())) { @@ -1045,8 +997,7 @@ private function _inputHtml(mixed $value, ?ElementInterface $element, bool $stat 'elementSiteId' => $element?->siteId, 'accessibleFieldName' => $this->_accessibleFieldName($element), 'describedBy' => $this->_describedBy($view), - 'entryTypeOptions' => $this->_getEntryTypeOptions(), - 'expandEntryButtons' => $this->expandEntryButtons, + 'entryTypeOptions' => $ckeConfig->getEntryTypeOptions(), 'findAndReplace' => [ 'uiType' => 'dropdown', ], @@ -1478,26 +1429,6 @@ protected function searchKeywords(mixed $value, ElementInterface $element): stri return $keywords; } - /** - * Returns entry type options in form of an array with 'label' and 'value' keys for each option. - * - * @return array - */ - private function _getEntryTypeOptions(): array - { - $entryTypeOptions = array_map( - fn(EntryType $entryType) => [ - 'icon' => $entryType->icon ? Cp::iconSvg($entryType->icon) : null, - 'color' => $entryType->getColor()?->value, - 'label' => Craft::t('site', $entryType->name), - 'value' => $entryType->id, - ], - $this->getEntryTypes(), - ); - - return $entryTypeOptions; - } - /** * Normalizes
tags, ensuring they have an `image` or `media` class depending on their contents, * and they contain a
or tag, depending on the `mediaEmbed.previewsInData` @@ -1954,7 +1885,8 @@ private function _adjustPurifierConfig(HTMLPurifier_Config $purifierConfig): HTM $def?->addAttribute('ul', 'style', 'Text'); } - if (in_array('createEntry', $ckeConfig->toolbar)) { + $createEntryToolbarItems = array_filter($ckeConfig->toolbar, fn($item) => str_starts_with($item, 'createEntry')); + if (!empty($createEntryToolbarItems)) { $def?->addElement('craft-entry', 'Inline', 'Inline', '', [ 'data-entry-id' => 'Number', 'data-site-id' => 'Number', diff --git a/src/Plugin.php b/src/Plugin.php index 6bbce147..8a5906f6 100644 --- a/src/Plugin.php +++ b/src/Plugin.php @@ -56,7 +56,7 @@ public static function registerCkeditorPackage(string $name, string $entry = 'in private static array $ckeditorPackages = []; private static array $ckeditorImports = []; - public string $schemaVersion = '3.0.0.0'; + public string $schemaVersion = '5.0.0.0'; public bool $hasCpSettings = true; public bool $hasReadOnlyCpSettings = true; diff --git a/src/controllers/CkeConfigsController.php b/src/controllers/CkeConfigsController.php index bfc833fc..4212b25d 100644 --- a/src/controllers/CkeConfigsController.php +++ b/src/controllers/CkeConfigsController.php @@ -13,11 +13,14 @@ use craft\ckeditor\helpers\CkeditorConfigSchema; use craft\ckeditor\Plugin; use craft\ckeditor\web\assets\ckeconfig\CkeConfigAsset; +use craft\helpers\Cp; +use craft\helpers\Json; use craft\helpers\StringHelper; use craft\web\assets\admintable\AdminTableAsset; use craft\web\Controller; use craft\web\CpScreenResponseBehavior; use yii\base\InvalidArgumentException; +use yii\web\BadRequestHttpException; use yii\web\NotFoundHttpException; use yii\web\Response; @@ -55,7 +58,7 @@ public function actionEdit(?CkeConfig $ckeConfig = null, ?string $uid = null): R if (!$ckeConfig) { if ($uid !== null) { try { - $ckeConfig = Plugin::getInstance()->getCkeConfigs()->getByUid($uid); + $ckeConfig = Plugin::getInstance()->getCkeConfigs()->getByUid($uid, true); } catch (InvalidArgumentException $e) { throw new NotFoundHttpException($e->getMessage()); } @@ -101,6 +104,7 @@ public function actionEdit(?CkeConfig $ckeConfig = null, ?string $uid = null): R 'jsonSchema' => CkeditorConfigSchema::create(), 'jsonSchemaUri' => $jsonSchemaUri, 'advanceLinkOptions' => CkeditorConfig::advanceLinkOptions(), + 'entryTypes' => $ckeConfig->getEntryTypes(), ]); }); @@ -135,6 +139,7 @@ public function actionSave(): ?Response 'json' => $this->request->getBodyParam('json'), 'js' => $this->request->getBodyParam('js'), 'css' => $this->request->getBodyParam('css'), + 'entryTypes' => $this->request->getBodyParam('entryTypes'), ]); if (!Plugin::getInstance()->getCkeConfigs()->save($ckeConfig)) { @@ -159,4 +164,34 @@ public function actionDelete(): Response Plugin::getInstance()->getCkeConfigs()->delete($uid); return $this->asSuccess(Craft::t('ckeditor', 'CKEditor config deleted.')); } + + /** + * Applies an entry type indicators depending on config. + * + * @return Response + * @throws BadRequestHttpException + * @since 5.0.0 + */ + public function actionApplyEntryTypeIndicators(): Response + { + $config = $this->request->getRequiredBodyParam('config'); + + // get entry type by id + $entryType = CkeditorConfig::getCkeEntryType($config); + + $chip = Cp::chipHtml($entryType, [ + 'inputName' => 'entryTypes[]', + 'inputValue' => Json::encode($entryType->toArray(['id', 'name', 'handle', 'expanded', 'withColor', 'withIcon', 'withText'])), + 'checkbox' => false, + 'showActionMenu' => true, + 'showHandle' => true, + 'showIndicators' => true, + 'hyperlink' => true, + 'sortable' => true, + ]); + + return $this->asJson([ + 'chip' => $chip, + ]); + } } diff --git a/src/gql/Generator.php b/src/gql/Generator.php index bc27c549..ecca4a7d 100644 --- a/src/gql/Generator.php +++ b/src/gql/Generator.php @@ -50,7 +50,7 @@ public static function generateType(mixed $context): ObjectType $entryArgs = EntryArguments::getArguments(); $gqlService = Craft::$app->getGql(); - foreach ($context->getEntryTypes() as $entryType) { + foreach ($context->getFieldLayoutProviders() as $entryType) { $entryArgs += $gqlService->getFieldLayoutArguments($entryType->getFieldLayout()); } diff --git a/src/helpers/CkeditorConfig.php b/src/helpers/CkeditorConfig.php index 355fce03..d1b481ef 100644 --- a/src/helpers/CkeditorConfig.php +++ b/src/helpers/CkeditorConfig.php @@ -8,6 +8,7 @@ namespace craft\ckeditor\helpers; use Craft; +use craft\ckeditor\models\EntryType as CkeEntryType; use Illuminate\Support\Collection; /** @@ -412,4 +413,19 @@ public static function advanceLinkOptions(): array ], ]; } + + /** + * Get ckeditor's Entry Type based on provided config. + * + * @param array $config + * @return CkeEntryType + * @since 5.0.0 + */ + public static function getCkeEntryType(array $config): CkeEntryType + { + $craftEntryType = Craft::$app->getEntries()->getEntryType($config); + $properties = get_object_vars($craftEntryType) + $config; + + return new CkeEntryType($properties); + } } diff --git a/src/migrations/m250523_124328_v5_upgrade.php b/src/migrations/m250523_124328_v5_upgrade.php new file mode 100644 index 00000000..35b26ec2 --- /dev/null +++ b/src/migrations/m250523_124328_v5_upgrade.php @@ -0,0 +1,146 @@ +getFields()->getFieldsByType(Field::class)) + /** @phpstan-ignore-next-line */ + ->groupBy(fn(Field $field) => $field->ckeConfig); + + $projectConfig = Craft::$app->getProjectConfig(); + + /** @var Collection $fields **/ + foreach ($fieldsByConfig->all() as $ckeConfigUid => $fields) { + // if there's only one field that uses this config + if ($fields->count() == 1) { + $this->updateConfigs($ckeConfigUid, $fields[0]); + } else { + // key fields by field uid + $fields = $fields->keyBy('uid'); + $fieldEntryTypeConfigs = []; + foreach ($fields as $field) { + // compare entry types for each field + $pcFieldConfig = $projectConfig->get($projectConfig::PATH_FIELDS . '.' . $field->uid); + $fieldEntryTypeConfigs[$field->uid] = ProjectConfig::unpackAssociativeArrays($pcFieldConfig['settings']['entryTypes']); + $fieldEntryTypeConfigs[$field->uid]['expandEntryButtons'] = $pcFieldConfig['settings']['expandEntryButtons']; + } + // get the list of the unique entry types configs + $uniqueFieldEntryTypeConfigs = Collection::make($fieldEntryTypeConfigs) + ->uniqueStrict() + ->values(); + + // if all the fields share the same config + if ($uniqueFieldEntryTypeConfigs->count() == 1) { + // update that config and all the fields + foreach ($fields as $field) { + // todo: could/should we only update the cke config once and field config for each field, in this case + $this->updateConfigs($field->ckeConfig, $field); + } + } else { + // otherwise + foreach ($uniqueFieldEntryTypeConfigs as $key => $uniqueFieldEntryTypeConfig) { + // get all the fields that use each unique config + $fieldsForThisConfig = Arr::where( + $fieldEntryTypeConfigs, + fn($fieldEntryTypeConfig) => $fieldEntryTypeConfig === $uniqueFieldEntryTypeConfig + ); + + // get the CKE config by UID + $ckeConfig = Plugin::getInstance()->getCkeConfigs()->getByUid($ckeConfigUid); + + // if it's not the first group of fields, we need to duplicate the config + if ($key > 0) { + // duplicate cke config + $duplicatedCkeConfig = clone $ckeConfig; + $duplicatedCkeConfig->uid = StringHelper::UUID(); + $duplicatedCkeConfig->name .= ' ' . ($key + 1); + Plugin::getInstance()->getCkeConfigs()->save($duplicatedCkeConfig); + } else { + $duplicatedCkeConfig = $ckeConfig; + } + + // update the configs for each field + foreach ($fieldsForThisConfig as $fieldUid => $config) { + /** @var Field $field */ + $field = $fields[$fieldUid]; + $this->updateConfigs($duplicatedCkeConfig->uid, $field); + + // if it's not the first group of fields, update each field with the duplicated CKE config uid + if ($key > 0) { + // update the field to use the new duplicate + $field->ckeConfig = $duplicatedCkeConfig->uid; + Craft::$app->getFields()->saveField($field); + } + } + } + } + } + } + + return true; + } + + /** + * @inheritdoc + */ + public function safeDown(): bool + { + echo "m250523_124328_v5_upgrade cannot be reverted.\n"; + return false; + } + + private function updateConfigs(string $ckeConfigUid, Field $field): void + { + $projectConfig = Craft::$app->getProjectConfig(); + + // move the entry types from field to the config + $pcCkeConfig = $projectConfig->get(CkeConfigs::PROJECT_CONFIG_PATH . '.' . $ckeConfigUid); + $pcFieldConfig = $projectConfig->get($projectConfig::PATH_FIELDS . '.' . $field->uid); + + if (isset($pcFieldConfig['settings']['entryTypes'])) { + $entryTypesConfig = ProjectConfig::unpackAssociativeArrays($pcFieldConfig['settings']['entryTypes']); + $pcCkeConfig['entryTypes'] = $entryTypesConfig; + unset($pcFieldConfig['settings']['entryTypes']); + + if ($pcFieldConfig['settings']['expandEntryButtons']) { + foreach ($entryTypesConfig as $key => $item) { + try { + $entryType = Craft::$app->getEntries()->getEntryType($item['uid']); + if ($entryType->getIcon() !== null) { + // mark as expanded + $entryTypesConfig[$key]['expanded'] = true; + } + // otherwise, the default expanded => false will be used + } catch (\Throwable $e) { + // if something went wrong, the default expanded => false will be used + } + } + $pcCkeConfig['entryTypes'] = $entryTypesConfig; + } + unset($pcFieldConfig['settings']['expandEntryButtons']); + + $projectConfig->set(sprintf('%s.%s', CkeConfigs::PROJECT_CONFIG_PATH, $ckeConfigUid), $pcCkeConfig); + $projectConfig->set(sprintf('%s.%s', $projectConfig::PATH_FIELDS, $field->uid), $pcFieldConfig); + } + } +} diff --git a/src/models/EntryType.php b/src/models/EntryType.php new file mode 100644 index 00000000..343f6845 --- /dev/null +++ b/src/models/EntryType.php @@ -0,0 +1,94 @@ + + * @since 5.0.0 + */ +class EntryType extends CraftEntryType +{ + public bool $withColor = true; + public bool $withIcon = true; + public bool $withText = true; + public bool $expanded = false; + + + /** + * @inheritdoc + */ + public function getIndicators(): array + { + $indicators = parent::getIndicators(); + + $indicators[] = [ + 'label' => $this->expanded ? Craft::t('ckeditor', 'Show as a separate button') : Craft::t('ckeditor', 'Show in a dropdown'), + 'icon' => $this->expanded ? 'eye' : 'eye-slash', + 'iconColor' => $this->expanded ? 'teal' : 'gray', + ]; + + if ($this->withColor) { + $indicators[] = [ + 'label' => Craft::t('ckeditor', 'Show with color'), + 'icon' => 'brush', + 'iconColor' => 'teal', + ]; + } + + if ($this->withIcon) { + $indicators[] = [ + 'label' => Craft::t('ckeditor', 'Show with icon'), + 'icon' => 'image', + 'iconColor' => 'teal', + ]; + } + + if ($this->withText) { + $indicators[] = [ + 'label' => Craft::t('ckeditor', 'Show with text'), + 'icon' => 't', + 'iconColor' => 'teal', + ]; + } + + return $indicators; + } + + /** + * @inheritdoc + */ + public function getUsageConfig(): array + { + $config = parent::getUsageConfig(); + + if (isset($this->expanded)) { + $config['expanded'] = $this->expanded; + } + + if (isset($this->withColor)) { + $config['withColor'] = $this->withColor; + } + + if (isset($this->withIcon)) { + $config['withIcon'] = $this->withIcon; + } + + if (isset($this->withText)) { + $config['withText'] = $this->withText; + } + + return $config; + } +} diff --git a/src/templates/_field-settings.twig b/src/templates/_field-settings.twig index 838aeae4..dfcfd3d6 100644 --- a/src/templates/_field-settings.twig +++ b/src/templates/_field-settings.twig @@ -70,31 +70,6 @@
-{% set headlessMode = craft.app.config.general.headlessMode %} -{% set entryTypes = entryTypeRows ?? [] %} - -{{ forms.entryTypeSelectField({ - label: 'Entry Types'|t('app'), - instructions: 'Choose the types of entries that can be created in this field.'|t('app'), - id: 'entry-types', - name: 'entryTypes[]', - values: field.getEntryTypes(), - allowOverrides: true, - create: true, - errors: field.getErrors('entryTypes'), - data: {'error-key': 'entryTypes'}, -}) }} - -{{ forms.lightswitchField({ - id: 'expand-entry-buttons', - name: 'expandEntryButtons', - label: 'Show toolbar buttons for entry types with icons'|t('ckeditor'), - instructions: 'Whether entry types with icons should be shown as separate buttons in the toolbar.' |t('ckeditor'), - on: field.expandEntryButtons, -}) }} - -
- {{ 'Assets'|t('app') }}