I am loading content in the magnific popup using the iframe method.
It works just fine, except that it take awhile to load the iframe content. Until the content is loaded the iframe is just a blank dark and empty popup and the user has no clue as to what is happening.
Is there a way to make the iframe show a loading message or animation until the content arrives?
The .mfp-preloader css class is of no help because it is hidden behind the iframe.
I'm thinking the best was is to somehow hide the iframe until it has content.
Thanks
Thanks to Dmitry who pointed me in the right direction, here is the answer that worked for me:
The callback:
callbacks: {
beforeAppend: showIframeLoading
}
The showIframeLoading function:
var showIframeLoading = function() {
var curLength = 0;
var interval = setInterval(function() {
if ($('iframe').length !== curLength) {
curLength = $('.column-header').length;
$('.mfp-content').hide();
$('.mfp-preloader').show();
}
}, 50);
this.content.find('iframe').on('load', function() {
clearInterval(interval);
$('.mfp-content').show();
$('.mfp-preloader').hide();
});
};
You may use popup events to create custom actions, e.g.:
callbacks: {
beforeAppend: function() {
console.log('before iframe is added to DOM');
this.content.find('iframe').on('load', function() {
console.log('iframe loaded');
});
}
}
Instead of polling, how about if we just detect iframe and toggle the mfp-s-ready class from the container.
In case of images, mfp-s-ready is added to the mfp-container div when image has loaded. We can simply toggle that ourself for video (iframe) + use some custom css to our advantage.
callbacks: {
beforeAppend: function () {
if (this.currItem.type === 'iframe') {
$('.mfp-container').removeClass('mfp-s-ready');
}
this.content.find('iframe').on('load', function () {
$('.mfp-container').addClass('mfp-s-ready');
});
}
}
and add this CSS:
.mfp-container .mfp-content {
display: none;
}
.mfp-s-ready.mfp-container .mfp-content {
display: inline-block;
}
This will also support mixmode galleries with videos and images.
Related
I'm trying to add links in my navbar that go to a section of page using Vuetifys scrolling, here's my code:
pageClicked (page) {
this.goToPage(page.path)
this.goToTarget(page, this.options)
},
goToPage (path) {
this.$router.push(path)
},
goToTarget (target, options) {
if (target.topOfPage) {
this.$vuetify.goTo(0, options)
} else if (target.id) {
this.$vuetify.goTo(target.id, options)
}
}
Problem is the scroll fails if I'm not on the same page that where I'm scrolling to is on cause it can't find the target id because it hasn't loaded yet. How can I ensure the page has fully loaded before trying to scroll to the section?
I'm using ui bootstrap v0.10 in my angular project. When I try to use the modal window, I can setup the width to a smaller size using the windowClass, however it changes also throws the window position to most right.
Can anyone help me?
the code that I'm using to try changing the width is as follows:
$stateProvider.state("signin", {
url: "/signin",
onEnter: function ($stateParams, $state, $modal) {
$modal.open({
templateUrl: 'Pages/Modals/Signin.html',
windowClass: 'fs-login-modal',
controller: ['$scope', function ($scope) {
$scope.dismiss = function () {
$scope.$dismiss();
};
}]
}).result.then(function (result) {
if (result) {
return $state.transitionTo("/");
}
});
}
});
My css class is setup as follows:
login-modal {
width:270px;
}
Best regards,
Chen
If memory serves me right, add a negative margin-left of half the width.
.login-modal {
width:270px;
margin-left: -135px;
}
I remember it being a bit more complicated, maybe dealing with a .modal-inner class or something, but this should get you on the right track.
I have a meteor app with multiple pages. I want to be able to deeplink to an anchor somewhere halfway the page.
Traditionally, in normal html, you'd make an somewhere in your page, and link to it via /mypage.html#chapter5.
If I do this, my meteor app won't scroll down to that spot.
What is the best approach around this?
#Akshat 's answer works for on the same page, but what if you want to be able to pass around a url w/ a "#" in it? I did it how the meteor docs did.
Template.myTemplate.rendered = function() {
var hash = document.location.hash.substr(1);
if (hash && !Template.myTemplate.scrolled) {
var scroller = function() {
return $("html, body").stop();
};
Meteor.setTimeout(function() {
var elem = $('#'+hash);
if (elem.length) {
scroller().scrollTop(elem.offset().top);
// Guard against scrolling again w/ reactive changes
Template.myTemplate.scrolled = true;
}
},
0);
}
};
Template.myTemplate.destroyed = function() {
delete Template.myTemplate.scrolled;
};
Stolen from the source to the meteor docs.
Are you using some kind of javascript router? Meteor Router?
You could use something like a javascript based scrolling method. One such example is with JQuery: (You can place this in your link/buttons click handler)
Template.hello.events({
'click #theitemtoclick':function(e,tmpl) {
e.preventDefault();
$('html, body').animate({
scrollTop: $("#item_id").offset().top
}, 600);
}
});
Then tag your html item where you would put your anchor with the id:
<h1 id="item_id">Section X</h1>
Currently, there's an issue in IronRouter where the hash is removed from the url. This is discussed here and here. Fortunately there is a fix even though it doesn't appear to be in the stable version.
My Iron Router solution with traditional anchor tags:
1) Apply the IronRouter fix above
2)
Router.configure({
...
after: function () {
Session.set('hash', this.params.hash);
},
...
});
3)
function anchorScroll () {
Deps.autorun(function (){
var hash = Session.get('hash');
if (hash) {
var offset = $('a[name="'+hash+'"]').offset();
if (offset){
$('html, body').animate({scrollTop: offset.top},400);
}
}
Session.set('hash', '');
});
}
Template.MYTEMPLATE.rendered = function (){
anchorScroll();
};
Unfortunately this has to be set in each template's .rendered() otherwise the anchor tag is not guaranteed to be in the DOM.
For better or worse this will scroll again with a code push.
Mike's Answer didn't quite work for me. The hash was returning empty in the onRendered callback. I nested the code in an additional Meteor.setTimeout
fyi I'm using Blaze.
Below worked like a charm :)
Template.myTemplate.onRendered(function() {
Meteor.setTimeout(function(){
var hash = document.location.hash.substr(1);
if (hash && !Template.myTemplate.scrolled) {
var scroller = function() {
return $("html, body").stop();
};
Meteor.setTimeout(function() {
var elem = $("a[name='" + hash + "']");
if (elem.length) {
scroller().scrollTop(elem.offset().top);
// Guard against scrolling again w/ reactive changes
Template.myTemplate.scrolled = true;
}
},
0);
}
},0);
});
Template.myTemplate.destroyed = function() {
delete Template.myTemplate.scrolled;
};
I have a div which is placed in any pages. When you click on this div, it will be closed by using jquery checking on its css class:
$('.content-box-header').click(function
() {
$(this).parent().children('.content-box-content').slideFadeToggle(200);
}
In several pages, I need to set that div with a specific ID in order to perform some tasks after that div closed. For example:
$('#divleft').live('click', function
(e) { runTask(); }
The above sample is trigger on that div with the specific ID = divleft.
The problem is that, I would like to check something ONLY after the div is really closed, but in my current situation, runTask() is performed before the div is closed.
SO my question is that how could the method runTask(); is delayed after the div is really closed?
Thanks in advance!!!!
I think what you are looking for is .queue(). See the documentation here: http://api.jquery.com/queue/
You can call this on a set of matched elements to get some information about the remaining effects to be run. So in your case you could do something like this:
$('#divleft').live('click', function (e) {
runTaskAfterAnimation()
});
function runTaskAfterAnimation() {
if ($('.content-box-content').queue('fx').length == 0) {
runTask();
} else {
setTimeout(runTaskAfterAnimation, 10);
}
}
View a demonstration here: http://jsfiddle.net/LeHHj/2/
This time it definitely works ;)
In your case, just use
$('.content-box-header').click(function () { $(this).parent().children('.content-box-content').slideFadeToggle(200, function() { runTask(); }); }
You can store the function on the div using jQuery's data() method.
This lets you set an 'afterClick' function on your element:
$('.content-box-header').click(function () {
var $this = $(this);
$this.parent().children('.content-box-content').slideUp(200, function () {
var after = $this.data('afterClick');
if (after) after();
});
});
$('#divleft').data('afterClick', function () { runTask(); });
You need to check if the item you are wanting to runTask() on is :animated and if so 'register' a callback (via .data()) for when it's done
.live('click', doRunTask);
doRuntask = function() {
if ($(this).is(':animated'))
$(this).data('afterAnimation', runTask);
else
runTask();
});
$('.content-box-header').click(function () {
$(this).parent().children('.content-box-content').slideFadeToggle(200, function() {
var cb = $(this).data('afterAnimation');
cb && cb();
});
}
I have made an custom collapsible fieldset control in asp.net. I use jquery to add the toggle effects. The control works perfectly but when i am using my fieldsets inside an updatepanel, afer a postback i loose my jquery logic because of the document.ready.
Now i have read about the new Live() function of Jquery but i don't get it working. What do i do wrong? Has someone the answer??
Thanks a lot
My Jquery code is:
$(document).ready(function() {
$.fn.collapse = function(options) {
var defaults = { closed: false }
settings = $.extend({}, defaults, options);
return this.each(function() {
var obj = $(this);
obj.find("legend").addClass('SmartFieldSetCollapsible').live("click", function() {
if (obj.hasClass('collapsed')) {
obj.removeClass('collapsed').addClass('SmartFieldSetCollapsible'); }
$(this).removeClass('collapsed');
obj.children().next().toggle("slow", function() {
if ($(this).is(":visible")) {
obj.find("legend").addClass('SmartFieldSetCollapsible');
obj.removeAttr("style");
obj.css({ padding: '10px' });
obj.find(".imgCollapse").css({ display: 'none' });
obj.find(".imgExpand").css({ display: 'inline' });
}
else {
obj.css({ borderLeftColor: 'transparent', borderRightColor: 'transparent', borderBottomColor: 'transparent', borderWidth: '1px 0px 0px 0px', paddingBottom: '0px' });
obj.find(".imgExpand").css({ display: 'none' });
obj.find(".imgCollapse").css({ display: 'inline' });
}
});
});
if (settings.closed) {
obj.addClass('collapsed').find("legend").addClass('collapsed');
obj.children().filter("p,img,table,ul,div,span,h1,h2,h3,h4,h5").css('display', 'none');
}
});
};
});
$(document).ready(function() {
$("fieldset.SmartFieldSetCollapsible").collapse();
});
The problem is that you are doing more then just a plain selector for your live selection
From api.jquery.com
"DOM traversal methods are not fully supported for finding elements to send to .live(). Rather, the .live() method should always be called directly after a selecton"
if (obj.hasClass('collapsed')) {
obj.removeClass('collapsed').addClass('SmartFieldSetCollapsible'); }
$(this).removeClass('collapsed');
First you want to remove the class an add another class if it has the class collapsed, an then you remove the class collapsed. I don't know if it affects the working of the system but it is worth to try.
Does the function work if you just use .click (when the field aren't updated)?
Traversing is the issue. You can solve it with a simple selection.
var obj = $(this),
obj.find("legend").addClass('SmartFieldSetCollapsible');
$('legend.SmartFieldSetCollapsible').live('click.collapsible', function(e){