Адаптируем статью под время суток

Есть такое медиа — «Кин­жал», кото­рое рас­ска­зы­ва­ет про полез­ные навы­ки и под­хо­ды к жиз­ни. Так сло­жи­лось, что наш главред Мак­сим так­же рабо­та­ет и там. Он при­ду­мал такую муль­ку: что­бы ста­тьи «Кин­жа­ла» напо­ми­на­ли всем, кто чита­ет их после 10 вече­ра, что пора лечь спать. А если на ули­це уже утро, то и напо­ми­нать не нужно. 

Это мы и сделаем. 

Логика проекта

В кон­це каж­дой ста­тьи «Кин­жа­ла» есть плаш­ка с заклю­чи­тель­ной мыс­лью, в кон­це кото­рой сто­ит кар­тин­ка кинжала:

Адаптируем статью под время суток

Нам нуж­но, что­бы с 10 вече­ра и до 5 утра в каж­дую такую плаш­ку перед кин­жа­лом добав­ля­лась фра­за «А теперь ложи­тесь спать». Для это­го сде­ла­ем так:

  1. Ждём, пока загру­зит­ся вся страница
  2. Нахо­дим в струк­ту­ре HTML-документа эту плаш­ку и полу­ча­ем её содержимое.
  3. Смот­рим на теку­щее вре­мя у пользователя.
  4. Если оно попа­да­ет в нуж­ный нам диа­па­зон — выпол­ня­ем всё, что ниже, а если не попа­да­ет — ниче­го не делаем.
  5. Если на плаш­ке есть кар­тин­ка кин­жа­ла — добав­ля­ем текст перед ней.
  6. Если кар­тин­ки кин­жа­ла нет — добав­ля­ем текст в самый конец плашки.

Готовим каркас

Что­бы код ждал, когда загру­зит­ся вся стра­ни­ца, и толь­ко потом начи­нал рабо­тать, нам пона­до­бит­ся обра­бот­чик собы­тия пол­ной загруз­ки. Это зна­чит, что когда содер­жи­мое стра­ни­цы загру­зит­ся у поль­зо­ва­те­ля, сра­бо­та­ет собы­тие пол­ной загруз­ки и мож­но выпол­нять код скрипта. 

За это в JavaScript отве­ча­ет обра­бот­чик addEventListener с пара­мет­ром
"DOMContentLoaded":

// ждём, пока страница полностью загрузится, потом алгоритм начинает работать
document.addEventListener("DOMContentLoaded", () => {
  // получаем текущую дату и время пользователя
  const now = new Date();
});

Всё осталь­ное мы будем писать тоже внут­ри это­го обработчика.

Находим финальную плашку

Что­бы не тащить в про­ект jQuery ради одно­го запро­са, реа­ли­зу­ем поиск нуж­но­го объ­ек­та род­ны­ми сред­ства­ми JavaScript:

// находим в документе среди всех разделов, которые относятся к статье, финальную плашку
const finalTexts = document
  .querySelector(".article-content")
  .querySelectorAll(".final");
// находим нужную и единственную плашку, с которой будем работать
const lastFinalText = finalTexts[finalTexts.length - 1];

Теперь пояс­ним код.

Мы зна­ем от ребят из «Кин­жа­ла», что у них на стра­ни­це есть один раз­дел с клас­сом ".article-content", внут­ри кото­ро­го лежит плаш­ка с клас­сом ".final". Мы мог­ли бы про­сто най­ти эле­мент с клас­сом ".final" и рабо­тать с ним, но мы хотим пере­стра­хо­вать­ся: вдруг их на стра­ни­це будет несколь­ко. Для это­го мы сна­ча­ла нахо­дим раз­дел со ста­тьёй и уже внут­ри неё нахо­дим нуж­ную плашку.

Послед­ней строч­кой мы полу­ча­ем сам объ­ект с плаш­кой, пото­му что коман­да поис­ка .querySelectorAll (".final") выдаст нам мас­сив из объ­ек­тов, а не кон­крет­ную плаш­ку. Что­бы полу­чить имен­но плаш­ку как один объ­ект, мы берём пер­вый эле­мент мас­си­ва. А так как нуме­ра­ция начи­на­ет­ся с нуля, мы берём раз­мер мас­си­ва (там один эле­мент, поэто­му он равен еди­ни­це) и вычи­та­ем из него еди­ни­цу. Полу­ча­ем ноль — то, что нам нужно.

Добавляем проверку времени

Для про­вер­ки вре­ме­ни мы извле­ка­ем из пол­ной даты зна­че­ние теку­ще­го часа. Так как нам нуж­но, что­бы код сра­ба­ты­вал с 10 вече­ра до 5 утра, то зна­че­ние часа долж­но быть боль­ше 21 и мень­ше 5:

