Skip to content

JavaScript in MyDef

Hui Zhou edited this page Mar 10, 2012 · 6 revisions

Whenever I see those web pages with cool JavaScript effects I would wonder how to do that. The best way is to just read the source code. In this page, let's use jqZoom http://www.mind-projects.it/projects/jqzoom/ as example. jqZoom are often seen in product page where when mouse is over the image, a zoomed-in portion of the detailed image will show on the side.

Upon opening "jquery.jqzoom-core.js", it appears a bit daunting with 733 lines of essentially one single statement. But nevertheless, it contains simple story line. Let's move it to MyDef.

There is no Javascript plugin for MyDef yet, so we'll use the gneral module instead. As we will see, even with MyDef's basic macro system, we can do quite a lot to improve the readability.

Note that subcode: main is the default entry point in MyDef.

page: jqzoom
    type: js
    subcode: main
	# A local scope where '$' refers to jQuery
	(function ($) {
	    $call jq_extension
	})(jQuery);

Somehow I never get used to the functional style of begin a statement here and end it a few hundred lines later. I like to have the whole thing in one bite. Javascript allows '$' as identifier, which allows jQuery to use $("..."), which is a mere function call -- an alias to jQuery("..."). Since '$' is unique, when writing extensions, we need worry about the case that '$' will be used somewhere else. See how reusing the whole wheel brings more complexity. In my opinions, certain use of global variables are good, it provides context. And listen to how we talk and think, human mind loves context. And we always have no trouble understand our context until we start trying to write code out of context. As we write code that is not confined by our context, we need worry about protecting or establishing the local context, therefore this extra complexity we have here.

What we are really trying to say here is:

$scope(let $=jQuery)
    code ...

Javascript has no such notion, so it uses a hack. I have mixed feelings over these hacks. On one hand, I admire the genius behind hacks, like magic. On the other hand, I see hacks or magic in general misleading. They block our view from seeing the right path.

Almost all jQuery extension will use this magic shell, so with MyDef, we could move it into a frame library and forget about it. Like following:

include: std_jq.def
page: jqzoom, jq_basic_frame
    type: js
    subcode: jq_extension
        # your actual code here.

where jq_basic is defined in std_jq.def as

subcode: jq_basic_frame
    # A local scope where '$' refers to jQuery
    (function ($) {
	$call jq_extension
    })(jQuery);

The new entry point jq_extension needs to be established by convention. Again, we human love conventions. They define our efficiency.

Now back to jqZoom.

subcode: jq_extension
    $call global_variables
    
    # Usage example, more than half of the understanding is in the usage.
    #
    # <a href="images/BIGIMAGE.JPG" class="MYCLASS" title="MYTITLE">  
    #    <img src="images/SMALLIMAGE.JPG" title="IMAGE TITLE">  
    # </a>  
    # $(document).ready(function(){  $('.MYCLASS').jqzoom(options); });  

    $.fn.jqzoom = function (options) {
	return this.each(function () {
	    var node = this.nodeName.toLowerCase();
	    if (node == 'a') {
		new jqzoom(this, options);
	    }
	});
    };

    jqzoom = function (el, options) {
	var settings = $.extend({}, $.jqzoom.defaults, options || {});
	$call jqzoom_definition
    };
    # -- defaults
    $.jqzoom = {
	defaults: {
	    $call default_options
	},
	$call fn_dis_en_able
    };

Variables are necessary but distracting. They are best to be defined wherever they are first referenced. We could make it esier to manage with a Javascript module plugin, or we could just cut them in pieces and disperse them where most approprate.

At least for me, the most essential understanding is in its purpose. Having a short concise usage example here is really helpful. For experienced, really good programmers, they may have acquired enough by now and can start go on to make their own wheels, in a different variety.

Next is another wrapper just to masquerade function interface.

Finally the actual jqzoom definition and an almost standard jQuery mechanism of parsing options. I felt all these codes here are sort of boilerplate code that could be moved to the frame code library. Boilerplate does not contain new ideas.

