How to make code in a Firefox Extension execute on a timer - firefox-addon

Today is my first day working with firefox extensions.
Basically I am making an extension that will be used on an internal network to check a web server for new notifications.
I used the wizard on the mozilla page to make a skeleton extension and then mainly edited overlay.js with some ajax code.
I am using the "load" event listener to call a setTimeout to my ajax call which then loops with setTimeouts.
The problem appears to be that the "load" event listener is executed on each new browser window. I just want one global timer for this to work off of.
Any ideas?
Update:
I found this: https://developer.mozilla.org/en/JavaScript_code_modules/Using
which seems like what i would want. The problem is I can't figure out how to import the jsm file. What is the directory structure?
Update:
When trying this:
chrome.manifest
content spt chrome/content/
skin spt classic/1.0 chrome/skin/
locale spt en-US chrome/locale/en-US/
overlay chrome://browser/content/browser.xul chrome://spt/content/ff-overlay.xul
style chrome://global/content/customizeToolbar.xul chrome://spt/skin/overlay.css
resource mycontent chrome/content/
First 5 lines of chrome/content/overlay.js
try{
Components.utils.import("resource://spt/mycontent/ajax.jsm");
}catch(err){
alert(err);
}
I get this error:
[Exception... "Component returned failure code: 0x80040111 (NS_ERROR_NOT_AVAILABLE) [nsIXPCComponents_Utils.import]" nsresult: "0x80040111 (NS_ERROR_NOT_AVAILABLE)" location: "JS frame :: chrome://spt/content/overlay.js :: :: line 2" data: no]
Or when if I remove the resource alias from chrome.manifest and use this at the beginning of overlay.js
try{
Components.utils.import("chrome://spt/content/ajax.jsm");
}catch(err){
alert(err);
}
I get this error:
[Exception... "Component returned failure code: 0x80070057 (NS_ERROR_ILLEGAL_VALUE) [nsIXPCComponents_Utils.import]" nsresult: "0x80070057 (NS_ERROR_ILLEGAL_VALUE)" location: "JS frame :: chrome://spt/content/overlay.js :: :: line 3" data: no]

Yes, if you have code that should be shared between windows (and should not be executed when a new window is loaded) and that don't need access to the chrome, use JavaScript code modules.
You can import your modules with:
Components.utils.import("resource://youraddon/your_module.jsm");
provided that you setup resource in your chrome.manifest. E.g. if you add
resource youraddon modules/
then you the file must be stored in /path/to/your/addon/modules/your_module.jsm.
Further notes:
Code modules don't have to have the file extensions .jsm. You can leave it .js. Works better sometimes with certain editors (and syntax highlighting etc).
Afaik you cannot use setTimeout in a module as it has no access to the window object. I suggest to use nsITimer.

Related

Why does Fpdi fail to extend TCPDF when using PHP8.1?

