var H5P = H5P || {}; /** * Constructor. * * @param {Object} params Options for this library. * @param {Number} id Content identifier * @returns {undefined} */ (function ($) { H5P.Image = function (params, id, extras) { H5P.EventDispatcher.call(this); this.extras = extras; if (params.file === undefined || !(params.file instanceof Object)) { this.placeholder = true; } else { this.source = H5P.getPath(params.file.path, id); this.width = params.file.width; this.height = params.file.height; } this.alt = (!params.decorative && params.alt !== undefined) ? params.alt : ''; if (params.title !== undefined) { this.title = params.title; } }; H5P.Image.prototype = Object.create(H5P.EventDispatcher.prototype); H5P.Image.prototype.constructor = H5P.Image; /** * Wipe out the content of the wrapper and put our HTML in it. * * @param {jQuery} $wrapper * @returns {undefined} */ H5P.Image.prototype.attach = function ($wrapper) { var self = this; var source = this.source; if (self.$img === undefined) { if(self.placeholder) { self.$img = $('
', { width: '100%', height: '100%', class: 'h5p-placeholder', title: this.title === undefined ? '' : this.title, on: { load: function () { self.trigger('loaded'); } } }); } else { self.$img = $('', { width: '100%', height: '100%', src: source, alt: this.alt, title: this.title === undefined ? '' : this.title, on: { load: function () { self.trigger('loaded'); } } }); } } $wrapper.addClass('h5p-image').html(self.$img); }; return H5P.Image; }(H5P.jQuery)); ; var H5P = H5P || {}; H5P.ImageSlide = (function ($) { /** * Constructor function. */ function C(options, contentId, extras) { var self = this; this.$ = $(this); H5P.EventDispatcher.call(this); this.aspectRatio = this.originalAspectRatio = extras.aspectRatio; // Extend defaults with provided options this.options = $.extend(true, {}, { image: null, }, options); // Keep provided id. this.contentId = contentId; this.image = H5P.newRunnable(this.options.image, this.contentId); this.image.on('loaded', function() { self.trigger('loaded'); self.trigger('resize'); }); } C.prototype = Object.create(H5P.EventDispatcher.prototype); C.prototype.constructor = C; /** * Attach function called by H5P framework to insert H5P content into * page * * @param {jQuery} $container */ C.prototype.attach = function ($container) { this.$container = $container; // Set class on container to identify it as a greeting card // container. Allows for styling later. $container.addClass("h5p-image-slide"); this.$imageHolder = $('
', { class: 'h5p-image-slide-image-holder', }); $container.append(this.$imageHolder); // Add image this.image.attach(this.$imageHolder); this.adjustSize(); }; /** * Set the ascpect ratio for this slide * * @param {Integer} newAspectRatio the aspect ratio */ C.prototype.setAspectRatio = function(newAspectRatio) { this.aspectRatio = newAspectRatio; // Adjust size if image has been attached if (this.$imageHolder) { this.adjustSize(); } }; /** * Reset the aspect ratio to the previously set aspect ratio * * Typically used when exiting fullscreen mode */ C.prototype.resetAspectRatio = function() { this.aspectRatio = this.originalAspectRatio; // Adjust size if image has been attached if (this.$imageHolder) { this.adjustSize(); } }; /** * Update the size of the slide * * Typically used when the screen resizes, goes to fullscreen or similar */ C.prototype.adjustSize = function() { var imageHeight = this.options.image.params.file.height; var imageWidth = this.options.image.params.file.width; var imageAspectRatio = imageWidth / imageHeight; if (this.aspectRatio >= imageAspectRatio) { // image too tall - Make it smaller and center it var widthInPercent = imageAspectRatio / this.aspectRatio * 100; var borderSize = (100 - widthInPercent) / 2 + '%'; this.$imageHolder.css({ height: '100%', width: imageAspectRatio / this.aspectRatio * 100 + '%', paddingLeft: borderSize, paddingRight: borderSize, paddingTop: 0, paddingBottom: 0 }); } else if (this.aspectRatio < imageAspectRatio) { // image too wide var heightInPercent = this.aspectRatio / imageAspectRatio * 100; // Note: divide by aspect ratio since padding top/bottom is relative to width var borderSize = (100 - heightInPercent) / 2 / this.aspectRatio + '%'; this.$imageHolder.css({ width: '100%', height: heightInPercent + '%', paddingTop: borderSize, paddingBottom: borderSize, paddingLeft: 0, paddingRight: 0 }); } else if (this.aspectRatio === undefined) { this.$imageHolder.css({ width: '100%', height: '', paddingTop: 0, paddingBottom: 0, paddingLeft: 0, paddingRight: 0 }); } }; return C; })(H5P.jQuery); ; var H5P = H5P || {}; H5P.ImageSlider = (function ($) { /** * Constructor function. */ function C(options, id) { this.$ = $(this); var self = this; H5P.EventDispatcher.call(this); // Extend defaults with provided options this.options = $.extend(true, {}, { imageSlides: [ { imageSlide: null } ], a11y: { nextSlide: 'Next Image', prevSlide: 'Previous Image', gotoSlide: 'Go to image %slide' }, aspectRatioMode: 'auto', aspectRatio: { aspectWidth: 4, aspectHeight: 3 } }, options); // Filter out slides without image this.options.imageSlides = this.options.imageSlides.filter(function (slide) { return slide.params && slide.params.image && slide.params.image.params && slide.params.image.params.file; }); // Keep provided id. this.id = id; this.currentSlideId = 0; this.imageSlides = []; this.imageSlideHolders = []; this.determineAspectRatio(); for (var i = 0; i < this.options.imageSlides.length; i++) { this.imageSlides[i] = H5P.newRunnable(this.options.imageSlides[i], this.id, undefined, undefined, { aspectRatio: this.aspectRatio }); this.imageSlides[i].on('loaded', function() { self.trigger('resize'); }); this.imageSlideHolders[i] = false; } this.on('enterFullScreen', function() { self.enterFullScreen(); }); this.on('exitFullScreen', function(){ self.exitFullScreen(); }); this.on('resize', function() { var fullScreenOn = self.$container.hasClass('h5p-fullscreen') || self.$container.hasClass('h5p-semi-fullscreen'); if (fullScreenOn) { self.$slides.css('height', ''); var newAspectRatio = window.innerWidth / (window.innerHeight - self.$progressBar.outerHeight()); for (var i = 0; i < self.imageSlides.length; i++) { self.imageSlides[i].setAspectRatio(newAspectRatio); } } else { if (self.aspectRatio && self.$slides) { self.$slides.height(self.$slides.width() / self.aspectRatio); } } self.updateNavButtons(); self.updateProgressBar(); }); } C.prototype = Object.create(H5P.EventDispatcher.prototype); C.prototype.constructor = C; /** * Set the aspect ratio for this image-slider */ C.prototype.determineAspectRatio = function() { // Set aspectRatio to default this.aspectRatio = 4/3; // Try to identify aspectRatio according to settings switch (this.options.aspectRatioMode) { case 'auto': var imageRatios = []; for (var i = 0; i < this.options.imageSlides.length; i++) { var imageFile = this.options.imageSlides[i].params.image.params.file; imageRatios[i] = imageFile.width / imageFile.height; } imageRatios.sort(function (a, b) { return a - b; }); // Get the median image ratio this.aspectRatio = imageRatios[Math.round(imageRatios.length / 2) - 1]; break; case 'custom': if (this.options.aspectRatio.aspectWidth && this.options.aspectRatio.aspectHeight) { this.aspectRatio = this.options.aspectRatio.aspectWidth / this.options.aspectRatio.aspectHeight; } break; case 'notFixed': this.aspectRatio = undefined; break; } }; /** * Attach function called by H5P framework to insert H5P content into * page * * @param {jQuery} $container */ C.prototype.attach = function ($container) { this.$container = $container; // Set class on container to identify it as a greeting card // container. Allows for styling later. $container.addClass("h5p-image-slider").addClass('h5p-image-slider-using-mouse'); $container.bind('keydown', function(e) { var keyboardNavKeys = [32, 13, 9]; if (keyboardNavKeys.indexOf(e.which) !== -1) { $container.removeClass('h5p-image-slider-using-mouse'); } }); $container.bind('mousedown', function() { $container.addClass('h5p-image-slider-using-mouse'); }); this.$slidesHolder = $('
', { class: 'h5p-image-slider-slides-holder' }).appendTo($container); this.$screenReaderAnnouncement = $('
', { class: 'h5p-image-slider-sr-only', 'aria-atomic': 'true', 'aria-live': 'polite' }).appendTo(this.$slidesHolder); this.$slides = $('
', { class: 'h5p-image-slider-slides' }).appendTo(this.$slidesHolder); this.loadImageSlides(); this.$currentSlide = this.imageSlideHolders[0].addClass('h5p-image-slider-current'); this.attachControls(); }; /** * Update aria-live region with the current image's alt text. */ C.prototype.announceCurrentSlide = function () { this.$screenReaderAnnouncement.text(this.imageSlides[this.currentSlideId].image.alt); }; /** * Update layout when entering fullscreen. * * Many layout changes are handled on resize. */ C.prototype.enterFullScreen = function() { this.updateNavButtons(); this.updateProgressBar(); }; /** * Update layout when entering fullscreen. * * Many layout changes are handled on resize. */ C.prototype.exitFullScreen = function() { for (var i = 0; i < this.imageSlides.length; i++) { this.imageSlides[i].resetAspectRatio(); } this.updateNavButtons(); this.updateProgressBar(); }; /** * Adds the HTML for the next three slides to the DOM */ C.prototype.loadImageSlides = function() { // Load next three imageSlides (not all for performance reasons) for (var i = this.currentSlideId; i < this.imageSlides.length && i < this.currentSlideId + 3; i++) { if (this.imageSlideHolders[i] === false) { this.imageSlideHolders[i] = $('
', { 'class': 'h5p-image-slide-holder' }); if (i > 0) { this.imageSlideHolders[i].attr('aria-hidden', true); } if (i > this.currentSlideId) { this.imageSlideHolders[i].addClass('h5p-image-slider-future'); } this.imageSlides[i].attach(this.imageSlideHolders[i]); this.$slides.append(this.imageSlideHolders[i]); } } }; /** * Attaches controls to the DOM */ C.prototype.attachControls = function() { var self = this; this.$leftButton = this.createControlButton(this.options.a11y.prevSlide, 'left'); this.$rightButton = this.createControlButton(this.options.a11y.nextSlide, 'right'); C.handleButtonClick(this.$leftButton, function () { if (!self.dragging) { self.gotoSlide(self.currentSlideId - 1); } }); C.handleButtonClick(this.$rightButton, function() { if (!self.dragging) { self.gotoSlide(self.currentSlideId + 1); } }); this.$slidesHolder.append(this.$leftButton); this.$slidesHolder.append(this.$rightButton); this.updateNavButtons(); this.attachProgressBar(); this.initDragging(); this.initKeyEvents(); }; /** * Attaches the progress bar to the DOM */ C.prototype.attachProgressBar = function() { this.$progressBar = $('
    ', { class: 'h5p-image-slider-progress' }); for (var i = 0; i < this.imageSlides.length; i++) { this.$progressBar.append(this.createProgressBarElement(i)); } this.$slidesHolder.append(this.$progressBar); }; /** * Creates a progress bar button * * @param {Integer} index - slide index the progress bare element corresponds to * @return {jQuery} - progress bar button */ C.prototype.createProgressBarElement = function(index) { var self = this; var $progressBarButton = $('