Access to the elements of the page in the Page-Worker - firefox-addon-sdk

I've created a page-worker in the extension
dup = pageWorker.Page({
contentScript: "self.port.on('alert', function(message) {"+
"console.log(message);"+
"document.querySelector('.test-element').title = message;"+
"});",
contentScriptWhen: "ready",
contentURL: "http://example.com/Licznik-beta/addon.html"
});
In "contentScript" I can relate to "document".
But I can not relate to the window, or function, or variable.
console.log(window) in contentScript return "TypeError: cyclic object value timers.js:43".
I do not understand how it works.
Can someone explain to me?
How to change it?
EDIT
I've added a few lines to the test:
self.port.on('addon-licznik', function () {
console.log(document);
console.log(window); // TypeError: cyclic object value timers.js:43
runFromAddon(); // ReferenceError: runFromAddon is not defined timers.js:43
});
Function: runFromAddon(); Of course there is.
Second test:
function funSet (tresc) {
var addonScript = document.querySelector(".addon-script");
if ( addonScript != undefined ) {
document.querySelector('head').removeChild( addonScript );
}
var script = document.createElement("script");
script.className = "addon-script";
script.textContent = tresc;
document.querySelector('head').appendChild(script);
}
function marmo (message) {
console.log(message);
funSet("console.log(window); runFromAddon();");
}
self.port.on('addon-licznik', marmo);
It works well.
Window → http://example.com/Licznik-beta/addon.html
runFromAddon-Log

If you're writing the HTML yourself, then use addon instead of self and attach the script to the page using <script></script> instead of contentScript(File). See Scripting trusted page content.
If you're not writing the HTML, then see Communicating with Page Scripts.

Related

Unity3D call function from another script (Unityscript)

I've looked up similar questions and responses and still have not been able to get this to work.
LessonRightButton.js
//#pragma strict
public var audio1 : AudioPlayback;
function OnClick(){
var findAudioSource = GameObject.Find("AudioPlaybackButton");
var audio1:AudioPlayback = findAudioSource.GetComponent(AudioPlayback);
audio1.woo(); // THIS IS LINE 50 IN THE ERROR
}
AudioPlayback.js
//#pragma strict
function woo(){
Debug.Log("wooooooooooooooo");
}
I get this error:
NullReferenceException: Object reference not set to an instance of an
object LessonRightButton.OnClick () (at
Assets/Scripts/LessonRightButton.js:50)
I'm trying to call the woo function from a different script.
These scripts are shortened for the purpose of ease of reading. Please advise.
you have no AudioPlayback attached on that AudioPlaybackButton object.
Either add one manually or by code:
function OnClick(){
var findAudioSource = GameObject.Find("AudioPlaybackButton");
var audio1:AudioPlayback = findAudioSource.GetComponent(AudioPlayback);
if(audio1 == null){
audio1 = findAudioSource.AddComponent(AudioPlayback);
}
audio1.woo();
}

"this" in a prototype method does not always refer to the prototype of the object itself?

