My web app non-deterministically crashes in Google Chrome - javascript

In my web app, I use Ctrl + Arrow keys to navigate from cell to cell in a table.
All cells contain a visible <span>, and a hidden <input> element -- their values are kept in sync.
When a cell is activated, the <span> is hidden, while the input is shown.
Everything works just fine in Firefox, IE, Opera, etc. Yet, when I load up Chrome, using Ctrl+Left or Ctrl+Right crashes the page (I'm seeing the "Aw Snap" page). Odd thing is, Ctrl+Up and Ctrl+Down work.
I've identified that the following code is (directly or indirectly responsible for the crashes):
/**
* Deactivates a cell, hiding its input field, and showing its span field
*/
View.prototype.deactivateCell = function (cell){
//Show the span, hide the input
var label = cell.descendants()[0];
var input = cell.descendants()[1];
if(label){
label.show();
}
if(input){
//THIS NEXT LINE IN PARTICULAR CAUSES THE CRASH
//I've also tried input.style.display = "none"; - same result
input.hide();
}
}
Odd thing is, this code is called by Ctrl+Up/Down, as well as Ctrl+Left/Right - yet it only crashes on Left/Right -- even with identical cell values!
All of these cells have two, and only two, descendants... And the crash has nothing to do with the source cells, or the destination cells -- it's possible to move into any cell from above, but not from the left.
What's even stranger; adding an alert(1); at the end of the deactivateCell(cell) method prevents the crash. Putting it at the start of the method has no effect (Other then displaying the alert dialogue, before the crash)
I've tried isolating the relevant HTML + this method in a test file - I could not reproduce the crash.
Has anyone encountered this? Should I write it off as a browser bug? Does anyone know how I might debug this, or try to fix it? I haven't the foggiest impression how my Javascript can cause the browser to caput, when so many other websites are fine.

I'm not a prototype hero, but I noticed that you call cell.descendants() without checking if cell is null or not.
Also, are you hiding the current input the cursor is in? if so, try to focus() to a different input before you hide the current one.

It turns out this is a bug with Webkit that was already filed and fixed.

Related

onpaste / paste event not firing for table on first few attempts

Google Chrome specific - this is an internal-use app that does not require cross-browser compatibility
See http://jsfiddle.net/spetnik/vpcyt4yv/
I have a table into which I am attempting to allow pasting of data. I made the individual cells selectable as such:
<td tabindex="0">
I originally tried adding the onpaste event to the TD elements themselves, but this did not work at all. So instead, I added the event to the table element and just check to make sure that the focused element is a TD and then paste the data to that element:
document.getElementById("tblData").onpaste = function(evt){
if(document.querySelector(":focus").tagName.toLowerCase() != "td"){
return;
}
document.querySelector(":focus").innerText = evt.clipboardData.getData("text/plain");
};
While this does essentially work, the event usually does not fire on the first attempt. It seems that I need to either a) click around in the table a random number of times (each time is different) or b) change focus to another window and then back again before the event fires. In the jsFiddle I have added a console.log() call to the very beginning of the event so that I can see exactly when the event fires in the debug pane.
See the above jsFiddle or just the result at https://jsfiddle.net/spetnik/vpcyt4yv/embedded/result/
Wow. The culprit seems to be the -webkit-user-select/user-select CSS! I discovered this when I noticed that pasting would be allowed only after initially clicking and dragging the mouse over a cell (which explains the random clicking - only after I clicked until my mouse moved mid-click did it work). I removed this CSS and now it works. Of course, now I need to find a workaround to prevent selecting, but at least I'm no longer stumped.
Edit: It seems that on a normal element (e.g. a DIV with the onpaste set to the element itself) onpaste does not work at all when -webkit-user-select is set to none. I submitted a bug report here
EDIT 2: I have managed to find the following workaround: If I programmatically select the contents of the cell before Ctrl-V is pressed, then it will work, even with -webkit-user-select set to none. I accomplished this by adding the following event handler (jQuery shown here) to the TD (this still does not work in a standalone DIV with -webkit-user-select set to none):
$(elem).click(function(evt){
var selection = window.getSelection();
var range = document.createRange();
range.selectNodeContents(this);
selection.removeAllRanges();
selection.addRange(range);
})

Input box will not "forget" the first value it gets Firefox 20.0

