I would like to know the simplest way to detect a first-run in a Firefox addon. I prefer not to use the (SQLite) Storage API as this seems way overkill for this simple usecase.
I guess my question could also be: what is the simplest way to store a flag?
There you go: http://mike.kaply.com/2011/02/02/running-add-on-code-at-first-run-and-upgrade/
var firstrun = Services.prefs.getBoolPref("extensions.YOUREXT.firstrun");
var curVersion = "0.0.0";
if (firstrun) {
Services.prefs.setBoolPref("extensions.YOUREXT.firstrun", false);
Services.prefs.setCharPref("extensions.YOUREXT.installedVersion", curVersion);
/* Code related to firstrun */
} else {
try {
var installedVersion = Services.prefs.getCharPref("extensions.YOUREXT.installedVersion");
if (curVersion > installedVersion) {
Services.prefs.setCharPref("extensions.YOUREXT.installedVersion", curVersion);
/* Code related to upgrade */
}
} catch (ex) {
/* Code related to a reinstall */
}
}
Maybe a better solution would be:
/**
* Check if this is the first run of the addon
*/
function checkFirstRun(){
if(ss.storage.firstRun == undefined){
ss.storage.firstRun = false;
return true;
}
else{
return false;
}
}
Related
I hope someone can help me here. How can I use this Autoptimize snippet to exclude two pages from optimization. The code below excludes the page "https//www.nameofsite/submit-an-article"
add_filter(‘autoptimize_filter_noptimize’,’submit_noptimize’,10,0);
function submit_noptimize() {
if (strpos($_SERVER[‘REQUEST_URI’],’submit-an-article’)!==false) {
return true;
} else {
return false;
}
}
I want to exclude also another page-->"https//:www.nameofsite.com/upload/file" I modified and tried to use the code below but it gave me an error.
add_filter(‘autoptimize_filter_noptimize’,’submit_noptimize’,10,0);
function submit_noptimize() {
if (strpos($_SERVER[‘REQUEST_URI’],’submit-an-article’, 'upload-
file')!==false) {
return true;
} else {
return false;
}
}
Perhaps, I did something wrong with code? Hope someone can help me here. I am just a newbie. Not really familiar in php. Thank you in advanced.
Try this:
// Disable autoptimize on all pages with the words "term1" or "term2" in the URL
add_filter('autoptimize_filter_noptimize','my_ao_noptimize',10,0);
function my_ao_noptimize() {
if (strpos($_SERVER['REQUEST_URI'],'term1')!==false || strpos($_SERVER['REQUEST_URI'],'term2')!==false) {
return true;
} else {
return false;
}
}
I try to implement Mixpanel's tweaks into my app for A/B testing. This is my code:
if (MPTweakValue(kFeaturedOffersTweak, NO)) {
return MenuItemRowHeight;
}
else {
return 0;
}
On the first lunch everything is OK and tweak value is YES. Then I switch off internet on my iPhone, open run again and tweak value is NO.
What is correct way to use Mixpanel's tweak without internet?
So, I created my custom manager, where I implemented tweaks' persistency.
Please, let me know, if you have better solution.
My code:
-(void)initManager {
[[Mixpanel sharedInstance] joinExperimentsWithCallback:^{
USE_SETTINGS;
SETTINGS_SETBOOL(kPreferredPartnersTweak, MPTweakValue(kPreferredPartnersTweak, NO));
SYNCHRONIZE_SETTINGS;
//===
SEND_NOTIF(kTweaksUpdated, nil);
}];
}
-(BOOL)getTweakWithName:(NSString*)tweakName {
BOOL result = NO;
//===
USE_SETTINGS;
if (SETTINGS_BOOL(tweakName)) {
result = SETTINGS_BOOL(tweakName);
}
else {
result = MPTweakValue(kPreferredPartnersTweak, NO);
}
//===
return result;
}
USE_SETTINGS, SETTINGS_BOOL, SYNCHRONIZE_SETTINGS is my macros wrappers for working with NSUserDefaults.
I was re-reading this post here: https://stackoverflow.com/a/24473888/1828637
And got concerned about if I did things correctly. This is how I do unloading:
So I set up some stuff per window. And unload them on shutdown. (i dont unload on window close, i havent found a need to yet, as when it closes, everything i added to it goes with with the close [such as my mutation observers]).
All code below is theoretical, the mutation stuff is example, so there might be typos or bugs in it. I was wondering if the idea behind it is appropriate:
var unloadersOnShutdown = [];
var unloadersOnClose = [];
function startup() {
let DOMWindows = Services.wm.getEnumerator(null);
while (DOMWindows.hasMoreElements()) {
let aDOMWindow = DOMWindows.getNext();
var worker = new winWorker(aDOMWindow);
unloadersOnShutdown.push({DOMWindow: aDOMWindow, fn: worker.destroy});
}
}
function shutdown() {
Array.forEach.call(unloadersOnShutdown, function(obj) {
//should probably test if obj.DOMWindow exists/is open, but just put it in try-ctach
try {
obj.fn();
} catch(ex) {
//window was probably closed
console.warn('on shutdown unlaoder:', ex);
}
});
}
function winWorker(aDOMWindow) {
this.DOMWindow = aDOMWindow;
this.init();
}
winWorker.prototype = {
init: function() {
this.gMutationObserver = new this.DOMWindow.MutationObserver(gMutationFunc.bind(this));
this.myElement = this.DOMWindow.querySelector('#myXulEl');
this.gMutationObserver.observe(this.myElement, gMutationConfig);
if (this.DOMWindow.gBrowser && this.DOMWindow.gBrowser.tabContainer) {
this.onTabSelectBinded = this.onTabSelect.bind(this);
this.gBrowser.tabContainer.addEventListener('TabSelect', this.onTabSelectBinded, false);
}
},
destroy: function() {
this.gMutationObserver.disconnect();
if (this.onTabSelectBinded) {
this.gBrowser.tabContainer.removeEventListener('TabSelect', this.onTabSelectBinded, false);
}
},
onTabSelect: function() {
console.log('tab selected = ', thisDOMWindow.gBrowser.selectedTab);
}
};
var windowListener = {
onOpenWindow: function (aXULWindow) {},
onCloseWindow: function (aXULWindow) {
var DOMWindow = aXULWindow.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowInternal || Ci.nsIDOMWindow);
for (var i=0; i<unloadersOnClose.length; i++) {
if (unloadersOnClose.DOMWindow == DOMWindow) {
try {
unloadersOnClose.fn();
} catch(ex) {
console.warn('on close unloader:', ex);
}
unloadersOnClose.splice(i, 1);
i--;
}
}
},
onWindowTitleChange: function (aXULWindow, aNewTitle) {},
}
I think one problem is me not using weak references with DOMWindows but I'm not sure.
The idea around unloaders in general seems to be OK, but very limited (to windows only).
The implementation is lacking. E.g. there is a big, fat bug:
unloadersOnShutdown.push({DOMWindow: aDOMWindow, fn: worker.destroy});
// and
obj.fn();
// or
unloadersOnClose.fn();
This will call winWorker.prototype.destroy with the wrong this.
The i++/i-- loop also looks, um... "interesting"?!
Also, keep in mind that there can be subtle leaks, so you should mind and test for Zombie compartments.
Not only can a window leak parts of your add-on (e.g. bootstrap.js) but it is also possible to leak closed windows by keeping references in your add-on. And of course, it's not just windows you need to care about, but also e.g. observers, other types of (XPCOM) listeners etc.
I know event.type in DOM. I can parse for example mouseup, keydown, touchstart and so on. But how can I check for the event subclass? Like MouseEvent, AnimationEvent or ClipboardEvent? Can I use the event.type property?
You can check the class like
void myHandler(Event e) {
if(e is MouseEvent) {
print('Mouse');
} else if(e is AnimationEvent) {
print('Animation');
} else if(e is KeyboardEvent) {
print('Keyboard');
}
}
Since JavaScript is a prototype-based language you can to do it a bit strangely using Object.prototype.toString.call() and then cleaning up the result a little, like this:
var button = document.getElementById("testEvent");
button.onclick = function(e) {
console.log(
Object.prototype.toString.call(e).replace(/^\[object ([^\]]*)\]/, "$1")
);
}
This fiddle shows it in action - http://jsfiddle.net/SrmGJ/1/ working for me in FireFox. It should output "MouseEvent" in the fiddle, but if you hook it up to some of the other events, you will see different results.
Another method would be to call EventType.prototype.isPrototypeOf(e) for each of the types:
...
if (MouseEvent.prototype.isPrototypeOf(e)) { console.log("MouseEvent"); }
if (AnimationEvent.prototype.isPrototypeOf(e)) { console.log("AnimationEvent"); }
if (KeyboardEvent.prototype.isPrototypeOf(e)) { console.log("KeyboardEvent"); }
...
But that would look pretty nasty IMHO.
I think I've gotten the most simplest scenario built. I just want to pass it by everyone for a sanity check. Here's the idea:
GetErrorCodes.cfm does the following:
<cfscript>
response = new ErrorCodes().WhereXXX(); // ACF or Railo, doesn't matter
</cfscript>
ErrorCodes.cfc:
function WhereXXX() {
return new sproc().exec('app.GetErrorCodes'); // All my functions will do this instead of executing the sproc themselves.
}
sproc.cfc:
component {
function exec(procedure) {
local.result = {};
if (server.ColdFusion.productname == 'Railo') {
return new Railo().exec(arguments.procedure); // Has to be outside of sproc.cfc because ColdFusion throws a syntax error otherwise.
}
local.svc = new storedProc();
local.svc.setProcedure(arguments.procedure);
local.svc.addProcResult(name='qry');
try {
local.obj = local.svc.execute();
local.result.Prefix = local.obj.getPrefix();
local.result.qry = local.obj.getProcResultSets().qry;
} catch(any Exception) {
request.msg = Exception.Detail;
}
return local.result;
}
Railo.cfc:
component {
function exec(procedure) {
local.result = {};
try {
storedproc procedure=arguments.procedure result="local.result.Prefix" returncode="yes" {
procresult name="local.result.qry";
}
} catch(any Exception) {
request.msg = Exception.Message;
}
return local.result;
}
}
So I've been working on this all day, but tell me, is this a sane way to keep the source code the same if it's to be run on either a ColdFusion server or a Railo server?
Um... just use <cfstoredproc> instead of trying to use two different CFScript approaches that are mutually exclusive to each other of the CFML platforms.