|
angular.module('myMod').factory('tabsTracker', function (tabsData) { |
|
var Factory = {ids: []}, |
|
checkingPeriod = 800, |
|
removeAfterMarkingTime = checkingPeriod * 3, |
|
tabNotAliveAfter = 5000; |
|
|
|
|
|
/** |
|
* do not allow open several tabs on certain pages |
|
* (it works with pages, generated on fly with ng-location, |
|
* please use it only with topmost $scope / template in nested templates / locations) |
|
**/ |
|
Factory.track = function ($scope) { |
|
/** |
|
* do not allow track single tab in same scope |
|
**/ |
|
if ($scope.trackingTabId) { |
|
throw new Error("tab already tracked with current scope"); |
|
return null; |
|
} |
|
/** |
|
* do not allow track single tab in same app |
|
**/ |
|
if (Factory.ids.length) { |
|
throw new Error("tab already tracked with another scope"); |
|
return null; |
|
} |
|
var id = tabsData.generateId(); |
|
tabsData.add(id); |
|
$scope.trackingTabId = id; |
|
/** |
|
* save these id to Factory to not allow track tab twice in |
|
* same ng-app |
|
**/ |
|
Factory.ids.push(id); |
|
/** |
|
* right away after tracking this tab we can block |
|
* it if other tab was opened |
|
**/ |
|
_checkOpenedTabsData($scope); |
|
|
|
var interval = setInterval(_checkOpenedTabsData, checkingPeriod, $scope); |
|
var destroyIdOnPageClose = function (/*event*/) { |
|
clearInterval(interval); |
|
_destroyId(id); |
|
} |
|
/** |
|
* destroy tabData when pages will be closed/redirected |
|
**/ |
|
window.addEventListener('beforeunload', destroyIdOnPageClose); |
|
/** |
|
* destroy tabData on $scope $destroy event |
|
* note that $destroy event doesnt fires when we close tab, |
|
* it fires only in normal angular-js workflow |
|
**/ |
|
$scope.$on('$destroy', function ($event) { |
|
window.removeEventListener('beforeunload', destroyIdOnPageClose); |
|
_destroyId(id); |
|
clearInterval(interval); |
|
}); |
|
} |
|
/** |
|
* set $scope.tooManyTabs true / false |
|
**/ |
|
function _checkOpenedTabsData ($scope) { |
|
var tooManyTabsOldVal = $scope.tooManyTabs; |
|
if (!_checkIsTabSingleAndRmoveOldTabsData($scope.trackingTabId)) { |
|
$scope.tooManyTabs = true; |
|
} else { |
|
$scope.tooManyTabs = false; |
|
} |
|
if (tooManyTabsOldVal != $scope.tooManyTabs && $scope.$$phase === null) { |
|
$scope.$apply(); |
|
} |
|
} |
|
|
|
/** |
|
* check if current tab is single and remove not alive tabs data |
|
**/ |
|
function _checkIsTabSingleAndRmoveOldTabsData (tabTrackingId) { |
|
var _tabs_data_arr = tabsData.all(), |
|
currentDateTime = new Date(), |
|
/** |
|
* @var bool currentTabSingle |
|
**/ |
|
currentTabSingle = true; |
|
/** |
|
* check that _tabs_data_arr.length contains only current tab data |
|
*/ |
|
if (_tabs_data_arr.length === 1 && _tabs_data_arr[0].id == tabTrackingId ) { |
|
return currentTabSingle; |
|
} else { |
|
tabsData.update(tabTrackingId); |
|
} |
|
|
|
for (var i = 0; i < _tabs_data_arr.length; i++) { |
|
var data = _tabs_data_arr[i]; |
|
|
|
/** |
|
* skip current tab |
|
**/ |
|
if (data.id == tabTrackingId) { |
|
continue; |
|
} |
|
|
|
var tabNotAlive = (currentDateTime - new Date(data.t)) > tabNotAliveAfter; |
|
/** |
|
* mark to remove and wait if tab is live it will update his data.t |
|
* or remove not live tabs data that was already marked |
|
**/ |
|
if (tabNotAlive) { |
|
_removeMarkedOldTabData(data); |
|
_markToRemove(data); |
|
continue; |
|
} |
|
currentTabSingle = false; |
|
} |
|
return currentTabSingle; |
|
} |
|
|
|
|
|
|
|
function _destroyId (tabTrackingId) { |
|
Factory.ids.removeItem(tabTrackingId); |
|
tabsData.remove(tabTrackingId); |
|
} |
|
function _markToRemove (tabData) { |
|
var isMarked = tabData.markedToRemove !== undefined; |
|
if (!isMarked) { |
|
tabsData.markToRemove(tabData.id); |
|
} |
|
} |
|
function _removeMarkedOldTabData (tabData) { |
|
var isMarked = tabData.markedToRemove !== undefined; |
|
if (!isMarked) { |
|
return; |
|
} |
|
var currentDateTime = new Date(), |
|
markedDateTime = new Date(tabData.markedToRemove), |
|
readyToRemove = currentDateTime - markedDateTime > removeAfterMarkingTime; |
|
if (readyToRemove) { |
|
tabsData.remove(tabData.id); |
|
} |
|
} |
|
|
|
|
|
return Factory; |
|
}); |