The problem I have is with an input box not forgetting the first input it gets. It then feeds it back even when the content should have been over written by a new input. The code I am using works fine with IE8 the problem is seen with Firefox 20.0.
I am working entirely in Javascript. There is no HTML beyond a body.
I use this to set up my input box:
addElementWithIdButNoNode("input","manimp","div42"); // add input box
addElementWithNodeAndId("button","Set","div42","setButton"); //add "set" button
document.getElementById("setButton").onclick=showIt;
"manimp" is the ID and the below successfully captures what is entered first time around as "theMainVar".
function showIt()
{
theMainVar=manimp.value;
theMainVar=parseFloat(theMainVar);
alert(theMainVar);
}
The problem is that if you run this again in Firefox you can enter any value you like but the alert comes back with what you entered the first time around.
You can manually sent the "manimp.value" to something else in javascript and it does change but it then stays stuck at this changed value.
I need a "reset manimp so it can accept a new value from the input box function"
I have had a look around and found lots of "reset()" and "clear()" funcitons but nothing works for me.
The same thing happens if I swap the input box for a drop down.
I'm new to Javascript so if the fix seem obvious to you, maybe it is!
Try getting the 'manimp' element inside your function, probably the value is referenced when the function is declared. So, inside your function use
theMainVar = document.getElementById('manimp').value;

jQuery finding wrong elements under Chrome

I'm using jQuery to iterate through an HTML table, and dynamically fill in the row numbers of each row (by populating the row number in a text box):
function updateRowNums() {
$('#myTable').find('tr').each(function(index) {
$(this).find('input[id$="_rowOrder"]').val(index);
});
}
This function gets called under:
$(document).ready(function() {
// .. code truncated ... //
updateRowNums();
});
This works perfectly fine under Firefox. However, under Chrome (tried both 5.x and 9.x (beta)) and sometimes Safari, this ends up populating a bunch of other fields that don't even match the:
'input[id$="_rowOrder"]'
criteria, with the row numbers. So basically it scatters the numbers around in other, unrelated, text fields...
I'm pretty sure this is some sort of Chrome or jQuery bug, but I'm just checking, since it seems like pretty basic functionality. BTW, if I introduce an alert in the code, it then works fine on Chrome, so this may have something to do with the timing of the document loading in Chrome:
function updateRowNums() {
$('#myTable').find('tr').each(function(index) {
alert("XXXXXXXXXXXXXXXXXXX");
$(this).find('input[id$="_rowOrder"]').val(index);
});
}
Go here to see example:
http://jsfiddle.net/eGutT/6/
In this example, the steps you need to reproduce are:
Go to URL using Chrome (or Safari -- sometimes fails as well).
You will notice that everything works as expected so far (i.e. numbers filled down 1st column)
Click on the "NAVIGATE AWAY" link.
Click back
You will see numbers filled in across top row AND down first column
You will notice that I added console logging, to output the ID's of the elements that are getting their value modified. The output of this log is:
one_rowOrder
two_rowOrder
three_rowOrder
which indicates that only 3 elements were touched. However, from the result, you can see that 5 elements have numbers in them.
Thanks,
Galen
The problem is that your input's do not have a name attribute. Chrome/Safari seems to try to save what you entered in to form fields when you go forward and back in the history. Because your inputs do not have name attributes its guessing which input field to put the values back in, and is guessing incorrectly.
Add name attributes to your fields and its all fixed: http://jsfiddle.net/petersendidit/eGutT/14/
Chrome/Safari probably should be checking for the id attribute of the name attribute is missing.
If you are using digits as your IDs, jQuery won't recognize them and/or act correctly because it is invalid HTML. Either remove the digits or put a letter in front of them.

How to prevent multiple html selection box displayed on screen?

