Investigation on PhotoSwipe - 01

58 篇文章 0 订阅
10 篇文章 0 订阅

Yes, this lib: http://www.photoswipe.com/


photoswipe-prev


I will break down the jQuery version, and walk through the js source code piece by piece.


Slice-01:


(function (window) {
	
	if (!Function.prototype.bind ) {

		Function.prototype.bind = function( obj ) 
		{
			
		};
	}

	
	if (typeof window.Code === "undefined") 
	{
		window.Code = {};
	}
	
	
	window.Code.Util = {
		
		
		/*
		 * Function: registerNamespace
		 */			
		registerNamespace: function () 
		{
			
		},
		
		
		/*
		 * Function: coalesce
		 * Takes any number of arguments and returns the first non Null / Undefined argument.
		 */
		coalesce: function () 
		{
			
		},
		
		
		/*
		 * Function: extend
		 */
		extend: function(destination, source, overwriteProperties)
		{
			
		},
		
		...
		
	};
	
}(window));

First of all, let's talk about the pattern in the above block, if we remove all the code in function body, it leaves:

(function (window) {}(window));

And that means to define an anonymous function with one argument named window, and then immediately call it, passing window to it. As we know already, window is a built-in object in Jjavascript runtime, and its actually the root object of all global variables and functions.


Inside this function, it defines bind() method for Function class. And define window.Code object to serve as a namespace, under this namespace, it defines Util: window.Code.Util, which holds a collection of global utility functions.


Slice-02:


(function(window, Util) {
	
	Util.Browser = {
	
		ua: null,
		version: null,
		safari: null,
		webkit: null,
		opera: null,
		msie: null,
		chrome: null,
		mozilla: null,
		
		android: null,
		blackberry: null,
		iPad: null,
		iPhone: null,
		iPod: null,
		iOS: null,
		
		is3dSupported: null,
		isCSSTransformSupported: null,
		isTouchSupported: null,
		isGestureSupported: null,
		
		
		_detect: function()
		{
			
		},
		
			
		_eventTagNames: {
			'select':'input',
			'change':'input',
			'submit':'form',
			'reset':'form',
			'error':'img',
			'load':'img',
			'abort':'img'
		},
				
				
		/*
		 * Function: isEventSupported
		 * http://perfectionkills.com/detecting-event-support-without-browser-sniffing/
		 */
		isEventSupported: function(eventName) 
		{

		},
		
		
		isLandscape: function()
		{
		
		}
  };
	
	Util.Browser._detect();
	
}
(
	window,
	window.Code.Util
));

This block defines a property Browser on Util, it has its member variables, to store the information about the environment, and further more, this block calles _detect() of Browser. 


Slice-03:


(function (window, $, Util) {
	
	Util.extend( Util, 
				{
					
					Events: 
					{
					
					}	// end of Events
				
				}
	);	// end of extend function call
	
}
(
	window,
	window.jQuery,
	window.Code.Util
));

This block declare an object: Event, to get together the functions operate on event, and then merge it with Util. And please note that it use jQuery functions in terms of some basic tasks.


Slice-04:

(function (window, $, Util) {
	
	Util.extend(Util, 
				{
					DOM: 
					{

					}	// end of DOM
				
					
				}
	);	// end of extend function call
		
}
(
	window,
	window.jQuery,
	window.Code.Util
));

This block declare an object: DOM, and its methods are almost proxy functions of jQuery DOM methods, and then merge it with Util.


Slice-05:

(function (window, Util) {
	
	Util.extend(Util, 
	
				{
					
					Animation: 
					{
					
						
					}	// end of Animation
					
					
				}
	
	);	// end of extend function call
	
	
}
(
	window,
	window.Code.Util
));

What this block does is similar to the previous ones, it defines some wrapper functions of jQuery methods, not just proxies, because it tries to solve it with HTML5 features firstly, and if those features were not supported, it then falls to use jQuery, let's take a look:

/*
 * Function: fadeIn
 */