I'm using:
TCPDF version 6.4.4.
FPDI version 2.3.6
PHP Version 8.1.7 (Running on Apache and Windows Server 2012,a dev environment)
And, I don't think it's relevant but I'm also using
tcpdf-extension
These were installed with composer:
{
"require": {
"tecnickcom/tcpdf": "6.4.4",
"setasign/fpdi": "^2.0",
"naitsirch/tcpdf-extension": "dev-master"
}
}
I am also using a Java/PHP bridge. This is relevant because it changes the error message, however, I doubt this is the cause of the issue.
The problem I'm having is that Fpdi fails to extend TCPDF.
The error message I get looks like this:
PHP Fatal error: During class fetch: Uncaught Error: Call to a member function invokeBegin()
on null in http://127.0.0.1:8080/JavaBridge/java/Java.inc:557
Stack trace:
#0 http://127.0.0.1:8080/JavaBridge/java/Java.inc(56): java_Client->invokeMethod(0, 'typeExists', Array)
#1 C:\Program Files (x86)\PHP\v8.1\vendor\setasign\fpdi\src\Tcpdf\Fpdi.php(33):
java_autoload_function('setasign\\Fpdi\\F...')
...
#8 {main} in C:\Program Files (x86)\PHP\v8.1\vendor\setasign\fpdi\src\Tcpdf\Fpdi.php on line 33
It is failing to fetch a class and the php/java bridge, as a last ditch effort to load it, is attempting to fetch the missing class with a java autoloader, which it fails to do because it's not a java class. Unfortunately, it doesn't give me the full name of the class that's it is trying to load. But this error occurs in setasign\fpdi\src\Tcpdf\Fpdi.php on line 33. Which reads:
class Fpdi extends \TCPDF
My code that invokes this looks like this:
define("COMPOSER_AUTOLOADER","C:\\Program Files (x86)\\PHP\\v8.1\\vendor\\autoload.php");
require_once(COMPOSER_AUTOLOADER);
use setasign\Fpdi\Tcpdf\Fpdi;
class PDF extends Fpdi {
...//functions related to my use case
}
My code that calls this extended class:
// initiate PDF
$pdf = new PDF($data['orientation'], 'mm', USLETTER, true, 'UTF-8', false);
$pdf->setPrintHeader(false);
$pdf->setPrintFooter(false);
$pdf->SetDefaultMonospacedFont(PDF_FONT_MONOSPACED);
$pdf->SetDisplayMode('real');
$pdf->SetAutoPageBreak(true, 1);
//set margins
$pdf->SetMargins(0,0);
$pdf->SetHeaderMargin(0);
$pdf->SetFooterMargin(0);
...
$pdf->AddPage($data['orientation']);
...
$pdf->Output('newpdf.pdf', 'I');
Also probably relevant, I set up a test that uses only the TCPDF library without Fpdi and it fails to load the constants that are supposed to be set up in TCPDF_static.php. (USLETTER for instance), but if I manually define that constant, it does load the PDF as expected:
require_once("C:\\Program Files (x86)\\PHP\\v8.1\\vendor\\autoload.php");
use setasign\Fpdi\Tcpdf\Fpdi;
define ('USLETTER',array( 612.000, 792.000));
$pdf = new TCPDF('', 'in', USLETTER, true, 'UTF-8', false);
...
$pdf->AddPage();
...
$pdf->Output('newpdf.pdf', 'I');
Another detail: this code was working fine with PHP 5.6 and some older versions of TCPDF (6.2.11) and Fpdi (1.4.2). Upgrading to PHP 8.1.7 required updating these libraries.
Why is TCPDF failing to load its constants and, more importantly, why can't Fpdi extend TCPDF?

Does Electron support drag-and-dropping a file path into another application?

