Random English Word Popup

Display a random word with its definition, pronunciation, and examples

您需要先安装一个扩展,例如 篡改猴Greasemonkey暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴Userscripts ,之后才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。

您需要先安装用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         Random English Word Popup
// @namespace    http://tampermonkey.net/
// @version      1.2
// @description  Display a random word with its definition, pronunciation, and examples
// @match        *://*/*
// @grant        GM_xmlhttpRequest
// @grant        GM_addStyle
// @require      https://code.jquery.com/jquery-3.6.0.min.js
// @license MIT
// ==/UserScript==

(function() {
  'use strict';

  let wordsQueue = [];
  let currentWordIndex = 0;
  let popupCreated = false;
  let changeWordTimeout;
  const wordsToLoad = 50; // Загружаем по 50 слов за раз

  // Используем localStorage для хранения состояния свёрнутости
  let isPopupMinimized = localStorage.getItem('isPopupMinimized') === 'true' || false;

  function openTranslationWindow(word) {
    const parentWindowX = window.screenX;
    const parentWindowY = window.screenY + window.outerHeight;
    window.open(`https://translate.google.com/#view=home&op=translate&sl=auto&tl=ru&text=${encodeURIComponent(word)}`, '_blank', `width=500,height=500,top=${parentWindowY + 600},left=${parentWindowX + 700},popup=yes`);
  }

  GM_addStyle(`
    .word-popup-button {
      background-color: transparent;
      border: 1px solid #D3D3D3;
      color: white;
      padding: 8px 16px;
      text-align: center;
      text-decoration: none;
      display: inline-block;
      font-size: 16px;
      margin: 4px 2px;
      cursor: pointer;
      border-radius: 4px;
      transition-duration: 0.4s;
    }

    .word-popup-button:hover {
      border-color: #A9A9A9;
      box-shadow: 0 12px 16px 0 rgba(0,0,0,0.24), 0 17px 50px 0 rgba(0,0,0,0.19);
    }
  `);

  function fetchWordData(word) {
    return new Promise((resolve, reject) => {
      GM_xmlhttpRequest({
        method: "GET",
        url: `https://api.dictionaryapi.dev/api/v2/entries/en/${word}`,
        onload: function (response) {
          try {
            const wordData = JSON.parse(response.responseText)[0];
            const definition = wordData.meanings[0].definitions[0].definition;
            const phoneticSpelling = wordData.phonetics[0] ? wordData.phonetics[0].text : 'N/A';
            let examples = "-";
            for (const meaning of wordData.meanings) {
              for (const definitionItem of meaning.definitions) {
                if (definitionItem.example) {
                  examples = `"${definitionItem.example}"`;
                  break;
                }
              }
            }
            resolve({ word, phoneticSpelling, definition, examples });
          } catch (error) {
            reject(error);
          }
        },
        onerror: function (error) {
          reject(error);
        }
      });
    });
  }

  function loadNextWord() {
    // Проверяем, нужно ли загружать ещё слова
    if (wordsQueue.length >= wordsToLoad) return;

    for (let i = wordsQueue.length; i < wordsToLoad; i++) {
      GM_xmlhttpRequest({
        method: "GET",
        url: "https://random-word-api.herokuapp.com/word?number=1",
        onload: async function(response) {
          const word = JSON.parse(response.responseText)[0];
          try {
            const wordData = await fetchWordData(word);
            wordsQueue.push(wordData);

            // Если это первое слово в очереди, создаём попап и отображаем слово
            if (wordsQueue.length === 1) {
              createPopup();
              displayWord();
            }
          } catch (error) {
            console.error("Ошибка при получении данных слова:", error);
          }
        },
        onerror: function(error) {
          console.error("Ошибка при получении случайного слова:", error);
        }
      });
    }
  }

  function displayWord() {
    if (wordsQueue.length === 0) return;

    const wordInfo = wordsQueue[currentWordIndex];
    $('#word').text(wordInfo.word);
    $('#phonetic').html(`<br><span style="font-size: smaller; color: lightgrey;">[${wordInfo.phoneticSpelling}]</span>`);
    $('#definition').text(wordInfo.definition);
    $('#examples').text(`Examples: ${wordInfo.examples}`);
  }

  function resetChangeWordTimer() {
    clearTimeout(changeWordTimeout);
    changeWordTimeout = setTimeout(showNextWord, 60000);
  }

  function createPopup() {
    if (popupCreated) return;
    popupCreated = true;

    const popupHTML = `
      <div id="wordPopup" style="position: fixed; bottom: 20px; right: 20px; width: 450px; height: 170px; background: rgba(0, 0, 0, 0.5); color: white; padding: 10px; z-index: 9999; ${isPopupMinimized ? 'display: none;' : ''}">
        <div style="display: flex; justify-content: space-between; align-items: center;">
          <h2 style="margin: 0;"><span id="word" style="font-weight: bold; color: #fff; cursor: pointer;"></span><span id="phonetic" style="font-size: smaller; color: lightgrey;"></span></h2>
          <div>
            <button id="prevWord" class="word-popup-button" style="font-size: 16px;">←</button>
            <button id="togglePopup" class="word-popup-button" style="font-size: 16px;">−</button>
            <button id="nextWord" class="word-popup-button" style="font-size: 16px;">→</button>
          </div>
        </div>
        <p id="definition" style="margin: 5px 0;"></p>
        <p id="examples" style="margin: 5px 0;"></p>
      </div>
      <div id="minimizedPopup" style="position: fixed; bottom: 20px; right: 20px; width: 30px; height: 30px; background: rgba(0, 0, 0, 0.5); color: white; padding: 5px; z-index: 9999; display: flex; justify-content: center; align-items: center; cursor: pointer; ${!isPopupMinimized ? 'display: none;' : ''}">
        <span id="expandPopup" class="word-popup-button" style="font-size: 16px;">+</span>
      </div>
    `;
    $('body').append(popupHTML);

    // При загрузке страницы проверяем состояние свёрнутости
    applyPopupState();
    $(window).on('load hashchange', applyPopupState);

    $('#togglePopup').one('click', function() {
      togglePopupState();
    });

    $('#minimizedPopup').one('click', function() {
      togglePopupState();
    });

    $('#prevWord').on('click', showPreviousWord);
    $('#nextWord').on('click', showNextWord);
    $('#word').on('click', () => openTranslationWindow($('#word').text()));
  }

  function showPreviousWord() {
    if (wordsQueue.length > 1) {
      currentWordIndex = (currentWordIndex - 1 + wordsQueue.length) % wordsQueue.length;
      displayWord();
      resetChangeWordTimer();
    }
  }

  function showNextWord() {
    if (wordsQueue.length > 0) {
      currentWordIndex = (currentWordIndex + 1) % wordsQueue.length;
      displayWord();
      resetChangeWordTimer();
      loadNextWord(); // Запускаем подгрузку новых слов
    }
  }

  // Функция для переключения состояния свёрнутости и сохранения в localStorage
  function togglePopupState() {
    $('#wordPopup').toggle();
    $('#minimizedPopup').toggle();
    isPopupMinimized = !isPopupMinimized;
    localStorage.setItem('isPopupMinimized', isPopupMinimized);
  }

  // Функция для установки состояния попапа
  function applyPopupState() {
    if (isPopupMinimized) {
      $('#wordPopup').hide();
      $('#minimizedPopup').show();
    } else {
      $('#wordPopup').show();
      $('#minimizedPopup').hide();
    }
  }

  $(document).on('keydown', function(event) {
    if (event.key === 'ArrowLeft') {
      showPreviousWord();
    } else if (event.key === 'ArrowRight') {
      showNextWord();
    }
  });

  $(document).ready(function() {
    loadNextWord(); // Загрузка первой порции слов
  });
})();