jQuery/JavaScript Tabs not working for IE9 - javascript

I have this tabs that are working perfect in any browser apart from IE 9. Have been trying to solve this problem for days now, and I think I'm going completely mad.
<div class="product-collateral">
<div class="tab"><h3 class="product_tabs_additional">Additional Information</h3></div>
<div class="product-tabs-content" id="product_tabs_additional_contents">
Additional Information Content
</div>
<div class="tab"><h3 class="product_tabs_agenda">Agenda</h3></div>
<div class="product-tabs-content" id="product_tabs_agenda_contents">
Agenda Content
</div>
<div class="tab"><h3 class="product_tabs_terms">Terms and Conditions</h3></div>
<div class="product-tabs-content" id="product_tabs_terms_contents">
Terms and Conditions Content
</div>
<div class="tab"><h3 class="product_tabs_locations">Locations</h3></div>
<div class="product-tabs-content" id="product_tabs_locations_contents">
Locations Content
</div></div>
​
<script type = "text/javascript" > $jQ = jQuery.noConflict();
$jQ('.product-collateral .tab h3').wrapAll('<ul class="product-tabs"></ul>').wrap('<li></li>');
$jQ('.product-collateral .product-tabs li').each(function(index) {
$jQ(this).attr('id', $jQ(this).find('h3').attr('class'));
if (index === 0) {
$jQ(this).addClass('active');
}
});
//<![CDATA[
Varien.Tabs = Class.create();
Varien.Tabs.prototype = {
initialize: function(selector) {
var self = this;
$$(selector + ' h3').each(this.initTab.bind(this));
},
initTab: function(el) {
el.href = 'javascript:void(0)';
if ($(el.parentNode).hasClassName('active')) {
this.showContent(el);
}
el.observe('click', this.showContent.bind(this, el));
},
showContent: function(a) {
var li = $(a.parentNode),
ul = $(li.parentNode);
ul.select('li', 'ol').each(function(el) {
var contents = $(el.id + '_contents');
if (el == li) {
el.addClassName('active');
contents.show();
} else {
el.removeClassName('active');
contents.hide();
}
});
}
}
new Varien.Tabs('.product-tabs');
//]]>
< /script>​
I know that one of the lines $$(selector + ' h3').each(this.initTab.bind(this)); there is a 2x$ but without it script stops working.
Im not a JavaScript specialist at all, hence my problem. Strangest for me is that this script is running in IE7 and 8 mode without any trouble. Only IE9 is breaking.
Any help much appreciated.
Thank you in advance
Dom

Please Check you code, and avoid declaring multiple versions of jQuery on the page. I think its the problem of jQuery conflict.

Looking at your page, you are using an old version of prototype (1.6.0.3), which was released in 2008 which is pre-IE9. In this version when you run the line: ul.select('li', 'ol') it's returning the empty list instead of the 4 element list you expect.
Quick fix: try changing the line to: ul.select('li'), which should select all the elements you want here.
Better fix: Upgrade to the latest version of prototype (1.7).

Related

Searching items causes lags