fadeIn: function(el, speed, callback, timingFunction, opacity){
	
	opacity = Util.coalesce(opacity, 1);
	if (opacity <= 0)
	{
		opacity = 1;
	}
	
	if (speed <= 0)
	{
		Util.DOM.setStyle(el, 'opacity', opacity);
		if (!Util.isNothing(callback))
		{
			callback(el);
			return;
		}
	}
	
	var currentOpacity = Util.DOM.getStyle(el, 'opacity');
	
	if (currentOpacity >= 1)
	{
		Util.DOM.setStyle(el, 'opacity', 0);
	}
	
	if (Util.Browser.isCSSTransformSupported)
	{
		this._applyTransition(el, 'opacity', opacity, speed, callback, timingFunction);
	}
	else if (!Util.isNothing(window.jQuery))
	{
		window.jQuery(el).fadeTo(speed, opacity, callback);
	}
	
},

In this fadeIn function definition, after some validation on the arguments, it would call _applyTransition method if CSS transform is supported, and otherwise it call jQuery fadeTo(). And how _applyTransition works:

/*
 * Function: _applyTransition
 */
_applyTransition: function(el, property, val, speed, callback, timingFunction){
		
	var style = {};
	
	timingFunction = Util.coalesce(timingFunction, 'ease-in');
	
	style[this._transitionPrefix + 'Property'] = property;
	style[this._transitionPrefix + 'Duration'] = speed + 'ms';
	style[this._transitionPrefix + 'TimingFunction'] = timingFunction;
	style[this._transitionPrefix + 'Delay'] = '0';
	
	Util.Events.add(el, this._transitionEndLabel, this._getTransitionEndHandler());
	
	Util.DOM.setStyle(el, style);
	
	if (!Util.isNothing(callback))
	{
		el['ccl' + property + 'callback'] = callback;
	}
	
	window.setTimeout(function(){
		Util.DOM.setStyle(el, property, val);
	}, this._applyTransitionDelay);	
	
},

That may involve some approaches of setting animation with HTML5, it sets style object with values that specify animations parameters, and apply it to the element, and set up a timer to update the target value of property after the period delay indicates. We can ignore the details here as we haven't finished <HTML5> and continue.



Slice-06:

(function(window, klass, Util){
	
	Util.registerNamespace('Code.Util.TouchElement');
	
	Util.TouchElement.EventTypes = {
		onTouch: 'CodeUtilTouchElementOnTouch'
	};
	
	Util.TouchElement.ActionTypes = {
		touchStart: 'touchStart',
		...
	
	};
	
}
(
	window, 
	window.klass, 
	window.Code.Util
));

(function(window, klass, Util){
	
	Util.registerNamespace('Code.Util.TouchElement');
	
	Util.TouchElement.TouchElementClass = klass(
		{
			el: null,
			captureSettings: null,
			...
			
			/*
			 * Function: dispose
			 */
			dispose: function(){},

			/*
			 * Function: initialize
			 */
			initialize: function(el, captureSettings){},
			
			...
		}
	);
	
}
(
	window, 
	window.klass, 
	window.Code.Util
));

This class is the key to turn the touch event capturable, it plays as a proxy, it listens to basic touch event and basic mouse event, and it maps all mouse event to corresponding touch events, it also determines if some complicated touch event occurs based on setting, and dispatches them. BTW, the complicated touch events include: swipe left, double tap and so on.   


klass

So klass is somehow a kind of 3rd-party lib that ease your implementation of OOP design, to make the inheritance more like those strict OOP languages. That is why its name is k(c)lass. According to docs, initialize() method will be called automatically when the class invocation.


At this point, I think we can figure out the overall hierarchy of the namespaces, by using Chrome utility:


overall-namespace-hierarchy


Slice-07:

(function(window, klass, Util){
	
	Util.registerNamespace('Code.PhotoSwipe.Image');
	var PhotoSwipe = window.Code.PhotoSwipe;

	PhotoSwipe.Image.EventTypes = { onLoad: 'onLoad', onError: 'onError' };
}
(
	window, 
	window.klass, 
	window.Code.Util
));

(function(window, klass, Util){
	
	Util.registerNamespace('Code.PhotoSwipe.Image');
	var PhotoSwipe = window.Code.PhotoSwipe;
	
	PhotoSwipe.Image.ImageClass = 
	klass(
		{
			
			refObj: null,
			imageEl: null,
			...
			
			/*
			 * Function: dispose
			 */
			dispose: function(){},
			...
			
		}
	);
	
}
(
	window, 
	window.klass, 
	window.Code.Util
));	




Now we start to explore PhotoSwipe namespace and this is Image and ImageClass, it represents 


Slice-08:

(function(window, klass, Util){
	
	Util.registerNamespace('Code.PhotoSwipe.Cache');
	var PhotoSwipe = window.Code.PhotoSwipe;
	
	PhotoSwipe.Cache.Mode = {
		
		normal: 'normal',
		aggressive: 'aggressive'
		
	};
	
	PhotoSwipe.Cache.Functions = {
		
		getImageSource: function(el){},
	
		getImageCaption: function(el){},

		getImageMetaData: function(el){}
		
	};

}
(
	window, 
	window.klass, 
	window.Code.Util
)
);

(function(window, klass, Util){

	Util.registerNamespace('Code.PhotoSwipe.Cache');
	var PhotoSwipe = window.Code.PhotoSwipe;
	
	
	PhotoSwipe.Cache.CacheClass = klass({
		
		images: null,
		settings: null,
		
		dispose: function(){},
		...
		
	});
	
}
(
	window, 
	window.klass, 
	window.Code.Util,
	window.Code.PhotoSwipe.Image
));		


This block defines Cacheand CacheClass.


Slice-09:

(function(window, klass, Util){
	
	Util.registerNamespace('Code.PhotoSwipe.DocumentOverlay');
	var PhotoSwipe = window.Code.PhotoSwipe;
	
	PhotoSwipe.DocumentOverlay.CssClasses = {
		documentOverlay: 'ps-document-overlay'
	};
	
}
(
	window, 
	window.klass, 
	window.Code.Util
));
(function(window, klass, Util){
	
	Util.registerNamespace('Code.PhotoSwipe.DocumentOverlay');
	var PhotoSwipe = window.Code.PhotoSwipe;
	
	PhotoSwipe.DocumentOverlay.DocumentOverlayClass = klass({
		
		el: null,
		settings: null,
		initialBodyHeight: null,
				
		dispose: function(){},
		...
	});
	
	
}
(
	window, 
	window.klass, 
	window.Code.Util
));


This block defines DocumentOverlayand DocumentOverlayClass.


Slice-10:

(function(window, klass, Util){
	
	Util.registerNamespace('Code.PhotoSwipe.Carousel');
	var PhotoSwipe = window.Code.PhotoSwipe;
	
	PhotoSwipe.Carousel.EventTypes = {};
	PhotoSwipe.Carousel.CssClasses = {};
	PhotoSwipe.Carousel.SlideByAction = {};
}
(
	window, 
	window.klass, 
	window.Code.Util
));

(function(window, klass, Util){
	
	Util.registerNamespace('Code.PhotoSwipe.Carousel');
	var PhotoSwipe = window.Code.PhotoSwipe;
	
	PhotoSwipe.Carousel.CarouselClass = klass({
		
		
		el: null,
		contentEl: null,
		...
		
		dispose: function(){},
		...
			
	});
	
}
(
	window, 
	window.klass, 
	window.Code.Util
));

(function(window, klass, Util, TouchElement){
	
	
	Util.registerNamespace('Code.PhotoSwipe.Carousel');
	var PhotoSwipe = window.Code.PhotoSwipe;
	
	PhotoSwipe.Carousel.CarouselClass = PhotoSwipe.Carousel.CarouselClass.extend({
	
		getStartingPos: function(){},
		...
	});
	
}
(
	window, 
	window.klass, 
	window.Code.Util,
	window.Code.PhotoSwipe.TouchElement
));


This block defines Carouseland CarouselClass.


Slice-11:

(function(window, klass, Util){
	
	Util.registerNamespace('Code.PhotoSwipe.Toolbar');
	var PhotoSwipe = window.Code.PhotoSwipe;
	
	PhotoSwipe.Toolbar.CssClasses = {};
	PhotoSwipe.Toolbar.ToolbarAction = {};
	PhotoSwipe.Toolbar.EventTypes = {};
	
	PhotoSwipe.Toolbar.getToolbar = function(){};
	
}
(
	window, 
	window.klass, 
	window.Code.Util
));