Most of the times all I have to do with JavaScript is just add some dynamics to simple HTML. Recently, however, after discovering CoffeeScript, I got interested in *Object Oriented JavaScript". Here is some code in CoffeeScript.
class MyClass
constructor: (title, purpose)->
#title = typeof title is undefined ? "My Class" : title
#purpose = typeof purpose is undefined ? "None" : purpose
#myMethod()
myMethod: ->
_getTitle = #getTitle
_getPurpose = #getPurpose
$(window).click ->
_getTitle()
_getPurpose()
return
return
getTitle: ->
_title = #title
window.console.log "Title of the class this object belongs to is: #{_title}"
return
getPurpose: ->
_purpose = #purpose
window.console.log "Purpose of creating this class is: #{_purpose}"
return
title = ""
purpose = ""
myObject = new MyClass("Testbed", "to test Object Oriented JavaScript")
For those who prefer JavaScript, here is the compiled (?) JavaScript.
var MyClass, myObject;
MyClass = (function() {
var purpose, title;
function MyClass(title, purpose) {
var _ref, _ref1;
this.title = (_ref = typeof title === void 0) != null ? _ref : {
"My Class": title
};
this.purpose = (_ref1 = typeof purpose === void 0) != null ? _ref1 : {
"None": purpose
};
this.myMethod();
}
MyClass.prototype.myMethod = function() {
var _getPurpose, _getTitle;
_getTitle = this.getTitle;
_getPurpose = this.getPurpose;
$(window).click(function() {
_getTitle();
_getPurpose();
});
};
MyClass.prototype.getTitle = function() {
var _title;
_title = this.title;
window.console.log("Title of the class this object belongs to is: " + _title);
};
MyClass.prototype.getPurpose = function() {
var _purpose;
_purpose = this.purpose;
window.console.log("Purpose of creating this class is: " + _purpose);
};
title = "";
purpose = "";
return MyClass;
})();
myObject = new MyClass("Testbed", "to test Object Oriented JavaScript");
Sorry about the long code. I had to try to keep it interesting. The thing is, this code outputs:
Title of the class this object belongs to is: undefined
Purpose of creating this class is: undefined
whereas I was expecting it to output:
Title of the class this object belongs to is: Testbed
Purpose of creating this class is: to test Object Oriented JavaScript
And I could've sworn this was how it worked when I last tinkered with it (around six months ago). I learnt that in a method that is part of the prototype of an object, this refers to the prototype itself. And this.something would actually point to object.something. Whereas in this example, inside myObject.myMethod(), this behaves as it should and this.getTitle() refers to myObject.getTitle(). Inside myObject.getTitle(), however, this refers to window. Why?
Is it because getTitle() was called inside a $(window).click() handler? But why would that change the context? getTitle() is still a property of myObject.
Also, you see what I am trying to accomplish here. How could I accomplish that?
There are several problems.
1) You never return anything from .getPurpose or .getTitle
2) You should create a reference to this in myMethod. i.e. var me = this and then inside the event listener call me.getTitle() and me.getPurpose(). This is needed because inside the event listener (window onclick), this refers to the window and not the object.
3) It looks like your ternary expressions are always evaluating to false. You need to rethink them.
P.S. I looked at the straight JS version

Is there any way to implement nsICommandLineHandler in a restartless add-on?