// проверяем время — если наступил нужный нам диапазон
if ((now.getHours() > 21 || now.getHours() < 5) && finalTexts) {
}

👉 Обра­ти­те вни­ма­ние — мы доба­ви­ли в усло­вие finalTexts. Если на преды­ду­щем эта­пе мы всё-таки ниче­го не нашли, то при такой про­вер­ке резуль­тат будет false, усло­вие не выпол­нит­ся и делать внут­ри несу­ще­ству­ю­щей плаш­ки ниче­го не нужно.

Теперь всё осталь­ное напи­шем внут­ри этой проверки.

Добавляем текст на плашку

У нас может быть две ситу­а­ции: кар­тин­ка с кин­жа­лом есть на плаш­ке или её там нет. Если есть — надо доба­вить текст до неё, а если кар­тин­ки нет — про­сто поста­вить текст в конец.

Что­бы поста­вить текст до кар­тин­ки, нам нуж­но сде­лать так:

  1. Ищем в тек­сте нача­ло тега кар­тин­ки "<img" и смот­рим, на какой пози­ции он начинается.
  2. Если такой текст внут­ри плаш­ки есть и поиск нам вер­нул кон­крет­ную пози­цию, то берём фраг­мент тек­ста до этой пози­ции, добав­ля­ем наш текст, а потом при­кле­и­ва­ем тег с картинкой.
  3. Если тега с кар­тин­кой на плаш­ке нет, то при­кле­и­ва­ем наш текст в конец исход­ной надписи.
  4. Резуль­тат отправ­ля­ем в плаш­ку вме­сто старого.

Запи­шем это в виде кода:

//  получаем содержимое финальной плашки
const s = lastFinalText.innerHTML;
// ищем начало картинки с кинжалом и его запоминаем позицию в строке
const c = s.indexOf("<img");
// если нашли…
if (c !== -1) {
  // то берём текст до картинки
  const s_begin = s.slice(0, c - 1);
  // затем берём текст после картинки
  const s_end = s.slice(c, s.length);
  // и склеиваем обратно, добавляя в середину наш текст
  const s_result = s_begin + ". А теперь ложитесь спать " + s_end;
  // отправляем результат обратно в финальную плашку
  lastFinalText.innerHTML = s_result;
// если картинки в плашке не оказалось…
} else {
  // то просто добавляем концовку
  const s_result = s + ". А теперь ложитесь спать";
 // и отправляем результат обратно в финальную плашку
  lastFinalText.innerHTML = s_result;

Соби­ра­ем код в одно целое и про­ве­ря­ем результат:

Адаптируем статью под время суток
Итоговый код

// ждём, пока страница полностью загрузится, потом алгоритм начинает работать
document.addEventListener("DOMContentLoaded", () => {
  // получаем текущую дату и время пользователя
  const now = new Date();
  // находим в документе среди всех разделов, которые относятся к статье, финальную плашку
  const finalTexts = document
    .querySelector(".article-content")
    .querySelectorAll(".final");
  // находим нужную и единственную плашку, с которой будем работать
  const lastFinalText = finalTexts[finalTexts.length - 1];
  //   проверяем время — если наступил нужный нам диапазон
  if ((now.getHours() > 21 || now.getHours() < 5) && finalTexts) {
    //  получаем содержимое финальной плашки
    const s = lastFinalText.innerHTML;
    // ищем начало картинки с кинжалом и его запоминаем позицию в строке
    const c = s.indexOf("<img");
    // если нашли…
    if (c !== -1) {
      // то берём текст до картинки
      const s_begin = s.slice(0, c - 1);
      // затем берём текст после картинки
      const s_end = s.slice(c, s.length);
      // и склеиваем обратно, добавляя в середину наш текст
      const s_result = s_begin + ". А теперь ложитесь спать " + s_end;
      // отправляем результат обратно в финальную плашку
      lastFinalText.innerHTML = s_result;
    // если картинки в плашке не оказалось…
    } else {
      // то просто добавляем концовку
      const s_result = s + ". А теперь ложитесь спать";
     // и отправляем результат обратно в финальную плашку
      lastFinalText.innerHTML = s_result;
    }
  }
});

Текст:

Миха­ил Полянин

Редак­тор:

Мак­сим Ильяхов

Худож­ник:

Даня Бер­ков­ский

Кор­рек­тор:

Ири­на Михеева

Вёрст­ка:

Ники­та Кучеров

Соц­се­ти:

Олег Веш­кур­цев