I can't seem to figure out how to programmatically hide or show a setting.
I have tried this:
function onSwitchChange(prefName) {
var ms = require("sdk/simple-prefs").prefs.option1;
if(ms == "S"){
require("sdk/simple-prefs").prefs.option2.hidden = false;
}else{
require("sdk/simple-prefs").prefs.option2.hidden = true;
}
}
require("sdk/simple-prefs").on("option1", onSwitchChange);
you need to give your pref an oninputchanged attribute.
see here: MDN :: Inline Options - Setting element changed notifications
it looks like you're using firefox-addon-sdk so after you make your addon to xpi. rename the xpi to zip then extract it. then edit options.xul then re-zip the files, then re-rename it to .xpi.
the edit you need to make to options.xul is find the setting element of option2. then add to it this:
<setting title="option1" type="string" pref="blahBlahBlah" oninputchanged="if (this.value == 'S') { document.querySelector('setting[title=\"option1\"]').style.display='none'; } else { document.querySelector('setting[title=\"option1\"]').style.display=''; } ">
option2
</setting>
Related
My ruby on rails app's CSP was working perfectly until I added webpacker. Now I get this:
Content Security Policy: The page’s settings observed the loading of a resource at inline (“style-src”). A CSP report is being sent. injectStylesIntoStyleTag.js:117
Content Security Policy: The page’s settings observed the loading of a resource at inline (“style-src”). A CSP report is being sent. injectStylesIntoStyleTag.js:190
The code in question looks like this:
function insertStyleElement(options) {
var style = document.createElement('style');
...
if (typeof options.insert === 'function') {
options.insert(style);
} else {
var target = getTarget(options.insert || 'head');
if (!target) {
throw new Error("Couldn't find a style target. This probably means that the value for the 'insert' parameter is invalid.");
}
target.appendChild(style); //LINE 117//
}
return style;
}
And:
function applyToTag(style, options, obj) {
var css = obj.css;
...
if (style.styleSheet) {
style.styleSheet.cssText = css;
} else {
while (style.firstChild) {
style.removeChild(style.firstChild);
}
style.appendChild(document.createTextNode(css)); //LINE 190//
}
}
How do I add a nonce? This says to add __webpack_nonce__ = 'random'; to my entry file ( in this case app/javascript/packs/application.js), yet adding that nonce to my csp file has no effect on the style-src violation. Which in this case, looks like this: config.style_src :self, 'https://fonts.googleapis.com', 'nonce-random'
I somehow wasn't able to find the injected styles in source, but the answer was to open the page in Chrome (I was using Firefox) and copy the sha-256 hash from the console log into the app's CSP.
I need to export a few tables to PDF format. I decided to use jspdf-autotable but I can't find a way to customize my header. I need to do this in the header style :
_________________________________________
|__________|______________|_____________|
|____|_____|___|__|___|___|___|___|__|__|
|____|_____| ... (content)
|____|_____| ... (content)
The first line is my problem, as headers are define differently, and I cant find a way to do this through the "drawHeaderCell" method.
Do u know a way to do this ?
Thank you
To get such a result you could implement the drawHeaderCell hook something like this:
drawHeaderCell: function(cell, data) {
if (data.column.dataKey === 'id' || data.column.dataKey === 'first_name' || data.column.dataKey === 'email') {
cell.width = data.table.width / 3;
} else {
return false;
}
}
Doing rowspans and colspans are quite complicated at this stage with jspdf-autotable. There is an example for how they could be implemented in the repo however.
I am creating a firefox addon using the SDK. My goal is simple, to intercept a specific iframe and load my own HTML page (packaged as a resource with my addon) instead of the content that was requested originally.
So far I have the following code:
var httpRequestObserver =
{
observe: function(subject, topic, data)
{
var httpChannel, requestURL;
if (topic == "http-on-modify-request") {
httpChannel = subject.QueryInterface(Ci.nsIHttpChannel);
requestURL = httpChannel.URI.spec;
var newRequestURL, i;
if (/someurl/.test(requestURL)) {
var ioService = Cc["#mozilla.org/network/io-service;1"].getService(Ci.nsIIOService);
httpChannel.redirectTo(ioService.newURI(self.data.url('pages/test.html'), undefined, undefined));
}
return;
}
}
};
var observerService = Cc["#mozilla.org/observer-service;1"].getService(Ci.nsIObserverService);
observerService.addObserver(httpRequestObserver, "http-on-modify-request", false);
This code works in that it detects the proper iframe loading and does the redirect correctly. However, I get the following error:
Security Error: Content at http://url.com may not load or link to
jar:file:///.../pages/test.html.
How can I get around this limitation?
actually man i was really over thinking this.
its already solved when I changed to using loadContext. Now when you get loadContext you get the contentWindow of whatever browser element (tab browser, or frame or iframe) and then just abort the http request like you are doing and then loadContext.associatedWindow.document.location = self.data('pages/tests.html');
done
ill paste the code here removing all the private stuff. you might need the chrome.manifest ill test it out and paste the code back here
Cu.import('resource://gre/modules/Services.jsm');
var httpRequestObserver = {
observe: function (subject, topic, data) {
var httpChannel, requestURL;
if (topic == "http-on-modify-request") {
httpChannel = subject.QueryInterface(Ci.nsIHttpChannel);
requestURL = httpChannel.URI.spec;
var newRequestURL, i;
if (/someurl/.test(requestURL)) {
var goodies = loadContextGoodies(httpChannel);
if (goodies) {
httpChannel.cancel(Cr.NS_BINDING_ABORTED);
goodies.contentWindow.location = self.data.url('pages/test.html');
} else {
//dont do anything as there is no contentWindow associated with the httpChannel, liekly a google ad is loading or some ajax call or something, so this is not an error
}
}
return;
}
}
};
Services.obs.addObserver(httpRequestObserver, "http-on-modify-request", false);
//this function gets the contentWindow and other good stuff from loadContext of httpChannel
function loadContextGoodies(httpChannel) {
//httpChannel must be the subject of http-on-modify-request QI'ed to nsiHTTPChannel as is done on line 8 "httpChannel = subject.QueryInterface(Ci.nsIHttpChannel);"
//start loadContext stuff
var loadContext;
try {
var interfaceRequestor = httpChannel.notificationCallbacks.QueryInterface(Ci.nsIInterfaceRequestor);
//var DOMWindow = interfaceRequestor.getInterface(Components.interfaces.nsIDOMWindow); //not to be done anymore because: https://developer.mozilla.org/en-US/docs/Updating_extensions_for_Firefox_3.5#Getting_a_load_context_from_a_request //instead do the loadContext stuff below
try {
loadContext = interfaceRequestor.getInterface(Ci.nsILoadContext);
} catch (ex) {
try {
loadContext = subject.loadGroup.notificationCallbacks.getInterface(Ci.nsILoadContext);
} catch (ex2) {}
}
} catch (ex0) {}
if (!loadContext) {
//no load context so dont do anything although you can run this, which is your old code
//this probably means that its loading an ajax call or like a google ad thing
return null;
} else {
var contentWindow = loadContext.associatedWindow;
if (!contentWindow) {
//this channel does not have a window, its probably loading a resource
//this probably means that its loading an ajax call or like a google ad thing
return null;
} else {
var aDOMWindow = contentWindow.top.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIWebNavigation)
.QueryInterface(Ci.nsIDocShellTreeItem)
.rootTreeItem
.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDOMWindow);
var gBrowser = aDOMWindow.gBrowser;
var aTab = gBrowser._getTabForContentWindow(contentWindow.top); //this is the clickable tab xul element, the one found in the tab strip of the firefox window, aTab.linkedBrowser is same as browser var above //can stylize tab like aTab.style.backgroundColor = 'blue'; //can stylize the tab like aTab.style.fontColor = 'red';
var browser = aTab.linkedBrowser; //this is the browser within the tab //this is where the example in the previous section ends
return {
aDOMWindow: aDOMWindow,
gBrowser: gBrowser,
aTab: aTab,
browser: browser,
contentWindow: contentWindow
};
}
}
//end loadContext stuff
}
NOTE: Now try this first, I didn't test it yet, if you get a security error when it tries to redirect then create a chrome.manifest file and put it in the root directory. If it throws a security error than you definitely need a chrome.manifest file and that will without question fix it up. I'll test this myself later tonight when I get some time.
The chrome.manifest should look like this:
content kaboom-data ./resources/kaboom/data/ contentaccessible=yes
Then in the code way above change the redirect line from goodies.contentWindow.location = self.data.url('pages/test.html'); to goodies.contentWindow.location = 'chrome://kaboom-data/pages/test.html');.
see this addon here: https://addons.mozilla.org/en-US/firefox/addon/ghforkable/?src=search
in the chrome.manifest file we set the contentaccessible parameter to yes
you dont need sdk for this addon. its so simple, just ocpy paste that into a bootstrap skeleton as seen here:
Bootstrap With Some Features, Like chrome.manifest which you will need
Bootstrap Ultra Basic
if you want to really do a redirect of a page to your site, maybe you want to make a custom about page? if you would like ill throw togather a demo for you on making a custom about page. you can see a bit hard to understand demo here
posting my trials here so it can help all:
trail 1 failed - created chrome.manifest file with contents content kaboom-data resources/kaboom/data/ contentaccessible=yes
var myuri = Services.io.newURI('chrome://kaboom-data/content/pages/test.html', undefined, undefined);
httpChannel.redirectTo(myuri);
Error Thrown
Security Error: Content at http://digg.com/tools/diggthis/confirm? may
not load or link to
jar:file:///C:/Documents%20and%20Settings/SONY%20VAIO/Application%20Data/Mozilla/Firefox/Profiles/vr10qb8s.default/extensions/jid1-g4RtC8vdvPagpQ#jetpack.xpi!/resources/kaboom/data/pages/test.html.
trial 2 failed - created resource in bootstrap.js
alias.spec =
file:///C:/Documents%20and%20Settings/SONY%20VAIO/Application%20Data/Mozilla/Firefox/Profiles/vr10qb8s.default/extensions/jid1-g4RtC8vdvPagpQ#jetpack.xpi
alias updated to spec:
jar:file:///C:/Documents%20and%20Settings/SONY%20VAIO/Application%20Data/Mozilla/Firefox/Profiles/vr10qb8s.default/extensions/jid1-g4RtC8vdvPagpQ#jetpack.xpi!/
let resource = Services.io.getProtocolHandler("resource").QueryInterface(Ci.nsIResProtocolHandler);
let alias = Services.io.newFileURI(data.installPath);
Cu.reportError('alias.spec = ' + alias.spec);
if (!data.installPath.isDirectory()) {
alias = Services.io.newURI("jar:" + alias.spec + "!/", null, null);
Cu.reportError('alias updated to spec: ' + alias.spec);
}
resource.setSubstitution("kaboom_data", alias);
...
var myuri = Services.io.newURI('resource://kaboom_data/resources/kaboom/data/pages/test.html', undefined, undefined);
httpChannel.redirectTo(myuri);
Error Thrown
Security Error: Content at http://digg.com/tools/diggthis/confirm? may
not load or link to
jar:file:///C:/Documents%20and%20Settings/SONY%20VAIO/Application%20Data/Mozilla/Firefox/Profiles/vr10qb8s.default/extensions/jid1-g4RtC8vdvPagpQ#jetpack.xpi!/resources/kaboom/data/pages/test.html.
CONCLUSION
in both trials above it was the weirdest thing, it wouldnt show the resource or chrome path in the security error thrown but it would give the full jar path. Leading me to believe that this has something to do with redirectTo function.
The solution that did work was your solution of
var gBrowser = utils.getMostRecentBrowserWindow().gBrowser;
var domWin = httpChannel.notificationCallbacks.getInterface(Ci.nsIDOMWindow);
var browser = gBrowser.getBrowserForDocument(domWin.document);
//redirect
browser.loadURI(self.data.url('pages/test.html'));
however I changed this to use loadContext instead of this method because it is the recommended way. also gBrowser to getMostRecentBrowserWindow will fail if the url load is slow and in that time the user swithces to another tab or window
I also changed to use Services.jsm as you had imported Cu anyways. Using Services.jsm is super fast not even blink fast. Its just a pointer.
Im still working on trying to the redirectTo method working its really bothering me. The changes I made are to my local copy.
Have you considered turning your local HTML file into a data URL and loading that?
I'm working on a firefox extension, until now I was working with XUL browser, to control the user navigation across web sites and save the visited pages, but the browser is limited, I tried a simple google search, when I click on some result, it won't be displayed in the browser.
One idea is to move the xul application to Dialog and control the actual firefox tabs.
But I have no idea how to do this.
(per your comment....)
To create an addon that logs TAB 'load' events, create a bootstrapped (restartless) addon:
bootstrap.js (The JavaScript file containing your 'privileged' code)
install.rdf (an XML file describing your addon to Firefrox)
To build the addon, simply place both files inside the top-level (no folders!) of a ZIP file with the file extension .xpi. To install the addon, navigate to about:addons then from the tools menu, click Install from file, find your XPI, open it, then after a short delay choose Install.
In install.rdf put something like this:
<?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>youraddonname#yourdomain</em:id>
<em:type>2</em:type>
<em:name>Name of your addon</em:name>
<em:version>1.0</em:version>
<em:bootstrap>true</em:bootstrap>
<em:description>Describe your addon.</em:description>
<em:creator>Your name</em:creator>
<!-- Firefox Desktop -->
<em:targetApplication>
<Description>
<em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id>
<em:minVersion>4.0.*</em:minVersion>
<em:maxVersion>29.0.*</em:maxVersion>
</Description>
</em:targetApplication>
</Description>
</RDF>
You need to implement two mandatory JavaScript functions in the bootstrap.js:
startup() - called when you install the addon, and when your browser starts up.
shutdown() - called when you uninstall the addon, and when your browser shuts down.
You should call all of the 'privileged' code from startup(). For hygiene, you can (and probably should) also implement install() and uninstall() functions.
Start by implementing the following code in bootstrap.js:
const Cc = Components.classes;
const Ci = Components.interfaces;
let consoleService = Cc["#mozilla.org/consoleservice;1"]
.getService(Ci.nsIConsoleService);
let wm = Cc["#mozilla.org/appshell/window-mediator;1"]
.getService(Ci.nsIWindowMediator);
function LOG(msg) {
consoleService.logStringMessage("EXTENSION: "+msg);
}
function startup() {
try {
LOG("starting up...");
let windows = wm.getEnumerator("navigator:browser");
while (windows.hasMoreElements()) {
let chromeWindow = windows.getNext().QueryInterface(Ci.nsIDOMWindow);
WindowListener.setupBrowserUI(chromeWindow);
}
wm.addListener(WindowListener);
LOG("done startup.");
} catch (e) {
LOG("error starting up: "+e);
}
}
function shutdown() {
try {
LOG("shutting down...");
let windows = wm.getEnumerator("navigator:browser");
while (windows.hasMoreElements()) {
let chromeWindow = windows.getNext().QueryInterface(Ci.nsIDOMWindow);
WindowListener.tearDownBrowserUI(chromeWindow);
}
wm.addListener(WindowListener);
LOG("done shutdown.");
} catch (e) {
LOG("error shutting down: "+e);
}
}
Basically, that calls WindowListener.setupBrowserUI() for each current & future window of your web-browser. WindowListener is defined as follows:
var WindowListener = {
setupBrowserUI: function(chromeWindow) {
chromeWindow.gBrowser.addEventListener('load', my_load_handler, true);
},
tearDownBrowserUI: function(chromeWindow) {
chromeWindow.gBrowser.removeEventListener('load', my_load_handler, true);
},
onOpenWindow: function(xulWindow) {
let chromeWindow = xulWindow.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDOMWindow);
chromeWindow.addEventListener("load", function listener() {
chromeWindow.removeEventListener("load", listener, false);
var domDocument = chromeWindow.document.documentElement;
var windowType = domDocument.getAttribute("windowtype");
if (windowType == "navigator:browser")
WindowListener.setupBrowserUI(chromeWindow);
}, false);
},
onCloseWindow: function(chromeWindow) { },
onWindowTitleChange: function(chromeWindow, newTitle) { }
};
That sets up an event listener for the OpenWindow event, and in turn installs an event listener for load events in the TabBrowser of each ChromeWindow. The load event handler is defined as:
var my_load_handler = function (evt) {
try {
var browserEnumerator = wm.getEnumerator("navigator:browser");
while (browserEnumerator.hasMoreElements()) {
var browserWin = browserEnumerator.getNext();
var tabbrowser = browserWin.gBrowser;
var numTabs = tabbrowser.browsers.length;
for (var index = 0; index < numTabs; index++) {
var currentBrowser = tabbrowser.getBrowserAtIndex(index);
var domWindow = currentBrowser.contentWindow.wrappedJSObject;
if (!domWindow.hasOwnProperty('__logged_this_window__')) {
LOG("TAB loaded:");
LOG(" URL: "+domWindow.location.href);
LOG(" TITLE: "+domWindow.title)
domWindow.__logged_this_window__ = 1;
}
}
}
} catch (e) {
LOG(e);
}
}
So basically, if there's a load event on any of the TabBrowser elements in Firefox, that function will run. It'll enumerate all of the Firefox windows, and all of those windows' tabs (Browser elements). The trick is that when a page reloads all the custom properties on a "content" DomWindow are lost, so we check to see if a custom property is present. If not, then we log details of the TAB's content page.
It is working properly every time the page loads at the first time. However when we do a Postback the editor disappears with just the textarea.
The postback is happening due to a dropdown on the page.
<asp:TextBox runat="server" ID="TBClosingInstructions" TextMode="MultiLine" Rows="8" Columns="40" TabIndex="2" Font-Name="Verdana"></asp:TextBox><script language="JavaScript">generate_wysiwyg('TBClosingInstructions');</script>
I would like the editor to remain even after postback. I have tried the following code
if (Page.IsPostBack)
{
this.ClientScript.RegisterStartupScript(this.GetType(), "script", "<script language=\"JavaScript\">generate_wysiwyg('TBClosingInstructions');</script>", true);
Page.ClientScript.RegisterClientScriptBlock(this.GetType(), "ClientScript", "<script language=\"JavaScript\">generate_wysiwyg('TBClosingInstructions');</script>", true);
}
Tried both registerStartupScript and registerClientScriptBlock individually to bind the javascript functions in every postback. But this doesn't work.
Is there any alternative? Please suggest.
There are a couple of methods that attach the editor to a textarea.
WYSIWYG.attach('all', mysettings);
This is what I was using which worked well if you content/form was not loaded dynamically.
Looking at the source code it attaches to the load event. This is probably why it isn't being attached.
WYSIWYG_Core.addEvent(window, "load", function generateEditor() { WYSIWYG._generate(id, settings); });
WYSIWYG.attachAll(mySettings);
I found this one works (all textareas), again looking at the source code it looks for every textarea in the DOM and does not attach to an event.
var areas = document.getElementsByTagName("textarea");
for (var i = 0; i < areas.length; i++) {
var id = areas[i].getAttribute("id");
if (id == null || id == "") continue;
this.setSettings(id, settings);
WYSIWYG_Core.includeCSS(this.config[id].CSSFile);
WYSIWYG._generate(id, settings);
}