- // ==UserScript==
- // @name Google Classroom | Interface modification
- // @description Modification of the interface for the 𝗚𝗼𝗼𝗴𝗹𝗲 𝗖𝗹𝗮𝘀𝘀𝗿𝗼𝗼𝗺.
-
- // @name:en Google Classroom | Interface modification
- // @description:en Modification of the interface for the 𝗚𝗼𝗼𝗴𝗹𝗲 𝗖𝗹𝗮𝘀𝘀𝗿𝗼𝗼𝗺.
-
- // @name:ru Google Classroom | Модификация интерфейса
- // @description:ru Модификация интерфейса для 𝗚𝗼𝗼𝗴𝗹𝗲 𝗖𝗹𝗮𝘀𝘀𝗿𝗼𝗼𝗺.
-
- // @name:uk Google Classroom | | Модифікація інтерфейсу
- // @description:uk Модифікація інтерфейсу для 𝗚𝗼𝗼𝗴𝗹𝗲 𝗖𝗹𝗮𝘀𝘀𝗿𝗼𝗼𝗺.
-
- // @name:bg Google Classroom | | Модификация на интерфейса
- // @description:bg Модификация на интерфейса за 𝗚𝗼𝗼𝗴𝗹𝗲 𝗖𝗹𝗮𝘀𝘀𝗿𝗼𝗼𝗺.
-
- // @iconURL https://ssl.gstatic.com/classroom/favicon.png
- // @version 1.5
- // @match https://classroom.google.com/*
- // @require https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js
- // @noframes
- // @namespace https://stomaks.me
- // @supportURL https://stomaks.me?feedback
- // @contributionURL https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=stomaks@gmail.com&item_name=Greasy+Fork+donation
- // @author Maksim_Stoyanov_(stomaks)
- // @developer Maksim_Stoyanov_(stomaks)
- // @copyright 2020, Maxim Stoyanov (stomaks.me)
- // @license MIT
- // @compatible chrome
- // @compatible firefox
- // @compatible opera
- // @compatible safari
- // ==/UserScript==
-
-
-
- (function() {
- 'use strict';
-
- // Интеграция иконок
- $(`head`).append(`
- <link rel="preload" as="font" href="//stomaks.app/fonts/MaterialIcons/MaterialIcons1.woff2" type="font/woff2" crossorigin="anonymous">
- <link rel="preload" as="font" href="//stomaks.app/fonts/MaterialIcons/MaterialIcons2.woff2" type="font/woff2" crossorigin="anonymous">
- <link href="//stomaks.app/styles/icons.min.css" rel="stylesheet">`);
-
- // Интеграция стилей
- {
- $(`head`).append(`
- <style>
-
- .tdS5P {
- z-index: 900;
- }
-
- ol.FpfvHe > li .ClSQxf > [expanded] {
- border-radius: 100px;
- }
-
- ol.FpfvHe > li .ClSQxf > [expanded] > i {
- transition:
- opacity 250ms 0ms cubic-bezier(.4, 0, .2, 1),
- transform 250ms 0ms cubic-bezier(.4, 0, .2, 1);
- padding: 8px;
- border-radius: 100px;
- }
-
- ol.FpfvHe > li[expanded="false"] .ClSQxf > [expanded] > i {
- -webkit-transform: rotate(180deg);
- transform: rotate(180deg);
- }
-
- ol.FpfvHe > li[expanded]:not([expanded="true"]) > .zq2w8b {
- display: none;
- }
-
- .xUYklb {
- font-size: 20px;
- }
-
- .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.e5Emjc.hVNH5c.bzD7fd.qjTEB {
- position: fixed !important;
- max-height: initial !important;
- top: initial !important;
- left: initial !important;
- right: 25px !important;
- bottom: 35px !important;
- }
-
- .JPdR6b.e5Emjc.hVNH5c.bzD7fd.qjTEB > .XvhY1d {
- max-height: initial !important;
- }
-
- .JPdR6b.e5Emjc.hVNH5c.bzD7fd.qjTEB #stomaks_classroom_automation [icon="open_in_new"] {
- opacity: .25;
- font-size: 18px;
- margin: auto;
- position: absolute;
- right: 10px;
- top: 8px;
- z-index: 1;
- }
-
- main {
- padding-bottom: 75px;
- }
-
- .ClSQxf {
- display: flex;
- flex-direction: row;
- }
-
- /* # 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 tick () {
- // Скрыть темы
- {
- Object.keys(localStorage).forEach(function ( key, i ) {
- const value = window.localStorage.getItem(key);
-
- $(`ol.FpfvHe > li[data-dom-id='${key}']`).attr("expanded", value);
- $(`ol.FpfvHe > li[data-dom-id='${key}'] .ClSQxf > [expanded]`).attr("expanded", value);
- });
- }
-
- // Для основного меню
- {
- 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);
- }
-
- // Установка кнопок для споилера
- {
- const el = $(`.ClSQxf`);
-
- if ( !el.find(`[expanded]`).length ) {
- el.prepend(`<div class="wwnMtb" expanded="true"><i icon="expand_less"></i></div>`);
- }
- }
-
- // Добавить опцию создания
- {
- const el = $(`.JPdR6b.e5Emjc.hVNH5c.bzD7fd.qjTEB > div > div`);
-
- if ( !el.find(`#stomaks_classroom_automation`).length ) {
- el.append(`
- <div role="separator" class="kCtYwe"></div>
- <span jsslot id="stomaks_classroom_automation" tabindex="-1" class="z80M1 FeRvI" aria-label="Автоматизация" role="menuitem">
- <div class="aBBjbd MbhUzd" jsname="ksKsZd"></div>
- <div class="PCdOIb Ce1Y1c" aria-hidden="true">
- <i icon="-cogs" class="mxmXhf NMm5M hhikbc"></i>
- </div>
- <div class="uyYuVb oJeWuf">
- <div class="jO7h3c">Автоматизация</div>
- </div>
- <div>
- <i icon="open_in_new"></i>
- </div>
- </span>`);
- }
- }
-
- setTimeout(tick, 1000);
- };
-
- setTimeout(tick, 100);
- //+----------------------------------------------------------------------------------------------+
-
-
-
-
-
- //+----------------------------------------------------------------------------------------------+
- /** Метод-утилита "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;
- };
- //+----------------------------------------------------------------------------------------------+
-
-
-
-
-
- //+----------------------------------------------------------------------------------------------+
- /** Метод-действие "showAlt" - Отображает подсказку.
- *
- * @param {string|jQuery} Путь к элементу, или ссылка на элемент, или объект с настройками.
- *
- * @param {object} callback Данные для подписанных функций или функция обратного вызова.
- *
- * @return {object|null|function} Объект, или выполняет функцию обратного вызова.
- */
- function showAlt ( data, callback = null, event = window.event ) {
- let result = {};
-
- result.data = {};
-
- try {
- 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");
- }
-
-
-
- // Без обратного вызова
- if ( !callback ) {
- return result.data;
- }
-
- // Функция обратного вызова
- if ( typeof callback === "function" ) {
- return callback( result );
- }
- } catch ( error ) {
- result.error = error;
- result.data = null;
- }
-
- return result.data;
- };
- //+----------------------------------------------------------------------------------------------+
-
-
-
-
-
- $(`html > body`)
-
- // Показать подсказку
- .on("mouseover focus", "*", function ( event = window.event ) {
- // Контейнер
- let el_container = $(this).find(event.target).closest(`[alt]`);
-
- showAlt( el_container );
- })
-
- // [Свернуть|Развернуть споилер]
- .on("mouseup", ".ClSQxf > [expanded]", function ( event = window.event ) {
- const el = $(this);
- const el_container = el.closest(`li`);
-
- let expanded = el.attr("expanded");
- const id = el_container.attr("data-dom-id");
-
- if ( expanded == "true" ) {
- expanded = "false";
- } else {
- expanded = "true";
- }
-
- el.attr("expanded", expanded);
- el_container.attr("expanded", expanded);
-
- localStorage.setItem(id, expanded);
- console.log( id, expanded );
- })
-
- // Показать подсказку
- .on("mouseover focus", "#stomaks_classroom_automation", function ( event = window.event ) {
- const el = $(this);
-
- el.addClass("FwR7Pc");
- })
-
- // Кнопка "Автоматизация"
- .on("mouseover focus", "#stomaks_classroom_automation", function ( event = window.event ) {
- const el = $(this);
-
- el.addClass("FwR7Pc");
- })
- .on("mouseleave focusout", "#stomaks_classroom_automation", function ( event = window.event ) {
- const el = $(this);
-
- el.removeClass("FwR7Pc");
- })
- .on("mouseup", "#stomaks_classroom_automation", function ( event = window.event ) {
- window.open("https://g-apps-script.com/blog/google-klass", "_blank");
- })
- ;
-
- })();