subcode: jqzoom_definition
    $call check_already_loaded
    $call local_variables

    var smallimage = new Smallimage(img);
    var largeimage = new Largeimage();
    # $div ZoomPup
    var lens = new Lens();
    # $div zoomPreload
    var loader = new Loader();
    # $div zoomWindow
    #     $div zoomWrapperTitle, /
    #     $div zoomWrapperImage, /
    var stage = new Stage();

    $call prevent_default_click
    $call check_zoom_type
    var obj = this;
    obj.el = el;
    $.extend(obj, {
	create: function () { //create the main objects
	    $call method_create_zoomPad
	    $call method_create_lens_stage_loader
	    $call method_create_load
	    obj.init()
	},
	init: function () {
	    $call method_init_settings
	    $call method_init_bind_events
	    $call method_init_thumb_preload
	},
	load: function () {
	    $call method_load
	},
	activate: function (e) {
	    $call method_activate
	},
	deactivate: function (e) {
	    $call method_deactivate
	},
	swapimage: function (link) {
	    $call method_swapimage
	}
    });
    $call check_onload

    $call define_Smallimage
    $call define_Largeimage
    $call define_Loader
    $call define_Lens
    $call define_Stage

    $(el).data("jqzoom", obj);

If jqZoom is a wheel, this part is the circle and axis. The rest part are merely details of this particular wheel.

What jqZoom does is to attach "div"s that represent lens and zoom window, and then listen to mouse events and then modify the image properties.

The rest of the code is roughly grouped but still very messy. When we have time, I would like to group codes that concerns different zoom types seperately. The modern day code base often have features interleaved everywhere and adding features is a one-way street. With MyDef, I would like to change that. For the minimum, it should be always easy to produce a version of the code that just does one default feature -- no need for all these option checking. The options can be controlled at MyDef level -- with much more flexibility.

Anyway, the follwoing is the rest of the detail code that needs more refactoring.

subcode: check_already_loaded
    var api = null;
    api = $(el).data("jqzoom");
    if (api) return api;

subcode: local_variables
    el.rel = $(el).attr('rel');
    //ANCHOR ELEMENT
    el.zoom_active = false;
    el.zoom_disabled = false; //to disable single zoom instance
    el.largeimageloading = false; //tell us if large image is loading
    el.largeimageloaded = false; //tell us if large image is loaded
    el.scale = {};
    el.timer = null;
    el.mousepos = {};
    el.mouseDown = false;
    $(el).css({
	'outline-style': 'none',
	'text-decoration': 'none'
    });
    //BASE IMAGE
    var img = $("img:eq(0)", el);
    el.title = $(el).attr('title');
    el.imagetitle = img.attr('title');
    var zoomtitle = ($.trim(el.title).length > 0) ? el.title : el.imagetitle;

subcode: prevent_default_click
    //preventing default click,allowing the onclick event [exmple: lightbox]
    $(el).bind('click', function (e) {
	e.preventDefault();
	return false;
    });

subcode: check_zoom_type
    //setting the default zoomType if not in settings
    var zoomtypes = ['standard', 'drag', 'innerzoom', 'reverse'];
    if ($.inArray($.trim(settings.zoomType), zoomtypes) < 0) {
	settings.zoomType = 'standard';
    }
subcode: check_onload
    //sometimes image is already loaded and onload will not fire
    if (img[0].complete) {
	//fetching data from smallimage if was previously loaded
	smallimage.fetchdata();
	if ($(".zoomPad", el).length == 0) obj.create();
    }
# ----
subcode: method_create_zoomPad
    //create ZoomPad
    if ($(".zoomPad", el).length == 0) {
	el.zoomPad = $('<div/>').addClass('zoomPad');
	img.wrap(el.zoomPad);
    }
    if(settings.zoomType == 'innerzoom'){
	settings.zoomWidth  = smallimage.w;
	settings.zoomHeight  =   smallimage.h;
    }
subcode: method_create_lens_stage_loader
    //creating ZoomPup
    if ($(".zoomPup", el).length == 0) {
	lens.append();
    }
    //creating zoomWindow
    if ($(".zoomWindow", el).length == 0) {
	stage.append();
    }
    //creating Preload
    if ($(".zoomPreload", el).length == 0) {
	loader.append();
    }
subcode: method_create_load
    //preloading images
    if (settings.preloadImages || settings.zoomType == 'drag' || settings.alwaysOn) {
	obj.load();
    }
    obj.init();