(function(window, klass, Util){
	
	Util.registerNamespace('Code.PhotoSwipe.Toolbar');
	var PhotoSwipe = window.Code.PhotoSwipe;
	
	PhotoSwipe.Toolbar.ToolbarClass = klass(
			{
				
				toolbarEl: null,
				closeEl: null,
				...
				
				dispose: function(){},
				...
				
			}
	);
}
(
	window, 
	window.klass, 
	window.Code.Util
));


This block defines Toolbarand ToolbarClass.


Slice-12:

(function(window, klass, Util){
	
	Util.registerNamespace('Code.PhotoSwipe.UILayer');
	var PhotoSwipe = window.Code.PhotoSwipe;
	
	PhotoSwipe.UILayer.CssClasses = {};
}
(
	window, 
	window.klass, 
	window.Code.Util
));

(function(window, klass, Util){
	
	Util.registerNamespace('Code.PhotoSwipe.UILayer');
	var PhotoSwipe = window.Code.PhotoSwipe;
	
	PhotoSwipe.UILayer.UILayerClass = Util.TouchElement.TouchElementClass.extend(
		{
		
			el: null,
			settings: null,
			
			dispose: function(){},
			...
		
		}
		
	);
	
}
(
	window, 
	window.klass, 
	window.Code.Util
));


This block defines UILayerand UILayerClass.


Slice-13:

(function(window, klass, Util){
	Util.registerNamespace('Code.PhotoSwipe.ZoomPanRotate');
	var PhotoSwipe = window.Code.PhotoSwipe;
	
	PhotoSwipe.ZoomPanRotate.CssClasses = {};
	PhotoSwipe.ZoomPanRotate.EventTypes = {};
}
(
	window, 
	window.klass, 
	window.Code.Util
));

(function(window, klass, Util){
	
	
	Util.registerNamespace('Code.PhotoSwipe.ZoomPanRotate');
	var PhotoSwipe = window.Code.PhotoSwipe;
	
	PhotoSwipe.ZoomPanRotate.ZoomPanRotateClass = klass(
		{
	
			el: null,
			settings: null,
			...
			
			dispose: function(){},
			...
		
		}
	);
	
}
(
	window, 
	window.klass, 
	window.Code.Util
));


This block defines ZoomPanRotateand ZoomPanRotateClass.


Slice-14:

(function(window, Util){
	
	Util.registerNamespace('Code.PhotoSwipe');
	var PhotoSwipe = window.Code.PhotoSwipe;
	
	PhotoSwipe.CssClasses = {};
	
	PhotoSwipe.EventTypes = {};
	
	PhotoSwipe.instances = [];
	PhotoSwipe.activeInstances = [];
	
	PhotoSwipe.setActivateInstance = function(instance){};
	PhotoSwipe.unsetActivateInstance = function(instance){};
	PhotoSwipe.attach = function(images, options, id){};

	if (window.jQuery){
		
		window.jQuery.fn.photoSwipe = function(options, id){
		
			return PhotoSwipe.attach(this, options, id);
			
		};
		
	}
	
	PhotoSwipe.detatch = function(instance){};
	
}
(
	window, 
	window.Code.Util
));


This block defines PhotoSwipe.


Slice-15:

(function(window, klass, Util, Cache, DocumentOverlay, Carousel, Toolbar, UILayer, ZoomPanRotate){
	
	Util.registerNamespace('Code.PhotoSwipe');
	var PhotoSwipe = window.Code.PhotoSwipe;
	
	PhotoSwipe.PhotoSwipeClass = klass(
		{
			id: null,
			settings: null,
			...
			
			dispose: function(){},
			initialize: function(images, options, id){},
			...
			
		}
	);
	
}
(
	window, 
	window.klass, 
	window.Code.Util,
	window.Code.PhotoSwipe.Cache,
	window.Code.PhotoSwipe.DocumentOverlay,
	window.Code.PhotoSwipe.Carousel,
	window.Code.PhotoSwipe.Toolbar,
	window.Code.PhotoSwipe.UILayer,
	window.Code.PhotoSwipe.ZoomPanRotate
));


This block define PhotoSwipeClass.




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值