BDemetrix / BDemetrix.github.io

3 stars 2 forks source link

Доработка плагина Tooltips #81

Open BDemetrix opened 2 months ago

BDemetrix commented 2 months ago

Есть ТЗ, требуется максимально его закрыть и дать объяснения с примерами

Доработки по тултипам от Владимира:

  1. Тултипы разметываются лево-право-центр-верх-низ - это здорово, но давай показывать тултип где-то около курсора (как системный), если не указано иного (в противном случае они могут выпадать в неожиданных для пользователя местах).

Kомментарий @BDemetrix : это логично сделать если таргет намного больше чем тултип

Реализация:

   new Tooltips({
      attachCursorXPos: 1.1,  // по умолчанию 1.3
      attachCursorYPos: true; // по умолчанию false
   })
   // если ширина таргета больше тултипа в attachCursorXPos раз, 
   // то позиция тултипа привязывается к позиции курсора по горизонтали
   this.attachCursorXPos = options.attachCursorXPos ?? 1.3; 
  1. Открытие и закрытие случается мгновенно, как только случается триггер - это не очень хорошо. Пример: 100 ссылок с аяксом, проведя просто по которым быстро мышкой мы дергаем 100 аяксов.... Надо сделать, чтобы для mouseenter\mouseleave триггер срабатывал через какой-то интервал типа 500мс, чтобы случайно пролетая над ссылкой мы не вызывали калбек и не показывали тултипы.

Kомментарий @BDemetrix: сделал timeout = 500 (мс) в конструкторе по умолчанию, настраивается

Реализация

   new Tooltips({
      timeout: 1000,  // по умолчанию 500
   })

   // в конструкторе
   this.timeout = options.timeout ?? 500;  
  1. Проблема наведения на тултип: При создании поповера на него нельзя навести\кликнуть в него и т.п. т.к. он сразу закрывается если открыт через mouseenter. Триггер срабатывает сразу как чел свел мышку с объекта. Надо сделать задержку для mouseleave с объекта и добавить задержку сведения с поповера. Т.е. сценарий - чел навел на ссылку - появился поповер, загрузил данные асинхронно и показал. Чел или убрал мышку или навел на поповер, там что-то покликал. Если он сводит мышку с поповера, то тот через какую-то задержку пропадает, если был открыт через mouseenter. Типичный кейс - https://smart-lab.ru/books/ - ссылки на книги.

Реализация

 window.tooltips = new Tooltips({
    attach: '.smart-tooltip-popover',
    popover: true,
    // attachCursorYPos: true,
    setContent:  '<div style="padding: 32px;"><button class="demo-btn js-tooltip-close-btn">Закрыть</button></div>',
    width: 'auto',
});
  1. Триггер клик в мобильных. ХЗ, но я бы сделал это в отдельной опции, т.к. иногда не надо открывать поповер, а просто надо перейти по ссылке. Ну т.е. оно определяет мобильное или нет, но не всегда ставит триггер аля клик, а срабатывает по нему если в опциях есть какой-то флажок.

Kомментарий @BDemetrix: нужно убрать тултип со ссылки и добввить на какую-тибудь иконку со знаком вопроса, иначе не реализовать, так как невозможно угадать пользователь по ссылке кликнул чтобы открыть или подсказку посмотреть

Реализация:

    new Tooltips({
    mobileAttach: 'none',             // На мобильных не будет открываться
    // mobileAttach: '.app-box__img',  // На мобильных будет открываться этот селектор, а не attach
    });
    // если тачскрин выходим или переопределяем this.attach  
    if (this.mobileAttach === 'none' && this.isTouch) {
      console.info(`Тултипы для селектора ${this.attach} на тачскринах отключены опцией {mobileAttach: 'none'}`);
      return;
    }
    else if(this.mobileAttach && this.isTouch) {
      this.attach = this.mobileAttach;
    }
  1. Функция, позволяющая как-то проверить че происходит и разрешить или запретить дальнейшее открытие тултипа. Типичный сценарий - есть документ, в нем куча ссылок /books/... и вот внутри там есть и ссылки на книги и ссылки на сервисные урлы и еще куча всякого говна. К сожалению селекторы не понимают регулярные выражения и как-то отфильтровать этот зоопарк в данном раскладе не удастся. Можно было бы какой-нить калбек перед открытием, который получал бы target и возвращал бы true например. Если калбека нет - всегда true.

Пример:

new Tooltips({
    // this этого колбека несет в себе родительский объект Tooltips(),
    beforeOpen: beforeOpen,
});

// колбек перед открытием 
async function beforeOpen(target, e) {
    console.info('The beforeOpen() has started');
    console.log(target);
    console.log(e);
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve(true);
            console.log(this);
            console.info('The beforeOpen() has ended');
        }, 2000);
    });
}
  1. Пару калбеков, чтобы повесить хендлеры после открытия и установки контента и снятия их перед закрытием. Например onOpen \ onClose с передачей туда ноды и параметов. Если не указано - пропускаем.

Пример:

new Tooltips({
    // this этого колбека несет в себе родительский объект Tooltips(),
    onOpen: function (target, e){ console.log(target); },
    onClose: function (){ console.log(this); },
});
  1. Какой-то способ закрытия тултипа из кода хендлера. Ну чтобы я мог сделать тормозную кнопку - чел нажал, я ему написал "выполняю..." вся эта конструкция подумала и потом закрылась, например. Можно например в onOpen \ onClose объект передавать или еще как. Или событие какое-нить родить, чтобы я его кидал в ноду или еще как-нибудь.

Реализация:

    // закрывает тултип при клике на кнопку
    this.el.addEventListener('click', e => {
      console.log(this)
      if (e.target.closest('.js-tooltip-close-btn')) this.close();
    })

Пример:

new Tooltips({
    openTrigger: 'click',
    setContent: () => '<div style="padding: 32px;"><button class="demo-btn js-tooltip-close-btn">Закрыть</button></div>',
});

// или

new Tooltips({
    openTrigger: 'click',
    setContent:  '<div style="padding: 32px;"><button class="demo-btn js-tooltip-close-btn">Закрыть</button></div>',
});
BDemetrix commented 2 months ago

Добавил опции:

new Tooltips({
    openTrigger: 'click',
    setContentOnce: true,   // флаг единоразовой загрузки контента из колбека если объект наведения/клика не изменился,  по умолчанию false,, работает только если в setContent передана функция
    holdUntilDone: true,    // флаг блокировки закрытия тултипа при асинхронной загрузке контента, по умолчанию false, работает только если в setContent передана функция
    setContent: async function (){},
});

Пример всех колбеков:

new Tooltips(
{
  attach:'#all-callbacks',
  onOpen: function()
  {
    console.log('open', this);
  },
  onClose: function()
  {
   console.log('close', this);
  },
  beforeOpen: function()
  {
    return new Promise((resolve, reject) => {
      setTimeout(() => {
        x = Math.random();
        console.log(x);
        x < 0.33 ? resolve(false) 
                : x < 0.66 ? resolve(true) 
                        : reject({error: 'Текст ошибки!'}) ; // просто проброс ошибки

      }, 1000);
    });
  }

});