our-journey
Version:
Our Journey interactive student journey creator. | © 2018 The Open University (IET-OU).
626 lines (574 loc) • 22.8 kB
JavaScript
/* Core API | ©The Open University.
*/
module.exports = {
// Functions.
initialiseElements: initialiseElements,
updateElements: updateElements,
changeFocus: changeFocus,
demoFill: demoFill,
updateElement: updateElement,
clearElement: clearElement,
moveFwdElement: moveFwdElement,
moveBackElement: moveBackElement,
canvasGotFocus: canvasGotFocus,
canvasLostFocus: canvasLostFocus,
// Properties.
getElements: getElements,
setFocusElement: setFocusElement,
getNumElements: getNumElements,
editFocus: editFocus,
stopFloatingFocus: stopFloatingFocus,
addElements: addElements,
getMaxElements: getMaxElements,
addMoreFocus: addMoreFocus,
setCardColour: setCardColour,
setEmoticonColour: setEmoticonColour,
isPrinting: isPrinting,
cardFocus: cardFocus,
addMoreCardFocus: addMoreCardFocus,
clearFocus: clearFocus,
addCard: addCard,
moveMenuChanged: moveMenuChanged
};
const UI = require('./user-interface');
const ASSET = require('./assets');
const DIM = require('./dimension.json');
const LAYOUT = require('./layout');
const UTIL = require('./util');
// Status variables
var elements = [];
var focusElement = 0;
var canvasInFocus = false;
var floatEditing = false;
var focusOnAddMore = false;
var printed = false;
var cardColour = 'Ivory';
var emoColour = 'White';
// Number of card elements presented in page
var numElements = 15;
var maxElements = 64;
// These variables state which elements are vertical ones for the default layout presentation. On the left (vl) or the right (vr).
var vlElements = [ 0, 9, 10, 19, 20, 29, 30, 39, 40, 49, 50, 59, 60 ];
var vrElements = [ 4, 5, 14, 15, 24, 25, 34, 35, 44, 45, 54, 55, 64 ];
document.addEventListener('keydown', function (event) { // Was: , (event) => {
const keyName = event.key;
var focus = document.activeElement.getAttribute('id');
if (canvasInFocus) {
switch (keyName) {
case 'Enter':
if (focusOnAddMore) {
LAYOUT.addElementsToLayout();
} else if (!floatEditing) {
editFocus();
}
break;
case 'Escape':
if (floatEditing) {
editFocus();
document.getElementById('group' + focusElement).focus();
}
break;
case 'Tab':
if (floatEditing) {
if (focus === 'floating_move_menu') {
if (event.shiftKey === false) {
editFocus();
document.getElementById('group' + focusElement).focus();
}
}
if (focus === 'floating_icon_select') {
if (event.shiftKey === true) {
if (focusElement === 0) {
event.preventDefault();
editFocus();
document.getElementById('help_link').focus();
} else {
editFocus();
document.getElementById('group' + focusElement).focus();
}
}
}
}
}
}
}, false);
window.addEventListener('beforeunload', function (e) {
var confirmationMessage = 'WARNING: If you leave without saving, you will lose changes to your journey.';
(e || window.event).returnValue = confirmationMessage;
return confirmationMessage;
});
function initialiseElements (start) {
for (var i = start; i < numElements; i++) {
var element = { eID: 'place' + i, description: '', emoticon: 'none', icon: 'none', postit: '' };
elements.push(element);
}
updateElements();
}
function demoFill () {
for (var i = 0; i < elements.length; i++) {
elements[i] = { eID: 'place' + i, description: 'test description ' + i, emoticon: 'happy', icon: 'timelost', postit: 'post it text' };
}
updateElements();
}
function elementClick () {
var e = parseInt(this.id.substring(5));
if (e !== focusElement) {
focusElement = e;
if (printed) {
UI.toggleEditor('show');
printed = false;
}
stopFloatingFocus();
} else {
editFocus();
}
}
function cardFocus () {
var e = parseInt(this.id.substring(5));
if (e !== focusElement) {
focusElement = e;
changeFocus();
}
}
function setCardColour (colour) {
cardColour = colour;
updateElements();
document.getElementById('card_colour_select').value = cardColour;
}
function setEmoticonColour (colour) {
emoColour = colour;
updateElements();
document.getElementById('emoticon_colour_select').value = emoColour;
}
function updateElements () {
for (var i = 0; i < numElements; i++) {
var elementGroup = document.getElementById('group' + i);
elementGroup.addEventListener('click', elementClick);
elementGroup.addEventListener('focus', cardFocus);
var card = document.getElementById('place' + i);
var emoticonback = document.getElementById('emoticonback' + i);
card.style.fill = cardColour;
emoticonback.style.fill = emoColour;
if ((LAYOUT.getLayoutStyle() === 'default') && vlElements.includes(i)) {
card.setAttribute('x', DIM.rectXV);
} else {
card.setAttribute('y', DIM.rectY);
}
updateDescription(i);
updateEmoticon(i);
updateIcon(i);
updatePostIt(i);
updateAltText(i);
}
}
function updateDescription (i) {
var eText = document.getElementById('description' + i);
var layout = LAYOUT.getLayoutStyle();
eText.textContent = getElement(i).description;
if ((layout === 'default') && vlElements.includes(i)) {
eText.setAttribute('x', DIM.textXV);
eText.setAttribute('y', DIM.textYV);
} else if ((layout === 'default') && vrElements.includes(i)) {
eText.setAttribute('x', DIM.textXVR);
eText.setAttribute('y', DIM.textYVR);
} else {
eText.setAttribute('x', DIM.textX);
eText.setAttribute('y', DIM.textY);
}
}
function updateEmoticon (i) {
var eEmo = document.getElementById('emoticon' + i);
var emptyEmo = document.getElementById('empty_emoticon');
var emptyEmoText = document.getElementById('empty_emoticon_text');
var backEmo = document.getElementById('emoticonback' + i);
var layoutStyle = LAYOUT.getLayoutStyle();
if (getElement(i).emoticon !== 'none') {
for (var j = 0; j < ASSET.emoticonCount(); j++) {
if (ASSET.hasEmoticon(j, getElement(i))) {
backEmo.setAttribute('visibility', 'visible');
eEmo.setAttribute('height', DIM.emoticonHeight);
eEmo.setAttribute('width', DIM.emoticonWidth);
if ((layoutStyle === 'default') && (vlElements.includes(i))) {
backEmo.setAttribute('cx', DIM.emoticonXV + 36);
backEmo.setAttribute('cy', DIM.emoticonYV + 36);
eEmo.setAttribute('x', DIM.emoticonXV);
eEmo.setAttribute('y', DIM.emoticonYV);
} else if ((layoutStyle === 'default') && (vrElements.includes(i))) {
backEmo.setAttribute('cx', DIM.emoticonXVR + 36);
backEmo.setAttribute('cy', DIM.emoticonYVR + 36);
eEmo.setAttribute('x', DIM.emoticonXVR);
eEmo.setAttribute('y', DIM.emoticonYVR);
} else {
backEmo.setAttribute('cx', DIM.emoticonX + 36);
backEmo.setAttribute('cy', DIM.emoticonY + 36);
eEmo.setAttribute('x', DIM.emoticonX);
eEmo.setAttribute('y', DIM.emoticonY);
}
eEmo.setAttribute('display', 'inline');
eEmo.setAttribute('href', ASSET.getEmoticonPath(j));
eEmo.setAttribute('alt', ASSET.getEmoticonName(j));
emptyEmo.setAttribute('fill-opacity', '0.0');
emptyEmoText.textContent = '';
}
}
} else {
eEmo.setAttribute('display', 'none');
backEmo.setAttribute('visibility', 'collapse');
}
}
function updateIcon (i) {
var eIcon = document.getElementById('icon' + i);
var emptyIcon = document.getElementById('empty_icon');
var emptyIconText = document.getElementById('empty_icon_text');
var layoutStyle = LAYOUT.getLayoutStyle();
if (getElement(i).icon !== 'none') {
for (var j = 0; j < ASSET.iconCount(); j++) {
if (ASSET.hasIcon(j, getElement(i))) {
eIcon.setAttribute('height', DIM.iconHeight);
eIcon.setAttribute('width', DIM.iconWidth);
if ((layoutStyle === 'default') && (vlElements.includes(i))) {
eIcon.setAttribute('x', DIM.iconXV);
eIcon.setAttribute('y', DIM.iconYV);
} else {
eIcon.setAttribute('x', DIM.iconX);
eIcon.setAttribute('y', DIM.iconY);
}
eIcon.setAttribute('display', 'inline');
eIcon.setAttribute('href', ASSET.getIconPath(j));
eIcon.setAttribute('alt', ASSET.getIconName(j));
emptyIcon.setAttribute('fill-opacity', '0.0');
emptyIconText.textContent = '';
}
}
} else {
eIcon.setAttribute('display', 'none');
}
}
function updatePostIt (i) {
var ePostIt = document.getElementById('postit' + i);
var ePostItText = document.getElementById('postittext' + i);
var layoutStyle = LAYOUT.getLayoutStyle();
if (getElement(i).postit !== '') {
ePostIt.setAttribute('visibility', 'visible');
ePostItText.setAttribute('visibility', 'visible');
ePostItText.setAttribute('width', DIM.postitTextWidth);
if (((layoutStyle === 'default') && vlElements.includes(i))) {
ePostIt.setAttribute('y', DIM.postitVY);
ePostIt.setAttribute('x', DIM.postitVX);
ePostItText.setAttribute('y', DIM.postitTextY + DIM.postitVY);
ePostItText.setAttribute('x', DIM.postitTextVX);
ePostItText.setAttribute('y', DIM.postitTextVY);
} else if ((layoutStyle === 'default') && vrElements.includes(i)) {
ePostIt.setAttribute('x', DIM.postitVRX);
ePostIt.setAttribute('y', DIM.postitVRY);
ePostItText.setAttribute('y', DIM.postitTextVRY);
ePostItText.setAttribute('x', DIM.postitTextVRX);
} else if (layoutStyle === 'scol') {
ePostIt.setAttribute('x', DIM.postitScolX);
ePostIt.setAttribute('y', DIM.postitScolY);
ePostItText.setAttribute('y', DIM.postitTextScolY + DIM.postitScolY);
ePostItText.setAttribute('x', DIM.postitTextScolX);
} else if (layoutStyle === 'default') {
ePostIt.setAttribute('x', DIM.postitX);
ePostIt.setAttribute('y', DIM.postitY);
ePostItText.setAttribute('x', DIM.postitTextX);
ePostItText.setAttribute('y', DIM.postitTextY);
}
ePostItText.textContent = getElement(i).postit;
} else {
ePostIt.setAttribute('visibility', 'collapse');
ePostItText.setAttribute('visibility', 'collapse');
}
}
function updateAltText (i) {
var ePlace = document.getElementById('group' + i);
var iconText;
for (var j = 0; j < ASSET.iconCount(); j++) {
if (ASSET.hasIcon(j, getElement(i))) {
iconText = ASSET.getIconAlt(j);
}
}
var alttext = 'Card ' + i + '. Event: ' + iconText + ' : ' + elements[i].description + '. Feeling ' + elements[i].emoticon + '. ' + elements[i].postit;
ePlace.setAttribute('aria-label', alttext);
}
function changeFocus () {
UI.toggleOptions(0);
for (var i = 0; i < elements.length; i++) {
document.getElementById(elements[i].eID).setAttribute('class', 'not-focussed');
}
document.getElementById(elements[focusElement].eID).setAttribute('class', 'focussed');
document.getElementById('group' + focusElement).focus();
if (UI.getEditor() === 'fixed') {
document.getElementById('event_desc').value = elements[focusElement].description;
document.getElementById('icon_select').value = elements[focusElement].icon;
document.getElementById('emoticon_select').value = elements[focusElement].emoticon;
document.getElementById('post_it_text').value = elements[focusElement].postit;
document.getElementById('title').innerHTML = 'Journey Editor: Card ' + focusElement;
} else if (UI.getEditor() === 'float') {
stopFloatingFocus();
addMoreFocus(false);
}
if (focusElement !== -1) {
var focusY = document.getElementById('group' + focusElement).getAttribute('y');
window.scrollTo(window.scrollX, focusY - 200);
}
}
function clearFocus () {
focusElement = -1;
for (var i = 0; i < elements.length; i++) {
document.getElementById(elements[i].eID).setAttribute('class', 'not-focussed');
}
}
function addMoreCardFocus () {
// - Needs improvement - tab focus does not remove focus from previous element
focusOnAddMore = true;
focusElement = -1;
// addMoreFocus(true);
// changeFocus();
var focusY = UTIL.qs('#add_more_card').getAttribute('y');
window.scrollTo(0, focusY);
}
function addMoreFocus (focusin) {
if (focusin) {
UTIL.qs('#add_more_rect').setAttribute('class', 'focussed');
// -causes loop? updateElements();
} else {
UTIL.qs('#add_more_rect').setAttribute('class', 'not-focussed');
focusOnAddMore = false;
}
}
function stopFloatingFocus () {
UTIL.qs('#floating_editor').setAttribute('visibility', 'collapse');
floatEditing = false;
}
function editFocus () {
const FL_EDITOR = UTIL.qs('#floating_editor');
const FL_ED_OUTLINE = UTIL.qs('#floating_editor_outline');
const FL_ICON = UTIL.qs('#floating_icon');
const FL_EMOJI = UTIL.qs('#floating_emoticon');
const FL_DESC = UTIL.qs('#floating_desc');
const FL_POST = UTIL.qs('#floating_post');
const EM_ICON = UTIL.qs('#empty_icon');
const EM_EMOJI = UTIL.qs('#empty_emoticon');
const FL_MOVE = UTIL.qs('#floating_move');
const FOCUS_EL = LAYOUT.getLayoutData()[ LAYOUT.getLayout() ][ focusElement ];
// let newX;
let newY;
if (UI.getEditor() === 'float') {
if (floatEditing) {
stopFloatingFocus();
} else {
if (LAYOUT.getLayoutStyle() === 'scol') {
newY = (focusElement * 130) + 170;
FL_EDITOR.setAttribute('x', '0');
FL_EDITOR.setAttribute('y', newY);
FL_EDITOR.setAttribute('visibility', 'visible');
} else if (LAYOUT.getLayoutStyle() === 'default') {
FL_EDITOR.setAttribute('x', FOCUS_EL[ '{x}' ]);
FL_EDITOR.setAttribute('y', FOCUS_EL[ '{y}' ]);
FL_EDITOR.setAttribute('visibility', 'visible');
if (vlElements.includes(focusElement)) {
FL_ED_OUTLINE.setAttribute('width', DIM.floatEditOutlineVW);
FL_ED_OUTLINE.setAttribute('height', DIM.floatEditOutlineVH);
FL_ED_OUTLINE.setAttribute('x', DIM.floatEditOutlineVX);
FL_ED_OUTLINE.setAttribute('y', DIM.floatEditOutlineVY);
FL_ICON.setAttribute('x', DIM.floatEditIconVX);
FL_ICON.setAttribute('y', DIM.floatEditIconVY);
FL_EMOJI.setAttribute('x', DIM.floatEditEmoVX);
FL_EMOJI.setAttribute('y', DIM.floatEditEmoVY);
FL_DESC.setAttribute('x', DIM.floatEditDescVX);
FL_DESC.setAttribute('y', DIM.floatEditDescVY);
EM_ICON.setAttribute('x', DIM.floatEmptyIconVX);
EM_ICON.setAttribute('y', DIM.floatEmptyIconVY);
EM_EMOJI.setAttribute('x', DIM.floatEmptyEmoVX);
EM_EMOJI.setAttribute('y', DIM.floatEmptyEmoVY);
FL_POST.setAttribute('x', DIM.floatPostItVX);
FL_POST.setAttribute('y', DIM.floatPostItVY);
FL_MOVE.setAttribute('x', DIM.floatMoveMenuVX);
FL_MOVE.setAttribute('y', DIM.floatMoveMenuVY);
} else if (vrElements.includes(focusElement)) {
FL_ED_OUTLINE.setAttribute('width', DIM.floatEditOutlineVRW);
FL_ED_OUTLINE.setAttribute('height', DIM.floatEditOutlineVRH);
FL_ED_OUTLINE.setAttribute('x', DIM.floatEditOutlineVRX);
FL_ED_OUTLINE.setAttribute('y', DIM.floatEditOutlineVRY);
FL_ICON.setAttribute('x', DIM.floatEditIconVRX);
FL_ICON.setAttribute('y', DIM.floatEditIconVRY);
FL_EMOJI.setAttribute('x', DIM.floatEditEmoVRX);
FL_EMOJI.setAttribute('y', DIM.floatEditEmoVRY);
FL_DESC.setAttribute('x', DIM.floatEditDescVRX);
FL_DESC.setAttribute('y', DIM.floatEditDescVRY);
EM_ICON.setAttribute('x', DIM.floatEmptyIconVRX);
EM_ICON.setAttribute('y', DIM.floatEmptyIconVRY);
EM_EMOJI.setAttribute('x', DIM.floatEmptyEmoVRX);
EM_EMOJI.setAttribute('y', DIM.floatEmptyEmoVRY);
FL_POST.setAttribute('x', DIM.floatPostItVRX);
FL_POST.setAttribute('y', DIM.floatPostItVRY);
FL_MOVE.setAttribute('x', DIM.floatMoveMenuVRX);
FL_MOVE.setAttribute('y', DIM.floatMoveMenuVRY);
} else {
FL_ED_OUTLINE.setAttribute('width', DIM.floatEditOutlineW);
FL_ED_OUTLINE.setAttribute('height', DIM.floatEditOutlineH);
FL_ED_OUTLINE.setAttribute('x', DIM.floatEditOutlineX);
FL_ED_OUTLINE.setAttribute('y', DIM.floatEditOutlineY);
FL_ICON.setAttribute('x', DIM.floatEditIconX);
FL_ICON.setAttribute('y', DIM.floatEditIconY);
FL_EMOJI.setAttribute('x', DIM.floatEditEmoX);
FL_EMOJI.setAttribute('y', DIM.floatEditEmoY);
FL_DESC.setAttribute('x', DIM.floatEditDescX);
FL_DESC.setAttribute('y', DIM.floatEditDescY);
EM_ICON.setAttribute('x', DIM.floatEmptyIconX);
EM_ICON.setAttribute('y', DIM.floatEmptyIconY);
EM_EMOJI.setAttribute('x', DIM.floatEmptyEmoX);
EM_EMOJI.setAttribute('y', DIM.floatEmptyEmoY);
FL_POST.setAttribute('x', DIM.floatPostItX);
FL_POST.setAttribute('y', DIM.floatPostItY);
FL_MOVE.setAttribute('x', DIM.floatMoveMenuX);
FL_MOVE.setAttribute('y', DIM.floatMoveMenuY);
}
}
const ICON_VALUE = elements[focusElement].icon;
const EMO_VALUE = elements[focusElement].emoticon;
const emptyIconText = UTIL.qs('#empty_icon_text');
const emptyEmoText = UTIL.qs('#empty_emoticon_text');
UTIL.qs('#floating_icon_select').value = ICON_VALUE;
if (ICON_VALUE === 'none') {
EM_ICON.setAttribute('fill-opacity', '0.9');
emptyIconText.textContent = '1. What happened?';
} else {
EM_ICON.setAttribute('fill-opacity', '0.0');
emptyIconText.textContent = '';
}
UTIL.qs('#floating_emoticon_select').value = EMO_VALUE;
if (EMO_VALUE === 'none') {
EM_EMOJI.setAttribute('fill-opacity', '0.9');
emptyEmoText.textContent = '3. How did you feel?';
} else {
EM_EMOJI.setAttribute('fill-opacity', '0.0');
emptyEmoText.textContent = '';
}
UTIL.qs('#floating_event_desc').value = elements[focusElement].description;
UTIL.qs('#floating_post_it_text').value = elements[focusElement].postit;
floatEditing = true;
UTIL.qs('#floating_icon_select').focus();
}
} else if (UI.getEditor() === 'fixed') {
UTIL.qs('#event_desc').focus();
}
}
function canvasGotFocus () {
canvasInFocus = true;
}
function canvasLostFocus () {
canvasInFocus = false;
}
function updateElement () {
if (UI.getEditor() === 'fixed') {
elements[focusElement].description = document.getElementById('event_desc').value;
elements[focusElement].icon = document.getElementById('icon_select').value;
elements[focusElement].emoticon = document.getElementById('emoticon_select').value;
elements[focusElement].postit = document.getElementById('post_it_text').value;
} else if (UI.getEditor() === 'float') {
elements[focusElement].icon = document.getElementById('floating_icon_select').value;
elements[focusElement].emoticon = document.getElementById('floating_emoticon_select').value;
elements[focusElement].description = document.getElementById('floating_event_desc').value;
elements[focusElement].postit = document.getElementById('floating_post_it_text').value;
}
updateElements();
}
function clearElement () {
// clears the information contained in the focused on element.
elements[focusElement] = { eID: 'place' + focusElement, description: '', emoticon: 'none', icon: 'none', postit: '' };
updateElements();
changeFocus();
}
function moveMenuChanged () {
var itemSelected = UTIL.qs('#floating_move_menu');
if (itemSelected.value === 'SwapBack') {
moveBackElement();
} else if (itemSelected.value === 'SwapFwd') {
moveFwdElement();
} else if (itemSelected.value === 'AddNew') {
addCard();
}
itemSelected.value = 'Move';
}
function moveBackElement () {
// moves the focused on element back towards the start
if (focusElement > 0) {
// swap the elements
var swap = elements[focusElement - 1];
elements[focusElement - 1] = elements[focusElement];
elements[focusElement] = swap;
// swap the eID strings for the elements to maintain correct link to the locations
var swapeIDfore = elements[focusElement].eID;
var swapeIDback = elements[focusElement - 1].eID;
elements[focusElement - 1].eID = swapeIDfore;
elements[focusElement].eID = swapeIDback;
// return focus to the same element as at the start of this process
focusElement--;
changeFocus();
editFocus();
}
updateElements();
}
function moveFwdElement () {
// moves the focused on element forward from its current position
if (focusElement < (elements.length - 1)) {
// swap the elements
var swap = elements[focusElement + 1];
elements[focusElement + 1] = elements[focusElement];
elements[focusElement] = swap;
// swap the eID strings for the elements to maintain correct link to the locations
var swapeIDfore = elements[focusElement].eID;
var swapeIDback = elements[focusElement + 1].eID;
elements[focusElement + 1].eID = swapeIDfore;
elements[focusElement].eID = swapeIDback;
focusElement++;
changeFocus();
editFocus();
}
updateElements();
}
function addCard () {
// adds in a new card after the one currently in focus
if (focusElement < (maxElements - 1)) {
// check if last card is used, if so, extend number of cards (if not already at maximum)
if ((elements[elements.length - 1].icon !== 'none') || (elements[elements.length - 1].description !== '') || (elements[elements.length - 1].emoticon !== 'none') || (elements[elements.length - 1].postit !== '')) {
if (elements.length < maxElements) {
LAYOUT.addElementsToLayout();
} else {
// TODO: alert the user to failure?
return;
}
}
// loop through all cards and move them forward one in the list
for (var i = elements.length - 2; i > focusElement; i--) {
elements[i + 1] = elements[i];
elements[i + 1].eID = 'place' + (i + 1);
}
// add the new card into place
elements[focusElement + 1] = { eID: 'place' + (focusElement + 1), description: '', emoticon: 'none', icon: 'none', postit: '' };
}
updateElements();
}
function setFocusElement (num) {
focusElement = num;
}
function getElements () {
return elements;
}
function getElement (idx) {
return elements[ idx ];
}
function getNumElements () {
return numElements;
}
function addElements (addition) {
numElements = numElements + addition;
}
function getMaxElements () {
return maxElements;
}
function isPrinting () {
printed = true;
}