Skip to content

Commit

Permalink
Updated for FW v5 compatibility (#9)
Browse files Browse the repository at this point in the history
* update for v5 compatibility, version bump
* remove reference to IE8 - it's not supported by this extension any more (as a result of FW v5 dependency)
* use aria-disabled instead of disabled (to match latest FW behaviour)
* use ES6 code where sensible
* bump FW version to the one with ES6 support
* fix eslint errors
* Indentation amends
* Added triple curly brace to aria label
* Theme amends
* remove .bowerrc
Co-authored-by: Guy Willis <[email protected]>
  • Loading branch information
Matt Leathes authored Mar 1, 2021
1 parent 21998c5 commit 4039c8b
Show file tree
Hide file tree
Showing 6 changed files with 185 additions and 193 deletions.
2 changes: 0 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,3 @@ The extension will hide the 'buttons' `<div>` for all the questions within the a
You should ensure that all questions within the article are set to 'do not show feedback' (either by setting `_canShowFeedback` to `false` on the individual question components or - if an assessment article - by setting `_questions._canShowFeedback` to `false` in the article's `_assessment` configuration) - if you don't, all the feedback will be shown at once which is unlikely to be desirable...

Also note that because the standard button group for each question gets hidden, the user will have no way of accessing the 'correct answer' functionality.

You might want to avoid using this extension if IE8 support is required. The extension triggers submission of multiple question components at once, just the sort of operation that is likely to trigger the 'script on this page is causing Internet Explorer to run slowly' error.
37 changes: 19 additions & 18 deletions bower.json
Original file line number Diff line number Diff line change
@@ -1,20 +1,21 @@
{
"name": "adapt-submitAll",
"repository": {
"type": "git",
"url": "git://github.com/cgkineo/adapt-submitAll.git"
},
"framework": ">=2",
"homepage": "https://github.com/cgkineo/adapt-submitAll",
"version": "2.1.0",
"displayName": "Submit All",
"extension": "submitAll",
"description": "Extension to allow multiple questions to be submitted via a single submit button",
"main": "/js/adapt-submitAll.js",
"keywords": [
"adapt-plugin",
"adapt-extension"
],
"license": "GPL-3.0",
"targetAttribute": "_submitAll"
"name": "adapt-submitAll",
"repository": {
"type": "git",
"url": "git://github.com/cgkineo/adapt-submitAll.git"
},
"version": "3.0.0",
"framework": ">=5.3",
"homepage": "https://github.com/cgkineo/adapt-submitAll",
"issues": "https://github.com/cgkineo/adapt-submitAll/issues/new",
"extension": "submitAll",
"displayName": "Submit All",
"description": "Extension to allow multiple questions to be submitted via a single submit button",
"main": "/js/adapt-submitAll.js",
"keywords": [
"adapt-plugin",
"adapt-extension"
],
"license": "GPL-3.0",
"targetAttribute": "_submitAll"
}
6 changes: 3 additions & 3 deletions example.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// To go in articles.json
"_submitAll": {
// To go in articles.json
"_submitAll": {
"_isEnabled": true,
"_insertAfterBlock": ""
}
}
287 changes: 143 additions & 144 deletions js/adapt-submitAll.js
Original file line number Diff line number Diff line change
@@ -1,147 +1,146 @@
define([
'core/js/adapt'
'core/js/adapt'
], function(Adapt) {

var SubmitAll = Backbone.View.extend({

events: {
'click .buttons-action': 'onSubmitAllButtonClicked'
},

initialize: function() {
this.model.get('_articleView').$el.addClass('noSubmitButtons');

this.listenTo(Adapt, {
'componentView:postRender': this.onComponentViewRendered,
remove: function() {
this.removeEventListeners();
this.remove();
}
});

_.bindAll(this, 'onInteraction', '_onInteractionDelegate');

this.render();
},

render: function() {
var submitButtonLabels = Adapt.course.get('_buttons')._submit;

this.$el.html(Handlebars.templates.submitAll({
buttonText: submitButtonLabels.buttonText,
ariaLabel: submitButtonLabels.ariaLabel
}));

this.$el.addClass('submitAll');

var $containerDiv = this.getContainerDiv(this.model.get('_articleView').$el, this.model.get('_insertAfterBlock'));
$containerDiv.after(this.$el);

return this;
},

/**
* Returns a reference to the `<div>` we're going to append our view to.
* @param {jQuery} $article JQuery reference to the article we're attached to
* @param {string} [blockId] The id of the block to append our view to. Must be in the article we're attached to...
* @return {jQuery}
*/
getContainerDiv: function($article, blockId) {
if (blockId) {
var $div = $article.find('.' + blockId);
if ($div.length > 0) return $div;
}

return $article.find('.block').last();
},

enableSubmitAllButton: function(enable) {
var $submitAllButton = this.$el.find('.buttons-action');
if (enable) {
$submitAllButton.removeClass('disabled').attr('disabled', false);
return;
}

$submitAllButton.addClass('disabled').attr('disabled', true);
},

/**
* Checks all the questions in the article to see if they're all ready to be submitted or not
* @return {boolean}
*/
canSubmit: function() {
return this.model.get('_componentViews').every(function(component) {
if (component.model.get('_isEnabled') && component.canSubmit()) {
return true;
}
});
},

removeEventListeners: function() {
this.model.get('_componentViews').forEach(function(view) {
if (view.model.get('_component') === 'textinput') {
view.$el.find('input').off('change.submitAll');
return;
}
view.$el.off('click.submitAll');
});
},

/**
* Checks the view to see if it is:
* a) a question component
* b) a child of the article we're attached to
* And, if it is, add it to the list and listen out for the learner interacting with it
* @param {Backbone.View} view
*/
onComponentViewRendered: function(view) {
if (!view.$el.hasClass('question-component')) return;

var parentArticleId = view.model.findAncestor('articles').get('_id');
var submitAllArticleId = this.model.get('_articleView').model.get('_id');
if (parentArticleId === submitAllArticleId) {
this.model.get('_componentViews').push(view);
if (view.model.get('_component') === 'textinput') {
view.$el.find('input').on('change.submitAll', this.onInteraction);
return;
}
view.$el.on('click.submitAll', this.onInteraction);
}
},

onInteraction: function() {
// need to wait until current call stack's done in FF
_.defer(this._onInteractionDelegate);
},

_onInteractionDelegate: function() {
if (!!this.model.get('_isSubmitted')) return;

this.enableSubmitAllButton(this.canSubmit());
},

onSubmitAllButtonClicked: function() {
this.model.get('_componentViews').forEach(function(view) {
$('.buttons-action', view.$el).trigger('click');
});

this.enableSubmitAllButton(false);

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

Adapt.trigger('submitAll:submitted', this.model.get('_componentViews'));
}
});

Adapt.on('articleView:postRender', function(view) {
var saData = view.model.get('_submitAll');
if(saData && saData._isEnabled) {
var model = new Backbone.Model(saData);
model.set({
_articleView: view,
_componentViews: []
});
new SubmitAll({ model: model });
}
});
});
const SubmitAll = Backbone.View.extend({

className: 'submit-all',

events: {
'click .js-btn-action': 'onSubmitAllButtonClicked'
},

initialize: function() {
this.model.get('_articleView').$el.addClass('no-submit-buttons');

this.listenTo(Adapt, {
'componentView:postRender': this.onComponentViewRendered,
remove: () => {
this.removeEventListeners();
this.remove();
}
});

_.bindAll(this, 'onInteraction', '_onInteractionDelegate');

this.render();
},

render: function() {
const submitButtonLabels = Adapt.course.get('_buttons')._submit;

this.$el.html(Handlebars.templates.submitAll({
buttonText: submitButtonLabels.buttonText,
ariaLabel: submitButtonLabels.ariaLabel
}));

const $containerDiv = this.getContainerDiv(this.model.get('_articleView').$el, this.model.get('_insertAfterBlock'));
$containerDiv.after(this.$el);

return this;
},

/**
* Returns a reference to the `<div>` we're going to append our view to.
* @param {jQuery} $article JQuery reference to the article we're attached to
* @param {string} [blockId] The id of the block to append our view to. Must be in the article we're attached to...
* @return {jQuery}
*/
getContainerDiv: function($article, blockId) {
if (blockId) {
const $div = $article.find('.' + blockId);
if ($div.length > 0) return $div;
}

return $article.find('.block').last();
},

enableSubmitAllButton: function(enable) {
const $submitAllButton = this.$el.find('.js-btn-action');
if (enable) {
$submitAllButton.removeClass('is-disabled').attr('aria-disabled', false);
return;
}

$submitAllButton.addClass('is-disabled').attr('aria-disabled', true);
},

/**
* Checks all the questions in the article to see if they're all ready to be submitted or not
* @return {boolean}
*/
canSubmit: function() {
const allAnswered = this.model.get('_componentViews').every(component => component.model.get('_isEnabled') && component.canSubmit());
return allAnswered;
},

removeEventListeners: function() {
this.model.get('_componentViews').forEach(view => {
if (view.model.get('_component') === 'textinput') {
view.$el.find('input').off('change.submitAll');
return;
}
view.$el.off('click.submitAll');
});
},

/**
* Checks the view to see if it is:
* a) a question component
* b) a child of the article we're attached to
* And, if it is, add it to the list and listen out for the learner interacting with it
* @param {Backbone.View} view
*/
onComponentViewRendered: function(view) {
if (!view.$el.hasClass('is-question')) return;

const parentArticleId = view.model.findAncestor('articles').get('_id');
const submitAllArticleId = this.model.get('_articleView').model.get('_id');
if (parentArticleId !== submitAllArticleId) return;

this.model.get('_componentViews').push(view);

if (view.model.get('_component') === 'textinput') {
view.$el.find('input').on('change.submitAll', this.onInteraction);
return;
}

view.$el.on('click.submitAll', this.onInteraction);
},

onInteraction: function() {
// need to wait until current call stack's done in FF
_.defer(this._onInteractionDelegate);
},

_onInteractionDelegate: function() {
if (this.model.get('_isSubmitted')) return;

this.enableSubmitAllButton(this.canSubmit());
},

onSubmitAllButtonClicked: function() {
this.model.get('_componentViews').forEach(view => view.$el.find('.js-btn-action').trigger('click'));

this.enableSubmitAllButton(false);

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

Adapt.trigger('submitAll:submitted', this.model.get('_componentViews'));
}
});

Adapt.on('articleView:postRender', view => {
const saData = view.model.get('_submitAll');
if (!saData || !saData._isEnabled) return;

const model = new Backbone.Model({
...saData,
_isSubmitted: false,
_articleView: view,
_componentViews: []
});

new SubmitAll({ model });
});
});
32 changes: 12 additions & 20 deletions less/submitAll.less
Original file line number Diff line number Diff line change
@@ -1,24 +1,16 @@
.noSubmitButtons {
.buttons {
display:none;
}
.no-submit-buttons {
.btn__container {
display: none;
}
}

.submitAll {
.buttons {
display: block;

.buttons-cluster {
text-align: center;
}

.buttons-action {
float:none;

& .disabled {

}
}
}
.submit-all {
.btn__container {
display: block;
}

.btn__action {
width: @device-width-large;
margin: 0 auto;
}
}
14 changes: 8 additions & 6 deletions templates/submitAll.hbs
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
<div class="buttons">
<div class="buttons-inner">
<div class="buttons-cluster clearfix">
<button class="buttons-action disabled" aria-label="{{ariaLabel}}" disabled="disabled">{{{buttonText}}}</button>
</div>
</div>
<div class="btn__container">
<div class="btn__response-container">

<button class="btn-text btn__action js-btn-action is-disabled" aria-label="{{{ariaLabel}}}" aria-disabled="true">
{{{buttonText}}}
</button>

</div>
</div>

0 comments on commit 4039c8b

Please sign in to comment.