Chrome extension: content script to popup? - google-chrome-extension

This extension scans DOM for text with V + digits e.g. V123, V333, V1, V21321321, and if the text is hovered it will send an API request from content.js and returns data. But the data should be displayed in popup and I can't seem to set it using document.getElementById('headline').innerHTML = data because it is null. Is there a way around it?
manifest.json
{
"manifest_version": 2,
"name": "AAAAA",
"description": "AAAAA Descriptionnnnnn",
"version": "1.0",
"browser_action": {
"default_popup": "popup.html"
},
"content_scripts": [
{
"matches": ["*://*/*"],
"js": ["content.js"],
"run_at": "document_end"
}
],
"permissions": [
"*://*/*"
]
}
popup.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div id="headline" class="headline" style="background-color: #ccc; width: 300px;">
This is a headline
</div>
</body>
</html>
content.js
const elements = document.getElementsByTagName('*')
// loop through all element
for (let x = 0; x < elements.length; x++) {
let element = elements[x]
// loop through all nodes in an element
for (let y = 0; y < element.childNodes.length; y++) {
let node = element.childNodes[y]
// if node is a text node
if (node.nodeType === 3) {
const searchText = new RegExp(/V\d+/gi)
const text = node.nodeValue
const matchFound = text.match(searchText)
if (matchFound) {
element.classList.add('serialcode')
}
}
}
}
const serials = document.getElementsByClassName('serialcode')
const url = 'https://jsonplaceholder.typicode.com/todos/1'
Array.from(serials).forEach((serial) => {
serial.addEventListener('mouseover', () => {
let getData = async () => {
const response = await fetch(url, {
method: 'get'
})
return response.json()
}
getData().then(data => {
document.getElementById('headline').innerHTML = data
console.log(data)
})
})
})

Related

Upload Recorded Screen Via Socket.io Not Working

