简体   繁体   中英

Selection objects and cross-origin iframes?

When a user selects text in a different-origin iframe, javascript calling window.getSelection() running in the containing document gets back a None selection object, because of cross-origin security policies.

So, programmatically, I can't tell the difference between getting back a None selection object because the user hasn't selected anything in the entire document, versus getting back a None because a user has selected something in the different-origin iframe, but it's off-limits to my code.

I'd like to be able to distinguish between the cases so I can show the user different error messages. Is this possible?

var sel = window.getSelection();
if ( sel && sel.type == 'None' ) {
    // Did the user not select anything in the entire document?
    // Or did the user select something in a different origin 
    // iframe that I can't see?
    // If I could tell the difference between these two cases,
    // I could show my user a much better error message
    alert('sel type = None, dunno what it means exactly, kthxbai');
}

Complete demo code is here: http://jsfiddle.net/t3bd6zy4/2/

Note: This needs to work with arbitrary websites, so altering the origin policies or doing something with postMessage() isn't a viable approach for me. Also, this code will run in recent Chrome browsers only.

UPDATE: I have a workaround to this problem, albeit one that will work only in Chrome extensions.

While I can't get different-origin selectedText from the DOM without altering the origin policies, the Chrome APIs will let you get selected text even if it does come from a different-origin iframe. (If you want to know more, see the samples for the contextMenus API: https://developer.chrome.com/extensions/contextMenus .)

Using this approach means I don't need to show iframe-specific messages for empty selections. Fewer error messages for my users: much awesomeness.

This works ( jsfiddle ):

var iframeClicked = false;

document.body.addEventListener('mouseup', iframe(false));

function iframe(bool) {
  return function(e) {
      iframeClicked = bool;   
      //console.log(iframeClicked);
  }
}

focus();
var listener = addEventListener('blur', function() {
  if(document.activeElement === document.getElementsByTagName('iframe')[0]) {
      iframe(true)();
  }

  removeEventListener(listener);
});

document.getElementById('selbutton').addEventListener('mousedown', function() {
  var sel = window.getSelection();

  if (!iframeClicked) {
      console.log("selection type of " + sel.type + " value is :" + sel + ":" );
  } else {
      console.log("did not get a selection object back from getSelection");
  }
});

The solution to check if the iframe was clicked can be found in this answer . What we're looking for is to see if the iframe was the last thing that was clicked (because as you know, if you select something, the next thing you click will unselect that selection... so if the iframe was the last thing clicked, and we click the "get selection" button, then we'll know that we tried to select something inside the iframe .) That was confusing.

Anyway, iframeClicked === true means that the last thing before clicking the "get selection" button that the user clicked was indeed the iframe . Otherwise, it was somewhere outside the iframe .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM