/** * Popovers * @param {type} $ * @param {type} window * @param {type} document * @param {type} name * @param {type} undefined * @returns {undefined} */ (function($, window, document, name) { var CLASS_POPOVER = $.className('popover'); var CLASS_POPOVER_ARROW = $.className('popover-arrow'); var CLASS_ACTION_POPOVER = $.className('popover-action'); var CLASS_BACKDROP = $.className('backdrop'); var CLASS_BAR_POPOVER = $.className('bar-popover'); var CLASS_BAR_BACKDROP = $.className('bar-backdrop'); var CLASS_ACTION_BACKDROP = $.className('backdrop-action'); var CLASS_ACTIVE = $.className('active'); var CLASS_BOTTOM = $.className('bottom'); var handle = function(event, target) { if (target.tagName === 'A' && target.hash) { $.targets._popover = document.getElementById(target.hash.replace('#', '')); if ($.targets._popover && $.targets._popover.classList.contains(CLASS_POPOVER)) { return target; } else { $.targets._popover = null; } } return false; }; $.registerTarget({ name: name, index: 60, handle: handle, target: false, isReset: false, isContinue: true }); var onPopoverShown = function(e) { this.removeEventListener('webkitTransitionEnd', onPopoverShown); this.addEventListener($.EVENT_MOVE, $.preventDefault); $.trigger(this, 'shown', this); } var onPopoverHidden = function(e) { setStyle(this, 'none'); this.removeEventListener('webkitTransitionEnd', onPopoverHidden); this.removeEventListener($.EVENT_MOVE, $.preventDefault); $.trigger(this, 'hidden', this); }; var backdrop = (function() { var element = document.createElement('div'); element.classList.add(CLASS_BACKDROP); element.addEventListener($.EVENT_MOVE, $.preventDefault); element.addEventListener('tap', function(e) { var popover = $.targets._popover; if (popover) { popover.addEventListener('webkitTransitionEnd', onPopoverHidden); popover.classList.remove(CLASS_ACTIVE); removeBackdrop(popover); } }); return element; }()); var removeBackdropTimer; var removeBackdrop = function(popover) { backdrop.setAttribute('style', 'opacity:0'); $.targets.popover = $.targets._popover = null; //reset removeBackdropTimer = $.later(function() { if (!popover.classList.contains(CLASS_ACTIVE) && backdrop.parentNode && backdrop.parentNode === document.body) { document.body.removeChild(backdrop); } }, 350); }; window.addEventListener('tap', function(e) { if (!$.targets.popover) { return; } var toggle = false; var target = e.target; for (; target && target !== document; target = target.parentNode) { if (target === $.targets.popover) { toggle = true; } } if (toggle) { e.detail.gesture.preventDefault(); //fixed hashchange togglePopover($.targets._popover, $.targets.popover); } }); var togglePopover = function(popover, anchor, state) { if ((state === 'show' && popover.classList.contains(CLASS_ACTIVE)) || (state === 'hide' && !popover.classList.contains(CLASS_ACTIVE))) { return; } removeBackdropTimer && removeBackdropTimer.cancel(); //取消remove的timer //remove一遍,以免来回快速切换,导致webkitTransitionEnd不触发,无法remove popover.removeEventListener('webkitTransitionEnd', onPopoverShown); popover.removeEventListener('webkitTransitionEnd', onPopoverHidden); backdrop.classList.remove(CLASS_BAR_BACKDROP); backdrop.classList.remove(CLASS_ACTION_BACKDROP); var _popover = document.querySelector($.classSelector('.popover.active')); if (_popover) { // _popover.setAttribute('style', ''); _popover.addEventListener('webkitTransitionEnd', onPopoverHidden); _popover.classList.remove(CLASS_ACTIVE); // _popover.removeEventListener('webkitTransitionEnd', onPopoverHidden); //同一个弹出则直接返回,解决同一个popover的toggle if (popover === _popover) { removeBackdrop(_popover); return; } } var isActionSheet = false; if (popover.classList.contains(CLASS_BAR_POPOVER) || popover.classList.contains(CLASS_ACTION_POPOVER)) { //navBar if (popover.classList.contains(CLASS_ACTION_POPOVER)) { //action sheet popover isActionSheet = true; backdrop.classList.add(CLASS_ACTION_BACKDROP); } else { //bar popover backdrop.classList.add(CLASS_BAR_BACKDROP); // if (anchor) { // if (anchor.parentNode) { // var offsetWidth = anchor.offsetWidth; // var offsetLeft = anchor.offsetLeft; // var innerWidth = window.innerWidth; // popover.style.left = (Math.min(Math.max(offsetLeft, defaultPadding), innerWidth - offsetWidth - defaultPadding)) + "px"; // } else { // //TODO anchor is position:{left,top,bottom,right} // } // } } } setStyle(popover, 'block'); //actionsheet transform popover.offsetHeight; popover.classList.add(CLASS_ACTIVE); backdrop.setAttribute('style', ''); document.body.appendChild(backdrop); calPosition(popover, anchor, isActionSheet); //position backdrop.classList.add(CLASS_ACTIVE); popover.addEventListener('webkitTransitionEnd', onPopoverShown); }; var setStyle = function(popover, display, top, left) { var style = popover.style; if (typeof display !== 'undefined') style.display = display; if (typeof top !== 'undefined') style.top = top + 'px'; if (typeof left !== 'undefined') style.left = left + 'px'; }; var calPosition = function(popover, anchor, isActionSheet) { if (!popover || !anchor) { return; } if (isActionSheet) { //actionsheet setStyle(popover, 'block') return; } var wWidth = window.innerWidth; var wHeight = window.innerHeight; var pWidth = popover.offsetWidth; var pHeight = popover.offsetHeight; var aWidth = anchor.offsetWidth; var aHeight = anchor.offsetHeight; var offset = $.offset(anchor); var arrow = popover.querySelector('.' + CLASS_POPOVER_ARROW); if (!arrow) { arrow = document.createElement('div'); arrow.className = CLASS_POPOVER_ARROW; popover.appendChild(arrow); } var arrowSize = arrow && arrow.offsetWidth / 2 || 0; var pTop = 0; var pLeft = 0; var diff = 0; var arrowLeft = 0; var defaultPadding = popover.classList.contains(CLASS_ACTION_POPOVER) ? 0 : 5; var position = 'top'; if ((pHeight + arrowSize) < (offset.top - window.pageYOffset)) { //top pTop = offset.top - pHeight - arrowSize; } else if ((pHeight + arrowSize) < (wHeight - (offset.top - window.pageYOffset) - aHeight)) { //bottom position = 'bottom'; pTop = offset.top + aHeight + arrowSize; } else { //middle position = 'middle'; pTop = Math.max((wHeight - pHeight) / 2 + window.pageYOffset, 0); pLeft = Math.max((wWidth - pWidth) / 2 + window.pageXOffset, 0); } if (position === 'top' || position === 'bottom') { pLeft = aWidth / 2 + offset.left - pWidth / 2; diff = pLeft; if (pLeft < defaultPadding) pLeft = defaultPadding; if (pLeft + pWidth > wWidth) pLeft = wWidth - pWidth - defaultPadding; if (arrow) { if (position === 'top') { arrow.classList.add(CLASS_BOTTOM); } else { arrow.classList.remove(CLASS_BOTTOM); } diff = diff - pLeft; arrowLeft = (pWidth / 2 - arrowSize / 2 + diff); arrowLeft = Math.max(Math.min(arrowLeft, pWidth - arrowSize * 2 - 6), 6); arrow.setAttribute('style', 'left:' + arrowLeft + 'px'); } } else if (position === 'middle') { arrow.setAttribute('style', 'display:none'); } setStyle(popover, 'block', pTop, pLeft); }; $.createMask = function(callback) { var element = document.createElement('div'); element.classList.add(CLASS_BACKDROP); element.addEventListener($.EVENT_MOVE, $.preventDefault); element.addEventListener('tap', function() { mask.close(); }); var mask = [element]; mask._show = false; mask.show = function() { mask._show = true; element.setAttribute('style', 'opacity:1'); document.body.appendChild(element); return mask; }; mask._remove = function() { if (mask._show) { mask._show = false; element.setAttribute('style', 'opacity:0'); $.later(function() { var body = document.body; element.parentNode === body && body.removeChild(element); }, 350); } return mask; }; mask.close = function() { if (callback) { if (callback() !== false) { mask._remove(); } } else { mask._remove(); } }; return mask; }; $.fn.popover = function() { var args = arguments; this.each(function() { $.targets._popover = this; if (args[0] === 'show' || args[0] === 'hide' || args[0] === 'toggle') { togglePopover(this, args[1], args[0]); } }); }; })(mui, window, document, 'popover');