I manage a site that I did not build. The site features some links, where you can click the link, and a modal window opens with content from a different html file. It used to work, and now it doesn't.
I have compared all the relevant files between now and when I took over the site, but do not see any changes that would have affected this.
The popup windows are called thusly:
<?php bioLinkText('Daniel Jones', 'Read more about Dr. Jones'); ?></p>
The page it should open is /bios/daniel-jones.html
From the functions.php file:
function bioLinkText($name,$text) {
$name = strtolower(str_replace(" ","-",$name));
echo ''.$text.'';}
This part functions OK. But it used to create a modal window, and now, it just opens the link like a regular link.
From the global.js file:
// AJAX Popups
function popUp(page,randId) {
$('body').append(
'<div id="'+randId+'" class="pWin" style="display:none;position:fixed">'+
'<span class="pHead">'+
'Open in new window'+
'<span class="pClose">X</span>'+
'</span>'+
'<div class="pBod"></div>'+
'</div>'
);
var top = (h/2) - 150;
var left = (w/2) - 300;
$('#'+randId+'.pWin').addClass('large').css({top:top+'px',left:left+'px'});
$('#'+randId+' .pBod').html('<img src="/images/loading.gif" alt="loading"/>').load(page+' #content', function() {
$('.pWin').show(300);
$('.pBod #content').find('img').filter('#portrait').attr('src', function(index, src) {
return '/bios/' + src;
});
});
}
$('.popUp').click(function() {
var randId = randomString();
var num = $('.pWin').length;
if (num < 5) {
var page = $(this).attr('href');
popUp(page,randId);
$('#'+randId+'.pWin').draggable({handle:'.pHead'}).resizable({alsoResize:'#'+randId+' .pBod', minWidth: 320, minHeight: 280, maxWidth: 800, maxHeight: 600});
}
return false;
});
function pClose(btn) {
var pWin = btn.closest('.pWin');
pWin.hide(200, function() { pWin.remove(); });
}
$('.pClose').live('click',function() {
var btn = $(this);
pClose(btn);
});
$(document).keyup(function(e) {
if (e.keyCode == 27) {
$('.pWin').hide(200, function() { $('.pWin').remove(); });
}
});
From the style.css file:
.popUp, .pHead a { padding-right: 16px; background: url(/images/external.gif) 100% 50% no-repeat; }
.popUp.noBg { background:none; padding-right:0; }
I have been trying to figure this out for 10+ hours. Any help would be greatly appreciated. The one thing is...I don't understand how the javascript function popUp would be invoked. Is that the missing ingredient?
Try this:
//Make sure the DOM is ready (If you call this function before '.popUp' exists, it wont be matched, and the '.click' handler wont be added.
$(document).ready(function() {
$('.popUp').click(function(e) {
//Prevent the default action (Clicking the button)
e.preventDefault();
//..Your code here
});
});
Well, I figured it out. I changed the function, adding an onclick="popup()" property to the a href, and now it works:
function bioLinkText($name,$text) {
$name = strtolower(str_replace(" ","-",$name));
echo ''.$text.'';
}
Related
Disclaimer: I know my code is pretty bad. I'm not very experienced with JavaScript yet.
So I built a gallery with filtering using JavaScript and the WP Rest API. I finally have it working, but after a few clicks between the gallery sub-categories, the page starts slowing down and eventually crashes. I imagine I'm doing something really inefficient that is killing the page, but I'm not sure what the main culprit is.
Besides the other obvious issues with how I've written the code, what might be causing it and is there a good way to test performance issues like this?
(Here's a link to a working version of this: http://victorysurfaces.x10host.com/gallery/)
Edit: Updated code with fix for extra HTML DOM nodes being added by lightbox code. Didn't fix page crashing issue, unfortunately.
Update: I've noticed that sometimes when I click on a sub-category, it makes more network requests, but sometimes it doesn't. I feel like this might be important.
Update 2: I think it might have something to do with the event listeners I'm adding. Since I'm adding the sub-categories dynamically, I have to add the event listeners after they have been loaded, but the event listeners from the previous run seem to remain, so the number of event listeners just grows and grows. I don't know what to do about that.
<div class="gallery">
<div class="medium-wrapper">
<div class="gallery__filters text-center">
<div class="gallery__main-filters">
<button class="category-filter main-category active" data-category="residential">Residential</button>
<span>|</span>
<button class="category-filter main-category" data-category="commercial">Commercial</button>
</div>
<div class="gallery__category-filters"></div>
</div>
<div class="gallery__images"></div>
</div>
</div>
<script>
/* I'm so sorry for this monstrosity. This was way more complicated than I thought and in the end I just wanted it to work */
jQuery(document).ready(function($) {
$('.main-category').on('click', function() {
$('.main-category').removeClass('active');
$(this).addClass('active');
});
initLightbox();
});
jQuery( function( $ ) {
$.getJSON("/wp-json/wp/v2/gallery-categories", function( data ) {
var currentMainCategory = $('.main-category.active').data('category');
getSubCategories();
var currentSubCategory = '';
document.querySelectorAll('.main-category').forEach( function(trigger) {
trigger.addEventListener('click', function() {
resetCategories($(this).data('category')); }, false);
});
function getSubCategories() {
var categoriesArray = [];
var subCategories = data.map(function(category) {
if( category.acf.gallery_section.trim().toLowerCase() === currentMainCategory) {
var setCategory = "<button class='category-filter sub-category' data-category='" + category.acf.category_title + "'>" + category.acf.category_title + "</button>";
categoriesArray.push(setCategory);
}
});
$('.gallery__category-filters').html(categoriesArray);
getPhotos();
}
function resetCategories(mainCategoryTitle) {
currentMainCategory = '';
currentSubCategory = '';
$('.sub-category').removeClass('active');
$('.gallery__category-filters').empty();
currentMainCategory = mainCategoryTitle;
getSubCategories();
}
function setSubCategory() {
currentSubCategory = document.querySelector('.sub-category.active').dataset.category;
getPhotos();
}
var galleryPhotos;
function getPhotos(photos) {
$('.gallery__images').empty();
var mainCategory = currentMainCategory.trim().toLowerCase();
if( (currentSubCategory !== undefined) && (currentSubCategory !== '' ) ) {
var subCategory = currentSubCategory.trim().toLowerCase();
}
galleryPhotos = data.map(function(category) {
if( category.acf.gallery_section.toLowerCase() === mainCategory ) {
if( subCategory !== '' && subCategory !== undefined) {
var categoryTitle = category.acf.category_title.toLowerCase().trim();
if( categoryTitle === subCategory ) {
var galleryCategory = category.acf.gallery_items;
var categoryPhotos = galleryCategory.map(function(photo) {
var galleryPhoto = "<div class='gallery__item'><a class='lightbox-link' href=''><img class='full-width lightbox-target' src='" + photo.gallery_item_image.sizes.flexible + "' alt='" + photo.gallery_item_image.alt + "'></a></div>";
return galleryPhoto;
});
$('.gallery__images').append(categoryPhotos);
}
} else {
var galleryCategory = category.acf.gallery_items;
var categoryPhotos = galleryCategory.map(function(photo) {
var galleryPhoto = "<div class='gallery__item'><a class='lightbox-link' href=''><img class='full-width lightbox-target' src='" + photo.gallery_item_image.sizes.flexible + "' alt='" + photo.gallery_item_image.alt + "'></a></div>";
return galleryPhoto;
});
$('.gallery__images').append(categoryPhotos);
}
}
});
$('.sub-category').on('click', function() {
$('.sub-category').removeClass('active');
$(this).addClass('active');
setSubCategory();
});
checkOrientation();
handleLightboxUpdate();
}
});
});
function checkOrientation() {
document.querySelectorAll('.lightbox-target').forEach(function(item) {
var image = new Image();
image.src = item.src;
image.onload = function() {
if(image.naturalHeight >= image.naturalWidth) {
item.classList.add('portrait');
}
}
});
}
function initLightbox() {
var $overlay = jQuery('<div id="overlay"></div>');
var $container = jQuery('<div class="lightbox">×</div>');
var $image;
var $imageClone;
jQuery('body').append($overlay);
$overlay.click(function(){
$overlay.hide();
});
$overlay.append($container);
}
function handleLightboxUpdate() {
document.querySelectorAll('.lightbox-link').forEach( function(trigger) {
trigger.addEventListener('click', function() {
event.preventDefault();
jQuery('.lightbox-image').remove();
$image = jQuery(this).find('.lightbox-target');
$imageClone = $image.clone();
if($imageClone.hasClass('portrait')) {
$imageClone.addClass('resize-lightbox');
}
jQuery('#overlay').show();
//add image to overlay
$imageClone.addClass('lightbox-image').appendTo('#overlay .lightbox');
});
});
}
</script>
I'm not looking much into code, but I can tell you what's going on here. Page slows down with each 'subcategory' click, because you add more and more HTML nodes into the page until it's just too much. To be specific you add <div id="overlay">...</div> exponentially with every click.
is there a good way to test performance issues like this?
I suggest opening dev tools and see what's happening there. If adding more html wasn't the case, I'd look into potential problems with recursion or creating too many objects.
I figured it out! My setSubCategory() function was calling getPhotos() which was calling setSubCategory(), and so on and so forth.
Turns out it was a simple never-ending loop. Face-palm.
I have a site in development which uses ajax page loading. This all works as expected except when it comes to images.
If you visit the link below, you will see a page title "Brands" which has an svg icon followed by an img.
Now if you click "Brands" in the sidebar the page will fade out, fetch the same page via the .load method and then fade in the content. However you will notice in Chrome that the svg is seemingly missing. If you check in safari the svg is visible but the img is missing. If you check it in Firefox then you get the alt attribute displayed.
After inspecting the page you will notice that they have a height of 0px and a width of 0px.
Why is happening and how can I resolve it?
http://kga.creativelittledevs.co.uk/consultant/brands/
I did try an create a reduced test case but it wasnt very easy to replicate.
Here's my full ajax code:
Object.defineProperty(String.prototype, "decodeHTML", {
value: function () {
return $('<div>', {html: '' + this}).html();
}
});
var init = function() {
$('select').selectric({
arrowButtonMarkup:'<svg class="selectric__button"><use xlink:href="/images/icons.svg#icon-right-chevron"></use></svg>'
}, 'refresh');
},
ajaxLoad = function(html) {
document.title = html.match(/<title>(.*?)<\/title>/)[1].trim().decodeHTML();
init();
},
loadPage = function(href, get, put) {
$(put).fadeOut(200, function(){
$(put).load(href + ' ' + get, function(){
ajaxLoad;
$(put).fadeIn(200);
});
});
};
init();
$(window).on('popstate', function(e) {
var state = e.originalEvent.state;
if (state !== null) {
loadPage(location.href, state.get, state.put);
} else {
history.pushState({get: '.app-main > *', put: '.app-main'}, '', location.href);
}
});
kga.doc.on('click', '.js-ajax', function() {
var $this = $(this),
href = $this.attr('href'),
get = $this.data('ajax-get') ? $this.data('ajax-get') + ' > *' : '.app-main > *',
put = $this.data('ajax-put') ? $this.data('ajax-put') : '.app-main';
if (href.indexOf(document.domain) > -1 || href.indexOf(':') === -1) {
history.pushState({get: get, put: put}, '', href);
loadPage(href, get, put);
return false;
}
});
Any help would be very much appreciated, thanks.
I've created a modal service within my Angular app that I can inject into controllers or directives. I'm running into a problem where after opening/closing a modal multiple times, everything within the modal stops workings. The modal works by grabbing content from a hidden div on the page and popping it into the modal. I've been able to determine that at some point, the value of modal.settings changes. If I insert a debugger at the beginning of my modal.open function and save the value of var x = settings in my console, I can see that after a few cycles, x !== settings. I've also tried comparing modal.settings, but the same thing happens. Eventually, after a few cycles, modal.settings changes and things stop working.
I think I need to refactor this service, but I'm not sure where to start and could use some guidance.
Here is the service code:
app.service('modal', ['$compile', function($compile) {
var modal = this;
modal.settings;
modal.contents;
modal.overlay = $('<div id="overlay"></div>');
modal.modal = $('<div id="modal"></div>');
modal.content = $('<div id="content"></div>');
modal.closeBtn = $('<div id="close"><i class="fa fa-times"></div>');
modal.modal.hide();
modal.overlay.hide();
modal.modal.append(modal.content, modal.closeBtn);
$(document).ready(function(){
$('body').append(modal.overlay, modal.modal);
});
modal.open = function (settings) {
if(!modal.settings) {
modal.settings = settings;
}
modal.content.empty().append(modal.settings.content);
if(modal.settings.class) modal.modal.addClass(modal.settings.class);
if(modal.settings.height) modal.modal.css({ height: modal.settings.height });
if(modal.settings.width) modal.modal.css({ width: modal.settings.width });
if(modal.settings.content_height) modal.modal.css({ height: modal.settings.content_height });
if(modal.settings.content_width) modal.modal.css({ width: modal.settings.content_width });
if(modal.settings.fitToWindow) {
modal.settings.width = $(window).width() - 160;
modal.settings.height = $(window).height() - 160;
};
center(modal.settings.top);
$(window).bind('resize.modal', center);
modal.modal.show();
modal.overlay.show();
$(modal.closeBtn).add(modal.overlay).on('click', function(e) {
e.stopPropagation();
modal.close();
});
$(document).on('keyup', function(e) {
if (e.keyCode == 27) {
modal.close();
$(document).unbind('keyup');
}
})
};
modal.close = function() {
debugger;
modal.settings.elem.empty().append(modal.settings.content);
modal.modal.hide();
modal.overlay.hide();
modal.content.empty();
$(window).unbind('resize.modal');
};
function center(top) {
if(!top || !isInt(top)) top = 130;
var mLeft = -1 * modal.modal.width() / 2;
modal.modal.css({
top: top + 'px',
left: '50%',
marginLeft: mLeft
});
function isInt(n) {
return n % 1 === 0;
}
}
}]);
Here is how the modal is opened from the controller or directive:
modal.open({
content: $('#edit_story_' + story.id),
elem: $('#edit_story_' + story.id + '_container')
});
I also tried running my elem through the compiler first like so:
modal.open({
content: $compile($('#edit_story_' + story.id))($scope),
elem: $('#edit_story_' + story.id + '_container')
});
That solved my initial problem, but now after a few cycles my modal contents are duplicated. I get one form stacked upon another.
You shouldn't use DOM elements in controllers. A good idea would be implement a service following this approach or to make something like this. http://ionicframework.com/docs/api/service/$ionicModal/
I'm building on a WordPress theme and wants to load posts and pages with AJAX. I got that sorted out through the snippet below, but now I just need to suppress the function when clicking on the logo, obviously linking to the home url. So when clicking on the logo it should force a normal reload, instead of using the function.
I figure it would have something to do with "if hasClass(logo) then use default"... Yeah, I'm fairly new to JavaScript, but I have been searching a lot, so any help in the right direction will be much appreciated. Thanks!
The snippet:
$(".home li.home").removeClass("home").addClass("current_page_item");
var $wrapperAjax = $("#wrapper-ajax"),
URL = '',
siteURL = "http://" + top.location.host.toString(),
$internalLinks = $("a[href^='"+siteURL+"']"),
hash = window.location.hash,
$ajaxSpinner = $("#ajax-loader"),
$el, $allLinks = $("a");
function hashizeLinks() {
$("a[href^='"+siteURL+"']").each(function() {
$el = $(this);
if ($.browser.msie) {
$el.attr("href", "#/" + this.pathname)
.attr("rel", "internal");
} else {
$el.attr("href", "#" + this.pathname)
.attr("rel", "internal");
}
});
};
hashizeLinks();
$("a[rel='internal']").live("click", function() {
$ajaxSpinner.fadeIn();
$wrapperAjax.animate({ opacity: "0.1" });
$el = $(this);
$(".current_page_item").removeClass("current_page_item");
$allLinks.removeClass("current_link");
URL = $el.attr("href").substring(1);
URL = URL + " .entry";
$wrapperAjax.load(URL, function() {
$el.addClass("current_link").parent().addClass("current_page_item");
$ajaxSpinner.fadeOut();
$wrapperAjax.animate({ opacity: "1" });
hashizeLinks();
});
});
$("#searchform").submit(function(e) {
$ajaxSpinner.fadeIn();
$wrapperAjax.animate({ opacity: "0.1" });
$el = $(this);
$(".current_page_item").removeClass("current_page_item");
$allLinks.removeClass("current_link");
URL = "/?s=" + $("#s").val() + " .entry";
$wrapperAjax.load(URL, function() {
$ajaxSpinner.fadeOut();
$wrapperAjax.animate({ opacity: "1" });
hashizeLinks();
});
e.preventDefault();
});
if ((hash) && (hash != "#/")) {
$("a[href*='"+hash+"']").trigger("click");
}
I'm guessing you mean the script from this line: $("a[rel='internal']")
In that case, $("a[rel='internal']").not('.logo') should do the trick.
I should've read the entire code. Replace $("a[href^='"+siteURL+"']") with $("a[href^='"+siteURL+"']").not('.logo') as well.
If it has the class .logo you could add this at the top of the function:
if ($(this).hasClass('logo')) return true;
See the simple example.
I'm building a site for someone and on the Admin side there is a "Manage Users" page to manage the website's users. Here is my two functions to suspend and unsuspend (and for the alert):
var admin = {
alert: (function(msg,dur) {
if(!dur || dur == null) {
dur = 1500;
}
$('#alert_box2').remove();
$('body').append('<div id="alert_box2" style="width: 100%; height: 9px; top: -17px; left: 0; position: absolute; text-align: center; z-index: 5;"><div id="alert_box_inner2"></div></div>');
$('#alert_box2').show(0, function() {
if(dur!=='none') {
$('#alert_box_inner2').html(msg).stop(true, true).fadeIn(800).delay(dur).fadeOut(800, function() {
$('#alert_box2').remove();
});
}
else {
$('#alert_box_inner').html(msg).show();
}
});
}),
suspendUser: (function(id) {
admin.alert('Please wait...',20000);
$.get('user_more_actions.php?action=suspend&nolightbox=1&id='+id, function(data,textStatus) {
setTimeout(function() {
if(textStatus=='success') {
if(data.indexOf('suspended') > -1) {
name = data.replace('suspended ','');
admin.alert(name+' is now suspended.',2500);
$('#status_'+id).html('<strong style="color: red;">Suspended</strong>');
$('#suspend_'+id).attr('id','unsuspend_'+id).text('Unsuspend').removeClass('suspend').addClass('unsuspend');
}
else {
admin.alert('Sorry, there was an error. <span class="s_link" onclick="$(\'#suspend_'+id+'\').click();">Try again</a>','none');
}
}
else {
admin.alert('Sorry, there was an error. <span class="s_link" onclick="$(\'#suspend_'+id+'\').click();">Try again</a>','none');
}
}, 500);
});
}),
unsuspendUser: (function(id) {
admin.alert('Please wait...',20000);
$.get('user_more_actions.php?action=unsuspend&nolightbox=1&id='+id, function(data,textStatus) {
setTimeout(function() {
if(textStatus=='success') {
if(data.indexOf('unsuspended') > -1) {
name = data.replace('unsuspended ','');
admin.alert(name+' is no longer suspended.',2500);
$('#status_'+id).html('<strong style="color: green;">Active</strong>');
$('#unsuspend_'+id).attr('id','suspend_'+id).text('Suspend').removeClass('unsuspend').addClass('suspend');
}
else {
admin.alert('Sorry, there was an error. <span class="s_link" onclick="$(\'#unsuspend_'+id+'\').click();">Try again</a>',20000);
}
}
else {
admin.alert('Sorry, there was an error. <span class="s_link" onclick="$(\'#unsuspend_'+id+'\').click();">Try again</a>',20000);
}
}, 500);
});
})
};
And the code that triggers the functions when a Suspend or Unsuspend link is clicked:
$('.suspend').each(function() {
$(this).live('click', function(e) {
e.preventDefault();
var id = $(this).attr('id').replace('suspend_', '');
admin.suspendUser(id);
});
});
$('.unsuspend').each(function() {
$(this).live('click', function(e) {
e.preventDefault();
var id = $(this).attr('id').replace('unsuspend_', '');
admin.unsuspendUser(id);
});
});
Everything is working ok, except when I click again it messes up. When a Suspend link is clicked, it changes to Unsuspend (and changes the ID). But then if I click Unsuspend it doesn't work, and it is calling the admin.suspend() function instead of admin.unsuspend() (and the ID isn't being passed so the name isn't displayed):
When the class and the ID is changed it should call either the admin.suspend(id_here) or admin.unsuspend(id_here); but it isn't.
Does anyone know why this is happening? Thanks in advance and I'm sorry that this post is long.
I've fiddled with it. Hope this helps:http://jsfiddle.net/wKGKu/
Update: After reading your concerns for .each, I've updated the code to demonstrate it isn't needed: http://jsfiddle.net/wKGKu/2/
I believe the way you wrote your live bindings is incorrect, they should have been bound like this:
$('.suspend').live('click', function(e) {
e.preventDefault();
var id = $(this).attr('id').replace('suspend_', '');
admin.suspendUser(id);
});
$('.unsuspend').live('click', function(e) {
e.preventDefault();
var id = $(this).attr('id').replace('unsuspend_', '');
admin.unsuspendUser(id);
});
I simplified fiddle showing the working code at: jsFiddle
You are attaching events to suspend/unsuspend classes, but your AJAX callback is modifying id attribute. Also you are horribly misusing live(). In the end your handler is already attached to the link and doesn't change after your AJAX calls.
Solution is to
1) leave ID's alone - you are only confusing yourself by modifying them
2) rewrite event handler to either not do each() or not use live - put together completely defeats purpose behind live()
$('.suspend').live('click', function(){
var id = $(this).attr('id').replace('suspend_', '');
admin.suspendUser(id);
return false;
});
$('.unsuspend').live('click', function(e){
var id = $(this).attr('id').replace('suspend_', '');
admin.unsuspendUser(id);
return false;
});