CreateContextualFragment not working in safari - javascript

We have a problem with a function (createContextualFragment) in safari.
We need to add some content in the body, so we use this line of code.
Code:
document.getElementsByTagName('body')[0].insertBefore(document.createRange().createContextualFragment("<div></div><script src="LINK_SOURCE"></script>"), null);
This line of code is working fine with Chrome and Firefox, but we are having some issue with createContextualFragment in Safari.
Error in Safari:
createContextualFragment —
asyncronousDocumentWrite2.html:28:115NotSupportedError: DOM Exception
9: The implementation did not support the requested type of object or
operation.

I realize that my answer is arriving a little late, but I recently ran into a similar situation.
What I found
According to https://developer.mozilla.org/en-US/docs/Web/API/Range/createContextualFragment#Browser_compatibility
Range.createContextualFragment() is not supported in Safari 9.0 or 9.1. It does work fine in Safari 10 though.
What can you do?
Since Safari does not support createContextualFragment we can delegate the responsibility of creating our document fragment to jQuery. The following illustrates two options to do this depending on what version of jQuery you are using:
jQuery 1.8 or newer use ParseHTML
document.getElementsByTagName('body')[0].insertBefore($.parseHTML("<div></div><script src='http://google.ca'></script>"), null);
Otherwise just let jQuery figure out what to do
document.getElementsByTagName('body')[0].insertBefore($("<div></div>
<script src='http://google.ca'></script>"), null);

I have found out that setting range.selectNodeContents(document.createElement('div')); fixes the issue as indirecly pointed out in this article https://grrr.tech/posts/create-dom-node-from-html-string/#range.
My example usage:
document.querySelectorAll('.container').forEach((el) => {
const range = document.createRange();
range.selectNodeContents(el);
range.deleteContents();
range.selectNodeContents(document.createElement('div')); // fix for safari
el.appendChild(range.createContextualFragment(htmlContent));
});

Related

.find(".class:first") behavior with Opera and Safari

I'm using Soundmanager2 to play some audio files in a web site, but not using Flash.
It works fine with Firefox and Chrome, as they support ogg and mp3 respectively. However, it doesn't work with Opera 12.16. Theoretically, it supports ogg, and pass the condition if( supports_ogg_audio() ):
It is returning 1 in this function:
function supports_ogg_audio() {
var a = document.createElement('audio');
return !!(a.canPlayType && a.canPlayType('audio/ogg; codecs="vorbis"').replace(/no/, ''));
}
So it detects ogg support. But as I'm doing:
currentRow = thisPlayer.find(".total-row:first");
I get this error from the Opera console:
Unknown pseudo class
[id='total-playlist'] .total-row:first
So I'm guessing that this is the problem. How could select the first thisPlayer.find(".total-row") element with better browser compatibility?
It neither works in Safari5+ and IE9+
You need to use first-child selector instead of first. See information here.

Different results for same jQuery code in chrome and Firefox

I can't figure out what the problem is. The following code works well in Chrome (v29) but not on firefox (v23):
// some test data
var serviceOptions = '<optgroup label="Domiciliary Care"><option value="1">Meals</option><option value="2">Personal Hygiene</option></optgroup><optgroup label="Live in Care"><option value="3">Housekeeping and Cleaning</option><option value="4">Assisted Mobility</option></optgroup>';
var cat = "Live in Care";
// escape illegal characters
var escaped_cat = cat.replace(/([ #;&,.+*~\':"!^$[\]()=>|\/#])/g, "\\$1");
var options = $(serviceOptions).filter("optgroup[label='" + escaped_cat + "']").html();
var expectedOptions = '<option value="3">Housekeeping and Cleaning</option><option value="4">Assisted Mobility</option>';
// OK in Chrome, ERROR in FF
console.log(options == expectedOptions ? "OK" : "ERROR")
// passing the string directly instead of using a var works on FF
options = $(serviceOptions).filter("optgroup[label='Live\ in\ Care']").html();
console.log(options == expectedOptions ? "OK" : "ERROR")
The goal is simple as you can see: to filter a set of options by a specific optgroup.
You can test it by opening the jQuery website, opening the console and copy-paste the code.
Meanwhile if I discover something, I'll update this post.
UPDATE
Thanks for the feedback:
It seams that the problem is with the escaping of illegal characters, on firefox with jQuery 1.9.1. Either upgrading jQuery or not escaping the characters produces the expected results under Firefox.
Since upgrading jQuery is not an option for me, anyone knows what can be the problem with that escape regex?
Seems to be an issue with older versions of jQuery but not newer ones. Try updating your jQuery to 1.10
Not working old version of jQuery including migrate
1.9.1 JSFIDDLE
Working new version of jQuery
1.10.1 JSFIDDLE
the jQuery main site is running an older version of jQuery by the way

Cannot access document's title element with jQuery (IE 8)

I'm seeing this issue in Internet Explorer 8, but not in Safari or Firefox. So far, I have not tested in other IE versions.
I am developing my own jQuery plugin and, for this question, I've stripped it down to the two relevant lines.
In IE 8, using the code below, $('title').text() does not do anything. docTitle is blank because title is blank, as if the jQuery selector for <title>, $('title') is not working. (Again, AFAIK, this is just in IE 8)
(function ($) {
$.fn.myPlugin = function (options) {
var title = $('title').text(),
docTitle = escape(title);
};
})(jQuery);
http://jsfiddle.net/sparky672/YMBQ2/
However, using the plain JavaScript code below, document.title is working fine in everything including IE 8...
(function ($) {
$.fn.myPlugin = function (options) {
var docTitle = escape(document.title);
};
})(jQuery);
EDIT:
It does not matter that this code is inside a plugin.
Same result in IE 8 with this...
$(document).ready(function () {
var title = $('title').text();
alert(title);
});
Just to clarify, I am not insisting on using this. In fact, I fixed my plugin by simply using document.title instead. If it wasn't clear initially, I'm just asking why this does not work in IE 8.
Can anyone explain why, or what stupid mistake I may have made here?
EDIT 2:
Here are some jQuery Bug reports on this issue
http://bugs.jquery.com/ticket/7025
http://bugs.jquery.com/ticket/5881
http://bugs.jquery.com/ticket/2755
And dozens of others reporting the same thing. The official response is to state, "document.title is the only reliable cross-browser way and should be used instead" and the Ticket is closed. So there you go.
I guess jQuery iterates over all TextNodes and concatenates its nodeValue. IE stores this value differently than other browsers.
var title = document.getElementsByTagName('title')[ 0 ];
title.firstChild // This would be the Text-Object with the characterdata of the title
// Firefox: [object Text]
// IE: null
This should be the reason you cannot get the textContent with jQuery.text(). title.text seems to be cross browser comp. I only tested it in IE 7 and Firefox 3.6 but you can check the other browser if you like. But why not using document.title?
try using $('title').html() which should work in all browsers

scrollBy doesn't work in Firefox and Opera

This scrollBy function works in Internet Explorer, but ignores by Firefox and Opera. Can anyone help to solve this problem?
function scrollLeft(s){
document.frames['my_iframe'].scrollBy(-s,0);
window.frames['my_iframe'].scrollBy(-s,0);
}
function scrollRight(s){
document.frames['my_iframe'].scrollBy(s,0);
window.frames['my_iframe'].scrollBy(s,0);
}
Here is an example that works in Internet Explorer browser, but doesn't work in Firefox and Opera: http://igproject.ru/iframe-scrolling/index.htm
In Firefox, etc. you need to use scrollTo() instead of scrollBy().
See: http://jsfiddle.net/4CkML/
Example:
window.scrollTo(50,50);
You cannot use scrollTo/By if the domains don't match. You can see here that a javascript error is produced:
http://jsfiddle.net/3CbZc/
Permission denied to access property 'scrollTo'
Edit - Updating answer to incorporate answer from long comment chain:
var oIF = document.getElementById('my_iframe').contentWindow; oIF.scrollBy(s, 0);

What is the correct way to detect Opera using jQuery?

Amazon.com recently updated their javascript, and it's causing problems with some Opera browsers.
Their browser detection code looks like so, but it's faulty:
function sitbReaderIsCompatibleBrowser() {
if (typeof(jQuery) == 'undefined') {
return false;
} else {
var version = jQuery.browser.version || "0";
var splitVersion = version.split('.');
return (
(jQuery.browser.msie && splitVersion[0] >= 6) // IE 6 and higher
|| (jQuery.browser.mozilla && (
(splitVersion[0] == 1 && splitVersion[1] >= 8) // Firefox 2 and higher
|| (splitVersion[0] >= 2)
))
|| (jQuery.browser.safari && splitVersion[0] >= 500) // Safari 5 and higher
|| (jQuery.browser.opera && splitVersion[0] >= 9) // Opera 5 and higher
);
}
}
Nothing obviously wrong jumps out at me with this code, but I've never used jQuery before so I don't know.
Even though this code looks like it's attempting to let Opera users through, when I visit the page with Opera 9.64 I get an "unsupported browser" message. If I change Opera's settings to report itself as Firefox, the page works perfectly! With that in mind, I'm pretty sure it's a problem with the script and not the browser.
Any jQuery experts have a suggestion?
You can replicate the behavior by visiting any book on Amazon and clicking the "look inside this book" link.
Prior to jQuery 1.3, you could use jQuery.browser:
if( $.browser.opera ){
alert( "You're using Opera version "+$.browser.version+"!" );
}
From version 1.3, you should use jQuery.support instead.
Main reason for this is that should should avoid checking for browsers, as features may change from version to version, making your code obsolete in no time.
You should always try to use feature detection instead. This will allow you to see if current browser supports the feature you're trying to use, regardless the browser brand, version, etc.
There is a special window.opera object which is present in all Opera 5+ browsers. So something as simple as:
if (window.opera && window.opera.buildNumber) {
// we are in Opera
}
would be enough.
I check for Opera like this:
if (/Opera/.test (navigator.userAgent)) // do something
Why would you want jQuery?
It is much better to detect javascript capabilities rather than browser userAgent.
ie DOM, XmlHttpRequest, eventing model (event.target vs event.srcElement), ActiveX, Java etc
By focusing on the API functions that you will require, rather than a target browser you will create a more robust set of scripts, and inevitably less special casing.
This link here at opera will probably tell you more
A very simple way from Opera themselves:
if (window.opera) {
//this browser is Opera
}
Source: http://my.opera.com/community/openweb/idopera/
The main reason why Amazon fails on Opera is because the send different code from the server side already... If you visit the same page with Firefox and then save that page and reopen it in Opera it works fine...
But they promised to fix that sometime in January...
I think this way is the best
if ( window.opera.version() == 12) {
}
This example check if opera version is 12. Very useful when I have problems with font-face in Opera.
I don't know for sure ( i never really check for opera anyway) but if the built-in jQuery functionality doesn't detect opera, may be a bug with the jQuery which needs to be fixed. I would suspect if that's the case, it should get resolved fairly quickly.
In current HTML5 times, you can also check for browser features instead often.
if (!window.FormData) { alert("xmlhttprequest L2 FormData interface not available"); }

Categories

Resources