I have following problem. Let's say I have DOM like this.
<div class="results">
<div class="result">
<div class="title">Aaa</div>
</div>
<div class="result filtered-out">
<div class="title">Aab</div>
</div>
<div class="result">
<div class="title">Aac</div>
</div>
<div class="result">
<div class="title">Aad</div>
</div>
<div class="result">
<div class="title">Aae</div>
</div>
</div>
and an input field like this
<input type="text" id="search">
And now I try to filter the results with a simple function defined by this
var searchBox = $(this);
searchBox.keyup(function(){
var searchBox = $(this);
var items = $(".results .result:not(.filtered-out)");
items.each(function(){
var title = $(this).find(".title").html();
if(title.toLowerCase().indexOf(searchBox.val().toLowerCase())!== -1)
$(this).show();
else
$(this).hide();
});
});
So the problem is that the list of results is quite long something between 100 and 200 elements and whenever I type something into the search input the code executes very long. Maybe around 2-3 seconds. Is there any other approach to solve this "lag"? Thank you for any advices!
EDIT Maybe something like delayed script execution or asynchronous script execution (like in ajax)?
It's generally not a good idea to use the DOM as a datasource, it's not meant for it and is therefore slow. Personally I would recommend using a small MVVM library or something similar so you don't have to manually manage the DOM yourself.
I've used Vue.js below, but you could just as well use any similar solution. Keeping your data in the code will allow you to operate on it a lot faster since you don't have to re-request it all the time and you avoid doing a lot of work for modifications. All operations below are done on 1000 objects:
var items = [];
for (var i = 0; i < 1000; i++) {
items.push({
title: 'Item #' + i
});
}
var v = new Vue({
el: '#list',
data: {
items: items,
input: ""
},
computed: {
filteredItems: function() {
var value = ("" || this.input).trim().toLowerCase();
if (!value.length) return this.items;
return this.items.filter(function(item) {
return item.title.toLowerCase().indexOf(value) !== -1;
});
}
}
});
ol {
list-style: none;
padding: 0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/0.12.16/vue.min.js"></script>
<div id="list">
<input placeholder="Search" v-model="input" />
<ol>
<li v-repeat="filteredItems">{{title}}</li>
</ol>
</div>
When searching the dom through many elements it is recommended to use javascript as opposed to jQuery if speed is what you are after. jQuery has it's purpose but for large amounts of dom searching using javascripts getElementById or querySelector / querySelectorAll is going to be much much faster. If you check this jsPerf example you can see that the jQuery selector operates roughly 94% slower than the comparable getElementById.
You should try using some logging to figure out which part is taking the longest. If you find that it's the items selector (with the psuedo-not), you could try to optimize that, however I don't see anything about the filtered-out class so I'm not sure exactly what that does.
Here's some simple optimizations though:
var searchBox = $(this);
searchBox.keyup(function(){
var $searchBox = $(this);
var searchBoxVal = $searchBox.val().toLowerCase();
var items = $(".results .result:not(.filtered-out)");
items.each(function(){
var $item = $(this);
var title = $item.find(".title").html();
if (title.toLowerCase().indexOf(searchBoxVal) !== -1)
$item.show();
else
$item.hide();
});
});
My guess the lag is because you are performing the search based on the DOM elements, and at the same time manipulating them with hiding/ showing.
I suppose the DOM is populated from some data source? If so it'll be better to perform the search/ filter from that data source, then use the filtered data set to populate the DOM again. (And even if you don't have the data source at first, you can build one by reading the original DOM)

Loop through element and change based on link attribute

Trying to figure this out. I am inexperienced at jQuery, and not understanding how to loop through elements and match one.
I have 3 divs:
<div class="first-image">
<img src="images/first.png">
</div>
<div class="second-image">
<img src="images/second.png">
</div>
<div class="third-image">
<img src="images/third.png">
</div>
And off to the side, links in a div named 'copy' with rel = first-image, etc.:
...
Clicking the link will fade up the image in the associated div (using GSAP TweenMax)
Here is the function I've been working on to do this... but I am not fully understanding how to loop through all the "rel" elements, and make a match to the one that has been clicked on.
<script>
//pause slideshow on members to ledger when text is clicked, and show associated image
$(function() {
$('.copy').on('click','a',function(e) {
e.preventDefault();
var slideName = $(this).attr('rel');
$("rel").each(function(i){
if (this.rel == slideName) {
console.log(this);
}
});
//var change_screens_tween = TweenMax.to('.'+slideName+'', 1, {
//autoAlpha:1
//});
});
});
</script>
What am I doing wrong? I don't even get an error in my browser. :-(
Thanks to the answer below, I got farther. Here is my revised code.
$('[rel]').each(function(k, v){
if (v == slideName) {
var change_screens_tween = TweenMax.to('.'+slideName+'', 1, {
autoAlpha:1
});
} else {
var change_screens_tween = TweenMax.to('.'+slideName+'', 1, {
autoAlpha:0
});
}
});
});
This is starting to work, but makes the screenshots appear and then instantly fade out. And it only works once. Any thoughts?
Add brackets around rel, like so:
$('[rel]').each(function() {
if ($(this).attr('rel') == slideName) {
console.log(this);
}
});

jQuery class change not triggered in IE? Chrome/FF work as designed