subcode: method_init_settings
    //drag option
    if (settings.zoomType == 'drag') {
	$(".zoomPad", el).mousedown(function () {
	    el.mouseDown = true;
	});
	$(".zoomPad", el).mouseup(function () {
	    el.mouseDown = false;
	});
	document.body.ondragstart = function () {
	    return false;
	};
	$(".zoomPad", el).css({
	    cursor: 'default'
	});
	$(".zoomPup", el).css({
	    cursor: 'move'
	});
    }
    if (settings.zoomType == 'innerzoom') {
	$(".zoomWrapper", el).css({
	    cursor: 'crosshair'
	});
    }
subcode: method_init_bind_events
    $(".zoomPad", el).bind('mouseenter mouseover', function (event) {
	img.attr('title', '');
	$(el).attr('title', '');
	el.zoom_active = true;
	//if loaded then activate else load large image
	smallimage.fetchdata();
	if (el.largeimageloaded) {
	    obj.activate(event);
	} else {
	    obj.load();
	}
    });
    $(".zoomPad", el).bind('mouseleave', function (event) {
	obj.deactivate();
    });
    $(".zoomPad", el).bind('mousemove', function (e) {

	//prevent fast mouse mevements not to fire the mouseout event
	if (e.pageX > smallimage.pos.r || e.pageX < smallimage.pos.l || e.pageY < smallimage.pos.t || e.pageY > smallimage.pos.b) {
	    lens.setcenter();
	    return false;
	}
	el.zoom_active = true;
	if (el.largeimageloaded && !$('.zoomWindow', el).is(':visible')) {
	    obj.activate(e);
	}
	if (el.largeimageloaded && (settings.zoomType != 'drag' || (settings.zoomType == 'drag' && el.mouseDown))) {
	    lens.setposition(e);
	}
    });
subcode: method_init_thumb_preload
    var thumb_preload = new Array();
    var i = 0;
    //binding click event on thumbnails
    var thumblist = new Array();
    thumblist = $('a').filter(function () {
	var regex = new RegExp("gallery[\\s]*:[\\s]*'" + $.trim(el.rel) + "'", "i");
	var rel = $(this).attr('rel');
	if (regex.test(rel)) {
	    return this;
	}
    });
    if (thumblist.length > 0) {
	//getting the first to the last
	var first = thumblist.splice(0, 1);
	thumblist.push(first);
    }
    thumblist.each(function () {
	//preloading thumbs
	if (settings.preloadImages) {
	    var thumb_options = $.extend({}, eval("(" + $.trim($(this).attr('rel')) + ")"));
	    thumb_preload[i] = new Image();
	    thumb_preload[i].src = thumb_options.largeimage;
	    i++;
	}
	$(this).click(function (e) {
	    if($(this).hasClass('zoomThumbActive')){
	      return false;
	    }
	    thumblist.each(function () {
		$(this).removeClass('zoomThumbActive');
	    });
	    e.preventDefault();
	    obj.swapimage(this);
	    return false;
	});
    });
subcode: method_load
    if (el.largeimageloaded == false && el.largeimageloading == false) {
	var url = $(el).attr('href');
	el.largeimageloading = true;
	largeimage.loadimage(url);
    }
subcode: method_activate
    clearTimeout(el.timer);
    //show lens and zoomWindow
    lens.show();
    stage.show();
subcode: method_deactivate
    switch (settings.zoomType) {
    case 'drag':
	//nothing or lens.setcenter();
	break;
    default:
	img.attr('title', el.imagetitle);
	$(el).attr('title', el.title);
	if (settings.alwaysOn) {
	    lens.setcenter();
	} else {
	    stage.hide();
	    lens.hide();
	}
	break;
    }
    el.zoom_active = false;
subcode: method_swapimage
    el.largeimageloading = false;
    el.largeimageloaded = false;
    var options = new Object();
    options = $.extend({}, eval("(" + $.trim($(link).attr('rel')) + ")"));
    if (options.smallimage && options.largeimage) {
	var smallimage = options.smallimage;
	var largeimage = options.largeimage;
	$(link).addClass('zoomThumbActive');
	$(el).attr('href', largeimage);
	img.attr('src', smallimage);
	lens.hide();
	stage.hide();
	obj.load();
    } else {
	alert('ERROR :: Missing parameter for largeimage or smallimage.');
	throw 'ERROR :: Missing parameter for largeimage or smallimage.';
    }
    return false;