In C# WinForms, I could do this
var data = new DataObject(DataFormats.FileDrop, filePaths);
myControl.DoDragDrop(data, DragDropEffects.Copy);
to make another application, such as Notepad, open the file specified by filePaths. The code is similar in WPF or even in JavaFX. The file path can be any arbitrary file path that is accessible within the system, such as C:\Windows\win.ini or \\myFileServer\sharedDir\sharedFile.txt. I mean making Notepad OPEN the file, NOT displaying the file path text in its editing area. That is, I am d&d'ing a file path, not a string that contains the file path.
Can I do the same thing if I make a desktop application with Electron (only for desktops; don't care about web/mobile)? I have tested it with VS Code, which is said to be created with Electron, and when I dragged a file from its "Explorer" into Notepad, nothing happened. When I did it into Notepad++, it just displayed the file path string in its editing area, so I am guessing Electron doesn't support it, but I want to make it sure.
Yes, there even is a full example in the Electron documentation about this.
Short summary of the example code: when a specific DOM element is being dragged, the renderer sends an event to the main process. For the dragstart event to fire, the DOM element needs to have the attribute draggable="true". In this example, we pass the filename of the file to be dragged along in the message to the main process.
document.getElementById("foo").ondragstart = event => {
event.preventDefault();
ipcRenderer.send("my-drag-start", "test-file.txt");
}
The main process handles the IPC message from the renderer and starts the drag operation. Note that you need to specify an icon to be attached to the cursor during the drag operation, triggering an error message if left out.
ipcMain.on("my-drag-start", (event, filePath) => {
event.sender.startDrag({
file: path.join(__dirname, filePath),
icon: path.join(__dirname, "dnd.png"),
});
});

Import my own files into the electron renderer process

This seems really dumb, but I need help for importing some source code into the renderer process in electron:
I have an electron app:
index.html (loads window.js with a tag)
- index.js
- window.js
- useful_functions.js
In window.js, I want to import some functions from useful_functions.js, so I've tried the following:
// fails with: Uncaught SyntaxError: Unexpected identifier
import { very_useful } from './useful_functions.js';
// fails with: Uncaught ReferenceError: require is not defined
const { very_useful } = require('./useful_functions.js');
// fails with: Uncaught ReferenceError: require is not defined
require('electron').remote.require('./useful_functions.js')
I also tried the nodeIntegration flag, but that didn't help either
Note: I'm not trying to import npm modules but my own code, in an other file right next to it.
I'm looking for examples, but I only find super small samples with just the basic files. (Or huge apps like atom that would take me a while to figure out)
I don't have webpack setup for this project yet, but I'm sure there is a simpler way to do this very basic task...
Thanks for any help.
In index.html, use require() instead of loading window.js with a tag, i.e., replace:
<script src="window.js"></script>
with:
<script>require('./window.js');</script>
Then, in window.js, the following statement should work too:
const { very_useful } = require('./useful_functions.js');
Note that nodeIntegration: true is needed in the options passed to new BrowserWindow() anyway:
webPreferences:
{
nodeIntegration: true
}
See:
Node Modules
Functions and objects are added to the root of a module by
specifying additional properties on the special exports object.
Variables local to the module will be private, because the module is
wrapped in a function by Node.js (see module wrapper).
Module Wrapper
Before a module's code is executed, Node.js will wrap it with a
function wrapper that looks like the following:
(function(exports, require, module, __filename, __dirname) {
// Module code actually lives in here
});

How to access custom javascript functions via browser-console in Rails 6

For the sake of debugging the javascript-part of a Rails 6 (version 6.0.0.rc1) web application I want to use my custom javascript functions also in the Chrome console (aka. Inspect).
Back when I used just static HTML files to build a website (as opposed to using a web-framework like Rails as of right now) you would simply embed the JS file in the DOM like this
<!-- custom JS -->
<script src="js/custom.js"></script>
and could instantly access and execute all custom functions that were placed in this file.
Background:
The JS file is placed at the correct rails 6 specific directory as provided in this article: How to require custom JS files in Rails 6
Note:
The rails 6 application also uses the JS file already, since the browser shows the console log message.
Here is the full content of the JS file:
// app/javascript/packs/custom.js
console.log("loaded custom.js successfully")
function sayHello () {
console.log("Hello good Sir or Madam!")
}
Expectation: I am expecting to open the browser's (Chrome) console and be able to use the sayHello() function in the console.
However, when I do so, I get an error message in the console stating:
Uncaught ReferenceError: sayHello is not defined
Try something like
sayHello = ()=>{
console.log("Hello good Sir or Madam!");
}
then you can evoke in console:
>sayHello();

"document" in mozilla extension js modules?

I am building Firefox extension, that creates single XMPP chat connection, that can be accessed from all tabs and windows, so I figured, that only way to to this, is to create connection in javascript module and include it on every browser window. Correct me if I am wrong...
EDIT: I am building traditional extension with xul overlays, not using sdk, and talking about those modules: https://developer.mozilla.org/en-US/docs/Mozilla/JavaScript_code_modules
So I copied Strophe.js into js module. Strophe.js uses code like this:
/*_Private_ function that creates a dummy XML DOM document to serve as
* an element and text node generator.
*/
[---]
if (document.implementation.createDocument === undefined) {
doc = this._getIEXmlDom();
doc.appendChild(doc.createElement('strophe'));
} else {
doc = document.implementation
.createDocument('jabber:client', 'strophe', null);
}
and later uses doc.createElement() to create xml(or html?) nodes.
All worked fine, but in module I got error "Error: ReferenceError: document is not defined".
How to get around this?
(Larger piece of exact code: http://pastebin.com/R64gYiKC )
Use the hiddenDOMwindow
Cu.import("resource://gre/modules/Services.jsm");
var doc = Services.appShell.hiddenDOMWindow.document;
It sounds like you might not be correctly attaching your content script to the worker page. Make sure that you're using something like tabs.attach() to attach one or more content scripts to the worker page (see documentation here).
Otherwise you may need to wait for the DOM to load, waiting for the entire page to load
window.onload = function ()
{
Javascript code goes here
}
Should take at least diagnose that issue (even if the above isn't the best method to use in production). But if I had to wager, I'd say that you're not attaching the content script.

Resources