I've got a little jQuery script that should display a fixed nav menu once the page is scrolled below a 200px threshold and then change the class on each menu list item to "current" once that section hits the top of the viewport.
The problem is the class change piece isn't working in IE (tested in IE11). IE console isn't throwing any errors and it works as designed in Chrome/FF.
The fadeIn/hide function works flawlessly across the board. I've got another piece of script to switch out some content based on a click event and that's working across the board as well.
I've looked at some other questions with answers revolving around blur/focus in IE, but my comprehension level just isn't there yet.
It probably doesn't matter, but I have jQuery 1.11 hosted locally.
Am I overlooking something obvious or is this more involved? Any help is so genuinely appreciated!
Rough working version of the site is at www.4sdesignstudio.com/new-projects/bwh/index.html.
Quick, abridged version of the HTML:
<footer class="main-links">
<ul>
<li>Welcome</li>
<li>The Tasting Room</li>
<li>Tasting Menu<li>
<li>Upcoming Events<li>
<li>The Artwork<li>
<li>Current Wine Releases<li>
<li>Wine Club<li>
<li>Contact Us<li>
</ul>
</footer>
<section id="main" class="marker">
A bunch of content
</section>
<section id="main2" class="marker">
A bunch of content
</section>
<section id="main3" class="marker">
A bunch of content
</section>
<!-- ...etc, etc -->
The jQuery script:
<script>
$(document).ready(function(){
// Cached variables to avoid multiple jQuery calls
var $mainLinks = $('.main-links');
var $headerLogo = $('.header-logo');
var $mainTastingMenu = $('#main-tasting-menu');
var $dessertTastingMenu = $('#dessert-tasting-menu');
var $menuSwitch_1 = $('#menu-switch1');
var $menuSwitch_2 = $('#menu-switch2');
// Plugins
$('.lightbox').nivoLightbox();
$('.scroll-pane').jScrollPane();
$('.scroll-pane2').jScrollPane();
// Event handlers
$menuSwitch_1.on('click', function(event) {
$mainTastingMenu.toggle('show');
$dessertTastingMenu.toggle('hide');
});
$menuSwitch_2.on('click', function(event) {
$mainTastingMenu.toggle('hide');
$dessertTastingMenu.toggle('show');
});
$(window).on('scroll', function(event) {
if ($(this).scrollTop() > 200) {
$mainLinks.fadeIn();
$headerLogo.fadeIn();
} else {
$mainLinks.hide();
$headerLogo.hide();
}
var top = $(this).scrollTop(),
idx = $('section.marker').sort(function (a, b) {
return top - $(b).offset().top;
}).first().index('section.marker'),
el = $('.main-links li a').eq(idx);
if (!el.hasClass('current')) {
$('.main-links li a').removeClass('current');
el.addClass('current');
}
});
});</script>
The problematic code is right here:
var top = $(this).scrollTop(),
idx = $('section.marker').sort(function (a, b) {
return top - $(b).offset().top;
}).first().index('section.marker'),
el = $('.main-links li a').eq(idx);
If you debug this in IE you will never get an index other than 0.
Even after playing with this for a while I couldn't quite understand your logic - so I decided to work up my own approach to determining the currently displayed div:
http://jsfiddle.net/6mkh2xme/3/
This has been tested on IE (windows, some ancient version), as well as Chrome and FF on a Mac.

Making editable table work cross-browser

I've been working on an ASP.NET page containing a ListView. When the user clicks a row, the content of the last (visible) column of this (once parsed) HTML table is replaced with a textbox (by means of jQuery), making the value editable.
So far, this works like a charm in Chrome but no joy in IE10.
In this jsfiddle, the value becomes editable but then the Save button doesn't work as expected.
In IE the textbox doesn't appear. Funny detail: if I comment out the four vars (invNr, newInvNr, oldHtml and spanWidth), the input element DOES appear in IE10 but of course I have no data to work with. Really REALLY weird.
The jQuery:
$(document).ready(function () {
$('tr[id*="itemRow"]').click(function () {
$clickedRow = $(this);
//this makes sure the input field isn't emptied when clicked again
if ($clickedRow.find('input[id$="editInvNr"]').length > 0) {
return;
}
var invNr = $clickedRow.find('span[id$="InvoiceNumber"]').text(),
newInvNr = '',
oldHtml = $clickedRow.find('span[id$="InvoiceNumber"]').html(),
spanWidth = $clickedRow.find('span[id$="InvoiceNumber"]').width();
$clickedRow.find('span[id$="InvoiceNumber"]').parent('td').html('<input type="text" ID="editInvNr"></input>');
$clickedRow.find('input[id="editInvNr"]').val(invNr).focus().on('input propertychange', function () {
$clickedRow.find('span[id$="SaveResultMsg"]').hide();
$clickedRow.find('td[id$="SaveOption"]').show();
$clickedRow.find('input[id*="btnSaveInvNrFormat"]').show();
newInvNr = $(this).val();
if (newInvNr == $clickedRow.find('span[id$="InvoiceNumber"]').text()) {
$clickedRow.find('td[id$="SaveOption"]').hide();
}
});
});
$('tr[id*="itemRow"]').focusout(function () {
$rowLosingFocus = $(this);
var previousValue = $rowLosingFocus.find('input[id$="editInvNr"]').val();
$rowLosingFocus.find('input[id$="editInvNr"]').closest('td').html('<asp:Label ID="lblInvoiceNumber" runat="server" />');
$rowLosingFocus.find('span[id$="InvoiceNumber"]').text(previousValue);
});
});
function UpdateInvoiceNrFormat(leButton) {
$buttonClicked = $(leButton);
$buttonClicked.focus();
var companyName = $buttonClicked.closest('tr').find('span[id$="lblCompanyName"]').text(),
invoiceType = $buttonClicked.closest('tr').find('span[id$="lblInvoiceType"]').text(),
invNrFormat = $buttonClicked.closest('tr').find('span[id$="lblInvoiceNumber"]').text();
PageMethods.UpdateInvoiceNumberFormat(companyName, invoiceType, invNrFormat, onSuccess, onError);
function onSuccess(result) {
$buttonClicked.hide();
$buttonClicked.siblings('span[id$="SaveResultMsg"]').text(result).show();
}
function onError(result) {
$buttonClicked.hide();
$buttonClicked.siblings('span[id$="SaveResultMsg"]').text('Error:' + result).show();
}
}
I've tried various combinations of jQuery statements, chaining and avoiding chaining, placing it at the bottom of the page as someone suggested, commenting out various parts of the code out of sheer desperation. Still nada.
There was no way to make the html() method replace the html correctly in IE10, although I never did find out exactly why. I ended up writing both elements into the table cell, set style="display:none" for one of them and use show() / hide() and that's good enough for me (and apparently for IE10 as well).
For anyone encountering the same issue: this is a workaround, not a solution in the strictest sense.