# ----
subcode: define_Smallimage
    /*========================================================,
    |   Smallimage
    |---------------------------------------------------------:
    |   Base image into the anchor element
    `========================================================*/

    function Smallimage(image) {
	var $obj = this;
	this.node = image[0];
	this.findborder = function () {
	    var bordertop = 0;
	    bordertop = image.css('border-top-width');
	    btop = '';
	    var borderleft = 0;
	    borderleft = image.css('border-left-width');
	    bleft = '';
	    if (bordertop) {
		for (i = 0; i < 3; i++) {
		    var x = [];
		    x = bordertop.substr(i, 1);
		    if (isNaN(x) == false) {
			btop = btop + '' + bordertop.substr(i, 1);
		    } else {
			break;
		    }
		}
	    }
	    if (borderleft) {
		for (i = 0; i < 3; i++) {
		    if (!isNaN(borderleft.substr(i, 1))) {
			bleft = bleft + borderleft.substr(i, 1)
		    } else {
			break;
		    }
		}
	    }
	    $obj.btop = (btop.length > 0) ? eval(btop) : 0;
	    $obj.bleft = (bleft.length > 0) ? eval(bleft) : 0;
	};
	this.fetchdata = function () {
	    $obj.findborder();
	    $obj.w = image.width();
	    $obj.h = image.height();
	    $obj.ow = image.outerWidth();
	    $obj.oh = image.outerHeight();
	    $obj.pos = image.offset();
	    $obj.pos.l = image.offset().left + $obj.bleft;
	    $obj.pos.t = image.offset().top + $obj.btop;
	    $obj.pos.r = $obj.w + $obj.pos.l;
	    $obj.pos.b = $obj.h + $obj.pos.t;
	    $obj.rightlimit = image.offset().left + $obj.ow;
	    $obj.bottomlimit = image.offset().top + $obj.oh;
	    
	};
	this.node.onerror = function () {
	    alert('Problems while loading image.');
	    throw 'Problems while loading image.';
	};
	this.node.onload = function () {
	    $obj.fetchdata();
	    if ($(".zoomPad", el).length == 0) obj.create();
	};
	return $obj;
    };
subcode: define_Loader
    /*========================================================,
    |  Loader
    |---------------------------------------------------------:
    |  Show that the large image is loading
    `========================================================*/

    function Loader() {
	var $obj = this;
	this.append = function () {
	    this.node = $('<div/>').addClass('zoomPreload').css('visibility', 'hidden').html(settings.preloadText);
	    $('.zoomPad', el).append(this.node);
	};
	this.show = function () {
	    this.node.top = (smallimage.oh - this.node.height()) / 2;
	    this.node.left = (smallimage.ow - this.node.width()) / 2;
	    //setting position
	    this.node.css({
		top: this.node.top,
		left: this.node.left,
		position: 'absolute',
		visibility: 'visible'
	    });
	};
	this.hide = function () {
	    this.node.css('visibility', 'hidden');
	};
	return this;
    }
