1785 lines
		
	
	
		
			52 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			1785 lines
		
	
	
		
			52 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| /**@license boxplus: a versatile lightweight pop-up window engine for MooTools
 | |
|  * @author  Levente Hunyadi
 | |
|  * @version 0.9.3
 | |
|  * @remarks Copyright (C) 2009-2011 Levente Hunyadi
 | |
|  * @remarks Licensed under GNU/GPLv3, see http://www.gnu.org/licenses/gpl-3.0.html
 | |
|  * @see     http://hunyadi.info.hu/projects/boxplus
 | |
|  **/
 | |
| 
 | |
| /*
 | |
| * boxplus: a versatile lightweight pop-up window engine for MooTools
 | |
| * Copyright 2009-2011 Levente Hunyadi
 | |
| *
 | |
| * boxplus is free software: you can redistribute it and/or modify
 | |
| * it under the terms of the GNU General Public License as published by
 | |
| * the Free Software Foundation, either version 3 of the License, or
 | |
| * (at your option) any later version.
 | |
| *
 | |
| * boxplus is distributed in the hope that it will be useful,
 | |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | |
| * GNU General Public License for more details.
 | |
| *
 | |
| * You should have received a copy of the GNU General Public License
 | |
| * along with boxplus.  If not, see <http://www.gnu.org/licenses/>.
 | |
| */
 | |
| 
 | |
| /*
 | |
| * Requires MooTools Core 1.2 or later.
 | |
| * Picasa support requires Request.JSONP from MooTools 1.2 More or later.
 | |
| *
 | |
| * Annotated for use with Google Closure Compiler's advanced optimization
 | |
| * method when supplemented with a MooTools extern file.
 | |
| *
 | |
| * Search for "EDIT OPTIONS" to find out where to modify default settings.
 | |
| */
 | |
| 
 | |
| ;
 | |
