297 lines
13 KiB
JavaScript
Executable File
297 lines
13 KiB
JavaScript
Executable File
|
|
/* ===================================================
|
|
* jqueryCenterImages.js v1.0.0
|
|
* ===================================================
|
|
* (c) 2015 Nicolas Guillaume, Nice, France
|
|
* CenterImages plugin may be freely distributed under the terms of the GNU GPL v2.0 or later license.
|
|
*
|
|
* License URI: http://www.gnu.org/licenses/gpl-2.0.html
|
|
*
|
|
* Center images in a specified container
|
|
*
|
|
* =================================================== */
|
|
(function ( $, window ) {
|
|
//defaults
|
|
var pluginName = 'centerImages',
|
|
defaults = {
|
|
enableCentering : true,
|
|
onresize : true,
|
|
onInit : true,//<= shall we smartload on init or wait for a custom event, typically smartload ?
|
|
oncustom : [],//list of event here
|
|
$containerToListen : null,//<= we might want to listen to custom event trigger to a parent container.Should be a jQuery obj
|
|
imgSel : 'img',
|
|
defaultCSSVal : { width : 'auto' , height : 'auto' },
|
|
leftAdjust : 0,
|
|
zeroLeftAdjust : 0,
|
|
topAdjust : 0,
|
|
zeroTopAdjust : -2,//<= top ajustement for h-centered
|
|
enableGoldenRatio : false,
|
|
goldenRatioLimitHeightTo : 350,
|
|
goldenRatioVal : 1.618,
|
|
skipGoldenRatioClasses : ['no-gold-ratio'],
|
|
disableGRUnder : 767,//in pixels
|
|
useImgAttr:false,//uses the img height and width attributes if not visible (typically used for the customizr slider hidden images)
|
|
setOpacityWhenCentered : false,//this can be used to hide the image during the time it is centered
|
|
addCenteredClassWithDelay : 0,//<= a small delay can be required when we rely on the v-centered or h-centered css classes to set the opacity for example
|
|
opacity : 1
|
|
};
|
|
|
|
function Plugin( element, options ) {
|
|
var self = this;
|
|
this.container = element;
|
|
this.options = $.extend( {}, defaults, options) ;
|
|
this._defaults = defaults;
|
|
this._name = pluginName;
|
|
this._customEvt = _.isArray(self.options.oncustom) ? self.options.oncustom : self.options.oncustom.split(' ');
|
|
this.init();
|
|
}
|
|
|
|
//can access this.element and this.option
|
|
//@return void
|
|
Plugin.prototype.init = function () {
|
|
var self = this,
|
|
_do = function( _event_ ) {
|
|
_event_ = _event_ || 'init';
|
|
//applies golden ratio to all containers ( even if there are no images in container )
|
|
self._maybe_apply_golden_r();
|
|
|
|
//parses imgs ( if any ) in current container
|
|
var $_imgs = $( self.options.imgSel , self.container );
|
|
|
|
//WINDOW RESIZE EVENT ACTIONS
|
|
//GOLDEN RATIO (before image centering)
|
|
//creates a golden ratio fn on resize
|
|
if ( self.options.enableGoldenRatio ) {
|
|
$(window).on(
|
|
'resize',
|
|
{},
|
|
_.debounce( function( evt ) { self._maybe_apply_golden_r( evt ); }, 200 )
|
|
);
|
|
}
|
|
|
|
|
|
//if no images or centering is not active, only handle the golden ratio on resize event
|
|
if ( 1 <= $_imgs.length && self.options.enableCentering ) {
|
|
self._parse_imgs( $_imgs, _event_ );
|
|
}
|
|
};
|
|
|
|
//fire
|
|
if ( self.options.onInit ) {
|
|
_do();
|
|
}
|
|
|
|
//console.log('$( self.container )', $( self.container ) );
|
|
//bind the container element with custom events if any
|
|
//( the images will also be bound )
|
|
if ( _.isArray( self._customEvt ) ) {
|
|
self._customEvt.map( function( evt ) {
|
|
var $_containerToListen = ( self.options.$containerToListen instanceof $ && 1 < self.options.$containerToListen.length ) ? self.options.$containerToListen : $( self.container );
|
|
//console.log('container to listen',$_containerToListen, evt );
|
|
$_containerToListen.on( evt, {} , function() {
|
|
_do( evt );
|
|
});
|
|
} );
|
|
}
|
|
};
|
|
|
|
|
|
//@return void
|
|
Plugin.prototype._maybe_apply_golden_r = function() {
|
|
//check if options are valids
|
|
if ( ! this.options.enableGoldenRatio || ! this.options.goldenRatioVal || 0 === this.options.goldenRatioVal )
|
|
return;
|
|
|
|
//make sure the container has not a forbidden class
|
|
if ( ! this._is_selector_allowed() )
|
|
return;
|
|
//check if golden ratio can be applied under custom window width
|
|
if ( ! this._is_window_width_allowed() ) {
|
|
//reset inline style for the container
|
|
$(this.container).attr('style' , '');
|
|
return;
|
|
}
|
|
|
|
var new_height = Math.round( $(this.container).width() / this.options.goldenRatioVal );
|
|
//check if the new height does not exceed the goldenRatioLimitHeightTo option
|
|
new_height = new_height > this.options.goldenRatioLimitHeightTo ? this.options.goldenRatioLimitHeightTo : new_height;
|
|
$(this.container)
|
|
.css({
|
|
'line-height' : new_height + 'px',
|
|
height : new_height + 'px'
|
|
})
|
|
.trigger('golden-ratio-applied');
|
|
};
|
|
|
|
|
|
/*
|
|
* @params string : ids or classes
|
|
* @return boolean
|
|
*/
|
|
Plugin.prototype._is_window_width_allowed = function() {
|
|
return $(window).width() > this.options.disableGRUnder - 15;
|
|
};
|
|
|
|
|
|
//@return void
|
|
Plugin.prototype._parse_imgs = function( $_imgs, _event_ ) {
|
|
var self = this;
|
|
$_imgs.each(function ( ind, img ) {
|
|
var $_img = $(img);
|
|
self._pre_img_cent( $_img, _event_ );
|
|
|
|
// IMG CENTERING FN ON RESIZE ?
|
|
// Parse Img can be fired several times, so bind once
|
|
if ( self.options.onresize && ! $_img.data('resize-react-bound' ) ) {
|
|
$_img.data('resize-react-bound', true );
|
|
$(window).on('resize', _.debounce( function() {
|
|
self._pre_img_cent( $_img, 'resize');
|
|
}, 100 ) );
|
|
}
|
|
|
|
});//$_imgs.each()
|
|
|
|
// Mainly designed to check if a container is not getting parsed too many times
|
|
if ( $(self.container).attr('data-img-centered-in-container') ) {
|
|
var _n = parseInt( $(self.container).attr('data-img-centered-in-container'), 10 ) + 1;
|
|
$(self.container).attr('data-img-centered-in-container', _n );
|
|
} else {
|
|
$(self.container).attr('data-img-centered-in-container', 1 );
|
|
}
|
|
};
|
|
|
|
|
|
|
|
//@return void
|
|
Plugin.prototype._pre_img_cent = function( $_img ) {
|
|
|
|
var _state = this._get_current_state( $_img ),
|
|
self = this,
|
|
_case = _state.current,
|
|
_p = _state.prop[_case],
|
|
_not_p = _state.prop[ 'h' == _case ? 'v' : 'h'],
|
|
_not_p_dir_val = 'h' == _case ? ( this.options.zeroTopAdjust || 0 ) : ( this.options.zeroLeftAdjust || 0 );
|
|
|
|
var _centerImg = function( $_img ) {
|
|
$_img
|
|
.css( _p.dim.name , _p.dim.val )
|
|
.css( _not_p.dim.name , self.options.defaultCSSVal[ _not_p.dim.name ] || 'auto' )
|
|
.css( _p.dir.name, _p.dir.val ).css( _not_p.dir.name, _not_p_dir_val );
|
|
|
|
if ( 0 !== self.options.addCenteredClassWithDelay && _.isNumber( self.options.addCenteredClassWithDelay ) ) {
|
|
_.delay( function() {
|
|
$_img.addClass( _p._class ).removeClass( _not_p._class );
|
|
}, self.options.addCenteredClassWithDelay );
|
|
} else {
|
|
$_img.addClass( _p._class ).removeClass( _not_p._class );
|
|
}
|
|
|
|
// Mainly designed to check if a single image is not getting parsed too many times
|
|
if ( $_img.attr('data-img-centered') ) {
|
|
var _n = parseInt( $_img.attr('data-img-centered'), 10 ) + 1;
|
|
$_img.attr('data-img-centered', _n );
|
|
} else {
|
|
$_img.attr('data-img-centered', 1 );
|
|
}
|
|
return $_img;
|
|
};
|
|
if ( this.options.setOpacityWhenCentered ) {
|
|
$.when( _centerImg( $_img ) ).done( function( $_img ) {
|
|
$_img.css( 'opacity', self.options.opacity );
|
|
});
|
|
} else {
|
|
_.delay(function() { _centerImg( $_img ); }, 0 );
|
|
}
|
|
};
|
|
|
|
|
|
|
|
|
|
/********
|
|
* HELPERS
|
|
*********/
|
|
//@return object with initial conditions : { current : 'h' or 'v', prop : {} }
|
|
Plugin.prototype._get_current_state = function( $_img ) {
|
|
var c_x = $_img.closest(this.container).outerWidth(),
|
|
c_y = $(this.container).outerHeight(),
|
|
i_x = this._get_img_dim( $_img , 'x'),
|
|
i_y = this._get_img_dim( $_img , 'y'),
|
|
up_i_x = i_y * c_y !== 0 ? Math.round( i_x / i_y * c_y ) : c_x,
|
|
up_i_y = i_x * c_x !== 0 ? Math.round( i_y / i_x * c_x ) : c_y,
|
|
current = 'h';
|
|
//avoid dividing by zero if c_x or i_x === 0
|
|
if ( 0 !== c_x * i_x ) {
|
|
current = ( c_y / c_x ) >= ( i_y / i_x ) ? 'h' : 'v';
|
|
}
|
|
|
|
var prop = {
|
|
h : {
|
|
dim : { name : 'height', val : c_y },
|
|
dir : { name : 'left', val : ( c_x - up_i_x ) / 2 + ( this.options.leftAdjust || 0 ) },
|
|
_class : 'h-centered'
|
|
},
|
|
v : {
|
|
dim : { name : 'width', val : c_x },
|
|
dir : { name : 'top', val : ( c_y - up_i_y ) / 2 + ( this.options.topAdjust || 0 ) },
|
|
_class : 'v-centered'
|
|
}
|
|
};
|
|
|
|
return { current : current , prop : prop };
|
|
};
|
|
|
|
//@return img height or width
|
|
//uses the img height and width if not visible and set in options
|
|
Plugin.prototype._get_img_dim = function( $_img, _dim ) {
|
|
if ( ! this.options.useImgAttr )
|
|
return 'x' == _dim ? $_img.outerWidth() : $_img.outerHeight();
|
|
|
|
if ( $_img.is(":visible") ) {
|
|
return 'x' == _dim ? $_img.outerWidth() : $_img.outerHeight();
|
|
} else {
|
|
if ( 'x' == _dim ){
|
|
var _width = $_img.originalWidth();
|
|
return typeof _width === undefined ? 0 : _width;
|
|
}
|
|
if ( 'y' == _dim ){
|
|
var _height = $_img.originalHeight();
|
|
return typeof _height === undefined ? 0 : _height;
|
|
}
|
|
}
|
|
};
|
|
|
|
/*
|
|
* @params string : ids or classes
|
|
* @return boolean
|
|
*/
|
|
Plugin.prototype._is_selector_allowed = function() {
|
|
//has requested sel ?
|
|
if ( ! $(this.container).attr( 'class' ) )
|
|
return true;
|
|
|
|
//check if option is well formed
|
|
if ( ! this.options.skipGoldenRatioClasses || ! _.isArray( this.options.skipGoldenRatioClasses ) )
|
|
return true;
|
|
|
|
var _elSels = $(this.container).attr( 'class' ).split(' '),
|
|
_selsToSkip = this.options.skipGoldenRatioClasses,
|
|
_filtered = _elSels.filter( function(classe) { return -1 != $.inArray( classe , _selsToSkip ) ;});
|
|
|
|
//check if the filtered selectors array with the non authorized selectors is empty or not
|
|
//if empty => all selectors are allowed
|
|
//if not, at least one is not allowed
|
|
return 0 === _filtered.length;
|
|
};
|
|
|
|
|
|
// prevents against multiple instantiations
|
|
$.fn[pluginName] = function ( options ) {
|
|
return this.each(function () {
|
|
if (!$.data(this, 'plugin_' + pluginName)) {
|
|
$.data(this, 'plugin_' + pluginName,
|
|
new Plugin( this, options ));
|
|
}
|
|
});
|
|
};
|
|
|
|
})( jQuery, window ); |