Drupal → Восстанавливаем позицию текстового курсора при ajax обновлении формы

08.02.2023

У ajax-форм в друпале есть бесючая особенность — если повесить ajax на текстовое поле, то при обновлении формы не сохранится позиция текстового курсора в этом поле. Например пользователь что-то набирает в textfield, срабатывает ajax, обновляется формы и текстовый курсор прыгает в начало поля. Issue весит с 2019 года, но никто даже не притронулся.

Фиксим самостоятельно:

(function ($, Drupal) {

  /**
   * Override AJAX "beforeSend" callback.
   */
  var originalAjaxBeforeSend = Drupal.Ajax.prototype.beforeSend;
  Drupal.Ajax.prototype.beforeSend = function (xmlhttprequest, options) {
    // Save text caret position
    if ('selectionStart' in this.element && this.element.selectionStart) {
      var $element = $(this.element);
      $element.data('selection-start', this.element.selectionStart);
      $element.data('selection-end', this.element.selectionEnd);
    }
    
    // Call original callback
    return originalAjaxBeforeSend.apply(this, arguments);
  };

  /**
   * Override AJAX "success" callback.
   */
  var originalAjaxSuccess = Drupal.Ajax.prototype.success;
  Drupal.Ajax.prototype.success = function (response, status) {
    // Call original callback
    var originalAjaxSuccessPromise = originalAjaxSuccess.apply(this, arguments);

    // Restore text caret position
    var $element = $(this.element);
    var elementSavedSelectionStart = $element.data('selection-start');
    var elementSavedSelectionEnd = $element.data('selection-end');
    if (elementSavedSelectionStart) {
      originalAjaxSuccessPromise.then(function () {
        var $newElement = $('[data-drupal-selector="' + $element.data('drupal-selector') + '"]');
        if ($newElement.length && 'setSelectionRange' in $newElement[0]) {
          $newElement[0].setSelectionRange(elementSavedSelectionStart, elementSavedSelectionEnd);
        }
      });
    }
    
    return originalAjaxSuccessPromise;
  };

})(jQuery, Drupal);

Подключать js файл так:

/**
 * Implements hook_library_info_alter().
 */
function MODULENAME_library_info_alter(array &$libraries, string $extension): void {
  if ($extension == 'core') {
    $module_path = '/' . \Drupal::service('extension.path.resolver')->getPath('module', 'MODULENAME');
    $libraries['drupal.ajax']['js'][$module_path . '/js/ajax-restore-text-caret.js'] = [];
  }
}
Написанное актуально для
Drupal 8+
Похожие записи

Добавить комментарий