Javascript variable is changing its value, reasons that can cause such? - javascript

I am debugging the weirdest error I ever seen. At this point my code look like this.
var counter = 0;
function setup() {
var count = ++counter;
var test = false;
function getSetter(arg?) {
if (typeof (arg) !== "undefined") {
console.log(["setting",count, arg]);
test = arg;
} else {
console.log(["getting",count, test]);
return test;
}
}
return getSetter;
}
var verticalScrollDisabled = setup();
this is in a closed scope and i have made sure that the variable test is not accessed outside the above code. I can change it to any name with same result. Updated such its clear that its not accessed outside of this scope. And updated with a counter to show its not written over.
Copy pasting result from the console.
["enter scroll area", div.fxs-blade-content, true, "3511>401 || 577>585"] HorizontalScrollBindingHandler.ts:12
["setting", 1,true] HorizontalScrollBindingHandler.ts:132
disable vert HorizontalScrollBindingHandler.ts:72
n.Event {originalEvent: WheelEvent, type: "mousewheel", isDefaultPrevented: function, timeStamp: 1422128039040, jQuery21104183536011260003: true…} HorizontalScrollBindingHandler.ts:15
["getting", 1,false] HorizontalScrollBindingHandler.ts:15
["getting", 1, false] HorizontalScrollBindingHandler.ts:75
[false, false]
Issue
As commented, my problem is that as seen in the trace. the variable get set to true, but when its being accessed again its false. I cant get why that can happen.
and the handler attached to mousescroll event.
var scrollHorizontally =(e) => {
// console.log([verticalScrollDisabled(), scrollInAction]);
console.log(e);
if (verticalScrollDisabled() && !scrollInAction)
return;
console.log([verticalScrollDisabled(), scrollInAction]);
This code has been working for ever and nothing changed to it other than we in some seperate code are opening a popup and closing it again. Is there anything that could cause events to be doing something out of the expected related to if the window loses focus or something? Again, the test variable is not altered outside the verticalcrollDisabled function, so I have no clue why it can go change itself to false, notice the ["setting", true].
Just verified that the popup is not the cause.
Heres the hole file. https://gist.github.com/s093294/e49ed46d2680c1403e3b

Answer is, validate your assumptions.
I assumed that the file was not loaded twice since it being a module defined with define and loaded with requirejs. This didnt hold up since there was some ID mapping that made two ids load this file and as one of the comments said, this is the thing that makes it possible.
I resolved the requirejs configuration and problem vent away.

Related

Prevent XUL notificationBox from closing when button is hit

I have a problem concerning the notificationBox. I create a notification using
appendNotification( label , value , image , priority , buttons, eventCallback )
and supply a button in the buttons argument.
Now, I want to prevent the notificationBox from closing when I hit the button. The XUL Documentation states that this can be done by throwing an error in the eventCallback function:
This callback can be used to prevent the notification box from closing on button click. In the callback function just throw an error. (For example: throw new Error('prevent nb close');)
This does not work for me, however, it works when I add the throw-statement to the callback function of the button itself.
Is this a bug in XUL or an inconsistency with the documentation?
Is there any harm done by adding it to the button's callback function?
In my opinion, this is an error in the documentation not a bug in the code. However, throwing an error in your button callback to prevent closure is not the best way to accomplish that goal.
Looking at the source code, there were clearly multiple discrepancies between the code and the documentation regarding how buttons work on a notification.
There is a specifically coded method of preventing the notification closing from within the button callback (return true from the callback).
Throwing an error in order to accomplish a normal functionality is usually a bad programming practice. Doing so also results in an error showing in the console every time your button is pressed. Having errors intentionally showing in the console under normal operation is bad. It also can result in your add-on not being approved in review.
As it was documented (not as operational), if you wanted to close when one button was pressed and not close when another was pressed, you would have to store in a global variable which button callback was last called and then choose based on that information if you wanted to prevent closure when your notificationBox callback was executed. That would be an inappropriately complex way to design operation of these notification buttons.
Given all that, I would say that intentionally throwing an error in order to prevent closure is not the "correct" way to do it. While, trowing an error to prevent closure doesn't cause any harm to the operation of the notification box, it does show the error in the console, which is bad.
The correct way to prevent the notification from closing from within the notification button callback is to return a True value from the callback.
While it is possible that the previously inaccurately documented way of doing this the way they intended to have it operate, it is not the way it actually works. Given
It is easier to update the documentation than it is to make changes to the code.
The code works in a way that is better than the documented method.
There were other inaccuracies in the documentation that would have prevented people from using functionality which was supposedly working (popups/menu buttons).
I have, therefore, updated the documentation to reflect what is actually in the source code and copied, with some modification, the code from this answer to an example there.
Here is some code I used to test this:
function testNotificationBoxWithButtons() {
//Create some common variables if they do not exist.
// This should work from any Firefox context.
// Depending on the context in which the function is being run,
// this could be simplified.
if (typeof window === "undefined") {
//If there is no window defined, get the most recent.
var window=Components.classes["#mozilla.org/appshell/window-mediator;1"]
.getService(Components.interfaces.nsIWindowMediator)
.getMostRecentWindow("navigator:browser");
}
if (typeof gBrowser === "undefined") {
//If there is no gBrowser defined, get it
var gBrowser = window.gBrowser;
}
function testNotificationButton1Callback(theNotification, buttonInfo, eventTarget) {
window.alert("Button 1 pressed");
//Prevent notification from closing:
//throw new Error('prevent nb close');
return true;
};
function testNotificationButton2Callback(theNotification, buttonInfo, eventTarget) {
window.alert("Button 2 pressed");
//Do not prevent notification from closing:
};
function testNotificationCallback(reason) {
window.alert("Reason is: " + reason);
//Supposedly prevent notification from closing:
//throw new Error('prevent nb close');
// Does not work.
};
let notifyBox = gBrowser.getNotificationBox();
let buttons = [];
let button1 = {
isDefault: false,
accessKey: "1",
label: "Button 1",
callback: testNotificationButton1Callback,
type: "", // If a popup, then must be: "menu-button" or "menu".
popup: null
};
buttons.push(button1);
let button2 = {
isDefault: true,
accessKey: "2",
label: "Button 2",
callback: testNotificationButton2Callback,
type: "", // If a popup, then must be: "menu-button" or "menu".
popup: null
};
buttons.push(button2);
//appendNotification( label , value , image (URL) , priority , buttons, eventCallback )
notifyBox.appendNotification("My Notification text", "Test notification unique ID",
"chrome://browser/content/aboutRobots-icon.png",
notifyBox.PRIORITY_INFO_HIGH, buttons,
testNotificationCallback);
}

Why does waitForKeyElements() only trigger once despite later changes?

For several years I've used the waitForKeyElements() function to track changes in webpages from a userscript. However, sometimes I've found it doesn't trigger as expected and have worked around out. I've run into another example of this problem, and so am now trying to figure out what the problem is. The following is the barest example I can create.
Given a simple HTML page that looks like this:
<span class="e1">blah</span>
And some Javascript:
// function defined here https://gist.github.com/BrockA/2625891
waitForKeyElements('.e1', handle_e1, false);
function handle_e1(node) {
console.log(node.text());
alert(node.text());
}
setInterval(function() {
$('.e1').text("updated: "+Math.random());
}, 5000);
I would expect this code to trigger an alert() and a console.log() every 5 seconds. However, it only triggers once. Any ideas?
Here's a codepen that demonstrates this.
By design and default, waitForKeyElements processes a node just once. To tell it to keep checking, return true from the callback function.
You'll also want to compare the string (or whatever) to see if it has changed.
So, in this case, handle_e1() would be something like:
function handle_e1 (jNode) {
var newTxt = jNode.text ();
if (typeof this.lastTxt === "undefined" || this.lastTxt !== newTxt) {
console.log (newTxt);
this.lastTxt = newTxt;
}
return true; // Allow repeat firings for this node.
}
With the constant string comparisons though, performance might be an issue if you have a lot of this on one page. In that scenario, switching to a MutationObserver approach might be best.

Automation script is not working?

This is the first time I get my hands on with automation instruments in xcode The script works well for all button taps but the one making server connection. I don't know the reason
Here is the script I tried so far
var target = UIATarget.localTarget();
target.pushTimeout(4);
target.popTimeout();
var window=target.frontMostApp().mainWindow()
var appScroll=window.scrollViews()[0];
appScroll.logElementTree();
UIATarget.localTarget().delay(2);
appScroll.buttons()[1].tap();
The above script works up to showing the UIActivityIndicator instead of moving to next controller after success
I know There must be a very simple point I am missing. So help me out
UIAutomation attempts to make things "easy" for the developer, but in doing so it can make things very confusing. It sounds like you're getting a reference to window, waiting for a button to appear, then executing .tap() on that button.
I see that you've already considered messing with target.pushTimeout(), which is related to your issue. The timeout system lets you do something that would be impossible in any sane system: get a reference to an element before it exists. I suspect that behind-the-scenes, UIAutomation repeatedly attempts to get the reference you want -- as long as the timeout will allow.
So, in the example you've posted, it's possible for this "feature" to actually hurt you.
var window=target.frontMostApp().mainWindow()
var appScroll=window.scrollViews()[0];
UIATarget.localTarget().delay(2);
appScroll.buttons()[1].tap();
What if the view changes during the 2-second delay? Your reference to target.frontMostApp().mainWindow.scrollViews()[0] may be invalid, or it may not point to the object you think you're pointing at.
We got around this in our Illuminator framework by forgetting about the timeout system altogether, and just manually re-evaluating a given reference until it actually returns something. We called it waitForChildExistence, but the functionality is basically as follows:
var myTimeout = 3; // how long we want to wait
// this function selects an element
// relative to a parent element (target) that we will pass in
var selectorFn = function (myTarget) {
var ret = myTarget.frontMostApp().mainWindow.scrollViews()[0];
// assert that ret exists, is visible, etc
return ret;
}
// re-evaluate our selector until we get something
var element = null;
var later = get_current_time() + myTimeout;
while (element === null && get_current_time() < later) {
try {
element = selectorFn(target);
} catch (e) {
// must not have worked
}
}
// check whether element is still null
// do something with element
For cases where there is a temporary progress dialog, this code will simply wait for it to disappear before successfully returning the element you want.

Determine if JavaScript syntax is valid in change handler of ACE

I'm using the ACE editor for interactive JavaScript editing. When I set the editor to JavaScript mode, ACE automatically determines if the code is valid or not, with an error message and line number highlighted when it's not.
During the change event handler, I want to detect if ACE thinks the code is valid or not before I attempt to eval() it. The only way I thought that I might do it is:
var jsMode = require("ace/mode/javascript").Mode;
var editor = ace.edit('mycode'), edEl = document.querySelector('#mycode');
editor.getSession().setMode(new jsMode);
editor.getSession().on('change',function(){
// bail out if ACE thinks there's an error
if (edEl.querySelector('div.ace_gutter-cell.ace_error')) return;
try{
eval(editor.getSession().getValue());
}catch(e){}
});
However:
Leaning on the presence of an element in the UI with a particular class seems awfully fragile, but more importantly,
The visual update for parsing occurs after the change callback occurs.
Thus, I actually have to wait more than 500ms (the delay before the JavaScript worker kicks in):
editor.getSession().on('change',function(){
setTimeout(function(){
// bail out if ACE thinks there's an error
if (edEl.querySelector('div.ace_gutter-cell.ace_error')) return;
try{
eval(editor.getSession().getValue());
}catch(e){}
},550); // Must be longer than timeout delay in javascript_worker.js
});
Is there a better way, something in an undocumented API for the JS mode, to ask whether there are any errors or not?
The current session fires onChangeAnnotation event when annotations change.
after that the new set of annotations can be retrieved as follows
var annotations = editor.getSession().getAnnotations();
seems to do the trick. It returns a JSON object which has the row as key and an array as value. The value array may have more than one object, depending on whether there are more than one annotation for each row.
the structure is as follows (copied from firebug –for a test script that I wrote)
// annotations would look like
({
82:[
{/*annotation*/
row:82,
column:22,
text:"Use the array literal notation [].",
type:"warning",
lint:{/*raw output from jslint*/}
}
],
rownumber : [ {anotation1}, {annotation2} ],
...
});
so..
editor.getSession().on("changeAnnotation", function(){
var annot = editor.getSession().getAnnotations();
for (var key in annot){
if (annot.hasOwnProperty(key))
console.log("[" + annot[key][0].row + " , " + annot[key][0].column + "] - \t" + annot[key][0].text);
}
});
// thanks http://stackoverflow.com/a/684692/1405348 for annot.hasOwnProperty(key) :)
should give you a list of all annotations in the current Ace edit session, when the annotations change!
Hope this helps!
I found a solution that is probably faster than traversing the DOM. The editor's session has a getAnnotations method you can use. Each annotation has a type that shows whether they are an error or not.
Here is how I set my callback for the on 'change'
function callback() {
var annotation_lists = window.aceEditor.getSession().getAnnotations();
var has_error = false;
// Unfortunately, you get back a list of lists. However, the first list is
// always length one (but not always index 0)
go_through:
for (var l in annotation_lists) {
for (var a in annotation_lists[l]) {
var annotation = annotation_lists[l][a];
console.log(annotation.type);
if (annotation.type === "error") {
has_error = true;
break go_through;
}
}
}
if (!has_error) {
try {
eval(yourCodeFromTextBox);
prevCode = yourCodeFromTextBox;
}
catch (error) {
eval(prevCode);
}
}
}
As far as I know, there are two other types for annotations: "warning" and "info", just in case you'd like to check for those as well.
I kept track of the pervious code that worked in a global (well, outside the scope of the callback function) because often there would be errors in the code but not in the list of annotations. In that case, when eval'ing the errored code, it would be code and eval the older code instead.
Although it seems like two evals would be slower, it seems to me like the performance is no that bad, thus far.
Ace uses JsHint internally (in a worker) and as you can see in the file there is an event emitted:
this.sender.emit("jslint", lint.errors);
You can subscribe to this event, or call the JSHint code yourself (it's pretty short) when needed.
I found you can subscribe worker events in Ace 1.1.7:
For javascript code, subscribe 'jslint' event:
session.setMode('ace/mode/javascript}');
session.on('changeMode', function() {
if (session.$worker) {
session.$worker.on('jslint', function(lint) {
var messages = lint.data, types;
if (!messages.length) return ok();
types = messages.map(function(item) {
return item.type;
});
types.indexOf('error') !== -1 ? ko() : ok();
});
}
});
For JSON code, subscribe 'error' and 'ok' event:
session.setMode('ace/mode/json');
session.on('changeMode', function() {
// session.$worker is available when 'changeMode' event triggered
// You could subscribe worker events here, whatever changes to the
// content will trigger 'error' or 'ok' events.
session.$worker.on('error', ko);
session.$worker.on('ok', ok);
});

Processing.js doesn't allow external javascript bind in firefox

I'm trying to send data to a processing script. But for some reason the variable pjs below binds to the canvas "competence1" and enters the first if statement, but then the bindJavascript(this)-call returns error, but only in firefox. (works perfectly in chrome):
[pjs.bindJavascript is not a function]
var bound = false;
function initProcessing(){
var pjs = Processing.getInstanceById('competence1');
if (pjs != null) {
// Calling the processing code method
pjs.bindJavascript(this);
bound = true;
//Do some work
}
if(!bound) setTimeout(initProcessing, 250);
}
Environment: Mac OS X - Lion;
OBS! The bindJavascript(this)- method exists in the pde script loaded in the canvas-tag
By wrapping up all my script in a varable-map and by using the second way for setTimeout to be called i can follow each state and control the result.
So wrap it up-->
var ex = {
init : function(canId){
var canId = canId;
// check the if bound
// bind in this closure
// set new timer
}
}
setTimeout-->
setTimeout('ex.init("'+canId+'")', 2000);
and ofcourse add the parameter in so it can hold that value during it's own execution. So processing works just fine and i should use closure more often, that's the solution.
I had the same problem. I was using almost identical JS to you (which I got from the Pomax tutorial), and it was working fine. However, when I added the following preload directive (to load a backdrop), then suddenly my initProcessing function stopped working.
/* #pjs preload="metal_background.jpg"; */
The error message was the same: pjs.bindJavascript is not a function
On debugging, I could see that the pjs object did indeed not have a bindJavaScript function exposed, even though there is one declared in my PDE file.
It turns out this was purely down to timing... the preload had slowed down the initialisation of the processing object, so the second time round the 250ms loop, the pjs object existed, but didn't yet have its bindJavaScript function.
I am not 100% sure how Processing.js does this object construction, but in this case, a simple solution was just to check whether bindJavaScript actually was defined! I changed my code to the following:
var bound = false;
function initProcessing() {
var pjs = Processing.getInstanceById('mySketchId');
if(pjs != null) {
if(typeof(pjs.bindJavaScript) == "function") {
pjs.bindJavaScript(this);
bound = true;
}
}
if(!bound) setTimeout(initProcessing, 250);
}
After this it worked fine!

Categories