Is there any way to implement nsICommandLineHandler in a restartless add-on?
It seems possible from https://addons.mozilla.org/en-US/developers/docs/sdk/latest/modules/sdk/platform/xpcom.html , but this code (run from within exports.main) is not working for me:
var { Class } = require('sdk/core/heritage');
var { Unknown, Factory } = require('sdk/platform/xpcom');
var { Cc, Ci } = require('chrome');
var contractId = '#mozilla.org/commandlinehandler/general-startup;1?type=webappfind';
// Define a component
var CommandLineHandler = Class({
extends: Unknown,
get wrappedJSObject() this,
classDescription: "webAppFinder",
/* Not used by SDK, so commenting out
_xpcom_categories: [{
category: "command-line-handler",
// category names are sorted alphabetically. Typical command-line handlers use a
// category that begins with the letter "m".
entry: "m-webappfind"
}],
*/
helpInfo : " -webappfind Open My Application\n",
// nsICommandLineHandler
handle : function clh_handle(cmdLine) {
try {
console.log('good so far'); // Doesn't actually reach here
var fileStr = cmdLine.handleFlagWithParam("webappfind", false);
if (fileStr) {
console.log('made it');
}
}
catch (e) {
Cu.reportError("incorrect parameter passed to -webappfind on the command line.");
}
if (cmdLine.handleFlag("webappfind", false)) { // no argument
cmdLine.preventDefault = true;
throw 'A valid ID must be provided to webappfind';
}
},
hello: function() {return 'Hello World';}
});
// Create and register the factory
var factory = Factory({
contract: contractId,
// id: '{7f397cba-7a9a-4a05-9ca7-a5b8d7438c6c}', // Despite the docs saying one can add both, this doesn't work
Component: CommandLineHandler
});
I have the following code afterward which works...
// XPCOM clients can retrieve and use this new
// component in the normal way
var wrapper = Cc[contractId].createInstance(Ci.nsISupports);
var helloWorld = wrapper.wrappedJSObject;
console.log(helloWorld.hello());
...but Firefox is not accepting command line args as per this error:
Error: Warning: unrecognized command line flag -webappfind
Source file: resource://app/components/nsBrowserContentHandler.js
Line: 765
UPDATE
I've now taken #nmaier's advice to add categories and therefore added these lines afterward:
var catMan = Cc['#mozilla.org/categorymanager;1'].getService(Ci.nsICategoryManager); //
catMan.addCategoryEntry('command-line-handler', 'm-webappfind' /*contractId*/, contractId, false, true);
But I'm getting these 3 errors when invoking from the command line:
Error: [Exception... "'Failure' when calling method:
[nsIFactory::createInstance]" nsresult: "0x80004005
(NS_ERROR_FAILURE)" location: "native frame :: ::
:: line 0" data: no]
Contract ID
'#mozilla.org/commandlinehandler/general-startup;1?type=webappfind'
was registered as a command line handler for entry 'm-webappfind', but
could not be created.
Error: Warning: unrecognized command line flag -webappfind
Source file: resource://app/components/nsBrowserContentHandler.js
Line: 765
The SDK will not register categories for you.
Some remarks regarding categories can be found here:
https://stackoverflow.com/a/18366485/484441
But still, I'm not sure if bootstrapped extensions are actually started before the initial command line is processed. Trial and error, I guess...
Edit:
Your component does not specify any interfaces, hence it does only support nsISupports.
The SDK module docs state that you should add an interfaces: [ 'nsICommandLineHandler' ] property.

Calling class function within a constructor isn't being recognised

Answer:
It turns out I had neglected to use the new keyword when creating the class instance. The code in the question itself is fine.
Question:
I have a fairly simple class where the constructor calls another method on the class (editor_for_node). The call happens inside a jQuery each() loop, but I've also tried moving it outside.
define ['jquery'], ($) ->
class Editor
constructor: (#node, #data, #template) ->
#node.widgets().each (i, elem) =>
data = if #data then #data[i] else null
node = $(elem)
#editor_for_node node, data
editor_for_node: (node, data) ->
console.log 'hello!'
return {
'Editor': Editor,
}
When the line #editor_for_node node, data gets called, I get an error (in Firebug) saying this.editor_for_node is not a function.
I really can't see why this isn't working properly, the only possible source of weirdness that I can see is my use of require.js's define function at the start.
Edit: Generated output
(function() {
define(['jquery'], function($) {
var Editor;
Editor = (function() {
Editor.name = 'Editor';
function Editor(node, data, template) {
var _this = this;
this.node = node;
this.data = data;
this.template = template;
this.node.widgets().each(function(i, elem) {
data = _this.data ? _this.data[i] : null;
node = $(elem);
return _this.editor_for_node(node, data);
});
}
Editor.prototype.editor_for_node = function(node, data) {
return console.log('hello!');
};
return Editor;
})();
return {
'Editor': Editor
};
});
}).call(this);
First: Which version of CoffeeScript are you using? The fat arrow has been a source of bugs in certain previous releases.
If you're using the latest (1.3.1), then I'm going to go ahead and say that this is an indentation issue. When I copy and paste your code, it works fine. Are you mixing tabs and spaces? Verify that the compiled output contains the line
Editor.prototype.editor_for_node = ...
Update: See the comments on this answer. Turns out the problem was that the new keyword wasn't being used when invoking the constructor.

tinymce.dom.replace throws an exception concerning parentNode

I'm writing a tinyMce plugin which contains a section of code, replacing one element for another. I'm using the editor's dom instance to create the node I want to insert, and I'm using the same instance to do the replacement.
My code is as follows:
var nodeData =
{
"data-widgetId": data.widget.widgetKey(),
"data-instanceKey": "instance1",
src: "/content/images/icon48/cog.png",
class: "widgetPlaceholder",
title: data.widget.getInfo().name
};
var nodeToInsert = ed.dom.create("img", nodeData);
// Insert this content into the editor window
if (data.mode == 'add') {
tinymce.DOM.add(ed.getBody(), nodeToInsert);
}
else if (data.mode == 'edit' && data.selected != null) {
var instanceKey = $(data.selected).attr("data-instancekey");
var elementToReplace = tinymce.DOM.select("[data-instancekey=" + instanceKey + "]");
if (elementToReplace.length === 1) {
ed.dom.replace(elementToReplace[0], nodeToInsert);
}
else {
throw new "No element to replace with that instance key";
}
}
TinyMCE breaks during the replace, here:
replace : function(n, o, k) {
var t = this;
if (is(o, 'array'))
n = n.cloneNode(true);
return t.run(o, function(o) {
if (k) {
each(tinymce.grep(o.childNodes), function(c) {
n.appendChild(c);
});
}
return o.parentNode.replaceChild(n, o);
});
},
..with the error Cannot call method 'replaceChild' of null.
I've verified that the two argument's being passed into replace() are not null and that their parentNode fields are instantiated. I've also taken care to make sure that the elements are being created and replace using the same document instance (I understand I.E has an issue with this).
I've done all this development in Google Chrome, but I receive the same errors in Firefox 4 and IE8 also. Has anyone else come across this?
Thanks in advance
As it turns out, I was simply passing in the arguments in the wrong order. I should have been passing the node I wanted to insert first, and the node I wanted to replace second.