I am using Driftbot, See Here
and am trying to get it to enable/disable based on the current route/url. I AM USING REACT-ROUTER.
I am able to use drift.unload() to stop it from running (in my componentWillMount() function) but am unable to get it started back up again.
We have some code that was pulled from here on SO that has been working, except we now need to modify it such that it is disabled on specific pages.
Here is the code we are currently using:
let driftbot_function = function() {
!function() {
var t;
if (t = window.driftt = window.drift = window.driftt || [], !t.init) return t.invoked ? void (window.console && console.error && console.error("Drift snippet included twice.")) : (t.invoked = !0,
t.methods = [ "identify", "config", "track", "reset", "debug", "show", "ping", "page", "hide", "off", "on"],
t.factory = function(e) {
return function() {
var n;
return n = Array.prototype.slice.call(arguments), n.unshift(e), t.push(n), t;
};
}, t.methods.forEach(function(e) {
t[e] = t.factory(e);
}), t.load = function(t) {
var e, n, o, i;
e = 3e5, i = Math.ceil(new Date() / e) * e, o = document.createElement("script"),
o.type = "text/javascript", o.async = !0, o.crossorigin = "anonymous", o.src = "https://js.driftt.com/include/" + i + "/" + t + ".js",
n = document.getElementsByTagName("script")[0], n.parentNode.insertBefore(o, n);
});
}();
drift.SNIPPET_VERSION = '0.3.1';
drift.load('****__our-key__****');
drift.page();
}
driftbot_function();
This is currently in the componentDidMount() of our app.js since it is our root '/'. I have also tried moving this over inside a script tag in index.html but had the same results.
When linking to a part of the app I want it disabled, the only method that will disable it is window.drift.unload(). .hide and .off will not work.
When going back to the root, I have the command, window.drift.load(), but now it is an empty function, where before running the unload() function it was working.
I have also tried including the functions found in the Drift Docs linked above in both my root.js and app.js files to no avail
Does anyone have any ideas?
So this was a very confusing ride but I finally figured it out with the help of some of the engineers over at drift.
First of all, in the settings of their dash when you "blacklist" urls you need to only include keywords not full URLs (my first mistake).
Secondly, put the fucntion in a script in the index.html file
Thirdly, find all of the top-level route components where you want the widget to be disabled and include the following code like in their react article
componentWillMount() {
drift.page(this.props.location.pathname)
}
componentWillReceiveProps(nextProps) {
if (nextProps.location.pathname !== this.props.location.pathname) {
drift.page(nextProps.location.pathname)
}
}
This will basically re-initialize the widget and run a .includes check from your provided url (this.props.location.pathname) against the keywords in your settings blacklist. It will then disable it or enable it depending on the results.
There you go, good luck to anyone else stuck on this...
drift.page() was not working for me
i am using the npm package for react
https://github.com/chardmd/react-drift
drift is included in one of my top level components
<Drift appId='123456789' />
<Favicon url={this.favicon} />
<Meta
meta={this.state.data.metaTags}
/>
routes rules are set then set as normal in the drift UI
componentDidUpdate (prevProps, prevState, snapshot) {
const prevLoc = prevProps.location.pathname
const newLoc = this.props.location.pathname
if (prevLoc !== newLoc) {
window.drift.reset()
I can think of two options for your case. First would be to create a component only for starting/stopping driftbot. You would initialise driftbot on componentDidMount then call window.drift.unload() on componentWillUnmount. Then instead of wrapping the whole app with it, you drop it only in the home page, in a way it will be unmounted when you navigate to another section.
The other option, since you mentioned React Router, would be to watch the location of the app, either using history.listen - https://github.com/ReactTraining/history - or checking the props provided by React Router - https://reacttraining.com/react-router/web/api/location - on componentWillUpdate, then turning driftbot on and off based on the current url.
Related
Here's the relevant code-
CONFIG.theme.activeScheme ? react.createElement(SortBox, {
onChange: this.updateColourScheme.bind(this),
onnewschemes: this.setState({}),
// TODO: Make this compatible with the changes to the theme install process: need to create a method to update the scheme options without a full reload.
sortBoxOptions: generateSchemesOptions(CONFIG.theme.schemes),
// It doesn't work when I directly use CONFIG.theme.activeScheme in the sortBySelectedFn
// because it hardcodes the value into the fn
sortBySelectedFn: (a) => a.key === this.getActiveScheme(),
}) : null,
My preferred end result is to be able to reload JUST the sortbox component using an via the onnewschemes event(I pretty much need to refresh all of the options within a little drop down method from outside the render itself.)
The event dispatcher i have looks like so:
const schemeSelector = document.querySelector("div.marketplace-header > div > div");
const newSchemeEvent = new CustomEvent("newschemes", {
bubbles: true,
detail: { schemes: () => parsedSchemes },
});
schemeSelector.dispatchEvent(newSchemeEvent);
I have some code in a web worker that is working perfectly locally, but as soon as I build and deploy (which minifies the code) it no longer works.
The unminified code looks like this:
const mapSourceCode = (treeNode, mfi, {objectType, types, fileType, templateType}) => {
let sourceCodeMap = new Map();
let ownerMap = new Map();
let sourceCodeList = [];
let ownerList = [];
let mfiMap = new Map();
mfi.forEach(row => mfiMap.set(row.uuid, row));
let sourceCodeObjects = mfi.filter(row => types.includes(row.objectTypeUuid));
if(sourceCodeObjects.length < 1)
return {sourceCodeMap, sourceCodeTree: undefined};
try {
sourceCodeObjects.forEach(sourceObj => {
let owner = findOwner(sourceObj, sourceObj, mfiMap, {...treeNode.data}, objectType);
The minified code is this:
i = function(e, t, n) {
var c = n.objectType
, o = n.types
, i = n.fileType
, u = n.templateType
, l = new Map
, s = new Map
, f = []
, p = []
, m = new Map;
t.forEach((function(e) {
return m.set(e.uuid, e)
}
));
var h = t.filter((function(e) {
return o.includes(e.objectTypeUuid)
}
));
if (h.length < 1)
return {
sourceCodeMap: l,
sourceCodeTree: void 0
};
try {
if (h.forEach((function(n) {
var r = a(n, n, m, Object(d.a)({}, e.data), c);
The line it's erroring out on is {...treeNode.data} on the last line.
The error is ReferenceError: d is not defined
I can't figure out what the issue could be? Like I said everything runs great on locally. Any help is greatly appreciated
I found the issue, in case anybody runs into this same thing.
Normally when using web workers you need to tell your builder (webpack) to build / compile workers separately. I'm using the default create-react-app configuration which doesn't give access to that part of webpack. unless you eject from create-react-app completely (which I'm currently not ready to do)
I'm using the react hook called useWorker, where I pass the function I want to allocate to the worker.
When your code is optimized and minified variable names are replaced with smaller names (mostly 1 or 2 letters from what I've seen). Because I didn't have any custom loaders to load my worker code, it used variables from the global scope assuming it would have access. When the code was extracted to a separate thread outside the main thread it no longer had access to those variables and thus didn't work.
The fix is to
Add a loader (you can either eject from create-react-app, or there may be some npm libraries that will give you access to that particular part of webpack)
Or my solution was to create the function in a string and create a function using the Function constructor like so
const generateFunction = new Function('treeNode', 'mfi', 'types', 'action', generateFunctionString);
Where the generateFunctionString was a string like: "return a + b"
I then passed that function into my useWorker hook:
const [generatorWorker] = useWorker(generateFunction);
I'm doing some optimisation on a site Ive recently taken over. I've found a script I don't recognise:
http://static.ak.fbcdn.net/rsrc.php/zo/r/V95Lkt_uLNB.js
It could be a facebook thing, and there's some key logging going on (that Im not too keen on)
It is without a doubt the largest file being requested on a page load (87kb) so if I can do without it, it'll really speed up the page load.
Does anyone know:
A) What it is
B) What it's for
C) What it does
D) Can I do without it
Okay so I had a look over the beautified version of this minified code and have noted the following:
By itself these are a bunch of utility functions.
CavalryLogger doesn't do anything with this file by itself because it doesn't exist, nor is it defined.
The code in question regarding key binding:
function KeyEventController() {
copy_properties(this, {
handlers: {}
});
document.onkeyup = this.onkeyevent.bind(this, 'onkeyup');
document.onkeydown = this.onkeyevent.bind(this, 'onkeydown');
document.onkeypress = this.onkeyevent.bind(this, 'onkeypress');
}
copy_properties(KeyEventController, {
instance: null,
getInstance: function () {
return KeyEventController.instance || (KeyEventController.instance = new KeyEventController());
},
defaultFilter: function (event, a) {
event = $E(event);
return KeyEventController.filterEventTypes(event, a) && KeyEventController.filterEventTargets(event, a) && KeyEventController.filterEventModifiers(event, a);
},
filterEventTypes: function (event, a) {
if (a === 'onkeydown') return true;
return false;
},
filterEventTargets: function (event, b) {
var a = $E(event).getTarget();
if (DOM.isNode(a, ['input', 'select', 'textarea', 'object', 'embed'])) if (a.type != 'checkbox' && a.type != 'radio' && a.type != 'submit') return false;
return a.getAttribute('contentEditable') != 'true';
},
filterEventModifiers: function (event, a) {
if (event.ctrlKey || event.altKey || event.metaKey || event.repeat) return false;
return true;
},
registerKey: function (f, a, d, g) {
if (d === undefined) d = KeyEventController.defaultFilter;
var b = KeyEventController.getInstance();
var c = b.mapKey(f);
if (is_empty(b.handlers)) onleaveRegister(b.resetHandlers.bind(b));
for (var e = 0; e < c.length; e++) {
f = c[e];
if (!b.handlers[f] || g) b.handlers[f] = [];
b.handlers[f].push({
callback: a,
filter: d
});
}
},
keyCodeMap: {
'[': [219],
']': [221],
'`': [192],
LEFT: [KEYS.LEFT, 63234],
RIGHT: [KEYS.RIGHT, 63235],
RETURN: [KEYS.RETURN],
TAB: [KEYS.TAB],
DOWN: [KEYS.DOWN, 63233],
UP: [KEYS.UP, 63232],
ESCAPE: [KEYS.ESC],
BACKSPACE: [KEYS.BACKSPACE],
DELETE: [KEYS.DELETE]
}
});
copy_properties(KeyEventController.prototype, {
mapKey: function (a) {
if (typeof (a) == 'number') return [48 + a, 96 + a];
if (KeyEventController.keyCodeMap[a.toUpperCase()]) return KeyEventController.keyCodeMap[a.toUpperCase()];
var b = a.toUpperCase().charCodeAt(0);
return [b];
},
onkeyevent: function (i, c) {
c = $E(c);
var d = null;
var g = this.handlers[c.keyCode];
var b, f, a;
if (g) for (var h = 0; h < g.length; h++) {
b = g[h].callback;
f = g[h].filter;
try {
if (!f || f(c, i)) {
var node = null;
if (window.Parent && Parent.byTag && c.getTarget) node = Parent.byTag(c.getTarget(), 'a');
user_action(node, 'key', c);
a = b(c, i);
if (a === false) return Event.kill(c);
}
} catch (e) {}
}
return true;
},
resetHandlers: function () {
this.handlers = {};
}
});
This code lets you bind keys to callbacks, and includes more human readable names for common keys. Take for example the usage here:
KeyEventController.registerKey('ESCAPE', Dialog._handleEscapeKey, a);
The ESCAPE key is registered to make Dialogs go away. handlers is also empty by default, so nothing is going to happen until you use registerKey or append to it manually. Note that this is the only instance of registerKey being called.
It also has a lot of AJAX utility functions. Can't really send anything to Facebook from your domain anyways because of same origin policy (unless you modified security permissions, but then that's your fault). Same thing with the cookies set.
There's also a history manger, but it uses an iFrame so it won't be able to read it from your domain anyways.
Finally the like button code I found is an iFrame, so it wouldn't need JS includes unless you were using javascript to create the iFrame or something.
With that in mind I don't see the need for you to include all this.
It looks like this is directly connected to having the "Like this" functionality on a page. The iframe you use to include the 'Like' button seems to come with a couple of 'bonus' scripts.
If you ask me, this is another good reason to NOT have Facebook integrated, it appears to be logging keypresses, and that is not cool.
A quick google search doesn't provide alot of answers - it's some sort of event tracking script for Facebook, and I saw a tweet and a couple of forum posts where people mentioned disabling it and gaining a speed boost - I think you can safely get rid of it, atleast it's worth giving it a try.
This is definitely from Facebook - one of many supporting files for FBML / API / etc.
If you are not using any FB features in your project, simply remove this file.
If you are using any FB features (like 'Like' button), you shouldn't use this file (or any other files with cryptic names) directly either.
You should instead
1) create empty <div id="fb-root"></div> somewhere at the end f your page
2) include http://connect.facebook.net/en_US/all.js script in your page
3) follow further instructions from http://developers.facebook.com/
When the IFRAME is loaded it calls the following URI:
https://www.facebook.com/plugins/like.php?api_key=[your_api_key]&channel_url=http%3A%2F%2Fstatic.ak.facebook.com%2Fconnect%2Fxd_arbiter.php%3Fversion%3D27%23cb%3Df39f390d40f7332%26domain%3D[your_TLD]%26origin%3Dhttp%253A%252F%252F[your_TLD]%252Ff72f1f9bea899e%26relation%3Dparent.parent&colorscheme=light&extended_social_context=false&href=[your_share_URI]&layout=button_count&locale=en_US&node_type=link&sdk=joey&send=false&show_faces=false&width=100
Within the script tags of this page are the following calls.
PluginAsyncLoader.load("**https:\/\/fbstatic-a.akamaihd.net\/rsrc.php\/v2\/yq\/r\/CNRdIwfy3yI.js**");
PluginAsyncLoader.ondemandjs = "**https:\/\/fbstatic-a.akamaihd.net\/rsrc.php\/v2\/yH\/r\/muz85bheueJ.js**";
I found "calverly logger" in a file that I did not download but I saw it download right in front of me when I closed Thunderbird (was running Firefox behind it and it showed up there as a file downloading) so went to check what it was.
The file was called: "See All.html" which I found odd and worrying.
the head of the file contains the following code indicating it is a Facebook function...
The Calvery Logger is mentioned near the bottom of the file (not shown here). I have stripped out the html < near the head of the file so that you can see the code... Not sure it will help but look forward to any insights...
// !DOCTYPE html
html lang="en" id="facebook" class="no_js"
head
meta charset="utf-8" />
meta name="referrer" content="origin-when-crossorigin" id="meta_referrer" />
script> window._cstart=+new Date();</script><script>function envFlush(a) {function b(c){for(var d in a)c[d]=a[d];}if(window.requireLazy){window.requireLazy(['Env'],b);}else{window.Env=window.Env||{};b(window.Env);}}envFlush({"ajaxpipe_token":"AXiYOZarFarwOff3","lhsh":"AAQFK_mp-","khsh":"0`sj`e`rm`s-0fdu^gshdoer-0gc^eurf-3gc^eurf;1;enbtldou;fduDmdldourCxO`ld-2YLMIuuqSdptdru;qsnunuxqd;rdoe-0unjdojnx-0unjdojnx0-0gdubi^rdbsduOdv-0`sj`e`r-0q`xm`r-0StoRbs`qhof-0mhoj^q`xm`r","timeslice_heartbeat_config":{"pollIntervalMs":33,"idleGapThresholdMs":60,"ignoredTimesliceNames":{"requestAnimationFrame":true,"Event listenHandler mousemove":true,"Event listenHandler mouseover":true,"Event listenHandler mouseout":true,"Event listenHandler scroll":true},"enableOnRequire":true},"shouldLogCounters":false,"timeslice_categories":{"react_render":true,"reflow":true}}); script> style> style>
It's linked to a virus hacker on Facebook, sending videos to all the friends of the person who's been hacked. If you open such a video, you too become hacked and all your friends get the video too. Do not open any suspect videos or messages, particularly in Messenger.
I'm doing some optimisation on a site Ive recently taken over. I've found a script I don't recognise:
http://static.ak.fbcdn.net/rsrc.php/zo/r/V95Lkt_uLNB.js
It could be a facebook thing, and there's some key logging going on (that Im not too keen on)
It is without a doubt the largest file being requested on a page load (87kb) so if I can do without it, it'll really speed up the page load.
Does anyone know:
A) What it is
B) What it's for
C) What it does
D) Can I do without it
Okay so I had a look over the beautified version of this minified code and have noted the following:
By itself these are a bunch of utility functions.
CavalryLogger doesn't do anything with this file by itself because it doesn't exist, nor is it defined.
The code in question regarding key binding:
function KeyEventController() {
copy_properties(this, {
handlers: {}
});
document.onkeyup = this.onkeyevent.bind(this, 'onkeyup');
document.onkeydown = this.onkeyevent.bind(this, 'onkeydown');
document.onkeypress = this.onkeyevent.bind(this, 'onkeypress');
}
copy_properties(KeyEventController, {
instance: null,
getInstance: function () {
return KeyEventController.instance || (KeyEventController.instance = new KeyEventController());
},
defaultFilter: function (event, a) {
event = $E(event);
return KeyEventController.filterEventTypes(event, a) && KeyEventController.filterEventTargets(event, a) && KeyEventController.filterEventModifiers(event, a);
},
filterEventTypes: function (event, a) {
if (a === 'onkeydown') return true;
return false;
},
filterEventTargets: function (event, b) {
var a = $E(event).getTarget();
if (DOM.isNode(a, ['input', 'select', 'textarea', 'object', 'embed'])) if (a.type != 'checkbox' && a.type != 'radio' && a.type != 'submit') return false;
return a.getAttribute('contentEditable') != 'true';
},
filterEventModifiers: function (event, a) {
if (event.ctrlKey || event.altKey || event.metaKey || event.repeat) return false;
return true;
},
registerKey: function (f, a, d, g) {
if (d === undefined) d = KeyEventController.defaultFilter;
var b = KeyEventController.getInstance();
var c = b.mapKey(f);
if (is_empty(b.handlers)) onleaveRegister(b.resetHandlers.bind(b));
for (var e = 0; e < c.length; e++) {
f = c[e];
if (!b.handlers[f] || g) b.handlers[f] = [];
b.handlers[f].push({
callback: a,
filter: d
});
}
},
keyCodeMap: {
'[': [219],
']': [221],
'`': [192],
LEFT: [KEYS.LEFT, 63234],
RIGHT: [KEYS.RIGHT, 63235],
RETURN: [KEYS.RETURN],
TAB: [KEYS.TAB],
DOWN: [KEYS.DOWN, 63233],
UP: [KEYS.UP, 63232],
ESCAPE: [KEYS.ESC],
BACKSPACE: [KEYS.BACKSPACE],
DELETE: [KEYS.DELETE]
}
});
copy_properties(KeyEventController.prototype, {
mapKey: function (a) {
if (typeof (a) == 'number') return [48 + a, 96 + a];
if (KeyEventController.keyCodeMap[a.toUpperCase()]) return KeyEventController.keyCodeMap[a.toUpperCase()];
var b = a.toUpperCase().charCodeAt(0);
return [b];
},
onkeyevent: function (i, c) {
c = $E(c);
var d = null;
var g = this.handlers[c.keyCode];
var b, f, a;
if (g) for (var h = 0; h < g.length; h++) {
b = g[h].callback;
f = g[h].filter;
try {
if (!f || f(c, i)) {
var node = null;
if (window.Parent && Parent.byTag && c.getTarget) node = Parent.byTag(c.getTarget(), 'a');
user_action(node, 'key', c);
a = b(c, i);
if (a === false) return Event.kill(c);
}
} catch (e) {}
}
return true;
},
resetHandlers: function () {
this.handlers = {};
}
});
This code lets you bind keys to callbacks, and includes more human readable names for common keys. Take for example the usage here:
KeyEventController.registerKey('ESCAPE', Dialog._handleEscapeKey, a);
The ESCAPE key is registered to make Dialogs go away. handlers is also empty by default, so nothing is going to happen until you use registerKey or append to it manually. Note that this is the only instance of registerKey being called.
It also has a lot of AJAX utility functions. Can't really send anything to Facebook from your domain anyways because of same origin policy (unless you modified security permissions, but then that's your fault). Same thing with the cookies set.
There's also a history manger, but it uses an iFrame so it won't be able to read it from your domain anyways.
Finally the like button code I found is an iFrame, so it wouldn't need JS includes unless you were using javascript to create the iFrame or something.
With that in mind I don't see the need for you to include all this.
It looks like this is directly connected to having the "Like this" functionality on a page. The iframe you use to include the 'Like' button seems to come with a couple of 'bonus' scripts.
If you ask me, this is another good reason to NOT have Facebook integrated, it appears to be logging keypresses, and that is not cool.
A quick google search doesn't provide alot of answers - it's some sort of event tracking script for Facebook, and I saw a tweet and a couple of forum posts where people mentioned disabling it and gaining a speed boost - I think you can safely get rid of it, atleast it's worth giving it a try.
This is definitely from Facebook - one of many supporting files for FBML / API / etc.
If you are not using any FB features in your project, simply remove this file.
If you are using any FB features (like 'Like' button), you shouldn't use this file (or any other files with cryptic names) directly either.
You should instead
1) create empty <div id="fb-root"></div> somewhere at the end f your page
2) include http://connect.facebook.net/en_US/all.js script in your page
3) follow further instructions from http://developers.facebook.com/
When the IFRAME is loaded it calls the following URI:
https://www.facebook.com/plugins/like.php?api_key=[your_api_key]&channel_url=http%3A%2F%2Fstatic.ak.facebook.com%2Fconnect%2Fxd_arbiter.php%3Fversion%3D27%23cb%3Df39f390d40f7332%26domain%3D[your_TLD]%26origin%3Dhttp%253A%252F%252F[your_TLD]%252Ff72f1f9bea899e%26relation%3Dparent.parent&colorscheme=light&extended_social_context=false&href=[your_share_URI]&layout=button_count&locale=en_US&node_type=link&sdk=joey&send=false&show_faces=false&width=100
Within the script tags of this page are the following calls.
PluginAsyncLoader.load("**https:\/\/fbstatic-a.akamaihd.net\/rsrc.php\/v2\/yq\/r\/CNRdIwfy3yI.js**");
PluginAsyncLoader.ondemandjs = "**https:\/\/fbstatic-a.akamaihd.net\/rsrc.php\/v2\/yH\/r\/muz85bheueJ.js**";
I found "calverly logger" in a file that I did not download but I saw it download right in front of me when I closed Thunderbird (was running Firefox behind it and it showed up there as a file downloading) so went to check what it was.
The file was called: "See All.html" which I found odd and worrying.
the head of the file contains the following code indicating it is a Facebook function...
The Calvery Logger is mentioned near the bottom of the file (not shown here). I have stripped out the html < near the head of the file so that you can see the code... Not sure it will help but look forward to any insights...
// !DOCTYPE html
html lang="en" id="facebook" class="no_js"
head
meta charset="utf-8" />
meta name="referrer" content="origin-when-crossorigin" id="meta_referrer" />
script> window._cstart=+new Date();</script><script>function envFlush(a) {function b(c){for(var d in a)c[d]=a[d];}if(window.requireLazy){window.requireLazy(['Env'],b);}else{window.Env=window.Env||{};b(window.Env);}}envFlush({"ajaxpipe_token":"AXiYOZarFarwOff3","lhsh":"AAQFK_mp-","khsh":"0`sj`e`rm`s-0fdu^gshdoer-0gc^eurf-3gc^eurf;1;enbtldou;fduDmdldourCxO`ld-2YLMIuuqSdptdru;qsnunuxqd;rdoe-0unjdojnx-0unjdojnx0-0gdubi^rdbsduOdv-0`sj`e`r-0q`xm`r-0StoRbs`qhof-0mhoj^q`xm`r","timeslice_heartbeat_config":{"pollIntervalMs":33,"idleGapThresholdMs":60,"ignoredTimesliceNames":{"requestAnimationFrame":true,"Event listenHandler mousemove":true,"Event listenHandler mouseover":true,"Event listenHandler mouseout":true,"Event listenHandler scroll":true},"enableOnRequire":true},"shouldLogCounters":false,"timeslice_categories":{"react_render":true,"reflow":true}}); script> style> style>
It's linked to a virus hacker on Facebook, sending videos to all the friends of the person who's been hacked. If you open such a video, you too become hacked and all your friends get the video too. Do not open any suspect videos or messages, particularly in Messenger.
Thanks to everyone in advance -
I need to load a preference before any windows are loaded at startup. Below is some /component code I have been working with. The SetPreference method seems to fail when it is called (nothing executes afterwords either) - I am assuming because the resources that it needs are not available at the time of execution...or I am doing something wrong. Any suggestions with this code or another approach to setting a preference at startup?
Thanks again,
Sam
For some reason the code formatting for SO is not working properly - here is a link to the code as well - http://samingrassia.com/_FILES/startup.js
Components.utils.import('resource://gre/modules/XPCOMUtils.jsm');
const Cc = Components.classes;
const Ci = Components.interfaces;
const ObserverService = Cc['#mozilla.org/observer-service;1'].getService(Ci.nsIObserverService);
function MyStartupService() {};
MyStartupService.prototype = {
observe : function(aSubject, aTopic, aData) {
switch (aTopic) {
case 'xpcom-startup':
this.SetPreference("my.extension.is_running", "false");
break;
case 'app-startup':
this.SetPreference("my.extension.is_running", "false");
ObserverService.addObserver(this, 'final-ui-startup', false);
break;
case 'final-ui-startup':
//make sure is_running is set to false
this.SetPreference("my.extension.is_running", "false");
ObserverService.removeObserver(this, 'final-ui-startup');
const WindowWatcher = Cc['#mozilla.org/embedcomp/window-watcher;1'].getService(Ci.nsIWindowWatcher);
WindowWatcher.registerNotification(this);
break;
case 'domwindowopened':
this.initWindow(aSubject);
break;
}
},
SetPreference : function(Token, Value) {
var prefs = Components.classes["#mozilla.org/preferences-service;1"].getService(Components.interfaces.nsIPrefService);
var str = Components.classes["#mozilla.org/supports-string;1"].createInstance(Components.interfaces.nsISupportsString);
str.data = Value;
prefs.setComplexValue(Token, Components.interfaces.nsISupportsString, str);
//save preferences
var prefService = Components.classes["#mozilla.org/preferences-service;1"].getService(Components.interfaces.nsIPrefService);
prefService.savePrefFile(null);
},
initWindow : function(aWindow) {
if (aWindow != '[object ChromeWindow]') return;
aWindow.addEventListener('load', function() {
aWindow.removeEventListener('load', arguments.callee, false);
aWindow.document.title = 'domwindowopened!';
// for browser windows
var root = aWindow.document.documentElement;
root.setAttribute('title', aWindow.document.title);
root.setAttribute('titlemodifier', aWindow.document.title);
}, false);
},
classDescription : 'My Startup Service',
contractID : '#mystartupservice.com/startup;1',
classID : Components.ID('{770825e7-b39c-4654-94bc-008e5d6d57b7}'),
QueryInterface : XPCOMUtils.generateQI([Ci.nsIObserver]),
_xpcom_categories : [{ category : 'app-startup', service : true }]
};
function NSGetModule(aCompMgr, aFileSpec) {
return XPCOMUtils.generateModule([MyStartupService]);
}
To answer your real question, which is
I have code that loads on every window load and I need to make sure that only gets executed once every time firefox starts up.
..you should just use a module, in the load handler that you wish to execute once, check a flag on the object exported from (i.e. "living in") the module, then after running the code you need, set the flag.
Since the module is shared across all windows, the flag will remain set until you close Firefox.
As for your intermediate problem, I'd suggest wrapping the code inside observe() in a try { ... } catch(e) {dump(e)} (you'll need to set a pref and run Firefox in a special way in order to see the output) and check the error returned.
I guess xpcom-startup and app-startup is too early to mess with preferences (I think you need a profile for that), note that you don't register to get xpcom-startup notification anyway. You probably want to register for profile-after-change instead.