I am new to Firefox extensions and i would like you to help me pack one extension that i build and send it to some friends to test it.
My Extension is about to "block" some URLs. Which means that if someone tries to join "facebook.com" my extension should redirect him to "www.google.com"
the code is below.
const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
Cu.import('resource://gre/modules/Services.jsm');
var urls_block = [
//If URLs contain any of these elements they will be blocked or redirected,
// your choice based on code in observer line 17
'www.facebook.com',
'www.apple.com'
];
var redir_obj = {
'www.facebook.com': 'http://www.google.com/',
'www.apple.com': 'http://www.samsung.com'
}
var observers = {
'http-on-modify-request': {
observe: function (aSubject, aTopic, aData) {
console.info('http-on-modify-request: aSubject = '
+ aSubject + ' | aTopic = ' + aTopic + ' | aData = ' + aData);
var httpChannel = aSubject.QueryInterface(Ci.nsIHttpChannel);
var requestUrl = httpChannel.URI.spec.toLowerCase();
for (var i=0; i<urls_block.length; i++) {
if (requestUrl.indexOf(urls_block[i]) > -1) {
//httpChannel.cancel(Cr.NS_BINDING_ABORTED); //this aborts the load
//Can redirect with this next line, if don't want to redirect and
// just block, then comment this line and uncomment the line above:
httpChannel.redirectTo(Services.io.newURI(redir_obj[urls_block[i]],
null, null));
break;
}
}
},
reg: function () {
Services.obs.addObserver(observers['http-on-modify-request'],
'http-on-modify-request', false);
},
unreg: function () {
Services.obs.removeObserver(observers['http-on-modify-request'],
'http-on-modify-request');
}
}
};
function install() {}
function uninstall() {}
function startup() {
for (var o in observers) {
observers[o].reg();
}
}
function shutdown(aData, aReason) {
if (aReason == APP_SHUTDOWN) return;
for (var o in observers) {
observers[o].unreg();
}
}
Big thanks to #Noitidart for his enormous help.
So i want to pack this code for Firefox Extension.
Could someone show me how to do it or any example?
Thanks a lot for your time helping me here.
At a minimum, you will need to create an install.rdf file and a chrome.manifest file. Go through those links, you are going to need to make some choices (e.g. what to call your extension, an <em:id>, etc.).
In addition, it appears that you are making a bootstrap/restartless add-on and should call the file containing the code you included in the question: bootstrap.js
.xpi file format (Extension Packaging):
The .xpi files that are used as containers for Mozilla (Firefox, Thunderbird, etc.) extensions are merely zip compressed archives that have had the file extension changed to .xpi. The files start in the root directory of the zip compressed archive (i.e. there is first level directory to contain the files). The files must either be uncompressed, or compressed using the "Deflate" algorithm. Using other compression algorithms will result in your .xpi file not loading and a popup being shown that the add-on is corrupt.
The contents of the archive could be only a few files to any number of files. At a minimum, you have an install.rdf and a chrome.manifest file. There will almost always be at least one additional file (if not many additional files).
My very simple Bootstrap/Restartless extension, Print Button is Print (changes the print button to print instead of print preview), has the following structure:
Archive contains:
bootstrap.js
chrome/
chrome/content/
chrome/content/options.xul
chrome/skin/
chrome/skin/printer-typeC128.png
chrome/skin/printer-typeC32.png
chrome/skin/printer-typeC48.png
chrome/skin/printer-typeC64.png
chrome.manifest
install.rdf
license.txt
Total 12 entries (42360 bytes)
There are the required install.rdf and chrome.manifest files.
The file bootstrap.js is required for Bootstrap/Restartless extensions. It contains the code that is run when the extension is installed, removed, enabled, disabled, or upon Firefox startup or shutdown. This extension is simple enough such that all the JavaScript code is contained in bootstrap.js.
There is a file chrome/content/options.xul which is a XUL definition of the options dialog.
The license.txt just explains that the extension was released under the Mozilla Public License, v2.0.
The .png files are the icon for this extension at various resolutions.
The install.rdf file for Print Button is Print is (all instances of PrintButtonIsPrint should be changed to something for your extension which you define in your chrome.manifest file; All of them you could just delete from the instal.rdf file if you wanted to as you have no options dialog, or icons defined (yet).):
<?xml version="1.0"?>
<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:em="http://www.mozilla.org/2004/em-rdf#">
<Description about="urn:mozilla:install-manifest">
<em:id>PrintButtonIsPrint#makyen.foo</em:id> <!-- MUST be unique to your extension. -->
<em:version>1.0.1</em:version>
<em:type>2</em:type>
<em:name>Print Button is Print</em:name> <!-- Should be unique to your extension. -->
<em:bootstrap>true</em:bootstrap> <!-- Indicate that the extension is restartless -->
<em:unpack>false</em:unpack>
<em:description>Makes the Print Button print the page instead of presenting a print preview. Adds the option of using shift-left-click and/or ctrl-left-click for Print Preview (both enabled by default).</em:description>
<em:creator>Makyen</em:creator>
<!-- No about.
<em:aboutURL>chrome://PrintButtonIsPrint/content/about.xul</em:aboutURL>
-->
<em:optionsURL>chrome://PrintButtonIsPrint/content/options.xul</em:optionsURL>
<em:iconURL>chrome://PrintButtonIsPrint/skin/printer-typeC48.png</em:iconURL>
<em:icon64URL>chrome://PrintButtonIsPrint/skin/printer-typeC64.png</em:icon64URL>
<!--Firefox-->
<em:targetApplication>
<Description>
<em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id>
<em:minVersion>29.0</em:minVersion>
<em:maxVersion>37.*</em:maxVersion>
</Description>
</em:targetApplication>
</Description>
</RDF>
The chrome.manifest is (both instances of PrintButtonIsPrint should be changed to something for your extension):
content PrintButtonIsPrint chrome/content/
skin PrintButtonIsPrint classic/1.0 chrome/skin/
To create the .xpi file I use a batch file, which uses a combination of DOS and Unix/Linux (actually Cygwin) commands:
mkxpi.bat:
rm -f PrintButtonIsPrint#makyen.foo.xpi
zip -1 -r PrintButtonIsPrint#makyen.foo.xpi * -x#xpi.ignore
pause
This removes any old version of the .xpi file. It then creates a new .xpi file using, -1, minimal compression (speed of access is more important than saving space) and containing all files and subdirectories ** but ignoring all the files in the xpi.ignore text file -x#xpi.ignore. Ignoring files is used because I have other things in the directory (e.g. .git directory, .bak files auto-created from editor, etc.). Once the .xpi file is created the script executes pause so that I can verify which files were included, that there were no errors, etc. instead of just having the window disappear and assuming that everything is fine.
My xpi.ignore file is a bit long, as it accumulates cruft from various projects and is rarely cleaned out:
*.com
*.class
*.dll
*.exe
*.o
*.so
*.7z
*.dmg
*.gz
*.iso
*.jar
*.rar
*.tar
*.zip
*.log
*.sql
*.sqlite
*.svg
*/.DS_Store
*/.DS_Store?
*/._*
._*
*/.Spotlight-V100
.Spotlight-V100
*/.Trashes
.Trashes
*/ehthumbs.db
*/Thumbs.db
*.ORIG
*.bak
*OLD*
OLD/*
*/OLD/*
*.OLD
*.OLD[0-9]
*/OLD/*
*/OLD[0-9]/*
*.unknown
*.unknown[0-9]
*.updated
*.updated[0-9]
*/Copy *
*/OLD
*/OLD*
*/OLD[0-9]
*/OLD[0-9][0-9]
*/test/*
*/not in xpi/*
*/tmp
*.tmp
*/foo
*.foo
*checkpoint
.git
*/.git
.gitignore
*/.gitignore
xpi.ignore
mkclean.bat
mkclean.bat.DONTRUN
mkxpi.bat
*.xpi
*/devtools-toolbox-window.ico
*/devtools-webconsole.ico
*/JSConsoleWindow.ico
*/main-window.ico
*/places.ico
*/viewSource.ico
Installing extensions:
As to installing extensions (i.e. the .xpi file), it can be a simple matter of dragging and dropping it onto a Firefox window running the profile in which you desire it installed. For development/testing, you can have the extension be in a directory on your local drive by using a Firefox extension proxy file (create a file named as the extension's <em:id> in the profile's extensions directory containing one line with the complete path to the directory containing the extension's files). Depending on what your goal is (one profile, all profiles, all users, which OS, etc.), there are other options as to how to install extensions.
This answer was mostly copied from my answer here.
Related
a client have a download area where users can download or browse single files. Files are divided in folder, so there are documents, catalogues, newsletter and so on, and their extension can vary: they can be .pdf, .ai or simple .jpeg. He asked me if I can provide a link to download every item in a specific folder as a big, compressed file. Problem is, I'm on a Windows server, so I'm a bit clueless if there's a way. I can edit pe pages of this area, so I can include jquery and scripts with a little freedom. Any hint?
Windows archiver is TAR and you are needing to build a TARbALL (Historically all related files in one Tape ARchive)
I have a file server which is mapped as S:\ (it does not have TAR command, and Tar cannot use URL but can use device:)
For any folders contents (including sub folders) it is easy to remotely save all current files in a zip with a single command (for multiple root locations they need a loop or a list)
It will build the Tape Archive as a windows.zip using the -a (auto) switch but you need to consider the desired level of nesting by collect all contents at the desired root location.
TAR -a[other options] file.zip [folder / files]
Points to watch out for
ensure here is not an older archive
it will comment error/warnings like the two given during run, however, should complete without fail.
Once you have the zip file you can offer post as a web asset such as
<a href="\\server\folder\all.zip" download="all.zip">Get All<a>
for other notes see https://stackoverflow.com/a/68728992/10802527
I am looking to merge PDF files from two separate folders into a third folder, based on file name.
Directory structure:
FOLDER_1 = File set #1.
FOLDER_2 = File set #2.
MERGED_PDFS = Output of merged files.
FOLDER_1 contains a set of PDF files which could be named with any combination of letters, numbers and allowed symbols.
FOLDER_2 contains a set of PDFs with the exact same names as FOLDER_1. The data on these sheets is different. The files from FOLDER_2 need to be inserted into the files from FOLDER_1, at the end of the file.
The output of this merged file will be placed in the MERGED_PDFs folder, retaining the name used to match the files in FOLDER_1 and FOLDER_2.
Example:
FOLDER_1: R000135322.PDF
FOLDER_2: R000135322.PDF
MERGED_PDFS: R000135322.PDF
(MERGED_PDFS contains a merged PDF from FOLDER_1 & FOLDER_2, with the PDF from FOLDER_2 being placed at the end of the PDF in FOLDER_1.
I saw some similar examples of this being done with PDFtk, but unsure how to edit to get my expected output.
Thanks
Here's what you need to do:
Install FolderMill
Specify the Incoming folder and the Output folder for FolderMill on your PC
Since you mention that files in FOLDER_1 and files in FOLDER_2 have the same filenames, just add "Convert to PDF" action and select Multipage: "Append pages to existing document" in the options.
Click Apply changes
Start FolderMill by pressing the Play button.
Grab the files from FOLDER_1 and put them into the Incoming folder
Grab the files from FOLDER_2 and do the same.
Receive the merged PDFs from the Output folder
If the you are not sure if all the corresponding files have the same filenames, you may also need to use the "Rename" action.
FYI, we have a detailed step-by-step guide how to do it (with screenshots).
You are welcome :)
I have an IDML file that I unzipped. I now want to compress the expanded folder back into an IDML file. I have access to a Mac or Linux machine.
What are the ways I can do this?
Zipping the file using zip (command line) or with Keka, BetterZip or Archive Utility don't work. InDesign issues the error:
Cannot open the file. Adobe InDesign may not support the file format, a plug-in that supports the file format may be missing, or the file may be open in another application.
The problem with regular zip is that the zip archive contains a “mimetype” file that shouldn’t be compressed if you want InDesign to identify the newly-created IDML. So the way you have to re-zip the file (and the way the ePub scripts work) is like this:
They first create a zip archive which contains only the mimetype file, uncompressed. zip -X0 'myfile.idml' mimetype
Then they add the rest of the files/folders into the zip archive, this time with full compression. zip -rDX9 "myfile.idml" * -x "*.DS_Store" -x mimetype
In shell script terms, the ePub scripts do this (assuming the current directory is the one containing all the IDML contents):
zip -X0 'myfile.idml' mimetype # create the zip archive 'myfile.idml', containing only the 'mimetype' file with no compression
zip -rDX9 "myfile.idml" * -x "*.DS_Store" -x mimetype # add everything else to the ‘myfile.idml’ archive, EXCEPT .DS_Store files and the ‘mimetype’ file (which is already there from the previous step)
To save you time reading the zip man page, here’s what all these options mean:
-X = “no extra” — do not save extra file attributes like user/group ID for each file
-0 = “compression level zero” — no compression
-r = “recurse paths” — go through everything in the directory, including nested subfolders
-D = “no directory entries” — don’t put special stuff in the zip archive for directories
-9 = “compression level 9 (optimal)”
-x = “exclude these files”
Follow this voodoo, and you should be able to create legal IDML files.
Source: http://indesignsecrets.com/topic/how-do-i-re-zipcompress-an-expanded-idml-file
A big thanks to Chuck Weger and David Blatner at http://indesignsecrets.com
From within InDesign
use this jsx script to expand an IDML
//DESCRIPTION: Expands an IDML file into folder format
ExpandIDML();
function ExpandIDML(){
var fromIDMLFile = File.openDialog("Please Select The IDML File to unpackage");
if(!fromIDMLFile){return}
var fullName = fromIDMLFile.fullName;
fullName = fullName.replace(/\.idml/,"");
var toFolder = new Folder(fullName);
app.unpackageUCF(fromIDMLFile,toFolder);
}
And that one to produce an IDML package:
//DESCRIPTION:Produces an IDML package from the contents of a directory:
CreateIDML();
function CreateIDML(){
var fromFolder = Folder.selectDialog("Please Select The Folder to package as IDML");
if(!fromFolder){return}
var fullName = fromFolder.fullName;
// var name = fromFolder.name;
// var path = fromFolder.path;
var toIDMLFile = new File(fullName+".idml");
app.packageUCF(fromFolder,toIDMLFile);
}
I need to make sure a custom build tool that operates on a lot of files is always run when one of those files are changed.
I know you can specify "Additional Dependencies" for the custom build tool, but is there a better way than specifying one file per line?
Just made the build tool depend on one file. Created another custom build tool that runs before it and that touches this file if any of the real dependencies have changed. The advantage is that I now have quite a lot of flexibility and don't need to change any of the project settings if the dependencies change - that's taken care of via a database that the new custom build tool accesses.
"Additional Dependencies" is the correct and only documented way. You could adjust the contents of this field for the build tool in the Project file using an external tool to save on the troubles of doing a copy & paste & typo-adjust.
It won't be quite as reliable, but you could put all files in a subfolder and just make the folder a dependency.
A little bit hack:
(1) group the dependency files into a separate folder
(2) create a jscript file detect.js as follow:
var output = WScript.arguments(0);
var folder = WScript.arguments(1);
var fso = new ActiveXObject("Scripting.FileSystemObject");
var objOutput = fso.GetFile(output);
var objFolder = fso.GetFolder(folder);
// if the output file is older than input folder,
// delete output file to force regenerate
if (objOutput.DateLastModified < objFolder.DateLastModified) {
fso.DeleteFile(objOutput);
} else {
// if the output file is older than one of files in the input folder,
// delete output file to force regenerate
var e = new Enumerator(objFolder.Files);
for (; !e.atEnd(); e.moveNext()) {
if (objOutput.DateLastModified < e.item().DateLastModified)
fso.DeleteFile(objOutput);
break;
}
}
}
(2) Add command lines to Pre-Build Event as follow:
cscript.exe /nologo detect.js $(Output) $(InputFolder)
(3) Setup the Custom Buld Step to force the Pre-Build Event to occur, i.e.
Command Line: echo --------------
Outputs: echo.fake
Execute After: PreBuildEvent
Build Rules are documented in the Xcode Build System Guide
They are well adapted to the common case where one input file is transformed into a fixed number (usually one) of output files.
The output files must be described in the "Output Files" area of the build rule definition; one line per output file. Typically the output files have the same name as the input file but have different extensions.
In my case, one single input file is transformed into a variable number of files with the same extensions. The number and the names of the output files depend on the content of the input file and are not known in advance.
The output files will have to be further processed later on (they are in this case C files to be compiled).
How can I set up a build rule for such a case?
Any suggestions welcome.
(I asked the same question on the Apple developer forum, but I figured it'd be a good idea to ask here too).
I dealt with this by, instead of generating multiple C files, just concatenating them all together into one file (e.g. "AUTOGENERATED.c"), and specifying that as the output file.
So long as your output files don't contain anything that will conflict (static functions with the same name, conflicting #defines etc.) this works well.
See this article on Cocoa With Love:
http://cocoawithlove.com/2010/02/custom-build-rules-generated-tables-and.html
This has an example of generating custom C code and using that as input to the normal build process. He's using ${} variable syntax in the output
The best way I found to add any number of files to my xcode project (and make some processing) is to write a little php script. The script can simply copy files into the bundle. The tricky part is the integration with xcode. It took me some time to find a clean way. (You can use the script language you like with this method).
First, use "Add Run Script" instead of "Add Copy File"
Shell parameter:
/bin/sh
Command parameter:
${SRCROOT}/your_script.php -s ${SRCROOT} -o ${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}
exit $?
(screenshot in xcode)
${SRCROOT} is your project directory.
${CONFIGURATION(...) is the bundle directory. Exactly what you need :)
This way, your script return code can stop xcode build (use die(0) for success and die(1) for failures) and the output of script will be visible in xcode's build log.
Your script will look like that: (don't forget chmod +x on it)
#!/usr/bin/php
<?php
error_reporting(E_ALL);
$options = getopt("s:o:");
$src_dir = $options["s"]."/";
$output_dir = $options["o"]."/";
// process_files (...)
die(0);
?>
BONUS: here my 'add_file' function.
Note the special treatment for PNG (use apple's png compression)
Note the filemtime/touch usage to prevent copy files each times.
l
define("COPY_PNG", "/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/usr/bin/copypng -compress");
function add_file_to_bundle($output_dir, $filepath) {
// split path
$path_info = pathinfo($filepath);
$output_filepath = $output_dir.$path_info['basename'];
// get file's dates of input and output
$input_date = filemtime($filepath);
$output_date = #filemtime($output_filepath);
if ($input_date === FALSE) { echo "can't get input file's modification date"; die(1); }
// skip unchanged files
if ($output_date === $input_date) {
//message("skip ".$path_info['basename']);
return 0;
}
// special copy for png with apple's png compression tool
if (strcasecmp($path_info['extension'], "png") == 0) {
//message($path_info['basename']." is a png");
passthru(COPY_PNG." ".escapeshellarg($filepath)." ".escapeshellarg($output_filepath), $return_var);
if ($return_var != 0) die($return_var);
}
// classic copy
else {
//message("copy ".$path_info['basename']);
passthru("cp ".escapeshellarg($filepath)." ".escapeshellarg($output_filepath), $return_var);
if ($return_var != 0) die($return_var);
}
// important: set output file date with input file date
touch($output_filepath, $input_date, $input_date);
return 1;
}