diff --git a/image-slider.css b/image-slider.css index d0bd8a3..36e273e 100644 --- a/image-slider.css +++ b/image-slider.css @@ -26,6 +26,10 @@ margin-bottom: 2.5em; } +.h5p-image-slider-slides-holder.h5p-image-slider-no-navigation { + margin-bottom: 0; +} + .h5p-image-slider-button { position: absolute; top: 0; @@ -59,9 +63,13 @@ -moz-osx-font-smoothing: grayscale; } +.h5p-image-slider-button-text.h5p-image-slider-no-navigation { + display: none; +} + .h5p-image-slider-left-button .h5p-image-slider-button-text { left: calc(20% - 0.2em); - + } .h5p-image-slider-left-button .h5p-image-slider-button-text:before { content: "\e901"; @@ -84,7 +92,7 @@ transition: opacity 0.3s; } -.h5p-image-slider-button:hover .h5p-image-slider-button-background { +.h5p-image-slider-button:hover .h5p-image-slider-button-background { opacity: 1; } diff --git a/image-slider.js b/image-slider.js index 52aaa74..ac45d28 100644 --- a/image-slider.js +++ b/image-slider.js @@ -21,10 +21,15 @@ H5P.ImageSlider = (function ($) { prevSlide: 'Previous Image', gotoSlide: 'Go to image %slide' }, - aspectRatioMode: 'auto', - aspectRatio: { - aspectWidth: 4, - aspectHeight: 3 + behaviour: { + aspectRatioMode: 'auto', + aspectRatio: { + aspectWidth: 4, + aspectHeight: 3 + }, + loop: false, + progressionTime: 0, + hideNavigation: false } }, options); @@ -61,7 +66,8 @@ H5P.ImageSlider = (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()); + const heightProgressBar = self.$progressBar ? self.$progressBar.outerHeight() : 0; + var newAspectRatio = window.innerWidth / (window.innerHeight - heightProgressBar); for (var i = 0; i < self.imageSlides.length; i++) { self.imageSlides[i].setAspectRatio(newAspectRatio); } @@ -87,7 +93,7 @@ H5P.ImageSlider = (function ($) { this.aspectRatio = 4/3; // Try to identify aspectRatio according to settings - switch (this.options.aspectRatioMode) { + switch (this.options.behaviour.aspectRatioMode) { case 'auto': var imageRatios = []; for (var i = 0; i < this.options.imageSlides.length; i++) { @@ -102,8 +108,8 @@ H5P.ImageSlider = (function ($) { break; case 'custom': - if (this.options.aspectRatio.aspectWidth && this.options.aspectRatio.aspectHeight) { - this.aspectRatio = this.options.aspectRatio.aspectWidth / this.options.aspectRatio.aspectHeight; + if (this.options.behaviour.aspectRatio.aspectWidth && this.options.behaviour.aspectRatio.aspectHeight) { + this.aspectRatio = this.options.behaviour.aspectRatio.aspectWidth / this.options.behaviour.aspectRatio.aspectHeight; } break; @@ -139,6 +145,10 @@ H5P.ImageSlider = (function ($) { class: 'h5p-image-slider-slides-holder' }).appendTo($container); + if (this.options.behaviour.hideNavigation) { + this.$slidesHolder.addClass('h5p-image-slider-no-navigation'); + } + this.$screenReaderAnnouncement = $('
', { class: 'h5p-image-slider-sr-only', 'aria-atomic': 'true', @@ -154,6 +164,37 @@ H5P.ImageSlider = (function ($) { this.$currentSlide = this.imageSlideHolders[0].addClass('h5p-image-slider-current'); this.attachControls(); + + // Auto progression + this.options.behaviour.progressionTime = this.options.behaviour.autoProgress ? this.options.behaviour.progressionTime : 0; + this.autoProgress(this.options.behaviour.progressionTime); + }; + + /** + * Auto progress after a certain time period. + * + * @param {number} seconds Time period in seconds, at least 1. + */ + C.prototype.autoProgress = function(seconds) { + if (!(seconds > 0)) { + return; + } + + const self = this; + + // Reset timer if running already + if (this.progressionTimer) { + clearTimeout(this.progressionTimer); + } + + this.progressionTimer = setTimeout(function() { + const success = self.gotoSlide(self.currentSlideId + 1); + + // Stop progression if we can't continue. + if (success) { + self.autoProgress(seconds); + } + }, seconds * 1000); }; /** @@ -213,8 +254,8 @@ H5P.ImageSlider = (function ($) { */ 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'); + this.$leftButton = this.createControlButton(this.options.a11y.prevSlide, 'left', this.options.behaviour.hideNavigation); + this.$rightButton = this.createControlButton(this.options.a11y.nextSlide, 'right', this.options.behaviour.hideNavigation); C.handleButtonClick(this.$leftButton, function () { if (!self.dragging) { self.gotoSlide(self.currentSlideId - 1); @@ -230,7 +271,9 @@ H5P.ImageSlider = (function ($) { this.$slidesHolder.append(this.$leftButton); this.$slidesHolder.append(this.$rightButton); this.updateNavButtons(); - this.attachProgressBar(); + if (!this.options.behaviour.hideNavigation) { + this.attachProgressBar(); + } this.initDragging(); this.initKeyEvents(); }; @@ -278,9 +321,10 @@ H5P.ImageSlider = (function ($) { * * @param {string} text - label for the button * @param {string} dir - next or prev + * @param {boolean} hidden - hide text * @return {jQuery} control button */ - C.prototype.createControlButton = function(text, dir) { + C.prototype.createControlButton = function(text, dir, hidden) { var $controlButton = $('
', { class: 'h5p-image-slider-button ' + 'h5p-image-slider-' + dir + '-button', }); @@ -296,6 +340,11 @@ H5P.ImageSlider = (function ($) { 'role': 'button', 'tabindex': 0 }); + + if (hidden) { + $controlText.addClass('h5p-image-slider-no-navigation'); + } + $controlButton.append($controlText); return $controlButton; @@ -308,9 +357,18 @@ H5P.ImageSlider = (function ($) { * @return {Boolean} false if failed(typically the slide didn't exist), true if not */ C.prototype.gotoSlide = function(slideId) { - if (slideId < 0 || slideId >= this.imageSlideHolders.length) { + if ((slideId < 0 || slideId >= this.imageSlideHolders.length) && !this.options.behaviour.loop) { return false; } + + // Loop to first/last slide + if (slideId < 0) { + slideId = this.imageSlideHolders.length - 1; + } + else if (slideId >= this.imageSlideHolders.length) { + slideId = 0; + } + $('.h5p-image-slider-removing', this.$container).removeClass('.h5p-image-slider-removing'); var nextSlideDirection = (this.currentSlideId < slideId) ? 'future' : 'past'; var prevSlideDirection = nextSlideDirection === 'past' ? 'future' : 'past'; @@ -339,6 +397,10 @@ H5P.ImageSlider = (function ($) { this.announceCurrentSlide(); this.updateNavButtons(); this.updateProgressBar(); + + // Reset auto progress timer + this.autoProgress(this.options.behaviour.progressionTime); + return true; }; @@ -359,13 +421,13 @@ H5P.ImageSlider = (function ($) { * Updates all navigation buttons, typically toggling and positioning */ C.prototype.updateNavButtons = function() { - if (this.currentSlideId >= this.imageSlides.length - 1) { + if (this.currentSlideId >= this.imageSlides.length - 1 && !this.options.behaviour.loop) { this.$rightButton.hide(); } else { this.$rightButton.show(); } - if (this.currentSlideId <= 0) { + if (this.currentSlideId <= 0 && !this.options.behaviour.loop) { this.$leftButton.hide(); } else { diff --git a/language/.en.json b/language/.en.json index 6b909ba..64b55be 100644 --- a/language/.en.json +++ b/language/.en.json @@ -12,30 +12,63 @@ } }, { - "label": "Aspect ratio", - "description": "Automatic means fixed aspect ratio automatically determined based on the images", - "options": [ + "label": "Behavioural settings", + "description": "These options will let you control how the task behaves.", + "fields": [ { - "label": "Automatic" + "label": "Aspect ratio", + "description": "Automatic means fixed aspect ratio automatically determined based on the images", + "default": "auto", + "options": [ + { + "label": "Automatic" + }, + { + "label": "Custom" + }, + { + "label": "Not fixed" + } + ] }, { - "label": "Custom" + "label": "Aspect Ratio Settings", + "showWhen": { + "rules": [ + {} + ] + }, + "fields": [ + { + "label": "Aspect ratio width", + "description": "If you use 4 here, and 3 for the height the aspect ratio will be 4:3" + }, + { + "label": "Aspect ratio height", + "description": "If you use 3 here, and 4 for the width the aspect ratio will be 4:3" + } + ] }, { - "label": "Not fixed" - } - ] - }, - { - "label": "Aspect Ratio Settings", - "fields": [ + "label": "Loop", + "description": "If set, slider will progress from last image to first image and vice versa" + }, { - "label": "Aspect ratio width", - "description": "If you use 4 here, and 3 for the height the aspect ratio will be 4:3" + "label": "Automatic progression", + "description": "If set, slider will progress to next slide automatically after a configurable time period" + }, + { + "label": "Progression time", + "description": "If a time period is set (in seconds), the slider will progress to the next slide automatically after that time period.", + "showWhen": { + "rules": [ + {} + ] + } }, { - "label": "Aspect ratio height", - "description": "If you use 3 here, and 4 for the width the aspect ratio will be 4:3" + "label": "Hide navigation", + "description": "If set, navigation will work, but items used for navigation are hidden." } ] }, @@ -60,4 +93,4 @@ ] } ] -} \ No newline at end of file +} diff --git a/language/nb.json b/language/nb.json index 509d861..c403397 100644 --- a/language/nb.json +++ b/language/nb.json @@ -12,30 +12,63 @@ } }, { - "label": "Aspect ratio", - "description": "Automatic means fixed aspect ratio automatically determined based on the images", - "options": [ + "label": "Behavioural settings", + "description": "These options will let you control how the task behaves.", + "fields": [ { - "label": "Automatic" + "label": "Aspect ratio", + "description": "Automatic means fixed aspect ratio automatically determined based on the images", + "default": "auto", + "options": [ + { + "label": "Automatic" + }, + { + "label": "Custom" + }, + { + "label": "Not fixed" + } + ] }, { - "label": "Custom" + "label": "Aspect Ratio Settings", + "showWhen": { + "rules": [ + {} + ] + }, + "fields": [ + { + "label": "Aspect ratio width", + "description": "If you use 4 here, and 3 for the height the aspect ratio will be 4:3" + }, + { + "label": "Aspect ratio height", + "description": "If you use 3 here, and 4 for the width the aspect ratio will be 4:3" + } + ] }, { - "label": "Not fixed" - } - ] - }, - { - "label": "Aspect Ratio Settings", - "fields": [ + "label": "Loop", + "description": "If set, slider will progress from last image to first image and vice versa" + }, { - "label": "Aspect ratio width", - "description": "If you use 4 here, and 3 for the height the aspect ratio will be 4:3" + "label": "Automatic progression", + "description": "If set, slider will progress to next slide automatically after a configurable time period" + }, + { + "label": "Progression time", + "description": "If a time period is set (in seconds), the slider will progress to the next slide automatically after that time period.", + "showWhen": { + "rules": [ + {} + ] + } }, { - "label": "Aspect ratio height", - "description": "If you use 3 here, and 4 for the width the aspect ratio will be 4:3" + "label": "Hide navigation", + "description": "If set, navigation will work, but items used for navigation are hidden." } ] }, diff --git a/semantics.json b/semantics.json index d074699..92ed90b 100644 --- a/semantics.json +++ b/semantics.json @@ -20,54 +20,101 @@ } }, { - "label": "Aspect ratio", - "name": "aspectRatioMode", - "type": "select", - "description": "Automatic means fixed aspect ratio automatically determined based on the images", - "default": "auto", - "options": [ - { - "value": "auto", - "label": "Automatic" + "name": "behaviour", + "type": "group", + "label": "Behavioural settings", + "importance": "low", + "description": "These options will let you control how the task behaves.", + "fields": [ + { + "label": "Aspect ratio", + "name": "aspectRatioMode", + "type": "select", + "description": "Automatic means fixed aspect ratio automatically determined based on the images", + "default": "auto", + "options": [ + { + "value": "auto", + "label": "Automatic" + }, + { + "value": "custom", + "label": "Custom" + }, + { + "value": "notFixed", + "label": "Not fixed" + } + ] + }, + { + "label": "Aspect Ratio Settings", + "name": "aspectRatio", + "type": "group", + "widget": "showWhen", + "expanded": true, + "showWhen": { + "rules": [ + { + "field": "aspectRatioMode", + "equals": "custom" + } + ] + }, + "fields": [ + { + "label": "Aspect ratio width", + "name": "aspectWidth", + "type": "number", + "default": 4, + "description": "If you use 4 here, and 3 for the height the aspect ratio will be 4:3" + }, + { + "label": "Aspect ratio height", + "name": "aspectHeight", + "type": "number", + "default": 3, + "description": "If you use 3 here, and 4 for the width the aspect ratio will be 4:3" + } + ] + }, + { + "name": "loop", + "type": "boolean", + "label": "Loop", + "description": "If set, slider will progress from last image to first image and vice versa", + "default": false }, { - "value": "custom", - "label": "Custom" + "name": "autoProgress", + "type": "boolean", + "label": "Automatic progression", + "description": "If set, slider will progress to next slide automatically after a configurable time period", + "default": false }, { - "value": "notFixed", - "label": "Not fixed" - } - ] - }, - { - "label": "Aspect Ratio Settings", - "name": "aspectRatio", - "type": "group", - "widget": "showWhen", - "expanded": true, - "showWhen": { - "rules": [ - { - "field": "aspectRatioMode", - "equals": "custom" - } - ] - }, - "fields": [ - { - "label": "Aspect ratio width", - "name": "aspectWidth", + "name": "progressionTime", "type": "number", - "default": 4, - "description": "If you use 4 here, and 3 for the height the aspect ratio will be 4:3" + "label": "Progression time", + "description": "If a time period is set (in seconds), the slider will progress to the next slide automatically after that time period.", + "default": 5, + "min": 1, + "widget": "showWhen", + "showWhen": { + "rules": [ + { + "field": "autoProgress", + "equals": true + } + ] + } }, { - "label": "Aspect ratio height", - "name": "aspectHeight", - "type": "number", - "default": 3, - "description": "If you use 3 here, and 4 for the width the aspect ratio will be 4:3" + "name": "hideNavigation", + "type": "boolean", + "label": "Hide navigation", + "description": "If set, navigation will work, but items used for navigation are hidden.", + "default": false } ] }, @@ -104,4 +151,4 @@ } ] } -] \ No newline at end of file +] diff --git a/upgrades.js b/upgrades.js new file mode 100644 index 0000000..4a61c57 --- /dev/null +++ b/upgrades.js @@ -0,0 +1,33 @@ +var H5PUpgrades = H5PUpgrades || {}; + +H5PUpgrades['H5P.ImageSlider'] = (function () { + return { + 1: { + /** + * Asynchronous content upgrade hook. + * + * Move aspect settings to behavioural settings group + * + * @param {Object} parameters + * @param {function} finished + */ + 1: function (parameters, finished, extras) { + // Copy aspect settings to behaviour group and set new defaults + parameters.behaviour = { + aspectRatioMode: parameters.aspectRatioMode, + aspectRatio: parameters.aspectRatio, + loop: false, + autoProgress: false, + progressionTime: 5, + hideNavigation: false + } + + // Delete old aspect settings + delete parameters.aspectRatioMode; + delete parameters.aspectRatio; + + finished(null, parameters, extras); + } + } + }; +})();