I am trying to implement this grid, however I do not wish to use the Masonry plugin, so the article states I need to remove the initialisation, however I do not know how to do this.
The function is as follows...
_init : function() {
this.items = Array.prototype.slice.call( document.querySelectorAll( '#' + this.el.id + ' > div' ) );
this.itemsCount = this.items.length;
this.itemsRenderedCount = 0;
this.didScroll = false;
var self = this;
imagesLoaded( this.el, function() {
// initialize masonry
new Masonry( self.el, {
itemSelector: 'div',
transitionDuration : 0
} );
if( Modernizr.cssanimations ) {
// the items already shown...
self.items.forEach( function( el, i ) {
if( inViewport( el ) ) {
self._checkTotalRendered();
classie.add( el, 'shown' );
}
} );
// animate on scroll the items inside the viewport
window.addEventListener( 'scroll', function() {
self._onScrollFn();
}, false );
window.addEventListener( 'resize', function() {
self._resizeHandler();
}, false );
}
});
},
How can I successfully remove the initialisation of the masonry script?
How about removing the lines
// initialize masonry
new Masonry( self.el, {
itemSelector: 'div',
transitionDuration : 0
});
[edit] After removing the lines above and you need to make the following changes to your HTML:
<script src="js/EventEmitter.min.js"></script>
<!-- <script src="js/masonry.pkgd.min.js"></script> -->
Simply download and include EventEmitter.min.js from https://github.com/Wolfy87/EventEmitter.
Related
I am writing a JQuery plugin for a project I'm working on which turns from tabbed content on desktop devices to an accordion on mobile devices. I've used JQuery Boilerplate (https://github.com/jquery-boilerplate/jquery-boilerplate/blob/master/dist/jquery.boilerplate.js) as an initial pattern for my plugin.
The plugin is called on any element with the class ".tabs2accordion" as shown here:
$(".tabs2accordion").tabs2Accordion({state:"desktop"});
The plugin works as expected if there is only one element with ".tabs2accordion" class on a page but starts to malfunction as soon as another element with the same class is added to the page. I've created a codepen of the basic code to demo the issue. To show the issue, on a window size of >768px try clicking any of the titles and observe how the content below changes as each title is clicked. Next uncomment the block of HTML and try clicking on the titles again.
http://codepen.io/decodedcreative/pen/MyjpRj
I have tried looping through each element with the class "tabs2accordion" like this:
$(".tabs2accordion").each(function(){
$(this).tabs2Accordion({state:"desktop"});
});
But this didn't fix the issue either.
Any ideas?
I have not used jQuery Boilerplate, but I believe the problem here is with your variable called plugin.
Nowhere in your code do you declare a variable called plugin. When I stop the debugger in Plugin.prototype.showTabContent, I can evaluate window.plugin and it returns the global value for plugin.
In the constructor for Plugin, the first line reads plugin= this;. Since plugin is not defined, it is declaring the variable at global scope on the window object.
The fix is to pass a reference to the plugin object when setting up the $().on() hook. The data passed is available in the event handlers via the event parameter that is passed in the data property.
Here is the solution (at http://codepen.io/shhQuiet/pen/JXEjMV)
(function($, window, document, undefined) {
var pluginName = "tabs2Accordion",
defaults = {
menuSelector: ".tabs2accordion-menu",
tabContentSelector: ".tabs2accordion-content"
};
function Plugin(element, options) {
this.element = element;
this.$element = $(this.element);
this.options = $.extend({}, defaults, options);
this.$menu = $(this.element).find(this.options.menuSelector),
this.$tabs = $(this.element).find(this.options.tabContentSelector),
this.$accordionTriggers = $(this.element).find(this.$tabs).find("h3");
this._defaults = defaults;
this._name = pluginName;
this.init();
}
Plugin.prototype = {
init: function() {
//Set all the tab states to inactive
this.$tabs.attr("data-active", false);
//Set the first tab to active
this.$tabs.first().attr("data-active", true);
//If you click on a tab, show the corresponding content
this.$menu.on("click", "li", this, this.showTabContent);
//Set the dimensions (height) of the plugin
this.resizeTabs2Accordion({
data: this
});
//If the browser resizes, adjust the dimensions (height) of the plugin
$(window).on("resize", this, this.resizeTabs2Accordion);
//Add a loaded class to the plugin which will fade in the plugin's content
this.$element.addClass("loaded");
console.log(this.$element);
},
resizeTabs2Accordion: function(event) {
var contentHeight;
var plugin = event.data;
if (!plugin.$element.is("[data-nested-menu]")) {
contentHeight = plugin.$tabs.filter("[data-active='true']").outerHeight() + plugin.$menu.outerHeight();
} else {
contentHeight = plugin.$tabs.filter("[data-active='true']").outerHeight();
}
plugin.$element.outerHeight(contentHeight);
},
showTabContent: function(event) {
var $target;
var plugin = event.data;
plugin.$menu.children().find("a").filter("[data-active='true']").attr("data-active", false);
plugin.$tabs.filter("[data-active='true']").attr("data-active", false);
$target = $($(this).children("a").attr("href"));
$(this).children("a").attr("data-active", true);
$target.attr("data-active", true);
plugin.resizeTabs2Accordion({data: plugin});
return false;
},
showAccordionContent: function(event) {
var plugin = event.data;
$("[data-active-mobile]").not($(this).parent()).attr("data-active-mobile", false);
if ($(this).parent().attr("data-active-mobile") === "false") {
$(this).parent().attr("data-active-mobile", true);
} else {
$(this).parent().attr("data-active-mobile", false);
}
}
};
$.fn[pluginName] = function(options) {
return this.each(function() {
if (!$.data(this, "plugin_" + pluginName)) {
$.data(this, "plugin_" + pluginName, new Plugin(this, options));
}
});
};
})(jQuery, window, document);
$(window).on("load", function() {
$(".tabs2accordion").tabs2Accordion({
state: "desktop"
});
});
I rewrote your code following jQuery's Plugin creation standard.
http://codepen.io/justinledouxmusique/pen/GZrMgB
Basically, I did two things:
Moved away from using data attributes for styling (switched to using an .active class instead)
Moved away from using this everywhere, as it bring a whole wave of binding issues...
$.fn.tabs2Accordion loops through all the selectors, and applies $.tabs2Accordion. It also returns the selector for chaining (it's a standard in jQuery).
Then, all the internal methods are function expressions which are in the same scope as all your old this "variables". This simplifies the code greatly as you can refer to those variables without passing them in as a parameter or without having to .bind( this ) somehow.
Finally, the old init() function is gone. Instead, I put the code at the end of the $.tabs2Accordion function.
Hope this helps!
(function ( window, $ ) {
$.tabs2Accordion = function ( node, options ) {
var options = $.extend({}, {
menuSelector: '.tabs2accordion-menu',
tabContentSelector: '.tabs2accordion-content'
}, options )
var $element = $( node ),
$menu = $element.find( options.menuSelector ),
$tabs = $element.find( options.tabContentSelector ),
$accordionTriggers = $tabs.find( 'h3' )
var resizeTabs2Accordion = function () {
$element.outerHeight( !$element.is( '[data-nested-menu]' )
? $element.find( 'div.active' ).outerHeight() + $menu.outerHeight()
: $element.find( 'div.active' ).outerHeight() )
}
var showTabContent = function () {
var $this = $( this ) // This will be the clicked element
$menu
.find( '.active' )
.removeClass( 'active' )
$element
.find( '.active' )
.removeClass( 'active' )
$( $this.find( 'a' ).attr( 'href' ) )
.addClass( 'active' )
$this
.find( 'a' )
.addClass( 'active' )
resizeTabs2Accordion()
return false
}
var showAccordionContent = function () {
var $this = $( this ),
$parent = $this.parent(),
mobileIsActive = $parent.data( 'active-mobile' )
$( '[data-active-mobile]' )
.not( $parent )
.data( 'active-mobile', false )
$parent
.data( 'active-mobile', mobileIsActive ? false : true )
}
// The equivalent of init()
$tabs
.removeClass( 'active' )
.first()
.addClass( 'active' )
$element.addClass( 'loaded' )
$menu.on( 'click', 'li', showTabContent )
$( window ).on( 'resize', resizeTabs2Accordion )
resizeTabs2Accordion()
console.log( $element )
}
$.fn.tabs2Accordion = function ( options ) {
this.each( function ( index, node ) {
$.tabs2Accordion( node, options )
})
return this
}
})( window, jQuery )
$( window ).on( 'load', function () {
$( '.tabs2accordion' ).tabs2Accordion({
state: 'desktop'
})
})
I have a website that displays various floor plans in different categories and the filter and sort from Isotope is perfect for displaying them. I have it working just fine but what I would like to do is add onhashchange so when they click on a floor plan and go to that page and then go back to the original page they don't lose the previous filters and sorts they have applied.
My problem is I have code that I can get the onhashchange to work with the filter but not the sort and I lose my onpageload filter. On initial page load I only want those plans which I have tagged with a class of all to show (this is really important).
I have a fiddle of for each, this is the fiddle with the onhashchange working on the filter but not the sort and I can not seem to get the element-items with the class of all to be the only ones that load on page load https://jsfiddle.net/h8gv9gh6/
$(document).ready( function(){
// init Isotope
var $container = $('.isotope').isotope({
itemSelector: '.element-item',
layoutMode: 'fitRows',
getSortData: {
name: '.name',
symbol: '.symbol'
}
});
// bind sort button click
$('#sorts').on( 'click', 'button', function() {
var sortByValue = $(this).attr('data-sort-by');
$container.isotope({ sortBy: sortByValue });
});
// change is-checked class on buttons
$('.button-group').each( function( i, buttonGroup ) {
var $buttonGroup = $( buttonGroup );
$buttonGroup.on( 'click', 'button', function() {
$buttonGroup.find('.is-checked').removeClass('is-checked');
$( this ).addClass('is-checked');
});
});
});
// external js: isotope.pkgd.js
// filter functions
var filterFns = {
// show if number is greater than 50
numberGreaterThan50: function() {
var number = $(this).find('.number').text();
return parseInt( number, 10 ) > 50;
},
// show if name ends with -ium
ium: function() {
var name = $(this).find('.name').text();
return name.match( /ium$/ );
}
};
function getHashFilter() {
// get filter=filterName
var matches = location.hash.match( /filter=([^&]+)/i );
var hashFilter = matches && matches[1];
return hashFilter && decodeURIComponent( hashFilter );
}
$( function() {
var $grid = $('.grid');
// bind filter button click
var $filterButtonGroup = $('.filter-button-group');
$filterButtonGroup.on( 'click', 'button', function() {
var filterAttr = $( this ).attr('data-filter');
// set filter in hash
location.hash = 'filter=' + encodeURIComponent( filterAttr );
});
var isIsotopeInit = false;
function onHashchange() {
var hashFilter = getHashFilter();
if ( !hashFilter && isIsotopeInit ) {
return;
}
isIsotopeInit = true;
// filter isotope
$grid.isotope({
itemSelector: '.element-item',
layoutMode: 'fitRows',
// use filterFns
filter: filterFns[ hashFilter ] || hashFilter
});
// set selected class on button
if ( hashFilter ) {
$filterButtonGroup.find('.is-checked').removeClass('is-checked');
$filterButtonGroup.find('[data-filter="' + hashFilter + '"]').addClass('is-checked');
}
}
$(window).on( 'hashchange', onHashchange );
// trigger event handler to init Isotope
onHashchange();
});
Here is my other fiddle where the sort and filter work as well as my onpageload filter of all but I have no onhashchange: https://jsfiddle.net/0kgavwud/
$( document ).ready( function() {
// init Isotope
var $container = $('.isotope').isotope({
itemSelector: '.element-item',
layoutMode: 'fitRows',
getSortData: {
name: '.name',
symbol: '.symbol'
}
});
var PageLoadFilter = '.all';
$container.isotope({ filter: PageLoadFilter});
// filter functions
var filterFns = {
// show if number is greater than 50
numberGreaterThan50: function() {
var number = $(this).find('.number').text();
return parseInt( number, 10 ) > 50;
},
// show if name ends with -ium
ium: function() {
var name = $(this).find('.name').text();
return name.match( /ium$/ );
}
};
// bind filter button click
$('#filters').on( 'click', 'button', function() {
var filterValue = $( this ).attr('data-filter');
// use filterFn if matches value
filterValue = filterFns[ filterValue ] || filterValue;
$container.isotope({ filter: filterValue });
});
// bind sort button click
$('#sorts').on( 'click', 'button', function() {
var sortByValue = $(this).attr('data-sort-by');
$container.isotope({ sortBy: sortByValue });
});
// change is-checked class on buttons
$('.button-group').each( function( i, buttonGroup ) {
var $buttonGroup = $( buttonGroup );
$buttonGroup.on( 'click', 'button', function() {
$buttonGroup.find('.is-checked').removeClass('is-checked');
$( this ).addClass('is-checked');
});
});
});
Is there a way to to get onhashchange working with sort and an initial page load filter?
So there is some code from codepen.io http://codepen.io/karolpodlesny/pen/npKqu. It is uploaded here: http://fredricarms.com/javatestindex.html.
Now, the HTML, CSS and JavaScript for making the boxes expand and do all the cool things, are working how they are supposed to, being in separate files, so is the modernizr. I also the know that the js is being called because in the boxlayout.js I wrote some code to bring up and alert box and it worked just fine. So I am guessing that codepen fixes the code so it runs perfectly. I just don't know what is wrong with the code in the boxlayout.js that is not working on my server. Please help and thank you so much. Below is the code in the boxlayout js file.
var Boxlayout = (function() {
var $el = $( '#bl-main' ),
$sections = $el.children( 'section' ),
// works section
$sectionWork = $( '#bl-work-section' ),
// work items
$workItems = $( '#bl-work-items > li' ),
// work panels
$workPanelsContainer = $( '#bl-panel-work-items' ),
$workPanels = $workPanelsContainer.children( 'div' ),
totalWorkPanels = $workPanels.length,
// navigating the work panels
$nextWorkItem = $workPanelsContainer.find( 'nav > span.bl-next-work' ),
// if currently navigating the work items
isAnimating = false,
// close work panel trigger
$closeWorkItem = $workPanelsContainer.find( 'nav > span.bl-icon-close' ),
transEndEventNames = {
'WebkitTransition' : 'webkitTransitionEnd',
'MozTransition' : 'transitionend',
'OTransition' : 'oTransitionEnd',
'msTransition' : 'MSTransitionEnd',
'transition' : 'transitionend'
},
// transition end event name
transEndEventName = transEndEventNames[ Modernizr.prefixed( 'transition' ) ],
// support css transitions
supportTransitions = Modernizr.csstransitions;
function init() {
initEvents();
}
function initEvents() {
$sections.each( function() {
var $section = $( this );
// expand the clicked section and scale down the others
$section.on( 'click', function() {
if( !$section.data( 'open' ) ) {
$section.data( 'open', true ).addClass( 'bl-expand bl-expand-top' );
$el.addClass( 'bl-expand-item' );
}
} ).find( 'span.bl-icon-close' ).on( 'click', function() {
// close the expanded section and scale up the others
$section.data( 'open', false ).removeClass( 'bl-expand' ).on( transEndEventName, function( event ) {
if( !$( event.target ).is( 'section' ) ) return false;
$( this ).off( transEndEventName ).removeClass( 'bl-expand-top' );
} );
if( !supportTransitions ) {
$section.removeClass( 'bl-expand-top' );
}
$el.removeClass( 'bl-expand-item' );
return false;
} );
} );
// clicking on a work item: the current section scales down and the respective work panel slides up
$workItems.on( 'click', function( event ) {
// scale down main section
$sectionWork.addClass( 'bl-scale-down' );
// show panel for this work item
$workPanelsContainer.addClass( 'bl-panel-items-show' );
var $panel = $workPanelsContainer.find("[data-panel='" + $( this ).data( 'panel' ) + "']");
currentWorkPanel = $panel.index();
$panel.addClass( 'bl-show-work' );
return false;
} );
// navigating the work items: current work panel scales down and the next work panel slides up
$nextWorkItem.on( 'click', function( event ) {
if( isAnimating ) {
return false;
}
isAnimating = true;
var $currentPanel = $workPanels.eq( currentWorkPanel );
currentWorkPanel = currentWorkPanel < totalWorkPanels - 1 ? currentWorkPanel + 1 : 0;
var $nextPanel = $workPanels.eq( currentWorkPanel );
$currentPanel.removeClass( 'bl-show-work' ).addClass( 'bl-hide-current-work' ).on( transEndEventName, function( event ) {
if( !$( event.target ).is( 'div' ) ) return false;
$( this ).off( transEndEventName ).removeClass( 'bl-hide-current-work' );
isAnimating = false;
} );
if( !supportTransitions ) {
$currentPanel.removeClass( 'bl-hide-current-work' );
isAnimating = false;
}
$nextPanel.addClass( 'bl-show-work' );
return false;
} );
// clicking the work panels close button: the current work panel slides down and the section scales up again
$closeWorkItem.on( 'click', function( event ) {
// scale up main section
$sectionWork.removeClass( 'bl-scale-down' );
$workPanelsContainer.removeClass( 'bl-panel-items-show' );
$workPanels.eq( currentWorkPanel ).removeClass( 'bl-show-work' );
return false;
} );
}
return { init : init };
})();
Your code relies entirely on jQuery, however you haven't included jQuery on your live site. On your CodePen example you're using jQuery 1.9.1:
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js">
You can continue to use the Google-hosted version, or if you want to host it yourself you can download jQuery from jQuery's own website.
The problem is that you need to initialize your BoxLayout once your document has finished loading (all those jQuery variables you're using inside your library won't be defined because their equivalent dom elements are not yet rendered), that's why you need to init everything when dom is ready.
Add this line of code to the bottom of your boxlayout.js file:
$(document).ready(function() {
Boxlayout.init();
});
Just for testing purposes, open up the web developer console on your website, and run this js code:
Boxlayout.init();
You'll see everything will work just fine.
i currently have 1 editor that will always be on the page when it loads, the page has a feature to add multiple editors by clicking a add button.
my code works on the first editor only that is loaded with the page, how can i adapt this to work on all the editors on the page, even if dynamically created after the page has been loaded? (the dynamically created editors)
$(document).ready(function(){
$.each(CKEDITOR.instances, function(instance){
var editor = CKEDITOR.instances[instance];
if (editor) {
editor.on( 'focus', function( e ) {
$('.hint').show();
});
editor.on( 'blur', function( e ) {
$('.hint').hide();
});
}
});
});
eidt 1 - fullcode minus html
$(document).ready(function(){
$('textarea').each(function(i) {
var editorId = $(this).attr('id');
if(editorId != 'master'){
if( $(this).hasClass('main') ){
ckeditor_simple_toolbar(editorId);
}
if( $(this).hasClass('extras') ){
ckeditor_advanced_toolbar(editorId);
}
}
});
$.each(CKEDITOR.instances, function(instance){
var editor = CKEDITOR.instances[instance];
if (editor) {
editor.on( 'focus', function( e ) {
$('.hint').show();
});
editor.on( 'blur', function( e ) {
$('.hint').hide();
});
}
});
$('.add_extra').live('click',function(){
ckeditor_advanced_toolbar(this.id);
});
});
function ckeditor_simple_toolbar(textA_id){
CKEDITOR.replace(textA_id,{
tabSpaces : 4
});
}
function ckeditor_advanced_toolbar(textA_id){
CKEDITOR.replace(textA_id,{
emailProtection : 'encode',
tabSpaces : 4,
extraPlugins : 'autogrow',
height : 100,
autoGrow_minHeight : 100,
autoGrow_maxHeight : 400,
removePlugins : 'resize',
toolbarLocation : 'bottom',
});
}
edit 2
here is a test setup of what is happening, the focus and blur aren't working on the dynamically added editors
http://elhalawa.net/editor/index.html
just added the on instanceReady code and it worked great
CKEDITOR.replace(textA_id,{
emailProtection : 'encode',
tabSpaces : 4,
extraPlugins : 'autogrow',
height : 100,
autoGrow_minHeight : 100,
autoGrow_maxHeight : 400,
removePlugins : 'resize',
toolbarLocation : 'bottom',
}).on("instanceReady", function (e) {
this.on("focus", function () {
});
this.on("blur", function () {
});
this.on( 'change', function() {
});
});
I'm writing a jquery plugin to display a jquery ui dialog when links are clicked to provide a confirmation dialog before the link is followed.
The problem i'm having is that when closing the dialog using the "Yes" button, the plugin uses $(element).trigger( 'click' ); to fire the click event on the original anchor element.
This does not cause the browser to follow the link, however a second click with my mouse after the dialog closes does work.
The plugin is used like this $('a').submitConfirm();
Here is the plugin
;(function ( $, window, document, undefined )
{
var pluginName = "submitConfirm";
var Plugin = function( element )
{
var confirmed = false;
var dialog = $( '<div style="display:none;">' )
.html( 'Visit this link?' )
.dialog(
{
modal: true,
title: 'Visit Link?',
autoOpen: false,
buttons :
[
{
text: 'Yes',
click: function( event )
{
confirmed = true;
dialog.dialog( "close" );
$(element).trigger( 'click' );
}
},
{
text: 'No',
click: function( event )
{
confirmed = false;
dialog.dialog( "close" );
}
}
]
});
$(element).bind( 'click',
function( event )
{
if ( ! confirmed )
{
dialog.dialog( "open" );
event.preventDefault();
}
});
};
// Init the plugin
$.fn[pluginName] = function( options )
{
return this.each(function ()
{
// Prevent re-instantiation
if ( !$.data(this, 'plugin_' + pluginName) )
{
$.data(this, 'plugin_' + pluginName,
new Plugin( this, options ));
}
});
};
})( jQuery );
You have to pass a function containing what you want to do to the plugin.
Add this line when you are setting the default parameters for the plugin at the bottom of your javascript.
$(function()
{
$('a').submitConfirm(
{
html: 'Are you sure?',
onConfirm: function(event){ // Do what you want in this function.
alert('Confirmed.. Now what?.. Redirect?.. ?? ');
// window.location = $(this).attr('href'); // redirect
},
beforeShow: function( dialog )
{
dialog.html( 'visit google?' );
}
});
});
Update
Check out this JSfiddle --> http://jsfiddle.net/kmTtQ/6/
I changed the lines below. Basically, we want to add a .click event to the element, then .trigger('click') that click.
if ( confirmed ){
console.log( element, elementEvent, event.isDefaultPrevented );
// .on() = jQuery 1.7+, for < 1.7 use .bind or .live. Aliases of .on() as of 1.7
$(element).on('click', function(){ // bind our element with the click
event.view.window.location = element.href; // on click redirect
});
$(element).trigger( 'click' ); // We want to trigger the ^ click event ^
}