I have been working on the last bit of my php + ajax based datagrid project.Everything works as I designed except one thing : I cannot stop user opening multiple selection boxes...
Go my research page and use username "ChenxiMao" and password "accedo" to login(without double quotes).
Note that perhaps the images used in this datagrid would not be displayed when page is loaded for the first time(weird, I am trying to fix this, browser incompatibilities, perhaps).
If you double click on one cell in the "CONSULTANT" column, a html select box would be displayed, you can select one consultant to assign him to this task or unassign the consultant from this task. No problem for this.
The problem is : when user leaves this selection box OPEN, he/she can still open another selection box... My jquery code cannot stop people from opening multiple selection boxes.
You can ctrl-U to see the source code on this page, and check the content inside the "gridview-helper.js" for what I have been done.
I want to let user only open a single selection box. When he/she leaves the cell, the selection box should be closed, without changing the html inside...
Puzzled, screwed up for this afternoon...
Thanks for any suggestons in advance!
JavaScript is single-threaded, so you can add a mutex variable and check its value before opening a new select box.
At the top of gridview-helper.js:
var is_choice_visible = false;
In your double-click handler:
$(this).dblclick(function()
{
if (is_choice_visible)
return;
is_choice_visible = true;
...
For your select box, add an onblur handler which sets is_choice_visible back to false and deletes itself.
Unrelated tip: Growing a string in a loop is slow on older versions of Internet Explorer. It's more efficient to append to an array and join the array, e.g.:
var html = ["<select>..."];
for (var i in consultantnames)
{
html.push("<option>...</option>");
}
html.push("</select>");
return html.join("");
Have you tried using the onmouseout event on the cell, and removing the child dropdown box element if mouse out is triggered? Seems that should work.

Problem getting selected text when using a sprited button and selection.createRange() in Internet Explorer

I'm working on implementing sprited buttons in Stackoverflow's beloved WMD markdown editor and I've run into an odd bug. On all versions of IE, the selected text is lost upon button clicks, so, say, highlighting a block of text and clicking the code button acts like you placed the cursor at the end of the selection and clicked the button.
e.g. highlighting this:
This
Is
Code
and clicking the code button give you:
This
Is
Code`enter code here`
What's really weird is that I left the original non-sprited button bar in and that works just fine. In fact ALL buttons and keyboard shortcuts code use the same doClick(button) function!
Old-style non-sprited buttons: OK
Keyboard shortcuts: OK
Sprited buttons in non-IE browsers: OK
Sprited buttons in IE: WTF
I've isolated the problem down to a call to selection.createRange() which finds nothing only when the sprited button is clicked. I've tried screwing around with focus()ing and making sure as little as possible happens before the doClick() but no joy. The keyboard shortcuts seem to work because the focus is never lost from the input textarea. Can anyone think of a hack that will let me somehow collect the selected text in IE?
The onclick handler looks like this:
button.onmouseout = function(){
this.style.backgroundPosition = this.XShift + " " + normalYShift;
};
button.onclick = function() {
if (this.onmouseout) {
this.onmouseout();
}
doClick(this);
}
I've tried moving the onmouseout call to after the doClick in case that was causing a loss of focus but that's not the problem.
EDIT:
The only thing that seems to be different is that, in the original button code, you are clicking on an image. In the sprited code, you are clicking on a list item <li> with a background image set. Perhaps it's trying to select the non-existent text in my list item?
/EDIT
Actual code is located in my wmd repository on git in the button-cleanup branch.
If you revert to the 0d6d1b32bb42a6bd1d4ac4e409a19fdfe8f1ffcc commit you can see both button bars. The top one is sprited and exhibits the weird behavior. The bottom one contains the remnants of the original button bar and works fine. The suspect code is in the setInputAreaSelectionStartEnd() function in the TextareaState object.
One last thing I should mention is that, for the time being, I'm trying to keep the control in pure Javascript so I'd like to avoid fixing this with an external library like jQuery if that's possible.
Thanks for your help!
I know what the answer to my own question is.
The sprited buttons are implemented using an HTML list and CSS, where all the list items have a background image. The background image is moved around using CSS to show different buttons and states (like mouseover highlights). Standard CSS button spriting stuff.
This works fine in IE with one exception: IE tries to select the empty list text when you click on the background image "button". The selection in the input textarea goes away and the current selection (which will be returned by document.selection.createRange()) is moved to the empty text in the list item.
The fix for this is simple - I created a variable to cache the selection and a flag. In IE I cache the selection and set the flag in a mousedown event handler. In the text processing, I check for the presence of the flag - if it's set I use the cached range instead of querying document.selection.createRange().
Here are some code snippets:
wmd.ieCachedRange = null;
wmd.ieRetardedClick = false;
if(global.isIE) {
button.onmousedown = function() {
wmd.ieRetardedClick = true;
wmd.ieCachedRange = document.selection.createRange();
};
}
var range;
if(wmd.ieRetardedClick && wmd.ieCachedRange) {
range = wmd.ieCachedRange;
wmd.ieRetardedClick = false;
}
else {
range = doc.selection.createRange();
}
The solution is only a few lines of code and avoids messing around with the DOM and potentially creating layout engine issues.
Thanks for your help, Cristoph. I came up with the answer while thinking and googling about your answer.
You have to blur() a button before IE can select anything else on a page.
Can you provide a minimal example (only containing relevant code) which reproduces the bug?

Categories