(function($, undefined) {
'use strict';

O_O.widget.BlogReader.Controller = function($elem, props, msgSys, env) {
	O_O.lib.Controller.apply(this, arguments);

	this.view = O_O.mm.oNew(O_O.widget.BlogReader.View, $elem, props,
		scopeC(this._controllerCb, this), env);
};

O_O.widget.BlogReader.Controller.prototype = {
	
	render: function(config) {
		if (typeof config !== 'object') {
			return new $.Deferred().reject().promise();
		}

		// TODO: check for multiple renders of same config

		var $dfd = new $.Deferred();
		
		//var color = (typeof config.color === 'string') ? config.color : null;
		this.view.config = config;
		var type = config.type;
		var url, limit, feedUrl;
		switch(type) {
		case 'tumblr':
			url = config.tumblr_url;
			limit = config.tumblr_limit;
			break;
		case 'blogger':
			url = config.blogger_url;
			limit = config.blogger_limit;
			break;
		case 'wordpress':
			url = config.wordpress_url;
			limit = config.wordpress_limit;
			feedUrl = config.wordpress_feedUrl;
			break;
		}

		this.view.render(url, type, limit, feedUrl).fail(function() {
			$dfd.reject();
		}).done(function() {
			$dfd.resolve();
		});
		
		return $dfd.promise();
	},

	_controllerCb: function(type, d) {
		switch(type) {
		case 'editWidget':
			return this.msgSys.pub('Shell', {
				msg: type,
				data: {
					view: d.view,
					cfgId: this.getCfg()
				}
			});
		case 'setLinkTag':
			this.msgSys.pub('Shell', {
				msg: type,
				data: {
					attrs: d
				}
			});
			break;
		}
	},

	/* unused functions (to override controller) */

	_eventH: function(type, data) {
		if (type !== "BlogReader") return;

		switch (data.cmd) {
		case 'renderPage':
			this.view.renderPage(data.data.page);
			break;
		}
	}
};

O_O.obj.inherit(O_O.lib.Controller, O_O.widget.BlogReader.Controller);

}(ps$));
(function($, undefined) {
'use strict';

$.support.cors = true;

O_O.widget.BlogReader.View = function($elem, props, contenttrollerCb, env) {
	O_O.lib.View.apply(this, arguments);
};

O_O.widget.BlogReader.View.prototype = {
	TUMBLR_API_KEY: 'VmUy8FNTTGOzaz9y7fB1qt9ECa3uBziyO5pVa5UIpqhx36kiLo',
	BLOGGER_API_KEY: 'AIzaSyDKV6RNrlLMu58v4lMzgh3lQuksDfifg2w',
	PATH: '/blog/',

	urlRegex: /[-a-zA-Z0-9@:%_\+.~#?&//=]{2,253}\.[a-z]{2,63}\b(\/[-a-zA-Z0-9@:%_\+.~#?&//=]*)?/gi,

	$main: null,
	$prevLink: null,
	$nextLink: null,
	$editorForm: null,

	limit: 10,
	prevPage: null,
	curPage: null,
	nextPage: null,
	rerender: null,

	_type: null,
	_url: null,
	_wpPosts: null,
	_feedUrl: null,

	viewMap: {
		prev: '.prev',
		next: '.next',
		loading: '.loading-c2'
	},

	_fixUrl: function(url) {
		if(url.substr(-1) === '/') {
			url = url.substr(0, url.length - 1);
		}
		if (url.indexOf('http://') !== 0 && url.indexOf('https://') !== 0) {
			url = 'http://' + url;
		}
		return url + '/';
	},

	_init: function() {

		this.$elem
			.onC('click', '.controls:eq(1) a', function () {
				this.$elem.parent()[0].scrollIntoView(true);
				this.$elem.parent().parent()[0].scrollIntoView(true);
				this.$elem.parent().parent().parent()[0].scrollIntoView(true);
			}, this);
	},

	updateControls: function(data) {
		if (this.prevPage === this.curPage) {
			this.prevPage = '';
		} else {
			if (typeof this.prevPage === 'undefined') this.prevPage = '';
		}

		if (this.nextPage !== this.curPage) {
			if (typeof this.nextPage === 'undefined') this.nextPage = '';
		}

		data = {
			prevPage: this.prevPage,
			curPage: this.curPage,
			nextPage: this.nextPage,
			path: this.PATH,
			config: this.config
		};

		this.tpl('controls', data, scopeC(function(html) {
			this.$controls.html(html);
		}, this));
	},

	_apifyWordpress: function(url) {
		url = this._fixUrl(url);
		return url + '/feed/';
	},

	_apifyTumblr: function(url) {
		var prefix = 'https://api.tumblr.com/v2/blog/' + url;
		var action = '/posts/?callback=?';

		return prefix + action;
	},

	_apifyBlogger: function(url) {
		url = this._fixUrl(url);
		return 'https://www.googleapis.com/blogger/v3/blogs/byurl?callback=?' +
			'&url=' + url;
	},

	renderPostCb: function(html) {
		// HACK: to better deal with random markup
		var $t = $($.parseHTML(html));
		$t.find('a').attr('target', '_blank');
		this.$main.append($t);
	},

	renderWPPosts: function(data) {
		var items = data.items;
		var len = items.length;
		var start = this.curPage;
		var end = len - 1;

		/* Disable pagination for wordpress for now
		if (start + this.limit >= len) {
			end = len;
			this.nextPage = this.curPage;
		} else {
			this.nextPage = end = start + this.limit;
		}

		if (start - this.limit < 0) {
			this.prevPage = 0;
		} else {
			this.prevPage = start - this.limit;
		}
		this.updateControls();
		*/

		this.updateControls();
		this.$main.empty();
		for (var i=start; i<=end; i++) {
			this.renderWPPost(items[i]);
		}
	},

	renderWPPost: function(post) {
		var body = post.content || post.description,
			date = new Date(post.updated);

		this.tpl('textpost', {
			title: post.title,
			body: body,
			link: post.link,
			date: date.toDateString()
		}, scopeC(this.renderPostCb, this));
	},

	renderBloggerPosts: function(data) {
		if (data.error) return;
		var postsUrl = data.posts.selfLink;
		var params = {
			key: this.BLOGGER_API_KEY,
			maxResults: this.limit
		};
		if (this.curPage) params.pageToken = this.curPage;
		$.getJSON(postsUrl, params, scopeC(function(data) {
			var posts = data.items;
			this.prevPage = data.prevPageToken || '';
			this.nextPage = data.nextPageToken;
			this.updateControls();
			for (var i=0, len=posts.length; i<len; i++) {
				this.renderBloggerPost(posts[i]);
			}
		}, this));
	},

	renderBloggerPost: function(post) {
		this.tpl('textpost', {
			title: post.title,
			body: post.content,
			link: post.url
		}, scopeC(this.renderPostCb, this));
	},

	renderTumblrPosts: function(data) {
		var posts = data.response.posts;
		var post;
		if (!posts) return;
		this.nextPage = this.curPage + this.limit;
		this.prevPage = this.limit > this.curPage ? 0 : this.curPage - this.limit;
		if (this.nextPage >= data.response.total_posts) this.nextPage = this.curPage;
		this.updateControls();

		for (var i=0, len=posts.length; i<len; i++) {
			post = posts[i];
			if (post.type === 'text') {
				this.renderTumblrTextPost(post);
			} else if (post.type === 'photo') {
				this.renderTumblrPhotoPost(post);
			} else if (post.type === 'link') {
				this.renderTumblrLinkPost(post);
			} else if (post.type === 'quote') {
				this.renderTumblrQuotePost(post);
			} else if (post.type === 'chat') {
				this.renderTumblrTextPost(post);
			} else if (post.type === 'video') {
				this.renderTumblrVideoPost(post);
			}
		}
	},

	convertTimeStamp: function(timestamp) {
		var date = new Date(timestamp * 1000); // fix milliseconds
		date = date.toDateString();

		return date;
	},

	renderTumblrTextPost: function(post) {
		this.tpl('textpost', {
			date: this.convertTimeStamp(post.timestamp),
			title: post.title,
			body: post.body,
			link: post.post_url
		}, scopeC(this.renderPostCb, this));
	},

	renderTumblrPhotoPost: function(post) {
		var cb = scopeC(function(html) {
			this.$main.append(html);
		}, this);
		this.tpl('photopost', {
			caption: post.caption,
			photos: post.photos,
			date: this.convertTimeStamp(post.timestamp)
		}, cb);
	},

	renderTumblrVideoPost: function(post) {
		var cb = scopeC(function(html) {
			this.$main.append(html);
		}, this);
		var video = post.player[0].embed_code;
		video = video.replace('<video','<video controls ')
		this.tpl('videopost', {
			caption: post.caption,
			video: video,
			date: this.convertTimeStamp(post.timestamp)
		}, cb);
	},

	renderTumblrLinkPost: function(post) {
		this.tpl('linkpost', {
			title: post.title,
			linkUrl: post.url,
			tumblrUrl: post.url,
			desc: post.description
		}, scopeC(this.renderPostCb, this));
	},

	renderTumblrQuotePost: function(post) {
		this.tpl('quotepost', {
			source: post.source,
			text: post.text
		}, scopeC(this.renderPostCb, this));
	},

	setFeedUrl: function() {
		this._feedUrl = this._url;
		},

	// if the PhotoShelter Wordpress plugin is installed,
	// visiting /?PS_FEEDURL=true on a wordpress blog will produce JSON
	// containing the URL of the RSS feed,
	// which is used here to set wordpress_feedUrl
	setWPFeedUrlFormVal: function(data) {
		if (!!data) this.$editorForm.find('input[name="wordpress_feedUrl"]').val(data.rss_url);

		if (isset(this.wpFeedDfr)) {
			this.wpFeedDfr.resolve();
		}
	},

	// format and validate wordpress blog URL
	formatWPUrl: function(url) {
		var fv = {PS_FEEDURL: 'true'};

		if (this.urlRegex.exec(url) === null) return false;

		url = this._fixUrl(url);

		// secure URLs can be loaded directly,
		// but insecure URLs must route to our handler
		// so they aren't blocked as mixed content
		if (url.indexOf('http://') === 0) {
			fv.URL = url;
			fv._ACT = 'feedcheck';
			fv.ID = this.env('custom').id;
			url = '/ext/wp_handler';
		}

		// check that the PhotoShelter Wordpress plugin
		// is installed on the target blog,
		// use the result to set the wordpress_feedUrl
		$.ajax({
			type: 'GET',
			url: url,
			data: fv,
			dataType: 'json',
			crossDomain: true,
			success: scopeC(this.setWPFeedUrlFormVal, this)
		});

		return true;
	},

	// format and validate tumblr blog URL
	formatTumblrUrl: function(url, $url) {
		var valUpdChk = false;

		// tumblr expects just the host;
		// strip protocol & trailing slash
		if (url.indexOf('http://') === 0) {
			url = url.replace('http://', '');
			valUpdChk = true;
		}
		else if (url.indexOf('https://') === 0) {
			url = url.replace('https://', '');
			valUpdChk = true;
		}
		if (url.substr(url.length - 1) === '/') {
			url = url.substr(0, (url.length - 1));
			valUpdChk = true;
		}

		if (valUpdChk) $url.val(url);

		return (this.urlRegex.exec(url) !== null);
	},

	render: function(url, type, limit, feedUrl) {
		var controlsDfr;
		this._type = type;
		this._url = url;
		this._feedUrl = feedUrl;
		this.limit = parseInt(limit, 10);
		if (this.$main) {
			this.$main.html('<div class="loading-c2"><div class="bar-holder"><div class="loading-bar"></div></div></div>');
			controlsDfr = $.Deferred().resolve();
		} else {
			controlsDfr = this.tpl('main', {}, scopeC(function(html){
				this._clearElem();
				this.$elem.append(html);

				this.$main = this.$elem.find('.main');
				this.$controls = this.$elem.find('.controls');

				return this.tpl('controls', {}, scopeC(function(html) {
					this.$controls.html(html);
				}, this));
			}, this));
			return controlsDfr; // Return so that the url parse event will finish the render
		}

		var apify, renderPosts, params;

		if (this.curPage === null) {
			this.curPage = 0;
		}
		this.$elem.attr('data-type', type);
		switch(type) {
			case 'wordpress':
				var renderDfr = $.Deferred();
				var fv = {};
				this.curPage = parseInt(this.curPage, 10);
				if (isNaN(this.curPage)) {
					this.curPage = 0;
				}

				// secure URLs can be loaded directly,
				// but insecure URLs must route to our handler
				// so they aren't blocked as mixed content
				if (feedUrl.indexOf('http://') === 0) {
					fv.URL = feedUrl;
					fv._ACT = 'rss';
					fv.ID = this.env('custom').id;
					feedUrl = '/ext/wp_handler';
				}

				controlsDfr.done(scopeC(function() {
					$.getFeed({
						url: feedUrl,
						data: fv,
						success: scopeC(function(data) {
							renderDfr.resolve();
							this.$main.find(this.viewMap.loading).remove();
							this.renderWPPosts(data);
						}, this)
					});
				}, this));
				return renderDfr;
			case 'blogger':
				apify = this._apifyBlogger;
				if (!isNaN(this.curPage)) {
					this.curPage = '';
				}
				renderPosts = scopeC(this.renderBloggerPosts, this);
				params = {
					key: this.BLOGGER_API_KEY
				};
				break;
			case 'tumblr':
			default:
				apify = this._apifyTumblr;
				renderPosts = scopeC(this.renderTumblrPosts, this);
				this.curPage = parseInt(this.curPage, 10);
				if (isNaN(this.curPage)) {
					this.curPage = 0;
				}
				params = {
					api_key: this.TUMBLR_API_KEY,
					limit: this.limit,
					offset: this.curPage
				};
				break;
		}

		this.controllerCb('setLinkTag', {
			rel: 'canonical',
			href: 'http://' + url
		});

		var apiUrl = apify.call(this, url);

		return controlsDfr.done(scopeC(function() {
			$.getJSON(apiUrl, params).done(scopeC(function(data) {
				this.$main.find(this.viewMap.loading).remove();
				renderPosts(data);
			}, this));
		}, this));
	},

	renderPage: function(page) {
		this.curPage = page;
		this.render(this._url, this._type, this.limit, this._feedUrl);
	}
};

O_O.obj.inherit(O_O.lib.View, O_O.widget.BlogReader.View);

}(ps$));
;(function($, undefined) {
'use strict';

O_O.widget.BlogReader.Editor = function() {};

O_O.widget.BlogReader.View.prototype.editorRefresh = function($form) {
	var $token = $form.find("select[name='type']");
	var $note = $form.find('.plugin-info');
	var platform = $token.val();
	var $url, url;

	this.$editorForm = $form;

	if (!$note.length) {
		$note = $("<p class='plugin-info note'><a target='_blank' class='ignore-disable' href='http://wordpress.org/plugins/photoshelter-official-plugin'>PhotoShelter Plugin for WordPress</a><br>Version 1.5 or later is required</p>");
		$token.siblings('.ps-select').after($note);
	}

	$form.find('.typeSelect').toggleClass('ignore-disable', platform==='wordpress');
	$note.toggle(platform==='wordpress');

	// format and validate the blog URL
	switch (platform) {
	case 'wordpress':
		$url = $form.find('input[name="wordpress_url"]');
		url = $url.val();

		return this.formatWPUrl(url);
		break;
	case 'tumblr':
		$url = $form.find('input[name="tumblr_url"]');
		url = $url.val();

		return this.formatTumblrUrl(url, $url);
		break;
	case 'blogger': // blogger not actually used!
		$url = $form.find('input[name="blogger_url"]');
		break;
	default:
		return false;
	}
};

}(ps$));
(function($, undefined) {
'use strict';

O_O.widget.ImageCover.Controller = function($elem, props, msgSys, env) {
	O_O.lib.Controller.apply(this, arguments);

	this.f_shown = false;
	this.imgSize = this.env('max_img_sz');

	this.view = O_O.mm.oNew(O_O.widget.ImageCover.View, $elem, props,
		scopeC(this._controllerCb, this), env);
};

O_O.widget.ImageCover.Controller.prototype = {
	// implementInterfaces: {
	// 	Cover: {
	// 		show: function() {
	// 			return this._showCoverOnce.apply(this, arguments);
	// 		}
	// 	}
	// },

	f_shown: null,
	imgSize: null,

	render: function() {
		return new $.Deferred().resolve().promise(); // via iwc instead
	},

	// _eventH: null,
	_eventH: function(type, data) {
		if (type === 'showCoverImage') this._showCoverOnce(data);
	},

	_showCoverOnce: function(id) {
		if (this.f_shown) return;

		var $dfd = new $.Deferred();

		this._getKeyImageUrl(id).done(scopeC(function(url) {
			if (!url) {
				$dfd.resolve();
				return;
			}

			this.view.render(id, url).fail(function() {
				$dfd.reject();
			}).done(function() {
				this.f_shown = true;
				$dfd.resolve();
			});
		}, this));

		return $dfd.promise();
	},

	_getKeyImageUrl: function(id) {
		var type = ((id.charAt(0) === 'C') ? 'Collection' : 'Gallery') +
			'KeyImage';

		//force model load in settings mode to allow for changes to key image from uploads
		var loadParams = this.env('edit') ? {f_force: true} : {};
		return O_O.model.get(type, id).load(loadParams).then(scopeC(function(d) {
			return O_O.app.imgMkUrlFromData({
				width: this.imgSize,
				height: this.imgSize,
				mode: 'fit'
			}, d);
		}, this));
	}
};

O_O.obj.inherit(O_O.lib.Controller, O_O.widget.ImageCover.Controller);

}(ps$));
(function($, undefined) {
'use strict';

O_O.widget.ImageCover.View = function($elem, props, controllerCb, env) {
	O_O.lib.View.call(this, $elem, props, controllerCb, env);
};

O_O.widget.ImageCover.View.prototype = {
	render: function(id, url) {
		return this.tpl('main', {
			link: '/portfolio/' + id // FIXME: hardcoded
		}, scopeC(function(html) {
			this._clearElem();

			this.$elem.append(html).find('div').css({
				background: 'url(' + url + ')',
				'background-repeat': 'no-repeat',
				'background-position': 'center top',
				'background-size': 'contain'
			});
		}, this));
	}
};

O_O.obj.inherit(O_O.lib.View, O_O.widget.ImageCover.View);

}(ps$));
;(function($, undefined) {
'use strict';

O_O.widget.ShareUrl.Controller = function($elem, props, msgSys, env) {
	O_O.lib.Controller.apply(this, arguments);

	this.view = O_O.mm.oNew(O_O.widget.ShareUrl.View, $elem, props,
		scopeC(this._controllerCb, this), env);
};

O_O.widget.ShareUrl.Controller.prototype = {
	implementInterfaces: {
		Share: {
			toggle: function(f, idx) {
				this.view.toggle(f, idx);
				if (!this.written) this.writeDOM(idx);
			}
		}
	},

	written: false,

	render: function(config) {
		this.config = config;
		return new $.Deferred().resolve().promise();
	},

	writeDOM: function(idx) {
		this.written = true;
		return this.view.render(this.config, idx);
	},

	_controllerCb: function(type, payload) {
		switch (type) {
		case 'close':
			payload = {
				msg: 'closeShare',
				data: {}
			};
			this.msgSys.pub('SlideShowControls:Controller', payload);
			break;
		case 'editWidget':
			return this.msgSys.pub('Shell', {
				msg: 'editWidget',
				data: {
					view: payload.view,
					cfgId: this.getCfg()
				}
			});
		}
	},

	/* unused functions (here to override abstract controller) */

	_eventH: null
};

O_O.obj.inherit(O_O.lib.Controller, O_O.widget.ShareUrl.Controller);

}(ps$));
;(function($, undefined) {
'use strict';

O_O.widget.ShareUrl.View = function($elem, props, controllerCb, env) {
	O_O.lib.View.apply(this, arguments);
};

O_O.widget.ShareUrl.View.prototype = {
	_pinSz: 750, // max width and height for img for pinterest share
	_serviceNames: { // class name in tpl: arg name in socialShare library
		'google_plusone_share': 'gplus',
		'facebook': 'facebook',
		'twitter': 'twitter',
		'pinterest': 'pinterest'
	},

	idx: null,
	gid: null,

	_init: function() {
		this._bindEvents();
		this._shareLibSetup();
	},

	_shareLibSetup: function() {
		var f_dev = (this.env('custom').isDevDomain);

		SocialShareUtil.setFB_ID(f_dev);
		SocialShareUtil.loadTwitter();
		SocialShareUtil.loadPinterest();
	},

	render: function(config, idx) {
		this.config = config;
		return this.tpl('main', this.config, scopeC(function(html){
			this._clearElem(); // clear all but config
			this.$elem.append(html);
			this._setScrolling();
			this._setLinks(idx);
			this._setZeroClip();
		}, this));
	},
	_setZeroClip: function(clip1, clip2) {
		clip1 = new ZeroClipboard(
			this.$elem.find('[data-clipboard-target="copyURL"]')[0],
			{
				moviePath: '/js/zeroclip/ZeroClipboard.swf'
			}
		);
		clip2 = new ZeroClipboard(
			this.$elem.find('[data-clipboard-target="copyEmbed"]')[0],
			{
				moviePath: '/js/zeroclip/ZeroClipboard.swf'
			}
		);
		var that = this;
		clip1.on('load', function() {
			that.$elem.find('[data-clipboard-target="copyURL"]').show();

			clip1.on('aftercopy', function() {
				this._gaEvent('ShareUrl', 'copyURL', that._mkEventLabel());
			});
		});


		clip2.on('load', function() {
			that.$elem.find('[data-clipboard-target="copyEmbed"]').show();

			clip2.on('aftercopy', function() {
				this._gaEvent('ShareUrl', 'copyEmbed', that._mkEventLabel());
			});
		});
	},
	_setScrolling: function() {
		if (typeof this.config !== 'undefined' &&
				typeof this.config.f_innerScroll !== 'undefined' &&
				this.config.f_innerScroll) {
			this._destroyNano();
			this.$elem.find('.content').scrollTop(0);
			this.$elem.nanoScroller({ iOSNativeScrolling: true });
		}
	},
	_destroyNano: function() {
		if (this.$elem[0].nanoscroller && this.$elem[0].nanoscroller !== null) {
			this.$elem.nanoScroller({ stop: true });
			this.$elem[0].nanoscroller = null;
		}
	},
	toggle: function(f, idx) {
		if (typeof f === 'undefined') f = null;
		this.$elem.toggleClass('on', f);

		if (typeof idx !== 'undefined' && $(this.$elem).hasClass('on'))
			this._setLinks(idx);
		if (f === null || !!f) this._setScrolling();
	},
	getQueryVariable: function (variable) {
		var query = window.location.search.substring(1),
			vars = query.split('&'),
			pair;
		for (var i=0;i<vars.length;i++) {
			pair = vars[i].split('=');
			if (pair[0] === variable) {
				return pair[1];
			}
		}
		return(false);
	},
	_isId: function(id) {
		// can't test on page since may not yet be loaded in a clc
		return (typeof id === 'string') &&
			!!id.match(/^I[a-zA-Z0-9\._]{15}$/);
	},
	_setLinks: function(idx) {
		this.idx = idx;
		var url = this._mkShareURL(idx);

		this.$elem.find('.link').val(url);

		// for embedable slideshow
		var gid = this.getQueryVariable('G_ID');
		if (!gid) return;

		this.gid = gid;
		this.$elem.find('.embed')
			.val('<div style="width:800px;height:600px;" data-ps-embed-type="slideshow" ' +
				'data-ps-embed-gid="' + gid + '"></div><script src="' + location.origin +
				'/js/psEmbed.js"></script><script>_psEmbed("' + location.origin +
				'");</script>');
	},
	_getSiteName: function() {
		return this.env('custom').site_name;
	},
	_getGalName: function(gid) {
		var gal = O_O.model.get('Gallery', gid);
		return gal.extractPrimitiveData().name;
	},
	_mkShareText: function() {
		var gid = this.getQueryVariable('G_ID');
		if (gid) return this._getGalName(gid);

		return this._getSiteName();
	},
	_mkShareURL: function(idx) {
		idx = idx || null;
		var href = location.href;

		href = href.replace('?edit', ''); // don't share site builder link
		href += ((typeof idx !== 'undefined' && !this._isId(idx) && idx !== null) ? '/' + idx : '');

		return href;
	},
	_mkEventLabel: function() {
		return (((isset(C2_CFG)) ? C2_CFG.customEnv.id : '') + window.location.pathname);
	},
	_mkImgUrl: function() {
		if (this.idx) { // beam
			var host = this.env('custom').server.img;
			return host + O_O.app.imgGet(this.idx, 's/' + this._pinSz);
		} else if (this.gid) { // slideshow
			var gal = O_O.model.get('Gallery', this.gid);
			return gal.getKeyImageModel().getLinkForSize({sz: this._pinSz});
		}

		return '';
	},
	_mkShareAttr: function(service) {
		var attr = {url: this._mkShareURL()};
		switch(service) {
			case 'twitter':
				attr.twitter = {text: this._mkShareText()};
				break;
			case 'pinterest':
				attr.note = this._mkShareText();
				attr.imgUrl = this._mkImgUrl();
				break;
			case 'facebook':
				var server = this.env('custom').server.web;
				attr.redirectUrl = server + '/ext/facebook_redirect.php';
				break;
			default:
		}
		return attr;
	},
	_socialShare: function(shareType) {
		var service = this._serviceNames[shareType];
		if (!service) throw new Error(shareType + ' is not a valid service name');
		socialShare(service, this._mkShareAttr(service), this._shareCb.bind(this, service));
	},
	_shareCb: function(service) {
		// only called if service is 'twitter'.
		var action = service + '-share-success';
		var label = this._mkEventLabel();

		this._gaEvent('ShareUrl', action, label);
	},
	_bindEvents: function() {
		this.$elem
			.onC('touchstart touchmove', function(e){
				if (typeof this.config !== 'undefined' &&
					typeof this.config.f_innerScroll !== 'undefined' &&
					this.config.f_innerScroll)
						e.stopPropagation();
			}, this)
			.onC('click', '.close', function(e) {
				e.preventDefault();
				this.toggle(false);
				this.controllerCb('close');
			}, this)
			.onC('click', function(e) {
				if (!this.config.f_closeable) return;
				if (e.target.className.search('widget') === -1 &&
					e.target.className.search('content') === -1) return;
				e.preventDefault();
				this.toggle(false);
				this.controllerCb('close');
			}, this)
			.on('click', 'input[type=text]', function() {
				this.select();
			})
			.onC('click', '.shareEmail', function(e){
				e.preventDefault();
				var $this = this.$elem.find('#emailURL'),
				    input = $this.val(),
				    label = this._mkEventLabel();

				if (input === '') {
					$this.attr('placeholder','Please enter an email address');
				} else {
					this._gaEvent('ShareUrl', 'email', label);

					var url = this._mkShareURL();
					var subject = this._mkShareText();
					socialShare('email', {
						to: input,
						subject: subject,
						body: url
					});
				}
			}, this)
			.onC('click', 'a', function(e) {
				e.preventDefault();
				var $this = $(e.currentTarget),
				    shareType = $this.attr('class'),
				    label = this._mkEventLabel();

				this._socialShare(shareType);
				this._gaEvent('ShareUrl', shareType, label);
			}, this);
	}
};

O_O.obj.inherit(O_O.lib.View, O_O.widget.ShareUrl.View);

}(ps$));
(function($) {

O_O.widget.ImageStage.Controller = function($elem, props, msgSys, env) {
	O_O.lib.Controller.apply(this, arguments);

	this.view = O_O.mm.oNew(O_O.widget.ImageStage.View, $elem, props,
		scopeC(this._controllerCb, this), env);
};

O_O.widget.ImageStage.Controller.prototype = {
	noState: false,

	delegateInterfaces: {
		State: {
			required: false,
			functions: ['count']
		},
		ImageMeta: {
			required: false,
			functions: ['load']
		}
	},

	jumpedTo: null,

	implementInterfaces: {
		Gallery: {
			load: function(gal, write, id, noState, c_id) {
				this.jumpedTo = true;
				if (isset(c_id) && c_id !== null) this.c_id = c_id;
				else if (this.galId !== gal.id)
					this.c_id = false;
				if (!isset(id)) {
					noState = true;
					if (isset(c_id))
						this._controllerCb('updateClcGal', {
							galId: gal.id,
							clcId: c_id
						});
				}
				this.galId = gal.id;
				if (typeof noState !== 'undefined') {
					this.noState = noState;
				}
				this.toggle(gal, write, id);
			}
		},
		Images: {
			set: function(imgs, id, noState) {
				this.imgs = imgs;
				this.gallery = false;
				if (!isset(id)) {
					noState = true;
				}
				if (typeof noState !== 'undefined') {
					this.noState = noState;
				}
				this.view.renderImages(this.imgs, id);
			}
		},
		Page: {
			goTo: function(dir) {
				this.view._goTo(dir);
			},
			chrome: function(settings) {
				this.view._toggleChrome(settings);
			}
		},
		Play: {
			toggle: function(cfg, jumpedTo) {
				if (isset(jumpedTo)) this.jumpedTo = jumpedTo;
				this.view._playState(cfg, this.jumpedTo);
				this.jumpedTo = false;
			}
		},
		JumpTo: {
			image: function(idx, noState) {
				this.thaw();
				this.jumpedTo = true;
				this.noState = noState || false;
				if (this.gallery)
					this.view.render(this.config, this.gallery, this.galleryData, idx);
				else (this.imgs)
					this.view.renderImages(this.imgs, idx);
			}
		},
		Meta: {
			toggle: function(f) {
				this.view.toggleMeta(f);
			}
		},
		WhatMeta: {
			what: function(elms) {
				this.view.toggleMeta();
				this.view.metaClassExtend = '';
				for (var i = elms.length - 1; i >= 0; i--) {
					this.view.metaClassExtend += ' ' + elms[i];
				}
				this.view.toggleMeta();
			}
		}
	},

	imgId: null,
	frozen: true,

	freeze: function() {
		O_O.lib.Controller.prototype.freeze.call(this);
		if (!this.frozen) {
			this.frozen = true;
			this.view.freeze();
		}
	},

	thaw: function() {
		O_O.lib.Controller.prototype.thaw.call(this);
		if (!!this.frozen) {
			this.frozen = false;
			this.view.thaw();
		}
	},

	render: function(cfg) {
		this.config = cfg;
		return this.view.render(this.config);
	},

	toggle: function(gal, write, id) {
		this.imgs = false;
		this.gallery = O_O.model.get('Gallery', gal.id);
		this.gallery.load().done(scopeC(function(galleryData){
			this.galleryData = galleryData;
			if (!!write) this.write(typeof id === 'undefined' ? 0 : id);
		}, this));
	},

	write: function(id) {
		this.imgId = id;
		this.view.render(this.config, this.gallery, this.galleryData, this.imgId);
	},

	_controllerCb: function(type, payload) {
		var data;
		switch (type) {
		case 'updateClcGal':
			data = payload;
			this.msgSys.pub('Shell', {
				msg: 'event',
				data: {
					type: 'updatePath',
					data: data
				}
			});
			return;
		case 'updateImage':
			this.delegate('State', 'count')(
				payload[0],
				this.config.size,
				(isset(payload[1].id)) ? payload[1].id : payload[1].getId().image_id
			);
			if (this.delegateMap.ImageMeta)
				this.delegate('ImageMeta', 'load')(payload[1], this.galleryData);
			if (this.noState || !this.f_active) {
				this.noState = false;
				return;
			}
			data = {
				imgId: [payload[1].getId().image_id]
			};
			if (!this.imgs)
				data.galId = [payload[1].getId().gallery_id];
			if (isset(this.c_id) && this.c_id !== false)
				data.clcId = this.c_id;
			this.msgSys.pub('Shell', {
				msg: 'event',
				data: {
					type: 'updatePath',
					data: data
				}
			});
			break;
		case 'toggle':
			this.showing = payload.showing;
			this.toggle();
			break;
		case 'editWidget':
			return this.msgSys.pub('Shell', {
				msg: 'editWidget',
				data: {
					view: payload.view,
					cfgId: this.getCfg()
				}
			});
		}
	},

	// Because old themes are stupid.
	// Support outdated msgCB as well
	// as IWC for newer themes.
	_msgCb: function(channel, payload) {
		var d = payload.data;
		switch (payload.msg) {
		case 'event':
			return this._eventH(d.type, d.data);
		case 'thaw':
			this.thaw();
			break;
		case 'freeze':
			this.freeze();
			break;
		}
	},

	_eventH: function(type, data) {
		switch(type) {
		case 'windowResize':
			this.view.resize();
			break;
		}
	}
};

O_O.obj.inherit(O_O.lib.Controller, O_O.widget.ImageStage.Controller);

})(ps$);
(function($) {

O_O.widget.ImageStage.View = function($elem, props, controllerCb, env) {
	O_O.lib.View.apply(this, arguments);
};

O_O.widget.ImageStage.View.prototype = {
	gallery: null,
	images: [],
	idx: null,
	loaded: 0,
	f_active: null,

	$img: null,
	$current: null,
	$next: null,
	$previous: null,
	$blank: null,

	animId: false,
	animing: false,
	isTouching: false,
	touched: false,
	isSliding: false,
	touchTime: 0,
	startX: 0,
	currentX: 0,
	d: 0,

	actionQueue: [],
	playing: false,
	timer: null,
	settingClasses: null,

	transEndEventName: O_O.browser.transEndEventName(),
	transPropertyName: Modernizr.prefixed('transform'),
	hasTransition: Modernizr.prefixed('transition'),

	metaClassBase: 'meta-on',
	metaClassExtend: '',

	elemWidth: 0,

	_init: function() {
		this.config = this.config || {};
		this._bindEvents();
	},
	render: function(cfg, gal, galData, id) {
		if (id === false) return;
		var dfr = new $.Deferred().resolve();
		this.elemWidth = this.$elem.width();
		if (cfg) {
			this.config = $.extend({}, this.config, cfg);
			this.settingClasses = this.config.transition + ' ' + this.config.size;
		}
		if (gal)
			this.gallery = gal;

		if (this.gallery) {
			this.gallery.getImages()
				.done(scopeC(function(imageModels){
					this.renderImages(imageModels, id);
				}, this));
		} else if (this.images.length) {
			this.renderImages(this.images, this.idx);
		}

		return dfr.promise();
	},

	renderImages: function(imageModels, id) {
		if (!imageModels || imageModels.length < 1) return;
		this.images = imageModels;
		this._getIdx(id);
		this.controllerCb(
			'updateImage',
			[{
				current: this.idx+1,
				count: this.images.length,
				ids: this.images[this.idx]._id,
				galName: this.images[this.idx].g_name
			}, this.images[this.idx]]
		);
		this._initialLoad();
		return this.tpl('main', {
				config: this.config,
				current: this.showing('current').getLinkForSize({
						width: this.env('max_img_sz'),
						height: this.env('max_img_sz'),
						mode: 'fit'
					}),
				next: this.showing('next').getLinkForSize({
						width: this.env('max_img_sz'),
						height: this.env('max_img_sz'),
						mode: 'fit'
					}),
				previous: this.showing('previous').getLinkForSize({
						width: this.env('max_img_sz'),
						height: this.env('max_img_sz'),
						mode: 'fit'
					})
			}, scopeC(function(html){
				this._clearElem();
				this.animing = false;
				this.$elem.append(html);
				this.startPlaying();
				this.$imgs = this.$elem.children('.img');
				this.$current = this.$elem.find('.current');
				this.$next = this.$elem.find('.next');
				this.$previous = this.$elem.find('.previous');
				this.$blank = this.$elem.find('.blank');
			}, this));
	},

	freeze: function() {
		this.f_active = false;
	},
	thaw: function() {
		this.f_active = true;
		if (!this.animId)
			this.animId = window.requestAnimationFrame(scopeC(this.animationTasks, this));
	},

	_toggleChrome: function(settings) {
		if(!(C2_CFG.theme === 'Theme5' && $('document').width() < 1024)) {
			this.$elem.toggleClass('chrome-off', settings.isChromeOff);
		}
	},

	toggleMeta: function(f) {
		if (typeof f === 'undefined') f = null;
		this.$elem.toggleClass(this.metaClassBase + ' ' + this.metaClassExtend, f);
	},

	_getIdx: function(id) {
		if (typeof id !== 'string') {
			this.idx = id || 0;
		} else {
			this.idx = 0;
			for (var i = 0, l = this.images.length; i < l; i++) {
				if (id === this.images[i].getId().image_id) this.idx = i;
			}
		}
	},

	resize: function() {
		this.elemWidth = this.$elem.width();
	},

	_playState: function(cfg, jumpedTo) {
		var wasPlaying = this.config.f_play;
		this.config = $.extend({}, this.config, cfg);
		this.settingClasses = this.config.transition + ' ' + this.config.size;
		if (jumpedTo) {
			if (this.config.f_play === 't' && wasPlaying !== 't')
				this.startPlaying();
			return;
		}
		if (this.f_active &&
			this.config.f_play === 't' &&
			typeof this.idx !== 'undefined' &&
			this.idx >= 0 &&
			this.$current !== null &&
			this.images.length > 1) {
				if (!this.playing) {
					this.playing = true;
					this._goTo('forward');
				}
		} else {
			this.playing = false;
		}
	},

	startPlaying: function() {
		if (this.images && this.config.f_play === 't' && this.images.length > 1) {
			this.timer = parseFloat(this.config.duration, 10) * 60;
			this.playing = true;
		}
	},

	cleanUp: function(e, direction) {
		var $current = (e)?$(e.currentTarget):this.$elem.find('.current'),
			idx = this.idx;
		if (!this.animing) return;
		switch (direction) {
			case 'forward':
				this.idx = this._next();
				this.$current = this.$next;
				this.$next = this.$blank;
				this.$blank = this.$previous;
				this.$previous = $current;
				this.$next.removeAttr('style').css(
					'background-image',
					'url(' + this.showing('next').getLinkForSize({
							width: this.env('max_img_sz'),
							height: this.env('max_img_sz'),
							mode: 'fit'
					}) + ')'
				);
				break;
			case 'backward':
				this.idx = this._previous();
				this.$current = this.$previous;
				this.$previous = this.$blank;
				this.$blank = this.$next;
				this.$next = $current;
				this.$previous.removeAttr('style').css(
					'background-image',
					'url(' + this.showing('previous').getLinkForSize({
							width: this.env('max_img_sz'),
							height: this.env('max_img_sz'),
							mode: 'fit'
					}) + ')'
				);
				break;
		}
		if (this.idx !== idx)
			this.controllerCb(
				'updateImage',
				[{

					current: this.idx+1,
					count: this.images.length,
					ids: this.images[this.idx]._id,
					galName: this.images[this.idx].g_name
				}, this.images[this.idx]]
			);
		this._removeAnims();
		if (!this.actionQueue.length) {
			this.startPlaying();
		}
		this._preload();
	},

	_removeAnims: function() {
		this.$current.attr('class', 'current ' + this.settingClasses);
		this.$previous.attr('class', 'previous ' + this.settingClasses);
		this.$next.attr('class', 'next ' + this.settingClasses);
		this.$blank.attr('class', 'blank ' + this.settingClasses);
		this.animing = false;
	},

	_goTo: function(move, touched) {
		switch (move) {
			case 'forward':
			case 'backward':
				if (!this.animing) {
					var catchup = touched ? ' with-swipe' : '';
					this.animing = true;
					this.$current.one(this.transEndEventName, scopeC(function(e) {
							this.cleanUp(e, move);
						}, this));
					this.$imgs
						.addClass('with-anim ' + move + catchup);

					//IE9 coverage.
					if(!this.hasTransition || this.config.transition === 'c') {
						this.cleanUp(null, move);
					}
				} else if (!this.playing && this.actionQueue.length < 2) {
					this.actionQueue.push(move);
				}
				break;
			default:
				if (typeof move === 'undefined') break;
				this.touched = true;
				if (this.elemWidth === 0) this.elemWidth = this.$elem.width();
				if (Math.abs(this.startX - this.currentX) > 10) {
					move.preventDefault();
					move.stopPropagation();
				}
				switch(move.type) {
				case 'touchstart':
					this.startSwipe(move);
					break;
				case 'touchmove':
					this.swipe(move);
					break;
				case 'touchend':
				case 'touchcancel':
					this.endSwipe();
					break;
				}
				break;
		}
	},

	startSwipe: function(e) {
		this.isTouching = true;
		this.startX = this._getPageX(e);
		this.currentX = this._getPageX(e);
	},

	swipe: function(e) {
		this.swiped = true;
		this.currentX = this._getPageX(e);
	},

	endSwipe: function() {
		this.testChange();
		this.touchTime = 0;
		this.isTouching = false;
		this.isSliding = false;
		this.startX = 0;
		this.currentX = 0;
	},

	testChange: function() {
		var change = this.currentX - this.startX,
			changeAbs = Math.abs(change),
			changeClass = 'with-anim ',
			threashold = Math.min(50, this.touchTime * 5),
			fastSwipeBoundryHigh = (this.config.transition === 'f') ? 200 : 300,
			fastSwipeBoundryLow = threashold + Math.max(0, 50 - this.touchTime * 5),
			reset = {
				'opacity': ''
			};
		reset[this.transPropertyName] = '';

		if (change > threashold)
			this._goTo('backward');
		else if (change < -threashold)
			this._goTo('forward');
		else {
			this.$current
				.one(this.transEndEventName, scopeC(function(e){
					this.cleanUp(e, null);
				}, this));
		}

		if (changeAbs > fastSwipeBoundryHigh || changeAbs < fastSwipeBoundryLow)
			changeClass += 'with-swipe ';
		if (changeAbs > threashold)
			changeClass += 'from-swipe ';

		this.$imgs
			.addClass(changeClass)
			.css(reset);
	},

	_doSlide: function() {
		if(this.isSliding || Math.abs(this.startX - this.currentX) > (10 - this.touchTime / 10)) {
			if (!this.isSliding)
				this.startX = this.currentX;
			this.isSliding = true;
			var d = this.currentX - this.startX;
			switch (this.config.transition) {
				case 's':
					var prev = this._translate3dStr(-this.elemWidth + d),
						curr = this._translate3dStr(d),
						next = this._translate3dStr(this.elemWidth + d);

					// translate all images left or right by delta
					this.$previous.css(this.transPropertyName, prev);
					this.$current.css(this.transPropertyName, curr);
					this.$next.css(this.transPropertyName, next);
					break;
				case 'f':
					var show = (d > 0) ? '$previous' : '$next',
						opacity = Math.sqrt((Math.abs(d) / this.elemWidth)),
						opacityOff = 1 - opacity;

					this.$current.css('opacity', opacityOff);
					this[show].css('opacity', opacity);
					break;
			}
		}
	},

	animationTasks: function() {
		if (this.playing) {
			this.timer-=1;
			if (this.timer === 0) {
				this._goTo('forward');
			}
		}
		if (this.isTouching && !this.animing) {
				this.touchTime++;
				this._doSlide();
		}
		if (this.f_active)
		{
			this.animId = window.requestAnimationFrame(scopeC(this.animationTasks, this));
			if (this.actionQueue.length > 0 && !this.playing) {
				this._goTo(
					this.actionQueue.shift(),
					O_O.browser.getResponsiveState() !== 'handhelds' ? this.touched : false
				);
			}
		}
		else
			this.animId = false;
	},

	showing: function(position) {
		switch (position) {
			case 'current':
				return this.images[this.idx];
			case 'next':
				return this.images[this._next()];
			case 'previous':
				return this.images[this._previous()];
		}
	},

	_next: function(idx) {
		idx = idx || this.idx;
		if (idx + 1 < this.images.length) {
			return idx + 1;
		} else {
			return 0;
		}
	},

	_previous: function(idx) {
		idx = idx || this.idx;
		if (idx - 1 > -1) {
			return idx - 1;
		} else {
			return this.images.length - 1;
		}
	},

	_initialLoad: function() {
		// FIXME: use group singleton when scheduler supports
		var group = O_O.mm.oNew(O_O.lib.RequestGroup, this.IMG_PRIORITY),
			curr = this.images[this.idx].getLinkForSize({
							width: this.env('max_img_sz'),
							height: this.env('max_img_sz'),
							mode: 'fit'
					}),
			prevIdx = this._previous(this._previous()),
			prev = this.images[prevIdx].getLinkForSize({
							width: this.env('max_img_sz'),
							height: this.env('max_img_sz'),
							mode: 'fit'
					}),
			nextIdx = this._next(this._next()),
			next = this.images[nextIdx].getLinkForSize({
							width: this.env('max_img_sz'),
							height: this.env('max_img_sz'),
							mode: 'fit'
					});
		group.addRequest(new O_O.lib.Request.Image($('<img/>'), curr, scopeC(this._initCB, this)));
		group.addRequest(new O_O.lib.Request.Image($('<img/>'), prev, scopeC(this._initCB, this)));
		group.addRequest(new O_O.lib.Request.Image($('<img/>'), next, scopeC(this._initCB, this)));
		O_O.scheduler.addGroup(group);
	},

	_initCB: function() {
		this.loaded++;
		if (this.loaded === 3) {
			this._preload();
		}
	},

	_preload: function() {
		// FIXME: use group singleton when scheduler supports
		var group = O_O.mm.oNew(O_O.lib.RequestGroup, this.IMG_PRIORITY),
			prevIdx = this._previous(this._previous()),
			prev = this.images[prevIdx].getLinkForSize({
							width: this.env('max_img_sz'),
							height: this.env('max_img_sz'),
							mode: 'fit'
					}),
			nextIdx = this._next(this._next()),
			next = this.images[nextIdx].getLinkForSize({
							width: this.env('max_img_sz'),
							height: this.env('max_img_sz'),
							mode: 'fit'
					});
		group.addRequest(new O_O.lib.Request.Image($('<img/>'), prev, null));
		group.addRequest(new O_O.lib.Request.Image($('<img/>'), next, null));
		O_O.scheduler.addGroup(group);
	},

	_bindEvents: function() {},

	/*
	 * Utilities
	 */

	_translate3dStr: function(x, y) {
		x = x || 0;
		y = y || 0;
		if (Modernizr.csstransforms3d) {
			return 'translate3d(' + x + 'px,' + y + 'px,0)';
		} else if (Modernizr.csstransforms) {
			return 'translateX('+ x + 'px) translateY('+ y + 'px)';
		}
	},

	_getPageX: function(e) {
		if (typeof e.originalEvent.changedTouches !== 'undefined')
			return e.originalEvent.changedTouches[0].pageX;
		else
			return e.originalEvent.pageX;
	},

	_getPageY: function(e) {
		if (typeof e.originalEvent.changedTouches !== 'undefined')
			return e.originalEvent.changedTouches[0].pageY;
		else
			return e.originalEvent.pageY;
	}
};

O_O.obj.inherit(O_O.lib.View, O_O.widget.ImageStage.View);

})(ps$);
;(function($, undefined) {
'use strict';

O_O.widget.MetaViewer.Controller = function($elem, props, msgSys, env) {
	O_O.lib.Controller.call(this, $elem, props, msgSys, env);

	this.view = O_O.mm.oNew(O_O.widget.MetaViewer.View, $elem, props,
		scopeC(this._controllerCb, this), env);
};

O_O.widget.MetaViewer.Controller.prototype = {
	noWrite: false,

	delegateInterfaces: {
		Meta: {
			required: false,
			functions: ['remove']
		},
		WhatMeta: {
			required: false,
			functions: ['what']
		}
	},


	implementInterfaces: {
		Gallery: {
			load: function(gallery) {
				this._setGallery(gallery);
			}
		},
		ImageMeta: {
			load: function(image) {
				this._setImage(image);
			}
		},
		Meta: {
			toggle: function(f) {
				this.toggle(f);
			}
		}
	},

	render: function(config) {
		this.config = config;
		var what = [];
		if(this.config.f_content === 'titleCaption') {
			what.push('title');
			what.push('caption');
		} else {
			what.push(this.config.f_content);
		}
		if (this.delegateMap && this.delegateMap.WhatMeta)
			this.delegate('WhatMeta', 'what')(what);
		return this.view.render(config);
	},

	writeDOM: function(gallery) {
		if (this.noWrite) return;
		this.view.render(this.config, gallery);
	},

	toggle: function(f) {
		this.view.toggle(f);
	},

	_setGallery: function(gallery) {
		if (this.noWrite) return;
		this.view.render(this.config, gallery);
	},

	_setImage: function(image) {
		if (this.noWrite) return;
		this.image = image;
		this.image.getImageModel().load().done(scopeC(function(imageData){
			if (typeof imageData.caption === 'undefined') {
				this.image.getImageModel().load({f_force:true}).done(scopeC(function(imageData){
					this.view.render(this.config, imageData);
				}, this));
			} else {
				this.view.render(this.config, imageData);
			}
		}, this));
	},

	_setModel: function(d) {
		var model = d.model;
		this.model = this.model || O_O.model.get(model.type, model.id);
		if(model.id === 'ImageViewer') {
			this.IVstep = this.$elem.closest('article').attr('class');
		}
		this.model.sub(this._modelCB, this);
	},

	_modelCB: function(d) {
		if(typeof d.current !== 'undefined' && typeof this.IVstep !== 'undefined') {
			this.updateStep(d);
			var step = d[this.IVstep],
				gal = d.gals[step],
				id = gal.id;
			if(this.id !== id) {
				this.writeDOM(gal);
				this.id = id;
			}
		}
	},

	updateStep: function(d) {
		if (typeof d.newStep !== 'undefined' && !!d.newStep) {
			if (d.newStep === 'next') {
				if (this.IVstep === 'current') {
					this.IVstep = 'previous';
				} else if (this.IVstep === 'previous') {
					this.IVstep = 'next';
				} else if (this.IVstep === 'next') {
					this.IVstep = 'current';
				}
			} else if (d.newStep === 'previous') {
				if (this.IVstep === 'current') {
					this.IVstep = 'next';
				} else if (this.IVstep === 'previous') {
					this.IVstep = 'current';
				} else if (this.IVstep === 'next') {
					this.IVstep = 'previous';
				}
			}
		}
	},

	_controllerCb: function(type, payload) {
		switch (type) {
		case 'modified':
			if(this.IVstep === 'current') {
				this.msgSys.pub('PageControl:Controller', {
					msg: 'modified',
					data: {}
				});
			}
			break;
		case 'close':
			payload = {
				msg: 'closeMeta',
				data: {}
			};
			this.msgSys.pub('SlideShowControls:Controller', payload);
			break;
		case 'editWidget':
			return this.msgSys.pub('Shell', {
				msg: 'editWidget',
				data: {
					view: payload.view,
					cfgId: this.getCfg()
				}
			});
		}
	},

	_msgCb: function(channel, payload) {
		var d = payload.data;

		switch (payload.msg) {
		case 'event':
			return this._eventH(d.type, d.data);
		case 'useModel':
			this._setModel(d);
			break;
		}
	},

	_eventH: function(type) {
		if (type === 'windowResize') {
			this.view._setScrolling();
		}
	}
};

O_O.obj.inherit(O_O.lib.Controller, O_O.widget.MetaViewer.Controller);

}(ps$));
;(function($, undefined) {
'use strict';

O_O.widget.MetaViewer.View = function($elem, props, controllerCb, env) {
	O_O.lib.View.call(this, $elem, props, controllerCb, env);
};

O_O.widget.MetaViewer.View.prototype = {
	data: null,

	_init: function() {
		this.config = this.config || {};
		this._bindEvents();
	},

	render: function(config, data) {
		this.config = config;
		if (typeof data !== 'undefined') this.data = data;
		if(C2_CFG.theme === 'Theme4' && JSON.parse(C2_CFG.themeCfg).modes.portfolio.sets.gallerySingleImage[0].f_meta === 'a') {
			this.$elem.addClass('on');
		}
		if (this.data) {
			this.tpl('main', {
					data: this.data,
					config: this.config
				}, scopeC(function(html){
				var contents = {};
				this._clearElem();
				this._destroyNano();
				this.$elem
					.append(html);
				contents['data-content'] = this.config.f_content;
				this.$elem.attr(contents);
				this._setScrolling();
				this.controllerCb('modified');
			}, this));
		}

		return new $.Deferred().resolve().promise();
	},
	_setScrolling: function() {
		if (typeof this.config !== 'undefined' &&
				typeof this.config.f_innerScroll !== 'undefined' &&
				this.config.f_innerScroll &&
				this.$elem.find('.content').length > 0) {
			this._destroyNano();
			this.$elem.nanoScroller({ iOSNativeScrolling: true });
		}
	},
	_destroyNano: function() {
		if (this.$elem[0].nanoscroller && this.$elem[0].nanoscroller !== null) {
			this.$elem.nanoScroller({ stop: true });
			this.$elem[0].nanoscroller = null;
		}
	},
	toggle: function(f) {
		if (typeof f === 'undefined') f = null;
		this.$elem.toggleClass('on', f);
		this._setScrolling();
	},
	_bindEvents: function() {
		this.$elem
			.onC('touchstart touchmove', function(e){
				if (typeof this.config !== 'undefined' &&
					typeof this.config.f_innerScroll !== 'undefined' &&
					this.config.f_innerScroll)
						e.stopPropagation();
			}, this);
	}
};

O_O.obj.inherit(O_O.lib.View, O_O.widget.MetaViewer.View);

}(ps$));
