I see that XPathEvaluator isn't supported in IE 11 however I wanted to know if there's a proper detection mechanism to check for it's existence if not fall back to the selectSingleNode method in IE.
Something similar to this however whenever I check for XPathEvaluator in this fashion it blows up in IE 11 but works in Firefox/Chrome
if (XPathEvaluator) {
var xpe = new XPathEvaluator();
...... evaluation logic
return results.singleNodeValue;
}
else {
return xmlDoc.selectSingleNode(elPath);
}
Previous logic used to rely on the existance of the window.ActiveXObject to call selectSingleNode however the property has since been removed in IE 11 causing XPathEvaluator logic to be hit instead.
I'd rather detect if this functionality exists and not check for browser versions as features and functionality are constantly changing.
This is my simple test case.
IE 11 will alert the I am not IE popup, and then blow up on the XPath.
FF/Chrome will alert the I am not IE pop and then alert XPathEvaluator is a go.
function selectSingleNode()
{
// previous logic relied on this to call XPathEvaluator
if(window.ActiveXObject)
{
alert('Im IE');
}
else
{
alert('I am Not IE');
}
// I wanted to do something like this.
if(XPathEvaluator)
{
alert('XPathEvaluator is a go');
}
else
{
alert('XPathEvaluator is a no go');
}
}
If you want to use a certain method then check for it, so if you want to use selectSingleNode then do
if (typeof xmlDoc.selectSingleNode != 'undefined') {
// now use selectSingleNode method here
}
I am not sure why you want to check for XPathEvaluator, if you want to check whether there is an evaluate method on the document node to use the W3C DOM Level 3 XPath API then doing
if (typeof xmlDoc.evaluate != 'undefined') {
// now use evaluate method here
}
So together you can check
if (typeof xmlDoc.evaluate != 'undefined') {
// now use evaluate method here
}
else if (typeof xmlDoc.selectSingleNode != 'undefined') {
// now use selectSingleNode method here
}
Related
Posted here is an answer that instructs those who miss the old window.showModalDialog JavaScript function to use the
<dialog>
element instead. I have used this along with the polyfill needed for IE and FF and it works. However, there is a noticeable lag introduced when using the polyfill that I would like to avoid for Chrome (not to mention there is a warning not to use the polyfill when browsers support it). How do I detect whether or not the dialog element is supported so I can leave out the polyfill processing? Specifically these lines:
var dialog = document.getElementById('<element id>');
dialogPolyfill.registerDialog(dialog);
You could write a simple test like this:
if (typeof HTMLDialogElement === 'function') {
/** yep */
} else {
/** nope */
}
Try console.log(typeof window.showModalDialog === 'undefined')
if (typeof window.showModalDialog === 'undefined') {
console.log('No. ');
} else {
console.log('Yes! ');
}
function dialogElementSupported() {
return typeof document.createElement('dialog').show === 'function';
}
I'm looking for an answer if this is possible, or even a good idea.
Usually, as a fix for IE8 and earlier versions, a workaround similar to this is used:
var addEvent = function(obj, e, cb) {
if(obj.attachEvent) {
return obj.attachEvent('on' + e, cb);
} else {
obj.addEventListener(e, cb, false);
return true;
}
}
and then the programmer would always use addEvent instead of addEventListener.
Is there any way or point to create an addEventListener function that would wrap around the attachEvent when it is undefined?
I imagine it's a bit tricky since the EventTarget can be a DOM element, the document, or the window, or somethign else.
It depends on how far back you want to go. On IE8, you can extend Element.prototype to add features to all HTML elements, which is 90% at least of the work. I'm fairly sure you can't do that in IE6 (PrototypeJS had to resort to extending individual Element instances), I don't remember about IE7. Unless you're targeting east-Asian markets, you can basically ignore IE7 and earlier, though.
Here's an example of how you do that:
(function() {
// Functions for IE
function stopPropagation() {
this.cancelBubble = true;
}
function preventDefault() {
this.returnValue = false;
}
function addEventUsingAttach(eventName, handler)
{
this.attachEvent("on" + eventName, function() {
var e = window.event;
e.stopPropagation = stopPropagation;
e.preventDefault = preventDefault;
handler.call(this, e);
});
}
// Function to add `addEvent` to the given target object
function extendIt(target)
{
if (target.addEventListener) {
target.addEvent = Element.prototype.addEventListener;
}
else {
target.addEvent = addEventUsingAttach;
}
}
// Add it to `Element.prototype` if we have it
if (typeof Element !== "undefined" &&
typeof Element.prototype !== "undefined") {
extendIt(Element.prototype);
}
// Add it to `window` and `document` (etc.)
extendIt(window);
extendIt(document);
})();
Live Example | Source
Then you manually extend the other EventTargets, like window and document (see the end of the code listing above).
Original answer: I originally misread your question to be about adding addEventListener, specifically, on IE8, whereas in fact your question is quite clearly not about adding that, but adding your own addEvent. I'm leaving this answer in place for other readers:
It depends on how far back you want to go. On IE8, you can extend Element.prototype to add addEventListener to it, and that will be used by all HTML elements on the page (see below). The shim you add can't support the capturing phase, though, because IE didn't support it until they supported addEventListener natively. I'm fairly sure you can't extend Element.prototype on earlier versions (IE7, IE6), PrototypeJS had to fall back to extending specific elements for older versions of IE. But it works in IE8.
Having extended Element.prototype, then you'd have to manually extend the other event targets you mentioned, but extending Element.prototype does most of the work.
But if you do this and you include third-party scripts, beware that they may assume a correct implementation of addEventListeneer complete with the capturing phase.
Here's a basic shim for adding addEventListener to IE8:
(function() {
function stopPropagation() {
this.cancelBubble = true;
}
function preventDefault() {
this.returnValue = false;
}
if (typeof Element !== "undefined" &&
typeof Element.prototype !== "undefined" &&
!Element.prototype.addEventListener) {
Element.prototype.addEventListener = function(eventName, handler, useCapture) {
if (useCapture) {
throw "Browser doesn't support capturing phase";
}
this.attachEvent("on" + eventName, function() {
var e = window.event;
e.stopPropagation = stopPropagation;
e.preventDefault = preventDefault;
handler.call(this, e);
});
};
}
})();
Live Example | Source
Generally, functions can be added to an object by attaching the function to the object
obj.addEventListener = function(/* args*/) { /* body */ }
or by attaching the function to the prototype of the object constuctor
EventTarget.prototype.addEventListener = function(/* args*/) { /* body */ }
With the former, the added function can be called on the particular object only, while the latter lets you call the function on all objects that where or will be created from that particular object constuctor.
However,
EventTargets are host objects and therefore it is implementation dependant whether functions can be added to such objects.
EventTargets are host objects and therefore it is implementation dependant whether EventTarget.prototype actually exists and has the same meaning as with native objects.
If an object adheres to the EventTarget interface, it most likely already has an addEventListener function.
The event listener attached with attachEvent has different arguments than the one added with addEventListener.
In the end, it is not feasable to try and make a browser with crappy DOM support more standards complient using JavaScript.
I have been searching on the internet for a reason why my fullscreen javascript doesn't work in Safari, but yet works in webkit browser Chrome. It seems to that safari doesn't support the element.ALLOW_KEYBOARD_INPUT add-on for webkitRequestFullScreen.
function cancelFullScreen(el) {
var requestMethod = el.cancelFullScreen || el.webkitCancelFullScreen || el.mozCancelFullScreen || el.exitFullscreen;
if (requestMethod) { // cancel full screen.
requestMethod.call(el);
} else if (typeof window.ActiveXObject !== "undefined") { // Older IE.
var wscript = new ActiveXObject("WScript.Shell");
if (wscript !== null) {
wscript.SendKeys("{F11}");
}
}
}
function requestFullScreen(el) {
// Supports most browsers and their versions.
var requestMethod = el.requestFullScreen || el.webkitRequestFullScreen(el.ALLOW_KEYBOARD_INPUT) || el.mozRequestFullScreen || el.msRequestFullScreen;
if (requestMethod) { // Native full screen.
requestMethod.call(el);
} else if (typeof window.ActiveXObject !== "undefined") { // Older IE.
var wscript = new ActiveXObject("WScript.Shell");
if (wscript !== null) {
wscript.SendKeys("{F11}");
}
}
return false
}
function toggleFull() {
var elem = document.body; // Make the body go full screen.
var isInFullScreen = (document.fullScreenElement && document.fullScreenElement !== null) || (document.mozFullScreen || document.webkitIsFullScreen);
if (isInFullScreen) {
cancelFullScreen(document);
} else {
requestFullScreen(elem);
}
return false;
}
Does anybody know a way to make safari accept fullscreen yet still be able to handle keyboard inputs?
According to Apple's documentation, this is supposed to work in Safari 5.1 and later, but obviously it doesn't. I filed a bug report with Apple (which they don't make public), and the reply was as follows:
Engineering has determined that this issue behaves as intended based on the following:
We intentionally disable keyboard access in full screen for security reasons.
I have replied asking that they at least update the documentation and make the lack of feature support detectable somehow. I will update here if I get a reply.
Unfortunately, there isn't a good way to even do feature detection, since element.ALLOW_KEYBOARD_INPUT is defined in Safari, and the function call with that flag doesn't throw an error. The only remaining option is to parse the user agent string (try this library).
Obviously, Apple doesn't yet document which version supports this, but according to this, it stopped working as of v5.1.2. That would leave a very small number of people using 5.1 un-patched, if it ever even worked at all. So it's probably not even worth detecting the version.
As a fallback, I would expand the desired DOM element to fill the browser window by setting CSS height and width to 100% and position to "fixed" or "absolute".
Update: It looks like the documentation has been corrected and no longer mentions the ALLOW_KEYBOARD_INPUT flag.
This has been fixed in Safari 10.1!
Under the "Safari Browser Behavior" section.
I am having the below code for population the select box dynamically.THis works fine in all browsers except FireFox 3.6
var option25 = document.createElement("option");
option25.text = '25 miles';
option25.value = 25;
if(rad == '25')
{
option25.selected = 'selected';
}
var combo = document.getElementById('ddlProximity_' + controlId);
combo.add(option25); //not working in FF3.6
Any suggestions
The add method on select elements takes two arguments in Gecko versions older than 7 (MDN).
In IE it only takes one argument, or two if it's IE 8 in IE 8 standards mode, or something MSDN.
If we take krg's code and check the arity before calling add it works in Firefox 3.6.28, Firefox 15.0.1, and IE 9:
if (typeof combo.add === 'function') {
if (combo.add.arity === 1) {
combo.add(option25);
} else {
combo.add(option25, null);
}
} else if (typeof combo.appendChild === 'function') {
combo.appendChild(option25);
}
Assuming combo is a select menu, see this jsFiddle example.
if (typeof combo.add === 'function') {
combo.add(option25);
} else if (typeof combo.appendChild === 'function') {
combo.appendChild(option25);
}
If you would like to ensure that your JS code works across a wide spectrum of browsers, I would use a JavaScript framework such as jQuery to perform the DOM manipulation. JS frameworks have worked out most of the cross-browser problems and abstracted away the handling of them, so that you don't have to worry about writing code to address problems in a specific browser. Here's jQuery's site: http://jquery.com/.
Now to accomplish what your example says in jQuery, you would do the following:
var option25 = $('<option>').val(25).text('25 miles');
if (rad == '25') {
option25.attr('selected', 'selected');
}
var combo = $('#ddlProximity_' + controlId);
combo.append(option25); // Will work in all browsers supported by jQuery
If you really want to do this without any JS frameworks, I would take a look here: http://www.w3schools.com/jsref/met_select_add.asp . The add method should work, but there are some caveats in IE versions prior to 8 and your page must have a proper DOCTYPE declaration. You can also try appendChild, but I would test it in a few browsers to see if that accomplishes what you need.
I'm upgrading a script to make it crosss browser. The current code I have is as follows.
function testFocus(){
var testSelection = document.getElementById('chattext').contentWindow.
window.document.selection.createRange().parentElement();
while (testSelection)
{
if (testSelection.id == "chatContent") {
return true;
}
testSelection = testSelection.parentElement;
}
return false;
}
However the following code no longer works in modern browsers. Presently the code above has to have text selected. Where it just needs to check that the textbox has focus. The function is used as a check before text is added by a button / javascript.
Strikes me that you could use an event listener to set a variable. The only problem being that IE uses attachEvent(event, callback) instead of addEventListner so you've actually got to add the code
<script type="text/javascript">
var ChatHasFocus = false;
var ts = document.getElementById('chattext');
function setFocus() {ChatHasFocus = true;}
function setNoFocus(){ChatHasFocus = false;}
if (ts.addEventListener != undefined) {
ts.addEventListener('focus', setFocus, false);
ts.addEventListener('blur', setNoFocus, false);
} else if (ts.attachEvent != undefined) {
ts.attachEvent('onfocus', setFocus);
ts.attachEvent('onblur', setNoFocus);
} else {
ts.onmouseover = setFocus;
ts.onmouseout = setNoFocus;
}
</script>
edit - I've added script tags to show you how it adds to your document. I've tested in firefox and chrome and it seems to work, but getting an IE sandbox together might be a little more difficult for me. I'm sure there's something little that I'm missing there - i'll take a look.
edit2 i made a mistake with the IE code. tuns out you don't put quotes around 'undefined' I've fixed the code above to reflect an answer that is tested and wotkign in firefox, chrome and IE6. I don't have any other IEs to test in.