subcode: define_Lens
    /*========================================================,
    |   Lens
    |---------------------------------------------------------:
    |   Lens over the image
    `========================================================*/

    function Lens() {
	var $obj = this;
	this.node = $('<div/>').addClass('zoomPup');
	//this.nodeimgwrapper = $("<div/>").addClass('zoomPupImgWrapper');
	this.append = function () {
	    $('.zoomPad', el).append($(this.node).hide());
	    if (settings.zoomType == 'reverse') {
		this.image = new Image();
		this.image.src = smallimage.node.src; // fires off async
		$(this.node).empty().append(this.image);
	    }
	};
	this.setdimensions = function () {
	    this.node.w = (parseInt((settings.zoomWidth) / el.scale.x) > smallimage.w ) ? smallimage.w : (parseInt(settings.zoomWidth / el.scale.x)); 
	    this.node.h = (parseInt((settings.zoomHeight) / el.scale.y) > smallimage.h ) ? smallimage.h : (parseInt(settings.zoomHeight / el.scale.y)); 
	    this.node.top = (smallimage.oh - this.node.h - 2) / 2;
	    this.node.left = (smallimage.ow - this.node.w - 2) / 2;
	    //centering lens
	    this.node.css({
		top: 0,
		left: 0,
		width: this.node.w + 'px',
		height: this.node.h + 'px',
		position: 'absolute',
		display: 'none',
		borderWidth: 1 + 'px'
	    });



	    if (settings.zoomType == 'reverse') {
		this.image.src = smallimage.node.src;
		$(this.node).css({
		    'opacity': 1
		});

		$(this.image).css({
		    position: 'absolute',
		    display: 'block',
		    left: -(this.node.left + 1 - smallimage.bleft) + 'px',
		    top: -(this.node.top + 1 - smallimage.btop) + 'px'
		});

	    }
	};
	this.setcenter = function () {
	    //calculating center position
	    this.node.top = (smallimage.oh - this.node.h - 2) / 2;
	    this.node.left = (smallimage.ow - this.node.w - 2) / 2;
	    //centering lens
	    this.node.css({
		top: this.node.top,
		left: this.node.left
	    });
	    if (settings.zoomType == 'reverse') {
		$(this.image).css({
		    position: 'absolute',
		    display: 'block',
		    left: -(this.node.left + 1 - smallimage.bleft) + 'px',
		    top: -(this.node.top + 1 - smallimage.btop) + 'px'
		});

	    }
	    //centering large image
	    largeimage.setposition();
	};
	this.setposition = function (e) {
	    el.mousepos.x = e.pageX;
	    el.mousepos.y = e.pageY;
	    var lensleft = 0;
	    var lenstop = 0;

	    function overleft(lens) {
		return el.mousepos.x - (lens.w) / 2 < smallimage.pos.l; 
	    }

	    function overright(lens) {
		return el.mousepos.x + (lens.w) / 2 > smallimage.pos.r; 
	       
	    }

	    function overtop(lens) {
		return el.mousepos.y - (lens.h) / 2 < smallimage.pos.t; 
	    }

	    function overbottom(lens) {
		return el.mousepos.y + (lens.h) / 2 > smallimage.pos.b; 
	    }
	    
	    lensleft = el.mousepos.x + smallimage.bleft - smallimage.pos.l - (this.node.w + 2) / 2;
	    lenstop = el.mousepos.y + smallimage.btop - smallimage.pos.t - (this.node.h + 2) / 2;
	    if (overleft(this.node)) {
		lensleft = smallimage.bleft - 1;
	    } else if (overright(this.node)) {
		lensleft = smallimage.w + smallimage.bleft - this.node.w - 1;
	    }
	    if (overtop(this.node)) {
		lenstop = smallimage.btop - 1;
	    } else if (overbottom(this.node)) {
		lenstop = smallimage.h + smallimage.btop - this.node.h - 1;
	    }
	    
	    this.node.left = lensleft;
	    this.node.top = lenstop;
	    this.node.css({
		'left': lensleft + 'px',
		'top': lenstop + 'px'
	    });
	    if (settings.zoomType == 'reverse') {
		if ($.browser.msie && $.browser.version > 7) {
		    $(this.node).empty().append(this.image);
		}

		$(this.image).css({
		    position: 'absolute',
		    display: 'block',
		    left: -(this.node.left + 1 - smallimage.bleft) + 'px',
		    top: -(this.node.top + 1 - smallimage.btop) + 'px'
		});
	    }
	   
	    largeimage.setposition();
	};
	this.hide = function () {
	    img.css({
		'opacity': 1
	    });
	    this.node.hide();
	};
	this.show = function () {  
	    
	    if (settings.zoomType != 'innerzoom' && (settings.lens || settings.zoomType == 'drag')) {
		this.node.show();
	    }       

	    if (settings.zoomType == 'reverse') {
		img.css({
		    'opacity': settings.imageOpacity
		});
	    }
	};
	this.getoffset = function () {
	    var o = {};
	    o.left = $obj.node.left;
	    o.top = $obj.node.top;
	    return o;
	};
	return this;
    };

