Using the addon-sdk of firefox I'm following a tutorial about creating reusable modules, the example uses the geolocation API built into Firefox, so the code is simple:
function getCurrentPosition(callback){
var xpcomGeolocation = Cc["#mozilla.org/geolocation;1"].getService(Ci.nsIDOMGeoGeolocation);
xpcomGeolocation.getCurrentPosition(callback);
}
var widget = require("sdk/widget").Widget({
id: "whereami",
label: "Where Am I?",
contentURL: "http://www.mozilla.org/favicon.ico",
onClick: function(){
console.log("clicked!");
getCurrentPosition(function(position){
console.log("latitude: " + position.coords.latitude);
console.log("longitude: " + position.coords.longitude);
});
}
});
When running firefox with the plugin on, clicking the widget give this error:
Message: [Exception... "Component returned failure code: 0x80570018 (NS_ERROR_XPC_BAD_IID) [nsIJSCID.getService]" nsresult: "0x80570018 (NS_ERROR_XPC_BAD_IID)" location: "JS frame :: resource://gre/modules/XPIProvider.jsm -> jar:file:///tmp/tmpTFowYc.mozrunner/extensions/jid1-LIBIfbK6zvWAiQ#jetpack.xpi!/bootstrap.js -> resource://gre/modules/commonjs/toolkit/loader.js -> resource://jid1-libifbk6zvwaiq-at-jetpack/whereami/lib/main.js :: getCurrentPosition :: line 7" data: no]
According to docs, it's possible to get an error when importing nsIDGeoGeolocation so you must use Cc["#mozilla.org/geolocation;1"].getService(Ci.nsISupports); instead. Also, you must ask for permission to access geolocation, please see section Prompting for permission in
Using geolocation
reference.
By the way, as an advice, I think it will be simpler to use navigator.geolocation.getCurrentPosition(successCallback, errorCallback) since it handles prompting for permission for you, but I don't know what are you trying to do beyond this. Just to explain it a little, you could have an addon page data/index.html where you tell the user you are going to prompt him for his geolocation. Besides this, you must have a PageMod that runs a data/script.js for that addon page page, which has access to navigator.geolocation. That content script may communicate with your lib/main.js file so it has access to the user geo location. Somethings like this:
data/index.html:
<html>
<body>
<h1>Hello user!</h1>
</body>
</html>
data/script.js:
var successCallback = function(position) {
/* this way this script will talk to the pagemod in lib/main.js the user's position */
self.port.emit("gotGeolocation", position.coords.latitude, position.coords.longitude);
};
navigator.geolocation.getCurrentPosition(successCallback, errorCallback);
lib/main.js:
var data = require("sdk/self").data;
var pageMod = require("sdk/page-mod");
var tabs = require("sdk/tabs");
pageMod.PageMod({
/* attach the contentScriptFile to this html page */
include: data.url("index.html"),
contentScriptFile: data.url("script.js"),
onAttach: function(worker) {
/* listen to the script.js worker "gotGeolocation" message */
worker.port.on("gotGeolocation", function(latitude, longitude) {
console.log("latitude:", latitude);
console.log("longitude:", longitude);
});
}
});
/* this will open the index.jtml page and promt the user to access his geo position */
tabs.open(data.url("index.html"));
All this code it's only to better describe the idea, it hasn't been tested and in fact there are some indefinded objects. But I hope to give you an idea of how you can acces navigator.geolocation and pass its coords to the main.js script.
I think that you just forgot this at the top:
var { Cc, Ci } = require('chrome');
Also there a third party module for geolocation https://github.com/ZER0/geolocation
Related
I have an AngularJS front-end that opens a Bootstrap Modal that has a button on it. When this button is clicked it calls a Web API method on the server that generates an OPEN XML Word Document as a stream and returns the file to the client. I have several files downloading successfully in IE where I see this:
However, for the file I'm trying to download with the open Modal I never see the above image. It's not the file itself because it downloads successfully when I try it without the open Modal. Also, I don't see any errors reported in IE Dev Tools. I don't think it's the code that generates the streams because the same code generates other files successfully. I also tried closing the Modal before downloading but that didn't work either. It's almost like the Modal is "blocking" the download.
Here is the Modal definition:
var isOUOModal;
var isSubmitItem = false;
var openSignificanceModal = function () {
return $modal.open({
scope: $scope,
templateUrl: './app/oa/significance_modal.html',
controller: SignificanceModalCtrl,
keyboard: false,
backdrop: 'static',
resolve: {
item: function () {
return $scope.item;
}
}
});
};
var SignificanceModalCtrl = function ($scope, $modalInstance, item, $window) {
$scope.cancel = function () {
$modalInstance.dismiss('cancel');
};
};
I seem to be out of ideas at the moment so any assistance is much appreciated.
Thanks,
Pete
I was able to determine the cause of the problem here. It had to do with the way I was calling the Web API Method. I was using an AJAX JQuery GET call. Instead I had to do something like this:
var url = url;
window.location.href = url;
When I changed the way I was calling the Web API method I saw the stream returned to the client as expected.
I am new in using ckeditor and its API. I would like to find a way to validate the content of the users through the accessibility checker while they are typing.
The information available in the documentation do not make clear how to do this.
I'm trying to figure out how to do this...
<script>
var instance = CKEDITOR.replace('editorck');
instance.on('focus', function(event) {
var editor = CKEDITOR.instances['editorck'];
if(editor.plugins.a11ychecker){
var a11ycheckerCommand = new CKEDITOR.command(editor, {
exec: function( editor ) {
editor.execCommand("a11ychecker");
}
});
a11ycheckerCommand.setState(CKEDITOR.TRISTATE_ON);
a11ycheckerCommand.exec(editor);
}
});
instance.on('key', function (event) {
var editor = CKEDITOR.instances['editorck'];
editor.execCommand("a11ychecker.listen");
});
</script>
The code above expects two events. The first is the "onfocus" which activate the accessibility checker when the editor area is focused. The second is what I'm looking for, call some command or execute something to validate the content while keyup event is occuring.
The next step is to allow the user to save the content if it is validated. Perhaps a way to get the current accessibility issues list?
CKEDITOR.plugins.a11ychecker.IssueList or editor.plugins.a11ychecker.IssueList ?
I'm porting a Chrome extension to a Firefox extension and due to the nature of the website that it runs on, I need to monitor the pushState.
Chrome Extensions has a handy way to handle this: chrome.webNavigation.onHistoryStateUpdated. The way that I use it in the Chrome extension is as follows:
chrome.webNavigation.onHistoryStateUpdated.addListener(function(details) {
var tabUrl = details.url;
if (isTabUrlValid(tabUrl)) {
$.get(tabUrl, function(data) {
var videoUrl = $(data).find('meta[itemprop=contentURL]').prop('content');
videoUrl = validateUrl(videoUrl);
videoUrl5k = make5kUrl(videoUrl);
});
}
});
I need to do the same thing for the Firefox Extension, but I haven't found any good answers. I've tried doing the answer mentioned here: How to get notified about changes of the history via history.pushState?
(function(history) {
var pushState = history.pushState;
history.pushState = function(state) {
if (typeof history.onpushstate == "function") {
history.onpushstate({state: state});
}
var tabUrl = tabs.activeTab.url;
console.log("UPDATED TAB URL: " + tabUrl);
if (isTabUrlValid(tabUrl)) {
$.get(tabUrl, function(data) {
var videoUrl = $(data).find('meta[itemprop=contentURL]').prop('content');
videoUrl = validateUrl(videoUrl);
videoUrl5k = make5kUrl(videoUrl);
});
}
return pushState.apply(history, arguments);
};
})(window.history);
The problem is that when I do cfx run it complains that history/window is undefined and therefore never gets detected. I think this is due to it being within the SDK, but I don't know of a good workaround.
Any thoughts?
Edit: I looked at #willma's answer below and I don't think that would work for me. The issue is that the URL is updated via pushState and the DOM is not... Is there any good way replicate what I do in the chrome extension?
Edit: Here's the pageMod portion
pageMod.PageMod({
attachTo: 'top', // Don't attach to iFrames --> http://goo.gl/b6b1Iv
include: [URLs],
contentScriptFile: [data.url("jquery-2.1.1.min.js"),
data.url("csScript.js")],
onAttach: function(worker) {
worker.port.on('url', function(url) {
var videoUrl = validateUrl(url);
videoUrl5k = make5kUrl(videoUrl);
console.log("--5K URL--: " + videoUrl5k);
});
}
});
That history code needs to get injected into a tab using a content script. Right now your logic says when the history event occurs, check to see if the tab URL is valid.
In Firefox, the logic will be the other way around: when a tab is opened, check if its URL is valid, and if so, then attach a script to it that will monitor for the history event. To do so you'll need to use a Page Mod.
Edit: All the code
One key concept you're missing is the difference between a content script and a main/library script. The library scripts are stored in lib and have access to all the SDK modules, but don't have access to the DOM, window object… The content scripts are stored in data, are injected into a page using the PageMod or tabs modules, can access the dom and window objects, but have no access to any SDK modules. Content scripts are essentially like the page scripts you'd attach your standard HTML page (with <script></script>) with the caveats that they can't share variables other page scripts but they can communicate with the main scripts.
The only reason I bring this up is because your initial problem was trying to access the window object from a main script and the problem in your fiddle is that you're trying to access the tabs module inside a content script. It's worth reading the topmost link in this answer if this is still confusing.
main.js
const { PageMod } = require('sdk/page-mod');
var sendXHR = function(url) {
// Do something with the new URL
// See Request Module docs (below) for sending XHRs from main script.
}
const pageMod = PageMod({
attachTo: 'top',
include: '*',
onAttach: function(worker) {
worker.port.on('newURL', sendXHR);
}
});
content.js
var sendNewUrlToMain = function() {
self.port.emit('newURL', location.href);
}
var pushState = window.history.pushState;
window.history.pushState = function(state) {
if (typeof history.onpushstate == "function") {
history.onpushstate({state: state});
}
sendNewUrlToMain();
return pushState.apply(history, arguments);
}
window.addEventListener('hashchange', sendNewUrlToMain);
Here are the request module docs, for making XHRs.
NB: if you don't want to use the request module (the only reason being that you already have standard XHR code for your chrome extension and don't want to take the time to learn/rewrite that code), you can send a standard XHR from the content script, but in doing so, you risk allowing the user to close the tab and thus destroy the script before your XHR callbacks are executed.
I just started using the FireFox Builder to build a simple addon. I realised that I cannot get direct access to the window object.
What I want to do is to get the window object and pollute it with some classes and functions so I can call them from the page itself.
Below is the current code:
// This is an active module of the ritcoder Add-on
require("widget").Widget({
id: "widgetID1",
label: "My Mozilla Widget",
contentURL: "http://www.mozilla.org/favicon.ico",
onClick: function(evt){
var tabs = require("tabs");
var activeTab = tabs.activeTab;
var notifications = require("notifications");
notifications.notify({
title: "Jabberwocky",
text: "'Twas brillig, and the slithy toves",
data: "did gyre and gimble in the wabe",
onClick: function (data) {
console.log(data);
// console.log(this.data) would produce the same result.
}
});
activeTab.window.a=20; //this fails
context.alert('yesx');
}
});
How do I do this? Inject some code into the active page so that it can be called.
regards,
You need to use tab.attach() to run a content script in the tab's context, and then use unsafeWindow to add properties the page's script can see. (You should also read the introduction to Content Scripts.)
The Addon SDK doesn't provide a direct access (without the content script) to the page from the add-on's code because it tries to be forward compatible with the plans to make web pages run in processes separate from the browser's and the add-on's process.
I would like to write a firefox extension. This extension is not a generic extension but work specifically for a domain where I need to highlight specific html components.
How should I do that? I just want the js loaded when the user is browsing a specific domain.
My current overaly.js is basically empty (generated by the Extension Wizard):
var myextension = {
onLoad: function() {
// initialization code
this.initialized = true;
this.strings = document.getElementById("myextension-strings");
},
onMenuItemCommand: function(e) {
var promptService = Components.classes["#mozilla.org/embedcomp/prompt-service;1"]
.getService(Components.interfaces.nsIPromptService);
promptService.alert(window, this.strings.getString("helloMessageTitle"),
this.strings.getString("helloMessage"));
},
onToolbarButtonCommand: function(e) {
// just reuse the function above. you can change this, obviously!
myextension.onMenuItemCommand(e);
}
};
window.addEventListener("load", myextension.onLoad, false);
And my ff-overlay.xul is:
myextension.onFirefoxLoad = function(event) {
document.getElementById("contentAreaContextMenu")
.addEventListener("popupshowing", function (e){ myextension.showFirefoxContextMenu(e); }, false);
};
myextension.showFirefoxContextMenu = function(event) {
// show or hide the menuitem based on what the context menu is on
document.getElementById("context-myextension").hidden = gContextMenu.onImage;
};
window.addEventListener("load", myextension.onFirefoxLoad, false);
I was thinking to go neanderthal and do a check inside myextension.onFirefoxLoad to see if the currentpage is the one I want but that requires the user to click the proper item on the context menu.
I'm not totally following what you have because both of those look like JS files, not XUL files. But what you probably want to do is listen for the load event coming from the web pages that are loaded. Then, in your event loader, just look at each page that loads and see whether it's coming from the specific domain you want.
A great (though not always quite as easy as it sounds) way to find out how to do something in a Firefox addon is to find another addon that does something similar. DOM Inspector and Inspect Context are your friends! The first such addon that comes to mind in this case is WikiTrust so you could try looking at that one to see if it gives you any inspiration.