Compare commits

..

2 Commits

Author SHA1 Message Date
Arsen Mirzaev Tatyano-Muradovich 95cf0b5c1f Added translate to english 2022-11-11 21:54:10 +10:00
Arsen Mirzaev Tatyano-Muradovich 7815b0c348 Исправлена страница настроек 2022-06-25 15:53:12 +10:00
5 changed files with 623 additions and 189 deletions

1
compile.sh Normal file
View File

@ -0,0 +1 @@
web-ext -s firefox run -f "C:\Program Files\Firefox Developer Edition\firefox.exe" -p "C:\Users\Пользователь\AppData\Roaming\Mozilla\Firefox\Profiles\development" --profile-create-if-missing --keep-profile-changes --verbose

View File

@ -0,0 +1,52 @@
{
"extensionName": {
"message": "Menu demo",
"description": "Name of the extension."
},
"extensionDescription": {
"message": "Demonstrates the menus API.",
"description": "Description of the add-on."
},
"menuItemSelectionLogger": {
"message": "Log '%s' to the browser console",
"description": "Title of context menu item that logs the selected text when clicked."
},
"menuItemRemoveMe": {
"message": "Remove me!",
"description": "Title of context menu item that removes itself when clicked."
},
"menuItemGreenify": {
"message": "Greenify",
"description": "Title of context menu item that adds a green border when clicked."
},
"menuItemBluify": {
"message": "Bluify",
"description": "Title of context menu item that adds a green border when clicked."
},
"menuItemCheckMe": {
"message": "Check me",
"description": "Title of context menu item when the item is checked."
},
"menuItemUncheckMe": {
"message": "Uncheck me",
"description": "Title of context menu item when the item is unchecked."
},
"menuItemOpenSidebar": {
"message": "Open sidebar",
"description": "Title of context menu item that opens a sidebar."
},
"menuItemToolsMenu": {
"message": "Click me!",
"description": "Title of tools menu item."
}
}

View File

@ -52,7 +52,7 @@
"webRequestBlocking" "webRequestBlocking"
], ],
"options_ui": { "options_ui": {
"page": "/system/settings/index.html" "page": "/settings/index.html"
}, },
"content_scripts": [ "content_scripts": [
{ {
@ -60,10 +60,10 @@
"https://*.vk.com/*" "https://*.vk.com/*"
], ],
"js": [ "js": [
"/system/log.js", "/log.js",
"/system/settings.js", "/settings.js",
"/system/core.js", "/core.js",
"/system/modules/module.js" "/modules/module.js"
], ],
"run_at": "document_start" "run_at": "document_start"
}, },
@ -72,8 +72,18 @@
"https://*.vk.com/*" "https://*.vk.com/*"
], ],
"js": [ "js": [
"/system/modules/visor/core.js", "/modules/visor/core.js",
"/system/modules/killer/core.js" "/modules/killer/core.js"
],
"run_at": "document_end"
},
{
"matches": [
"https://vk.com/*"
],
"js": [
"/modules/visor/core.js",
"/modules/killer/core.js"
], ],
"run_at": "document_end" "run_at": "document_end"
}, },
@ -82,7 +92,7 @@
"https://vk.com/settings?act=nadrez" "https://vk.com/settings?act=nadrez"
], ],
"js": [ "js": [
"/system/pages/settings/index.js" "/pages/settings/index.js"
], ],
"run_at": "document_end" "run_at": "document_end"
}, },
@ -91,7 +101,7 @@
"https://vk.com/im?sel=*" "https://vk.com/im?sel=*"
], ],
"js": [ "js": [
"/system/modules/killer/conversation.js" "/modules/killer/conversation.js"
], ],
"run_at": "document_end" "run_at": "document_end"
} }

View File

