I'm making a spreadsheet where double-clicking a cell brings up the 'edit' control, gives it focus, and sets up an onblur event handler to hide the 'edit' control and set the value of the cell to be that of the control once it loses focus. The assumed flow is the user double-clicks to bring up the edit control, selects/enters a value, then clicks/tabs to something else, thus moving focus to another element and triggering the edit control's onblur handler.
It works just fine, except with SELECT tags in IE 10 and 11 (Chrome and FF work fine): Every time I click on the carat to drop the drop-down, the SELECT loses focus and triggers the onblur handler, which then hides the edit control, thus preventing me from editing a value.
Does anyone know why this is happening or how to fix it?
I found this blog post which describes the problem and proposes a solution of adding a background image to the SELECT, but that didn't seem to fix the problem (or I did it wrong).
Below is the code where I generate and insert the HTML for the edit control into the cell.
/**Changes the contents of the cell to be its editing control instead of plain text.
@method SetCellEditMode
@param {String} mappingId: The Id of the PropertyMapping representing cell to switch over to edit mode.*/
this.SetCellEditMode = function (mappingId)
{
if (this.Editing === true) return false;
var cell = this.GetCell(mappingId);
var tagType = null;
if (cell == null) return false;
var propInfo = cell.SourceObject.PropertyInfo;
if (propInfo.IsReadOnly === true) return false;
var innerHtml = null;
if (propInfo.PropertyType === SDCMS.Resources.PropertyType.Boolean)
{
innerHtml = makeBoolHTML(cell.SourceObject);
}
else if (propInfo.PropertyType === SDCMS.Resources.PropertyType.Enum)
{
innerHtml = makeEnumHTML(cell.SourceObject);
}
else if (propInfo.PropertyType === SDCMS.Resources.PropertyType.Number || propInfo.PropertyType === SDCMS.Resources.PropertyType.String)
{
innerHtml = makeStringEntryHTML(cell.SourceObject);
}
cell.Node[0].innerText = "";
cell.Node.html(innerHtml);
cell.Node[0].firstChild.focus();
this.Editing = true;
return true;
};
/**Makes the HTML for a boolean <select> control.
@method makeBoolHTML
@param {Object} propertyMapping: The SDCMS.Resources.PropertyMapping for which we are making an <select> control.*/
var makeBoolHTML = function (propertyMapping)
{
if (propertyMapping == null) return null;
var innerHtml = "<select mappingId=\"" + propertyMapping.Id + "\" onblur=\"SD_Click(event, 'SD_ChangeValue')\">" +
"<option>true</option>" +
"<option>false</option>" +
"</select>";
if (propertyMapping.PropertyValue === true)
{
innerHtml.replace("<option>true</option>", "<option selected=\"selected\">true</option>")
}
else
{
innerHtml.replace("<option>false</option>", "<option selected=\"selected\">false</option>")
}
return innerHtml;
};
Found a solution. Turns out it was all input/select type nodes were losing focus, and what was happening was that the nodes that were in a table would, when clicked, bubble the event from the control to the table cell, which would then get focus and cause blur() to trigger on the internal control. The solution was to hook up event handlers for onclick, onmousedown, and onmouseup (for good measure) that do nothing but preventDefault() and stopPropagation(). Once the event stopped propagating to the containing table cell, everything worked as it should.
Instead of calling focus directly call it using settimeout (), an interval of 1 to 10 ms should be enough.