i'm trying to make a zoom/google meet clone.. and i'm using RecordRTC to record the screen and then send it the Node Server via socket.io ...sometimes i get data , and sometimes i don't,..
however i tried to do the same code with websocket ... i didn't get any problem .. always work ... that even made me wonder more,
Please help Me figure the problem where and why ... thank you..
Server Side [Node] :
const express = require('express');
const chalk = require('chalk');
const socketio = require('socket.io')
require('dotenv').config();
const PORT = process.env.PORT || 5000;
const app = express();
app.use(express.static(__dirname + '/public'))
const server = app.listen(PORT, () => {
console.log(chalk.yellowBright.inverse.bold(`Server is Running on PORT ${PORT}`))
})
function writeToDisk(dataURL, fileName) {
var fileExtension = fileName.split('.').pop(),
fileRootNameWithBase = './uploads/' + fileName,
filePath = fileRootNameWithBase,
fileID = 2,
fileBuffer;
// #todo return the new filename to client
while (fs.existsSync(filePath)) {
filePath = fileRootNameWithBase + '(' + fileID + ').' + fileExtension;
fileID += 1;
}
dataURL = dataURL.split(',').pop();
fileBuffer = new Buffer(dataURL, 'base64');
fs.writeFileSync(filePath, fileBuffer);
console.log('filePath', filePath);
}
const io = socketio(server)
io.on('connect', (socket) => {
console.log("Client Has Been Connected")
socket.emit('messageFromServer', { text:'You Are Connected To The Server!'})
socket.on('fromClient',(data)=>{
console.log(chalk.red.bold(data))
if (data.data.video) {
console.log(chalk.red.bold("Video Found"))
writeToDisk(data.data.video.dataURL, fileName + '.webm');
}
})
})
Client Side [Javascript]
var recordButton = document.getElementById('start-recording');
var stopButton = document.getElementById('stop-recording');
var local_video = document.querySelector("#local-video")
const socketio = io('http://localhost:3000/')
console.log('Hello World')
socketio.on('connect', () => {
console.log(socketio.id)
})
function invokeGetDisplayMedia(success, error) {
var displaymediastreamconstraints = {
video: {
displaySurface: 'monitor', // monitor, window, application, browser
logicalSurface: true,
cursor: 'always' // never, always, motion
}
};
displaymediastreamconstraints = {
video: true
};
if (navigator.mediaDevices.getDisplayMedia) {
navigator.mediaDevices.getDisplayMedia(displaymediastreamconstraints).then(success).catch(error);
}
else {
navigator.getDisplayMedia(displaymediastreamconstraints).then(success).catch(error);
}
}
function captureScreen(callback) {
invokeGetDisplayMedia(function (screen) {
callback(screen);
}, function (error) {
console.error(error);
alert('Unable to capture your screen. Please check console logs.\n' + error);
});
}
function startRecording() {
captureScreen(function (stream) {
mediaStream = stream;
local_video.srcObject = stream;
var videoOnlyStream = new MediaStream();
stream.getVideoTracks().forEach(function (track) {
videoOnlyStream.addTrack(track);
});
recordVideo = RecordRTC(videoOnlyStream, {
type: 'video/webm',
canvas: {
width: 1280,
height: 720
},
mandatory: {
// chromeMediaSource: 'screen',
minWidth: 1280,
minHeight: 720,
maxWidth: 1920,
maxHeight: 1080,
minAspectRatio: 1.77
},
recorderType: !!navigator.mozGetUserMedia ? MediaStreamRecorder : WhammyRecorder
});
recordVideo.startRecording();
stopButton.disabled = false;
});
}
function stopRecording() {
recordButton.disabled = false;
stopButton.disabled = true;
// stop video recorder
recordVideo.stopRecording(function () {
recordVideo.getDataURL(function (videoDataURL) {
var files = {
video: {
type: recordVideo.getBlob().type || 'video/webm',
dataURL: videoDataURL
}
};
const data = JSON.stringify(files)
console.log(data)
socketio.emit('fromClient', { "message": "Sent from client!", "data": data });
console.log('EMIT: fromClient');
if (mediaStream) mediaStream.stop();
});
});
}
recordButton.onclick = function () {
recordButton.disabled = true;
startRecording();
}
stopButton.onclick = function () {
stopButton.disabled = true;
stopRecording();
}
HTML :
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>RealTime Record</title>
</head>
<body>
<center>
<h1>Testing Recording</h1>
</center>
<center>
<div class="record-action">
<button id="start-recording">Start Recording</button>
<button id="stop-recording" disabled>Stop Recording</button>
<button id="fromClient">From Client</button>
</div>
<video id="local-video" autoplay style="border: 1px solid rgb(15, 158, 238);"></video>
</center>
<script src="RecordRTC.js"></script>
<script src="/socket.io/socket.io.js"></script>
<script src="client.js"></script>
</body>
</html>

Is there a problem with dialog.showOpenDialog in Electron on Windows?