@ -5,42 +5,6 @@
*/ */
class killer { class killer {
constructor() { constructor() {
// /**
// * Генерация списка пользователей
// *
// * @param {string} id Идентификатор
// * @param {string} page Идентификатор страницы настроек
// *
// * @return {Function} Функция для выполнения в генераторе группы
// */
// this.list = function (id, page = 'nadrez') {
// /**
// * Запись в группу (подразумевается выполнение в функции генерирующую группу)
// *
// * @param {string} group Группа
// *
// * @return {bool} Статус выполнения
// */
// return function (group) {
// if (typeof page === 'string' && typeof id === 'string' && typeof group === 'string') {
// // Пройдена проверка входных параметров
// // Инициализация блока
// let block = document.getElementById('block_' + group);
// // Инициализация верхнего колонтинула блока
// let header = block.getElementsByClassName('page_block_header')[0];
// // Инициализация элемента со статусом
// let status = header.getElementsByClassName('page_block_saved')[0];
// // Инициализация тела блока
// let body = block.getElementsByClassName('settings_panel clear_fix settings_' + core.id + ' settings_section_' + core.id)[0];
// }
// return false;
// }
// }
/** /**
* Обработка группы сообщений * Обработка группы сообщений
* *
@ -49,9 +13,12 @@ class killer {
* @param {string} group Группа для обработки * @param {string} group Группа для обработки
* *
* @return {bool} Статус выполнения * @return {bool} Статус выполнения
*
* @todo 1. Добавить режим в котором проверяется не каждая группа сообщений, а
* сначала читаются все найденные группы сообщений и только потом обрабатываются все вместе
*/ */
this.tribunal = async function (group = this.last(), list = this.list()) { this.tribunal = async function (group = this.last(), list = this.list()) {
if (await this.search(this.account(group), this.list())) { if (await this.search(await this.account(group), await list)) {
// Найдена цель на удаление // Найдена цель на удаление
// Инициализация типа действия с группой сообщений заблокированного аккаунта // Инициализация типа действия с группой сообщений заблокированного аккаунта
@ -78,6 +45,8 @@ class killer {
/** /**
* Обработка всех видимых групп сообщений * Обработка всех видимых групп сообщений
* *
* Все сообщения загруженные в документе будут обработаны
*
* @return {number} Количество обработанных групп сообщений * @return {number} Количество обработанных групп сообщений
*/ */
this.genocide = async function () { this.genocide = async function () {
@ -103,6 +72,8 @@ class killer {
/** /**
* Найти элемент-оболочку групп сообщений * Найти элемент-оболочку групп сообщений
* *
* Элемент хранит в себе все группы сообщений (окно чата)
*
* @return {Element} Оболочка групп сообщений * @return {Element} Оболочка групп сообщений
*/ */
this.wrap = function () { this.wrap = function () {
@ -112,6 +83,14 @@ class killer {
/** /**
* Найти последнюю группу сообщений * Найти последнюю группу сообщений
* *
* Группа сообщений - элемент-оболочка в котором хранятся
* сообщения от одного и того же пользователя. Группу сообщений
* закрывает сообщение от другого пользователя или прохождение
* некоторого времени, таким образом будет создана отдельная группа.
*
* Определить группы можно по аватарам пользователей (у каждой группы
* аватар отправителя отображается только 1 раз)
*
* @return {Element} Группа сообщений, если найдена * @return {Element} Группа сообщений, если найдена
*/ */
this.last = function () { this.last = function () {
@ -125,9 +104,9 @@ class killer {
} }
/** /**
* Найти и прочитать пользователя последней группы сообщений * Найти и прочитать пользователя группы сообщений
* *
* @param {string} group Группа для обработки * @param {string} group Группа для обработки (иначе самая последняя, новая)
* *
* @return {number} Идентификатор страницы ВКонтакте (только цифры) * @return {number} Идентификатор страницы ВКонтакте (только цифры)
*/ */
@ -141,13 +120,20 @@ class killer {
/** /**
* Прочитать список аккаунтов на удаление из реестра * Прочитать список аккаунтов на удаление из реестра
* *
* Реестр очищается через определённое в настройках время
* он должен быть маленьким, чтобы не проводить длительные поиски аккаунта,
* но при этом он должен быть большим, чтобы проверять каждого пользователя
* в чате слишком часто, что ещё хуже, посколько выполняет отдельный запрос
* и ищет данные о нахождении в чёрном списке.
*
* Реестр может хранить в себе данные об аккаунтах записанных туда непосредственно,
* то есть аккаунты не обязательно находятся в чёрном списке
*
* @return {object} Список аккаунтов на удаление * @return {object} Список аккаунтов на удаление
*/ */
this.list = async function () { this.list = async function () {
// Инициализация списка аккаунтов на удаление // Инициализация списка аккаунтов на удаление
const targets = await settings.read('killer_targets'); return await settings.read('killer_targets');
return targets;
} }
/** /**
@ -156,42 +142,32 @@ class killer {
* @param {number} account Аккаунт для обработки * @param {number} account Аккаунт для обработки
* *
* @return {boolean} Статус наличия аккаунта в списке на удаление * @return {boolean} Статус наличия аккаунта в списке на удаление
*
* @todo 1. Возможно оно может асинхронно перезаписывать само себя когда сохраняет нового
* пользователя в реестр и сразу же после этого сохраняет реестр с другим пользователем без первого
* из-за того что оба процесса были запущены одновременно
*/ */
this.search = async function (account = this.account(), targets = await this.list()) { this.search = async function (account = this.account(), targets = this.list()) {
if (account === this.self()) { if (account === this.self()) {
// Обрабатывается свой аккаунт // Обрабатывается свой аккаунт
// Инициализация статуса разрешения блокировки самого себя // Инициализация статуса разрешения блокировки самого себя
const self = await settings.read('killer_self'); return await settings.read('killer_self') ?? false;
return self ?? false;
} }
console.log(targets); if (typeof await targets === 'object') {
if (typeof targets === 'object') {
// Пройдена проверка на тип // Пройдена проверка на тип
if (Object.keys(targets).length >= await settings.read('killer_targets_limit') ?? 500) { if (Object.keys(targets).length >= await settings.read('killer_targets_limit') ?? 500) {
// Достигло ограничения количество аккаунтов в реестре // Достигло ограничения количество аккаунтов в реестре
// Полная очистка реестра // Реинициализация реестра
this.purge(); this.purge();
} else { } else {
// Не достигло ограничения rоличество аккаунтов в ресстре // Не достигло ограничения rоличество аккаунтов в ресстре
for (const { target, status } in targets) {
// Перебор искомых целей для удаления // Перебор искомых целей для удаления
for (const target in targets) if (+target === +account) return true;
alert(target);
alert(status);
if (target === account) {
// Найдена цель
return true;
}
}
} }
} else { } else {
// Не пройдена проверка на тип и пустоту // Не пройдена проверка на тип и пустоту
@ -324,11 +300,8 @@ class killer {
// Инициализация кнопки "Заблокировать пользователя" // Инициализация кнопки "Заблокировать пользователя"
const button = page.body.querySelector('a[data-task-click="ProfileAction/toggle_blacklist"]'); const button = page.body.querySelector('a[data-task-click="ProfileAction/toggle_blacklist"]');
// Проверка на инициализированность кнопки
if (typeof button === 'null') return false;
// Возвращает true если заблокирован пользователь (подразумевается наличие текста "Разблокировать {пользователь}") // Возвращает true если заблокирован пользователь (подразумевается наличие текста "Разблокировать {пользователь}")
return button.innerText.trim()[0] === 'Р'; return (button.innerText.trim()[0] === 'Р') ?? false;
} }
/** /**
@ -340,18 +313,18 @@ class killer {
* *
* @todo Доделать * @todo Доделать
*/ */
this.forgive = async function (account, targets = await this.list()) { this.forgive = async function (account, targets) {
if (typeof account !== 'undefined' && typeof account !== 'null') { if (typeof account !== 'undefined' && typeof account !== 'null') {
// Пройдена проверка полученных значений аргументов // Пройдена проверка полученных значений аргументов
// Инициализация буфера записи в хранилище // Инициализация буфера записи в хранилище
let buffer = {}; let buffer = {};
for (const { target, status } in targets) { for (const target in targets) {
// Перебор заблокированных аккаунтов // Перебор заблокированных аккаунтов
// Проверка на совпадение // Проверка на совпадение
if (target === account) continue; if (+target === +account) continue;
// Запись в буфер записи в хранилище // Запись в буфер записи в хранилище
buffer.push(account); buffer.push(account);

View File

@ -83,11 +83,12 @@ class page {
this.blocks.header('Убийца'), this.blocks.header('Убийца'),
// text('Удаление активности выбранных пользователей'), // text('Удаление активности выбранных пользователей'),
this.blocks.fields.checkbox('activate', 'lightning', 'Активировать'), this.blocks.fields.checkbox('activate', 'lightning', 'Активировать'),
this.blocks.fields.checkbox('list', 'lightning', 'Заблокированные ВКонтакте', 'Удалять тех кто находится в списке заблокированных ВКонтакте'), this.blocks.fields.text('asdasdasd', 'lightning', 'Активировать', 'asdasdasdasd', 'Тестирование всплывающей подсказки', 'text', 0, 8, 'фффф', 'сюда писать'),
this.blocks.fields.checkbox('list', 'group', 'Заблокированные ВКонтакте', 'Удалять тех кто находится в списке заблокированных ВКонтакте', 'Тестирование всплывающей подсказки'),
this.blocks.fields.checkbox('target', 'list', 'Отдельный список на удаление', 'Выбрать пользователей вручную'), this.blocks.fields.checkbox('target', 'list', 'Отдельный список на удаление', 'Выбрать пользователей вручную'),
this.blocks.fields.dropdown('targetasdasd', 'promo', 'Какаято хуитень', 'Выбфывелей вручную', 'Тестирование всплывающей подсказки'),
modules.killer.list('asdasd'), modules.killer.list('asdasd'),
); );
} }
/** /**
@ -123,7 +124,7 @@ class page {
*/ */
header(text = '') { header(text = '') {
/** /**
* Запись в группу (подразумевается выполнение в функции генерирующую группу) * Запись в группу (подразумевается выполнение в функции генерирующей группу)
* *
* @param {string} group Группа * @param {string} group Группа
* *
@ -134,20 +135,19 @@ class page {
// Пройдена проверка входных параметров // Пройдена проверка входных параметров
// Инициализация блока куда надо записать заголовок // Инициализация блока куда надо записать заголовок
let block = document.getElementById('block_' + group); const block = document.getElementById('block_' + group);
// Инициализация оболочки заголовка // Инициализация оболочки заголовка
let title = block.getElementsByTagName('h2')[0].getElementsByClassName('page_block_header')[0]; const title = block.getElementsByTagName('h2')[0].getElementsByClassName('page_block_header')[0];
// Запись содержимого в буфер // Запись содержимого в буфер
let buffer = title.cloneNode(true); const buffer = title.cloneNode(true);
// Запись заголовка // Запись заголовка
title.innerText = text; title.innerText = text;
// Запись содержимого заголовка из буфера // Запись содержимого заголовка из буфера
for (let element of buffer.children) for (let element of buffer.children) title.appendChild(element);
title.appendChild(element);
return true; return true;
} }
@ -167,7 +167,7 @@ class page {
*/ */
header_extra(left = '', center = '', right = '') { header_extra(left = '', center = '', right = '') {
/** /**
* Запись в группу (подразумевается выполнение в функции генерирующую группу) * Запись в группу (подразумевается выполнение в функции генерирующей группу)
* *
* @param {string} group Группа * @param {string} group Группа
* *
@ -176,11 +176,12 @@ class page {
return function (group) { return function (group) {
if (typeof group === 'string' && typeof left === 'string' && typeof center === 'string' && typeof right === 'string') { if (typeof group === 'string' && typeof left === 'string' && typeof center === 'string' && typeof right === 'string') {
// Пройдена проверка входных параметров // Пройдена проверка входных параметров
// Инициализация блока // Инициализация блока
let block = document.getElementById('block_' + group); const block = document.getElementById('block_' + group);
// Инициализация оболочки заголовка // Инициализация оболочки заголовка
let title = block.getElementsByTagName('h2')[0].getElementsByClassName('page_block_header')[0]; const title = block.getElementsByTagName('h2')[0].getElementsByClassName('page_block_header')[0];
// Запись заголовков // Запись заголовков
title.getElementsByClassName('page_block_header_extra_left _header_extra_left')[0].innerText = left; title.getElementsByClassName('page_block_header_extra_left _header_extra_left')[0].innerText = left;
@ -295,62 +296,128 @@ class page {
* Поля * Поля
*/ */
fields: { fields: {
macroses: {
/**
* Шаблон для инициализации элементов строки с полем
*
* @param {string} group Группа
* @param {string|null} icon Иконка
* @param {function} content Функция которая будет обрабатывать содержимое макроса
*/
row(group, icon, content) {
// Инициализация блока
const block = document.getElementById('block_' + group);
// Инициализация головного элемента блока
const header = block.getElementsByClassName('page_block_header')[0];
// Инициализация элемента со статусом
const status = header.getElementsByClassName('page_block_saved')[0];
// Инициализация тела блока
const body = block.getElementsByClassName('settings_panel clear_fix settings_' + this.core.id + ' settings_section_' + this.core.id)[0];
// Инициализация оболочки кнопки активации
const wrap = document.createElement('div');
wrap.classList.add('settings_separated_row', this.core.icons[icon] ?? this.core.icons['lightning'], 'settings_separated_row_iconed');
// Инициализация разделителя
const separator = document.createElement('div');
separator.classList.add('settings_separated_row_extra');
// Генерация содержимого строки
return content(status, body, wrap, separator);
},
dropdown(active, rows) {
if (typeof active === 'string' && typeof rows === 'object') {
// Пройдена проверка входных параметров
// Инициализация оболочки
const wrap = document.createElement('div');
wrap.classList.add('privacy_dropdown', 'privacy_dropdown_mail', 'pdd_ralign');
wrap.setAttribute('style', 'opacity: 1; display: none;');
// Инициализация списка строк
const list = document.createElement('div');
list.classList.add('rows', 'rows__flex');
wrap.setAttribute('style', 'font-size: 13px;');
// Инициализация головной строки
const header = document.createElement('div');
header.classList.add('header');
wrap.setAttribute('onclick', 'Privacy.hide(-1)');
// Инициализация активной строки (выбранного параметра)
const active = document.createElement('div');
active.classList.add('header_label');
active.innerHTML = active;
// Инициализация основной группы строк
const body = document.createElement('div');
body.classList.add('body', 'body__flex');
body.setAttribute('role', 'list');
body.setAttribute('aria-labelledby', 'privacy_who_can_view');
for (const row in rows) {
// Перебор строк для генерации списка
// Инициализация кнопки
const button = document.createElement('button');
}
}
return null;
}
},
/** /**
* Генерация HTML-элемента настройки с кнопкой активации * Генерация HTML-элемента настройки с кнопкой активации
* *
* @param {string} id Идентификатор * @param {string} id Идентификатор
* @param {string|null} icon Иконка
* @param {string|null} name Название * @param {string|null} name Название
* @param {string|null} description Описание
* @param {string|null} hint Всплывающая подсказка (иконка с вопросительным знаком возле верхнего колонтинула)
* @param {string|null} onchange Код который выполняется после изменения состояния
* *
* @return {Function} Функция для выполнения в генераторе группы * @return {function} Функция для выполнения в генераторе группы
* *
* @todo 1. Добавить проверку на существование нижнего колонтинула и записывать перед ним, вместо конца блока * @todo 1. Добавить проверку на существование нижнего колонтинула и записывать перед ним, вместо конца блока
*/ */
checkbox(id, icon, name, description) { checkbox(id, icon, name, description, hint, onchange) {
// Инициализация ядра // Инициализация ядра
let core = this.core; const core = this.core;
/** /**
* Запись в группу (подразумевается выполнение в функции генерирующую группу) * Запись в группу (подразумевается выполнение в функции генерирующей группу)
* *
* @param {string} group Группа * @param {string} group Группа
* *
* @return {bool} Статус выполнения * @return {bool} Статус выполнения
*/ */
return function (group) { return function (group) {
if (typeof id === 'string' && typeof icon === 'string' && typeof core === 'object' && typeof group === 'string') { if (typeof id === 'string' && typeof core === 'object' && typeof group === 'string') {
// Пройдена проверка входных параметров // Пройдена проверка входных параметров
// Инициализация блока return core.blocks.fields.macros(group, icon,
let block = document.getElementById('block_' + group); function (status, body, wrap, separator) {
// Инициализация верхнего колонтинула блока
let header = block.getElementsByClassName('page_block_header')[0];
// Инициализация элемента со статусом
let status = header.getElementsByClassName('page_block_saved')[0];
// Инициализация тела блока
let body = block.getElementsByClassName('settings_panel clear_fix settings_' + core.id + ' settings_section_' + core.id)[0];
settings.read(id).then(result => {
// Инициализация оболочки кнопки активации
let wrap = document.createElement('div');
wrap.classList.add('settings_separated_row', core.icons[icon] ?? core.icons['lightning'], 'settings_separated_row_iconed');
wrap.addEventListener("click", fn => { wrap.addEventListener("click", fn => {
// Инициализация кнопки // Инициализация кнопки
let button = wrap.getElementsByClassName('ui_toggler')[0]; const button = wrap.getElementsByClassName('ui_toggler')[0];
if (button.classList.contains('on')) { if (button.classList.contains('on')) {
// Активирована // Активирована
if (settings.write(group + '_' + id, false)) { if (settings.write(group + '_' + id, false)) {
// Записан статус активации // Записан статус активации
// Запуск анимации и переход в состояние деактивации // Запуск анимации и переход в состояние деактивации
button.classList.remove('on'); button.classList.remove('on');
settings.read(group + '_' + id).then(result => { settings.read(group + '_' + id).then(result => {
if (result[group + '_' + id] === false) { if (result === false) {
// Сохранены изменения // Сохранены изменения
// Запуск анимации // Запуск анимации
status.style.transition = '0.5s'; status.style.transition = '0.5s';
status.style.opacity = 1; status.style.opacity = 1;
@ -365,12 +432,14 @@ class page {
// Деактивирована // Деактивирована
if (settings.write(group + '_' + id, true)) { if (settings.write(group + '_' + id, true)) {
// Записан статус активации // Записан статус активации
// Запуск анимации и переход в состояние активации // Запуск анимации и переход в состояние активации
button.classList.add('on'); button.classList.add('on');
settings.read(group + '_' + id).then(result => { settings.read(group + '_' + id).then(result => {
if (result[group + '_' + id] === true) { if (result === true) {
// Сохранены изменения // Сохранены изменения
// Запуск анимации // Запуск анимации
status.style.transition = '0.5s'; status.style.transition = '0.5s';
status.style.opacity = 1; status.style.opacity = 1;
@ -384,65 +453,394 @@ class page {
} }
}); });
// Инициализация разделителя кнопки активации
let separator = document.createElement('div');
separator.classList.add('settings_separated_row_extra');
separator.checked = result[id] === true || result[id] === 1 || result[id] === '1' ? true : false;
// Инициализация кнопки активации // Инициализация кнопки активации
let button = document.createElement('div'); const button = document.createElement('div');
button.classList.add('ui_toggler_wrap'); button.classList.add('ui_toggler_wrap');
// Инициализация элемента-иконки кнопки активации // Инициализация элемента-иконки
let checkbox = document.createElement('div'); const checkbox = document.createElement('div');
checkbox.classList.add('_ui_toggler', 'ui_toggler', '_settings_ienable'); checkbox.classList.add('_ui_toggler', 'ui_toggler', '_settings_ienable');
if (typeof onchange === 'string') checkbox.setAttribute('onchange', onchange);
settings.read(group + '_' + id).then(result => { settings.read(group + '_' + id).then(result => {
// Получены данные о значении настройки // Получены данные о значении настройки
// Запись состояния // Запись состояния
if (result[group + '_' + id]) if (result) checkbox.classList.add('on');
checkbox.classList.add('on');
}); });
// Инициализация элемента-иконки кнопки активации // Инициализация элемента-иконки
let label = document.createElement('div'); const label = document.createElement('div');
label.classList.add('ui_toggler_label'); label.classList.add('ui_toggler_label');
// Инициализация названия кнопки активации // Инициализация названия
let header = document.createElement('div'); const header = document.createElement('div');
header.classList.add('settings_separated_row_text'); header.classList.add('settings_separated_row_text');
// Инициализация текста названия кнопки активации // Инициализация текста названия
let title = document.createElement('div'); const colonic = document.createElement('div');
title.classList.add('settings_separated_row_text_inner'); colonic.classList.add('settings_separated_row_text_inner');
title.innerText = name !== undefined && typeof name === 'string' ? name : id; colonic.innerText = name !== undefined && typeof name === 'string' ? name : id;
// Инициализация архитектуры // Инициализация архитектуры
button.appendChild(checkbox); button.appendChild(checkbox);
separator.appendChild(button); separator.appendChild(button);
wrap.appendChild(separator); wrap.appendChild(separator);
header.appendChild(colonic);
if (typeof hint === 'string') {
// Получена подсказка
// Инициализация текста-подсказки
const question = document.createElement('span');
question.classList.add('hint_icon');
question.setAttribute('data-title', hint);
question.setAttribute('onmouseover', 'showHint(this);');
// Инициализация архитектуры
colonic.appendChild(question);
}
if (description !== undefined && typeof description === 'string') { if (description !== undefined && typeof description === 'string') {
// Получено описание // Получено описание
// Инициализация текста описания кнопки активации
let text = document.createElement('div'); // Инициализация текста описания
const text = document.createElement('div');
text.classList.add('settings_separated_row_hint'); text.classList.add('settings_separated_row_hint');
text.innerText = description; text.innerText = description;
// Инициализация архитектуры // Инициализация архитектуры
title.appendChild(text); colonic.appendChild(text);
} }
// Инициализация архитектуры // Инициализация архитектуры
header.appendChild(title);
wrap.appendChild(header); wrap.appendChild(header);
// Запись в блок // Запись в блок
body.appendChild(wrap); body.appendChild(wrap);
return true; return true;
}
);
}
return false;
};
},
/**
* Генерация HTML-элемента настройки с полем для ввода текста
*
* @param {string} id Идентификатор
* @param {string|null} icon Иконка
* @param {string|null} name Название
* @param {string|null} description Описание
* @param {string|null} hint Всплывающая подсказка (иконка с вопросительным знаком возле верхнего колонтинула)
* @param {string|null} type Тип поля для ввода (HTML-категории: text, password, email, number)
* @param {number|null} min Ограничение по минимальному количеству символов
* @param {number|null} max Ограничение по максимальному количеству символов
* @param {string|null} title Текст выводимый во всплывающем окне при наведении курсора
* @param {string|null} placeholder Текст отображаемый в поле для ввода если оно пустое
* @param {string|null} pattern Шаблон значений которые позволено вводить в поле
* @param {boolean|null} readonly Запретить редактирование
* @param {boolean|null} spellcheck Использовать проверку орфографии
* @param {object|null} options Массив со строками для автозаполнения поля
* @param {string|null} onchange Код который выполняется после изменения состояния
* @param {string|null} oninput Код который выполняется при вводе текста
*
* @return {function} Функция для выполнения в генераторе группы
*
* @todo 1. Добавить проверку на существование нижнего колонтинула и записывать перед ним, вместо конца блока
*/
text(id, icon, name, description, hint, type = 'text', min = 0, max = 100, title, placeholder, pattern, readonly, spellcheck, options, onchange, oninput) {
// Инициализация ядра
const core = this.core;
/**
* Запись в группу (подразумевается выполнение в функции генерирующей группу)
*
* @param {string} group Группа
*
* @return {bool} Статус выполнения
*/
return function (group) {
if (typeof id === 'string' && typeof icon === 'string' && typeof core === 'object' && typeof group === 'string') {
// Пройдена проверка входных параметров
return core.blocks.fields.macros(group, icon,
function (status, body, wrap, separator) {
wrap.addEventListener("input", fn => {
// Инициализация поля ввода
const input = wrap.getElementsByTagName('input')[0];
if (settings.write(group + '_' + id, input.value)) {
// Записано значение поля
// Запуск анимации
settings.read(group + '_' + id).then(result => {
if (result === input.value) {
// Сохранены изменения
// Запуск анимации
status.style.transition = '0.5s';
status.style.opacity = 1;
setTimeout(fn => {
status.style.transition = '1.5s';
status.style.opacity = 0;
}, 1000);
}
}); });
} }
});
// Инициализация элемента для ввода текста
const input = document.createElement('input');
input.classList.add('dark');
input.setAttribute('type', type);
input.setAttribute(type === 'number' ? 'min' : 'minlength', min);
input.setAttribute(type === 'number' ? 'max' : 'maxlength', max);
if (typeof title === 'string') input.setAttribute('title', title);
if (typeof placeholder === 'string') input.setAttribute('placeholder', placeholder);
if (typeof pattern === 'string') input.setAttribute('pattern', pattern);
if (readonly === true) input.setAttribute('readonly', readonly);
if (spellcheck === true) input.setAttribute('spellcheck', spellcheck);
input.setAttribute('list', group + '_' + id + '_datalist');
settings.read(group + '_' + id).then(result => {
// Получены данные о значении настройки
// Запись значения в поле
if (result) input.value = result;
});
if (typeof onchange === 'string') input.setAttribute('onchange', onchange);
if (typeof oninput === 'string') input.setAttribute('oninput', oninput);
if (typeof options === 'object' && options.length > 0) {
// Инициализация элемента-списка для выбора значений автозаполнения
const datalist = document.createElement('datalist');
datalist.id = group + '_' + id + '_datalist';
for (const option of options) {
// Перебор значений для автозаполнения поля
// Инициализация элемента со значением автозаполнения
const element = document.createElement('option');
element.setAttribute('value', option);
// Запись в список
datalist.appendChild(element);
}
}
// Инициализация элемента-иконки
const label = document.createElement('div');
label.classList.add('ui_toggler_label');
// Инициализация названия
const header = document.createElement('div');
header.classList.add('settings_separated_row_text');
// Инициализация текста названия
const colonic = document.createElement('div');
colonic.classList.add('settings_separated_row_text_inner');
colonic.innerText = name !== undefined && typeof name === 'string' ? name : id;
// Инициализация архитектуры
separator.appendChild(input);
if (typeof datalist === 'object') separator.appendChild(datalist);
wrap.appendChild(separator);
header.appendChild(colonic);
if (typeof hint === 'string') {
// Получена подсказка
// Инициализация текста-подсказки
const question = document.createElement('span');
question.classList.add('hint_icon');
question.setAttribute('data-title', hint);
question.setAttribute('onmouseover', 'showHint(this);');
// Инициализация архитектуры
colonic.appendChild(question);
}
if (description !== undefined && typeof description === 'string') {
// Получено описание
// Инициализация текста описания
const text = document.createElement('div');
text.classList.add('settings_separated_row_hint');
text.innerText = description;
// Инициализация архитектуры
colonic.appendChild(text);
}
// Инициализация архитектуры
wrap.appendChild(header);
// Запись в блок
body.appendChild(wrap);
return true;
}
);
}
return false;
};
},
/**
* Генерация HTML-элемента настройки с всплывающим списком
*
* @param {string} id Идентификатор
* @param {string|null} icon Иконка
* @param {string|null} name Название
* @param {string|null} description Описание
* @param {string|null} hint Всплывающая подсказка (иконка с вопросительным знаком возле верхнего колонтинула)
* @param {string|null} type
* @param {string|null} button
* @param {object|null} options Массив со строками для автозаполнения поля
* @param {string|null} onclick
* @param {string|null} onchange Код который выполняется после изменения состояния
* @param {string|null} oninput Код который выполняется при вводе текста
*
* @return {function} Функция для выполнения в генераторе группы
*
* @todo 1. Добавить проверку на существование нижнего колонтинула и записывать перед ним, вместо конца блока
*/
button(id, icon, name, description, hint, type = 'dropdown', value = 'Выбрать', onclick, onchange, oninput) {
// Инициализация ядра
const core = this.core;
/**
* Запись в группу (подразумевается выполнение в функции генерирующей группу)
*
* @param {string} group Группа
*
* @return {bool} Статус выполнения
*/
return function (group) {
if (typeof id === 'string' && typeof icon === 'string' && typeof core === 'object' && typeof group === 'string') {
// Пройдена проверка входных параметров
return core.blocks.fields.macroses.row(group, icon,
function (status, body, wrap, separator) {
wrap.addEventListener("input", fn => {
// Инициализация поля ввода
const input = wrap.getElementsByTagName('input')[0];
if (settings.write(group + '_' + id, input.value)) {
// Записано значение поля
// Запуск анимации
settings.read(group + '_' + id).then(result => {
if (result === input.value) {
// Сохранены изменения
// Запуск анимации
status.style.transition = '0.5s';
status.style.opacity = 1;
setTimeout(fn => {
status.style.transition = '1.5s';
status.style.opacity = 0;
}, 1000);
}
});
}
});
// Инициализация элемента-кнопки
const button = document.createElement('a');
button.innerText = value;
if (typeof onchange === 'string') button.setAttribute('onchange', onchange);
if (typeof oninput === 'string') button.setAttribute('oninput', oninput);
if (type === 'dropdown') {
// Инициализация всплывающего списка
// Инициализация элемента-кнопки
button.setAttribute('onclick', 'return Privacy.show(this, event, \'mail\');' + typeof onclick === 'string' ? ' ' + onclick : '');
// Инициализация элемента-списка
const dropdown = core.blocks.fields.macroses.dropdown();
// Инициализация архитектуры
separator.appendChild(button);
} else if (type === 'popup') {
// Инициализация всплывающего окна
// Инициализация элемента-кнопки
button.setAttribute('href', '#');
button.setAttribute('onclick', 'return Settings.showGroupMessagesNotifyBox(event, \'settings\');' + typeof onclick === 'string' ? ' ' + onclick : '');
// Инициализация архитектуры
separator.appendChild(button);
} else if (type === 'button') {
// Инициализация кнопки
// Инициализация элемента-кнопки
if (typeof onclick === 'string') button.setAttribute('onclick', onclick);
// Инициализация архитектуры
separator.appendChild(button);
}
// Инициализация элемента-иконки
const label = document.createElement('div');
label.classList.add('ui_toggler_label');
// Инициализация названия
const header = document.createElement('div');
header.classList.add('settings_separated_row_text');
// Инициализация текста названия
const colonic = document.createElement('div');
colonic.classList.add('settings_separated_row_text_inner');
colonic.innerText = name !== undefined && typeof name === 'string' ? name : id;
// Инициализация архитектуры
separator.appendChild(button);
wrap.appendChild(separator);
header.appendChild(colonic);
if (typeof hint === 'string') {
// Получена подсказка
// Инициализация текста-подсказки
const question = document.createElement('span');
question.classList.add('hint_icon');
question.setAttribute('data-title', hint);
question.setAttribute('onmouseover', 'showHint(this);');
// Инициализация архитектуры
colonic.appendChild(question);
}
if (description !== undefined && typeof description === 'string') {
// Получено описание
// Инициализация текста описания
const text = document.createElement('div');
text.classList.add('settings_separated_row_hint');
text.innerText = description;
// Инициализация архитектуры
colonic.appendChild(text);
}
// Инициализация архитектуры
wrap.appendChild(header);
// Запись в блок
body.appendChild(wrap);
return true;
}
);
}
return false; return false;
}; };