amazeui
Version:
Sleek, intuitive, and powerful front-end framework for faster and easier web development.
412 lines (340 loc) • 11.4 kB
JavaScript
'use strict';
var $ = require('jquery');
var UI = require('./core');
var PinchZoom = require('./ui.pinchzoom');
var Hammer = require('./util.hammer');
var animation = UI.support.animation;
var transition = UI.support.transition;
/**
* PureView
* @desc Image browser for Mobile
* @param element
* @param options
* @constructor
*/
var PureView = function(element, options) {
this.$element = $(element);
this.$body = $(document.body);
this.options = $.extend({}, PureView.DEFAULTS, options);
this.$pureview = $(this.options.tpl).attr('id',
UI.utils.generateGUID('am-pureview'));
this.$slides = null;
this.transitioning = null;
this.scrollbarWidth = 0;
this.init();
};
PureView.DEFAULTS = {
tpl: '<div class="am-pureview am-pureview-bar-active">' +
'<ul class="am-pureview-slider"></ul>' +
'<ul class="am-pureview-direction">' +
'<li class="am-pureview-prev"><a href=""></a></li>' +
'<li class="am-pureview-next"><a href=""></a></li></ul>' +
'<ol class="am-pureview-nav"></ol>' +
'<div class="am-pureview-bar am-active">' +
'<span class="am-pureview-title"></span>' +
'<div class="am-pureview-counter"><span class="am-pureview-current"></span> / ' +
'<span class="am-pureview-total"></span></div></div>' +
'<div class="am-pureview-actions am-active">' +
'<a href="javascript: void(0)" class="am-icon-chevron-left" ' +
'data-am-close="pureview"></a></div>' +
'</div>',
className: {
prevSlide: 'am-pureview-slide-prev',
nextSlide: 'am-pureview-slide-next',
onlyOne: 'am-pureview-only',
active: 'am-active',
barActive: 'am-pureview-bar-active',
activeBody: 'am-pureview-active'
},
selector: {
slider: '.am-pureview-slider',
close: '[data-am-close="pureview"]',
total: '.am-pureview-total',
current: '.am-pureview-current',
title: '.am-pureview-title',
actions: '.am-pureview-actions',
bar: '.am-pureview-bar',
pinchZoom: '.am-pinch-zoom',
nav: '.am-pureview-nav'
},
shareBtn: false,
// press to toggle Toolbar
toggleToolbar: true,
// 从何处获取图片,img 可以使用 data-rel 指定大图
target: 'img',
// 微信 Webview 中调用微信的图片浏览器
// 实现图片保存、分享好友、收藏图片等功能
weChatImagePreview: true
};
PureView.prototype.init = function() {
var _this = this;
var options = this.options;
var $element = this.$element;
var $pureview = this.$pureview;
this.refreshSlides();
$('body').append($pureview);
this.$title = $pureview.find(options.selector.title);
this.$current = $pureview.find(options.selector.current);
this.$bar = $pureview.find(options.selector.bar);
this.$actions = $pureview.find(options.selector.actions);
if (options.shareBtn) {
this.$actions.append('<a href="javascript: void(0)" ' +
'class="am-icon-share-square-o" data-am-toggle="share"></a>');
}
this.$element.on('click.pureview.amui', options.target, function(e) {
e.preventDefault();
var clicked = _this.$images.index(this);
// Invoke WeChat ImagePreview in WeChat
// TODO: detect WeChat before init
if (options.weChatImagePreview && window.WeixinJSBridge) {
window.WeixinJSBridge.invoke('imagePreview', {
current: _this.imgUrls[clicked],
urls: _this.imgUrls
});
} else {
_this.open(clicked);
}
});
$pureview.find('.am-pureview-direction').
on('click.direction.pureview.amui', 'li', function(e) {
e.preventDefault();
if ($(this).is('.am-pureview-prev')) {
_this.prevSlide();
} else {
_this.nextSlide();
}
});
// Nav Contorl
$pureview.find(options.selector.nav).on('click.nav.pureview.amui', 'li',
function() {
var index = _this.$navItems.index($(this));
_this.activate(_this.$slides.eq(index));
});
// Close Icon
$pureview.find(options.selector.close).
on('click.close.pureview.amui', function(e) {
e.preventDefault();
_this.close();
});
this.$slider.hammer().on('swipeleft.pureview.amui', function(e) {
e.preventDefault();
_this.nextSlide();
}).on('swiperight.pureview.amui', function(e) {
e.preventDefault();
_this.prevSlide();
}).on('press.pureview.amui', function(e) {
e.preventDefault();
options.toggleToolbar && _this.toggleToolBar();
});
this.$slider.data('hammer').get('swipe').set({
direction: Hammer.DIRECTION_HORIZONTAL,
velocity: 0.35
});
// Observe DOM
$element.DOMObserve({
childList: true,
subtree: true
}, function(mutations, observer) {
// _this.refreshSlides();
// console.log('mutations[0].type);
});
// NOTE:
// trigger this event manually if MutationObserver not supported
// when new images appended, or call refreshSlides()
// if (!UI.support.mutationobserver) $element.trigger('changed.dom.amui')
$element.on('changed.dom.amui', function(e) {
e.stopPropagation();
_this.refreshSlides();
});
$(document).on('keydown.pureview.amui', $.proxy(function(e) {
var keyCode = e.keyCode;
if (keyCode == 37) {
this.prevSlide();
} else if (keyCode == 39) {
this.nextSlide();
} else if (keyCode == 27) {
this.close();
}
}, this));
};
PureView.prototype.refreshSlides = function() {
// update images collections
this.$images = this.$element.find(this.options.target);
var _this = this;
var options = this.options;
var $pureview = this.$pureview;
var $slides = $([]);
var $navItems = $([]);
var $images = this.$images;
var total = $images.length;
this.$slider = $pureview.find(options.selector.slider);
this.$nav = $pureview.find(options.selector.nav);
var viewedFlag = 'data-am-pureviewed';
// for WeChat Image Preview
this.imgUrls = this.imgUrls || [];
if (!total) {
return;
}
if (total === 1) {
$pureview.addClass(options.className.onlyOne);
}
$images.not('[' + viewedFlag + ']').each(function(i, item) {
var src;
var title;
// get image URI from link's href attribute
if (item.nodeName === 'A') {
src = item.href; // to absolute path
title = item.title || '';
} else {
// NOTE: `data-rel` should be a full URL, otherwise,
// WeChat images preview will not work
src = $(item).data('rel') || item.src; // <img src='' data-rel='' />
src = UI.utils.getAbsoluteUrl(src);
title = $(item).attr('alt') || '';
}
// add pureviewed flag
item.setAttribute(viewedFlag, '1');
// hide bar: wechat_webview_type=1
// http://tmt.io/wechat/ not working?
_this.imgUrls.push(src);
$slides = $slides.add($('<li data-src="' + src + '" data-title="' + title +
'"></li>'));
$navItems = $navItems.add($('<li>' + (i + 1) + '</li>'));
});
$pureview.find(options.selector.total).text(total);
this.$slider.append($slides);
this.$nav.append($navItems);
this.$navItems = this.$nav.find('li');
this.$slides = this.$slider.find('li');
};
PureView.prototype.loadImage = function($slide, callback) {
var appendedFlag = 'image-appended';
if (!$slide.data(appendedFlag)) {
var $img = $('<img>', {
src: $slide.data('src'),
alt: $slide.data('title')
});
$slide.html($img).wrapInner('<div class="am-pinch-zoom"></div>').redraw();
var $pinchWrapper = $slide.find(this.options.selector.pinchZoom);
$pinchWrapper.data('amui.pinchzoom', new PinchZoom($pinchWrapper[0], {}));
$slide.data('image-appended', true);
}
callback && callback.call(this);
};
PureView.prototype.activate = function($slide) {
var options = this.options;
var $slides = this.$slides;
var activeIndex = $slides.index($slide);
var title = $slide.data('title') || '';
var active = options.className.active;
if ($slides.find('.' + active).is($slide)) {
return;
}
if (this.transitioning) {
return;
}
this.loadImage($slide, function() {
UI.utils.imageLoader($slide.find('img'), function(image) {
$slide.find('.am-pinch-zoom').addClass('am-pureview-loaded');
$(image).addClass('am-img-loaded');
});
});
this.transitioning = 1;
this.$title.text(title);
this.$current.text(activeIndex + 1);
$slides.removeClass();
$slide.addClass(active);
$slides.eq(activeIndex - 1).addClass(options.className.prevSlide);
$slides.eq(activeIndex + 1).addClass(options.className.nextSlide);
this.$navItems.removeClass().
eq(activeIndex).addClass(options.className.active);
if (transition) {
$slide.one(transition.end, $.proxy(function() {
this.transitioning = 0;
}, this)).emulateTransitionEnd(300);
} else {
this.transitioning = 0;
}
// TODO: pre-load next image
};
PureView.prototype.nextSlide = function() {
if (this.$slides.length === 1) {
return;
}
var $slides = this.$slides;
var $active = $slides.filter('.am-active');
var activeIndex = $slides.index($active);
var rightSpring = 'am-animation-right-spring';
if (activeIndex + 1 >= $slides.length) { // last one
animation && $active.addClass(rightSpring).on(animation.end, function() {
$active.removeClass(rightSpring);
});
} else {
this.activate($slides.eq(activeIndex + 1));
}
};
PureView.prototype.prevSlide = function() {
if (this.$slides.length === 1) {
return;
}
var $slides = this.$slides;
var $active = $slides.filter('.am-active');
var activeIndex = this.$slides.index(($active));
var leftSpring = 'am-animation-left-spring';
if (activeIndex === 0) { // first one
animation && $active.addClass(leftSpring).on(animation.end, function() {
$active.removeClass(leftSpring);
});
} else {
this.activate($slides.eq(activeIndex - 1));
}
};
PureView.prototype.toggleToolBar = function() {
this.$pureview.toggleClass(this.options.className.barActive);
};
PureView.prototype.open = function(index) {
var active = index || 0;
this.checkScrollbar();
this.setScrollbar();
this.activate(this.$slides.eq(active));
this.$pureview.show().redraw().addClass(this.options.className.active);
this.$body.addClass(this.options.className.activeBody);
};
PureView.prototype.close = function() {
var options = this.options;
this.$pureview.removeClass(options.className.active);
this.$slides.removeClass();
function resetBody() {
this.$pureview.hide();
this.$body.removeClass(options.className.activeBody);
this.resetScrollbar();
}
if (transition) {
this.$pureview.one(transition.end, $.proxy(resetBody, this)).
emulateTransitionEnd(300);
} else {
resetBody.call(this);
}
};
PureView.prototype.checkScrollbar = function() {
this.scrollbarWidth = UI.utils.measureScrollbar();
};
PureView.prototype.setScrollbar = function() {
var bodyPaddingRight = parseInt((this.$body.css('padding-right') || 0), 10);
if (this.scrollbarWidth) {
this.$body.css('padding-right', bodyPaddingRight + this.scrollbarWidth);
}
};
PureView.prototype.resetScrollbar = function() {
this.$body.css('padding-right', '');
};
UI.plugin('pureview', PureView);
// Init code
UI.ready(function(context) {
$('[data-am-pureview]', context).pureview();
});
module.exports = PureView;
// TODO: 1. 动画改进
// 2. 改变图片的时候恢复 Zoom
// 3. 选项
// 4. 图片高度问题:由于 PinchZoom 的原因,过高的图片如果设置看了滚动,则放大以后显示不全