(function () {
'use strict';
// Slideshow dialog window
angular
.module('mohistory')
.directive('slideshowDialog', slideshowDialog);
slideshowDialog.$inject = ['$transitions', '$rootScope', '$timeout'];
/**
* Directive for the photo slideshow accessible via blog posts.
* @memberof mohistory
* @name slideshowDialog
* @ngdoc directive
*/
function slideshowDialog($transitions, $rootScope, $timeout) {
var directive = {
templateUrl: 'app/components/slideshow-dialog/slideshow-dialog.directive.html',
controller: slideshowDialogCtrl,
controllerAs: 'slideD',
bindToController: true,
scope: {
isDialogOpen: '<',
startIdx: '<',
images: '<',
closeDialog: '<',
},
link: slideshowDialogLink,
restrict: 'E',
};
return directive;
function slideshowDialogCtrl() {
var vm = this;
/* ----- Variables ----- */
vm.curIdx = 0;
/* ----- Function Bindings ----- */
vm.$onInit = onInit;
vm.$onChanges = onChanges;
vm.slideNext = slideNext;
vm.slidePrevious = slidePrevious;
/* ----- Function Definitions ----- */
/**
* Called when component is created.
* @function onInit
* @memberof slideshowDialog
*/
function onInit() {
vm.curIdx = vm.startIdx;
}
/**
* Any changes to the information passed into this component from
* the parent will trigger this hook.
* @function onChanges
* @memberof slideshowDialog
*/
function onChanges() {
vm.curIdx = vm.startIdx;
}
/**
* Advance slide show. Only available when there is content in the mhs:slideshow
* portion of the dataset
* @function slideNext
* @memberof slideshowDialog
*/
function slideNext() {
if (vm.curIdx < (vm.images.length - 1)) {
vm.curIdx = vm.curIdx + 1;
} else {
vm.curIdx = 0
}
}
/**
* Retreat the slide show. Only available when there is content in the mhs:slideshow
* portion of the dataset
* @function slidePrevious
* @memberof slideshowDialog
*/
function slidePrevious(x) {
if (vm.curIdx == 0) {
vm.curIdx = vm.images.length - 1
} else {
vm.curIdx = vm.curIdx - 1;
}
}
}
/**
* Update the DOM and handle keyboard events for slideshow-dialog.
* @param {String} $scope an AngularJS scope object.
* @param {String} $element the jqLite-wrapped element that this directive matches.
* @param {String} $attrs a hash object with key-value pairs of normalized attribute
* names and their corresponding attribute values.
* @param {String} $ctrl the controller associated with the directive
* @function slideshowDialogLink
* @memberof slideshowDialog
*/
function slideshowDialogLink($scope, $element, $attrs, $ctrl) {
/* ----- Variables ----- */
var body = $('body');
var html = $('html');
var oldFocus = null;
var dialogWindow = $('#slideshow-dialog-window');
/* --- Scope Listeners --- */
// Watch the boolean value passed in from the slideshow-dialog component
$scope.$watch(function () {
return $ctrl.isDialogOpen;
}, toggleFocusLock);
// Remove JQuery listeners when directive is destroyed
$scope.$on('$destroy', function () {
body.off('keyup', closeOnEscape);
body.off('keyup', onArrowKey);
dialogWindow.find('#slideshow-dialog-close').off('keydown', onShiftTabGoToLast);
dialogWindow.find('button').last().off('keydown', onTabGoToFirst);
});
/* ----- Function Definitions ----- */
/**
* When menu is open make sure the close button has focus and scrolling
* behind the menu is disabled.
* @param {String} value true if the menu is open, false otherwise
* @function toggleFocusLock
* @memberof slideshowDialogLink
*/
function toggleFocusLock(value) {
value = Boolean(value);
if (value) {
oldFocus = $(document.activeElement);
body.addClass('locked');
html.addClass('locked');
// Use timeout to add commands to the end of the command stack
// this gives the DOM enough time to fully render
$timeout(function () {
dialogWindow = $('#slideshow-dialog-window');
dialogWindow.find('#slideshow-dialog-close').focus();
body.on('keyup', closeOnEscape);
body.on('keyup', onArrowKey);
dialogWindow.find('#slideshow-dialog-close').on('keydown', onShiftTabGoToLast);
dialogWindow.find('button').last().on('keydown', onTabGoToFirst);
});
} else {
body.removeClass('locked');
html.removeClass('locked');
// Use timeout to add commands to the end of the command stack
// this gives the DOM enough time to fully render
$timeout(function () {
if (!$ctrl.isDialogOpen && oldFocus) {
oldFocus.focus();
body.off('keyup', closeOnEscape);
body.off('keyup', onArrowKey);
dialogWindow.find('#slideshow-dialog-close').off('keydown', onShiftTabGoToLast);
dialogWindow.find('button').last().off('keydown', onTabGoToFirst);
}
})
}
}
/**
* Pressing Shift plus Tab on the first focusable element will
* move focus to the last focusable element.
* @function onShiftTabGoToLast
* @memberof slideshowDialogLink
* @param {object} e Event object
*/
function onShiftTabGoToLast(e) {
var keyCode = e.keyCode || e.which;
if($ctrl.isDialogOpen && keyCode === 9 && e.shiftKey) {
dialogWindow.find('button').last().focus();
e.preventDefault();
}
}
/**
* If the left arrow key is pressed, move the slideshow back.
* If the right arrow key is pressed, move the slideshow forward.
* @function onArrowKey
* @memberof slideshowDialogLink
* @param {object} e Event object
*/
function onArrowKey(e) {
var keyCode = e.keyCode || e.which;
if($ctrl.isDialogOpen && keyCode === 37) {
$ctrl.slidePrevious();
} else if($ctrl.isDialogOpen && keyCode == 39) {
$ctrl.slideNext();
}
$scope.$apply();
}
/**
* Close the menu when the escape key is pressed.
* @function closeOnEscape
* @memberof slideshowDialogLink
* @param {Object} e event Object
*/
function closeOnEscape(e) {
var keyCode = e.keyCode || e.which;
if (keyCode === 27 && $ctrl.isDialogOpen) {
$ctrl.closeDialog();
$scope.$apply();
}
}
/**
* When menu is open pressing tab on the last link in the menu
* will move focus to the top of the menu.
* @function onTabGoToFirst
* @memberof slideshowDialogLink
* @param {Object} e event object
*/
function onTabGoToFirst(e) {
var keyCode = e.keyCode || e.which;
if ($ctrl.isDialogOpen && keyCode === 9 && !e.shiftKey) {
dialogWindow.find('button').first().focus();
e.preventDefault();
}
}
}
}
})();