5

code: http://jsfiddle.net/4hV6c/4/ just make any selection, and you'll get a script error in ie8

I'm trying to do this:

$(end_node.parentNode).has(start_node)

which in modern browsers (chrome, ff, opera, etc) returns [] if start_node is not in end_node.parentNode, and returns the element (I forget which) if it is found.

now, end_node is a text element, and the parentNode is an actual DOM entity. IE will perform .has on just $(end_node).has(start_node) but that is obviously different behavior.

Is there a work around to get this to work?

  • in IE the fiddle will error, other browsers will alert you with a boolean value.

UPDATE: here is a word around that overrides .has() for my specific scenario.. not sure if it works for all the cases of .has, as I don't know them all. http://jsfiddle.net/8F57r/13/

NullVoxPopuli
  • 51,415
  • 69
  • 184
  • 335
  • 1
    If this were really true, it would be a big deal and also have a jQuery bug report associated with it, no? – Sparky Mar 30 '12 at 16:58
  • the fiddle doesn't lie. =\ I'll see if I can contact someone at jQuery / post this somewhere. – NullVoxPopuli Mar 30 '12 at 17:01
  • What is the intended sequence of operation and expected result in your jsFiddle? I'm getting an alert which contains "false" no matter what I do. Using Safari. – Sparky Mar 30 '12 at 17:07
  • http://bugs.jquery.com/ticket/11539 a boolean value is correct. in IE, it just errors. – NullVoxPopuli Mar 30 '12 at 17:17
  • @Sparky672 This really is true, oh ye of little faith. Now there is a bug report associated with it – Juan Mendes Mar 30 '12 at 17:30
  • @JuanMendes, I'm just _asking_ questions here, nothing else. How many times on SO people _think_ jQuery has a bug when it's really something else? We should never _blindly_ put faith in any single claim or answer. – Sparky Mar 30 '12 at 17:33
  • @Sparky672 I'm just saying you assumed the OP was wrong... – Juan Mendes Mar 30 '12 at 17:41
  • @Sparky672 I'm not bashing you, just poking you, I also initially thought OP was wrong, as you can see from the first sentence in my answer – Juan Mendes Mar 30 '12 at 17:49
  • @JuanMendes, Yes, as you/we should always initially assume. It's the best way to get to the root of things. – Sparky Mar 30 '12 at 17:55

3 Answers3

4

The problem is not jQuery

Running

console.log( $("div:has(span)").html() );
console.log( $("div").has($("span")[0]).html() );

However, the following throws an exception http://jsfiddle.net/mendesjuan/4hV6c/8/

var textNode =  $("span")[0].childNodes[0];
$("div").has(textNode);

What that means is that you can't pass a text node into $.has. You should file a bug with jQuery

The line that is erroring out is giving the following message

No such interface supported jquery-1.7.1.js, line 5244 character 3

That is trying to call the contains method on a node. What that means is that this really is an IE bug that jQuery hasn't worked around. I've reproduced the problem without needing to call $.has http://jsfiddle.net/4hV6c/10/

// This is broken in IE
var textNode =  $("span")[0].childNodes[0];
var divNode = $("div")[0];
divNode.contains(textNode);

Workaround http://jsfiddle.net/4hV6c/12/

function contains(outer, inner) {
   var current = inner;
    do {
        if (current == outer) {
           return true;
        }
    } while((current = current.parentNode) != document.body);

    return false;

}
rangy.init();

$(document).bind("mouseup", function() {
    var a = rangy.getSelection();
    start_node = a.anchorNode;
    end_node = a.focusNode;
    var b = a.getRangeAt(0);
    var c = b.commonAncestorContainer;
    b.selectNodeContents(c);
    a.setSingleRange(b);
    alert( contains( end_node.parentNode, start_node) );
});
Juan Mendes
  • 80,964
  • 26
  • 138
  • 189
  • 1
    it's not just detecting if it has a tag, i need to check for the specific element. Because what if there are multiple spans? Also, isn't that different from the jQuery selector? – NullVoxPopuli Mar 30 '12 at 16:53
  • Checking for a specific element also works fine, see my update – Juan Mendes Mar 30 '12 at 16:57
  • the problem is that in IE8, end_node.parentNode (which is an undetermined DOM element to me, as it could be a div, span, or whatever) does not have a .has() method. You are calling .has() an EVERY div... ALso, you are hardcoding to get the first span match.... – NullVoxPopuli Mar 30 '12 at 16:59
  • @TheLindyHop I'm assuming just the HTML you showed us in the jsfiddle, I'm sure you know how to change the code to make the selectors more specific – Juan Mendes Mar 30 '12 at 17:06
  • @TheLindyHop I added my simple jsfiddles to your bug report – Juan Mendes Mar 30 '12 at 17:29
  • @TheLindyHop Added a simple contains function that you can use as a workaround until jQuery fixes it. I tried to override `Sizzle.contains` but that is not possible since Sizzle is private to the jQuery code (self calling anonymous function) – Juan Mendes Mar 30 '12 at 17:39
  • Nice workaround, I'm working on figuring out how to override jquery .has method, so it's more pre-existing code friendly – NullVoxPopuli Mar 30 '12 at 19:16
  • To do that you have to patch the jQuery file from the inside (could be a maintenance nightmare), look for the line that says `Sizzle.contains = function() {}` and update it to be like the function I showed you above. – Juan Mendes Mar 30 '12 at 19:19
  • Couldn't I just override .has for ie8? – NullVoxPopuli Mar 30 '12 at 19:21
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/9513/discussion-between-juan-mendes-and-thelindyhop) – Juan Mendes Mar 30 '12 at 19:21
1

You could always DIY? :) I hear recursive child indexing works real quick and is pretty easy to implement.

See here for an excellent tutorial:

http://blog.swapnilsarwe.com/javascript-traversing-html-dom-recursively.html

Travis J
  • 77,009
  • 39
  • 185
  • 250
  • @KirkWoll - See link for details, it is actually rather easy to do. Instead of building the whole tree you can just check weather the node is the one you need. However, based on Juan's answer above it would seem that IE supports `.has()` making this unnecessary for the OP to do. – Travis J Mar 30 '12 at 16:54
  • 1
    This goes against the idea of jquery, where all the gritty stuff is done for you to help keep your own code cleaner. – NullVoxPopuli Mar 30 '12 at 16:58
  • @TheLindyHop - I agree, however the OP asked for a workaround so I suggested a more basic javascript approach as an option. Just trying to show some different angles. – Travis J Mar 30 '12 at 17:00
  • Fair enough. I'll take a second look. – NullVoxPopuli Mar 30 '12 at 17:06
  • @TravisJ IE does not support has when passing in text nodes. The workaround (basic JS) is not very complicated, it's posted in my answer – Juan Mendes Mar 30 '12 at 17:43
0

Does find do what you want?

rangy.init();

$(document).bind("mouseup", function() {
    var a = rangy.getSelection();
    start_node = a.anchorNode;
    end_node = a.focusNode;
    var b = a.getRangeAt(0);
    var c = b.commonAncestorContainer;
    b.selectNodeContents(c);
    a.setSingleRange(b);
    alert($(end_node.parentNode).find(start_node).length > 0);
});​
Matt Wolfe
  • 8,585
  • 7
  • 56
  • 75