templates = \Drupal::moduleHandler() ->invokeAll('layouter_templates_info'); } /** * {@inheritdoc} */ public function getFormId() { return 'layouter_multistep_form'; } /** * {@inheritdoc} */ public function buildForm(array $form, FormStateInterface $form_state, $textarea_id = NULL) { $step = $form_state->get('step'); if (!$step) { $step = 1; $form_state->set('step', $step); } $form['#prefix'] = '
'; $form['#sufix'] = '
'; $form['errors'] = []; $button_label = ''; if ($step == 1) { $options = []; foreach ($this->templates as $id => $params) { $options[$id] = $params['title']->render(); } $form['data']['type'] = [ '#title' => $this->t('Choose the layout'), '#type' => 'radios', '#options' => $options, '#required' => TRUE, '#after_build' => ['::processLayoutTypeRadios'], ]; $button_label = $this->t('Next'); } if ($step == 2) { $this->buildLayouterFields($form, $form_state); $button_label = $this->t('Submit'); } $form['actions']['submit'] = [ '#type' => 'submit', '#value' => $button_label, '#name' => 'submit_button', '#attributes' => [ 'class' => ['use-ajax-submit'], ], '#ajax' => [ 'callback' => '::ajaxResponse', ], ]; $form['actions']['cancel'] = [ '#type' => 'submit', '#value' => $this->t('Cancel'), '#name' => 'cancel_button', '#submit' => ['::cancelForm'], '#limit_validation_errors' => [], '#attributes' => [ 'class' => ['use-ajax-submit'], ], ]; return $form; } /** * {@inheritdoc} */ public function submitForm(array &$form, FormStateInterface $form_state) { $step = $form_state->get('step'); if ($step < $this->steps) { $form_state->setRebuild(); if ($step == 1) { $form_state->set('type', $form_state->getValue('type')); } } $step++; $form_state->set('step', $step); } /** * Ajax callback prints rebuilded form. * * @param array $form * @param \Drupal\Core\Form\FormStateInterface $form_state * * @return \Drupal\Core\Ajax\AjaxResponse */ public function ajaxResponse(array &$form, FormStateInterface $form_state) { if ($form_state->hasAnyErrors()) { $form['errors']['#prefix'] = '
'; $form['errors']['#suffix'] = '
'; $form['errors']['#markup'] = ''; $mess = drupal_get_messages('error'); foreach ($mess as $errors) { foreach ($errors as $error) { $form['errors']['#markup'] .= $error . '
'; } } $form_state->clearErrors(); } $step = $form_state->get('step'); $response = new AjaxResponse(); if ($step == $this->steps + 1 && $form_state->isExecuted()) { $textarea_id = $form_state->getBuildInfo()['args'][0]; $content = $this->buildResponseHtml($form_state); $command = new CloseModalDialogCommand(); $response->addCommand($command); $command = new InvokeCommand( NULL, 'layouterAddContent', [$textarea_id, $content] ); $response->addCommand($command); } else { $command = new ReplaceCommand('#layouter-form-wrapper', $form); $response->addCommand($command); } return $response; } /** * Form submit handler triggered by 'cancel' button. Closes popup form. * * @param array $form * @param \Drupal\Core\Form\FormStateInterface $form_state */ public function cancelForm(array &$form, FormStateInterface $form_state) { // Delete loaded files. if ($form_state->hasFileElement()) { foreach ($form_state->get('fields') as $name => $params) { if ($params['type'] == 'image') { $input = $form_state->getUserInput(); if (!empty($input[$name]['fids'])) { File::load($input[$name]['fids'])->delete(); } } } } $response = new AjaxResponse(); $response->addCommand(new CloseModalDialogCommand()); $form_state->setResponse($response); } /** * Wraps each radio button item in the 'radios' set into additional container. * After-build callback. * * @param array * $element - form element. * * @return array */ public function processLayoutTypeRadios($element) { foreach ($this->templates as $id => $params) { if (!empty($element[$id])) { $element[$id]['#prefix'] = '
'; $element[$id]['#suffix'] = '
'; } } return $element; } /** * Returns the 'textarea' form item. * * @param string $name * Field name. * @param array $params * Additional parameters for field from layouter template. * * @return array * Renderable array for textfield. */ private function textContentHandler($name, array $params) { $result[$name] = [ '#type' => 'textarea', '#title' => $params['title'], '#description' => $params['description'], '#rows' => 10, '#required' => 1, ]; return $result; } /** * Returns the form item with actual settings, to upload image. * * @param string $name * Field name. * @param array $params * Additional parameters for field from layouter template. * * @return array * Renderable array for file field. */ private function imageContentHandler($name, array $params) { $fieldset_name = 'image_' . $name; // Fieldset for image fields. $result['#type'] = 'fieldset'; $result['#title'] = $params['title']; // Prepare managed_file field. $allowed_extensions = ['png gif jpeg jpg']; $max_upload_size_mb = (int) ini_get('upload_max_filesize'); $max_upload_size = [$max_upload_size_mb * 1024 * 1024]; $image_field_description = $this->t( 'Files must be less than @size.', ['@size' => format_size($max_upload_size[0])] ); $image_field_description .= '
' . $this->t( 'Allowed file types: @extensions.', ['@extensions' => $allowed_extensions[0]] ); if (!empty($params['description'])) { $image_field_description .= '
' . $params['description']; } $location_scheme = \Drupal::config('layouter.settings')->get('uri_scheme'); // Add managed_file field and textfield for image alternative text. $result[$name] = [ '#type' => 'managed_file', '#title' => $this->t('Image'), '#field_name' => 'layouter_image', '#description' => $image_field_description, '#required' => 1, '#upload_location' => $location_scheme . '://layouter_images', '#upload_validators' => [ 'file_validate_extensions' => $allowed_extensions, 'file_validate_size' => [$max_upload_size], ], ]; $result[$name . '_alt'] = [ '#type' => 'textfield', '#title' => $this->t('Alternative text'), ]; // Prepare list field with allowed image styles. if (\Drupal::currentUser()->hasPermission('administer image styles')) { $url = Url::fromRoute('entity.image_style.collection')->getInternalPath(); $description = $this->t('You can also') . ' ' . $this->t('add your own image style') . ' ' . $this->t('if you need to.'); $admin_image_style_description = $description; } else { $admin_image_style_description = ''; } $image_styles = \Drupal::config('layouter.settings')->get('image_styles'); $image_styles_options['none'] = 'none'; foreach ($image_styles as $k => $v) { if ($v != '0') { $image_styles_options[$k] = $v; } } // Add image style field to result. $result[$name . '_style'] = [ '#type' => 'select', '#title' => $this->t('Image style'), '#required' => TRUE, '#options' => $image_styles_options, '#description' => $admin_image_style_description, ]; $fieldset[$fieldset_name] = $result; return $fieldset; } /** * Builds HTML that will be added to textarea. * * @param \Drupal\Core\Form\FormStateInterface $form_state * @return null * Content for output. */ private function buildResponseHtml(FormStateInterface $form_state) { $content = [ '#theme' => $this->templates[$form_state->get('type')]['theme'], ]; $fields = $form_state->get('fields'); foreach ($fields as $field_name => $fiels_params) { switch ($fiels_params['type']) { case 'image': $image_fid = $form_state->getValue($field_name)[0]; $image = File::load($image_fid); /** @var FileInterface $image */ $image->setPermanent(); $image_style = $form_state->getValue($field_name . '_style'); if ($image_style == 'none') { $image_content = [ '#theme' => 'image', ]; } else { $image_content = [ '#theme' => 'image_style', '#style_name' => $image_style, ]; } $image_content['#uri'] = $image->getFileUri(); $image_content['#alt'] = $form_state->getValue($field_name . '_alt'); $content['#' . $field_name] = render($image_content); break; case 'text': $content['#' . $field_name] = $form_state->getValue($field_name); break; } } return render($content); } /** * Sets up and builds fields from selected layouter template. * * @param array $form * @param \Drupal\Core\Form\FormStateInterface $form_state */ private function buildLayouterFields(array &$form, FormStateInterface $form_state) { $type = $form_state->get('type'); $fields = $this->templates[$type]['fields']; if (!is_null($fields)) { $form_state->set('fields', $fields); $form['data'] = []; foreach ($fields as $name => $params) { $params['description'] = ($params['description']) ?: ''; if ($params['type'] == 'image') { $params['title'] = ($params['title']) ?: $this->t('Image settings'); $form['data'] += $this->imageContentHandler($name, $params); } if ($params['type'] == 'text') { $params['title'] = ($params['title']) ?: $this->t('Text'); $form['data'] += $this->textContentHandler($name, $params); } } } } }