| (function ($) {
 | |
| 	Object.append(Element['NativeEvents'], {
 | |
| 		'popstate': 2,
 | |
| 		'dragstart': 2  // listen to browser-native drag-and-drop events
 | |
| 	});
 | |
| 
 | |
| 	/**
 | |
| 	* Converts a query string into an object.
 | |
| 	* @param {string} querystring
 | |
| 	* @return {!Object}
 | |
| 	*/
 | |
| 	function fromQueryString(querystring) {
 | |
| 		var data = {};
 | |
| 		if (querystring.length > 1) {
 | |
| 			querystring.substr(1).split('&').each(function (keyvalue) {
 | |
| 				var index = keyvalue.indexOf('=');
 | |
| 				var key = index >= 0 ? keyvalue.substr(0,index) : keyvalue;
 | |
| 				var value = index >= 0 ? keyvalue.substr(index+1) : '';
 | |
| 				data[unescape(key)] = unescape(value);
 | |
| 			});
 | |
| 		}
 | |
| 		return data;
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	* Identifier of boxplus container element.
 | |
| 	* @type {string}
 | |
| 	* @const
 | |
| 	*/
 | |
| 	var BOXPLUS_ID = 'boxplus';
 | |
| 	/**
 | |
| 	* @type {string}
 | |
| 	* @const
 | |
| 	*/
 | |
| 	var BOXPLUS_HIDDEN = 'boxplus-hidden';
 | |
| 	/**
 | |
| 	* @type {string}
 | |
| 	* @const
 | |
| 	*/
 | |
| 	var BOXPLUS_DISABLED = 'boxplus-disabled';
 | |
| 	/**
 | |
| 	* @type {string}
 | |
| 	* @const
 | |
| 	*/
 | |
| 	var BOXPLUS_UNAVAILABLE = 'boxplus-unavailable';
 | |
| 	/**
 | |
| 	* Time between successive scroll animations [ms].
 | |
| 	* @type {number}
 | |
| 	* @const
 | |
| 	*/
 | |
| 	var BOXPLUS_SCROLL_INTERVAL = 10;
 | |
| 	/**
 | |
| 	* Key under which the cloaked href attribute of the anchor should be stored in the mootools Elements storage.
 | |
| 	* @type {string}
 | |
| 	* @const
 | |
| 	*/
 | |
| 	var BOXPLUS_HREF = 'boxplus-href';
 | |
| 
 | |
| 	/**
 | |
| 	* Cloaks an anchor href attribute by moving it to the Elements Storage.
 | |
| 	* @param {Element} anchor
 | |
| 	*/
 | |
| 	function cloak(anchor) {
 | |
| 		if (!anchor.retrieve(BOXPLUS_HREF)) {  // prevent double-obfuscating an anchor
 | |
| 			anchor.store(BOXPLUS_HREF, anchor.get('href'));
 | |
| 			anchor.set('href', 'javascript:void(0);');
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	* Uncloaks an anchor by settings its href attribute based on the value in the Elements Storage.
 | |
| 	* @param {Element} anchor
 | |
| 	*/
 | |
| 	function uncloak(anchor) {
 | |
| 		var href = anchor.retrieve(BOXPLUS_HREF);
 | |
| 		if (href) {
 | |
| 			anchor.set('href', href);
 | |
| 			anchor.eliminate(BOXPLUS_HREF);
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	* Represents the boxplus dialog.
 | |
| 	* Events fired are 'close', 'previous', 'next', 'first', 'last', 'start', 'stop' and 'change'.
 | |
| 	*/
 | |
| 	var boxplusDialog = new Class({
 | |
| 		'Implements': [Events, Options],
 | |
| 
 | |
| 		// --- EDIT OPTIONS BELOW TO MODIFY DEFAULTS --- //
 | |
| 		// ---  SEE FURTHER BELOW FOR OTHER OPTIONS  --- //
 | |
| 
 | |
| 		/**
 | |
| 		* boxplus dialog options.
 | |
| 		* Normally, these would be configured via a boxplus gallery and not directly.
 | |
| 		*/
 | |
| 		'options': {
 | |
| 			/**
 | |
| 			* Pop-up window theme. If set, stylesheets that have a "title" attribute starting with
 | |
| 			* "boxplus" but with a different ending than specified will be disabled. For instance,
 | |
| 			* the value "darksquare" will enable the stylesheet "boxplus-darksquare" but disable
 | |
| 			* "boxplus-darkrounded" and "boxplus-lightsquare".
 | |
| 			* @type {boolean|string}
 | |
| 			*/
 | |
| 			'theme': false,
 | |
| 			/**
 | |
| 			* Whether navigation controls are displayed.
 | |
| 			* @type {boolean}
 | |
| 			*/
 | |
| 			'navigation': true,
 | |
| 			/**
 | |
| 			* Whether to center pop-up windows smaller than browser window size.
 | |
| 			* @type {boolean}
 | |
| 			*/
 | |
| 			'autocenter': true,
 | |
| 			/**
 | |
| 			* Whether to reduce images that would otherwise exceed screen dimensions to fit
 | |
| 			* the browser window when they are displayed.
 | |
| 			* @type {boolean}
 | |
| 			*/
 | |
| 			'autofit': true,
 | |
| 			/**
 | |
| 			* Duration of animation sequences. Expects a value in milliseconds, or one of 'short' or 'long'.
 | |
| 			* @type {string|number}
 | |
| 			*/
 | |
| 			'duration': 'short',
 | |
| 			/**
 | |
| 			* Easing equation to use for the transition effect.
 | |
| 			* The easing equation determines the speed at which the animation progresses
 | |
| 			* at different stages of an animation. Examples values include 'sine', 'linear' and
 | |
| 			* 'bounce'. For a complete list of supported values see the MooTools framework object
 | |
| 			* Fx.Transitions <http://mootools.net/docs/core/Fx/Fx.Transitions>.
 | |
| 			* @type {string}
 | |
| 			*/
 | |
| 			'transition': 'sine',
 | |
| 			/**
 | |
| 			* Client-side image protection feature.
 | |
| 			* This feature suppresses the browser "contextmenu" and "dragstart" events so that
 | |
| 			* a user cannot easily extract the image with conventional methods. Needless to say,
 | |
| 			* such measures are completely ineffective against advanced users who can always
 | |
| 			* extract the image from the browser cache or use developer page inspection tools
 | |
| 			* like Firebug.
 | |
| 			* @type {boolean}
 | |
| 			*/
 | |
| 			'protection': true,
 | |
| 			/**
 | |
| 			* Scroll speed [px/s].
 | |
| 			* @type {number}
 | |
| 			*/
 | |
| 			'scrollspeed': 200,
 | |
| 			/**
 | |
| 			* Acceleration factor, multiplier of scroll speed in fast scroll mode.
 | |
| 			* @type {number}
 | |
| 			*/
 | |
| 			'scrollfactor': 5,
 | |
| 			/**
 | |
| 			* Default width if no width is specified or can be derived.
 | |
| 			* @type {number}
 | |
| 			*/
 | |
| 			'width': 800,
 | |
| 			/**
 | |
| 			* Default height if no height is specified or can be derived.
 | |
| 			* @type {number}
 | |
| 			*/
 | |
| 			'height': 600
 | |
| 		},
 | |
| 
 | |
| 		// --- END OF DEFAULT OPTIONS --- //
 | |
| 
 | |
| 		// Properties assigned on initialization:
 | |
| 		//    container,
 | |
| 		//    shadedbackground,
 | |
| 		//    popup,
 | |
| 		//    viewer,
 | |
| 		//    viewerimage,
 | |
| 		//    viewerframe,
 | |
| 		//    viewervideo,
 | |
| 		//    viewerobject,
 | |
| 		//    viewercontent
 | |
| 		//    thumbs
 | |
| 
 | |
| 		/**
 | |
| 		* Download URL associated with the current item.
 | |
| 		* @type {string}
 | |
| 		*/
 | |
| 		_url: '',
 | |
| 		/**
 | |
| 		* Actual dimensions of the current item.
 | |
| 		*/
 | |
| 		_imagedims: null,
 | |
| 
 | |
| 		/**
 | |
| 		* Timer used in animating the progress indicator.
 | |
| 		*/
 | |
| 		_progresstimer: null,
 | |
| 		/**
 | |
| 		* Timer used in scrolling the quick-access navigation bar.
 | |
| 		*/
 | |
| 		_scrolltimer: null,
 | |
| 		/**
 | |
| 		* Current speed of the quick-access navigation bar.
 | |
| 		* @type {number}
 | |
| 		*/
 | |
| 		_scrollspeed: 0,
 | |
| 
 | |
| 		/**
 | |
| 		* Injects the pop-up window HTML code into the document.
 | |
| 		*/
 | |
| 		'initialize': function (options) {
 | |
| 			this['setOptions'](options);  // protect "setOptions" from being renamed during minification
 | |
| 
 | |
| 			var self = this;
 | |
| 			self.decelerateScroll();
 | |
| 
 | |
| 			/**
 | |
| 			* Creates a boxplus pop-up window element.
 | |
| 			* @param {string|Array.<string>} cls A class name or array of class names to apply to the element.
 | |
| 			* @param {!Object=} attrs An object of attributes to apply to the element.
 | |
| 			* @param {...Element} children Child elements to inject into the element.
 | |
| 			* @return {Element}
 | |
| 			*/
 | |
| 			function _create(cls, attrs, children) {
 | |
| 				var elem = new Element('div', {
 | |
| 					'class': typeof(cls) == 'string' ? 'boxplus-' + cls : cls.map(function (classname) { return 'boxplus-' + classname; }).join(' ')
 | |
| 				});
 | |
| 				if (attrs) {
 | |
| 					elem.set(attrs);
 | |
| 				}
 | |
| 				for (var i = 2; i < arguments.length; i++) {
 | |
| 					elem.adopt(arguments[i]);
 | |
| 				}
 | |
| 				return elem;
 | |
| 			}
 | |
| 
 | |
| 			/**
 | |
| 			* @return {Element}
 | |
| 			*/
 | |
| 			function _message(cls) {
 | |
| 				return new Element('span', {
 | |
| 					'class': 'boxplus-' + cls
 | |
| 				});
 | |
| 			}
 | |
| 
 | |
| 			/**
 | |
| 			* Binds a callback function to an event.
 | |
| 			* @param {function()} callback The callback function to subscribe for the event.
 | |
| 			* @param {string=} eventtype The name of the event.
 | |
| 			*/
 | |
| 			function _bind(cls, callback, eventtype) {
 | |
| 				if (!eventtype) {
 | |
| 					eventtype = 'click';
 | |
| 				}
 | |
| 				self._getElements(cls).addEvent(eventtype, callback.bind(self));
 | |
| 			}
 | |
| 
 | |
| 			// navigation controls in the quick-access navigation bar
 | |
| 			var thumbselem = _create('thumbs', {},
 | |
| 				new Element('ul'),
 | |
| 				_create('rewind'),
 | |
| 				_create('forward')
 | |
| 			);
 | |
| 
 | |
| 			// title and text for caption
 | |
| 			var captionelem = _create('caption', {},
 | |
| 				_create('title'),
 | |
| 				_create('text')
 | |
| 			);
 | |
| 
 | |
| 			// control buttons outside the image area
 | |
| 			var controlselem = _create('controls', {},
 | |
| 				_create('prev'),
 | |
| 				_create('next'),
 | |
| 				_create('start'),
 | |
| 				_create(['stop','unavailable']),
 | |
| 				_create('close'),
 | |
| 				_create('download'),
 | |
| 				_create('metadata')
 | |
| 			);
 | |
| 
 | |
| 			/**
 | |
| 			* @type {string}
 | |
| 			* @const
 | |
| 			*/
 | |
| 			var HIDDEN = 'hidden';
 | |
| 			self.container = _create([], {id: BOXPLUS_ID},
 | |
| 				self.shadedbackground = _create(['background',HIDDEN]),
 | |
| 				self.popup = _create(['dialog',HIDDEN], {},
 | |
| 					_create('progress'),
 | |
| 					_create('sideways', {},
 | |
| 						thumbselem.clone(),
 | |
| 						controlselem.clone(),
 | |
| 						captionelem.clone()
 | |
| 					),
 | |
| 					_create('title'),
 | |
| 					_create('main', {},
 | |
| 						self.centerpanel = _create('center', {},
 | |
| 							self.viewer = _create(['viewer',HIDDEN], {},
 | |
| 								/** @type {HTMLImageElement} */
 | |
| 								self.viewerimage = new Element('img'),
 | |
| 								_create('prev'),
 | |
| 								_create('next'),
 | |
| 								_create('resizer', {},
 | |
| 									_create('enlarge').addEvent('click', function () { self.magnify(); }),
 | |
| 									_create(['shrink','unavailable']).addEvent('click', function () { self.magnify(); })
 | |
| 								),
 | |
| 								self.thumbs = thumbselem.clone(),
 | |
| 								/** @type {HTMLIFrameElement} */
 | |
| 								self.viewerframe = new Element('iframe', {
 | |
| 									'frameborder': 0
 | |
| 								}),
 | |
| 								/** @type {HTMLVideoElement} */
 | |
| 								self.viewervideo = new Element('video', {
 | |
| 									'autoplay': true,
 | |
| 									'controls': true
 | |
| 								}),
 | |
| 								/** @type {HTMLObjectElement} */
 | |
| 								self.viewerobject = _create('object'),
 | |
| 								/** @type {HTMLDivElement} */
 | |
| 								self.viewercontent = _create('content'),
 | |
| 								_create('progress')
 | |
| 							)
 | |
| 						),
 | |
| 						_create('bottom', {},
 | |
| 							thumbselem.clone(),
 | |
| 							controlselem.clone(),
 | |
| 							captionelem.clone()
 | |
| 						)
 | |
| 					),
 | |
| 					_create('lt'),
 | |
| 					_create('t'),
 | |
| 					_create('rt'),
 | |
| 					_create('l'),
 | |
| 					_create(['m',HIDDEN]),
 | |
| 					_create('r'),
 | |
| 					_create('lb'),
 | |
| 					_create('b'),
 | |
| 					_create('rb')
 | |
| 				),
 | |
| 
 | |
| 				self.popupclone = _create(['dialog',HIDDEN], {},
 | |
| 					self.sidewaysclone = _create('sideways', {},
 | |
| 						thumbselem.clone(),
 | |
| 						captionelem.clone(),
 | |
| 						controlselem.clone()
 | |
| 					),
 | |
| 					_create('title'),
 | |
| 					_create('main', {},
 | |
| 						self.centerclone = _create('center', {},
 | |
| 							self.viewerclone = _create(['viewer',HIDDEN], {},
 | |
| 								self.viewercontentclone = new Element('div')
 | |
| 							)
 | |
| 						),
 | |
| 						self.bottomclone = _create('bottom', {},
 | |
| 							thumbselem.clone(),
 | |
| 							captionelem.clone(),
 | |
| 							controlselem.clone()
 | |
| 						)
 | |
| 					)
 | |
| 				),
 | |
| 
 | |
| 				_message('unknown-type'),
 | |
| 				_message('not-found')
 | |
| 			).inject(document.body);
 | |
| 
 | |
| 			// close window when user clicks outside window area (but not on mobile devices)
 | |
| 			if (self.container.getStyle('background-repeat') == 'repeat') {  // test for CSS @media handheld
 | |
| 				self.shadedbackground.addEvent('click', function () { self.close(); });
 | |
| 			}
 | |
| 
 | |
| 			/**
 | |
| 			* Fired when the user right-clicks or starts to drag an item in the viewer to open the context menu or copy an image.
 | |
| 			* @param {Event} event An event object.
 | |
| 			*/
 | |
| 			self._onProhibitedUIAction = function (event) {
 | |
| 				return !self.options['protection'] || !self.viewer.getElements('*').contains(event.target);
 | |
| 			};
 | |
| 
 | |
| 			/**
 | |
| 			* Fired when the user presses a key while the lightweight pop-up window is shown.
 | |
| 			* @param {Event} event An event object.
 | |
| 			*/
 | |
| 			self._onKeyDown = function (event) {
 | |
| 				if (!['input','textarea'].contains($(event.target).get('tag'))) {  // let form elements handle their own input
 | |
| 					var keyindex = [37,39,36,35,13,27].indexOf(event.code);  // keys are [left arrow, right arrow, home, end, ENTER, ESC]
 | |
| 					if (keyindex >= (self['options']['navigation'] ? 0 : 4)) {  // ignore navigation keys if navigation buttons are disabled
 | |
| 						[self.previous,self.next,self.first,self.last,self.magnify,self.close][keyindex].bind(self)();  // call function with proper context for "this"
 | |
| 						return false;  // cancel event propagation
 | |
| 					}
 | |
| 				}
 | |
| 			};
 | |
| 
 | |
| 			/**
 | |
| 			* Fired when the user resizes the browser window while the lightweight pop-up window is shown.
 | |
| 			*/
 | |
| 			var resizeTimer;
 | |
| 			self._onResize = function () {
 | |
| 				window.clearTimeout(resizeTimer);
 | |
| 				if (!self.resizing) {
 | |
| 					resizeTimer = window.setTimeout(function () {
 | |
| 						self.resize.bind(self)();
 | |
| 					}, 10);
 | |
| 				}
 | |
| 			};
 | |
| 
 | |
| 			_bind('prev', self.previous);
 | |
| 			_bind('next', self.next);
 | |
| 			_bind('start', self.start);
 | |
| 			_bind('stop', self.stop);
 | |
| 			_bind('close', self.close);
 | |
| 			_bind('download', self.download);
 | |
| 			_bind('metadata', self.toggleMetadata);
 | |
| 			_bind('rewind', self.startRewind, 'mouseover');
 | |
| 			_bind('rewind', self.stopScroll, 'mouseout');
 | |
| 			_bind('rewind', self.accelerateScroll, 'mousedown')
 | |
| 			_bind('rewind', self.decelerateScroll, 'mouseup')
 | |
| 			_bind('forward', self.startForward, 'mouseover');
 | |
| 			_bind('forward', self.stopScroll, 'mouseout');
 | |
| 			_bind('forward', self.accelerateScroll, 'mousedown')
 | |
| 			_bind('forward', self.decelerateScroll, 'mouseup')
 | |
| 
 | |
| 			self.setEmpty();
 | |
| 		},
 | |
| 
 | |
| 		/**
 | |
| 		* @param {string|Array.<string>} cls
 | |
| 		* @return {string}
 | |
| 		*/
 | |
| 		_class: function (cls) {
 | |
| 			return Array.from(cls).map(function (selector) {
 | |
| 				return selector.replace(/\b([\w-]+)/g, '.boxplus-$1');
 | |
| 			}).join(', ');
 | |
| 		},
 | |
| 		/**
 | |
| 		* @param {string|Array.<string>} cls
 | |
| 		* @return {Element}
 | |
| 		*/
 | |
| 		_getElement: function (cls) {
 | |
| 			return this.popup.getElement(this._class(cls));
 | |
| 		},
 | |
| 		/**
 | |
| 		* @param {string|Array.<string>} cls
 | |
| 		* @return {Elements}
 | |
| 		*/
 | |
| 		_getElements: function (cls) {
 | |
| 			return this.popup.getElements(this._class(cls));
 | |
| 		},
 | |
| 		/**
 | |
| 		* @param {string|Array.<string>} cls
 | |
| 		* @return {Elements}
 | |
| 		*/
 | |
| 		_getClonedElements: function (cls) {
 | |
| 			return this.popupclone.getElements(this._class(cls));
 | |
| 		},
 | |
| 		_toggle: function (cls, clstoggle, state) {
 | |
| 			this._getElements(cls)[state ? 'addClass' : 'removeClass'](clstoggle);
 | |
| 		},
 | |
| 		_toggleCloned: function (cls, clstoggle, state) {
 | |
| 			this._getClonedElements(cls)[state ? 'addClass' : 'removeClass'](clstoggle);
 | |
| 		},
 | |
| 		setAvailable: function (cls, state) {
 | |
| 			this._toggle(cls, BOXPLUS_UNAVAILABLE, !state);
 | |
| 		},
 | |
| 		setAllAvailable: function (cls, state) {
 | |
| 			this._toggle(cls, BOXPLUS_UNAVAILABLE, !state);
 | |
| 			this._toggleCloned(cls, BOXPLUS_UNAVAILABLE, !state);
 | |
| 		},
 | |
| 		setEnabled: function (cls, state) {
 | |
| 			this._toggle(cls, BOXPLUS_DISABLED, !state);
 | |
| 		},
 | |
| 		setAllEnabled: function (cls, state) {
 | |
| 			this._toggle(cls, BOXPLUS_DISABLED, !state);
 | |
| 			this._toggleCloned(cls, BOXPLUS_DISABLED, !state);
 | |
| 		},
 | |
| 		setVisible: function (cls, state) {
 | |
| 			this._toggle(cls, BOXPLUS_HIDDEN, !state);
 | |
| 		},
 | |
| 		setAllVisible: function (cls, state) {
 | |
| 			this._toggle(cls, BOXPLUS_HIDDEN, !state);
 | |
| 			this._toggleCloned(cls, BOXPLUS_HIDDEN, !state);
 | |
| 		},
 | |
| 		_bindEvents: function (events, state) {
 | |
| 			var self = this;
 | |
| 			for (var name in events) {
 | |
| 				window[state ? 'addEvent' : 'removeEvent'](name, events[name]);
 | |
| 			}
 | |
| 		},
 | |
| 		_fireEvent: function (event, arg) {
 | |
| 			this['fireEvent'](event, arg);
 | |
| 		},
 | |
| 
 | |
| 		getMessage: function (msg) {
 | |
| 			return this.container.getElement('.boxplus-' + msg).get('html');
 | |
| 		},
 | |
| 
 | |
| 		/**
 | |
| 		* Shows the lightweight pop-up window.
 | |
| 		* @param {!Object} options
 | |
| 		*/
 | |
| 		show: function (options) {
 | |
| 			var self = this;
 | |
| 			self['setOptions'](options);  // prevent minification of "setOptions"
 | |
| 
 | |
| 			// enable associated theme (if any) and disable other themes that might be linked to the page
 | |
| 			var theme = self['options']['theme'];
 | |
| 			if (theme) {
 | |
| 				// disable unused themes and enable selected theme
 | |
| 				$$('link[rel=stylesheet][title^=boxplus]').set('disabled', true).filter('[title="boxplus-' + theme + '"]').set('disabled', false);
 | |
| 			}
 | |
| 
 | |
| 			// toggle navigation buttons
 | |
| 			self.setEnabled(['prev','next','start','stop'], self['options']['navigation']);
 | |
| 
 | |
| 			// show visuals
 | |
| 			self.setVisible('bottom', false);    // will be shown when resizing terminates
 | |
| 			self.setVisible('sideways', false);  // will be shown when resizing terminates
 | |
| 			self.center(self.popup);
 | |
| 			$$([self.shadedbackground, self.popup]).removeClass(BOXPLUS_HIDDEN);
 | |
| 			self.shadedbackground.fade('hide').fade('in');
 | |
| 
 | |
| 			// register events
 | |
| 			self._bindEvents({
 | |
| 				'contextmenu': self._onProhibitedUIAction,
 | |
| 				'dragstart': self._onProhibitedUIAction,
 | |
| 				'keydown': self._onKeyDown,
 | |
| 				'resize': self._onResize
 | |
| 			}, true);
 | |
| 		},
 | |
| 
 | |
| 		/**
 | |
| 		* Hides the lightweight pop-up window.
 | |
| 		* Fired when the user clicks the close button, clicks outside the pop-up window or presses the ESC key.
 | |
| 		*/
 | |
| 		hide: function () {
 | |
| 			var self = this;
 | |
| 
 | |
| 			// unregister events
 | |
| 			self._bindEvents({
 | |
| 				'contextmenu': self._onProhibitedUIAction,
 | |
| 				'dragstart': self._onProhibitedUIAction,
 | |
| 				'keydown': self._onKeyDown,
 | |
| 				'resize': self._onResize
 | |
| 			}, false);
 | |
| 
 | |
| 			// hide visuals
 | |
| 			self.shadedbackground.fade('out');
 | |
| 			$$([self.shadedbackground, self.popup]).addClass(BOXPLUS_HIDDEN);
 | |
| 		},
 | |
| 
 | |
| 		/**
 | |
| 		* Closes the pop-up window.
 | |
| 		*/
 | |
| 		close: function () {
 | |
| 			var self = this;
 | |
| 			self.setEmpty();
 | |
| 			self.resize(function () {
 | |
| 				self._fireEvent('close');
 | |
| 			});
 | |
| 		},
 | |
| 
 | |
| 		/**
 | |
| 		* Navigates to the first image/content.
 | |
| 		* Fired when the user clicks the navigate to first control or presses the HOME key.
 | |
| 		*/
 | |
| 		first: function () {
 | |
| 			this._fireEvent('first');
 | |
| 		},
 | |
| 
 | |
| 		/**
 | |
| 		* Navigates to the previous image/content.
 | |
| 		* Fired when the user clicks the navigate to previous control or presses the left arrow key.
 | |
| 		*/
 | |
| 		previous: function () {
 | |
| 			this._fireEvent('previous');
 | |
| 		},
 | |
| 
 | |
| 		/**
 | |
| 		* Navigates to the next image/content.
 | |
| 		* Fired when the user clicks the navigate to next control or presses the right arrow key.
 | |
| 		*/
 | |
| 		next: function () {
 | |
| 			this._fireEvent('next');
 | |
| 		},
 | |
| 
 | |
| 		/**
 | |
| 		* Navigates to the last image/content.
 | |
| 		* Fired when the user clicks the navigate to last control or presses the END key.
 | |
| 		*/
 | |
| 		last: function () {
 | |
| 			this._fireEvent('last');
 | |
| 		},
 | |
| 
 | |
| 		/**
 | |
| 		* Start the slideshow timer.
 | |
| 		* Fired when the user clicks the play control.
 | |
| 		*/
 | |
| 		start: function () {
 | |
| 			this._fireEvent('start');
 | |
| 		},
 | |
| 
 | |
| 		/**
 | |
| 		* Stop the slideshow timer.
 | |
| 		* Fired when the user clicks the stop control.
 | |
| 		*/
 | |
| 		stop: function () {
 | |
| 			this._fireEvent('stop');
 | |
| 		},
 | |
| 
 | |
| 		magnify: function () {
 | |
| 			var self = this;
 | |
| 			self._getElements('shrink').toggleClass(BOXPLUS_UNAVAILABLE);
 | |
| 			self._getElements('enlarge').toggleClass(BOXPLUS_UNAVAILABLE);
 | |
| 			self._setPositioning();
 | |
| 			self.resize();
 | |
| 		},
 | |
| 
 | |
| 		startRewind: function () {
 | |
| 			this.startScroll(-1);
 | |
| 		},
 | |
| 
 | |
| 		startForward: function () {
 | |
| 			this.startScroll(1);
 | |
| 		},
 | |
| 
 | |
| 		/**
 | |
| 		* Starts scrolling the thumbs navigation bar either forward or backward.
 | |
| 		* @param {number} dir -1 to scroll backward, 1 to scroll forward, 0 to initialize controls (no scrolling)
 | |
| 		*/
 | |
| 		startScroll: function (dir) {
 | |
| 			var self = this;
 | |
| 			var target = self._getElements('thumbs').getElement('ul');  // thumbs navigation bars in either panel
 | |
| 			var bar = self.thumbs.getElement('ul');  // thumbs navigation bar in main panel
 | |
| 
 | |
| 			// current left offset of thumbs navigation bar w.r.t. left edge of viewer
 | |
| 			var x = bar.getStyle('left').toInt();  // 0 > x > minpos
 | |
| 			x = isNaN(x) ? 0 : x;
 | |
| 
 | |
| 			// maximum negative value permitted as left offset w.r.t. left edge of viewer
 | |
| 			var minpos = self.viewer.getSize().x - bar.getSize().x;
 | |
| 
 | |
| 			// set initial values for current state of forward and rewind scroll buttons
 | |
| 			var forward_current;
 | |
| 			var rewind_current;
 | |
| 
 | |
| 			// set initial visibility of forward and rewind buttons
 | |
| 			self.setVisible('forward', true);
 | |
| 			self.setVisible('rewind', true);
 | |
| 
 | |
| 			// assign scroll function, avoid complex operations
 | |
| 			var func = function () {
 | |
| 				var forward_next = true;
 | |
| 				var rewind_next = true;
 | |
| 
 | |
| 				x -= dir * self._scrollspeed;
 | |
| 				if (x <= minpos) {
 | |
| 					x = minpos;
 | |
| 					forward_next = false;
 | |
| 				}
 | |
| 				if (x >= 0) {
 | |
| 					x = 0;
 | |
| 					rewind_next = false;
 | |
| 				}
 | |
| 
 | |
| 				// update visibility of forward and rewind scroll buttons only if their visibility status has changed
 | |
| 				forward_current === forward_next || self.setVisible('forward', forward_current = forward_next);
 | |
| 				rewind_current === rewind_next || self.setVisible('rewind', rewind_current = rewind_next);
 | |
| 				target.setStyle('left', x + 'px');
 | |
| 			};
 | |
| 
 | |
| 			// invoke scroll function to force initial visibility
 | |
| 			func();
 | |
| 
 | |
| 			// start scrolling only if it would advance thumbs navigation bar in either direction
 | |
| 			if (dir) {
 | |
| 				self._scrolltimer = window.setInterval(func, BOXPLUS_SCROLL_INTERVAL);
 | |
| 			}
 | |
| 		},
 | |
| 
 | |
| 		stopScroll: function () {
 | |
| 			this.decelerateScroll();
 | |
| 			if (this._scrolltimer) {
 | |
| 				window.clearInterval(this._scrolltimer);
 | |
| 				this._scrolltimer = null;
 | |
| 			}
 | |
| 		},
 | |
| 
 | |
| 		accelerateScroll: function () {
 | |
| 			this._scrollspeed = this['options']['scrollspeed'] * BOXPLUS_SCROLL_INTERVAL * this['options']['scrollfactor'] / 1000;
 | |
| 		},
 | |
| 
 | |
| 		decelerateScroll: function () {
 | |
| 			this._scrollspeed = this['options']['scrollspeed'] * BOXPLUS_SCROLL_INTERVAL / 1000;
 | |
| 		},
 | |
| 
 | |
| 		download: function () {
 | |
| 			window.location.href = this._url;
 | |
| 		},
 | |
| 
 | |
| 		/**
 | |
| 		* @param {boolean} state
 | |
| 		*/
 | |
| 		showMetadata: function (state) {
 | |
| 			var self = this;
 | |
| 			state = !state;  // invert state (show controls when metadata is NOT displayed)
 | |
| 			self.setVisible('resizer', state);
 | |
| 			self.setVisible('thumbs', state);
 | |
| 			self.setVisible('viewer prev', state);
 | |
| 			self.setVisible('viewer next', state);
 | |
| 			var elems = $$([self.viewerimage, self.viewervideo, self.viewerobject, self.viewerframe]);
 | |
| 			if (state) {
 | |
| 				elems.removeClass(BOXPLUS_HIDDEN);
 | |
| 				self.viewercontent.addClass(BOXPLUS_HIDDEN);
 | |
| 			} else {
 | |
| 				elems.addClass(BOXPLUS_HIDDEN);
 | |
| 				self.viewercontent.removeClass(BOXPLUS_HIDDEN);
 | |
| 			}
 | |
| 		},
 | |
| 
 | |
| 		/**
 | |
| 		* Shows or hides image metainformation.
 | |
| 		* Fired when the user clicks the metadata icon.
 | |
| 		*/
 | |
| 		toggleMetadata: function () {
 | |
| 			this.showMetadata(!this.isMetadata());
 | |
| 		},
 | |
| 
 | |
| 		/**
 | |
| 		* @return {boolean}
 | |
| 		*/
 | |
| 		isMetadata: function () {
 | |
| 			return !this.viewercontent.hasClass(BOXPLUS_HIDDEN);
 | |
| 		},
 | |
| 
 | |
| 		/**
 | |
| 		* Sets an image (with metadata) to be shown in the pop-up window.
 | |
| 		* @param {HTMLImageElement} image An image element.
 | |
| 		* @param {string=} url
 | |
| 		* @param {string|Element|HTMLElement=} metadata
 | |
| 		*/
 | |
| 		setImage: function (image, url, metadata) {
 | |
| 			var self = this;
 | |
| 			self.setEmpty();
 | |
| 			if (image) {
 | |
| 				// store image dimensions for future use to be able to restore image to original size
 | |
| 				self._imagedims = {
 | |
| 					width: image.width,
 | |
| 					height: image.height
 | |
| 				};
 | |
| 
 | |
| 				// set image
 | |
| 				self.viewerimage.set('src', image.src).set(self._imagedims).removeClass(BOXPLUS_UNAVAILABLE);
 | |
| 
 | |
| 				// set download availability
 | |
| 				self._url = url;
 | |
| 				self.setAvailable('download', url);
 | |
| 
 | |
| 				// set metadata availability
 | |
| 				if (metadata) {
 | |
| 					switch (typeof(metadata)) {
 | |
| 						case 'string':
 | |
| 							self.viewercontent.set('html', metadata); break;
 | |
| 						default:
 | |
| 							metadata = $(metadata);  // make Element methods available on object
 | |
| 							if (metadata) {
 | |
| 								self.viewercontent.adopt(metadata.clone());
 | |
| 							}
 | |
| 					}
 | |
| 					self.viewercontent.removeClass(BOXPLUS_UNAVAILABLE);
 | |
| 				}
 | |
| 				self.setAvailable('metadata', metadata);
 | |
| 			}
 | |
| 		},
 | |
| 
 | |
| 		/**
 | |
| 		* @param {Element} elem
 | |
| 		*/
 | |
| 		setContent: function (elem) {
 | |
| 			var self = this;
 | |
| 			self.setEmpty();
 | |
| 
 | |
| 			self.setVisible('resizer', false);
 | |
| 			self.setVisible('thumbs', false);
 | |
| 			self.setVisible('viewer prev', false);
 | |
| 			self.setVisible('viewer next', false);
 | |
| 			self.viewercontent.adopt(elem.clone()).removeClass(BOXPLUS_UNAVAILABLE).removeClass(BOXPLUS_HIDDEN);
 | |
| 
 | |
| 			self._imagedims = {
 | |
| 				width: self.options.width,
 | |
| 				height: self.options.height
 | |
| 			};
 | |
| 		},
 | |
| 
 | |
| 		/**
 | |
| 		* Set dimensions data based on explicitly set values.
 | |
| 		* @param {HTMLAnchorElement} anchor An HTML anchor element.
 | |
| 		*/
 | |
| 		setDimensions: function (anchor) {
 | |
| 			var dims = fromQueryString(anchor.search);
 | |
| 			dims = {
 | |
| 				width: dims.width ? dims.width.toInt() : this.options.width,
 | |
| 				height: dims.height ? dims.height.toInt() : this.options.height
 | |
| 			};
 | |
| 			this._imagedims = dims;
 | |
| 		},
 | |
| 
 | |
| 		/**
 | |
| 		* @param {HTMLAnchorElement} anchor An HTML anchor element.
 | |
| 		*/
 | |
| 		setObject: function (anchor) {
 | |
| 			var self = this;
 | |
| 			self.setEmpty();
 | |
| 
 | |
| 			// fetch dimension data
 | |
| 			self.setDimensions(anchor);
 | |
| 			var dims = self._imagedims;
 | |
| 
 | |
| 			var href = anchor.href;
 | |
| 			var path = anchor.pathname;
 | |
| 			if (/\.(ogg|webM)$/i.test(path)) {  // supported by HTML5-native <video> tag
 | |
| 				self.viewervideo.set(dims).set('src', href).setStyles(dims).removeClass(BOXPLUS_UNAVAILABLE);
 | |
| 			} else {
 | |
| 				self.viewerobject.setStyles(dims).removeClass(BOXPLUS_UNAVAILABLE);
 | |
| 				if (/\.(pdf|mov)$/i.test(path)) {
 | |
| 					var classid;
 | |
| 					var type;
 | |
| 					var attrs = {
 | |
| 						src: href
 | |
| 					};
 | |
| 
 | |
| 					if (/\.pdf$/i.test(path)) {
 | |
| 						classid = 'CA8A9780-280D-11CF-A24D-444553540000';
 | |
| 						type = 'application/pdf';
 | |
| 					} else if (/\.mov$/i.test(path)) {
 | |
| 						classid = '02BF25D5-8C17-4B23-BC80-D3488ABDDC6B';
 | |
| 						type = 'video/quicktime';
 | |
| 					} else if (/\.mpe?g/i.test(path)) {
 | |
| 						classid = '22d6f312-b0f6-11d0-94ab-0080c74c7e95';
 | |
| 						type = 'video/mpeg';
 | |
| 					}
 | |
| 
 | |
| 					/**
 | |
| 					* Converts an object into a name="value" HTML attribute list.
 | |
| 					*/
 | |
| 					function _getAsAttributeList(attrs) {
 | |
| 						var s = '';
 | |
| 						for (var name in attrs) {
 | |
| 							s += ' ' + name + '="' + attrs[name] + '"';
 | |
| 						}
 | |
| 						return s;
 | |
| 					}
 | |
| 
 | |
| 					/**
 | |
| 					* Converts an object into a list of HTML <param /> elements.
 | |
| 					*/
 | |
| 					function _getAsParameterList(attrs) {
 | |
| 						var s = '';
 | |
| 						for (var name in attrs) {
 | |
| 							s += '<param name="' + name + '" value="' + attrs[name] + '" />';
 | |
| 						}
 | |
| 						return s;
 | |
| 					}
 | |
| 
 | |
| 					// build custom HTML string of nested <object> elements with the specified dimensions and attributes
 | |
| 
 | |
| 					self.viewerobject.set('html',
 | |
| 						'<object' + _getAsAttributeList(Object.merge({
 | |
| 							'classid': 'clsid:' + classid
 | |
| 						}, dims)) + '>' +
 | |
| 						_getAsParameterList(attrs) +
 | |
| 						'<!--[if lt IE 9]><!--><object' + _getAsAttributeList(Object.merge({
 | |
| 							'type': type,
 | |
| 							'data': href
 | |
| 						}, dims)) + '>' + dialog.getMessage('unknown-type').replace('%s', type) + '</object><!--<![endif]-->' +
 | |
| 						'</object>'
 | |
| 					);
 | |
| 				} else {  // /\.swf$/i.test(path)
 | |
| 					// classid = 'D27CDB6E-AE6D-11cf-96B8-444553540000';
 | |
| 					new Swiff(href, Object.merge({
 | |
| 						'container': self.viewerobject,
 | |
| 						'params': {
 | |
| 							'allowFullScreen': true
 | |
| 						}
 | |
| 					}, dims));
 | |
| 				}
 | |
| 			}
 | |
| 		},
 | |
| 
 | |
| 		/**
 | |
| 		* @param {HTMLAnchorElement} anchor An HTML anchor element.
 | |
| 		*/
 | |
| 		setFrame: function (anchor) {
 | |
| 			var self = this;
 | |
| 			self.setEmpty();
 | |
| 			self.setDimensions(anchor);
 | |
| 			self.viewerframe.set('src', anchor.href).setStyles(self._imagedims).removeClass(BOXPLUS_UNAVAILABLE);
 | |
| 		},
 | |
| 
 | |
| 		/**
 | |
| 		* Clears all content from the pop-up window.
 | |
| 		*/
 | |
| 		setEmpty: function () {
 | |
| 			var self = this;
 | |
| 
 | |
| 			// reset content
 | |
| 			$$([self.viewercontent, self.viewerimage, self.viewervideo, self.viewerobject, self.viewerframe]).addClass(BOXPLUS_UNAVAILABLE);
 | |
| 			self.viewercontent.empty();
 | |
| 			self.viewerimage.erase('src');
 | |
| 			!self.viewervideo.pause || self.viewervideo.pause();
 | |
| 			self.viewervideo.erase('src');
 | |
| 			self.viewerobject.empty();
 | |
| 			self.viewerframe.set('src', 'about:blank').erase('src');
 | |
| 
 | |
| 			// reset pop-up window size
 | |
| 			self.viewer.setStyles(self._imagedims = {
 | |
| 				width: 150,
 | |
| 				height: 150
 | |
| 			});
 | |
| 
 | |
| 			// clear download URL
 | |
| 			self._url = '';
 | |
| 			self.setAvailable('download', false);
 | |
| 			self.setAvailable('metadata', false)
 | |
| 
 | |
| 			// clear title and description text
 | |
| 			self.setCaption();
 | |
| 		},
 | |
| 
 | |
| 		/**
 | |
| 		* Sets title and description text.
 | |
| 		* @param {string} title
 | |
| 		* @param {string} text
 | |
| 		*/
 | |
| 		setCaption: function (title, text) {
 | |
| 			var self = this;
 | |
| 			self._getElements('title').set('html', title);
 | |
| 			self._getElements('text').set('html', text);
 | |
| 			self._getClonedElements('title').set('html', title);
 | |
| 			self._getClonedElements('text').set('html', text);
 | |
| 			self.setAllAvailable('title', title);
 | |
| 			self.setAllAvailable('text', text);
 | |
| 			self.setAllAvailable('caption', title || text);
 | |
| 		},
 | |
| 
 | |
| 		/**
 | |
| 		* @param {string} pos
 | |
| 		*/
 | |
| 		setCaptionPosition: function (pos) {
 | |
| 			this.setAllEnabled('bottom', false);
 | |
| 			this.setAllEnabled('sideways', false);
 | |
| 			switch (pos) {
 | |
| 				case 'bottom':
 | |
| 					this.setAllEnabled('bottom', true); break;
 | |
| 				case 'sideways':
 | |
| 					this.setAllEnabled('sideways', true); break;
 | |
| 			}
 | |
| 		},
 | |
| 
 | |
| 		/**
 | |
| 		* Toggles quick-access thumbnail navigation bars inside/outside image viewport.
 | |
| 		* @param {string} pos 'inside' or 'outside'
 | |
| 		*/
 | |
| 		setThumbPosition: function (pos) {
 | |
| 			this.setAllEnabled('thumbs', false);
 | |
| 			switch (pos) {
 | |
| 				case 'inside':
 | |
| 					this.setAllEnabled('viewer thumbs', true);
 | |
| 					break;
 | |
| 				case 'outside':
 | |
| 					this.setAllEnabled('bottom thumbs', true);
 | |
| 					this.setAllEnabled('sideways thumbs', true);
 | |
| 					break;
 | |
| 			}
 | |
| 		},
 | |
| 
 | |
| 		/**
 | |
| 		* Adds thumbnails to the quick-access thumbnail navigation bars.
 | |
| 		* @param {Elements} images The thumbnail images to use.
 | |
| 		*/
 | |
| 		addThumbs: function (images) {
 | |
| 			var self = this;
 | |
| 			self._getElements('thumbs').each(function (item) {
 | |
| 				images.each(function (image) {
 | |
| 					new Element('li').adopt(image.clone().addEvent('click', function () {
 | |
| 						var item = $(this).getParent();
 | |
| 						self._fireEvent('change', item.getParent().getChildren().indexOf(item));
 | |
| 					})).inject(item.getElement('ul'));
 | |
| 				});
 | |
| 			});
 | |
| 			self.setAvailable('thumbs', images.length > 1);
 | |
| 		},
 | |
| 
 | |
| 		/**
 | |
| 		* Removes all thumbnails from the quick-access thumbnail navigation bars.
 | |
| 		*/
 | |
| 		clearThumbs: function () {
 | |
| 			this._getElements('thumbs').each(function (item) {
 | |
| 				item.getElement('ul').empty();
 | |
| 			});
 | |
| 		},
 | |
| 
 | |
| 		isShrunk: function () {
 | |
| 			var self = this;
 | |
| 			// resizing videos impacts performance and HTML <object> does not always support dynamic resizing
 | |
| 			return self.viewervideo.get('src') || self.viewerobject.getChildren().length ? false : self._getElement('shrink').hasClass(BOXPLUS_UNAVAILABLE);
 | |
| 		},
 | |
| 
 | |
| 		/**
 | |
| 		* @param {Element} obj
 | |
| 		*/
 | |
| 		getCenter: function (obj) {
 | |
| 			var winsize = window.getSize();
 | |
| 			var objsize = obj.getSize();
 | |
| 			var x = (0).max((winsize['x'] - objsize['x']) / 2);  // function max avoids dialog extending beyond left or top edge where browser does not let user scroll
 | |
| 			var y = (0).max((winsize['y'] - objsize['y']) / 2);
 | |
| 			if (this.popup.getStyle('position') != 'fixed') {
 | |
| 				var scroll = window.getScroll();
 | |
| 				x += scroll['x'];
 | |
| 				y += scroll['y'];
 | |
| 			}
 | |
| 			return {
 | |
| 				'x': x,
 | |
| 				'y': y
 | |
| 			};
 | |
| 		},
 | |
| 		center: function (obj) {
 | |
| 			obj.setPosition(this.getCenter(obj));
 | |
| 		},
 | |
| 
 | |
| 		recenter: function () {
 | |
| 			var self = this;
 | |
| 			self.center(self.popupclone);
 | |
| 			self.popup.set('morph', {
 | |
| 				duration: self.options.duration,
 | |
| 				link: 'cancel'
 | |
| 			}).morph(self.popupclone.getStyles(['left','top']));
 | |
| 		},
 | |
| 
 | |
| 		/**
 | |
| 		* Sets absolute or fixed positioning on the pop-up window.
 | |
| 		*/
 | |
| 		_setPositioning: function() {
 | |
| 			var self = this;
 | |
| 
 | |
| 			var iscentered = self['options']['autocenter'] && self.isShrunk();
 | |
| 			var dst = iscentered ? 'fixed' : 'absolute';
 | |
| 			var src = self.popup.getStyle('position');
 | |
| 
 | |
| 			var position = self.popup.getPosition();
 | |
| 			var x = position['x'];
 | |
| 			var y = position['y'];
 | |
| 			if (src != dst) {
 | |
| 				var scroll = window.getScroll();
 | |
| 				if (iscentered) {  // fixed positioned target, absolute positioned at the moment
 | |
| 					x -= scroll['x'];  // absolute positioning takes into account window scroll
 | |
| 					y -= scroll['y'];
 | |
| 				} else {  // absolute positioned target, fixed positioned at the moment
 | |
| 					x += scroll['x'];  // fixed positioning does not take into account window scroll
 | |
| 					y += scroll['y'];
 | |
| 				}
 | |
| 			}
 | |
| 			self.popup.setStyle('position', dst);
 | |
| 			self.popup.setPosition({
 | |
| 				'x': x,
 | |
| 				'y': y
 | |
| 			});
 | |
| 		},
 | |
| 
 | |
| 		/**
 | |
| 		* Resizes the pop-up window dialog.
 | |
| 		* @param {function()=} callback A function to invoke when the animated sizing completes.
 | |
| 		*/
 | |
| 		resize: function (callback) {
 | |
| 			var self = this;
 | |
| 			self.resizing = true;
 | |
| 
 | |
| 			// hide bottom and sideways caption area temporarily while resizing
 | |
| 			self.setVisible('bottom', false);
 | |
| 			self.setVisible('sideways', false);
 | |
| 
 | |
| 			// hide viewer area
 | |
| 			self.setVisible('viewer', false);
 | |
| 
 | |
| 			// whether only HTML content is shown (no image, video or flash)
 | |
| 			var contentonly = !self.viewerimage.get('src') && !self.viewervideo.get('src') && !self.viewerobject.getChildren().length && !self.viewerframe.get('src');
 | |
| 
 | |
| 			// show metadata only if available
 | |
| 			self.showMetadata(contentonly);  // hide metadata (show image, video or flash instead)
 | |
| 
 | |
| 			// show quick-access thumbnail navigation bar only if available
 | |
| 			self.setVisible('thumbs', self._getElement('thumbs').getChildren().length > 1);
 | |
| 
 | |
| 			// calculate pop-up window size based on internal image copy
 | |
| 			var w = self._imagedims.width;
 | |
| 			var h = self._imagedims.height;
 | |
| 
 | |
| 			/**
 | |
| 			* Updates the size of the viewer and returns the new dimensions of the dialog.
 | |
| 			*/
 | |
| 			function _dialogresize(w, h) {
 | |
| 				self.viewerclone.setStyles({
 | |
| 					width: w,
 | |
| 					height: h
 | |
| 				});
 | |
| 				return self.popupclone.getSize();
 | |
| 			}
 | |
| 			self.viewerclone.setStyle('margin-right', self.sidewaysclone.getSize().x);
 | |
| 
 | |
| 			// calculate size for large images that need shrinking
 | |
| 			var winsize = window.getSize();
 | |
| 			var dlgsize;
 | |
| 			if (contentonly) {
 | |
| 				dlgsize = _dialogresize(w, 'auto');
 | |
| 				self.viewercontentclone.empty();
 | |
| 				var children = self.viewercontent.getChildren();
 | |
| 				if (children.length) {
 | |
| 					self.viewercontentclone.adopt(children);  // temporarily give children to other clone parent
 | |
| 				}
 | |
| 				h = self.viewerclone.getSize().y;
 | |
| 				dlgsize = _dialogresize(w, h);
 | |
| 				dlgsize = _dialogresize(Math.min(winsize.x, dlgsize.x) - (dlgsize.x-w), Math.min(winsize.y, dlgsize.y) - (dlgsize.y-h));
 | |
| 				if (children.length) {
 | |
| 					self.viewercontent.adopt(children);  // take children back from clone parent
 | |
| 				}
 | |
| 			} else {
 | |
| 				dlgsize = _dialogresize(w, h);
 | |
| 				var needShrunk = self['options']['autofit']  // autofit is enabled
 | |
| 					&& ((winsize.x < dlgsize.x) || (winsize.y < dlgsize.y));  // does not fit browser window dimensions
 | |
| 				if (needShrunk && self.isShrunk()) {  // needs shrinking and is in shrunk mode
 | |
| 					var ratio;
 | |
| 					if ((ratio = winsize.x / dlgsize.x) < 1.0) {
 | |
| 						w *= ratio;
 | |
| 						h *= ratio;
 | |
| 						dlgsize = _dialogresize(w, h);
 | |
| 					}
 | |
| 					while ((ratio = winsize.y / dlgsize.y) < 1.0) {
 | |
| 						w *= ratio;
 | |
| 						h *= ratio;
 | |
| 						dlgsize = _dialogresize(w, h);
 | |
| 					}
 | |
| 				}
 | |
| 				self.setAvailable('resizer', needShrunk);
 | |
| 			}
 | |
| 
 | |
| 			// set positioning
 | |
| 			self._setPositioning();
 | |
| 
 | |
| 			// calculate pop-up window center position
 | |
| 			self.center(self.popupclone);
 | |
| 
 | |
| 			function _dialogdimensions() {
 | |
| 				return self.popupclone.getStyles(['left','top','width','height']);
 | |
| 			}
 | |
| 
 | |
| 			// hide bottom and sideways panel
 | |
| 			self.setAllAvailable('bottom', false);
 | |
| 			self.setAllAvailable('sideways', false);
 | |
| 
 | |
| 			// set center panel to occupy the entire content of the pop-up window
 | |
| 			self.centerpanel.setStyle('height', '100%');
 | |
| 
 | |
| 			// morph pop-up window to appropriate position and size
 | |
| 			var dims = _dialogdimensions();  // reduced height
 | |
| 			var params = {
 | |
| 				'duration': self['options']['duration'],
 | |
| 				'link': 'cancel',
 | |
| 				'transition': self['options']['transition']
 | |
| 			};
 | |
| 			var morph = new Fx.Morph(self.popup, Object.merge(params, {
 | |
| 				'onComplete': function () {
 | |
| 					// clear forced height of center panel, the pop-up window dimensions should allow for bottom and sideways panel
 | |
| 					self.centerpanel.setStyle('height', 'auto');
 | |
| 
 | |
| 					// set dimensions of viewer when first resizing phase completes
 | |
| 					var viewerdims = self.viewerclone.getStyles(['width','height']);
 | |
| 					self.viewerframe.setStyles(viewerdims);  // inline frame size should reflect viewer size
 | |
| 					self.viewer.setStyles(viewerdims);
 | |
| 
 | |
| 					// scroll inner content window into view
 | |
| 					self.viewercontent.scrollTo(0,0);
 | |
| 
 | |
| 					// show viewer content
 | |
| 					self.setVisible('viewer', true);
 | |
| 
 | |
| 					// reset thumbnail quick-access navigation bar
 | |
| 					self.startScroll(0);
 | |
| 
 | |
| 					// invoke callback if defined
 | |
| 					callback && callback();
 | |
| 
 | |
| 					new Fx.Morph(self.popup, Object.merge(params, {
 | |
| 						'onComplete': function () {
 | |
| 							self.setAvailable('bottom', true);
 | |
| 							self.setAvailable('sideways', true);
 | |
| 
 | |
| 							// show bottom and sideways caption area temporarily hidden
 | |
| 							self.setVisible('bottom', true);
 | |
| 							self.setVisible('sideways', true);
 | |
| 
 | |
| 							// set resizing complete
 | |
| 							self.resizing = false;
 | |
| 
 | |
| 							// re-center dialog if page has been scrolled during resizing
 | |
| 							self.recenter();
 | |
| 						}
 | |
| 					})).start(_dialogdimensions());
 | |
| 				}
 | |
| 			}));
 | |
| 
 | |
| 			morph.start(dims);
 | |
| 			self.bottomclone.removeClass(BOXPLUS_UNAVAILABLE);
 | |
| 			self.sidewaysclone.removeClass(BOXPLUS_UNAVAILABLE);
 | |
| 		},
 | |
| 
 | |
| 		/**
 | |
| 		* Enables or disables progress indicators.
 | |
| 		* A progress indicator is a PNG image with alpha transparency
 | |
| 		* @param {boolean} state
 | |
| 		*/
 | |
| 		toggleProgress: function (state) {
 | |
| 			var indicators = this._getElements('progress');
 | |
| 			if (this._progresstimer) {
 | |
| 				window.clearInterval(this._progresstimer);
 | |
| 			}
 | |
| 			if (indicators.length && state) {
 | |
| 				/** @type {string} */
 | |
| 				var backpos = indicators[0].getStyle('background-position');  // extract first integer from a string like "-64px 0px"
 | |
| 				var offset = backpos ? backpos.toInt() : 0;
 | |
| 				this._progresstimer = window.setInterval(function () {
 | |
| 					indicators.setStyle('background-position', (offset = (offset - 32) % 384) + 'px 0');  // 384px = 12 states * 32px width
 | |
| 				}, 150);
 | |
| 			} else {
 | |
| 				this._progresstimer = null;
 | |
| 			}
 | |
| 			this.setVisible('progress', state);
 | |
| 		}
 | |
| 	});
 | |
| 
 | |
| 	var dialog;
 | |
| 	window.addEvent('domready', function () {
 | |
| 		dialog = new boxplusDialog();  // inject pop-up HTML to document
 | |
| 	});
 | |
| 
 | |
| 	/**
 | |
| 	* A boxplus gallery.
 | |
| 	* Fires the following events:
 | |
| 	* 1. change:  fired when new content is being shown
 | |
| 	* 2. open:    fired when the pop-up window opens
 | |
| 	* 3. close:   fired when the pop-up window closes
 | |
| 	* @constructor
 | |
| 	* @param {Element|Elements} el
 | |
| 	* @param {!Object=} options
 | |
| 	*/
 | |
| 	var boxplus = new Class({
 | |
| 		'Implements': [Events,Options],
 | |
| 
 | |
| 		/**
 | |
| 		* The index of the currently shown item. Read only.
 | |
| 		* @type {number}
 | |
| 		*/
 | |
| 		current: -1,
 | |
| 		/**
 | |
| 		* @type {Elements}
 | |
| 		*/
 | |
| 		_anchors: $$([]),
 | |
| 		_timer: null,
 | |
| 
 | |
| 		// --- EDIT FUNCTIONS BELOW TO MODIFY DEFAULT TITLE, DESCRIPTION, DOWNLOAD URL AND METADATA --- //
 | |
| 
 | |
| 		/**
 | |
| 		* Title text that belongs an anchor.
 | |
| 		* @param {Element} anchor A mootools Element object representing the anchor.
 | |
| 		* @return {?string} Raw HTML data as a string.
 | |
| 		*/
 | |
| 		_getTitle: function (anchor) {
 | |
| 			var image = anchor.getElement('img');
 | |
| 			return anchor.retrieve('title') || (image ? image.getProperty('alt') : '');
 | |
| 		},
 | |
| 		/**
 | |
| 		* Description text that belongs to an anchor.
 | |
| 		* @param {Element} anchor A mootools Element object representing the anchor.
 | |
| 		* @return {string} Raw HTML data as a string.
 | |
| 		*/
 | |
| 		_getText: function (anchor) {
 | |
| 			return anchor.retrieve('summary') || anchor.getProperty('title');
 | |
| 		},
 | |
| 		/**
 | |
| 		* Download URL associated with an anchor.
 | |
| 		* @param {Element} anchor A mootools Element object representing the anchor.
 | |
| 		* @return {string} A URL.
 | |
| 		*/
 | |
| 		_getDownloadUrl: function (anchor) {
 | |
| 			return anchor.retrieve('download');
 | |
| 		},
 | |
| 		/**
 | |
| 		* Metadata associated with an anchor.
 | |
| 		* @param {Element} anchor A mootools Element object representing the anchor.
 | |
| 		* @return {string|Element} Raw HTML data as a string, or an Element object.
 | |
| 		*/
 | |
| 		_getMetadata: function (anchor) { },
 | |
| 
 | |
| 		// --- EDIT OPTIONS BELOW TO MODIFY DEFAULTS --- //
 | |
| 		// ---  SEE FURTHER ABOVE FOR OTHER OPTIONS  --- //
 | |
| 
 | |
| 		/**
 | |
| 		* boxplus gallery options.
 | |
| 		*/
 | |
| 		'options': {
 | |
| 			/*
 | |
| 			onChange: function () {},    // triggered when the current item shown is about to be changed
 | |
| 			onClose: function () {},     // triggered when the pop-up window has been closed
 | |
| 			*/
 | |
| 			/**
 | |
| 			* Time spent viewing an image when slideshow mode is active, or 0 to disable slideshow mode.
 | |
| 			* @type {number}
 | |
| 			*/
 | |
| 			'slideshow': 0,
 | |
| 			/**
 | |
| 			* Whether to start a slideshow when the dialog opens.
 | |
| 			* @type {boolean}
 | |
| 			*/
 | |
| 			'autostart': false,
 | |
| 			/**
 | |
| 			* Whether the image/content sequence loops such that the first image/content follows the last.
 | |
| 			* @type {boolean}
 | |
| 			*/
 | |
| 			'loop': false,
 | |
| 			/**
 | |
| 			* Placement of captions. Takes the value 'bottom' (below the image), 'sideways' (next to the image) or 'none'.
 | |
| 			*/
 | |
| 			'captions': 'bottom',
 | |
| 			/**
 | |
| 			* Placement of thumbnail navigation bar. Takes the value 'inside' (over the image), 'outside' (in the caption area) or 'none'.
 | |
| 			*/
 | |
| 			'thumbs': 'inside',
 | |
| 			/**
 | |
| 			* Whether to cloak anchor URLs. Cloaked anchors will not reveal the target image URL
 | |
| 			* when the user positions the mouse cursor over the image.
 | |
| 			* Cloaking URLs also prevents other javascript code from reading the anchor "href" attribute.
 | |
| 			*/
 | |
| 			'cloak': false
 | |
| 		},
 | |
| 
 | |
| 		// Other options include (see their default definition above):
 | |
| 		//  getTitle
 | |
| 		//  getText
 | |
| 		//  getDownloadUrl
 | |
| 		//  getMetadata
 | |
| 
 | |
| 		// --- END OF DEFAULT OPTIONS --- //
 | |
| 
 | |
| 		/**
 | |
| 		* @param {Element} elem
 | |
| 		* @param {!Object} options
 | |
| 		*/
 | |
| 		'initialize': function (elem, options) {
 | |
| 			var self = this;
 | |
| 
 | |
| 			// find anchors that belong to a gallery.
 | |
| 			var anchors;  // a collection of anchors that form the gallery
 | |
| 			var tag = elem.get('tag');
 | |
| 			if (elem.each) {  // is a collection
 | |
| 				if (tag.every(function (item) { return item == 'a'; })) {
 | |
| 					anchors = elem;
 | |
| 					self.current = 0;
 | |
| 				} else {
 | |
| 					return;
 | |
| 				}
 | |
| 			} else if (tag == 'a') {  // is a single anchor item
 | |
| 				boxplus['extenders'].each(function (fn) {
 | |
| 					anchors = fn.bind(self)(elem);
 | |
| 				});
 | |
| 
 | |
| 				if (!anchors) {  // anchor not recognized by any of the extenders
 | |
| 					// extend with related anchors (if any) whose rel attribute starts with "boxplus-" or "boxplus["
 | |
| 					var rel = elem.get('rel');
 | |
| 					anchors = $$(rel && rel.test(/^boxplus\b(?!$)/) ? 'a[rel="' + rel + '"]' : elem);
 | |
| 
 | |
| 					self.current = anchors.indexOf(elem);
 | |
| 				}
 | |
| 			} else if (/^[udo]l$/.test(tag)) {  // is a single list item
 | |
| 				anchors = $$(elem.getChildren('li,dt').map(function (item) {
 | |
| 					return item.getElement('a');
 | |
| 				}).filter(function (item) {
 | |
| 					return item;  // filter null values
 | |
| 				}));
 | |
| 				self.current = anchors.length > 0 ? 0 : -1;
 | |
| 			} else {
 | |
| 				self.initialize(elem.getElement('ul,ol,dl'), options);
 | |
| 				return;
 | |
| 			}
 | |
| 
 | |
| 			// interpret settings
 | |
| 			self['setOptions'](options);
 | |
| 			if (options) {
 | |
| 				self._getTitle = [options['getTitle'], self._getTitle].pick();
 | |
| 				self._getText = [options['getText'], self._getText].pick();
 | |
| 				self._getDownloadUrl = [options['getDownloadUrl'], self._getDownloadUrl].pick();
 | |
| 				self._getMetadata = [options['getMetadata'], self._getMetadata].pick();
 | |
| 			}
 | |
| 
 | |
| 			// click event bindings
 | |
| 			anchors.addEvent('click', function () {  // event "click" opens the gallery showing image of selected anchor
 | |
| 				self.show['delay'](1, self, this);  // this = image clicked, delay required for seamless history support (event processing function must exit before function "show" is invoked)
 | |
| 				return false;
 | |
| 			});
 | |
| 
 | |
| 			// cloak anchor href attributes
 | |
| 			self['options']['cloak'] && anchors.each(cloak);
 | |
| 
 | |
| 			// set anchors used in extracting image properties
 | |
| 			self._anchors = anchors;
 | |
| 		},
 | |
| 
 | |
| 		/**
 | |
| 		* Shows the gallery in a pop-up window.
 | |
| 		* @param {Element} anchor An anchor (HTML <a>) that points to an image/content, or a list (HTML <ul> or <ol>) with each item containing an anchor.
 | |
| 		*/
 | |
| 		'show': function (anchor) {
 | |
| 			var self = this;
 | |
| 
 | |
| 			if (anchor) {
 | |
| 				self.current = (0).max(self._anchors.get('href').indexOf(anchor.get('href')));
 | |
| 			}
 | |
| 
 | |
| 			dialog.hide();  // hide other dialog if visible
 | |
| 
 | |
| 			// show progress indicator
 | |
| 			dialog.toggleProgress(true);
 | |
| 
 | |
| 			// toggle captions below/next to image viewport based on settings
 | |
| 			dialog.setCaptionPosition(self['options']['captions']);
 | |
| 
 | |
| 			// toggle thumbnail bars inside/outside image viewport based on settings
 | |
| 			dialog.setThumbPosition(self['options']['thumbs']);
 | |
| 
 | |
| 			// add thumbnails
 | |
| 			dialog.addThumbs($$(self._anchors.map(function (anchor) {
 | |
| 				var image = [anchor.retrieve('thumb'), anchor.getElement('img')].pick();  // use thumbnail associated with anchor (via element storage) or find an image child
 | |
| 				if (image) {
 | |
| 					// thumbnail image source, inspecting all candidate attributes
 | |
| 					var attrthumb = image.get('data-thumb');
 | |
| 					return new Element('img', {
 | |
| 						'src': attrthumb ? attrthumb : image.get('src')
 | |
| 					});
 | |
| 				} else {
 | |
| 					return null;
 | |
| 				}
 | |
| 			})));
 | |
| 
 | |
| 			// associate events with callback functions
 | |
| 			var events = ['previous','next','first','last','start','stop','change','close'];
 | |
| 			var callbacks = events.map(function (event) {
 | |
| 				return self[event].bind(self);
 | |
| 			});
 | |
| 			self.dialogevents = callbacks.associate(events);
 | |
| 
 | |
| 			// add history support
 | |
| 			self._updateHistory(anchor['href']);
 | |
| 			window.addEvent('popstate', self.close['bind'](self));
 | |
| 
 | |
| 			// subscribe to dialog box events
 | |
| 			dialog.addEvents(self.dialogevents);
 | |
| 			dialog.show(self['options']);
 | |
| 
 | |
| 			// toggle slideshow start button
 | |
| 			var allowSlideshow = self['options']['slideshow'] && self._anchors.length > 1;
 | |
| 			dialog.setEnabled('start', allowSlideshow);
 | |
| 
 | |
| 			// change to image
 | |
| 			self._replace(self.current);
 | |
| 
 | |
| 			if (allowSlideshow && self['options']['autostart']) {
 | |
| 				self.start();
 | |
| 			}
 | |
| 
 | |
| 			// fire onShow event
 | |
| 			self._fireEvent('open');
 | |
| 		},
 | |
| 
 | |
| 		'close': function () {
 | |
| 			dialog.setEmpty();
 | |
| 			dialog.removeEvents(this.dialogevents);
 | |
| 			dialog.hide();
 | |
| 			dialog.clearThumbs();
 | |
| 
 | |
| 			// unwind history stack
 | |
| 			while (window.history.state == 'boxplus') {  // boxplus uses the special history state string "boxplus"
 | |
| 				window.history.go(-1);
 | |
| 			}
 | |
| 
 | |
| 			// fire onClose event
 | |
| 			this._fireEvent('close');
 | |
| 		},
 | |
| 
 | |
| 		'previous': function () {
 | |
| 			this._change(this.current - 1);
 | |
| 		},
 | |
| 
 | |
| 		'next': function () {
 | |
| 			this._change(this.current + 1);
 | |
| 		},
 | |
| 
 | |
| 		'first': function () {
 | |
| 			this._change(0);
 | |
| 		},
 | |
| 
 | |
| 		'last': function () {
 | |
| 			this._change(this._anchors.length - 1);
 | |
| 		},
 | |
| 
 | |
| 		/**
 | |
| 		* @param {number} index
 | |
| 		*/
 | |
| 		'change': function (index) {
 | |
| 			this._change(index);
 | |
| 		},
 | |
| 
 | |
| 		'start': function () {
 | |
| 			var self = this;
 | |
| 			if (!self._timer) {
 | |
| 				self._timer = setTimeout(self.next.bind(self), self['options']['slideshow']);
 | |
| 			}
 | |
| 
 | |
| 			dialog.setAvailable('start', false);
 | |
| 			dialog.setAvailable('stop', true);
 | |
| 		},
 | |
| 
 | |
| 		'stop': function () {
 | |
| 			var self = this;
 | |
| 			if (self._timer) {
 | |
| 				clearTimeout(self._timer);
 | |
| 				self._timer = null;
 | |
| 			}
 | |
| 
 | |
| 			dialog.setAvailable('stop', false);
 | |
| 			dialog.setAvailable('start', true);
 | |
| 		},
 | |
| 
 | |
| 		/**
 | |
| 		* @param {number} index
 | |
| 		*/
 | |
| 		_change: function (index) {
 | |
| 			var self = this;
 | |
| 			if (index != self.current && (self['options']['loop'] || index >= 0 && index < self._anchors.length)) {
 | |
| 				self._replace(index);
 | |
| 				self._fireEvent('change');
 | |
| 			}
 | |
| 		},
 | |
| 
 | |
| 		_fireEvent: function (event, arg) {
 | |
| 			this['fireEvent'](event, arg);
 | |
| 		},
 | |
| 
 | |
| 		/**
 | |
| 		* Updates the latest history entry, either injecting a new entry or updating an existing one.
 | |
| 		* The history entry is updated only if the latest entry has also been injected by this class.
 | |
| 		* @param {string} href The new URL for the topmost history entry.
 | |
| 		*/
 | |
| 		_updateHistory: function (href) {
 | |
| 			// check if the latest history entry has been injected by boxplus (which uses the special history state string "boxplus")
 | |
| 			var hist = window.history;
 | |
| 			var name = hist.state == 'boxplus' ? 'replaceState' : 'pushState';
 | |
| 
 | |
| 			// check for history support and execute function
 | |
| 			var fn = hist[name];
 | |
| 			if (fn) {
 | |
| 				try {
 | |
| 					fn('boxplus', '', href);
 | |
| 				} catch (err) {
 | |
| 					// catch security vulnerability errors (e.g. site URL domain does not match image URL domain)
 | |
| 				}
 | |
| 			}
 | |
| 		},
 | |
| 
 | |
| 		/**
 | |
| 		* @param {number} index
 | |
| 		*/
 | |
| 		_replace: function (index) {
 | |
| 			var self = this;
 | |
| 			var noSlideshow = !self._timer;
 | |
| 			self.stop();  // stop slideshow animation
 | |
| 
 | |
| 			dialog.setEmpty();  // clear current image
 | |
| 			var count = self._anchors.length;
 | |
| 			var last = index >= count - 1;
 | |
| 			dialog.setVisible('viewer', false);  // hide viewer
 | |
| 			dialog.setAvailable('start', !last);
 | |
| 			var loop = self['options']['loop'];
 | |
| 			dialog.setAvailable('prev', loop && count > 1 || index > 0);
 | |
| 			dialog.setAvailable('next', loop && count > 1 || !last);
 | |
| 
 | |
| 			function _show() {
 | |
| 				dialog.resize(function () {
 | |
| 					dialog.toggleProgress(false);
 | |
| 					noSlideshow || last || self.start();  // continue slideshow if possible
 | |
| 				});
 | |
| 			}
 | |
| 
 | |
| 			function _showCaption(anchor) {
 | |
| 				dialog.setCaption(self._getTitle(anchor), self._getText(anchor));
 | |
| 			}
 | |
| 
 | |
| 			function _showImage(anchor, image) {
 | |
| 				dialog.setImage(image, self._getDownloadUrl(anchor), self._getMetadata(anchor));
 | |
| 				_showCaption(anchor);
 | |
| 				_show();
 | |
| 			}
 | |
| 
 | |
| 			function _showContent(elem) {
 | |
| 				dialog.setContent(elem);
 | |
| 				_show();
 | |
| 			}
 | |
| 
 | |
| 			if (count > 0) {
 | |
| 				self.current = (index + count) % count;  // avoid mod operator with negative numbers
 | |
| 				var anchor = self._anchors[self.current];
 | |
| 
 | |
| 				// un-cloak URLs to be able to extract anchor parameters
 | |
| 				uncloak(anchor);
 | |
| 
 | |
| 				// update history
 | |
| 				self._updateHistory(anchor['href']);
 | |
| 
 | |
| 				// extract anchor parameters
 | |
| 				var href = anchor.get('href');  // <a> href (as it occurs in source)
 | |
| 				var url = anchor.href;  // <a> href (resolved)
 | |
| 				var path = anchor.pathname;
 | |
| 
 | |
| 				if (/^#/.test(href)) {  // content in the same document
 | |
| 					var elem = $(href.substr(1));
 | |
| 					switch (elem.get('tag')) {
 | |
| 						case 'img':
 | |
| 							_showImage(anchor, elem);
 | |
| 							break;
 | |
| 						default:
 | |
| 							_showContent(elem);
 | |
| 					}
 | |
| 				} else if (/\.(txt|html?)$/i.test(path) && anchor['host'] == window['location']['host']) {  // use AJAX only for requests to the same domain
 | |
| 					new Request.HTML({
 | |
| 						'url': url,
 | |
| 						'onSuccess': function (html) {
 | |
| 							_showContent($$(html));
 | |
| 						},
 | |
| 						'onFailure': function (xhr) {
 | |
| 							alert(dialog.getMessage('not-found'));
 | |
| 							dialog.hide();
 | |
| 						}
 | |
| 					}).get();
 | |
| 				} else if (/\.(gif|jpe?g|png)$/i.test(path)) {  // preload image
 | |
| 					$(new Image).addEvent('load', function () {  // triggered when the image has been preloaded
 | |
| 						_showImage(anchor, this);  // the keyword 'this' refers to the image
 | |
| 					}).set('src', url);
 | |
| 				} else if (/\.(pdf|mov|mpe?g|ogg|swf|webM|wmv)$/i.test(path) || /(viddler|vimeo|youtube)\.com$/.test(anchor.hostname)) {
 | |
| 					dialog.setObject(anchor);
 | |
| 					_showCaption(anchor);
 | |
| 					_show();
 | |
| 				} else if (anchor.protocol != 'javascript:') {
 | |
| 					dialog.setFrame(anchor);
 | |
| 					_showCaption(anchor);
 | |
| 					_show();
 | |
| 				}
 | |
| 
 | |
| 				// re-cloak URLs if needed
 | |
| 				self['options']['cloak'] && cloak(anchor);
 | |
| 			}
 | |
| 		}
 | |
| 	});
 | |
| 
 | |
| 	// create constructor and add static methods
 | |
| 	Object.append(window['boxplus'] = boxplus, {
 | |
| 		/**
 | |
| 		* List of custom URL parser functions.
 | |
| 		*/
 | |
| 		'extenders': [
 | |
| 			/**
 | |
| 			* Picasa extender.
 | |
| 			* Remove this function if you do not need Picasa support.
 | |
| 			*/
 | |
| 			function (anchor) {
 | |
| 				var self = this;
 | |
| 				var match;  // results of a regular expression match
 | |
| 				if (Request.JSONP && (match = anchor.href.match(/https?:\/\/picasaweb.google.com\/data\/feed\/(?:api|base)\/user\/([^\/?#]+)\/albumid\/([^\/?#]+)/))) {
 | |
| 					new Request.JSONP({
 | |
| 						'url': 'http://picasaweb.google.com/data/feed/api/user/' + match[1] + '/albumid/' + match[2],
 | |
| 						'data': {
 | |
| 							'alt': 'json',
 | |
| 							'imgmax': 800,      // maximum image size (uncropped)
 | |
| 							'kind': 'photo',
 | |
| 							'thumbsize': '64u'  // maximum thumbnail image size (uncropped or cropped)
 | |
| 						},
 | |
| 						'onComplete': function (data) {
 | |
| 							self._anchors = $$([]);
 | |
| 							data['feed']['entry'].each(function (entry) {
 | |
| 								var thumb = entry['media$group']['media$thumbnail'][0];
 | |
| 								self._anchors.include(
 | |
| 									new Element('a', {
 | |
| 										'href': entry['content']['src'],
 | |
| 										'title': entry['summary']['$t']
 | |
| 									}).adopt(
 | |
| 										new Element('img', {
 | |
| 											'width': thumb['width'],
 | |
| 											'height': thumb['height'],
 | |
| 											'alt': entry['title']['$t'],
 | |
| 											'src': thumb['url']
 | |
| 										})
 | |
| 									)
 | |
| 								);
 | |
| 							});
 | |
| 							self.current = 0;
 | |
| 						}
 | |
| 					}).send();
 | |
| 					return $$(anchor);
 | |
| 				}
 | |
| 			}
 | |
| 		],
 | |
| 
 | |
| 		/**
 | |
| 		* Auto-discovery service.
 | |
| 		* Remove this function if you do not need automatic boxplus binding.
 | |
| 		* @param {boolean} strict
 | |
| 		* @param {!Object} options
 | |
| 		*/
 | |
| 		'autodiscover': function (strict, options) {
 | |
| 			window.addEvent('domready', function () {
 | |
| 				// links part of a gallery
 | |
| 				var groups = [];
 | |
| 				$$('a[rel^=boxplus]:not([rel=boxplus])').each(function (item) {  // leave out individual items
 | |
| 					groups.include(item.get('rel'));
 | |
| 				});
 | |
| 				groups.each(function (group) {
 | |
| 					new boxplus($$('a[rel="'+ group +'"]'), options);
 | |
| 				});
 | |
| 
 | |
| 				// individual links with rel attribute set
 | |
| 				$$('a[rel=boxplus]').each(function (item) {
 | |
| 					new boxplus(item, options);
 | |
| 				});
 | |
| 
 | |
| 				if (!strict) {
 | |
| 					// individual links to images or flash not part of a gallery
 | |
| 					$$('a[href]:not([rel^=boxplus])').filter(function (item) {
 | |
| 						return /\.(gif|jpe?g|png|swf)$/i.test(item.pathname) && !/_(blank|parent|self|top)/.test(item.get('target'));
 | |
| 					}).each(function (item) {
 | |
| 						new boxplus(item, options);
 | |
| 					});
 | |
| 				}
 | |
| 			});
 | |
| 		}
 | |
| 	});
 | |
| })(document.id); |