(function (factory) {
if (typeof define === 'function' && define.amd) {
// amd (register as an anonymous module)
define(['jquery'], factory);
} else if (typeof exports === 'object') {
// node/commonjs
module.exports = factory(require('jquery'));
} else {
// browser globals
factory((function(){
if (typeof jquery !== 'undefined') {
return jquery;
} else if (typeof zepto !== 'undefined') {
return zepto;
}
return $;
})());
}
}(function ($) {
function log(type, msg){
if(window.console){
if(typeof type != 'undefined' && type && typeof msg != 'undefined' && msg){
type = type.tolowercase();
if(type == 'error'){
console.error(msg);
}else if(type == 'log'){
console.log(msg);
}else{
console.error('"' + type + '" is not supported as console type.');
}
}
}
}
function strtonum(str){
str = $.trim(str.tostring());
if(str.tolowercase() === 'auto'){
return str;
}
return parsefloat(str);
// return number(str.replace(/[^\d.-]/g, ''));
}
function validatexyperc(val, wh){
var temp = val.tostring().match(/(-*)+\d+/)[0]; // '-200%' -> -200
if(getmeasurement(val) == 'px'){
if(val < 0){
return 0;
}else if(val > wh){
return wh;
}else{
return val;
}
}else if(getmeasurement(val) == '%'){
if(temp < 0){
return '0%';
}else if(temp > 100){
return '100%';
}else{
return val;
}
}
}
function getmeasurement(str){ // determine if input is a px or % value
var ma = str.tostring().match(/\d+(.*)/i);
if(ma){
switch($.trim(ma[1])){
case '':
return 'px';
case 'px':
return 'px';
case '%':
return '%';
default:
break;
}
}
return '';
}
var css3supported = (function(){
/* code available at http://net.tutsplus.com/tutorials/html-css-techniques/quick-tip-detect-css-support-in-browsers-with-javascript/ */
var div = document.createelement('div'),
vendors = 'khtml ms o moz webkit'.split(' '),
len = vendors.length;
return function(prop) {
if ( prop in div.style ) return true;
prop = prop.replace(/^[a-z]/, function(val) {
return val.touppercase();
});
for(var i in vendors){
if ( vendors[i] + prop in div.style ) {
return true;
}
}
return false;
};
})();
/*
zepto does not come with $.fn.outerwidth() & $.fn.outerheight()
code: https://gist.github.com/pamelafox/1379704
*/
if (!$.fn.outerheight || !$.fn.outerwidth) {
if (typeof array.prototype.foreach != 'function') { // fix for older browsers
array.prototype.foreach = function(callback){
for (var i = 0; i < this.length; i++){
callback.apply(this, [this[i], i, this]);
}
};
}
['width', 'height'].foreach(function(dimension) {
var offset, dimension = dimension.replace(/./, function(m) { return m[0].touppercase(); });
if (!$.fn['outer' + dimension]) {
$.fn['outer' + dimension] = function() {
var elem = this;
if (elem) {
var size = elem[dimension]();
var sides = { 'width': ['left', 'right'], 'height': ['top', 'bottom'] };
sides[dimension].foreach(function(side) {
size += parseint(elem.css('margin-' + side), 10);
size += parseint(elem.css('padding-' + side), 10);
size += parseint(elem.css('border-' + side + '-width'), 10);
});
return size;
} else {
return null;
}
};
}
});
}
/* fallback for older versions of jquery */
if(!$.fn.unwrap){
$.fn.unwrap = function(){
this.parent().each(function() {
if ( !$.nodename( this, 'body' ) ) {
$( this ).replacewith( this.childnodes );
}
}).end();
};
}
var checkpositionreach = function($elem, scrollcheck){
var $win = $(window),
bounds = $elem.offset(),
viewport = {
top : $win.scrolltop(),
// left : $win.scrollleft() // zepto does not support this
left : window.scrollx
};
viewport.right = viewport.left + $win.width();
viewport.bottom = viewport.top + $win.height();
bounds.right = bounds.left + $elem.outerwidth();
bounds.bottom = bounds.top + $elem.outerheight();
scrollcheck = (scrollcheck) ? strtonum(scrollcheck) : 0;
return (!(
viewport.right < (bounds.left - scrollcheck) ||
viewport.left > (bounds.right + scrollcheck) ||
viewport.bottom < (bounds.top - scrollcheck) ||
viewport.top > (bounds.bottom + scrollcheck)
));
};
var pluginname = 'jqthumb',
$window = $(window),
ondemandscrolleventobj = (function(){
var tmp = ['scroll', 'resize', 'scrolltop'];
var obj = {};
for(var i=0; i')
.css({
'width' : strtonum(optw) + getmeasurement(optw),
'height' : strtonum(opth) + getmeasurement(opth),
'display' : 'none',
'position' : 'relative',
'overflow' : 'hidden'
})
.addclass(options.classname)
.data(pluginname, pluginname); // it would be easy to kill later
$fakeimg = $('
')
.css({
'width' : '100%',
'height' : '100%',
'background-image' : 'url("' + imgurl + '")',
// '-ms-filter' : '"progid:dximagetransform.microsoft.alphaimageloader(src="' + $oriimage.attr(options.source) + '",sizingmethod="scale")', // this does not work in zepto
'background-repeat' : 'no-repeat',
'background-position': strtonum(optposx) + getmeasurement(optposx) + ' ' + strtonum(optposy) + getmeasurement(optposy),
'background-size' : 'cover'
})
.appendto($wrapper);
if(options.renderposition.tolowercase() === 'after'){
$wrapper.insertafter(obj.oriimg);
}else{
$wrapper.insertbefore(obj.oriimg);
}
$wrapper.show(); // must show first to get resolution
$fakeimg
.css({
'width' : parsefloat(100 * optz) + '%',
'height' : parsefloat(100 * optz) + '%',
'position' : 'absolute'
})
.css({ // cannot combine css() as width and height have to be defined before doing calculation
'top' : (function(){
// (ch - ph) / ph * 100 / percentage
var ch = $wrapper.height(),
ph = $fakeimg.height();
if(getmeasurement(optposy) == '%'){
return '-' + parsefloat((ph - ch) / ch * 100 / (100 / strtonum(optposy) ) ) + '%';
}
})(),
'left' : (function(){
// (cw - pw) / cw * 100 / percentage
var cw = $wrapper.width(),
pw = $fakeimg.width();
if(getmeasurement(optposx) == '%'){
return '-' + parsefloat((pw - cw) / cw * 100 / (100 / strtonum(optposx) ) ) + '%';
}
})()
});
$wrapper.hide();
if (typeof obj.done === 'function'){
obj.done($wrapper);
}
}
function nativemath(obj){
var oriw = obj.tmpimgdom.width,
orih = obj.tmpimgdom.height,
optw = ($.trim(options.width.tostring().tolowercase()) === 'auto') ? oriw.tostring() : options.width,
opth = ($.trim(options.height.tostring().tolowercase()) === 'auto') ? orih.tostring() : options.height,
optz = options.zoom,
optposx = options.position.x,
optposy = options.position.y,
measure_optw = getmeasurement(optw),
measure_opth = getmeasurement(opth),
optresp = options.responsive,
$wrapper, $fakeimg;
$fakeimg = $(obj.tmpimgdom);
$wrapper = $('');
function calculatereso(){
var ratio = 0;
if(oriw > orih){ // horizontal
$fakeimg.css({
'width' : 'auto',
'max-height' : 99999999,
'min-height' : 0,
'max-width' : 99999999,
'min-width' : 0,
'height' : $wrapper.height() + 'px'
});
ratio = $fakeimg.height() / $fakeimg.width(); // get ratio
if($fakeimg.width() < $wrapper.width()){
$fakeimg.css({
'width' : $wrapper.width() * optz,
'height': parsefloat($wrapper.width() * ratio) * optz
});
}else{
$fakeimg.css({
'width' : $fakeimg.width() * optz,
'height': parsefloat($fakeimg.width() * ratio) * optz
});
}
}else{ // vertical
$fakeimg.css({
'width' : $wrapper.width() + 'px',
'max-height' : 99999999,
'min-height' : 0,
'max-width' : 99999999,
'min-width' : 0,
'height' : 'auto'
});
ratio = $fakeimg.width() / $fakeimg.height(); // get ratio
if($fakeimg.height() < $wrapper.height()){
$fakeimg.css({
'width' : parsefloat($wrapper.height() * ratio) * optz,
'height': $wrapper.height() * optz
});
}
}
if(optz < 1){ // workaround for zoom level < 1
var $subcontainer = $('');
$subcontainer
.css({
'width' : parsefloat(strtonum(optw.tostring()) * optz) + getmeasurement(optw.tostring()),
'height' : parsefloat(strtonum(opth.tostring()) * optz) + getmeasurement(opth.tostring()),
'position' : 'relative',
'overflow' : 'hidden'
})
.appendto($fakeimg.parent());
$fakeimg.appendto($subcontainer); // move $fakeimg into $subcontainer
}
$fakeimg.css({
'position' : 'absolute',
'left' : (function(){
var x = 0;
if(getmeasurement(optposx) == '%'){
x = parsefloat(($fakeimg.width() - $fakeimg.parent().width()) / 100 * strtonum(optposx));
return (x <= 0) ? x + 'px' : '-' + x + 'px';
}else if(getmeasurement(optposx) == 'px' || isnan(optposx) === false){
return strtonum(optposx) + 'px';
}
})(),
'top' : (function(){
var y = 0;
if(getmeasurement(optposy) == '%'){
y = parsefloat(($fakeimg.height() - $fakeimg.parent().height()) / 100 * strtonum(optposy));
return (y <= 0) ? y + 'px' : '-' + y + 'px';
}else if(getmeasurement(optposy) == 'px' || isnan(optposy) === false){
return strtonum(optposy) + 'px';
}
})()
});
}
if(options.renderposition.tolowercase() === 'after'){
$wrapper.insertafter(obj.oriimg);
}else{
$wrapper.insertbefore(obj.oriimg);
}
$wrapper
.append($fakeimg)
.css({
'position' : 'absolute',
'overflow' : 'hidden',
'left' : '0',
'top' : '0',
'width' : strtonum(optw) + (measure_optw ? measure_optw : 'px'),
'height' : strtonum(opth) + (measure_opth ? measure_opth : 'px')
})
.data(pluginname, pluginname); // it would be easy to kill later
calculatereso();
if(!isnan(optresp) && optresp > 0){
$(obj.oriimage).data(dtevtfnresponsive, function(){
settimeout(function(){
calculatereso();
}, optresp);
});
$window.bind(ondemandscrolleventobj.resize, $(obj.oriimage).data(dtevtfnresponsive));
}
$wrapper
.hide()
.addclass(options.classname);
if (typeof obj.done === 'function'){
obj.done($wrapper);
}
}
options.before.apply(self, [self]);
var pluginclass = this,
$oriimage = $(self),
imgurl = $oriimage.attr(options.source),
domath = (function(method){
if(method == 'auto'){
if(css3supported('backgroundsize') === false){ // old browsers need to do calculation to perform same output like "background-size: cover"
return nativemath;
}
return modernmath; // modern browsers that support css3 would be easier
}else if(method == 'modern'){
return modernmath;
}else if(method == 'native'){
return nativemath;
}else{
log('error', 'invalid method. only "auto", "modern" and "native" are allowed.');
}
})(options.method.tostring().tolowercase());
if(domath){
$oriimage.data(oristyledataname, $oriimage.attr('style')); // keep original styles into data
$oriimage.data(renderposdataname, options.renderposition); // store render position (before/after) for killing purpose
$oriimage.hide();
if(options.ondemand === true){
pluginclass.demand(self, options, imgurl, domath);
}else{
$oriimage.data(dttmpimg, new image());
pluginclass.lazyload(pluginclass, self, options, function(img){
pluginclass.processimg(self, options, img, domath);
$oriimage.removedata(dttmpimg);
});
}
}else{
$oriimage.data(dtstatus, 'error');
pluginclass.kill($oriimage);
}
},
demand: function(self, options, imgurl, fndomathonsuccess){
var pluginclass = this,
$oriimage = $(self);
if(options.ondemandevent === 'scroll'){
$oriimage.wrap(''); // add temporary tag to get its offset().top
var $tmpwrapper = $oriimage.parent();
$tmpwrapper.css({ // set temporarily height
'width' : ((options.width) ? strtonum(options.width) + getmeasurement(options.width) : $oriimage.width() + 'px'),
'height' : ((options.height) ? strtonum(options.height) + getmeasurement(options.height) : $oriimage.height() + 'px')
});
$oriimage.data(dtevtfnongoing, function(){ // store event fn into data for unbinding purpose
if( checkpositionreach($tmpwrapper, options.threshold) ){ // check scroll position
$window.unbind(ondemandscrolleventstr, $oriimage.data(dtevtfnongoing)); // unbind when it is done process to save cpu usage
$oriimage.removedata(dtevtfnongoing);
$oriimage.unwrap(); // remove temporary tag
$oriimage.data(dttmpimg, new image());
pluginclass.lazyload(pluginclass, self, options, function(img){
pluginclass.processimg(self, options, img, fndomathonsuccess);
$oriimage.removedata(dttmpimg);
});
}
});
$window
.bind(ondemandscrolleventstr, $oriimage.data(dtevtfnongoing))
.triggerhandler(ondemandscrolleventobj.scroll);
}else if(
options.ondemandevent === 'click' ||
options.ondemandevent === 'mouseenter'
){
var $bindtarget = $oriimage.parent(),
bindname = ((options.ondemandevent === 'click') ? ondemandclickeventname : ondemandmouseentereventname);
$oriimage.data(dtevtfnonetime, function(){ // store event fn into data for unbinding purpose
$bindtarget.unbind(bindname, $oriimage.data(dtevtfnonetime)); // unbind when it is done process to save cpu usage
$oriimage.removedata(dtevtfnonetime);
$oriimage.data(dttmpimg, new image());
pluginclass.lazyload(pluginclass, self, options, function(img){
pluginclass.processimg(self, options, img, fndomathonsuccess);
$oriimage.removedata(dttmpimg);
});
$oriimage.data(inviewportdataname, true);
});
$bindtarget.bind(bindname, $oriimage.data(dtevtfnonetime));
}
},
updateglobal: function(self, obj, options){
self.global.outputelems.push( $(obj)[0] );
self.global.elemcounter++;
grandglobal.outputelems.push( $(obj)[0] );
if(self.global.elemcounter == self.global.inputelems.length){
options.done.apply(self, [self.global.outputelems]);
}
}
};
$.fn[ pluginname ] = function ( options ) {
var obj = {},
global = {
elemcounter : 0,
outputelems : [],
inputelems : (function(_this){
var $this = $(_this),
total = $this.length,
temparr = [];
for(var i=0; i