Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ItemsComponentModel #179

Merged
merged 23 commits into from
Jun 26, 2018
Merged
Show file tree
Hide file tree
Changes from 17 commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
374 changes: 9 additions & 365 deletions js/adapt-contrib-narrative.js
Original file line number Diff line number Diff line change
@@ -1,368 +1,12 @@
define(function(require) {

var ComponentView = require('coreViews/componentView');
var Adapt = require('coreJS/adapt');

var Narrative = ComponentView.extend({

events: {
'click .narrative-strapline-title': 'openPopup',
'click .narrative-controls': 'onNavigationClicked',
'click .narrative-indicators .narrative-progress': 'onProgressClicked'
},

preRender: function() {
this.listenTo(Adapt, 'device:changed', this.reRender, this);
this.listenTo(Adapt, 'device:resize', this.resizeControl, this);
this.listenTo(Adapt, 'notify:closed', this.closeNotify, this);
this.setDeviceSize();

// Checks to see if the narrative should be reset on revisit
this.checkIfResetOnRevisit();
},

setDeviceSize: function() {
if (Adapt.device.screenSize === 'large') {
this.$el.addClass('desktop').removeClass('mobile');
this.model.set('_isDesktop', true);
} else {
this.$el.addClass('mobile').removeClass('desktop');
this.model.set('_isDesktop', false)
}
},

postRender: function() {
this.renderState();
this.$('.narrative-slider').imageready(_.bind(function() {
this.setReadyStatus();
}, this));
this.setupNarrative();
},

// Used to check if the narrative should reset on revisit
checkIfResetOnRevisit: function() {
var isResetOnRevisit = this.model.get('_isResetOnRevisit');

// If reset is enabled set defaults
if (isResetOnRevisit) {
this.model.reset(isResetOnRevisit);
this.model.set({_stage: 0});

_.each(this.model.get('_items'), function(item) {
item._isVisited = false;
});
}
},

setupNarrative: function() {
this.setDeviceSize();
if(!this.model.has('_items') || !this.model.get('_items').length) return;
this.model.set('_marginDir', 'left');
if (Adapt.config.get('_defaultDirection') == 'rtl') {
this.model.set('_marginDir', 'right');
}
this.model.set('_itemCount', this.model.get('_items').length);

this.model.set('_active', true);

if (this.model.get('_stage')) {
this.setStage(this.model.get('_stage'), true);
} else {
this.setStage(0, true);
}
this.calculateWidths();

if (Adapt.device.screenSize !== 'large' && !this.model.get('_wasHotgraphic')) {
this.replaceInstructions();
}
this.setupEventListeners();
},

calculateWidths: function() {
var slideWidth = this.$('.narrative-slide-container').width();
var slideCount = this.model.get('_itemCount');
var marginRight = this.$('.narrative-slider-graphic').css('margin-right');
var extraMargin = marginRight === '' ? 0 : parseInt(marginRight);
var fullSlideWidth = (slideWidth + extraMargin) * slideCount;

this.$('.narrative-slider-graphic').width(slideWidth);
this.$('.narrative-strapline-header').width(slideWidth);
this.$('.narrative-strapline-title').width(slideWidth);

this.$('.narrative-slider').width(fullSlideWidth);
this.$('.narrative-strapline-header-inner').width(fullSlideWidth);

var stage = this.model.get('_stage');
var margin = -(stage * slideWidth);

this.$('.narrative-slider').css(('margin-' + this.model.get('_marginDir')), margin);
this.$('.narrative-strapline-header-inner').css(('margin-' + this.model.get('_marginDir')), margin);

this.model.set('_finalItemLeft', fullSlideWidth - slideWidth);
},

resizeControl: function() {
var wasDesktop = this.model.get('_isDesktop');
this.setDeviceSize();
var isDesktop = this.model.get('_isDesktop');
if (wasDesktop != isDesktop) this.replaceInstructions();
this.calculateWidths();
this.evaluateNavigation();

/**
* need to set current stage item to visited when moving from small/medium screen size to large
* see https://github.com/adaptlearning/adapt_framework/issues/2100
*/
if (isDesktop) this.setCurrentItemVisited();
},

setCurrentItemVisited: function() {
var stage = this.model.get('_stage') || 0;
if (this.getCurrentItem(stage)._isVisited) return;
this.setStage(stage, true);
},

reRender: function() {
if (this.model.get('_wasHotgraphic') && Adapt.device.screenSize == 'large') {
this.replaceWithHotgraphic();
} else {
this.resizeControl();
}
},

closeNotify: function() {
this.evaluateCompletion();
},

replaceInstructions: function() {
if (Adapt.device.screenSize === 'large') {
this.$('.narrative-instruction-inner').html(this.model.get('instruction')).a11y_text();
} else if (this.model.get('mobileInstruction') && !this.model.get('_wasHotgraphic')) {
this.$('.narrative-instruction-inner').html(this.model.get('mobileInstruction')).a11y_text();
}
},

replaceWithHotgraphic: function() {
var Hotgraphic = Adapt.getViewClass('hotgraphic');

var model = this.prepareHotgraphicModel();
var newHotgraphic = new Hotgraphic({ model: model });
var $container = $(".component-container", $("." + this.model.get("_parentId")));

$container.append(newHotgraphic.$el);
this.remove();
$.a11y_update();
_.defer(function() {
Adapt.trigger('device:resize');
});
},

prepareHotgraphicModel: function() {
var model = this.model;
model.set('_component', 'hotgraphic');
model.set('body', model.get('originalBody'));
model.set('instruction', model.get('originalInstruction'));
return model;
},

moveSliderToIndex: function(itemIndex, animate, callback) {
var extraMargin = parseInt(this.$('.narrative-slider-graphic').css('margin-right'));
var movementSize = this.$('.narrative-slide-container').width() + extraMargin;
var marginDir = {};
if (animate && !Adapt.config.get('_disableAnimation')) {
marginDir['margin-' + this.model.get('_marginDir')] = -(movementSize * itemIndex);
this.$('.narrative-slider').velocity("stop", true).velocity(marginDir);
this.$('.narrative-strapline-header-inner').velocity("stop", true).velocity(marginDir, {complete:callback});
} else {
marginDir['margin-' + this.model.get('_marginDir')] = -(movementSize * itemIndex);
this.$('.narrative-slider').css(marginDir);
this.$('.narrative-strapline-header-inner').css(marginDir);
callback();
}
},

setStage: function(stage, initial) {
this.model.set('_stage', stage);
if (this.model.get('_isDesktop')) {
// Set the visited attribute for large screen devices
var currentItem = this.getCurrentItem(stage);
currentItem._isVisited = true;
}

this.$('.narrative-progress:visible').removeClass('selected').eq(stage).addClass('selected');
this.$('.narrative-slider-graphic').children('.controls').a11y_cntrl_enabled(false);
this.$('.narrative-slider-graphic').eq(stage).children('.controls').a11y_cntrl_enabled(true);
this.$('.narrative-content-item').addClass('narrative-hidden').a11y_on(false).eq(stage).removeClass('narrative-hidden').a11y_on(true);
this.$('.narrative-strapline-title').a11y_cntrl_enabled(false).eq(stage).a11y_cntrl_enabled(true);

this.evaluateNavigation();
this.evaluateCompletion();

this.moveSliderToIndex(stage, !initial, _.bind(function() {
if (this.model.get('_isDesktop')) {
if (!initial) this.$('.narrative-content-item').eq(stage).a11y_focus();
} else {
if (!initial) this.$('.narrative-strapline-title').a11y_focus();
}
}, this));
},

constrainStage: function(stage) {
if (stage > this.model.get('_items').length - 1) {
stage = this.model.get('_items').length - 1;
} else if (stage < 0) {
stage = 0;
}
return stage;
},

constrainXPosition: function(previousLeft, newLeft, deltaX) {
if (newLeft > 0 && deltaX > 0) {
newLeft = previousLeft + (deltaX / (newLeft * 0.1));
}
var finalItemLeft = this.model.get('_finalItemLeft');
if (newLeft < -finalItemLeft && deltaX < 0) {
var distance = Math.abs(newLeft + finalItemLeft);
newLeft = previousLeft + (deltaX / (distance * 0.1));
}
return newLeft;
},

evaluateNavigation: function() {
var currentStage = this.model.get('_stage');
var itemCount = this.model.get('_itemCount');
if (currentStage == 0) {
this.$('.narrative-controls').addClass('narrative-hidden');

if (itemCount > 1) {
this.$('.narrative-control-right').removeClass('narrative-hidden');
}
} else {
this.$('.narrative-control-left').removeClass('narrative-hidden');

if (currentStage == itemCount - 1) {
this.$('.narrative-control-right').addClass('narrative-hidden');
} else {
this.$('.narrative-control-right').removeClass('narrative-hidden');
}
}

},

getNearestItemIndex: function() {
var currentPosition = parseInt(this.$('.narrative-slider').css('margin-left'));
var graphicWidth = this.$('.narrative-slider-graphic').width();
var absolutePosition = currentPosition / graphicWidth;
var stage = this.model.get('_stage');
var relativePosition = stage - Math.abs(absolutePosition);

if (relativePosition < -0.3) {
stage++;
} else if (relativePosition > 0.3) {
stage--;
}

return this.constrainStage(stage);
},

getCurrentItem: function(index) {
return this.model.get('_items')[index];
},

getVisitedItems: function() {
return _.filter(this.model.get('_items'), function(item) {
return item._isVisited;
});
},

evaluateCompletion: function() {
if (this.getVisitedItems().length === this.model.get('_items').length) {
this.trigger('allItems');
}
},

moveElement: function($element, deltaX) {
var previousLeft = parseInt($element.css('margin-left'));
var newLeft = previousLeft + deltaX;

newLeft = this.constrainXPosition(previousLeft, newLeft, deltaX);
$element.css(('margin-' + this.model.get('_marginDir')), newLeft + 'px');
},

openPopup: function(event) {
event.preventDefault();
var currentItem = this.getCurrentItem(this.model.get('_stage'));
var popupObject = {
title: currentItem.title,
body: currentItem.body
};

// Set the visited attribute for small and medium screen devices
currentItem._isVisited = true;

Adapt.trigger('notify:popup', popupObject);
},

onNavigationClicked: function(event) {

if (!this.model.get('_active')) return;

var stage = this.model.get('_stage');
var numberOfItems = this.model.get('_itemCount');

if ($(event.currentTarget).hasClass('narrative-control-right')) {
stage++;
} else if ($(event.currentTarget).hasClass('narrative-control-left')) {
stage--;
}
stage = (stage + numberOfItems) % numberOfItems;
this.setStage(stage);
},

onProgressClicked: function(event) {
event.preventDefault();
var clickedIndex = $(event.target).index();
this.setStage(clickedIndex);
},

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-inner').off('inview');
this.setCompletionStatus();
}
}
},

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.model.get('_items').length > 1) {
this.on(this.completionEvent, _.bind(this.onCompletion, this));
} else {
this.$('.component-widget').on('inview', _.bind(this.inview, this));
}
}

define([
'core/js/adapt',
'./narrativeView',
'core/js/models/itemsComponentModel'
],function(Adapt, NarrativeView, ItemsComponentModel) {

return Adapt.register('narrative', {
model: ItemsComponentModel,
view: NarrativeView
});

Adapt.register('narrative', Narrative);

return Narrative;

});
Loading