I'm trying to change my image size with javascript to be 500x375 instead of 130x98. If there is no 500x37 for that image, than I would like it to fallback to 130x98.
So far, I have the code below. It changes my images to 500x375, but the ones that do not have that size it appears broken instead of falling back to 130x98. Any ideas on how to fix this?
function ImageExists(selector) {
var imageFound = $(selector);
if (imageFound.height() === 0) {
console.log('no height');
return false;
}
return true;
}
$('div.photo > a > img').each(function(k, v) {
var x = v.src;
v.src = x.replace('130x98', '500x375');
if (!ImageExists(v)) {
console.log(v.src);
v.src = x.replace('500x375', '130x98')
}
});
You can try this code
$(document).ready(function(){
var src1 = '130x98';
var src2 = '500x375';
$('div.photo > a > img').each(function(){
var changeSrc;
var Image = $(this);
var GetSrc = $(this).attr('src');
Image.error(function() {
if(GetSrc.indexOf(src1) !== -1 ){
changeSrc = GetSrc.replace(src1 , src2);
}else if(GetSrc.indexOf(src2) !== -1 ){
changeSrc = GetSrc.replace(src2 , src1);
}
Image.attr("src", changeSrc);
});
})
});
DEMO
Are you missing semicolon in v.src = x.replace('500x375', '130x98'):in this line??
try putting alert();function in which line you doubted... alert(); will not work if any previous line is in error
$('div.photo > a > img').each(function (k, v) {
var x = v.src;
v.src = x.replace('130x98', '500x375');
if (!ImageExists(v)) {
console.log(v.src);
v.src = x.replace('500x375', '130x98');
};
How about trying the on error event instead of your ImageExists method:
$("img").error(function () {
//load in your default image dimensions.
});
When there's an error loading the image this will be triggered.
You might also want to unbind this event the first time it us run in case it continuously loops.
Related
I have a site with a banner video that worked fine when we were running jquery2. After upgrading to jquery 3, the banner video no longer works. Can anyone look at the code and see what is wrong? When I look at the console in chrome, I see this error (as well as a cookie error) : jquery.min.js:2 Uncaught TypeError: e.indexOf is not a function
at S.fn.init.S.fn.load (jquery.min.js:2)
at (index):532
<video id="BannerVideo" class="Banner" muted playsinline loop oncanplaythrough="playBannerVideo()"></video>
<script>
function playBannerVideo()
{
var videoElement = document.getElementById('BannerVideo');
try
{
videoElement.play();
}
catch(err) {}
}
var basePosterURL = '/FCC/media/Images/Home2018/Banner/Banner.jpg';
var baseVideoURL = '/FCC/media/Images/Home2018/Banner/BannerVideo.mp4';
function getNameForCurrentWidth()
{
var bodyWidth = document.body.clientWidth; // $('body').width();
if (bodyWidth <= 767)
return '_Phone';
if (bodyWidth <= 990)
return '_Tablet';
return ''; // Desktop
}
var loadedWidthName;
function loadBannerVideo(posterOnly)
{
var newWidthName = getNameForCurrentWidth();
if(newWidthName == loadedWidthName)
return;
loadedWidthName = newWidthName;
var videoElement = document.getElementById('BannerVideo');
if (!videoElement.paused)
videoElement.pause();
videoElement.src = '';
videoElement.poster = addToFilename(basePosterURL, loadedWidthName);
if (posterOnly == true)
return;
setBannerVideoSrc(loadedWidthName);
}
function setBannerVideoSrc(newWidthName)
{
// don't play video if in design or edit modes
if( $('body.DesignMode').length == 1 || $('body.EditMode').length == 1)
return;
var videoElement = document.getElementById('BannerVideo');
videoElement.src = addToFilename(baseVideoURL, newWidthName);
videoElement.load();
}
// load poster as soon as possible
$(function() // document.ready
{
loadBannerVideo(true);
});
// load and play video after everything else loads
$(window).load(function()
{
setBannerVideoSrc(loadedWidthName);
});
var resizeTimeout;
$(window).resize(function()
{
clearTimeout(resizeTimeout);
resizeTimeout = setTimeout(resizeEnd, 200);
});
function resizeEnd()
{
loadBannerVideo();
}
</script>
According to this article with the same error, the load(), error() and toggle() event listeners are deprecated. Meaning you're using out of date code that isn't supported by jQuery no more.
Analyzing your code I see that you use the load() event listener. The fix here would be to use the on to listen to the load event.
$(window).on('load', function() {
// ...
});
But your code uses so little jQuery and way more vanilla JavaScript that it makes little sense to use jQuery at all. I'd recommend that you ditch it if you don't use it anywhere else. In case you do, the snippet below is the equivalent of what you posted, but without jQuery.
function playBannerVideo() {
var videoElement = document.getElementById("BannerVideo");
try {
videoElement.play();
} catch (err) {}
}
var basePosterURL = "/FCC/media/Images/Home2018/Banner/Banner.jpg";
var baseVideoURL = "/FCC/media/Images/Home2018/Banner/BannerVideo.mp4";
function getNameForCurrentWidth() {
var bodyWidth = document.body.clientWidth;
if (bodyWidth <= 767) return "_Phone";
if (bodyWidth <= 990) return "_Tablet";
return ""; // Desktop
}
var loadedWidthName;
function loadBannerVideo(posterOnly) {
var newWidthName = getNameForCurrentWidth();
if (newWidthName == loadedWidthName) return;
loadedWidthName = newWidthName;
var videoElement = document.getElementById("BannerVideo");
if (!videoElement.paused) videoElement.pause();
videoElement.src = "";
videoElement.poster = addToFilename(basePosterURL, loadedWidthName);
if (posterOnly == true) return;
setBannerVideoSrc(loadedWidthName);
}
function setBannerVideoSrc(newWidthName) {
// don't play video if in design or edit modes
if (document.querySelector("body.DesignMode").length == 1 || document.querySelector("body.EditMode").length == 1)
return;
var videoElement = document.getElementById("BannerVideo");
videoElement.src = addToFilename(baseVideoURL, newWidthName);
videoElement.load();
}
// load poster as soon as possible
loadBannerVideo(true);
// load and play video after everything else loads
window.addEventListener('load', function() {
setBannerVideoSrc(loadedWidthName);
});
var resizeTimeout;
window.addEventListener('resize', function () {
clearTimeout(resizeTimeout);
resizeTimeout = setTimeout(resizeEnd, 200);
});
function resizeEnd() {
loadBannerVideo();
}
I'm stuck as to why I can't get an AddEventListener click event to work on a set of images that appear in a modal. I had them working before before the modal aspect was involve, but I'm not sure that the modal broke the image click event either.
Here is the function in question, which is called within a massive document.addEventListener("DOMContentLoaded", function (event) function:
var attachClick = function () {
Array.prototype.forEach.call(containers, function (n, i) {
n.addEventListener('click', function (e) {
// populate
cleanDrawer();
var mediaFilterSelected = document.querySelector('.media-tags .tag-container .selected');
var selectedFilters = "";
if (mediaFilterSelected != "" && mediaFilterSelected != null) {
selectedFilters = mediaFilterSelected.innerHTML;
}
var portfolioItemName = '';
var selectedID = this.getAttribute('data-portfolio-item-id');
var data = portfolioItems.filter(function (item) {
portfolioItemName = item.name;
return item.id === selectedID;
})[0];
clientNameContainer.innerHTML = data.name;
descriptionContainer.innerHTML = data.description;
var childItems = data.child_items;
//We will group the child items by media tag and target the unique instance from each group to get the right main banner
Array.prototype.groupBy = function (prop) {
return this.reduce(function (groups, item) {
var val = item[prop];
groups[val] = groups[val] || [];
groups[val].push(item);
return groups;
}, {});
}
var byTag = childItems.groupBy('media_tags');
if (childItems.length > 0) {
handleBannerItem(childItems[0]);
var byTagValues = Object.values(byTag);
byTagValues.forEach(function (tagValue) {
for (var t = 0; t < tagValue.length; t++) {
if (tagValue[t].media_tags == selectedFilters) {
handleBannerItem(tagValue[0]);
}
}
});
childItems.forEach(function (item, i) {
// console.log("childItems.forEach"); we get into here
var img = document.createElement('img'),
container = document.createElement('div'),
label = document.createElement('p');
container.appendChild(img);
var mediaTags = item.media_tags;
container.className = "thumb";
label.className = "childLabelInactive thumbLbl";
thumbsContainer.appendChild(container);
if (selectedFilters.length > 0 && mediaTags.length > 0) {
for (var x = 0; x < mediaTags.length; x++) {
if (mediaTags[x] == selectedFilters) {
container.className = "thumb active";
label.className = "childLabel thumbLbl";
}
}
}
else {
container.className = i == 0 ? "thumb active" : "thumb";
// console.log("no tags selected"); we get to here
}
img.src = item.thumb;
if (item.media_tags != 0 && item.media_tags != null) {
childMediaTags = item.media_tags;
childMediaTags.forEach(function (cMTag) {
varLabelTxt = document.createTextNode(cMTag);
container.appendChild(label);
label.appendChild(varLabelTxt);
});
}
//console.log("before adding click to images"); we get here
console.log(img.src);
img.addEventListener("click", function () {
console.log("thumbnail clicked"); //this is never reached
resetThumbs();
handleBannerItem(item);
container.className = "thumb active";
});
});
}
attachClick();
//open a modal to show off the portfolio pieces for the selected client
var tingleModal = document.querySelector('.tingle-modal');
drawer.className = 'drawer';
var portfolioModal = new tingle.modal({
onOpen: function() {
if(tingleModal){
tingleModal.remove();
}
console.log('modal open');
},
onClose: function() {
console.log('modal closed');
//tingleModal.remove();
}
});
e.preventDefault();
portfolioModal.open();
portfolioModal.setContent(document.querySelector('.drawer-content').innerHTML);
});
});
};
And the specific bit that I'm having trouble with:
console.log(img.src);
img.addEventListener("click", function () {
console.log("thumbnail clicked"); //this is never reached
resetThumbs();
handleBannerItem(item);
container.className = "thumb active";
});
I tried removing the e.PreventDefault() bit but that didn't solve the issue. I know the images are being created, so the img variable isn't empty. I feel like the addEventListener is setup correctly. I also tried moving that bit up just under the img.src = item.thumb line, but no luck. For Some reason, the click event just will not trigger for the images.
So if I understand correctly, you have a modal that lies above the images (it has a higher z-index)? Well in this case the clicks are not reaching the images as they will hit the modal. You can pass clicks through elements that lie above by applying the css property pointer-events: none; to the modal, but thats somehow controversial to what a modal is intended to do.
Are the images present in the modal on DOMContentLoaded? You may be able to try delegating the handling of clicks to a parent element if that's the case.
You can try the delegation approach shown here: Vanilla JavaScript Event Delegation
I managed to add interactivity to a feature layer added from a remote GeoJSON resource. When I click on a feature I get its ID, fire an AJAX request and display some relevant info about the feature, on the page outside of the map area.
I used a Select interaction.
I would like to make it even clearer to the user that he can click on the features on the map. Is there any way I can change the mouse cursor to "cursor" of "hand" when the mouse hovers a feature contained in a ol.layer.Vector ?
I couldn't find anything in the doc, on this site or by googling.
It can be done as well without jQuery:
map.on("pointermove", function (evt) {
var hit = this.forEachFeatureAtPixel(evt.pixel, function(feature, layer) {
return true;
});
if (hit) {
this.getTargetElement().style.cursor = 'pointer';
} else {
this.getTargetElement().style.cursor = '';
}
});
Here is another way to do it:
map.on('pointermove', function(e){
var pixel = map.getEventPixel(e.originalEvent);
var hit = map.hasFeatureAtPixel(pixel);
map.getViewport().style.cursor = hit ? 'pointer' : '';
});
If that doesn't work, try a combination of the 2, seemed to work for my vector popup...
var target = map.getTarget();
var jTarget = typeof target === "string" ? $("#" + target) : $(target);
// change mouse cursor when over marker
$(map.getViewport()).on('mousemove', function (e) {
var pixel = map.getEventPixel(e.originalEvent);
var hit = map.forEachFeatureAtPixel(pixel, function (feature, layer) {
return true;
});
if (hit) {
jTarget.css("cursor", "pointer");
} else {
jTarget.css("cursor", "");
}
});
Thanks to the example link provided by Azathoth in the comments I worked a solution out:
using OL3 pointermove event
using jQuery to get the target element and change its cursor style
Here is the code :
var cursorHoverStyle = "pointer";
var target = map.getTarget();
//target returned might be the DOM element or the ID of this element dependeing on how the map was initialized
//either way get a jQuery object for it
var jTarget = typeof target === "string" ? $("#"+target) : $(target);
map.on("pointermove", function (event) {
var mouseCoordInMapPixels = [event.originalEvent.offsetX, event.originalEvent.offsetY];
//detect feature at mouse coords
var hit = map.forEachFeatureAtPixel(mouseCoordInMapPixels, function (feature, layer) {
return true;
});
if (hit) {
jTarget.css("cursor", cursorHoverStyle);
} else {
jTarget.css("cursor", "");
}
});
Here is the link to the example on OpenLayers site : http://openlayers.org/en/v3.0.0/examples/icon.html
For me it worked like this:
map.on('pointermove', function(e) {
if (e.dragging) return;
var pixel = e.map.getEventPixel(e.originalEvent);
var hit = e.map.forEachFeatureAtPixel(pixel, function (feature, layer) {
return true;
});
e.map.getTargetElement().style.cursor = hit ? 'pointer' : '';
});
I also added a layer filter:
map.on('pointermove', function(e) {
if (e.dragging) return;
var pixel = e.map.getEventPixel(e.originalEvent);
var hit = e.map.forEachFeatureAtPixel(pixel, function (feature, layer) {
return layer.get('name') === 'myLayer';
});
e.map.getTargetElement().style.cursor = hit ? 'pointer' : '';
});
I had to select a new solution as the old one I had use for the layer filter before did not work anymore:
var hit = e.map.hasFeatureAtPixel(e.pixel, function(layer){
return layer.get('name') === 'myLayer';
});
I did it with the following code:
var target = $(map.getTargetElement()); //getTargetElement is experimental as of 01.10.2015
map.on('pointermove', function (evt) {
if (map.hasFeatureAtPixel(evt.pixel)) { //hasFeatureAtPixel is experimental as of 01.10.2015
target.css('cursor', 'pointer');
} else {
target.css('cursor', '');
}
});
Another way (combined from parts of above answers, but even simpler):
map.on("pointermove", function (evt) {
var hit = map.hasFeatureAtPixel(evt.pixel);
map.getTargetElement().style.cursor = (hit ? 'pointer' : '');
});
Uncaught TypeError: Cannot set property 'cursor' of undefined.
Fixed with: map.getTargetElement()s.style.cursor = hit ? 'pointer' : ''; instead of map.getTarget().style.cursor = hit ? 'pointer' : '';
Simple way to get target element
var target = map.getTarget();
target = typeof target === "string" ?
document.getElementById(target) : target;
target.style.cursor = features.length > 0) ? 'pointer' : '';
If you guys are using Angular 2 you must use the following code:
this.map.on("pointermove", function (evt) {
var hit = evt.map.hasFeatureAtPixel(evt.pixel);
this.getTargetElement().style.cursor = hit ? 'pointer' : '';
});
If the map variable is a member class you refer to it as "this.map", instead if it is declared inside the current function it can be refered to as "map". But above all, you don't write
map.getTargetElement()
but you write
this.getTargetElement()
I tried to minimize pointermove event closure, by avoiding to update style when not necessary, because it calls so very often:
Example-1: uses jQuery:
var cursorStyle = "";
map.on("pointermove", function (e) {
let newStyle = this.hasFeatureAtPixel(e.pixel) ? "pointer" : "";
newStyle !== cursorStyle && $(this.getTargetElement()).css("cursor", cursorStyle = newStyle);
});
Example-2: no jQuery:
var cursorStyle = "";
map.on("pointermove", function (e) {
let newStyle = this.hasFeatureAtPixel(e.pixel) ? "pointer" : "";
if (newStyle !== cursorStyle) {
this.getTargetElement().style.cursor = cursorStyle = newStyle;
}
});
Easy way
map.on('pointermove', (e) => {
const pixel = map.getEventPixel(e.originalEvent);
const hit = map.hasFeatureAtPixel(pixel);
document.getElementById('map').style.cursor = hit ? 'pointer' : '';
});
}
I am trying to create collapsible DIVs that react to links being clicked. I found how to do this using "next" but I wanted to put the links in a separate area. I came up with this which works...
JSFiddle - Works
function navLink(classs) {
this.classs = classs;
}
var homeLink = new navLink(".content-home");
var aboutLink = new navLink(".content-about");
var contactLink = new navLink(".content-contact");
var lastOpen = null;
$('.home').click(function() {
if(lastOpen !== null) {
if(lastOpen === homeLink) {
return; } else {
$(lastOpen.classs).slideToggle('fast');
}
}
$('.content-home').slideToggle('slow');
lastOpen = homeLink;
}
);
$('.about').click(function() {
if(lastOpen !== null) {
if(lastOpen === aboutLink) {
return; } else {
$(lastOpen.classs).slideToggle('fast');
}
}
$('.content-about').slideToggle('slow');
lastOpen = aboutLink;
}
);
$('.contact').click(function() {
if(lastOpen !== null) {
if(lastOpen === contactLink) {
return; } else {
$(lastOpen.classs).slideToggle('fast');
}
}
$('.content-contact').slideToggle('slow');
lastOpen = contactLink;
}
);
I am now trying to create the same result but with a single function instead of one for each link. This is what I came up with....
function navLink(contentClass, linkClass, linkId) {
this.contentClass = contentClass;
this.linkClass = linkClass;
this.linkId = linkId;
}
var navs = [];
navs[0] = new navLink(".content-home", "nav", "home");
navs[1] = new navLink(".content-about", "nav", "about");
navs[2] = new navLink(".content-contact", "nav", "contact");
var lastOpen = null;
$('.nav').click(function(event) {
//loop through link objects
var i;
for (i = 0; i < (navsLength + 1); i++) {
//find link object that matches link clicked
if (event.target.id === navs[i].linkId) {
//if there is a window opened, close it
if (lastOpen !== null) {
//unless it is the link that was clicked
if (lastOpen === navs[i]) {
return;
} else {
//close it
$(lastOpen.contentClass).slideToggle('fast');
}
}
//open the content that correlates to the link clicked
$(navs[i].contentClass).slideToggle('slow');
navs[i] = lastOpen;
}
}
});
JSFiddle - Doesn't Work
No errors so I assume that I am just doing this completely wrong. I've been working with Javascript for only about a week now. I've taken what I've learned about arrays and JQuery events and tried to apply them here. I assume I'm way off. Thoughts? Thanks
You just forgot to define navsLength:
var navsLength=navs.length;
Of course you could also replace it with a $().each loop as you're using jQuery.
[Update] Two other errors I corrected:
lastOpen=navs[i];
for(i=0; i < navsLength ; i++)
Demo: http://jsfiddle.net/jMzPJ/4/
Try:
var current, show = function(){
var id = this.id,
doShow = function() {
current = id;
$(".content-" + id).slideToggle('slow');
},
toHide = current && ".content-" + current;
if(current === id){ //Same link.
return;
}
toHide ? $(toHide).slideToggle('fast', doShow): doShow();;
};
$("#nav").on("click", ".nav", show);
http://jsfiddle.net/tarabyte/jMzPJ/5/
I'm trying to make my website scroll to specific post that is on separate page. I figured the PHP part behind this to generate anchors for me however I'm stuck with JS part. I managed to make webpage start at position 0,0 and then to go to static anchor tag. What I struggle with is how do I make JS fetch anchor tag from current URL and then make it smoothly scroll to given tag after short delay.
My current code is:
$(document).ready(function() {
if (location.hash) {
window.scrollTo(0, 0);
}
});
setTimeout("window.location.hash = '#scroll';", 5000);
I found following snipped that fetches an anchor tag off URL but I'm not sure how can I make it execute after some delay.
$(document).ready(function() {
function filterPath(string) {
return string
.replace(/^\//,'')
.replace(/(index|default).[a-zA-Z]{3,4}$/,'')
.replace(/\/$/,'');
}
var locationPath = filterPath(location.pathname);
var scrollElem = scrollableElement('html', 'body');
$('a[href*=#]').each(function() {
var thisPath = filterPath(this.pathname) || locationPath;
if ( locationPath == thisPath
&& (location.hostname == this.hostname || !this.hostname)
&& this.hash.replace(/#/,'') ) {
var $target = $(this.hash), target = this.hash;
if (target) {
var targetOffset = $target.offset().top;
$(this).click(function(event) {
event.preventDefault();
$(scrollElem).animate({scrollTop: targetOffset}, 400, function() {
location.hash = target;
});
});
}
}
});
// use the first element that is "scrollable"
function scrollableElement(els) {
for (var i = 0, argLength = arguments.length; i <argLength; i++) {
var el = arguments[i],
$scrollElement = $(el);
if ($scrollElement.scrollTop()> 0) {
return el;
} else {
$scrollElement.scrollTop(1);
var isScrollable = $scrollElement.scrollTop()> 0;
$scrollElement.scrollTop(0);
if (isScrollable) {
return el;
}
}
}
return [];
}
});
I don't believe setTimeout accepts any old code passed as a string, only function names. Try using an anonymous function instead:
setTimeout(function() { window.location.hash = '#scroll'; }, 5000);
I managed to solve my problem using snippet that I found on CSS-Tricks forum. It scrolls to an anchor tag on page load, always starting from the very top of the page.
$(window).bind("ready", function() {
var urlHash = window.location.href.split("#")[1];
$('html,body').animate({scrollTop:$('a[href="#'+urlHash+'"]').offset().top}, 1500);
});