I'm trying to make a simple tumblr theme using the fluffy plugin (https://github.com/mzdr/fluffy.js) but I've ran into a problem. The plugin only executes once on page load. I'm trying to get it to work with the infinite scroll plugin (http://www.infinite-scroll.com/) and I need the fluffy plugin to trigger whenever new content loads.
I'm fairly new when it comes to JS so I appreciate any help I can get. Thanks.
Edit added code:
<script src="https://code.jquery.com/jquery-2.2.2.min.js"></script>
<script src="https://npmcdn.com/imagesloaded#4.1/imagesloaded.pkgd.min.js"></script>
<script src="http://static.tumblr.com/hpghjri/co2nfnr1j/infinitescroll.min.js"></script>
<script src="http://static.tumblr.com/nxwjyyg/XWUob8gtq/fluffy.min.js"></script>
<script>
$(function(){
app.initInfinite();
app.onImagesLoad();
}); //end document ready
var app = {
'initInfinite' : function() {
var $container = $('.page-index .posts');
$container.infinitescroll({
navSelector:".pagination",
nextSelector:".pagination-next",
itemSelector:".posts__container",
appendCallback:true,
loading:{
finishedMsg:" ",
img:"data:image/gif;base64,R0lGODlhAQABAHAAACH5BAUAAAAALAAAAAABAAEAAAICRAEAOw==",
msg:null,
msgText:" ",
selector:null,
finished:function() {
}
}
},
function(newElements) {
var $newElems = $(newElements).css({opacity:0});
var $newElemsIDs = $newElems.map(function() {
return this.id;
Tumblr.LikeButton.get_status_by_post_ids($newElemsIDs);
}).get();
$newElems.imagesLoaded(function() {
$newElems.animate({opacity: 1});
//what to do when new elems appended
// I need to trigger fluffy here
});
var $newElemsIDs = $newElems.map(function() {
return this.id;
}).get();
Tumblr.LikeButton.get_status_by_post_ids($newElemsIDs);
});
},
'onImagesLoad' : function() {
$('.content .posts').imagesLoaded()
.always( function( instance ) {
console.log('all images loaded');
$('.overlay').addClass('hide');
$('.overlay__preloader').attr('class', '');
})
.done( function( instance ) {
console.log('all images successfully loaded');
});
}
}
</script>
This is your lucky day! I just released v2.1.0 which fixes your problem. Now you can create Fluffy objects on the fly like that:
// Start automatic detection
Fluffy.detect();
// Or provide a DOM node for single creation
var myElement = document.querySelector('#what-ever-you-like');
Fluffy.create(myElement);
// Or use a selector to create one
Fluffy.create('[data-fluffy-container]');
Don't forget to check out the updated docs.
Related
I have a template I've deeply integrated with Meteor. It uses a scripts.js file that runs a bunch of commands after $(document).ready and $(window).load.
I put scripts.js inside of client/compatibility, and it works only if I do a hard refresh of the template. Otherwise, the template doesn't render and the functions don't execute.
Specifically, this code:
// Append .background-image-holder <img>'s as CSS backgrounds
$('.background-image-holder').each(function() {
var imgSrc = $(this).children('img').attr('src');
$(this).css('background', 'url("' + imgSrc + '")');
$(this).children('img').hide();
$(this).css('background-position', 'initial');
});
Much appreciated if you know how I should take it from here.
If you want a function to fire off when the DOM is loaded and all images, use this: (be forewarned, this is in ES6)
let imgCount;
let imgTally = 0;
Template.myTemplate.onRendered(function () {
this.autorun(() => {
if (this.subscriptionsReady()) {
Tracker.afterFlush(() => {
imgCount = this.$('img').length;
});
}
});
});
Template.myTemplate.events({
'load img': function (event, template) {
if (++imgTally >= imgCount) {
(template.view.template.imagesLoaded.bind(template))();
}
}
});
Then you just need to declare imagesLoaded which will get fired off when all images are done.
Template.myTemplate.imagesLoaded = function () {
// do something
};
Place this stuff in the onRendered function of the template.
Template.<name>.onRendered(function(){
//do your jquery business here!
});
For more info check the docs
I have been trying to add a jQuery plugin to Meteor but Meteor refuses to let the plugin work client side.
The example is I have this plugin that allows me to shuffle a bunch of divs around called jQuery Shuffle but when I call the following script in the head or from an external file it does not execute. It could be the plugin not publishing functions but it is client side so that makes no sense. I have verified that javascript and jQuery is working through a few console.log() command tests and those seem to work in external files or in the head wether they are inclosed in a jQuery function or not. Here is the code I am trying to use with jQuery Shuffle:
(do take note that this script also is using a few other plugins that appear not to be working either)
$(document).ready(function () {
var hash = window.location.hash.substr(1);
// Puts hash into search field
if (hash !== "") {
$("#search").val(hash);
$("#search").focus();
$('#search').keyup();
}
/* initialize shuffle plugin */
var $grid = $('#grid');
var $gridn = $('#gridn');
$grid.shuffle({
itemSelector: '.item',
group: 'alll'
});
$gridn.shuffle({
itemSelector: '.item',
group: 'news'
});
/* detects a news post */
if (hash.indexOf("news") > -1) {
$('#alll').removeClass('active');
$('#news').addClass('active');
$('#n-news').addClass('active');
$grid.shuffle('shuffle', 'news');
}
/* reshuffle when user clicks a filter item */
$('#filter a').click(function (e) {
e.preventDefault();
window.scrollTo(0, 0);
// set active class
$('#filter a').removeClass('active');
$(this).addClass('active');
// get group name from clicked item
var groupName = $(this).attr('data-group');
// reshuffle grid
$grid.shuffle('shuffle', groupName);
$gridn.shuffle('shuffle', groupName);
var n_catagories = ["n-v", "n-am", "n-av", "n-gd", "n-d", "comic", "blog"];
n_catagories.forEach(function (n_selectedcat) {
if ($("#" + n_selectedcat).hasClass("active")) {
$('#news').addClass('active');
//console.log(n_selectedcat)
}
});
});
// Sorting options
$('.select-options').on('change', function () {
var sort = this.value,
opts = {};
// We're given the element wrapped in jQuery
if (sort === 'date-created') {
opts = {
reverse: true,
by: function ($el) {
return $el.data('date-created');
}
};
} else if (sort === 'title') {
opts = {
by: function ($el) {
return $el.data('title').toLowerCase();
}
};
}
// Filter elements
$grid.shuffle('sort', opts);
});
// Advanced filtering
$('.search').on('keyup change', function () {
var val = this.value.toLowerCase();
window.scrollTo(0, 0);
$grid.shuffle('shuffle', function ($el, shuffle) {
// Only search elements in the current group
if (shuffle.group !== 'all' && $.inArray(shuffle.group, $el.data('groups')) === -1) {
return false;
}
var text = $.trim($el.find('.item-tags').text()).toLowerCase() + $.trim($el.find('.hidden').text()).toLowerCase();
return text.indexOf(val) !== -1;
});
$gridn.shuffle('shuffle', function ($el, shuffle) {
// Only search elements in the current group
if (shuffle.group !== 'all' && $.inArray(shuffle.group, $el.data('groups')) === -1) {
return false;
}
var text = $.trim($el.find('.item-tags').text()).toLowerCase() + $.trim($el.find('.hidden').text()).toLowerCase();
return text.indexOf(val) !== -1;
});
});
//REMOVE AND HIDE HANDELER
var $nnitems = $('.nnotice');
$(".nnotice-button").click(function () {
Cookies.set('hidennotice', 'true', {
expires: 31557600
});
});
if (Cookies.get('hidennotice') == 'true') {
$grid.shuffle('remove', $nnitems);
}
$(".nnotice").click(function () {
$grid.shuffle('remove', $nnitems);
});
//Auto Shuffle
$(".social-toggle").click(function () {
$(".social-stuffs").slideToggle("slow");
setTimeout(function () {
var catagories = ["alll", "v", "am", "av", "gd", "d", "news", "n-v", "n-am", "n-av", "n-gd", "n-d", "comic", "blog"];
catagories.forEach(function (selectedcat) {
if ($("#" + selectedcat).hasClass("active")) {
$grid.shuffle('shuffle', selectedcat);
}
});
}, 1000);
});
});
When not enclosed in Meteor, this script works as expected.
I have tried loading the JS files for the plugins by calling them normally through <script type="text/javascript" src="directory/somescript.js"></script> and by loading the scripts through the /client directory meteor uses to process files that are going to the client. It automatically loads these files in a <script> when put here. Even with Meteor loading them it seems not to work. I don't know if it is because the functions inside the plugins need to be published or if it is just no possible to use these kinds of plugins/apis with Meteor.
This is a working, unfinished version of the site without Meteor (and that has missing files and an unfinished color scheme)
Edit:
Basically I just need to be able to load a jQuery plugin somehow and then load the script to control it. That is what I am having trouble doing.
Using plugins like query could be a little tricky on meteor, example you are using
$(document).ready(function () {});
And its ok but i prefer to work with
Meteor.startup(function () {
});
Reference here Stack Question about onReady and Startup
Also some people prefer to use the Template.myTemplate.rendered ) function(){}
and its works (on my case works), and also try to use some Timeouts
You are not getting anything errors on the console, because nothings wrong happens all DOM elements were created, i face this problems many times using Carrousels, dynamic list from codrops etc.
If you have your web/project on some github repo or working in some cloud host Service like nitrous.io i could help you
Safest way is to deliver the plugin as a package and initialise it in template.rendered
I had this problem with a jquery plugin.
My html code was:
<head>
<meta charset="utf-8">
<!-- Plugin JQuery -->
<script src="js/jquery.easing.min.js"></script>
</head>
<body>
{{main}}
</body>
Then I put the script after {{main}} template and it works. The script is loaded after all javascript meteor packages:
<head>
<meta charset="utf-8">
</head>
<body>
{{main}}
<!-- Plugin JQuery -->
<script src="js/jquery.easing.min.js"></script>
</body>
In my plug-in I need to wrapp all sidebar's children in a div to let them overflow but if those elements are loaded dynamically the function does not work and I don't know either how to make it work.
The code is:
<div class="sidebar">
</div>
var $sidebar = $( '.sidebar' );
$sidebar.load( 'external-page.ext' );
$sidebar.MyPlugin();
$.fn.MyPlugin = function() {
this.wrapInner( '<div />' );
});
If those elements are not loaded dynamically there is no problem.
Firstly the code was:
$sidebar.wrapInner( '<div/>' );
and this just works fine if elemens are not loaded dynamically, so I tried this way:
var children = $sidebar.children();
$( document ).on( 'load', children, function() {
$( this ).wrapAll( '<div />' );
});
but, of course it does not work.
Can you please help me?
I thought that this rule would have worked this time too but it didn't. What did I mistake?
You can find the whole code here.
And a demo here
MORE DETAILS
I want to handle this issue from the inside, not from the outside! I don't know if users will load content dinamically or not. that's the point.
So there is a way to handle this issue inside the plugin and not outside?
From the manual
http://api.jquery.com/load/
Callback Function
If a "complete" callback is provided, it is executed after
post-processing and HTML insertion has been performed. The callback is
fired once for each element in the jQuery collection, and this is set
to each DOM element in turn.
Try the following code and see if this works:
$sidebar.load( 'external-page.ext', function() { $sidebar.MyPlugin(); } );
Thanks.
$.load() makes an ajax call to load the data ,
So there is a possibility that your this.wrapInner( '<div />' ) method has invoked before any data is loaded inside the div.sidebar.
Make sure this.wrapInner( '<div />' ) is called after all data has been loaded successfully using the complete callback.
$.load() trigger callback for each div ,call your plugin from callback
$sidebar.load('http://fiddle.jshell.net/vikrant47/ncagab2y/1/show/', function () {
$(this).MyPlugin();
}
});
DEMO
OR
If you are using $.load() only to load inside multiple elements then you could probably use one of the more powerful jQuery ajax methods (i.e., get() or post() or ajax()).
$.get('http://fiddle.jshell.net/vikrant47/ncagab2y/1/show/', {}, function(data) {
$sidebar.html(data).MyPlugin();
});
DEMO using $.get() Method
UPDATE-
Answer to the comment-
You should not have to worry about weather user gonna call your plugin like this $sidebar.load(...).MyPlugin().User must be aware enough about how to handle asynchronous methods.
You can not make your plugin work until there is some data inside div.slider
but ,you can add ajax loading functionality inside your plugin like -
$(document).ready(function () {
$.fn.MyPlugin = function (options) {
var $elem=this;
var init = function () {
options.load = $.extend({}, $.fn.MyPlugin.defaultOptions.load, options.load);
load();
}
//adding load method to load data dynamically
var load = function () {
if (!options.load.url) {
alert("url can not be empty");
} else {
$.ajax({
url: options.load.url,
type: options.load.type,
data: options.load.data,
success: function (response) {
options.load.success.call(this, response);
$elem.html(response).wrapInner('<div class="wrapper"/>');//wrap after data has been loaded successfully
},
error : function (jqXHR, textStatus, errorThrown) {
alert("error occured" + textStatus + " ," + errorThrown)
}
})
}
}
init();
}
$.fn.MyPlugin.defaultOptions = {
load: {
tye: "get",
data: {},
success: function () {}
}
};
Now use your plugin like-
var $sidebar = $('.sidebar');
$sidebar.MyPlugin({
load: {
url: 'http://fiddle.jshell.net/vikrant47/ncagab2y/1/show/'
}
});
});
DEMO with load
Try adding adding below piece to plugin . Added at lines 84 - 110 at gist .
var target = $sidebar.get(0);
// create an observer instance
var observer = new MutationObserver(function (mutations) {
mutations.forEach(function (mutation) {
// do stuff when
// `childList` modified
// i.e.g.,
$.each(mutation.addedNodes, function (k, v) {
$(v)
.wrapInner('<div data-'
+ dataName
+ '="sub-wrapper"></div>')
})
});
});
// configuration of the observer:
var _config = {
childList: true
};
// pass in the target node, as well as the observer options
observer.observe(target, _config);
jsfiddle http://jsfiddle.net/guest271314/s5wzptc8/
See MutationObserver
I'm using jquery 1.9.1 and I'm trying to develop a plugin. The problem is that the plugin isn't working. Here's the code:
;(function($) {
$.fn.single = function() {
return this.each(function(){
// Get the instance
var element = $(this);
// Resize the "data-target" divs
element.load(function(){
changeCSS(element);
});
// Bind the method to the resize window event
$(window).bind("resize", function(){
changeCSS(element);
});
});
};
// function to resize all the "data-target" divs
function changeCSS(element) {
// Grab the screen resolution
var windowWidth = $(window).width();
var windowHeight = $(window).height();
// Count how many targets the div has
var targetsSize = $("[data-target]").size();
// Resize the parent div
$(element).css({
"width" : windowWidth,
"height": windowHeight * targetsSize
});
// Resize all the targets div
$(element + "> div[data-target]").each(function(){
$(this).css({
"width" : windowWidth,
"height": windowHeight
});
});
}
})(jQuery);
And I'm calling it on the document like that:
<script src="js/jquery-1.9.1.min.js"></script>
<script src="js/single-0.1.0.js"></script>
<script type="text/javascript">
$(document).ready(function(){
$("#single").single();
});
</script>
There's no problem in the console. What I'm doing wrong?
I'm assuming that it is because you are misusing the method .load. If you look at the jQuery docs, it is intended for:
.load() : Load data from the server and place the returned HTML
into the matched element.
http://api.jquery.com/load/
Remove the lines element.load(function ..., simply call your changeCSS function, you're already loading this extension on Document.Ready
return this.each(function () {
// ...
changeCSS(element); // <-- just run the function right away
// ... etc
});
Generally it is bad practice to call a function before it is declared. To get your plugin right, you will be better of starting structuring it correctly from the beginning. Besides that, as #mcpDESIGNS point out, you are using the .load method wrongly. Also, it would be useful if you explain what exactly it is you are trying to accomplice here.
To get a good start making jQuery plugins, try to look at the documentation at jQuery here or you can look at this tutorial.
This is the preferred structure:
(function($) {
// Declare your methods at the beginning of your plugin
var yourMethods = {
'methodOne' : function() {
},
'methodTwo' : function() {
}
};
$.fn.pluginName = function() {
return this.each(function() {
});
}
}(jQuery));
Instead of:
element.load(function(){
changeCSS(element);
});
I did:
changeCSS(element);
And... Instead of:
$(element + "> div[data-target]")
I did:
$(element).children('div[data-target]')
And now the plugin is being executed with no bugs or errors.
Thanks Guys!
I have the following function which is for ajaxing in a page and the showing it only once all the images are loaded:
$.get('target-page.php', function(data){
var $live = $('#preview_temp_holder').html(data);
var imgCount = $live.find('img').length;
$('img',$live).load(function(){
imgCount--;
if (imgCount==0){
//DO STUFF HERE ONCE ALL IMAGES ARE LOADED
$('#preview_pane').html($live.children()).fadeIn(800);
$live.children().remove();
}
});
});
The problem comes with cached images not firing the .load() event and thus not decrementing the imgCount.
I know i need to implement Nick Craver's solution but am not sure how. Can anyone help me?
I spent a long time looking for solutions for this. The plugin suggested on the jQuery API page (https://github.com/peol/jquery.imgloaded/raw/master/ahpi.imgload.js) did not work in firefox.
My solution was to loop through each image and only add the load event if it was not already loaded (i.e. cached by the browser). The code below includes a counter that I was using to check that load events were only firing for images not already in the cache:
$(document).ready(function () {
var images = $("img.lazy");
$(".image-wrapper").addClass("loading");
var loadedCount = 0;
images
.hide()
.each(function () {
if (!this.complete) {
$(this).load(function () {
loadedCount++;
console.log(loadedCount);
displayImage(this);
});
}
else {
displayImage(this);
}
});
});
function displayImage(img) {
$(img).fadeIn(300, function () {
$(this).parents(".image_wrapper").removeClass("loading");
});
}
I'm no javascript expert so if you spot any problems with this solution please do let me know. As I say, it works in IE8, Chrome and Firefox (not sure about older versions of IE).
Ok, managed to get them merged:
$.get('target-page.php', function(data){
var $live = $('#preview_temp_holder').html(data);
var $imgs = $live.find('img')
var imgCount = $imgs.length;
$imgs.one('load', function() {
imgCount--;
if (imgCount==0){
//DO STUFF HERE
//ALL IMAGES ARE LOADED
$('#preview_pane').html($live.children()).fadeIn(800);
}
})
.each(function() {
if(this.complete){
$(this).load();
}
});
});
note: a 404-ing image would break this.
Change:
$('img',$live).one('load', function(){
...
});
And after above append:
$live.find('img').each(function() {
if(this.complete) $(this).load();
});
Generally I suggest to reuse $live.find('img') from previous count statement.