View source
<?php
namespace Drupal\autosave_form\Form;
use Drupal\Core\Ajax\AjaxResponse;
use Drupal\Core\Ajax\InvokeCommand;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\StringTranslation\StringTranslationTrait;
trait AutosaveFormAlterTrait {
use StringTranslationTrait;
use AutosaveButtonClickedTrait;
public function formAlter(array &$form, FormStateInterface $form_state) {
if (!$this
->isAutosaveEnabled($form_state)) {
return;
}
$form['#attributes']['class'][] = 'autosave-form';
$form['#attached']['library'][] = 'autosave_form/drupal.autosave_form';
$form['#attached']['drupalSettings']['autosaveForm']['interval'] = $this->configFactory
->get('autosave_form.settings')
->get('interval');
$form['#attached']['drupalSettings']['autosaveForm']['onlyOnFormChange'] = $this->configFactory
->get('autosave_form.settings')
->get('only_on_form_change');
$form['#attached']['drupalSettings']['autosaveForm']['notification'] = $this->configFactory
->get('autosave_form.settings')
->get('notification');
$input = $form_state
->getUserInput();
$show_restore_discard = !$form_state
->isRebuilding() ?: !empty($input['autosave_restore_discard']);
if ($show_restore_discard && !$form_state
->get('autosave_form_state_timestamp') && !$form_state
->get('autosave_form_rejected') && ($autosave_form_state_timestamp = $this
->getLastAutosavedTimestamp($form_state, $this->currentUser
->id()))) {
$form[AutosaveFormInterface::AUTOSAVE_RESTORE_ELEMENT_NAME] = [
'#type' => 'submit',
'#name' => AutosaveFormInterface::AUTOSAVE_RESTORE_ELEMENT_NAME,
'#value' => $this
->t('Autosave restore'),
'#limit_validation_errors' => [],
'#attributes' => [
'class' => [
'autosave-form-restore',
'visually-hidden',
],
],
'#submit' => [
[
$this,
'autosaveFormRestoreSubmit',
],
],
'#autosave_form_state_timestamp' => $autosave_form_state_timestamp,
];
$form[AutosaveFormInterface::AUTOSAVE_REJECT_ELEMENT_NAME] = [
'#type' => 'submit',
'#name' => 'autosave_form_reject',
'#value' => $this
->t('Autosave reject'),
'#limit_validation_errors' => [],
'#attributes' => [
'class' => [
'autosave-form-reject',
'visually-hidden',
],
],
'#submit' => [
[
$this,
'autosaveFormRejectSubmit',
],
],
'#ajax' => [
'callback' => [
$this,
'autosaveFormRejectAjax',
],
],
];
$form['autosave_restore_discard'] = [
'#type' => 'hidden',
'#default_value' => 'autosave_restore_discard',
'#attributes' => [
'class' => [
'autosave-form-restore-discard',
],
],
];
$date = $this->dateFormatter
->format($autosave_form_state_timestamp, 'custom', 'M d, Y H:i');
$message = $this
->t('A version of this page you were editing at @date was saved as a draft. Do you want to resume editing or discard it?', [
'@date' => $date,
]);
$form['#attached']['drupalSettings']['autosaveForm']['message'] = (string) $message;
}
$autosave_form_session_id = $this
->getAutosaveFormSessionID($form_state);
if (!$autosave_form_session_id) {
$autosave_form_session_id = !empty($input['autosave_form_session_id']) ? $input['autosave_form_session_id'] : $form['#build_id'];
$this
->setAutosaveFormSessionID($form_state, $autosave_form_session_id);
}
$form['autosave_form_session_id'] = [
'#type' => 'hidden',
'#value' => $autosave_form_session_id,
'#name' => 'autosave_form_session_id',
'#parents' => [
'autosave_form_session_id',
],
];
$form[AutosaveFormInterface::AUTOSAVE_ELEMENT_NAME] = [
'#type' => 'submit',
'#name' => AutosaveFormInterface::AUTOSAVE_ELEMENT_NAME,
'#value' => $this
->t('Autosave save'),
'#attributes' => [
'class' => [
'autosave-form-save',
'visually-hidden',
],
],
'#submit' => [
[
$this,
'autosaveFormSubmit',
],
],
'#ajax' => [
'callback' => [
$this,
'autosaveFormAjax',
],
'disable-refocus' => TRUE,
'progress' => FALSE,
],
'#autosave_form' => TRUE,
'#autosave_form_session_id' => $autosave_form_session_id,
];
$form['autosave_form_last_autosave_timestamp'] = [
'#type' => 'hidden',
'#name' => 'autosave_form_last_autosave_timestamp',
'#value' => $form_state
->get('autosave_form_last_autosave_timestamp') ?: '',
];
}
public function autosaveFormRestoreSubmit($form, FormStateInterface $form_state) {
$triggering_element = $form_state
->getTriggeringElement();
if (!empty($triggering_element['#autosave_form_state_timestamp'])) {
$form_state
->set('autosave_form_state_timestamp', $triggering_element['#autosave_form_state_timestamp']);
$form_state
->setRebuild();
}
}
public function autosaveFormRejectSubmit($form, FormStateInterface $form_state) {
ignore_user_abort(TRUE);
$form_state
->set('autosave_form_rejected', TRUE);
$form_state
->setCached();
$this
->purgeAllAutosavedStates($form_state, $this->currentUser
->id());
}
public function autosaveFormRejectAjax($form, FormStateInterface $form_state) {
return new AjaxResponse();
}
public function autosaveFormSubmit($form, FormStateInterface $form_state) {
ignore_user_abort(TRUE);
if (!$this
->isAutosaveSubmitValid($form_state)) {
$form_state
->disableCache();
return;
}
$autosave_form_session_id = $this
->getAutosaveFormSessionID($form_state);
$current_user_id = $this->currentUser
->id();
$autosaved_form_state = $this
->getLastAutosavedFormState($form_state, $autosave_form_session_id, $current_user_id);
if (is_null($autosaved_form_state)) {
if ($initial_user_input = $this->keyValueExpirableFactory
->get('autosave_form')
->get($autosave_form_session_id)) {
$autosaved_form_state_input = $initial_user_input;
}
else {
$expire = 21600;
$this->keyValueExpirableFactory
->get('autosave_form')
->setWithExpire($autosave_form_session_id, $form_state
->getUserInput(), $expire);
$form_state
->disableCache();
return;
}
}
else {
$autosaved_form_state_input = $autosaved_form_state
->getUserInput();
}
$form_state_input = $form_state
->getUserInput();
$skip_from_comparison_keys = [
'form_build_id',
'form_token',
'ajax_page_state',
'autosave_form_last_autosave_timestamp',
AutosaveFormInterface::AUTOSAVE_RESTORE_ELEMENT_NAME,
AutosaveFormInterface::AUTOSAVE_REJECT_ELEMENT_NAME,
'autosave_restore_discard',
];
foreach ($skip_from_comparison_keys as $skip_from_comparison_key) {
unset($autosaved_form_state_input[$skip_from_comparison_key]);
unset($form_state_input[$skip_from_comparison_key]);
}
$store = $autosaved_form_state_input != $form_state_input;
if ($store) {
$autosave_timestamp = $this->time
->getRequestTime();
$form_state
->set('autosave_form_last_autosave_timestamp', $autosave_timestamp);
$form_state
->setTemporaryValue('autosave_form_last_autosave_timestamp', $autosave_timestamp);
$this
->storeState($form_state, $autosave_form_session_id, $autosave_timestamp, $current_user_id);
$this->keyValueExpirableFactory
->get('autosave_form')
->delete($autosave_form_session_id);
}
$form_state
->disableCache();
}
public function autosaveFormAjax($form, FormStateInterface $form_state) {
$response = new AjaxResponse();
$timestamp = $form_state
->getTemporaryValue('autosave_form_last_autosave_timestamp');
if (is_numeric($timestamp)) {
$response
->addCommand(new InvokeCommand('input[name="autosave_form_last_autosave_timestamp"]', 'attr', [
'value',
$timestamp,
]));
}
return $response;
}
protected static function getAutosaveFormSessionID(FormStateInterface $form_state) {
return $form_state
->get('autosave_form_session_id');
}
protected function setAutosaveFormSessionID(FormStateInterface $form_state, $autosave_form_session_id) {
$form_state
->set('autosave_form_session_id', $autosave_form_session_id);
}
protected function getRequestMethod() {
return \Drupal::requestStack()
->getCurrentRequest()
->getMethod();
}
}