From e6074c8d8db544eba4c30bf4c95e2ec09272850f Mon Sep 17 00:00:00 2001 From: lc-thomasberger Date: Tue, 26 Jun 2018 10:48:15 +0200 Subject: [PATCH] ItemsComponentModel (#147) rebuild of plugin to split it into view/model (using ItemsComponentModel); implement proper popup view that uses the Adapt Notify view to display the popup; total restructure of code to bring it up to modern standards. --- js/adapt-contrib-hotgraphic.js | 313 +-------------------------------- js/hotgraphicPopupView.js | 138 +++++++++++++++ js/hotgraphicView.js | 213 ++++++++++++++++++++++ less/hotgraphic.less | 246 +++++++++++++++----------- properties.schema | 9 + templates/hotgraphic.hbs | 52 +----- templates/hotgraphicPopup.hbs | 42 +++++ 7 files changed, 552 insertions(+), 461 deletions(-) create mode 100644 js/hotgraphicPopupView.js create mode 100644 js/hotgraphicView.js create mode 100644 templates/hotgraphicPopup.hbs diff --git a/js/adapt-contrib-hotgraphic.js b/js/adapt-contrib-hotgraphic.js index 3f42499..b03f15b 100644 --- a/js/adapt-contrib-hotgraphic.js +++ b/js/adapt-contrib-hotgraphic.js @@ -1,307 +1,12 @@ -define(function(require) { - - var ComponentView = require('coreViews/componentView'); - var Adapt = require('coreJS/adapt'); - - var HotGraphic = ComponentView.extend({ - - isPopupOpen: false, - - initialize: function() { - this.listenTo(Adapt, 'remove', this.remove); - this.listenTo(this.model, 'change:_isVisible', this.toggleVisibility); - this.listenTo(Adapt, 'accessibility:toggle', this.onAccessibilityToggle); - - this.model.set('_globals', Adapt.course.get('_globals')); - - _.bindAll(this, 'onKeyUp'); - - this.preRender(); - - if (this.model.get('_canCycleThroughPagination') === undefined) { - this.model.set('_canCycleThroughPagination', false); - } - if (Adapt.device.screenSize == 'large') { - this.render(); - } else { - this.reRender(); - } - }, - - events: function() { - return { - 'click .hotgraphic-graphic-pin': 'onPinClicked', - 'click .hotgraphic-popup-done': 'closePopup', - 'click .hotgraphic-popup-nav .back': 'previousHotGraphic', - 'click .hotgraphic-popup-nav .next': 'nextHotGraphic' - } - }, - - preRender: function() { - this.listenTo(Adapt, 'device:changed', this.reRender, this); - - // Checks to see if the hotgraphic should be reset on revisit - this.checkIfResetOnRevisit(); - }, - - postRender: function() { - this.renderState(); - this.$('.hotgraphic-widget').imageready(_.bind(function() { - this.setReadyStatus(); - }, this)); - - this.setupEventListeners(); - }, - - // Used to check if the hotgraphic should reset on revisit - checkIfResetOnRevisit: function() { - var isResetOnRevisit = this.model.get('_isResetOnRevisit'); - - // If reset is enabled set defaults - if (isResetOnRevisit) { - this.model.reset(isResetOnRevisit); - - _.each(this.model.get('_items'), function(item) { - item._isVisited = false; - }); - } - }, - - reRender: function() { - if (Adapt.device.screenSize != 'large') { - this.replaceWithNarrative(); - } - }, - - inview: function(event, visible, visiblePartX, visiblePartY) { - if (visible) { - if (visiblePartY === 'top') { - this._isVisibleTop = true; - } else if (visiblePartY === 'bottom') { - this._isVisibleBottom = true; - } else { - this._isVisibleTop = true; - this._isVisibleBottom = true; - } - - if (this._isVisibleTop && this._isVisibleBottom) { - this.$('.component-widget').off('inview'); - this.setCompletionStatus(); - } - } - }, - - replaceWithNarrative: function() { - if (!Adapt.componentStore.narrative) throw "Narrative not included in build"; - var Narrative = Adapt.componentStore.narrative; - - var model = this.prepareNarrativeModel(); - var newNarrative = new Narrative({ model: model }); - var $container = $(".component-container", $("." + this.model.get("_parentId"))); - - newNarrative.reRender(); - newNarrative.setupNarrative(); - $container.append(newNarrative.$el); - Adapt.trigger('device:resize'); - _.defer(_.bind(function () { - this.remove(); - }, this)); - }, - - prepareNarrativeModel: function() { - var model = this.model; - model.set('_component', 'narrative'); - model.set('_wasHotgraphic', true); - model.set('originalBody', model.get('body')); - model.set('originalInstruction', model.get('instruction')); - if (model.get('mobileBody')) { - model.set('body', model.get('mobileBody')); - } - if (model.get('mobileInstruction')) { - model.set('instruction', model.get('mobileInstruction')); - } - - return model; - }, - - applyNavigationClasses: function (index) { - var $nav = this.$('.hotgraphic-popup-nav'), - itemCount = this.$('.hotgraphic-item').length; - - $nav.removeClass('first').removeClass('last'); - this.$('.hotgraphic-popup-done').a11y_cntrl_enabled(true); - if(index <= 0 && !this.model.get('_canCycleThroughPagination')) { - this.$('.hotgraphic-popup-nav').addClass('first'); - this.$('.hotgraphic-popup-controls.back').a11y_cntrl_enabled(false); - this.$('.hotgraphic-popup-controls.next').a11y_cntrl_enabled(true); - } else if (index >= itemCount-1 && !this.model.get('_canCycleThroughPagination')) { - this.$('.hotgraphic-popup-nav').addClass('last'); - this.$('.hotgraphic-popup-controls.back').a11y_cntrl_enabled(true); - this.$('.hotgraphic-popup-controls.next').a11y_cntrl_enabled(false); - } else { - this.$('.hotgraphic-popup-controls.back').a11y_cntrl_enabled(true); - this.$('.hotgraphic-popup-controls.next').a11y_cntrl_enabled(true); - } - var classes = this.model.get("_items")[index]._classes - ? this.model.get("_items")[index]._classes - : ''; // _classes has not been defined - - this.$('.hotgraphic-popup').attr('class', 'hotgraphic-popup ' + 'item-' + index + ' ' + classes); - - }, - - onPinClicked: function (event) { - if(event) event.preventDefault(); - - this.$('.hotgraphic-popup-inner').a11y_on(false); - this.$('.hotgraphic-item').hide().removeClass('active'); - - var $currentHotSpot = this.$('.' + $(event.currentTarget).data('id')); - $currentHotSpot.show().addClass('active'); - - var currentIndex = this.$('.hotgraphic-item.active').index(); - this.setVisited(currentIndex); - - this.openPopup(); - - this.applyNavigationClasses(currentIndex); - }, - - openPopup: function() { - var currentIndex = this.$('.hotgraphic-item.active').index(); - this.$('.hotgraphic-popup-count .current').html(currentIndex + 1); - this.$('.hotgraphic-popup-count .total').html(this.$('.hotgraphic-item').length); - this.$('.hotgraphic-popup').attr('class', 'hotgraphic-popup item-' + currentIndex).show(); - this.$('.hotgraphic-popup-inner .active').a11y_on(true); - - this.isPopupOpen = true; - - Adapt.trigger('popup:opened', this.$('.hotgraphic-popup-inner')); - - this.$('.hotgraphic-popup-inner .active').a11y_focus(); - - this.setupEscapeKey(); - }, - - closePopup: function(event) { - if(event) event.preventDefault(); - - this.$('.hotgraphic-popup').hide(); - - this.isPopupOpen = false; - - Adapt.trigger('popup:closed', this.$('.hotgraphic-popup-inner')); - }, - - previousHotGraphic: function (event) { - event.preventDefault(); - var currentIndex = this.$('.hotgraphic-item.active').index(); - - if (currentIndex === 0 && !this.model.get('_canCycleThroughPagination')) { - return; - } else if (currentIndex === 0 && this.model.get('_canCycleThroughPagination')) { - currentIndex = this.model.get('_items').length; - } - - this.$('.hotgraphic-item.active').hide().removeClass('active'); - this.$('.hotgraphic-item').eq(currentIndex-1).show().addClass('active'); - this.setVisited(currentIndex-1); - this.$('.hotgraphic-popup-count .current').html(currentIndex); - this.$('.hotgraphic-popup-inner').a11y_on(false); - - this.applyNavigationClasses(currentIndex-1); - this.$('.hotgraphic-popup-inner .active').a11y_on(true); - this.$('.hotgraphic-popup-inner .active').a11y_focus(); - }, - - nextHotGraphic: function (event) { - event.preventDefault(); - var currentIndex = this.$('.hotgraphic-item.active').index(); - if (currentIndex === (this.model.get('_items').length-1) && !this.model.get('_canCycleThroughPagination')) { - return; - } else if (currentIndex === (this.model.get('_items').length-1) && this.model.get('_canCycleThroughPagination')) { - currentIndex = -1; - } - this.$('.hotgraphic-item.active').hide().removeClass('active'); - this.$('.hotgraphic-item').eq(currentIndex+1).show().addClass('active'); - this.setVisited(currentIndex+1); - this.$('.hotgraphic-popup-count .current').html(currentIndex+2); - this.$('.hotgraphic-popup-inner').a11y_on(false); - - this.applyNavigationClasses(currentIndex+1); - this.$('.hotgraphic-popup-inner .active').a11y_on(true); - this.$('.hotgraphic-popup-inner .active').a11y_focus(); - }, - - setVisited: function(index) { - var item = this.model.get('_items')[index]; - item._isVisited = true; - - var $pin = this.$('.hotgraphic-graphic-pin').eq(index); - $pin.addClass('visited'); - // append the word 'visited.' to the pin's aria-label - var visitedLabel = this.model.get('_globals')._accessibility._ariaLabels.visited + "."; - $pin.attr('aria-label', function(index, val) {return val + " " + visitedLabel}); - - $.a11y_alert("visited"); - - this.checkCompletionStatus(); - }, - - getVisitedItems: function() { - return _.filter(this.model.get('_items'), function(item) { - return item._isVisited; - }); - }, - - checkCompletionStatus: function() { - if (this.getVisitedItems().length == this.model.get('_items').length) { - this.trigger('allItems'); - } - }, - - onCompletion: function() { - this.setCompletionStatus(); - if (this.completionEvent && this.completionEvent != 'inview') { - this.off(this.completionEvent, this); - } - }, - - setupEventListeners: function() { - this.completionEvent = (!this.model.get('_setCompletionOn')) ? 'allItems' : this.model.get('_setCompletionOn'); - if (this.completionEvent !== 'inview') { - this.on(this.completionEvent, _.bind(this.onCompletion, this)); - } else { - this.$('.component-widget').on('inview', _.bind(this.inview, this)); - } - }, - - setupEscapeKey: function() { - var hasAccessibility = Adapt.config.has('_accessibility') && Adapt.config.get('_accessibility')._isActive; - - if (!hasAccessibility && this.isPopupOpen) { - $(window).on("keyup", this.onKeyUp); - } else { - $(window).off("keyup", this.onKeyUp); - } - }, - - onAccessibilityToggle: function() { - this.setupEscapeKey(); - }, - - onKeyUp: function(event) { - if (event.which != 27) return; - - event.preventDefault(); - - this.closePopup(); - } - +define([ + 'core/js/adapt', + './hotgraphicView', + 'core/js/models/itemsComponentModel' +], function(Adapt, HotgraphicView, ItemsComponentModel) { + + return Adapt.register('hotgraphic', { + model: ItemsComponentModel, + view: HotgraphicView }); - Adapt.register('hotgraphic', HotGraphic); - - return HotGraphic; - }); \ No newline at end of file diff --git a/js/hotgraphicPopupView.js b/js/hotgraphicPopupView.js new file mode 100644 index 0000000..6561d62 --- /dev/null +++ b/js/hotgraphicPopupView.js @@ -0,0 +1,138 @@ +define([ + 'core/js/adapt' +], function(Adapt) { + 'use strict'; + + var HotgraphicPopupView = Backbone.View.extend({ + + className: 'hotgraphic-popup', + + events: { + 'click .hotgraphic-popup-done': 'closePopup', + 'click .hotgraphic-popup-controls': 'onControlClick' + }, + + initialize: function() { + this.listenToOnce(Adapt, "notify:opened", this.onOpened); + this.listenTo(this.model.get('_children'), { + 'change:_isActive': this.onItemsActiveChange, + 'change:_isVisited': this.onItemsVisitedChange + }); + this.render(); + }, + + onOpened: function() { + this.applyNavigationClasses(this.model.getActiveItem().get('_index')); + this.updatePageCount(); + this.handleTabs(); + }, + + applyNavigationClasses: function (index) { + var itemCount = this.model.get('_items').length; + var canCycleThroughPagination = this.model.get('_canCycleThroughPagination'); + + var shouldEnableBack = index > 0 || canCycleThroughPagination; + var shouldEnableNext = index < itemCount - 1 || canCycleThroughPagination; + var $controls = this.$('.hotgraphic-popup-controls'); + + this.$('hotgraphic-popup-nav') + .toggleClass('first', !shouldEnableBack) + .toggleClass('last', !shouldEnableNext); + + $controls.filter('.back').a11y_cntrl_enabled(shouldEnableBack); + $controls.filter('.next').a11y_cntrl_enabled(shouldEnableNext); + }, + + updatePageCount: function() { + var template = Adapt.course.get("_globals")._components._hotgraphic.popupPagination; + var labelText = Handlebars.compile(template)({ + itemNumber: this.model.getActiveItem().get('_index') + 1, + totalItems: this.model.get("_items").length + }); + this.$('.hotgraphic-popup-count').html(labelText); + }, + + handleTabs: function() { + this.$('.hotgraphic-popup-inner').a11y_on(false); + this.$('.hotgraphic-popup-inner .active').a11y_on(true); + }, + + onItemsActiveChange: function(item, _isActive) { + if (!_isActive) return; + + var index = item.get('_index'); + this.applyNavigationClasses(index); + this.updatePageCount(); + this.handleTabs(); + this.applyItemClasses(index); + this.handleFocus(); + }, + + applyItemClasses: function(index) { + this.$('.hotgraphic-item.active').removeClass('active'); + this.$('.hotgraphic-item').filter('[data-index="' + index + '"]').addClass('active'); + }, + + handleFocus: function() { + this.$('.hotgraphic-popup-inner .active').a11y_focus(); + }, + + onItemsVisitedChange: function(item, _isVisited) { + if (!_isVisited) return; + + this.$('.hotgraphic-item') + .filter('[data-index="' + item.get('_index') + '"]') + .addClass('visited'); + }, + + render: function() { + var data = this.model.toJSON(); + data.view = this; + var template = Handlebars.templates['hotgraphicPopup']; + this.$el.html(template(data)); + }, + + closePopup: function(event) { + Adapt.trigger('notify:close'); + }, + + onControlClick: function(event) { + event.preventDefault(); + + var direction = $(event.currentTarget).hasClass('back') ? 'back' : 'next'; + var index = this.getNextIndex(direction); + + if (index !== -1) { + this.setItemState(index); + } + }, + + getNextIndex: function(direction) { + var index = this.model.getActiveItem().get('_index'); + var lastIndex = this.model.get('_items').length - 1; + + switch (direction) { + case 'back': + if (index > 0) return --index; + if (this.model.get('_canCycleThroughPagination')) return lastIndex; + break; + case 'next': + if (index < lastIndex) return ++index; + if (this.model.get('_canCycleThroughPagination')) return 0; + } + return -1; + }, + + setItemState: function(index) { + this.model.getActiveItem().toggleActive(); + + var nextItem = this.model.getItem(index); + nextItem.toggleActive(); + nextItem.toggleVisited(true); + } + + }); + + return HotgraphicPopupView; + +}); diff --git a/js/hotgraphicView.js b/js/hotgraphicView.js new file mode 100644 index 0000000..660220d --- /dev/null +++ b/js/hotgraphicView.js @@ -0,0 +1,213 @@ +define([ + 'core/js/adapt', + 'core/js/views/componentView', + './hotgraphicPopupView' +], function(Adapt, ComponentView, HotgraphicPopupView) { + 'use strict'; + + var HotGraphicView = ComponentView.extend({ + + events: { + 'click .hotgraphic-graphic-pin': 'onPinClicked' + }, + + initialize: function() { + ComponentView.prototype.initialize.call(this); + _.bindAll(this, 'inview'); + this.setUpViewData(); + this.setUpModelData(); + this.setUpEventListeners(); + this.checkIfResetOnRevisit(); + }, + + setUpViewData: function() { + this.popupView = null; + this._isPopupOpen = false; + }, + + setUpModelData: function() { + if (this.model.get('_canCycleThroughPagination') === undefined) { + this.model.set('_canCycleThroughPagination', false); + } + }, + + setUpEventListeners: function() { + this.listenTo(Adapt, 'device:changed', this.reRender); + + this.listenTo(this.model.get('_children'), { + 'change:_isActive': this.onItemsActiveChange, + 'change:_isVisited': this.onItemsVisitedChange + }); + }, + + reRender: function() { + if (Adapt.device.screenSize !== 'large') { + this.replaceWithNarrative(); + } + }, + + replaceWithNarrative: function() { + var NarrativeView = Adapt.getViewClass('narrative'); + + var model = this.prepareNarrativeModel(); + var newNarrative = new NarrativeView({ model: model }); + var $container = $(".component-container", $("." + this.model.get("_parentId"))); + + newNarrative.reRender(); + newNarrative.setupNarrative(); + $container.append(newNarrative.$el); + Adapt.trigger('device:resize'); + _.defer(this.remove.bind(this)); + }, + + prepareNarrativeModel: function() { + var model = this.model; + model.set({ + '_component': 'narrative', + '_wasHotgraphic': true, + 'originalBody': model.get('body'), + 'originalInstruction': model.get('instruction') + }); + + // Check if active item exists, default to 0 + var activeItem = model.getActiveItem(); + if (!activeItem) { + model.getItem(0).toggleActive(true); + } + + // Swap mobile body and instructions for desktop variants. + if (model.get('mobileBody')) { + model.set('body', model.get('mobileBody')); + } + if (model.get('mobileInstruction')) { + model.set('instruction', model.get('mobileInstruction')); + } + + return model; + }, + + onItemsActiveChange: function(model, _isActive) { + this.getItemElement(model).toggleClass('active', _isActive); + }, + + getItemElement: function(model) { + var index = model.get('_index'); + return this.$('.hotgraphic-graphic-pin').filter('[data-index="' + index + '"]'); + }, + + onItemsVisitedChange: function(model, _isVisited) { + if (!_isVisited) return; + var $pin = this.getItemElement(model); + + // Append the word 'visited.' to the pin's aria-label + var visitedLabel = this.model.get('_globals')._accessibility._ariaLabels.visited + "."; + $pin.attr('aria-label', function(index, val) { + return val + " " + visitedLabel; + }); + + $pin.addClass('visited'); + }, + + // Used to check if the hotgraphic should reset on revisit + checkIfResetOnRevisit: function() { + var isResetOnRevisit = this.model.get('_isResetOnRevisit'); + + // If reset is enabled set defaults + if (isResetOnRevisit) { + this.model.reset(isResetOnRevisit); + } + }, + + preRender: function() { + if (Adapt.device.screenSize === 'large') { + this.render(); + } else { + this.reRender(); + } + }, + + postRender: function() { + this.renderState(); + this.$('.hotgraphic-widget').imageready(this.setReadyStatus.bind(this)); + + this.setUpInviewListener(); + }, + + setUpInviewListener: function() { + if (this.model.get('_setCompletionOn') === 'inview') { + this.$('.component-widget').on('inview', this.inview); + } + }, + + inview: function(event, visible, visiblePartX, visiblePartY) { + if (!visible) return; + + if (visiblePartY === 'top') { + this._isVisibleTop = true; + } else if (visiblePartY === 'bottom') { + this._isVisibleBottom = true; + } else { + this._isVisibleTop = true; + this._isVisibleBottom = true; + } + + var wasAllInview = (this._isVisibleTop && this._isVisibleBottom); + if (!wasAllInview) return; + + this.removeInviewListener(); + this.setCompletionStatus(); + }, + + onPinClicked: function (event) { + if(event) event.preventDefault(); + + var item = this.model.getItem($(event.currentTarget).data('index')); + item.toggleActive(true); + item.toggleVisited(true); + + this.openPopup(); + }, + + openPopup: function() { + if (this._isPopupOpen) return; + + this._isPopupOpen = true; + + this.popupView = new HotgraphicPopupView({ + model: this.model + }); + + Adapt.trigger("notify:popup", { + _view: this.popupView, + _isCancellable: true, + _showCloseButton: false, + _closeOnBackdrop: true, + _classes: ' hotgraphic' + }); + + this.listenToOnce(Adapt, { + 'popup:closed': this.onPopupClosed + }); + }, + + onPopupClosed: function() { + this.model.getActiveItem().toggleActive(); + this._isPopupOpen = false; + }, + + remove: function() { + this.removeInviewListener(); + ComponentView.prototype.remove.apply(this, arguments); + }, + + removeInviewListener: function() { + if (this.model.get('_setCompletionOn') === 'inview') { + this.$('.component-widget').off('inview'); + } + } + + }); + + return HotGraphicView; + +}); diff --git a/less/hotgraphic.less b/less/hotgraphic.less index 42e4d14..8c7086d 100644 --- a/less/hotgraphic.less +++ b/less/hotgraphic.less @@ -1,8 +1,11 @@ .hotgraphic-component { + + + .hotgraphic-graphic { position: relative; - display:inline-block; + display: inline-block; width: 100%; } @@ -12,8 +15,9 @@ top: 0%; left: 0%; background-color: @item-text-color; - border-radius:50%; + border-radius: 50%; text-decoration: none; + &.visited { .hotgraphic-graphic-pin-icon { color: @item-color-visited; @@ -29,120 +33,146 @@ .hotgraphic-graphic-pin-icon { color: @item-color; font-size: (@icon-size*2); - width:auto; - height:auto; + height: (@icon-size*2); + width: (@icon-size*2); } - .hotgraphic-popup { - display: none; - width: auto; - position: absolute; - left: 0px; - right: 0px; - top: 0px; - height: auto; - margin: 40px; - background-color: @background-color; - border: @item-border; - z-index: 5; - } +} - .hotgraphic-popup-toolbar { - position: relative; - background-color: @item-color; - height: (@item-padding-top + @item-padding-bottom) + @icon-size; - } +.hotgraphic-item:not(.active) { + display: none; +} - .hotgraphic-popup-nav { - background-color: @item-color; - } +.notify.hotgraphic { - .hotgraphic-popup-done { - position: absolute; - top: 0; - right: 0; - text-decoration: none; - .dir-rtl & { - right: inherit; - left: 0; - } - .no-touch &:hover { - .hotgraphic-popup-close { - color: @button-text-color-hover; - } - } - } + .notify-popup { + pointer-events: none; + background-color: transparent; + color: @font-color; - .hotgraphic-popup-arrow-l, - .hotgraphic-popup-arrow-r, - .hotgraphic-popup-close { - padding: @item-padding; - color: @button-text-color; + .notify-popup-content { + width: auto; + pointer-events: auto; + } } - .hotgraphic-popup-count { - padding: @item-padding; - vertical-align: baseline; - color: @item-text-color; - float: left; - .dir-rtl & { - float: right; + .notify-popup-content-inner { + .hotgraphic-popup { + width: auto; + height: auto; + margin: 40px; + background-color: @background-color; + border: @item-border; + z-index: 5; + position: relative; + padding-top: (@item-padding-top + @item-padding-bottom) + @icon-size; } - span { - display: inline-block; + + .hotgraphic-popup-toolbar { + position: absolute; + top: 0; + left: 0; + width: 100%; + background-color: @item-color; + height: (@item-padding-top + @item-padding-bottom) + @icon-size; } - } - .hotgraphic-popup-controls { - float: left; - text-decoration: none; - .dir-rtl & { - float: right; + .hotgraphic-popup-nav { + background-color: @item-color; } - .no-touch &:hover { - .hotgraphic-popup-arrow-l, - .hotgraphic-popup-arrow-r { - color: @button-text-color-hover; + + .hotgraphic-popup-done { + position: absolute; + top: 0; + right: 0; + text-decoration: none; + .dir-rtl & { + right: inherit; + left: 0; + } + .no-touch &:hover { + .hotgraphic-popup-close { + color: @button-text-color-hover; + } } } - &.disabled { - visibility: hidden; + + .hotgraphic-popup-arrow-l, + .hotgraphic-popup-arrow-r, + .hotgraphic-popup-close { + padding: @item-padding; + color: @button-text-color; } - } - .hotgraphic-popup-inner { - padding: @item-padding; - } + .hotgraphic-popup-count { + padding: @item-padding; + vertical-align: baseline; + color: @item-text-color; + float: left; + .dir-rtl & { + float: right; + } + span { + display: inline-block; + } + } - .hotgraphic-item-graphic { - width: 50%; - float: right; - .dir-rtl & { + .hotgraphic-popup-controls { float: left; + text-decoration: none; + .dir-rtl & { + float: right; + } + .no-touch &:hover { + .hotgraphic-popup-arrow-l, + .hotgraphic-popup-arrow-r { + color: @button-text-color-hover; + } + } + &.disabled { + visibility: hidden; + } } - text-align: center; - } - .hotgraphic-item-graphic-inner{ - padding-left: @item-padding-left; - .dir-rtl & { - padding-left: inherit; - padding-right: @item-padding-left; + .hotgraphic-popup-inner { + padding: @item-padding; } - } - .hotgraphic-item-content { - width: 50%; - float: left; - .dir-rtl & { + .hotgraphic-item-graphic { + padding-left: @item-padding-left; + width: 50%; + box-sizing: border-box; float: right; + .dir-rtl & { + float: left; + } + text-align: center; } - } - .graphic-attribution { - font-size:0.75em; - line-height: 1em; - } + .hotgraphic-item-graphic-inner{ + img { + display: block; + } + .dir-rtl & { + padding-left: inherit; + padding-right: @item-padding-left; + } + } + + .hotgraphic-item-content { + width: 50%; + float: left; + .dir-rtl & { + float: right; + } + } + + .graphic-attribution { + font-size: 0.75em; + line-height: 1em; + padding-top: 0.5em; + } + } } // Hotgraphic Narrative @@ -154,39 +184,41 @@ .hotgraphic-graphic-pin { border-radius: 0px; - position:absolute; - display:block; - box-sizing:border-box; - -moz-box-sizing:border-box; - -webkit-box-sizing:border-box; - border:4px solid @background-color; + position: absolute; + display: block; + box-sizing: border-box; + -moz-box-sizing: border-box; + -webkit-box-sizing: border-box; + border: 4px solid @background-color; background-size: cover; transition: background-size .4s; - overflow:hidden; + overflow: hidden; + .hotgraphic-graphic-pin-image { display:block; - width:100%; - height:100%; + width: auto; + height: 100%; -webkit-transition: transform .4s; transition: transform .4s; background-size: cover; &:before { content: ''; - position:absolute; - top:0px; - left:0px; - width:100%; - height:100%; - background:fadeout(@foreground-color, 50%); + position: absolute; + top: 0px; + left: 0px; + width: 100%; + height: 100%; + background: fadeout(@foreground-color, 50%); transition: background .5s; } } + &:hover { .hotgraphic-graphic-pin-image { -webkit-transform: scale(1.1); transform: scale(1.1); &:before { - background:fadeout(@foreground-color, 100%); + background: fadeout(@foreground-color, 100%); } } } diff --git a/properties.schema b/properties.schema index 66137c9..9310941 100644 --- a/properties.schema +++ b/properties.schema @@ -19,6 +19,15 @@ "inputType": "Text", "validators": [], "translatable": true + }, + "popupPagination": { + "type": "string", + "required": true, + "default": "{{itemNumber}} / {{totalItems}}", + "inputType": "Text", + "validators": [], + "help": "This is the aria label for each item. Use {{itemNumber}} and {{totalItems}} in your text to tell the user which item they are viewing and how many items there are in total.", + "translatable": true } }, "properties": { diff --git a/templates/hotgraphic.hbs b/templates/hotgraphic.hbs index 9345ecc..ca15c85 100644 --- a/templates/hotgraphic.hbs +++ b/templates/hotgraphic.hbs @@ -1,60 +1,12 @@ -{{! Maintainers - Kevin Corry}}
{{> component this}}
- - {{#if _useGraphicsAsPins}}
{{#each _items}} - {{/each}} @@ -65,7 +17,7 @@
{{{_graphic.attribution}}}
{{/if}} {{#each _items}} - {{/each}} diff --git a/templates/hotgraphicPopup.hbs b/templates/hotgraphicPopup.hbs new file mode 100644 index 0000000..d7abbbb --- /dev/null +++ b/templates/hotgraphicPopup.hbs @@ -0,0 +1,42 @@ +
+ {{#each _items}} +
+
+
+
+ {{{title}}} +
+
+ {{{a11y_text body}}} +
+
+
+
+
+ +
+ {{#if _graphic.attribution}} +
{{{a11y_text _graphic.attribution}}}
+ {{/if}} +
+
+ {{/each}} +
+
+ {{#unless _hidePagination}} +
+ +
+
+ +
+ {{/unless}} + +
+{{a11y_wrap_focus}}