subcode: define_Stage
    /*========================================================,
    |   Stage
    |---------------------------------------------------------:
    |   Window area that contains the large image
    `========================================================*/

    function Stage() {
	var $obj = this;
	this.node = $("<div class='zoomWindow'><div class='zoomWrapper'><div class='zoomWrapperTitle'></div><div class='zoomWrapperImage'></div></div></div>");
	this.ieframe = $('<iframe class="zoomIframe" src="javascript:\'\';" marginwidth="0" marginheight="0" align="bottom" scrolling="no" frameborder="0" ></iframe>');
	this.setposition = function () {
	    this.node.leftpos = 0;
	    this.node.toppos = 0;
	    if (settings.zoomType != 'innerzoom') {
		//positioning
		switch (settings.position) {
		case "left":
		    this.node.leftpos = (smallimage.pos.l - smallimage.bleft - Math.abs(settings.xOffset) - settings.zoomWidth > 0) ? (0 - settings.zoomWidth - Math.abs(settings.xOffset)) : (smallimage.ow + Math.abs(settings.xOffset));
		    this.node.toppos = Math.abs(settings.yOffset);
		    break;
		case "top":
		    this.node.leftpos = Math.abs(settings.xOffset);
		    this.node.toppos = (smallimage.pos.t - smallimage.btop - Math.abs(settings.yOffset) - settings.zoomHeight > 0) ? (0 - settings.zoomHeight - Math.abs(settings.yOffset)) : (smallimage.oh + Math.abs(settings.yOffset));
		    break;
		case "bottom":
		    this.node.leftpos = Math.abs(settings.xOffset);
		    this.node.toppos = (smallimage.pos.t - smallimage.btop + smallimage.oh + Math.abs(settings.yOffset) + settings.zoomHeight < screen.height) ? (smallimage.oh + Math.abs(settings.yOffset)) : (0 - settings.zoomHeight - Math.abs(settings.yOffset));
		    break;
		default:
		    this.node.leftpos = (smallimage.rightlimit + Math.abs(settings.xOffset) + settings.zoomWidth < screen.width) ? (smallimage.ow + Math.abs(settings.xOffset)) : (0 - settings.zoomWidth - Math.abs(settings.xOffset));
		    this.node.toppos = Math.abs(settings.yOffset);
		    break;
		}
	    }
	    this.node.css({
		'left': this.node.leftpos + 'px',
		'top': this.node.toppos + 'px'
	    });
	    return this;
	};
	this.append = function () {
	    $('.zoomPad', el).append(this.node);
	    this.node.css({
		position: 'absolute',
		display: 'none',
		zIndex: 5001
	    });
	    if (settings.zoomType == 'innerzoom') {
		this.node.css({
		    cursor: 'default'
		});
		var thickness = (smallimage.bleft == 0) ? 1 : smallimage.bleft;
		$('.zoomWrapper', this.node).css({
		    borderWidth: thickness + 'px'
		});    
	    }
	    
	      $('.zoomWrapper', this.node).css({
		  width: Math.round(settings.zoomWidth) + 'px' ,
		  borderWidth: thickness + 'px'
	      });
	      $('.zoomWrapperImage', this.node).css({
		  width: '100%',
		  height: Math.round(settings.zoomHeight) + 'px'
	      });
	      //zoom title
	     $('.zoomWrapperTitle', this.node).css({
		    width: '100%',
		    position: 'absolute'
	      });  
	  
	    $('.zoomWrapperTitle', this.node).hide();
	    if (settings.title && zoomtitle.length > 0) {
		$('.zoomWrapperTitle', this.node).html(zoomtitle).show();
	    }
	    $obj.setposition();
	};
	this.hide = function () {
	    switch (settings.hideEffect) {
	    case 'fadeout':
		this.node.fadeOut(settings.fadeoutSpeed, function () {});
		break;
	    default:
		this.node.hide();
		break;
	    }
	    this.ieframe.hide();
	};
	this.show = function () {
	    switch (settings.showEffect) {
	    case 'fadein':
		this.node.fadeIn();
		this.node.fadeIn(settings.fadeinSpeed, function () {});
		break;
	    default:
		this.node.show();
		break;
	    }
	    if (isIE6 && settings.zoomType != 'innerzoom') {
		this.ieframe.width = this.node.width();
		this.ieframe.height = this.node.height();
		this.ieframe.left = this.node.leftpos;
		this.ieframe.top = this.node.toppos;
		this.ieframe.css({
		    display: 'block',
		    position: "absolute",
		    left: this.ieframe.left,
		    top: this.ieframe.top,
		    zIndex: 99,
		    width: this.ieframe.width + 'px',
		    height: this.ieframe.height + 'px'
		});
		$('.zoomPad', el).append(this.ieframe);
		this.ieframe.show();
	    };
	};
    };
