Google Classroom | Модификация интерфейса

Модификация интерфейса для Google Classroom.

Verzia zo dňa 19.04.2020. Pozri najnovšiu verziu.

Na nainštalovanie skriptu si budete musieť nainštalovať rozšírenie, ako napríklad Tampermonkey, Greasemonkey alebo Violentmonkey.

Na inštaláciu tohto skriptu je potrebné nainštalovať rozšírenie, ako napríklad Tampermonkey.

Na nainštalovanie skriptu si budete musieť nainštalovať rozšírenie, ako napríklad Tampermonkey, % alebo Violentmonkey.

Na nainštalovanie skriptu si budete musieť nainštalovať rozšírenie, ako napríklad Tampermonkey alebo Userscripts.

Na inštaláciu tohto skriptu je potrebné nainštalovať rozšírenie, ako napríklad Tampermonkey.

Na inštaláciu tohto skriptu je potrebné nainštalovať rozšírenie správcu používateľských skriptov.

(Už mám správcu používateľských skriptov, nechajte ma ho nainštalovať!)

Na inštaláciu tohto štýlu je potrebné nainštalovať rozšírenie, ako napríklad Stylus.

Na inštaláciu tohto štýlu je potrebné nainštalovať rozšírenie, ako napríklad Stylus.

Na inštaláciu tohto štýlu je potrebné nainštalovať rozšírenie, ako napríklad Stylus.

Na inštaláciu tohto štýlu je potrebné nainštalovať rozšírenie správcu používateľských štýlov.

Na inštaláciu tohto štýlu je potrebné nainštalovať rozšírenie správcu používateľských štýlov.

Na inštaláciu tohto štýlu je potrebné nainštalovať rozšírenie správcu používateľských štýlov.

(Už mám správcu používateľských štýlov, nechajte ma ho nainštalovať!)

// ==UserScript==
// @name             Google Classroom | Модификация интерфейса
// @name:ru          Google Classroom | Модификация интерфейса
// @name:en          Google Classroom | Interface modification
// @description      Модификация интерфейса для Google Classroom.
// @description:ru   Модификация интерфейса для Google Classroom.
// @description:en   Modification of the interface for the Google Classroom editor.
// @iconURL          https://ssl.gstatic.com/classroom/favicon.png
// @version          1.0
// @noframes
// @author           Максим Стоянов (stomaks)
// @developer        Максим Стоянов (stomaks)
// @match            https://classroom.google.com/*
// @require          https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js
// @namespace        https://stomaks.me
// @supportURL       https://stomaks.me?feedback
// @contributionURL  https://www.paypal.com/cgi-bin/webscr?cmd=_donations&[email protected]&item_name=Greasy+Fork+donation
// @license          WTFPL; http://www.wtfpl.net/txt/copying
// ==/UserScript==

