mirror of
https://github.com/anatolykopyl/vk-mute.git
synced 2026-03-26 12:55:13 +00:00
Refactoring and add build-tools
This commit is contained in:
14
src/background/background.js
Normal file
14
src/background/background.js
Normal file
@@ -0,0 +1,14 @@
|
||||
chrome.runtime.onInstalled.addListener(function () {
|
||||
chrome.storage.sync.set({ isExtensionOn: true }, function () {
|
||||
console.log('isExtensionOn: ' + true);
|
||||
});
|
||||
|
||||
chrome.declarativeContent.onPageChanged.removeRules(undefined, function () {
|
||||
chrome.declarativeContent.onPageChanged.addRules([{
|
||||
conditions: [new chrome.declarativeContent.PageStateMatcher({
|
||||
pageUrl: { hostEquals: 'vk.com' },
|
||||
})],
|
||||
actions: [new chrome.declarativeContent.ShowPageAction()]
|
||||
}]);
|
||||
});
|
||||
});
|
||||
126
src/dom/controls.js
vendored
Normal file
126
src/dom/controls.js
vendored
Normal file
@@ -0,0 +1,126 @@
|
||||
/**
|
||||
*
|
||||
* @param id {String}
|
||||
* @return {HTMLSpanElement}
|
||||
*/
|
||||
import {getChatBody} from "../utils/getChatBody";
|
||||
|
||||
function muteBtnHTML(id) {
|
||||
const element = document.createElement('span');
|
||||
element.setAttribute('class', 'mute_message');
|
||||
element.setAttribute('id', `mute${id}`);
|
||||
element.innerHTML = `
|
||||
🔇
|
||||
<span class="mutetooltip">Заглушить</span>
|
||||
`;
|
||||
return element;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param chatBody {HTMLElement}
|
||||
* @return {function(...[*]=)}
|
||||
*/
|
||||
export function addControls(chatBody) {
|
||||
return function (event) {
|
||||
if (event.target.className === 'im-mess--check fl_l') {
|
||||
const message = event.target.parentElement;
|
||||
addControlButton(message, chatBody)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create mute button and inset it to the actionArea
|
||||
* @param actionArea {HTMLElement}
|
||||
* @param senderId {String}
|
||||
* @return {HTMLElement}
|
||||
*/
|
||||
function addMuteButton(actionArea, senderId) {
|
||||
const muteButton = muteBtnHTML(senderId);
|
||||
actionArea.appendChild(muteButton);
|
||||
muteButton.style.display = "none";
|
||||
return muteButton;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add event listeners to the actionArea
|
||||
* @param actionsArea {HTMLElement}
|
||||
*/
|
||||
function addActionAreaEvents(actionsArea) {
|
||||
actionsArea.parentElement.addEventListener("mouseenter", function (event) {
|
||||
event.target.getElementsByClassName("mute_message")[0].style.display = "inline-block";
|
||||
});
|
||||
|
||||
actionsArea.parentElement.addEventListener("mouseleave", function (event) {
|
||||
event.target.getElementsByClassName("mute_message")[0].style.display = "none";
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param chatBody {HTMLElement}
|
||||
* @return {function(...[]=)}
|
||||
*/
|
||||
function setIdToHideHandle(chatBody) {
|
||||
return function (event) {
|
||||
const clickedId = event.target.id.substr(4); // get id of sender from element id
|
||||
|
||||
chrome.storage.sync.set({idToHide: clickedId}, function () {
|
||||
hideExistingMessages(clickedId);
|
||||
console.log('idToHide: ' + clickedId);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export function hideExistingMessages(id) {
|
||||
const chatBody = getChatBody();
|
||||
for (let item of chatBody.children) {
|
||||
if (item.dataset.peer === id) {
|
||||
item.style.display = "none";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Try to add controls until successful. Needed for page refresh.
|
||||
export function createTryToInitInterval() {
|
||||
const controlsInterval = setInterval(function () {
|
||||
if(!tryToInitControls(controlsInterval)){
|
||||
clearInterval(controlsInterval);
|
||||
|
||||
}
|
||||
}, 200)
|
||||
return controlsInterval;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param message {HTMLElement}
|
||||
*/
|
||||
function addControlButton(message, chatBody) {
|
||||
const actionsArea = message.getElementsByClassName("im-mess--actions")[0];
|
||||
if (actionsArea && actionsArea.lastChild.className !== "mute_message") {
|
||||
const senderId = message.parentElement.parentElement.parentElement["dataset"].peer;
|
||||
const muteBtn = addMuteButton(actionsArea, senderId);
|
||||
addActionAreaEvents(actionsArea);
|
||||
muteBtn.addEventListener("click", setIdToHideHandle(chatBody));
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
export function tryToInitControls() {
|
||||
let status = true;
|
||||
const chatBody = getChatBody();
|
||||
if(!chatBody) return false;
|
||||
for (let item of chatBody.children) {
|
||||
if (item.className.includes('im-mess-stack _im_mess_stack')) {
|
||||
let messages = item.children[1].children[1].getElementsByClassName('im-mess im_in _im_mess');
|
||||
for (let message of messages) {
|
||||
status = addControlButton(message, chatBody)
|
||||
}
|
||||
}
|
||||
}
|
||||
return status;
|
||||
}
|
||||
49
src/dom/dom.css
Normal file
49
src/dom/dom.css
Normal file
@@ -0,0 +1,49 @@
|
||||
.mute_message .mutetooltip {
|
||||
visibility: hidden;
|
||||
width: 120px;
|
||||
background-color: #555;
|
||||
color: #fff;
|
||||
text-align: center;
|
||||
padding: 5px 0;
|
||||
border-radius: 6px;
|
||||
|
||||
/* Position the tooltip text */
|
||||
position: absolute;
|
||||
z-index: 1;
|
||||
bottom: 125%;
|
||||
left: 50%;
|
||||
margin-left: -60px;
|
||||
|
||||
/* Fade in tooltip */
|
||||
opacity: 0;
|
||||
transition: opacity 0.3s;
|
||||
}
|
||||
|
||||
/* Tooltip arrow */
|
||||
.mute_message .mutetooltip::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: 100%;
|
||||
left: 50%;
|
||||
margin-left: -5px;
|
||||
border-width: 5px;
|
||||
border-style: solid;
|
||||
border-color: #555 transparent transparent transparent;
|
||||
}
|
||||
|
||||
/* Show the tooltip text when you mouse over the tooltip container */
|
||||
.mute_message:hover .mutetooltip {
|
||||
visibility: visible;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.mute_message {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
vertical-align: top;
|
||||
/*background: url('chrome-extension://__MSG_@@extension_id__/mute.png') !important;*/
|
||||
background-repeat: no-repeat;
|
||||
padding: 6px;
|
||||
}
|
||||
28
src/dom/hide_element.js
Normal file
28
src/dom/hide_element.js
Normal file
@@ -0,0 +1,28 @@
|
||||
import {getChatBody} from "../utils/getChatBody";
|
||||
|
||||
export function addNewMessageEventListener() {
|
||||
const chatBody = getChatBody();
|
||||
chrome.storage.sync.get('idToHide', function(data) {
|
||||
let idToHide = data.idToHide;
|
||||
chatBody.addEventListener('DOMNodeInserted', function(event) {
|
||||
newMessageHandler(event.target, idToHide)
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function newMessageHandler(message, idToHide) {
|
||||
if (message.className === 'im-mess-stack _im_mess_stack ') {
|
||||
chrome.storage.sync.get('idToHide', function(data) {
|
||||
idToHide = data.idToHide;
|
||||
});
|
||||
|
||||
chrome.storage.sync.get('isExtensionOn', function(data) {
|
||||
if (data.isExtensionOn) {
|
||||
if (message.dataset.peer === idToHide) {
|
||||
message.style.display = "none";
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
20
src/dom/main.js
Normal file
20
src/dom/main.js
Normal file
@@ -0,0 +1,20 @@
|
||||
import './dom.css'
|
||||
import {createTryToInitInterval, hideExistingMessages, tryToInitControls} from "./controls";
|
||||
import {UrlController} from "../utils/Url";
|
||||
import {addNewMessageEventListener} from "./hide_element";
|
||||
|
||||
function init() {
|
||||
const url = new UrlController();
|
||||
url.onChange((oldUrl, newUrl) => {
|
||||
// chrome.storage.sync.get('idToHide', function (data) {
|
||||
// let idToHide = data.idToHide;
|
||||
// hideExistingMessages(idToHide)
|
||||
// });
|
||||
if (tryToInitControls()) {
|
||||
createTryToInitInterval();
|
||||
addNewMessageEventListener();
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
init();
|
||||
94
src/popup/popup.css
Normal file
94
src/popup/popup.css
Normal file
@@ -0,0 +1,94 @@
|
||||
body {
|
||||
min-width: 80px;
|
||||
}
|
||||
/* The switch - the box around the slider */
|
||||
.switch {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
width: 60px;
|
||||
height: 34px;
|
||||
}
|
||||
|
||||
/* Hide default HTML checkbox */
|
||||
.switch input {
|
||||
opacity: 0;
|
||||
width: 0;
|
||||
height: 0;
|
||||
}
|
||||
|
||||
/* The slider */
|
||||
.slider {
|
||||
position: absolute;
|
||||
cursor: pointer;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background-color: #ccc;
|
||||
-webkit-transition: .4s;
|
||||
transition: .4s;
|
||||
}
|
||||
|
||||
.slider:before {
|
||||
position: absolute;
|
||||
content: "";
|
||||
height: 26px;
|
||||
width: 26px;
|
||||
left: 4px;
|
||||
bottom: 4px;
|
||||
background-color: white;
|
||||
-webkit-transition: .4s;
|
||||
transition: .4s;
|
||||
}
|
||||
|
||||
input:checked + .slider {
|
||||
background-color: #2196F3;
|
||||
}
|
||||
|
||||
input:focus + .slider {
|
||||
box-shadow: 0 0 1px #2196F3;
|
||||
}
|
||||
|
||||
input:checked + .slider:before {
|
||||
-webkit-transform: translateX(26px);
|
||||
-ms-transform: translateX(26px);
|
||||
transform: translateX(26px);
|
||||
}
|
||||
|
||||
/* Rounded sliders */
|
||||
.slider.round {
|
||||
border-radius: 34px;
|
||||
}
|
||||
|
||||
.slider.round:before {
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
.header {
|
||||
background-color: #2196F3;
|
||||
color: white;
|
||||
width: 100vw;
|
||||
position: relative;
|
||||
margin-left: -50vw;
|
||||
left: 50%;
|
||||
margin-top: -20vw;
|
||||
margin-bottom: 10vw;
|
||||
padding-top: 5px;
|
||||
padding-bottom: 5px;
|
||||
}
|
||||
|
||||
#idToHide {
|
||||
margin: 10px;
|
||||
}
|
||||
|
||||
.id_list {
|
||||
background-color: #dcdfde;
|
||||
color: black;
|
||||
width: 100vw;
|
||||
position: relative;
|
||||
margin-left: -50vw;
|
||||
left: 50%;
|
||||
margin-top: 10vw;
|
||||
padding-top: 5px;
|
||||
padding-bottom: 5px;
|
||||
}
|
||||
21
src/popup/popup.html
Normal file
21
src/popup/popup.html
Normal file
@@ -0,0 +1,21 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
</head>
|
||||
<body>
|
||||
<div class="header">
|
||||
<h3 align="center" id="status"></h3>
|
||||
</div>
|
||||
<!--<button id="disableButton">Toggle</button>-->
|
||||
<div style="text-align: center;">
|
||||
<label class="switch">
|
||||
<input type="checkbox" id="disableCheckbox">
|
||||
<span class="slider round"></span>
|
||||
</label>
|
||||
</div>
|
||||
<div class="id_list">
|
||||
<div id="idToHide"></div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
47
src/popup/popup.js
Normal file
47
src/popup/popup.js
Normal file
@@ -0,0 +1,47 @@
|
||||
import './popup.css'
|
||||
|
||||
//let disableButton = document.getElementById('disableButton');
|
||||
let disableCheckbox = document.getElementById('disableCheckbox');
|
||||
let idToHideDisplay = document.getElementById('idToHide');
|
||||
let status = document.getElementById('status');
|
||||
var isExtensionOn;
|
||||
var idToHide;
|
||||
|
||||
var enableText = "Кринж офф";
|
||||
var disableText = "Кринж он";
|
||||
|
||||
chrome.storage.sync.get('isExtensionOn', function(data) {
|
||||
isExtensionOn = data.isExtensionOn;
|
||||
|
||||
disableCheckbox.checked = isExtensionOn;
|
||||
if (isExtensionOn) {
|
||||
status.innerHTML = enableText;
|
||||
} else {
|
||||
status.innerHTML = disableText;
|
||||
}
|
||||
});
|
||||
|
||||
chrome.storage.sync.get('idToHide', function(data) {
|
||||
idToHide = data.idToHide;
|
||||
idToHideDisplay.innerText = idToHide;
|
||||
});
|
||||
|
||||
disableCheckbox.addEventListener('change', (event) => {
|
||||
isExtensionOn = event.target.checked;
|
||||
if (event.target.checked) {
|
||||
status.innerHTML = enableText;
|
||||
} else {
|
||||
status.innerHTML = disableText;
|
||||
}
|
||||
|
||||
chrome.storage.sync.set({isExtensionOn}, function() {
|
||||
console.log('isExtensionOn: '+isExtensionOn);
|
||||
});
|
||||
});
|
||||
|
||||
idToHideDisplay.addEventListener('click', function() {
|
||||
chrome.storage.sync.set({idToHide: ''}, function() {
|
||||
idToHideDisplay.innerText = '';
|
||||
console.log('Cleared idToHide');
|
||||
});
|
||||
});
|
||||
47
src/utils/Url.js
Normal file
47
src/utils/Url.js
Normal file
@@ -0,0 +1,47 @@
|
||||
const INTERVAL_TIME = 100;
|
||||
|
||||
export class UrlController {
|
||||
|
||||
constructor() {
|
||||
this._changeListeners = [];
|
||||
this._interval = null;
|
||||
this._url = window.location.href;
|
||||
}
|
||||
|
||||
onChange(cb) {
|
||||
this._changeListeners.push(cb);
|
||||
if (this._interval === null) {
|
||||
this._createInterval();
|
||||
}
|
||||
}
|
||||
|
||||
removeEventListener(cb) {
|
||||
this._changeListeners = this._changeListeners.filter(item=>item !== cb);
|
||||
if(this._changeListeners.length === 0) {
|
||||
this._clearInterval();
|
||||
}
|
||||
}
|
||||
|
||||
_intervalTick() {
|
||||
const currentUrl = window.location.href;
|
||||
if (currentUrl !== this.url) {
|
||||
this._broadcast(this.url, currentUrl);
|
||||
this.url = currentUrl;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
_broadcast(oldUrl, newUrl) {
|
||||
this._changeListeners.forEach(cb => cb(oldUrl, newUrl));
|
||||
}
|
||||
|
||||
_createInterval() {
|
||||
this.interval = setInterval(() => this._intervalTick(), INTERVAL_TIME)
|
||||
}
|
||||
|
||||
_clearInterval() {
|
||||
clearInterval(this.interval)
|
||||
this.interval = null
|
||||
}
|
||||
|
||||
}
|
||||
3
src/utils/getChatBody.js
Normal file
3
src/utils/getChatBody.js
Normal file
@@ -0,0 +1,3 @@
|
||||
export function getChatBody() {
|
||||
return document.getElementsByClassName("_im_peer_history im-page-chat-contain")[0];
|
||||
}
|
||||
Reference in New Issue
Block a user