subcode: define_Largeimage
    /*========================================================,
    |   LargeImage
    |---------------------------------------------------------:
    |   The large detailed image
    `========================================================*/

    function Largeimage() {
	var $obj = this;
	this.node = new Image();
	this.loadimage = function (url) {
	    //showing preload
	    loader.show();
	    this.url = url;
	    this.node.style.position = 'absolute';
	    this.node.style.border = '0px';
	    this.node.style.display = 'none';
	    this.node.style.left = '-5000px';
	    this.node.style.top = '0px';
	    document.body.appendChild(this.node);
	    this.node.src = url; // fires off async
	};
	this.fetchdata = function () {
	    var image = $(this.node);
	    var scale = {};
	    this.node.style.display = 'block';
	    $obj.w = image.width();
	    $obj.h = image.height();
	    $obj.pos = image.offset();
	    $obj.pos.l = image.offset().left;
	    $obj.pos.t = image.offset().top;
	    $obj.pos.r = $obj.w + $obj.pos.l;
	    $obj.pos.b = $obj.h + $obj.pos.t;
	    scale.x = ($obj.w / smallimage.w);
	    scale.y = ($obj.h / smallimage.h);
	    el.scale = scale;
	    document.body.removeChild(this.node);
	    $('.zoomWrapperImage', el).empty().append(this.node);
	    //setting lens dimensions;
	    lens.setdimensions();
	};
	this.node.onerror = function () {
	    alert('Problems while loading the big image.');
	    throw 'Problems while loading the big image.';
	};
	this.node.onload = function () {
	    //fetching data
	    $obj.fetchdata();
	    loader.hide();
	    el.largeimageloading = false;
	    el.largeimageloaded = true;
	    if (settings.zoomType == 'drag' || settings.alwaysOn) {
		lens.show();
		stage.show();
		lens.setcenter();
	    }
	};
	this.setposition = function () {
	    var left = -el.scale.x * (lens.getoffset().left - smallimage.bleft + 1);
	    var top = -el.scale.y * (lens.getoffset().top - smallimage.btop + 1);
	    $(this.node).css({
		'left': left + 'px',
		'top': top + 'px'
	    });
	};
	return this;
    };
# -----------------------------------------------------------
subcode: global_variables
    //GLOBAL VARIABLES
    var isIE6 = ($.browser.msie && $.browser.version < 7);
    var body = $(document.body);
    var window = $(window);
    var jqzoompluging_disabled = false; //disabilita globalmente il plugin

subcode: default_options
    zoomType: 'standard',
    //innerzoom/standard/reverse/drag
    zoomWidth: 300,
    //zoomWindow  default width
    zoomHeight: 300,
    //zoomWindow  default height
    xOffset: 10,
    //zoomWindow x offset, can be negative(more on the left) or positive(more on the right)
    yOffset: 0,
    //zoomWindow y offset, can be negative(more on the left) or positive(more on the right)
    position: "right",
    //zoomWindow default position
    preloadImages: true,
    //image preload
    preloadText: 'Loading zoom',
    title: true,
    lens: true,
    imageOpacity: 0.4,
    alwaysOn: false,
    showEffect: 'show',
    //show/fadein
    hideEffect: 'hide',
    //hide/fadeout
    fadeinSpeed: 'slow',
    //fast/slow/number
    fadeoutSpeed: '2000' //fast/slow/number

subcode: fn_dis_en_able
    disable: function (el) {
	var api = $(el).data('jqzoom');
	api.disable();
	return false;
    },
    enable: function (el) {
	var api = $(el).data('jqzoom');
	api.enable();
	return false;
    },
    disableAll: function (el) {
	jqzoompluging_disabled = true;
    },
    enableAll: function (el) {
	jqzoompluging_disabled = false;
    }

To compile, mydef_page.pl -m general jqzoom.def, the output is jqzoom.js, which should be the same as the original version.

Clone this wiki locally