(function() {
  'use strict';

  $(`head`).append(`
<style>
.joJglb {
  z-index: 980;
}

.tdS5P {
  z-index: 900;
}

.xUYklb {
  font-size: 85%;
}

.SRX5Hd {
  position: fixed;
  bottom: 45px;
  right: 45px;
  height: auto;
  width: auto;
  z-index: 900;
}

.SRX5Hd .aS18D.p0oLxb {
  min-width: inherit;
}

.SRX5Hd .GcVcmc .RdyDwe {
  display: none;
}

.SRX5Hd .aS18D.p0oLxb .Fxmcue.cd29Sd {
  padding: 20px;
  text-align: center;
}

.SRX5Hd .aS18D.p0oLxb .Ce1Y1c {
  margin: 0;
}

.Kb1iQ {
  margin: 0 0 0 auto;
}

.JPdR6b.qjTEB {
  position: fixed !important;
}

main {
  padding-bottom: 75px;
}

/* # alt */
body > [name="alt"] {
  position: absolute;
  top: 50%;
  left: 50%;
  border-radius: 2px;
  padding: 5px 10px;
  max-width: 500px;
  background: rgba(97, 97, 97, 0.9);
  -webkit-transition: opacity 250ms 250ms cubic-bezier(.4, 0, .2, 1),
    transform 250ms 250ms cubic-bezier(.4, 0, .2, 1),
    top 250ms 0ms cubic-bezier(.4, 0, .2, 1),
    left 250ms 0ms cubic-bezier(.4, 0, .2, 1);
  transition: opacity 250ms 250ms cubic-bezier(.4, 0, .2, 1),
    transform 250ms 250ms cubic-bezier(.4, 0, .2, 1),
    top 250ms 0ms cubic-bezier(.4, 0, .2, 1),
    left 250ms 0ms cubic-bezier(.4, 0, .2, 1);
  -webkit-transform: scale3d(0, 0, 0);
  transform: scale3d(0, 0, 0);
  -webkit-transform-origin: top left;
  transform-origin: top left;
  opacity: 0;
  pointer-events: none;
  z-index: 970;
}

body > [name="alt"],
body > [name="alt"] > * {
  color: #fff;
  font-family: Roboto, Helvetica, Arial, sans-serif;
  font-size: 10px;
  line-height: initial;
  letter-spacing: .5px;
}

body > [name="alt"][state="show"] {
  -webkit-transform: scale3d(1, 1, 1);
  transform: scale3d(1, 1, 1);
  opacity: 1;
}

</style>`);



  $(`body`).append(`<div name="alt"></div>`);



  // Установка подсказок
  function setAlt () {
    // Для основного меню
    {
      const el = $(`div[role="menu"].OX4Vcb a[aria-label]`);

      el.each(function () {
        const el_text = $(this).attr("aria-label");

        $(this).attr("alt", el_text);
      });
    }

    // Для меню
    {
      const el = $(`aside.GP1o5c ul > li`);

      el.each(function () {
        const el_text = $(this).find(`div.YVvGBb`).text();

        $(this).attr("alt", el_text);
      });
    }

    // Для тем
    {
      const el = $(`ol.FpfvHe > li > div[data-topic-id]`);

      el.each(function () {
        const el_text = $(this).find(`> div > a`).text();

        $(this).attr("alt", el_text);
      });
    }

    // Для елементов темы
    {
      const el = $(`ol.Xzp3fc > li > div`);

      el.each(function () {
        const el_text = $(this).find(`.kByKEb > span`).text();

        $(this).attr("alt", el_text);
      });
    }

    //  Кнопка +
    {
      const el = $(`.SRX5Hd`);

      const el_text = el.find(`.GcVcmc .RdyDwe`).text();

      el.attr("alt", el_text);
    }


    setTimeout(setAlt, 1000);
  };

  setTimeout(setAlt, 1000);







  //+----------------------------------------------------------------------------------------------+
  /** Метод-утилита "getCoordinates" - Получает координаты курсора или элемента.
     *
     * @param {string|jQuery} Путь к элементу, ссылка на элемент или объект с настройками.
     *
     * @param {object} callback Данные для подписанных функций или функция обратного вызова.
     *
     * @return {object|null|function} Объект, или вызывает подписанные функции, или выполняет функцию обратного вызова.
     */
  function getCoordinates ( data, callback = null, event = window.event ) {
    let result = {};

    try {
      result.data = {};

      if ( data == null ) {
        result.data = {
          X: event.clientX || null,
          Y: event.clientY || null,
          x: event.pageX || null,
          y: event.pageY || null
        };
      } else {
        switch ( typeof data ) {
          case "string":
            data = $(data);

          case "object":
            if ( data instanceof jQuery && data.is(":visible") ) {
              result.data = {
                X: data.position().left || null,
                Y: data.position().top || null,
                x: data.offset().left || null,
                y: data.offset().top || null
              };
            }
            break;

          default: break;
        }
      }





      // Без обратного вызова
      if ( !callback ) {
        return result.data;
      }

      // Функция обратного вызова
      if ( typeof callback === "function" ) {
        return callback( result );
      }
    } catch ( error ) {
      result.error = error;
      result.data = null;
    }

    return result.data;
  };
  //+----------------------------------------------------------------------------------------------+



  function showAlt ( data, callback = null, event = window.event ) {
    let result = {};

    result.data = {};

    function _ ( x, y ) {
      let float = [];
      let temp = x / $(`body`).width() * 100;

      if ( temp <= 10 ) {
        float.push("left");
      } else if ( temp > 10 && temp < 90 ) {
        float.push("center");
      } else {
        float.push("right");
      }

      temp = y / $(`body`).height() * 100;

      if ( temp <= 10 ) {
        float.push("top");
      } else if ( temp > 10 && temp < 90 ) {
        float.push("center");
      } else {
        float.push("bottom");
      }

      return float;
    }

    // Контейнер
    switch ( typeof data ) {
      case "string":
        if ( data.length > 0 ) {
          result.data.container = $(data);
          break;
        }

      case "object":
        if ( data instanceof jQuery ) {
          result.data.container = data;
          break;
        }

      default:
        throw new TypeError(`Входящие данные не определены или имеют неверный тип данных.`);
    }

    // Подсказка
    result.data.alt = result.data.container.attr("alt");

    // Направление подсказки
    result.data.float = [];
    {
      let temp = result.data.container.attr("alt-float");

      if ( typeof temp === "string" ) {
        temp = temp.split(" ");

        result.data.float = [temp[0], temp[1]];
      }
    }

    // Определение соответствия текста в alt и в элементе
    function isAlt ( el, alt ) {
      if ( el.children().length > 0 ) {
        // Видимые в элементы
        el = el.children(`:visible:not(.content)`).filter(function() {
          return !($(this).css(`opacity`) === "0" || $(this).css(`visibility`) === "hidden");
        });
      }

      // Текст
      result.data.text = el.text().replace(/^\s+|\s+$/g, ``);

      return (typeof alt === "string" && alt.length ); // && alt !== result.data.text
    }

    if ( isAlt(result.data.container, result.data.alt) ) {
      $(`body > div[name="alt"]`)
        .attr("state", "show")
        .html( result.data.alt );



      // Получить координаты контейнера
      result.data.coordinates = getCoordinates( data );

      // Валидация направления подсказки
      {
        let isX = false;
        if ( result.data.float[0] === "left" || result.data.float[0] === "center" || result.data.float[0] === "right" ) {
          isX = true;
        }

        let isY = false;
        if ( result.data.float[1] === "top" || result.data.float[1] === "center" || result.data.float[1] === "bottom" ) {
          isY = true;
        }

        if ( !isX || !isY || result.data.float.length !== 2 ) {
          // Получить положение контейнера
          let temp = _(result.data.coordinates.x, result.data.coordinates.y);

          if ( !isX ) {
            result.data.float = [temp[0], result.data.float[1]];
          }

          if ( !isY ) {
            result.data.float = [result.data.float[0], temp[1]];
          }
        }
      }



      let app_width = $(`body`).outerWidth() || $(`body`).width();
      let app_height = $(`body`).outerHeight() || $(`body`).height();

      let alt_width = $(`body > div[name="alt"]`).outerWidth() || $(`body > div[name="alt"]`).width();
      let alt_height = $(`body > div[name="alt"]`).outerHeight() || $(`body > div[name="alt"]`).height();

      let container_width = result.data.container.outerWidth() || result.data.container.width();
      let container_height = result.data.container.outerHeight() || result.data.container.height();

      switch ( result.data.float.join(" ")  ) {
        case "left top": // ↘
          result.data.coordinates.y += container_height + 10;
          break;

        case "left center": // →
          result.data.coordinates.x += container_width + 20;
          result.data.coordinates.y += (container_height - alt_height ) / 2;
          break;

        case "left bottom": // ↗
          result.data.coordinates.x += container_width + 20;
          result.data.coordinates.y += (container_height - alt_height ) / 2;
          break;

        case "center top": // ↓
          result.data.coordinates.x += ((container_width - alt_width) / 2);
          result.data.coordinates.y += container_height + 10;
          break;

        case "center center": // •
          result.data.coordinates.x += ((container_width - alt_width) / 2);
          result.data.coordinates.y += container_height + 10;
          break;

        case "center bottom": // ↑
          result.data.coordinates.x += ((container_width - alt_width) / 2);
          result.data.coordinates.y -= alt_height + 10;
          break;

        case "right top": // ↙
          result.data.coordinates.x += container_width - alt_width;
          result.data.coordinates.y += container_height + 10;
          break;

        case "right center": // ←
          result.data.coordinates.x -= alt_width + 25;
          result.data.coordinates.y += (container_height - alt_height ) / 2;
          break;

        case "right bottom": // ↖
          result.data.coordinates.x -= alt_width + 25;
          result.data.coordinates.y += (container_height - alt_height ) / 2;
          break;
      }

      if ( result.data.coordinates.x < 20 ) {
        result.data.coordinates.x = 20;
      }
      if ( result.data.coordinates.x + 40 >= app_width ) {
        result.data.coordinates.x = app_width - (alt_width + 20);
      }

      if ( result.data.coordinates.y < 20 ) {
        result.data.coordinates.y = 20;
      }
      if ( result.data.coordinates.y + 40 >= app_height ) {
        result.data.coordinates.y = app_height - (alt_height + 20);
      }



      $(`body > div[name="alt"]`)
        .css({
        "left": result.data.coordinates.x,
        "top": result.data.coordinates.y,
        "-webkit-transform-origin": result.data.float.join(" "),
        "transform-origin": result.data.float.join(" ")
      });
    } else {
      $(`body > div[name="alt"]`)
        .attr("state", "hide");
    }
  };



  $(`html > body`)

  // Показать подсказку
    .on("mouseover focus", "*", function ( event = window.event ) {
    // Контейнер
    let el_container = $(this).find(event.target).closest(`[alt]`);

    showAlt( el_container );
  });

})();