jQuery Cookie Question

I've looked around a lot, and can't seem to find anything that's simple enough for me to do...
I've set up a web page that detects which browser is currently running, and if it's something other than Firefox 4.0, it displays a hidden div that gives a warning stating that the page is best viewed in Firefox 4.0 or greater. Within that div is a button that hides the div onclick.
I'm looking for a way to remember that this button has been clicked during a session, so that when a user clicks on my "home" page, they don't get the same message every time.
Current code:
<head>
<script src="js/browsercheck.js"></script>
<script type="text/javascript">
// external script "browsercheck.js" checks
// which browser/version is being used
// check browser and display message if != Firefox 4.0 or >
function checkBrowser() {
var browser = BrowserDetect.browser;
var version = BrowserDetect.version;
if (browser == "Firefox") {
if (version >= 4) {
// do nothing
}
} else {
document.getElementById("coverall").style.visibility="visible";
document.getElementById("browser").innerHTML = browser + " " + version;
}
}
// remove overlay if user commands
function removeCoverall() {
document.getElementById("coverall").style.visibility="hidden";
}
</script>
</head>
<body>
<div id="coverall" style="visibility:hidden;">
<p>I see you're using <span id="browser"></span>. Please use Firefox.</p>
<button type="button" onclick="removeCoverall()">I understand</button>
</div>
</body>
Using jQuery and the cookie plugin, you can do:
function removeCoverall() {
$.cookie("user_clicked_ok", "true");
document.getElementById("coverall").style.visibility="hidden";
}
$(window).ready(function() {
if ($.cookie("user_clicked_ok")=="true") {removeCoverall();}
});
More details at: http://www.electrictoolbox.com/jquery-cookies/
In the removeCoverall function you could set a cookie which indicates that the user closed the div and in checkBrowser function verify if the cookie is present before showing the div.
You seem to have the right idea, you need cookies! YUM!
JS
function removeCoverall() {
var date = new Date();
date.setTime(date.getTime()+(7*24*60*60*1000));// expires in one week
document.cookie = 'skipNotify=1;expires='+date.toGMTString()+'; path=/';
document.getElementById("coverall").style.visibility="hidden";
}
Now retrieving the cookie can be difficult in javascript, but you can use PHP!
PHP
function checkBrowser() {
<?php if(isset($_COOKIE['skipNotify']))echo'return;';?>
var browser = BrowserDetect.browser;
var version = BrowserDetect.version;
if (browser == "Firefox") {
if (version >= 4) {
// do nothing
}
} else {
document.getElementById("coverall").style.visibility="visible";
document.getElementById("browser").innerHTML = browser + " " + version;
}
}
The above code injects a return statement if the user has the cookie, so the call to the function won't do anything.
As mentioned in the other posts, I highly recommend you use jQuery for all your javascript needs. It's very popular, stable and useful! I only gave my answer as it does not use any third party solution.

Categories

Resources