I'm working on an example out of a book and can't seem to get past this. When I hit Ctrl-o it shows the dialog to open a file, but it never loads in the file into the markup editor. However, if I run it using the debugger in VSCode it works fine.
I believe the problem is with this section:
dialog.showOpenDialog(window, options, paths => {
if (paths && paths.length > 0) {
const content = fs.readFileSync(paths[0]).toString();
window.webContents.send('load', content);
}
});
This is my menu.js file:
const {
app,
Menu,
shell,
ipcMain,
BrowserWindow,
globalShortcut,
dialog
} = require('electron');
const fs = require('fs');
function saveFile() {
console.log('Saving the file');
const window = BrowserWindow.getFocusedWindow();
window.webContents.send('editor-event', 'save');
}
function loadFile() {
console.log('loadFile confirmation');
const window = BrowserWindow.getFocusedWindow();
const options = {
title: 'Pick a markdown file',
filters: [
{ name: 'Markdown files', extensions: ['md'] },
{ name: 'Text files', extensions: ['txt'] }
]
};
dialog.showOpenDialog(window, options, paths => {
if (paths && paths.length > 0) {
const content = fs.readFileSync(paths[0]).toString();
window.webContents.send('load', content);
}
});
}
app.on('ready', () => {
globalShortcut.register('CommandOrControl+S', () => {
saveFile();
});
globalShortcut.register('CommandorControl+O', () => {
console.log('Ctrl-O received');
loadFile();
});
});
ipcMain.on('save', (event, arg) => {
console.log(`Saving content of the file`);
console.log(arg);
const window = BrowserWindow.getFocusedWindow();
const options = {
title: 'Save markdown file',
filters: [
{
name: 'MyFile',
extensions: ['md']
}
]
};
//Broken code from book apparently: dialog.showSaveDialog(window, options, filename => {
let filename = dialog.showSaveDialogSync(window, options);
console.log(filename);
if (filename) {
console.log(`Saving content to the file: ${filename}`);
fs.writeFileSync(filename, arg);
}
//Broken code from book apparently });
});
ipcMain.on('editor-reply', (event, arg) => {
console.log(`Receieved reply from web page: ${arg}`);
});
const template = [
{
label: 'Format',
submenu: [
{
label: 'Toggle Bold',
click() {
const window = BrowserWindow.getFocusedWindow();
window.webContents.send('editor-event',
'toggle-bold'
);
}
}
]
}
];
if (process.env.DEBUG) {
template.push({
label: 'Debugging',
submenu: [
{
label: 'Dev Tools',
role: 'toggleDevTools'
},
{type: 'separator' },
{
role: 'reload',
accelerator: 'Alt+R'
}
]
});
}
const menu = Menu.buildFromTemplate(template);
module.exports = menu;
My index.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta
http-equiv="Content-Security-Policy"
content="script-src 'self' 'unsafe-inline';" />
<style>
html, body {
height: 100%;
display: flex;
flex: 1;
flex-direction: column;
}
.CodeMirror {
flex: 1;
}
</style>
<title>Document</title>
<link rel="stylesheet" href="./node_modules/simplemde/dist/simplemde.min.css">
<script src="./node_modules/simplemde/dist/simplemde.min.js"></script>
</head>
<body>
<textarea id="editor"></textarea>
<script>
var editor = new SimpleMDE({
element: document.getElementById('editor')
});
const { ipcRenderer } = require('electron');
ipcRenderer.on('editor-event', (event, arg) => {
console.log(arg);
event.sender.send('editor-reply', `Received ${arg}`);
if (arg === 'toggle-bold') {
editor.toggleBold();
}
if (arg === 'save') {
event.sender.send('save', editor.value());
}
});
ipcRenderer.on('load', (event, content) => {
if (content) {
editor.value(content);
}
});
ipcRenderer.send('editor-reply', 'Page Loaded');
</script>
</body>
</html>
In recent versions of Electron, as stated in the relevant documentation: dialog.showOpenDialog () is no longer making use of a callback function, but is now returning a promise, so the .then syntax must be used instead:
function loadFile() {
console.log('loadFile confirmation');
const window = BrowserWindow.getFocusedWindow();
const options = {
title: 'Pick a markdown file',
filters: [
{ name: 'Markdown files', extensions: ['md'] },
{ name: 'Text files', extensions: ['txt'] }
]
};
dialog.showOpenDialog(window, options).then
(
result => {
if (!result.canceled)
{
let paths = result.filePaths;
if (paths && paths.length > 0) {
const content = fs.readFileSync(paths[0]).toString();
console.log (content);
// window.webContents.send('load', content);
}
}
}
);
}
loadFile();
Alternatively, you can use the dialog.showOpenDialogSync () function, which directly returns an array of file paths, or undefined if the dialog has been cancelled by the user...
TLDR: change the callback for dialog.showOpenDialog inside loadFile to:
dialog.showOpenDialog(window, options, (canceled, paths) => {
Instead of:
dialog.showOpenDialog(window, options, paths => {
Long version:
The callback for dialog.showOpenDialog passes in 3 arguments:
canceled
filePaths
And only on mac: bookmarks
You wanted the 2nd argument filePaths, although if your callback was just: paths => { expecting only one argument Electron would pass in the canceled argument because it's the first and you only said you wanted one argument.
So this means you need to pass in an argument before paths like: (canceled, paths) => {
See the docs

Slow loading web page served by Node.js HTTP server

I'm trying to create an HTTP server using Node.js where I can stream video files using video.js player. But it's taking a long time loading the web page.
I've tried to encode HTML codes Javascript files and CSS files using gzip, but it didn't improve the loading speed.
Here is my code:
const http = require('http');
const fs = require('fs');
const url = require('url');
const path = require('path');
const zlib = require('zlib');
const mime = require('mime');
http.createServer((req, res) => {
let uri = url.parse(req.url).pathname;
// Serve index page for root path
if (uri !== '/') {
let filename = path.join("./", uri);
fs.exists(filename, exists => {
if (!exists) {
res.writeHead(404);
res.end();
} else {
let stat = fs.statSync(filename);
let headers = {
'Accept-Ranges': 'bytes',
'Content-Type' = mime.getType(filename),
'Content-Length': stat.size,
'Vary': 'Accept-Encoding'
};
// Handle `Accept-Ranges` header
let range = req.headers.range;
let stream;
if (range) {
let parts = range.replace(/bytes=/, '').split('-');
let start = parseInt(parts[0]);
let end = parts[1] ? parseInt(parts[1]) : stat.size - 1;
let chunk_size = end - start + 1;
stream = fs.createReadStream(filename, {start, end});
headers['Content-Length'] = chunk_size;
headers['Content-Range'] = `bytes ${start}-${end}/${stat.size}`;
} else {
stream = fs.createReadStream(filename);
}
stream.on('error', err => {
res.writeHead(500);
res.end();
});
// gzip encode javascript and css files.
if (/\.(js)|(css)$/.test(filename.toLowerCase())) {
let gzip = zlib.createGzip();
gzip.on('error', err => {
throw err;
});
headers['Content-Encoding'] = 'gzip';
res.writeHead(200, headers);
stream.pipe(gzip).pipe(res);
} else {
if (range) {
res.writeHead(206, headers);
} else {
res.writeHead(200, headers);
}
stream.pipe(res);
}
}
});
} else {
let page = `<!DOCTYPE html>
<html lang="en">
<head>
<title>Video</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, height=device-height, initial-scale=1.0, minimum-scale=1.0">
<link rel="shortcut icon" href="favicon.ico">
<link rel="stylesheet" type="text/css" href="assets/css/video-js.min.css">
<script src="assets/js/video.min.js"></script>
</head>
<body>
<div id="video_area">
<video id="video" class="video-js vjs-big-play-centered">
<source src="video.mkv" type="video/webm"/>
<track kind="subtitles" lang="en" src="en.vtt" default/>
</video>
</div>
<script>
window.player = videojs('video', {
controls: true,
autoplay: false,
preload: 'auto',
fluid: true,
playbackRates: [0.5, 1, 1.5, 2]
});
</script>
</body>
</html>`;
let headers = {
'Accept-Ranges': 'bytes',
'Content-Encoding': 'gzip',
'Content-Length': Buffer.byteLength(page),
'Content-Type': 'text/html'
};
res.writeHead(200, headers);
zlib.gzip(page, (err, data) => {
if (err) {
log.e(err);
throw err;
}
res.end(data);
});
}
}).listen(80);
This is a screenshot I captured from my Google Chrome's DevTools.
First of all make sure the video autoplay is set to false and preload="none"
In your code add async
http.createServer(async(req, res)
now put html in a function and in your else block execute that function with await
else{
await htmlFunction()
}

Sending message from popup to content script - Chrome Extension

I want to update the html in popup.html when I open it through the browser action button. The popup.js should send a message to the content script running on the current tab, and should receive a response and update the html. However the content script does not receive any message, therefore not sending a proper response.
Content.js
var text = "hello";
chrome.runtime.onMessage.addListener(
function(message, sender, sendResponse) {
switch(message.type) {
case "getText":
sendResponse(text);
break;
}
}
);
Popup.js
chrome.tabs.getCurrent(function(tab){
chrome.tabs.sendMessage(tab.id, {type:"getText"}, function(response){
alert(response)
$("#text").text(response);
});
});
Manifest.json
{
"manifest_version": 2,
"name": "It's Just A Name",
"description": "This extension is able to",
"version": "1.0",
"permissions" : ["tabs"],
"browser_action": {
"default_icon": "icon.png",
"default_popup": "popup.html",
"default_title": "Click here!"
},
"content_scripts": [
{
"matches": ["https://*/*"],
"js": ["jquery.min.js","content.js"]
}]
}
Popup.html
<!doctype html>
<html>
<head>
<title>Title</title>
<style>
body {
font-family: "Segoe UI", "Lucida Grande", Tahoma, sans-serif;
font-size: 100%;
}
#status {
white-space: pre;
text-overflow: ellipsis;
overflow: hidden;
max-width: 400px;
}
</style>
<script src="popup.js"></script>
</head>
<body>
<p id="text"></p>
</body>
</html>
chrome.tabs.getCurrent uses for:
Gets the tab that this script call is being made from
Your popup.js should be:
chrome.tabs.query({active: true, currentWindow: true}, function(tabs) {
chrome.tabs.sendMessage(tabs[0].id, {type:"getText"}, function(response){
alert(response)
$("#text").text(response);
});
});
To add to above answer, You often want to send a msg from a popup to all tabs, so
popup:
chrome.tabs.query({}, tabs => {
tabs.forEach(tab => {
chrome.tabs.sendMessage(tab.id, msgObj);
});
});
content script:
chrome.runtime.onMessage.addListener(msgObj => {
// do something with msgObj
});
As per the latest docs you can also try the following:
popup:
(async () => {
const [tab] = await chrome.tabs.query({active: true, lastFocusedWindow: true});
const response = await chrome.tabs.sendMessage(tab.id, {greeting: "hello"});
// do something with response here, not outside the function
console.log(response);
})();
content_script:
chrome.runtime.onMessage.addListener(
function(request, sender, sendResponse) {
console.log(sender.tab ?
"from a content script:" + sender.tab.url :
"from the extension");
if (request.greeting === "hello")
sendResponse({farewell: "goodbye"});
}
);
Message passing docs!

Chrome extension: callback in backgroud.js to popup.js

I have simple Chrome extension to show temperature from Json.
Background.js: how to pass response temp to ??? in popup.html????
Manifest ist OK.
manifest:
{
"name": "AlarmText",
"version": "0.0.1",
"manifest_version": 2,
"permissions": ["alarms", "http://api.openweathermap.org/data/2.5/weather?q=London"],
"icons": { "128": "icons/icon128.png",
"64": "icons/icon64.png",
"32": "icons/icon32.png" },
"browser_action": {
"default_title": "Alarm test",
"default_popup": "popup.html"
},
"background": {
"scripts": ["background.js"],
"persistent": true
}
}
In popup I will show temp from URL. In div id="out", popup.html:
<!doctype html>
<html>
<head>
<title>popup</title>
<script src="popup.js"></script>
<script src="background.js"></script>
</head>
<body>
<div id="out">???</div>
<button id="checkPage">Refresh</button>
</body>
</html>
In popup.js is call alarm to get temp. popup.js:
document.addEventListener('DOMContentLoaded', function() {
var checkPageButton = document.getElementById('checkPage');
checkPageButton.addEventListener('click', function() {
chrome.runtime.sendMessage({greeting: "alert"}, function(response) {
alert("response");
document.getElementById('out').innerHTML = response.farewell;
document.getElementById('checkPage').innerHTML = response.farewell;
});
}, false);
}, false);
In background.js is problem :-) How write data to div in popup.html? Why don't work sendResponse in callback function?
background.js
function getTemp(callback) {
var xhr = new XMLHttpRequest();
xhr.open ("GET", "http://api.openweathermap.org/data/2.5/weather?q=London", true);
xhr.onreadystatechange = function() {
if (xhr.readyState == 4 && xhr.status == 200) {
// defensive check
if (typeof callback == "function") {
// apply() sets the meaning of "this" in the callback
callback.apply(xhr);
}
}
}
// send the request *after* the event handler is defined
xhr.send();
}
//alarm
chrome.runtime.onMessage.addListener(
function(request, sender, sendResponse) {
if (request.greeting == "alert"){
alert("alert alarm");
getTemp(function() {
responseArray = JSON.parse(this.responseText);
//#TODO how to pass response temp to <div id="out">???</div> in popup.html????
alert("response get temp: " + responseArray["main"]["temp"]);
sendResponse({farewell: "goodbye"});
});
}
}
);
Thank :-)

Resources