Skip to content

Commit 7383f69

Browse files
initial commit
0 parents  commit 7383f69

14 files changed

+1452
-0
lines changed

LICENSE

Lines changed: 674 additions & 0 deletions
Large diffs are not rendered by default.

README.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# adapt-contrib-languagePicker
2+
3+
**language Picker** is an *extension* bundled with the [Adapt framework](https://github.com/adaptlearning/adapt_framework).
4+
5+
todo:

bower.json

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
{
2+
"name": "adapt-contrib-pageLevelProgress",
3+
"version": "1.0.0",
4+
"framework": "^2.0.0",
5+
"homepage": "https://github.com/lc-thomasberger/adapt-languagePicker",
6+
"issues": "https://github.com/adaptlearning/adapt_framework/issues",
7+
"displayName": "Langauge Picker",
8+
"extension": "languagePicker",
9+
"description": "An extension to select a Language",
10+
"main": "/js/adapt-languagePicker.js",
11+
"keywords": [
12+
"adapt-plugin",
13+
"adapt-extension"
14+
],
15+
"license": "GPLv3",
16+
"targetAttribute": "_languages"
17+
}

example.json

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
// To go on in config
2+
3+
"_languagePicker": {
4+
"_isEnabled": true,
5+
"displayTitle": "Please select a language",
6+
"body": "This course is available in the following languages",
7+
"_languages": [
8+
{
9+
"_language": "en",
10+
"_direction": "ltr",
11+
"displayName": "English",
12+
"warningTitle": "Change language?",
13+
"warningMessage": "Changing the language will reset course progress.<br><br>Would you like to proceed?",
14+
"_buttons": {
15+
"yes": "Yes",
16+
"no": "No"
17+
}
18+
},
19+
{
20+
"_language": "de",
21+
"_direction": "ltr",
22+
"displayName": "Deutsch",
23+
"warningTitle": "Sprache ändern?",
24+
"warningMessage": "Ändern der Sprache wird den Fortschritt des Kurses zurücksetzen.<br><br>Möchte Sie fortfahren?",
25+
"_buttons": {
26+
"yes": "Ja",
27+
"no": "Nein"
28+
}
29+
}
30+
],
31+
"_accessibility": {
32+
"_accessibilityToggleTextOn": "Turn accessibility on?",
33+
"_accessibilityToggleTextOff": "Turn accessibility off?",
34+
"_accessibilityInstructions": {
35+
"touch": "Usage instructions. Use swipe right for next. Use swipe left for previous. Use a double tap to select. Use a two finger slide up to go to the top of the page.",
36+
"notouch": "Usage instructions. Use tab for next. Use shift tab for previous. Use enter to select. Use escape to go to the top of the page.",
37+
"ipad": "Usage instructions for touchscreens. Use swipe right for next. Use swipe left for previous. Use a double tap to select. Use a two finger slide up to go to the top of the page. Usage instructions for keyboard access. Use right for next. Use left for previous. Use up and down together to select."
38+
}
39+
}
40+
}

js/accessibilityView.js

Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
1+
define([
2+
'coreJS/adapt'
3+
], function(Adapt) {
4+
5+
var cookie = (function cookie(){function e(){for(var e=0,n={};e<arguments.length;e++){var t=arguments[e];for(var r in t)n[r]=t[r]}return n}function n(t){function r(n,o,i){var c;if("undefined"!=typeof document){if(arguments.length>1){if(i=e({path:"/"},r.defaults,i),"number"==typeof i.expires){var a=new Date;a.setMilliseconds(a.getMilliseconds()+864e5*i.expires),i.expires=a}try{c=JSON.stringify(o),/^[\{\[]/.test(c)&&(o=c)}catch(s){}return o=t.write?t.write(o,n):encodeURIComponent(String(o)).replace(/%(23|24|26|2B|3A|3C|3E|3D|2F|3F|40|5B|5D|5E|60|7B|7D|7C)/g,decodeURIComponent),n=encodeURIComponent(String(n)),n=n.replace(/%(23|24|26|2B|5E|60|7C)/g,decodeURIComponent),n=n.replace(/[\(\)]/g,escape),document.cookie=[n,"=",o,i.expires&&"; expires="+i.expires.toUTCString(),i.path&&"; path="+i.path,i.domain&&"; domain="+i.domain,i.secure?"; secure":""].join("")}n||(c={});for(var p=document.cookie?document.cookie.split("; "):[],u=/(%[0-9A-Z]{2})+/g,d=0;d<p.length;d++){var f=p[d].split("="),l=f[0].replace(u,decodeURIComponent),m=f.slice(1).join("=");'"'===m.charAt(0)&&(m=m.slice(1,-1));try{if(m=t.read?t.read(m,l):t(m,l)||m.replace(u,decodeURIComponent),this.json)try{m=JSON.parse(m)}catch(s){}if(n===l){c=m;break}n||(c[l]=m)}catch(s){}}return c}}return r.set=r,r.get=function(e){return r(e)},r.getJSON=function(){return r.apply({json:!0},[].slice.call(arguments))},r.defaults={},r.remove=function(n,t){r(n,"",e(t,{expires:-1}))},r.withConverter=n,r}return n(function(){})})();
6+
7+
var AccessibilityView = Backbone.View.extend({
8+
9+
el: '#accessibility-toggle',
10+
11+
initialize: function() {
12+
this.setupHelpers();
13+
14+
var settings = this.getStoredSettings();
15+
Adapt.config.get("_accessibility")._isActive = settings.a11y || false;
16+
17+
this.configureAccessibility();
18+
this.setupUsageInstructions();
19+
20+
this.render();
21+
},
22+
23+
getStoredSettings: function() {
24+
var str = cookie.get("_languagePicker") || "{}";
25+
var settings = JSON.parse(str);
26+
return settings;
27+
},
28+
29+
setStoredSettings: function(settings) {
30+
var str = JSON.stringify(settings);
31+
cookie.set("_languagePicker", str);
32+
},
33+
34+
events: {
35+
'click' : 'toggleAccessibility'
36+
},
37+
38+
render: function() {
39+
var hasAccessibility = Adapt.config.has('_accessibility')
40+
&& Adapt.config.get('_accessibility')._isEnabled;
41+
42+
if (!hasAccessibility) {
43+
return;
44+
} else {
45+
var isActive = Adapt.config.get('_accessibility')._isActive;
46+
var offLabel = this.model.get("_accessibility") && this.model.get("_accessibility")._accessibilityToggleTextOff;
47+
var onLabel = this.model.get("_accessibility") && this.model.get("_accessibility")._accessibilityToggleTextOn;
48+
49+
var toggleText = isActive ? offLabel : onLabel;
50+
51+
this.$el.html(toggleText);
52+
53+
if (isActive) {
54+
$("html").addClass('accessibility');
55+
$("#accessibility-instructions").a11y_focus();
56+
} else {
57+
$("html").removeClass('accessibility');
58+
}
59+
}
60+
},
61+
62+
toggleAccessibility: function(event) {
63+
event.preventDefault();
64+
65+
var hasAccessibility = Adapt.config.get('_accessibility')._isActive;
66+
67+
var toggleAccessibility = (hasAccessibility) ? false : true;
68+
69+
Adapt.config.get('_accessibility')._isActive = toggleAccessibility;
70+
71+
Adapt.trigger('languagepicker:accessibility:toggle');
72+
73+
this.configureAccessibility();
74+
this.setupUsageInstructions();
75+
76+
this.render();
77+
78+
window.location.reload();
79+
},
80+
81+
setupHelpers: function() {
82+
var config = Adapt.config.get("_accessibility");
83+
84+
Handlebars.registerHelper('a11y_text', function(text) {
85+
//ALLOW ENABLE/DISABLE OF a11y_text HELPER
86+
if (config && config._isTextProcessorEnabled === false) {
87+
return text;
88+
} else {
89+
return $.a11y_text(text);
90+
}
91+
});
92+
},
93+
94+
configureAccessibility: function() {
95+
96+
var isActive = Adapt.config.get('_accessibility')._isActive;
97+
98+
if (!Modernizr.touch) {
99+
var settings = {
100+
a11y: Adapt.config.get("_accessibility")._isActive
101+
};
102+
this.setStoredSettings(settings);
103+
Adapt.offlineStorage.set("a11y", settings.a11y);
104+
}
105+
106+
if (isActive) {
107+
108+
_.extend($.a11y.options, {
109+
isTabbableTextEnabled: true,
110+
isUserInputControlEnabled: true,
111+
isFocusControlEnabled: true,
112+
isFocusLimited: true,
113+
isRemoveNotAccessiblesEnabled: true,
114+
isAriaLabelFixEnabled: true,
115+
isFocusWrapEnabled: true,
116+
isScrollDisableEnabled: true,
117+
isScrollDisabledOnPopupEnabled: false,
118+
isSelectedAlertsEnabled: true,
119+
isAlertsEnabled: true
120+
});
121+
} else {
122+
_.extend($.a11y.options, {
123+
isTabbableTextEnabled: false,
124+
isUserInputControlEnabled: true,
125+
isFocusControlEnabled: true,
126+
isFocusLimited: false,
127+
isRemoveNotAccessiblesEnabled: true,
128+
isAriaLabelFixEnabled: true,
129+
isFocusWrapEnabled: true,
130+
isScrollDisableEnabled: true,
131+
isScrollDisabledOnPopupEnabled: false,
132+
isSelectedAlertsEnabled: false,
133+
isAlertsEnabled: false
134+
});
135+
}
136+
137+
$.a11y.ready();
138+
},
139+
140+
setupUsageInstructions: function() {
141+
if (!this.model.get("_accessibility") || !this.model.get("_accessibility")._accessibilityInstructions) {
142+
$("#accessibility-instructions").remove();
143+
return;
144+
}
145+
146+
var instructionsList = this.model.get("_accessibility")._accessibilityInstructions;
147+
148+
var usageInstructions;
149+
if (instructionsList[Adapt.device.browser]) {
150+
usageInstructions = instructionsList[Adapt.device.browser];
151+
} else if (Modernizr.touch) {
152+
usageInstructions = instructionsList.touch || "";
153+
} else {
154+
usageInstructions = instructionsList.notouch || "";
155+
}
156+
157+
$("#accessibility-instructions").html( usageInstructions );
158+
}
159+
160+
});
161+
162+
return AccessibilityView;
163+
164+
});

js/adapt-languagePicker.js

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
define([
2+
'coreJS/adapt',
3+
'backbone',
4+
'./languagePickerView',
5+
'./languagePickerNavView',
6+
'./languagePickerModel'
7+
], function(Adapt, Backbone, LanguagePickerView, LanguagePickerNavView, LanguagePickerModel) {
8+
9+
var languagePickerModel;
10+
11+
Adapt.once('configModel:dataLoaded', onConfigLoaded);
12+
13+
function onConfigLoaded() {
14+
if (!Adapt.config.has('_languagePicker')) return;
15+
if (!Adapt.config.get('_languagePicker')._isEnabled) return;
16+
17+
// stop default language loading
18+
Adapt.config.set("_canLoadData", false);
19+
languagePickerModel = new LanguagePickerModel(Adapt.config.get('_languagePicker'));
20+
21+
Adapt.on('router:page', setupNavigationView);
22+
Adapt.on('router:menu', setupNavigationView);
23+
24+
// wait for spoor to initialize on the configModel:dataLoaded event
25+
_.defer(onSpoorInitialized);
26+
}
27+
28+
function onSpoorInitialized() {
29+
// see if a language was previously saved
30+
var previousLanguage = Adapt.offlineStorage.get("lang");
31+
if (!previousLanguage) {
32+
// ask user for lanugage if non specified
33+
showLanguagePickerView();
34+
} else {
35+
// set config default language
36+
languagePickerModel.setDefaultLanguage(previousLanguage);
37+
loadLanguage();
38+
}
39+
}
40+
41+
function showLanguagePickerView () {
42+
var languagePickerView = new LanguagePickerView({
43+
model: languagePickerModel
44+
});
45+
46+
languagePickerView.$el.appendTo('#wrapper');
47+
}
48+
49+
function loadLanguage () {
50+
// continue loading course
51+
Adapt.trigger('configModel:loadCourseData');
52+
}
53+
54+
function setupNavigationView () {
55+
var languagePickerNavView = new LanguagePickerNavView({
56+
model: languagePickerModel
57+
});
58+
59+
languagePickerNavView.$el.appendTo('.navigation-inner');
60+
}
61+
62+
});

js/languagePickerDrawerView.js

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
define([
2+
'coreJS/adapt',
3+
'backbone'
4+
], function(Adapt, Backbone) {
5+
6+
var LanguagePickerDrawerView = Backbone.View.extend({
7+
8+
events: {
9+
'click button': 'onButtonClick'
10+
},
11+
12+
initialize: function () {
13+
this.listenTo(Adapt, 'remove', this.remove);
14+
this.listenTo(Adapt, 'languagepicker:changelanguage:yes', this.onDoChangeLanguage);
15+
this.listenTo(Adapt, 'languagepicker:changelanguage:no', this.onDontChangeLanguage);
16+
this.render();
17+
},
18+
19+
render: function () {
20+
var data = this.model.toJSON();
21+
var template = Handlebars.templates[this.constructor.template];
22+
this.$el.html(template(data));
23+
},
24+
25+
onButtonClick: function (event) {
26+
var newLanguge = $(event.target).attr('data-language');
27+
this.model.set('newLanguge', newLanguge);
28+
var data = this.model.getLanguageDetails(newLanguge);
29+
30+
var promptObject = {
31+
title: data.warningTitle,
32+
body: data.warningMessage,
33+
_prompts:[
34+
{
35+
promptText: data._buttons.yes,
36+
_callbackEvent: "languagepicker:changelanguage:yes",
37+
},
38+
{
39+
promptText: data._buttons.no,
40+
_callbackEvent: "languagepicker:changelanguage:no"
41+
}
42+
],
43+
_showIcon: true
44+
}
45+
46+
47+
//keep active element incase the user cancels - usually navigation bar icon
48+
this.$finishFocus = $.a11y.state.focusStack.pop();
49+
//move drawer close focus to #focuser
50+
$.a11y.state.focusStack.push($("#focuser"));
51+
52+
Adapt.once('drawer:closed', function() {
53+
//wait for drawer to fully close
54+
_.delay(function(){
55+
//show yes/no popup
56+
Adapt.once('popup:opened', function() {
57+
//move popup close focus to #focuser
58+
$.a11y.state.focusStack.pop();
59+
$.a11y.state.focusStack.push($("#focuser"));
60+
});
61+
62+
Adapt.trigger('notify:prompt', promptObject);
63+
}, 250);
64+
});
65+
Adapt.trigger('drawer:closeDrawer');
66+
67+
},
68+
69+
onDoChangeLanguage: function () {
70+
// set default languge
71+
var newLanguge = this.model.get('newLanguge');
72+
this.model.setDefaultLanguage(newLanguge);
73+
// reset progress
74+
// this.model.resetCourseProgress();
75+
// reload course Data
76+
this.model.reloadCourseData();
77+
78+
this.remove();
79+
},
80+
81+
onDontChangeLanguage: function () {
82+
this.remove();
83+
84+
//wait for notify to close fully
85+
_.delay(_.bind(function(){
86+
//focus on navigation bar icon
87+
this.$finishFocus.a11y_focus();
88+
}, this), 500);
89+
90+
}
91+
92+
}, {
93+
template: 'languagePickerDrawerView'
94+
});
95+
96+
return LanguagePickerDrawerView;
97+
98+
});

0 commit comments

Comments
 (0)