(function() { "use strict"; angular.module('shared') .factory('ResourcePopout', ['$document', resourcePopoutService]); function resourcePopoutService($document) { var isTouchDevice = clg.commonUtils.isTouchDevice(); var MS_POINTER_TYPE_TOUCH = 0x2; function ResourcePopout(gridContainer, popoutTargetSelector, mouseLeaveTargetSelector, getDisplayInfo, closePopout, element, fromSearchResults, popoutComponentName) { var self = this; self.gridContainer = gridContainer; self.popoutTargetSelector = popoutTargetSelector; self.mouseLeaveTargetSelector = mouseLeaveTargetSelector; self.popoutComponentName = popoutComponentName; self.getDisplayInfo = getDisplayInfo; self.closePopout = closePopout; self.fromSearchResults = fromSearchResults; self.element = element; self.popoutState = { enteredPopout: false, wasTouched: false, popoutActive: false, eventsEnabled: false }; self.currentPopoutTarget = { domElement : null, dataQueryString : null, coverImageId : null, dataQueryMap : null }; self._latestDisplayPopoutTimoutIds = []; self.isGridView = true; self.eventNames = getEventNames(); self.popoutEnterVerifyUtil = { setTimeoutToVerifyIfEnteredPopout : function (delayInMs) { self.lastPopoutEnterCheckTimeoutId = setTimeout(function verifyIfEnteredPopout() { if (!self.popoutState.enteredPopout) { dismissPopout(); } }, delayInMs); }, resetPopoutEnterVerification: function () { self.popoutState.enteredPopout = false; clearTimeout(self.lastPopoutEnterCheckTimeoutId); } }; self.enableEventTriggers = function() { self.disableEventTriggers(); enablePopoutTargetEventTriggers(); enablePopoutAreaEventTriggers(); self.popoutState.eventsEnabled = true; }; self.disableEventTriggers = function() { var items = self.gridContainer.find(self.popoutTargetSelector); if(self.isTouchDevice) items.off(self.eventNames.startTouchEvent); items.off(self.eventNames.enterMouseEvent); var images = self.gridContainer.find(self.mouseLeaveTargetSelector); images.off(self.eventNames.leaveMouseEvent); self.element.off('mouseenter'); var popoutContents = self.element.children().first(); popoutContents.off('mouseleave'); // remember in the state that the events are disabled self.popoutState.eventsEnabled = false; }; self.overrideLinkClickForTouch = function() { self.gridContainer.off('click', self.popoutTargetSelector); self.gridContainer.on('click', self.popoutTargetSelector, function(linkClickEvent) { if(isPointerAndTouch(linkClickEvent.originalEvent) || self.popoutState.wasTouched) { linkClickEvent.preventDefault(); } }); }; self.closeIfClickedOutsidePopout = function() { self.onDocumentMouseDown = function(event) { var isChild = self.element.find(event.target).length > 0; var isMessageBox = angular.element(event.target).closest('.message-box').length > 0; if(!isChild && !isMessageBox) { self.closePopout(); } }; $document.on("mousedown " + getEventNames().startTouchEvent, self.onDocumentMouseDown); }; function displayPopout(event, fromTouch) { dismissPopout(event); if ($j('.resultsView').length !== 0) { self.isGridView = $j('#gridView')[0].className.indexOf('active') > -1; } var thumbnailParameter = (self.isGridView || self.fromSearchResults) ? '' : '&showThumbnail=true'; var fromTouchParameter = fromTouch ? '&fromTouchDevice=y' : ''; self.currentPopoutTarget.domElement = event.currentTarget; self.currentPopoutTarget.dataQueryString = $j(self.currentPopoutTarget.domElement).attr('data-query') + thumbnailParameter + fromTouchParameter; self.currentPopoutTarget.coverImageId = $j(self.currentPopoutTarget.domElement).find('img').attr('id'); self.currentPopoutTarget.dataQueryMap = dataQueryStringToMap(self.currentPopoutTarget.dataQueryString); self.getDisplayInfo().then(function (response) { var popoutDisplayTarget = $j(self.currentPopoutTarget.domElement).find('.thumbnail'); var foundThumbnailForDisplayTarget = popoutDisplayTarget.length !== 0; if (!foundThumbnailForDisplayTarget || (!self.isGridView && !self.fromSearchResults)) { popoutDisplayTarget = $j(self.currentPopoutTarget.domElement).find('a'); } var displayDelay = 150; var latestTimeoutId = setTimeout(function() { fadeInPopout(popoutDisplayTarget); }, displayDelay); self._latestDisplayPopoutTimoutIds.push(latestTimeoutId); }).catch(function failure(response) { console.error('couldn\'t fetch popout data\nresponse %o', response); }); } function fadeInPopout(popoutDisplayTarget) { var popoutContents = self.element.children().first(); // "visibility maniuplation is needed for position() to work correctly popoutContents.css('visibility', 'hidden'); self.element.show(1, function() { popoutContents.position({ my: 'left top', at: 'right+12px top', of: popoutDisplayTarget, collision: 'flipfit' }); popoutContents.hide(); popoutContents.css('visibility', 'visible'); popoutContents.fadeIn('fast'); self.popoutState.popoutActive = true; }); } function dismissPopout(event) { var prevDisplayPopoutTimeoutIds = self._latestDisplayPopoutTimoutIds; self._latestDisplayPopoutTimoutIds = []; prevDisplayPopoutTimeoutIds.forEach(function(timeoutId) { clearTimeout(timeoutId); }); self.closePopout(); self.popoutState.popoutActive = false; } function enablePopoutTargetEventTriggers() { var items = self.gridContainer.find(self.popoutTargetSelector); //console.log(items.length); var images = self.gridContainer.find(self.mouseLeaveTargetSelector); if (isTouchDevice) { items.on(self.eventNames.startTouchEvent, handleTouch); } items.on(self.eventNames.enterMouseEvent, handleMouseEnter); images.on(self.eventNames.leaveMouseEvent, handleMouseLeave); } function enablePopoutAreaEventTriggers() { self.element.on('mouseenter', function() { self.popoutState.enteredPopout = true; self.popoutState.wasTouched = false; }); var popoutContents = self.element.children().first(); popoutContents.on('mouseleave', function(e) { self.popoutState.enteredPopout = false; var delayInMs = 200; self.popoutEnterVerifyUtil.setTimeoutToVerifyIfEnteredPopout(delayInMs); }); self.popoutState.eventsEnabled = true; } function handleTouch(startEvent) { if (isPointerAndNotTouch(startEvent.originalEvent)){ return; } self.popoutEnterVerifyUtil.resetPopoutEnterVerification(); displayPopout(startEvent, true); self.popoutState.wasTouched = true; startEvent.stopImmediatePropagation(); startEvent.preventDefault(); } function handleMouseEnter(enterEvent) { if(isPointerAndTouch(enterEvent.originalEvent) || (self.popoutState.wasTouched && enterEvent.currentTarget === self.currentPopoutTarget.domElement)) return; self.popoutEnterVerifyUtil.resetPopoutEnterVerification(); self.popoutState.wasTouched = false; self.popoutState.enteredPopout = true; enterEvent.stopImmediatePropagation(); displayPopout(enterEvent, false); } function handleMouseLeave(leaveEvent) { if(isPointerAndTouch(leaveEvent.originalEvent) || (self.popoutState.wasTouched && leaveEvent.currentTarget === self.currentPopoutTarget.domElement)) return; if (!$j(leaveEvent.relatedTarget).parents(self.popoutComponentName).length) { self.popoutState.enteredPopout = false; var delayInMs = 100; self.popoutEnterVerifyUtil.setTimeoutToVerifyIfEnteredPopout(delayInMs); } } function dataQueryStringToMap(dataQueryString) { var dataQueryMap = {}; dataQueryString.split('&').forEach(function (param) { var paramTuple = param.split('='); dataQueryMap[paramTuple[0]] = paramTuple[1]; }); return dataQueryMap; } function isPointerAndNotTouch(event){ return event.pointerType && (event.pointerType !== 'touch' && event.pointerType !== MS_POINTER_TYPE_TOUCH); } function isPointerAndTouch(event){ return event.pointerType && (event.pointerType === 'touch' || event.pointerType === MS_POINTER_TYPE_TOUCH); } function getEventNames(){ if('ontouchstart' in window) return {startTouchEvent: 'touchstart', endTouchEvent: 'touchend', enterMouseEvent: 'mouseenter', leaveMouseEvent: 'mouseleave'}; else if(window.PointerEvent) return {startTouchEvent: 'pointerdown', endTouchEvent: 'pointerup', enterMouseEvent: 'pointerenter', leaveMouseEvent: 'pointerleave'}; else return {startTouchEvent: 'MSPointerDown', endTouchEvent: 'MSPointerUp', enterMouseEvent: 'mouseenter', leaveMouseEvent: 'mouseleave'}; } } return ResourcePopout; } })();