I am used to using Atlas. Recently i have started transitioning to jQuery and sometimes prototype. The project that i'm currently working on is using prototype.
In Prototype, is there an easy way to get the browser name and version? I've looked over the API documentation and can't seem to find it.
As a completion to nertzy's answer you can add the ability for detecting IE versions using this:
Prototype.Browser.IE6 = Prototype.Browser.IE && parseInt(navigator.userAgent.substring(navigator.userAgent.indexOf("MSIE")+5)) == 6;
Prototype.Browser.IE7 = Prototype.Browser.IE && parseInt(navigator.userAgent.substring(navigator.userAgent.indexOf("MSIE")+5)) == 7;
Prototype.Browser.IE8 = Prototype.Browser.IE && !Prototype.Browser.IE6 && !Prototype.Browser.IE7;
On the other hand you have to detect user agent details on the server side, too.
Anyways browser detection is a seriously flawed strategy for writing cross-browser scripts, that's just to be used when browser feature detection fails. It's pretty easy for a user to alter his/her user agent details.
Prototype offers some flags you can check to get an idea as to which browser is running. Keep in mind that it's much better practice to check for the functionality you wish to use rather than check for a particular browser.
Here is the browser- and feature-detection portion of prototype.js currently in the source tree:
var Prototype = {
Browser: {
IE: !!(window.attachEvent &&
navigator.userAgent.indexOf('Opera') === -1),
Opera: navigator.userAgent.indexOf('Opera') > -1,
WebKit: navigator.userAgent.indexOf('AppleWebKit/') > -1,
Gecko: navigator.userAgent.indexOf('Gecko') > -1 &&
navigator.userAgent.indexOf('KHTML') === -1,
MobileSafari: !!navigator.userAgent.match(/Apple.*Mobile.*Safari/)
},
BrowserFeatures: {
XPath: !!document.evaluate,
SelectorsAPI: !!document.querySelector,
ElementExtensions: !!window.HTMLElement,
SpecificElementExtensions:
document.createElement('div')['__proto__'] &&
document.createElement('div')['__proto__'] !==
document.createElement('form')['__proto__']
},
}
So you could check if the current browser is IE by investigating the value of Prototype.Browser.IE, or alternatively, be more future-compatible and check for a particular feature like XPath with Prototype.BrowserFeatures.XPath.
You're right - prototype doesn't provide a utility for ascertaining the browser name or version.
If you specifically need to get the browser info as a plugin, I would suggest adding the following (taken from directly jQuery):
var Browser = Class.create({
initialize: function() {
var userAgent = navigator.userAgent.toLowerCase();
this.version = (userAgent.match( /.+(?:rv|it|ra|ie)[\/: ]([\d.]+)/ ) || [])[1];
this.webkit = /webkit/.test( userAgent );
this.opera = /opera/.test( userAgent );
this.msie = /msie/.test( userAgent ) && !/opera/.test( userAgent );
this.mozilla = /mozilla/.test( userAgent ) && !/(compatible|webkit)/.test( userAgent );
}
});
I use this over and above Prototype's browser definitions.
Object.extend(Prototype.Browser, {
ie6: (/MSIE (\d+\.\d+);/.test(navigator.userAgent)) ? (Number(RegExp.$1) == 6 ? true : false) : false,
ie7: (/MSIE (\d+\.\d+);/.test(navigator.userAgent)) ? (Number(RegExp.$1) == 7 ? true : false) : false,
ie8: (/MSIE (\d+\.\d+);/.test(navigator.userAgent)) ? (Number(RegExp.$1) == 8 ? true : false) : false,
ie9: (/MSIE (\d+\.\d+);/.test(navigator.userAgent)) ? (Number(RegExp.$1) == 9 ? true : false) : false
});
Hope it helps!
I have prototype.js extended after:
var Prototype = { ... };
with this:
// extension
if (Prototype.Browser.IE) {
if (/MSIE (\d+\.\d+);/.test(navigator.userAgent)) {
Prototype.BrowserFeatures['Version'] = new Number(RegExp.$1);
}
}
Works fine for me, calling is like:
if (Prototype.Browser.IE && Prototype.BrowserFeatures['Version'] == 8) { ... }
<script type="text/JavaScript">
function getBrowserVersion()
{
var msg = "Not Recognised Browser";
if (/Firefox[\/\s](\d+\.\d+)/.test(navigator.userAgent))
{
var ffversion = new Number(RegExp.$1)
for (var i = 1; i < 20; i++)
{
if (ffversion == i)
{
msg = "FF" + i + "x";
break;
}
}
}
else if (/MSIE (\d+\.\d+);/.test(navigator.userAgent))
{
var ieversion = new Number(RegExp.$1)
for (var i = 1; i < 20; i++)
{
if (ieversion == i)
{
msg = "IE" + i + "x";
break;
}
}
}
alert(msg); // return msg;
}
</script>
Related
I need to check and compare browser versions that are outdated. If the user's browser version is below a defined (<=) version number, a message should appear telling the user to update his/her browser. The version is defined in the following array in my html.
<script type="text/javascript" language="javascript">
var browserarr = {Name:"Chrome", ChromeVersion:52, URL:"http://www.google.com",
Name:"Firefox", FirefoxVersion:40, URL:"http://www.firefox.com",
Name:"Safari", SafariVersion:10, URL:""
};
</script>
My logic has been to code it using if statements but i want another way to do it so that i can fetch the browser family (chrome, firefox or IE) and then the corresponding outdated version and a url to go to update the browser. It should be dynamic so that I only need to add a new line to my array specifying a new browser to make the comparison in javascript.
Check browser
detectJS: function () {
b = detect.parse(navigator.userAgent);
if (b.browser.family === 'Chrome' && b.browser.major <= browserarr["ChromeVersion"]) {
document.getElementById('browserNotificationDiv').style.display = "block";
var url = 'google.com';
//document.getElementById("msgURL").innerHTML = browserarr["URL"];
}
if (b.browser.family === 'IE' && b.browser.major <= 9) {
document.getElementById('browserNotificationDiv').style.display = "block";
var url = 'ie.com';
}
if (b.browser.family === 'Safari' && b.browser.major <= browserarr["SafariVersion"]) {
document.getElementById('browserNotificationDiv').style.display = "block";
var url = 'safari.com';
}
if (b.browser.family === 'Firefox' && b.browser.major <= browserarr["FirefoxVersion"]) {
document.getElementById('browserNotificationDiv').style.display = "block";
var url = 'firefox.com';
}
browserDetect.displayInfo(
'Your current browser ' + b.browser.family + ' version ' + b.browser.major +' is outdated. </br>' +
'Please download the latest version by going to: ' + url + ' ' + 'link' +'</br>'
);
},
How shall I proceed?
There is a widget that does exactly what you are looking for, and you can configure which versions you want to mark as outdated here:
https://updatemybrowser.org/widget.html
But in terms of your current code. I would change your browser object to have a structure more like:
var browserList = {
"chrome" : {
acceptedVersion: 52,
downloadUrl: "https://www.google.com"
},
"firefox" : {
acceptedVersion: 40,
downloadUrl: "https://www.firefox.com"
},
"safari" : {
acceptedVersion: 10,
downloadUrl: "https://www.apple.com"
}
}
Then in your code you can have a switch statement that compares browser name (to lower case to make it easier), then an if statement in that switch clause that checks accepted version and acts on it appropriately.
var broswerName = b.browser.family.toLowerCase();
switch(broswerName) {
case 'chrome':
if(broswerList[broswerName].acceptedVersion > b.browser.major) {
//browser is outdated
}
break;
case 'firefox':
if(broswerList[broswerName].acceptedVersion > b.browser.major) {
//browser is outdated
}
break;
}
I've been working to scrape some webpage that is using the OWASP CRSFGuard project for protection. The library seems to be causing one of my requests to get a 401 so I started digging through their code and noticed the following;
function isValidDomain(current, target) {
var result = false;
/** check exact or subdomain match **/
if(current == target || current == 'localhost') {
result = true;
} else if(true == false) {
if(target.charAt(0) == '.') {
result = current.endsWith(target);
} else {
result = current.endsWith('.' + target);
}
}
return result;
}
From what I can tell, there must be instances where this code is executed; result = current.endsWith('.' + target);. Given true == false is inherently false, how would the code reach that statement? Is this some JS oddity (I know we're not using the strict === equality, but seriously...)?
Answer: It will never reach that code block.
function isValidDomain(current, target) {
var result = false;
/** check exact or subdomain match **/
if (current == target || current == 'localhost') {
result = true;
} else if (true == false) {
if (target.charAt(0) == '.') {
result = current.endsWith(target);
} else {
result = current.endsWith('.' + target);
}
}
return result;
}
var trueFalse = document.getElementById('trueFalse');
trueFalse.innerHTML = isValidDomain('true', 'false') ? 'WTF!' : 'All is good in the JS World';
trueFalse.addEventListener('click', function(e) {
trueFalse.innerHTML = (true == false) ? 'WTF!' : 'All is good in the JS World Still';
});
<div id="trueFalse"></div>
I would say that Blazemonger is most likely correct.
That else if probably had some other condition at some point, and for whatever reason, they decided they didn't want that block of code to execute anymore, so they changed the condition to something that is always false.
It's also not entirely uncommon to see programmers use 1 === 0 as an indication for false. Why they would want to do this is anybody's guess.
I have the following code which is used for a mixitup filter, this code regulates the input from an input range and sets it to a checkbox which is checked it works in every browser except for internet explorer (tested in ie11). I think it has something to do with the initial function.
var p = document.getElementById("range"),
res = document.getElementById("output");
p.addEventListener("input", function () {
$("output").html(p.value);
var classes = "";
var minimal = 0;
var maximal = p.value;
$("input[type='range']").attr({'data-filter': "."+ maximal});
$("input[type=checkbox].budget").val('.'+maximal);
$( ".active" ).each(function( index ) {
var thisClass = $(this).attr("data-filter");
if (thisClass == '#mix.activiteiten') {
} else {
if (thisClass != 'undefined') {
classes += thisClass + ',';
}
}
});
if (classes.length > 0) {
var replaced = classes.replace('undefined', '');
var matching = 0;
var arrClasses = replaced.split(",")
}
}, true);
p.addEventListener("change", function() {
var $show = $('#FilterContainer').find('#mix.activiteiten').filter(function(){
var price = Number($(this).attr('data-budget'));
if (classes.length == 0) {
return price >= minimal && price <= maximal;
} else {
for (index = 0; index < arrClasses.length; index++) {
var thisValue = arrClasses[index].replace('.', '');
if ($(this).hasClass(thisValue) && price >= minimal && price <= maximal) {
matching = 1;
return (price >= minimal && price <= maximal);
}
}
}
});
$('#FilterContainer').mixItUp('filter', $show);
}, true);
`
Try this ... by using the jQuery On, you can ensure better response across browsers and versions.
var p = document.getElementById("range"),
res = document.getElementById("output");
$("#range").on("input", function () {
...
}, true);
$("#range").on("change", function() {
...
}, true);
In older IE attachEvent method works instead of addEventListner
see Docs
If you're interested in a cross-browser approach, try creating a function that handles the feature detection for you. Here's one way that might help as a starting point:
function registerEvent( sTargetID, sEventName, fnToBeRun )
{
var oTarget = document.getElementById( sTargetID );
if ( oTarget != null )
{
if ( oTarget.addEventListener ) {
oTarget.addEventListener( sEventName, fnToBeRun, false );
} else {
if ( oTarget.attachEvent )
{
oTarget.attachEvent( sOnEvent, fnToBeRun );
}
}
}
}
Note that this function makes a few assumptions that you may wish to expand in in order to incorporate this into production code, such as error checking, fallback to attribute based event handlers, and so on. Still, it may serve as a proof of concept.
Also, those claiming that IE predominately relies on attachEvent are referring to older versions of IE. Starting with IE9, addEventListener is not only supported, it's recommended for IE. To learn more, see:
How to detect features, rather than browsers
Use feature and behavior detection
IECookbook: Compatibility guidelines and best practices
The IE Blog is a good way to stay up-to-date on the latest news and best practices for IE. (For example, here's the entry talking about why you should use addEventListener instead of attachEvent.)
Hope this helps...
-- Lance
P.S. If 'addEventListener' doesn't seem to be working for you, trying adding <!DOCTYPE html> as the first line of your HTML file. To learn more, see How to enable standards support.
P.P.S. If you create a personal library of such functions, you can greatly reduce the amount of time it takes you to incorporate common tasks into new projects.
I have the following JavaScript function which is failing in internet explorer 9 on the line which declares the variable filesattached.
function VesselDetails() {
insurancestart = $('#ctl00_ContentPlaceHolder1_datetimepickerinsstart').val();
insuranceend = $('#ctl00_ContentPlaceHolder1_datetimepickerinsend').val();
filesattached = $("input:File")[0].files.length;
//set up JS objects
$('#ctl00_ContentPlaceHolder1_datetimepickerinsend').datetimepicker({ format: 'd/m/Y H:i a' });
$('#ctl00_ContentPlaceHolder1_datetimepickerinsstart').datetimepicker({ format: 'd/m/Y H:i a' });
//subscribe to change events
$('#ctl00_ContentPlaceHolder1_datetimepickerinsstart').change(function () {
insurancestart = $("ctl00_ContentPlaceHolder1_datetimepickerinsstart").val();
});
$('#ctl00_ContentPlaceHolder1_datetimepickerinsend').change(function () {
insuranceend = $("ctl00_ContentPlaceHolder1_datetimepickerinsend").val();
});
$("input:File").change(function () {
filesattached = $("input:File")[0].files.length;
});
ins_client();
}
The ins_client method looks like this:
function ins_client(sender, e) {
if (pagemode == 'EditVessel') {
e.IsValid = true;
}
if (pagemode == 'NewVessel') {
if (insurancestart !== '' && insuranceend !== '' && filesattached > 0) {
e.IsValid = true;
}
else {
e.IsValid = false;
}
}
}
This all works perfectly well in chrome and ie 11 but the length property is returning an undefined for ie 9. I am using the length because I only want the page to be valid for a new vessel request once a document has been submitted, is there another way of doing this which will work in ie 9 onwards and chrome, apologies if this has already been answered elsewhere but I cannot find a workaround anywhere that enables this to continue working in the same way but in ie9 onwards and chrome.
I replaced:
filesattached = $("input:File")[0].files.length;
With:
var areFilesAttached = document.getElementById('ctl00_ContentPlaceHolder1_fuAttachment').value ? true : false;
Within the VesselDetails function.
Then replaced the if statement within ins_client with the following:
if (pagemode == 'NewVessel') {
if (insurancestart !== '' && insuranceend !== '' && areFilesAttached == true) {
e.IsValid = true;
}
else {
e.IsValid = false;
}
}
This was an alternative approach which enabled me to check whether or not a file had been provided without using the files.length property which is not compatible with IE9.
I'm afraid this can't be achieved, IE9 does not support HTML5 File API and therefore it returns undefined value for files property.
Take a look at FILE API
if (typeof t.plugins != D && typeof t.plugins[S] == r) {
ab = t.plugins[S].description;
if (ab && !(typeof t.mimeTypes != D && t.mimeTypes[q] && !t.mimeTypes[q].enabledPlugin)) {
T = true;
X = false;
ab = ab.replace(/^.*\s+(\S+\s+\S+$)/, "$1");
ag[0] = parseInt(ab.replace(/^(.*)\..*$/, "$1"), 10);
ag[1] = parseInt(ab.replace(/^.*\.(.*)\s.*$/, "$1"), 10);
ag[2] = /[a-zA-Z]/.test(ab) ? parseInt(ab.replace(/^.*[a-zA-Z]+(.*)$/, "$1"), 10) : 0
}
} else {
if (typeof O.ActiveXObject != D) {
try {
var ad = new ActiveXObject(W);
if (ad) {
ab = ad.GetVariable("$version");
if (ab) {
X = true;
ab = ab.split(" ")[1].split(",");
ag = [parseInt(ab[0], 10), parseInt(ab[1], 10), parseInt(ab[2], 10)]
}
}
} catch (Z) {}
}
}
return {
w3: aa,
pv: ag,
wk: af,
ie: X,
win: ae,
mac: ac
}
}()
The above code used in swf object library .They checking plugin and ActiveX object written in jquery.Activex will work in IE only.My doubt is whether it will work in all the browsers?if it is yes means ,how its working?
Why shouldn't it work? The check for ActiveX is conditional as well as the access to the ActiveX object catched in case of an error.
So any browser that does not support non-IE behavior (that is, all except IE ;)), will be handled by the else.
BTW: the latest version in the repos has the code a little differently structrued
.... }
else if (typeof win.ActiveXObject != UNDEF) {
try {
var a = new ActiveXObject(SHOCKWAVE_FLASH_AX);
if (a) { // a will return null when ActiveX is disabled
d = a.GetVariable("$version");
if (d) {
ie = true; // cascaded feature detection for Internet Explorer
d = d.split(" ")[1].split(",");
playerVersion = [parseInt(d[0], 10), parseInt(d[1], 10), parseInt(d[2], 10)];
}
}
catch(e) {}
}
It's not an else anymore but an else if (again with a try-catch). The most common case is coverd before hand. They simply check for all the plugins loaded by the browser as reported by navigator.plugins. Since this is the way to do it, most browsers will never enter the else if part.
To get some information about navigator.plugins, check the MDN docs. This is a browser thing and available in all browsers (except the usual IEs, but the technique from the code above will take care of this). This will always be "plugins". If you try to access it differently e.g. "plugin", you will get an error since it is not defined.
I'm not quite sure what you mean by mentioning jQuery. This is vanilla JS, so there is no jQuery used. We used this library quite often and I can asure you, it is stable and well tested.