\
+ "
+ );
+ },
+
+ clearCard: function () {
+ $(`#bfafEImage`).val('');
+ $(`#bfafEURLImageBack`).val('');
+
+ $('#bfafEAuthor').val('');
+ $('#bfafEAuthorBack').val('');
+
+ $('#bfafEAlt').val('');
+ $('#bfafEAltBack').val('');
+
+ $('#bfafEText').val('');
+ $('#bfafETextBack').val('');
+ $('#bfafEDescription').val('');
+ $exeDevice.showImage(0);
+ $exeDevice.showImage(1);
+ },
+
+ addCard: function () {
+ if (!$exeDevice.validateCard()) return;
+ let cards = $exeDevice.cardsGame;
+ $exeDevice.clearCard();
+ cards.push($exeDevice.getDefaultCard());
+ $exeDevice.active = cards.length - 1;
+ $('#bfafEPasteC').hide();
+ $('#bfafENumCards').text(cards.length);
+ $('#bfafENumberCard').val(cards.length);
+ $exeDevice.showCard($exeDevice.active);
+ },
+
+ removeCard: function () {
+ let cards = $exeDevice.cardsGame,
+ active = $exeDevice.active;
+ if (cards.length < 2) {
+ $exeDevice.showMessage($exeDevice.msgs.msgEOneCard);
+ return;
+ }
+
+ cards.splice(active, 1);
+ if (active >= cards.length - 1) {
+ active = cards.length - 1;
+ }
+
+ $('#bfafENumberCard').val(active);
+ $exeDevice.showCard(active);
+ $exeDevice.active = active;
+
+ $exeDevice.typeEdit = -1;
+ $('#bfafEPasteC').hide();
+ $('#bfafENumCards').text(cards.length);
+ },
+
+ copyCard: function () {
+ if (!$exeDevice.validateCard()) return;
+
+ $exeDevice.typeEdit = 0;
+ $exeDevice.clipBoard = JSON.parse(
+ JSON.stringify($exeDevice.cardsGame[$exeDevice.active])
+ );
+
+ $('#bfafEPasteC').show();
+ },
+
+ cutCard: function () {
+ if (!$exeDevice.validateCard()) return;
+
+ $exeDevice.numberCutCuestion = $exeDevice.active;
+ $exeDevice.typeEdit = 1;
+ $('#bfafEPasteC').show();
+ },
+
+ pasteCard: function () {
+ let cards = $exeDevice.cardsGame,
+ active = $exeDevice.active;
+
+ if ($exeDevice.typeEdit == 0) {
+ active++;
+ cards.splice(active, 0, $exeDevice.clipBoard);
+ } else if ($exeDevice.typeEdit == 1) {
+ $('#bfafEPasteC').hide();
+ $exeDevice.typeEdit = -1;
+ $exeDevices.iDevice.gamification.helpers.arrayMove(
+ cards,
+ $exeDevice.numberCutCuestion,
+ active
+ );
+ $('#bfafENumCards').text(cards.length);
+ $('#bfafENumberCard').val(active + 1);
+ }
+
+ $exeDevice.active = active;
+ $exeDevice.showCard(active);
+ },
+
+ nextCard: function () {
+ if (!$exeDevice.validateCard()) return;
+ if ($exeDevice.active < $exeDevice.cardsGame.length - 1) {
+ $exeDevice.active++;
+ $exeDevice.showCard($exeDevice.active);
+ }
+ },
+
+ lastCard: function () {
+ if (!$exeDevice.validateCard()) return;
+ if ($exeDevice.active < $exeDevice.cardsGame.length - 1) {
+ $exeDevice.active = $exeDevice.cardsGame.length - 1;
+ $exeDevice.showCard($exeDevice.active);
+ }
+ },
+
+ previousCard: function () {
+ if (!$exeDevice.validateCard()) return;
+ if ($exeDevice.active > 0) {
+ $exeDevice.active--;
+ }
+ $exeDevice.showCard($exeDevice.active);
+ },
+
+ firstCard: function () {
+ if (!$exeDevice.validateCard()) return;
+ if ($exeDevice.active > 0) {
+ $exeDevice.active = 0;
+ $exeDevice.showCard($exeDevice.active);
+ }
+ },
+
+ showCard: function (i) {
+ let num = Math.max(0, Math.min(i, $exeDevice.cardsGame.length - 1)),
+ p = $exeDevice.cardsGame[num];
+
+ $('#bfafEURLImage').val(p.url);
+ $('#bfafEURLImageBack').val(p.urlBk);
+
+ $('#bfafENumberCard').val(num + 1);
+
+ $('#bfafEAuthor').val(p.author);
+ $('#bfafEAuthorBack').val(p.authorBk);
+
+ $('#bfafEAlt').val(p.alt);
+ $('#bfafEAltBack').val(p.altBk);
+
+ $('#bfafEText').val(p.eText);
+ $('#bfafETextBack').val(p.eTextBk);
+
+ $('#bfafEDescription').val(p.description);
+ $('#bfafEPosition').val(p.position);
+ $('#bfafEVertical').prop('checked', p.vertical);
+ $('#bfafEVertical')
+ .closest('.toggle-item')
+ .attr('aria-checked', !!p.vertical);
+
+ $exeDevice.showImage(0);
+ $exeDevice.showImage(1);
+ },
+
+ validateCard: function () {
+ const msgs = $exeDevice.msgs;
+ let p = {
+ url: $('#bfafEURLImage').val().trim(),
+ author: $('#bfafEAuthor').val(),
+ alt: $('#bfafEAlt').val(),
+ eText: $('#bfafEText').val(),
+ urlBk: $('#bfafEURLImageBack').val().trim(),
+ authorBk: $('#bfafEAuthorBack').val(),
+ altBk: $('#bfafEAltBack').val(),
+ eTextBk: $('#bfafETextBack').val(),
+ description: $('#bfafEDescription').val(),
+ position: $('#bfafEPosition').val(),
+ vertical: $('#bfafEVertical').is(':checked'),
+ };
+
+ let message = '';
+ p.position = p.position ?? 50;
+ p.vertical = p.vertical ?? false;
+ if (!p.url) {
+ message = msgs.msgCompleteData;
+ }
+ if (!p.urlBk) {
+ message = msgs.msgCompleteDataBack;
+ }
+ if (!p.description) {
+ message = msgs.msgDescription;
+ }
+
+ if (!message) {
+ $exeDevice.cardsGame[$exeDevice.active] = p;
+ return true;
+ } else {
+ $exeDevice.showMessage(message);
+ return false;
+ }
+ },
+
+ enableForm: function () {
+ $exeDevice.initCards();
+ $exeDevice.loadPreviousValues();
+ $exeDevice.addEvents();
+ $exeDevice.addEventCard();
+ },
+
+ addEventCard: function () {
+ $('#bfafEAuthorAlt, #bfafEAuthorAltBack').hide();
+
+ const loadAndPlayImage = (index) => $exeDevice.loadImage(index);
+
+ $('#bfafEURLImage').on('change', () => loadAndPlayImage(0));
+ $('#bfafEURLImageBack').on('change', () => loadAndPlayImage(1));
+
+ $('#bfafEPlayImage').on('click', (e) => {
+ e.preventDefault();
+ loadAndPlayImage(0);
+ });
+ $('#bfafEPlayImageBack').on('click', (e) => {
+ e.preventDefault();
+ loadAndPlayImage(1);
+ });
+
+ $('#bfafEShowMore').on('click', (e) => {
+ e.preventDefault();
+ $('#bfafEAuthorAlt').slideToggle();
+ });
+ $('#bfafEShowMoreBack').on('click', (e) => {
+ e.preventDefault();
+ $('#bfafEAuthorAltBack').slideToggle();
+ });
+
+ $('#bfafEText, #bfafETextBack').on('keyup', function () {
+ const textDiv = $(this).is('#bfafEText')
+ ? '#bfafETextDiv'
+ : '#bfafETextDivBack';
+ $(textDiv)
+ .html($(this).val())
+ .toggle($(this).val().trim().length > 0);
+ });
+ },
+
+ getDefaultCard: function () {
+ return {
+ id: '',
+ position: 50,
+ vertical: false,
+ url: '',
+ author: '',
+ alt: '',
+ eText: '',
+ urlBk: '',
+ authorBk: '',
+ altBk: '',
+ eTextBk: '',
+ };
+ },
+
+ loadPreviousValues: function () {
+ const originalHTML = this.idevicePreviousData;
+
+ if (originalHTML && Object.keys(originalHTML).length > 0) {
+ const wrapper = $('
').html(originalHTML),
+ json = $('.beforeafter-DataGame', wrapper).text(),
+ dataGame =
+ $exeDevices.iDevice.gamification.helpers.isJsonString(json),
+ cards = dataGame.cardsGame,
+ $imagesLink = $('.beforeafter-LinkImages', wrapper),
+ $imagesLinkBack = $('.beforeafter-LinkImagesBack', wrapper);
+
+ $imagesLink.each(function () {
+ const iq = parseInt($(this).text());
+ if (!isNaN(iq) && iq < cards.length) {
+ const flipcard = cards[iq];
+ flipcard.url =
+ $(this).attr('href').length < 4
+ ? ''
+ : $(this).attr('href');
+ }
+ });
+
+ $imagesLinkBack.each(function () {
+ const iq = parseInt($(this).text());
+ if (!isNaN(iq) && iq < cards.length) {
+ const flipcard = cards[iq];
+ flipcard.urlBk =
+ $(this).attr('href').length < 4
+ ? ''
+ : $(this).attr('href');
+ }
+ });
+
+ $exeDevice.updateFieldGame(dataGame);
+
+ let instructions = $('.beforeafter-instructions', wrapper);
+ if (instructions.length === 1) {
+ instructions = instructions.html() || '';
+ $('#eXeGameInstructions').val(instructions);
+ }
+
+ let textAfter = $('.beforeafter-extra-content', wrapper);
+ if (textAfter.length === 1) {
+ textAfter = textAfter.html() || '';
+ $('#eXeIdeviceTextAfter').val(textAfter);
+ }
+
+ $exeDevicesEdition.iDevice.gamification.common.setLanguageTabValues(
+ dataGame.msgs
+ );
+ $exeDevice.showCard(0);
+ }
+ },
+
+ save: function () {
+ if (!$exeDevice.validateCard()) return false;
+
+ const dataGame = $exeDevice.validateData();
+
+ if (!dataGame) return false;
+
+ const i18n = { ...this.ci18n };
+
+ Object.keys(this.ci18n).forEach((i) => {
+ const fVal = $('#ci18n_' + i).val();
+ if (fVal) i18n[i] = fVal;
+ });
+
+ dataGame.msgs = i18n;
+ const json = JSON.stringify(dataGame);
+ const cards = dataGame.cardsGame;
+
+ let divContent = dataGame.instructions
+ ? `
`
+ : '';
+ const linksMedias = $exeDevice.createlinksIMedias(cards);
+ let html = `
`;
+ return html;
+ },
+
+ validateAlt: function () {
+ if (!$exeDevice.checkAltImage || $('#beforeafter-EAlt').val() !== '')
+ return true;
+
+ eXe.app.confirm(
+ $exeDevice.msgs.msgTitleAltImageWarning,
+ $exeDevice.msgs.msgAltImageWarning,
+ () => {
+ $exeDevice.checkAltImage = false;
+ document
+ .getElementsByClassName('button-save-idevice')[0]
+ .click();
+ }
+ );
+ return false;
+ },
+
+ createlinksIMedias: function (cardsGame) {
+ return cardsGame
+ .map((p, i) => {
+ const properties = [
+ { prop: 'url', className: 'beforeafter-LinkImages' },
+ { prop: 'urlBk', className: 'beforeafter-LinkImagesBack' },
+ ];
+ return properties
+ .map(({ prop, className }) => {
+ const val = p[prop];
+ if (val && val.indexOf('http') !== 0) {
+ return `
`;
+ }
+ return '';
+ })
+ .join('');
+ })
+ .join('');
+ },
+
+ showMessage: function (msg) {
+ eXe.app.alert(msg);
+ },
+
+ getIdeviceID: function () {
+ const ideviceid =
+ $('#beforeAfterQIdeviceForm')
+ .closest(`div.idevice_node.${$exeDevice.classIdevice}`)
+ .attr('id') || '';
+ return ideviceid;
+ },
+
+ validateData: function () {
+ const clear = $exeDevice.removeTags,
+ instructions = tinyMCE.get('eXeGameInstructions').getContent(),
+ textAfter = tinyMCE.get('eXeIdeviceTextAfter').getContent(),
+ author = $('#bfafEAuthory').val(),
+ cardsGame = $exeDevice.cardsGame,
+ id = $exeDevice.getIdeviceID(),
+ itinerary =
+ $exeDevicesEdition.iDevice.gamification.itinerary.getValues(),
+ scorm = $exeDevicesEdition.iDevice.gamification.scorm.getValues(),
+ evaluation = $('#bfafEEvaluation').is(':checked'),
+ evaluationID = $('#bfafEEvaluationID').val();
+
+ if (evaluation && evaluationID.length < 5) {
+ eXe.app.alert($exeDevice.msgs.msgIDLenght);
+ return false;
+ }
+ if (!itinerary) return;
+ return {
+ typeGame: 'BeforeAfter',
+ author,
+ instructions,
+ isScorm: scorm.isScorm,
+ textButtonScorm: scorm.textButtonScorm,
+ repeatActivity: true,
+ itinerary,
+ weighted: scorm.weighted ?? 100,
+ cardsGame,
+ textAfter: escape(textAfter),
+ version: $exeDevice.version,
+ evaluation,
+ evaluationID,
+ id,
+ };
+ },
+
+ showImage: function (type) {
+ const suffix = type == 0 ? '' : 'Back',
+ $image = $(`#bfafEImage${suffix}`),
+ $nimage = $(`#bfafENoImage${suffix}`),
+ alt = $(`#bfafEAlt${suffix}`).val(),
+ url = $(`#bfafEURLImage${suffix}`).val();
+
+ $image.hide();
+ $image.attr('alt', alt);
+ $nimage.show();
+
+ $image
+ .prop('src', url)
+ .on('load', function () {
+ if (
+ this.complete &&
+ typeof this.naturalWidth !== 'undefined' &&
+ this.naturalWidth !== 0
+ ) {
+ const mData = $exeDevice.placeImageWindows(
+ this,
+ this.naturalWidth,
+ this.naturalHeight
+ );
+ $exeDevice.drawImage(this, mData);
+ $image.show();
+ $nimage.hide();
+ return true;
+ }
+ return false;
+ })
+ .on('error', function () {
+ return false;
+ });
+ },
+
+ drawImage: function (image, mData) {
+ $(image).css({
+ position: 'absolute',
+ left: `${mData.x}px`,
+ top: `${mData.y}px`,
+ width: `${mData.w}px`,
+ height: `${mData.h}px`,
+ });
+ },
+
+ addEvents: function () {
+ $('#bfafEPasteC').hide();
+
+ $('#bfafEAddC').on('click', (e) => {
+ $exeDevice.addCard(true);
+ });
+
+ $('#bfafEDeleteC').on('click', (e) => {
+ e.preventDefault();
+ $exeDevice.removeCard();
+ });
+
+ $('#bfafECopyC').on('click', (e) => {
+ e.preventDefault();
+ $exeDevice.copyCard();
+ });
+
+ $('#bfafECutC').on('click', (e) => {
+ e.preventDefault();
+ $exeDevice.cutCard();
+ });
+
+ $('#bfafEPasteC').on('click', (e) => {
+ $exeDevice.pasteCard();
+ });
+
+ $('#bfafEFirstC, #bfafEPreviousC, #bfafENextC, #bfafELastC').on(
+ 'click',
+ (e) => {
+ e.preventDefault();
+ const actions = {
+ bfafEFirstC: 'firstCard',
+ bfafEPreviousC: 'previousCard',
+ bfafENextC: 'nextCard',
+ bfafELastC: 'lastCard',
+ };
+ $exeDevice[actions[e.currentTarget.id]]();
+ }
+ );
+
+ $('#bfafEReverseFaces').on('click', (e) => {
+ e.preventDefault();
+ $exeDevice.reverseFaces();
+ });
+
+ $('#bfafEReverseCard').on('click', (e) => {
+ e.preventDefault();
+ $exeDevice.reverseCard();
+ });
+
+ // Ayuda evaluación
+ $('#bfafEEvaluationHelpLnk').on('click', function () {
+ $('#bfafEEvaluationHelp').toggle();
+ return false;
+ });
+
+ $('#beforeAfterQIdeviceForm').on(
+ 'change',
+ '.toggle-input',
+ function () {
+ const $input = $(this);
+ const checked = $input.is(':checked');
+ const $item = $input.closest('.toggle-item');
+ $item.attr('aria-checked', checked);
+ const target = $item.data('target');
+ if (target) {
+ const $targetEl = $('#' + target);
+ if ($targetEl.length) {
+ $targetEl.toggle(checked);
+ }
+ }
+ if (this.id === 'bfafEEvaluation') {
+ $('#bfafEEvaluationID').prop('disabled', !checked);
+ } else if (this.id === 'bfafEVertical') {
+ if ($exeDevice.cardsGame[$exeDevice.active]) {
+ $exeDevice.cardsGame[$exeDevice.active].vertical =
+ checked;
+ }
+ }
+ }
+ );
+
+ (function initToggleStates() {
+ const evalChecked = $('#bfafEEvaluation').is(':checked');
+ $('#bfafEEvaluation')
+ .closest('.toggle-item')
+ .attr('aria-checked', evalChecked);
+ $('#bfafEEvaluationIDWrapper').toggle(evalChecked);
+ const vertChecked = $('#bfafEVertical').is(':checked');
+ $('#bfafEVertical')
+ .closest('.toggle-item')
+ .attr('aria-checked', vertChecked);
+ })();
+
+ $exeDevicesEdition.iDevice.gamification.itinerary.addEvents();
+ //eXe 3.0 Dismissible messages
+ $('.exe-block-dismissible .exe-block-close').click(function () {
+ $(this).parent().fadeOut();
+ return false;
+ });
+ },
+
+ reverseFaces: function () {
+ if (!$exeDevice.validateCard()) return;
+
+ const properties = ['url', 'author', 'alt', 'eText'];
+ $exeDevice.cardsGame.forEach((p) => {
+ properties.forEach((prop) => {
+ const temp = p[prop];
+ p[prop] = p[`${prop}Bk`];
+ p[`${prop}Bk`] = temp;
+ });
+ });
+ $exeDevice.showCard($exeDevice.active);
+ },
+
+ reverseCard: function () {
+ if (!$exeDevice.validateCard()) return;
+
+ const p = $exeDevice.cardsGame[$exeDevice.active],
+ properties = ['url', 'author', 'alt', 'eText'];
+ properties.forEach((prop) => {
+ const temp = p[prop];
+ p[prop] = p[`${prop}Bk`];
+ p[`${prop}Bk`] = temp;
+ });
+ $exeDevice.showCard($exeDevice.active);
+ },
+
+ loadImage: function (type) {
+ const validExt = ['jpg', 'png', 'gif', 'jpeg', 'svg', 'webp'],
+ url =
+ type === 0
+ ? $('#bfafEURLImage').val()
+ : $('#bfafEURLImageBack').val(),
+ ext = url.split('.').pop().toLowerCase();
+
+ if (url.length < 3) {
+ return false;
+ }
+ if (url.startsWith('files') && !validExt.includes(ext)) {
+ $exeDevice.showMessage(
+ `${_('Supported formats')}: jpg, jpeg, gif, png, svg, webp`
+ );
+ return false;
+ }
+ $exeDevice.showImage(type);
+ },
+
+ updateFieldGame: function (game) {
+ $exeDevice.active = 0;
+ $exeDevice.id = $exeDevice.getIdeviceID();
+ $('#bfafEAuthory').val(game.author);
+ game.evaluation =
+ typeof game.evaluation !== 'undefined' ? game.evaluation : false;
+ game.evaluationID =
+ typeof game.evaluationID !== 'undefined' ? game.evaluationID : '';
+ game.weighted =
+ typeof game.weighted !== 'undefined' ? game.weighted : 100;
+ game.position =
+ typeof game.position !== 'undefined' ? parseInt(game.position) : 50;
+ $exeDevice.cardsGame = game.cardsGame;
+ $exeDevicesEdition.iDevice.gamification.scorm.setValues(
+ game.isScorm,
+ game.textButtonScorm,
+ game.repeatActivity,
+ game.weighted
+ );
+ $('#bfafEEvaluation').prop('checked', game.evaluation);
+ $('#bfafEEvaluationID').val(game.evaluationID);
+ $('#bfafEEvaluationID').prop('disabled', !game.evaluation);
+ $('#bfafEPosition').val(game.position);
+ $exeDevicesEdition.iDevice.gamification.itinerary.setValues(
+ game.itinerary
+ );
+ },
+
+ placeImageWindows: function (image, naturalWidth, naturalHeight) {
+ const $parent = $(image).parent(),
+ wDiv = $parent.width() || 1,
+ hDiv = $parent.height() || 1,
+ varW = naturalWidth / wDiv,
+ varH = naturalHeight / hDiv;
+
+ let wImage = wDiv,
+ hImage = hDiv,
+ xImagen = 0,
+ yImagen = 0;
+
+ if (varW > varH) {
+ hImage = Math.round(naturalHeight / varW);
+ yImagen = Math.round((hDiv - hImage) / 2);
+ } else {
+ wImage = Math.round(naturalWidth / varH);
+ xImagen = Math.round((wDiv - wImage) / 2);
+ }
+
+ return { w: wImage, h: hImage, x: xImagen, y: yImagen };
+ },
+
+ removeTags: function (str) {
+ return $('
').html(str).text();
+ },
+};
diff --git a/vendor/exelearning/export-resources/idevices/beforeafter/edition/quextEIMore.png b/vendor/exelearning/export-resources/idevices/beforeafter/edition/quextEIMore.png
new file mode 100644
index 0000000..3ee9dff
Binary files /dev/null and b/vendor/exelearning/export-resources/idevices/beforeafter/edition/quextEIMore.png differ
diff --git a/vendor/exelearning/export-resources/idevices/beforeafter/edition/quextIEAdd.png b/vendor/exelearning/export-resources/idevices/beforeafter/edition/quextIEAdd.png
new file mode 100644
index 0000000..7306026
Binary files /dev/null and b/vendor/exelearning/export-resources/idevices/beforeafter/edition/quextIEAdd.png differ
diff --git a/vendor/exelearning/export-resources/idevices/beforeafter/edition/quextIECopy.png b/vendor/exelearning/export-resources/idevices/beforeafter/edition/quextIECopy.png
new file mode 100644
index 0000000..57dab4f
Binary files /dev/null and b/vendor/exelearning/export-resources/idevices/beforeafter/edition/quextIECopy.png differ
diff --git a/vendor/exelearning/export-resources/idevices/beforeafter/edition/quextIECoverCards.png b/vendor/exelearning/export-resources/idevices/beforeafter/edition/quextIECoverCards.png
new file mode 100644
index 0000000..688b330
Binary files /dev/null and b/vendor/exelearning/export-resources/idevices/beforeafter/edition/quextIECoverCards.png differ
diff --git a/vendor/exelearning/export-resources/idevices/beforeafter/edition/quextIECursor.gif b/vendor/exelearning/export-resources/idevices/beforeafter/edition/quextIECursor.gif
new file mode 100644
index 0000000..cc13b8e
Binary files /dev/null and b/vendor/exelearning/export-resources/idevices/beforeafter/edition/quextIECursor.gif differ
diff --git a/vendor/exelearning/export-resources/idevices/beforeafter/edition/quextIECut.png b/vendor/exelearning/export-resources/idevices/beforeafter/edition/quextIECut.png
new file mode 100644
index 0000000..4af1b42
Binary files /dev/null and b/vendor/exelearning/export-resources/idevices/beforeafter/edition/quextIECut.png differ
diff --git a/vendor/exelearning/export-resources/idevices/beforeafter/edition/quextIEDelete.png b/vendor/exelearning/export-resources/idevices/beforeafter/edition/quextIEDelete.png
new file mode 100644
index 0000000..17346f8
Binary files /dev/null and b/vendor/exelearning/export-resources/idevices/beforeafter/edition/quextIEDelete.png differ
diff --git a/vendor/exelearning/export-resources/idevices/beforeafter/edition/quextIEError.png b/vendor/exelearning/export-resources/idevices/beforeafter/edition/quextIEError.png
new file mode 100644
index 0000000..d4c6f30
Binary files /dev/null and b/vendor/exelearning/export-resources/idevices/beforeafter/edition/quextIEError.png differ
diff --git a/vendor/exelearning/export-resources/idevices/beforeafter/edition/quextIEFirst.png b/vendor/exelearning/export-resources/idevices/beforeafter/edition/quextIEFirst.png
new file mode 100644
index 0000000..9862605
Binary files /dev/null and b/vendor/exelearning/export-resources/idevices/beforeafter/edition/quextIEFirst.png differ
diff --git a/vendor/exelearning/export-resources/idevices/beforeafter/edition/quextIEHelp.gif b/vendor/exelearning/export-resources/idevices/beforeafter/edition/quextIEHelp.gif
new file mode 100644
index 0000000..8510195
Binary files /dev/null and b/vendor/exelearning/export-resources/idevices/beforeafter/edition/quextIEHelp.gif differ
diff --git a/vendor/exelearning/export-resources/idevices/beforeafter/edition/quextIEHelp.png b/vendor/exelearning/export-resources/idevices/beforeafter/edition/quextIEHelp.png
new file mode 100644
index 0000000..a6475b4
Binary files /dev/null and b/vendor/exelearning/export-resources/idevices/beforeafter/edition/quextIEHelp.png differ
diff --git a/vendor/exelearning/export-resources/idevices/beforeafter/edition/quextIEHit.png b/vendor/exelearning/export-resources/idevices/beforeafter/edition/quextIEHit.png
new file mode 100644
index 0000000..99038ff
Binary files /dev/null and b/vendor/exelearning/export-resources/idevices/beforeafter/edition/quextIEHit.png differ
diff --git a/vendor/exelearning/export-resources/idevices/beforeafter/edition/quextIEImage.png b/vendor/exelearning/export-resources/idevices/beforeafter/edition/quextIEImage.png
new file mode 100644
index 0000000..e93769c
Binary files /dev/null and b/vendor/exelearning/export-resources/idevices/beforeafter/edition/quextIEImage.png differ
diff --git a/vendor/exelearning/export-resources/idevices/beforeafter/edition/quextIELast.png b/vendor/exelearning/export-resources/idevices/beforeafter/edition/quextIELast.png
new file mode 100644
index 0000000..2778d88
Binary files /dev/null and b/vendor/exelearning/export-resources/idevices/beforeafter/edition/quextIELast.png differ
diff --git a/vendor/exelearning/export-resources/idevices/beforeafter/edition/quextIENext.png b/vendor/exelearning/export-resources/idevices/beforeafter/edition/quextIENext.png
new file mode 100644
index 0000000..2ea0306
Binary files /dev/null and b/vendor/exelearning/export-resources/idevices/beforeafter/edition/quextIENext.png differ
diff --git a/vendor/exelearning/export-resources/idevices/beforeafter/edition/quextIENoImageVideo.png b/vendor/exelearning/export-resources/idevices/beforeafter/edition/quextIENoImageVideo.png
new file mode 100644
index 0000000..2b426c8
Binary files /dev/null and b/vendor/exelearning/export-resources/idevices/beforeafter/edition/quextIENoImageVideo.png differ
diff --git a/vendor/exelearning/export-resources/idevices/beforeafter/edition/quextIENoVideo.png b/vendor/exelearning/export-resources/idevices/beforeafter/edition/quextIENoVideo.png
new file mode 100644
index 0000000..0941049
Binary files /dev/null and b/vendor/exelearning/export-resources/idevices/beforeafter/edition/quextIENoVideo.png differ
diff --git a/vendor/exelearning/export-resources/idevices/beforeafter/edition/quextIENumber.png b/vendor/exelearning/export-resources/idevices/beforeafter/edition/quextIENumber.png
new file mode 100644
index 0000000..11f5fab
Binary files /dev/null and b/vendor/exelearning/export-resources/idevices/beforeafter/edition/quextIENumber.png differ
diff --git a/vendor/exelearning/export-resources/idevices/beforeafter/edition/quextIEPaste.png b/vendor/exelearning/export-resources/idevices/beforeafter/edition/quextIEPaste.png
new file mode 100644
index 0000000..f81506b
Binary files /dev/null and b/vendor/exelearning/export-resources/idevices/beforeafter/edition/quextIEPaste.png differ
diff --git a/vendor/exelearning/export-resources/idevices/beforeafter/edition/quextIEPlay.png b/vendor/exelearning/export-resources/idevices/beforeafter/edition/quextIEPlay.png
new file mode 100644
index 0000000..c321493
Binary files /dev/null and b/vendor/exelearning/export-resources/idevices/beforeafter/edition/quextIEPlay.png differ
diff --git a/vendor/exelearning/export-resources/idevices/beforeafter/edition/quextIEPrev.png b/vendor/exelearning/export-resources/idevices/beforeafter/edition/quextIEPrev.png
new file mode 100644
index 0000000..8beaa8f
Binary files /dev/null and b/vendor/exelearning/export-resources/idevices/beforeafter/edition/quextIEPrev.png differ
diff --git a/vendor/exelearning/export-resources/idevices/beforeafter/export/beforeafter-icon.png b/vendor/exelearning/export-resources/idevices/beforeafter/export/beforeafter-icon.png
new file mode 100644
index 0000000..a310e64
Binary files /dev/null and b/vendor/exelearning/export-resources/idevices/beforeafter/export/beforeafter-icon.png differ
diff --git a/vendor/exelearning/export-resources/idevices/beforeafter/export/beforeafter.css b/vendor/exelearning/export-resources/idevices/beforeafter/export/beforeafter.css
new file mode 100644
index 0000000..ce9b6ea
--- /dev/null
+++ b/vendor/exelearning/export-resources/idevices/beforeafter/export/beforeafter.css
@@ -0,0 +1,639 @@
+.sr-av {
+ position: absolute;
+ width: 1px;
+ height: 1px;
+ margin: -1px;
+ padding: 0;
+ overflow: hidden;
+ clip: rect(0, 0, 0, 0);
+ white-space: nowrap;
+ border: 0;
+}
+
+.BFAFP-ContainerBA {
+ position: relative;
+ margin: 0 auto;
+}
+
+.BFAFP-CustomBtn {
+ background: transparent;
+ border: none;
+ padding: 0;
+ cursor: pointer;
+ width: 42px;
+ width: 42px;
+}
+
+.BFAFP-CustomBtn img {
+ width: 100%;
+ width: 100%;
+}
+
+.BFAFP-Overlay img{
+ max-width: none !important;
+}
+
+.BFAFP-TitleAfter, .BFAFP-TitleAfterV, .BFAFP-TitleBefore, .BFAFP-TitleBeforeV {
+ position: absolute;
+ background-color: black;
+ color: white;
+ border: 1px solid #333;
+ width: 150px;
+ min-height: 30px;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ text-align: center;
+ font-size: 0.8em;
+ border-radius: 4px;
+ padding: 5px 5px;
+}
+
+.BFAFP-TitleAfter {
+ left: 10px;
+ bottom: 10px;
+}
+.BFAFP-TitleBefore {
+ right: 10px;
+ bottom: 10px;
+}
+
+.BFAFP-TitleAfterV {
+ left: 10px;
+ top: 10px;
+}
+
+.BFAFP-TitleBeforeV {
+ left: 10px;
+ bottom: 10px;
+}
+
+.BFAFP-ImageBefore {
+ display: block;
+ background-color: #fff;
+}
+
+.BFAFP-Overlay {
+ position: absolute;
+ top: 0;
+ left: 0;
+ overflow: hidden;
+ z-index: 2;
+ transition: width 0.1s ease-out;
+}
+
+/* Horizontal (por defecto) */
+.BFAFP-ContainerBA:not([data-orientation="vertical"]) .BFAFP-Overlay {
+ width: 50%;
+ height: 100%;
+}
+
+/* Vertical */
+.BFAFP-ContainerBA[data-orientation="vertical"] .BFAFP-Overlay {
+ width: 100%;
+ height: 50%;
+}
+
+.BFAFP-Overlay img {
+ display: block;
+ background-color: #fff;
+}
+
+
+
+.BFAFP-MainContainer {
+ margin: 1em auto;
+ padding: 0;
+ width: 100%;
+ height: auto;
+ position: relative;
+ min-height: 100px;
+}
+
+.BFAFP-MainContainer * {
+ box-sizing: border-box;
+}
+
+.BFAFP-MainContainer p {
+ margin: 0 !important;
+ padding: 0 !important;
+}
+
+.BFAFP-instructions {
+ margin: 0.3em auto;
+ width: 100%;
+ overflow: auto;
+}
+
+.BFAFP-GameMinimize {
+ margin: 1em auto;
+ width: 100%;
+}
+
+.BFAFP-LinkMaximize {
+ align-items: center;
+ display: flex;
+ justify-content: center;
+}
+
+.BFAFP-IconMinimize {
+ height: 2em;
+ margin-right: 0.5em;
+ width: 2em;
+}
+
+.BFAFP-GameContainer {
+ margin: 0 auto;
+ padding: 2em 0.3em 0 0.3em;
+ position: relative;
+ max-width: 1650px;
+ width: 100%;
+ height: auto;
+ overflow: visible;
+}
+
+.BFAFP-Image {
+ margin: 0;
+ max-width: 100%;
+ max-height: 100%;
+ height: 100%;
+ width: 100%;
+ margin: auto;
+ object-fit: contain;
+ display: block;
+}
+
+.BFAFP-EText {
+ border: none;
+ width: 70%;
+ height: 100%;
+ padding: 10px;
+ overflow: hidden;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ -webkit-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
+}
+
+.BFAFP-Multimedia {
+ background-color: transparent;
+ width: 100%;
+ max-width: 800px;
+ margin: 1em auto;
+ aspect-ratio: 16 / 9;
+}
+
+.BFAFP-ButtonsBar {
+ width: 100%;
+ max-width: 900px;
+ margin: 1em auto;
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+}
+
+.BFAFP-NumberInfo {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ font-size: 1.2em;
+}
+
+.BFAFP-Author {
+ position: absolute;
+ width: 1.2em;
+ height: 1.2em;
+ z-index: 4;
+ display: block;
+ bottom: 1px;
+}
+
+.BFAFP-AuthorWord {
+ left: 1px;
+}
+
+.BFAFP-AuthorDef {
+ right: 1px;
+}
+
+.BFAFP-Author img {
+ width: 100%;
+ height: 100%;
+}
+
+.BFAFP-Cover {
+ width: 100%;
+ height: 95%;
+ position: absolute;
+ top: 1%;
+ left: 0;
+ display: flex;
+ justify-content: flex-start;
+ align-items: center;
+ flex-direction: column;
+ z-index: 20;
+ background-color: rgb(255, 255, 255, 0.1)
+}
+
+.BFAFP-ClueBotton {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ margin: 0.6em auto;
+}
+
+.BFAFP-Information,
+.BFAFP-Buttons {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+}
+
+.BFAFP-Buttons {
+ gap: 10px;
+ display: none;
+}
+
+.BFAFP-Information a,
+.BFAFP-Buttons a {
+ font-size: 1.1em;
+ display: inline-block;
+ text-align: center;
+ text-decoration: none;
+}
+
+.BFAFP-Message {
+ width: 100%;
+ text-align: center;
+ font-size: 1.1em;
+ min-height: 1.5em;
+ display: none;
+}
+
+.BFAFP-AuthorGame {
+ margin: 0.5em auto;
+ width: 100%;
+ text-align: center;
+ font-size: 0.9em;
+ display: none;
+}
+
+.BFAFP-CodeAccessDiv {
+ background-color: white;
+ width: 50%;
+ max-width: 400px;
+ border: 1px solid #ddd;
+ border-radius: 0.6em;
+ box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.20), 0 6px 20px 0 rgba(0, 0, 0, 0.19);
+ padding: 1.5em;
+ margin-top: 1em;
+}
+
+.BFAFP-MessageCodeAccessE {
+ text-align: center;
+ vertical-align: middle;
+ width: 100%;
+ margin: 0.5em;
+}
+
+.BFAFP-DataCodeAccessE {
+ align-items: center;
+ display: flex;
+ justify-content: center;
+ margin: 0.7em auto 0 auto;
+ width: 100%;
+}
+
+.BFAFP-CodeAccessE {
+ margin: 0 .3em;
+ width: 100%;
+ text-align: center;
+ max-width: 350px;
+}
+
+.BFAFP-MainContainer .exeQuextIcons-Submit {
+ height: 1.7em;
+ width: 1.7em;
+}
+
+.BFAFP-DivInstructions {
+ margin: 1em 0 0 0;
+ text-align: center;
+ width: 95%;
+}
+
+.BFAFP-FullLinkImage .exeQuextIcons {
+ margin: 0;
+ width: 18px;
+ height: 18px;
+}
+
+.beforeafter-extra-content {
+ margin-top: 1.7em;
+}
+
+
+
+.BFAFP-Activo {
+ cursor: pointer;
+ -webkit-transition: transform 0.3s, -webkit-filter 0.3s;
+ transition: transform 0.3s, filter 0.3s;
+ -webkit-filter: drop-shadow(0 2px 4px rgba(0, 0, 0, 0.2));
+ filter: drop-shadow(0 2px 4px rgba(0, 0, 0, 0.2));
+}
+
+
+.BFAFP-Activo:hover {
+ -moz-transform: scale(1.1);
+ -ms-transform: scale(1.1);
+ -o-transform: scale(1.1);
+ -webkit-transform: scale(1.1);
+ transform: scale(1.1);
+ -webkit-filter: drop-shadow(0 4px 8px rgba(0, 0, 0, 0.3));
+ filter: drop-shadow(0 4px 8px rgba(0, 0, 0, 0.3));
+}
+
+.Games-FullScreenImage {
+ max-width: 100%;
+ max-height: 100%;
+ object-fit: contain;
+}
+
+.noselect {
+ -webkit-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
+}
+
+.BFAFP-MainContainer .exeQuextIcons {
+ background-size: 100% 100%;
+ height: 1.4em;
+ margin-right: 0.3em;
+ width: 1.4em;
+}
+
+.BFAFP-GameContainer:-webkit-full-screen {
+ background-color: white;
+ height: 100vh;
+ width: 100%;
+}
+
+.BFAFP-GameContainer:-moz-full-screen {
+ background-color: white;
+ height: 100vh;
+ width: 100%;
+ padding-top: 3px;
+ overflow-y: auto;
+}
+
+.BFAFP-GameContainer:-ms-full-screen {
+ background-color: white;
+ height: 100vh;
+ width: 100%;
+ padding-top: 3px;
+ overflow-y: auto;
+}
+
+.BFAFP-GameContainer:-o-full-screen {
+ background-color: white;
+ height: 100vh;
+ width: 100%;
+ padding-top: 3px;
+ overflow-y: auto;
+}
+
+.BFAFP-GameContainer:fullscreen {
+ background-color: white;
+ height: 100vh;
+ width: 100%;
+ padding-top: 3px;
+ overflow-y: auto;
+}
+
+.BFAFP-Cover .exeQuextIcons-Submit {
+ height: 1.7em;
+ width: 1.7em;
+}
+.BFAFP-MainContainer .exeQuextIcons-Submit {
+ background: url(exequextreply.png) no-repeat;
+ background-size: cover;
+ cursor: pointer;
+}
+
+.BFAFP-GameContainer .exeQuextIcons-FullScreen {
+ background-image: url(exequextfull.svg);
+ background-size: 100% 100%;
+}
+
+div:fullscreen .exeQuextIcons-FullScreen {
+ background-image: url(exequextfull.svg);
+ background-size: 100% 100%;
+}
+
+div:fullscreen .BFAFP-Multimedia {
+ width: 100%;
+ max-width: 1200px;
+}
+
+div:fullscreen .BFAFP-Message {
+ font-weight: 1.1em;
+}
+
+.BFAFP-GameContainer:-webkit-full-screen {
+ background-color: white;
+ height: 100vh;
+ width: 100%;
+ max-width: 100vw;
+ padding: 0.6em 0.6em 1em 0.6em;
+ overflow-y: auto;
+}
+
+.BFAFP-GameContainer:-moz-full-screen {
+ background-color: white;
+ height: 100vh;
+ width: 100%;
+ max-width: 100vw;
+ padding: 0.6em 0.6em 1em 0.6em;
+ overflow-y: auto;
+ padding-top: 0;
+}
+
+.BFAFP-GameContainer:-ms-full-screen {
+ background-color: white;
+ height: 100vh;
+ width: 100%;
+ max-width: 100vw;
+ padding: 0.6em 0.6em 1em 0.6em;
+ overflow-y: auto;
+ padding-top: 0;
+}
+
+.BFAFP-GameContainer:fullscreen {
+ background-color: white;
+ height: 100vh;
+ width: 100%;
+ max-width: 100vw;
+ padding: 0.6em 0.6em 1em 0.6em;
+ overflow-y: auto;
+ padding-top: 0;
+}
+
+.BFAFP-Container {
+ display: flex;
+ justify-content: center;
+ align-items: flex-start;
+ gap: 2em;
+ width: 100%;
+}
+
+.BFAFP-ContainerGame {
+ padding: 0;
+ width: 100%;
+ display: flex;
+ justify-content: center;
+ align-items: flex-start;
+ gap: 20%;
+ height: auto;
+ position: relative;
+ background-color: transparent;
+}
+
+.BFAFP-LinkFullScreen {
+ position: absolute;
+ top: 5px;
+ right: 5px;
+ z-index: 4;
+}
+
+.BFAFP-Slider {
+ position: absolute;
+ z-index: 3;
+ transition: all 0.1s ease-out;
+ opacity: 0.1;
+
+}
+
+
+.BFAFP-ContainerBA:not([data-orientation="vertical"]) .BFAFP-Slider {
+ top: 0;
+ left: calc(50% - 12px);
+ width: 24px;
+ height: 100%;
+ cursor: ew-resize;
+}
+
+
+.BFAFP-ContainerBA:not([data-orientation="vertical"]) .BFAFP-Overlay {
+ width: 50%;
+ height: 100%;
+}
+
+.BFAFP-ContainerBA[data-orientation="vertical"] {
+ display: block;
+}
+
+.BFAFP-ContainerBA[data-orientation="vertical"] .BFAFP-Slider {
+ left: 0;
+ top: calc(50% - 12px);
+ width: 100%;
+ height: 24px;
+ cursor: ns-resize;
+}
+
+
+.BFAFP-ContainerBA[data-orientation="vertical"] .BFAFP-Overlay {
+ width: 100%;
+ height: 50%;
+}
+
+
+@media screen and (max-width:650px) {
+ .BFAFP-LinkFullScreen {
+ display: none;
+ }
+
+ .BFAFP-ContainerGame {
+ gap: 80px;
+ font-size: 0.9em;
+ }
+
+ .BFAFP-MainContainer {
+ font-size: 0.9rem;
+ }
+
+ .BFAFP-LinkMinimize {
+ display: none;
+ }
+
+ .BFAFP-DataCodeAccessE label {
+ display: none;
+ }
+
+ .BFAFP-GameContainer .exeQuextIcons-Submit {
+ height: 2em;
+ width: 2em;
+ }
+
+
+
+ .BFAFP-CodeAccessDiv,
+ .BFAFP-ShowClue {
+ width: 90%;
+ }
+
+ div:fullscreen .BFAFP-Message {
+ font-size: 1em;
+ }
+
+ .BFAFP-ContainerGame {
+ gap: 80px;
+ font-size: 0.9rem;
+ }
+
+ .BFAFP-Information a,
+ .BFAFP-Information p,
+ .BFAFP-Buttons a {
+ font-size: 1em;
+ }
+
+ .BFAFP-Message {
+ min-height: 1.3em;
+ }
+
+}
+
+
+@media screen and (max-width:425px) {
+
+ .BFAFP-MainContainer {
+ font-size: 0.8rem;
+ }
+
+ .BFAFP-instructions p {
+ margin: 0 auto;
+ }
+
+ .BFAFP-Message {
+ min-height: 1em;
+ }
+
+ .BFAFP-ContainerGame {
+ gap: 70px;
+ font-size: 0.8rem;
+ }
+}
+
+@media screen and (max-width:375px) {
+ .BFAFP-MainContainer {
+ font-size: 0.7rem;
+ }
+
+ .BFAFP-ContainerGame {
+ gap: 50px;
+ font-size: 0.7rem;
+ }
+
+}
\ No newline at end of file
diff --git a/vendor/exelearning/export-resources/idevices/beforeafter/export/beforeafter.js b/vendor/exelearning/export-resources/idevices/beforeafter/export/beforeafter.js
new file mode 100644
index 0000000..a1c2519
--- /dev/null
+++ b/vendor/exelearning/export-resources/idevices/beforeafter/export/beforeafter.js
@@ -0,0 +1,760 @@
+/**
+ * Relaciona activity (Export)
+ *
+ * Released under Attribution-ShareAlike 4.0 International License.
+ * Author: Manuel Narváez Martínez
+ * License: http://creativecommons.org/licenses/by-sa/4.0/
+ *
+ */
+var $eXeBeforeAfter = {
+ idevicePath: '',
+ borderColors: $exeDevices.iDevice.gamification.colors.borderColors,
+ colors: $exeDevices.iDevice.gamification.colors.backColor,
+ options: [],
+ hasSCORMbutton: false,
+ isInExe: false,
+ userName: '',
+ previousScore: '',
+ initialScore: '',
+ version: 3,
+ scormAPIwrapper: 'libs/SCORM_API_wrapper.js',
+ scormFunctions: 'libs/SCOFunctions.js',
+ mScorm: null,
+ init: function () {
+ $exeDevices.iDevice.gamification.initGame(
+ this,
+ 'Before/After',
+ 'beforeafter',
+ 'beforeafter-IDevice'
+ );
+ },
+
+ enable: function () {
+ $eXeBeforeAfter.loadGame();
+ },
+
+ loadGame: function () {
+ $eXeBeforeAfter.options = [];
+
+ $eXeBeforeAfter.activities.each(function (i) {
+ const dl = $('.beforeafter-DataGame', this);
+ const mOption = $eXeBeforeAfter.loadDataGame(dl, this);
+
+ mOption.scorerp = 0;
+ mOption.idevicePath = $eXeBeforeAfter.idevicePath;
+ mOption.main = 'bfafMainContainer-' + i;
+ mOption.idevice = 'beforeafter-IDevice';
+
+ $eXeBeforeAfter.options.push(mOption);
+
+ const bfaf = $eXeBeforeAfter.createInterfaceCards(i);
+
+ dl.before(bfaf).remove();
+ $('#bfafGameMinimize-' + i).hide();
+ $('#bfafGameContainer-' + i).hide();
+ $('#bfafCubierta-' + i).hide();
+ if (mOption.showMinimize) {
+ $('#bfafGameMinimize-' + i)
+ .css({ cursor: 'pointer' })
+ .show();
+ } else {
+ $('#bfafGameContainer-' + i).show();
+ }
+ $eXeBeforeAfter.addEvents(i);
+ });
+
+ let node = document.querySelector('.page-content');
+ if (this.isInExe) {
+ node = document.getElementById('node-content');
+ }
+ if (node)
+ $exeDevices.iDevice.gamification.observers.observeResize(
+ $eXeBeforeAfter,
+ node
+ );
+
+ const html = $('.beforeafter-IDevice').html();
+ if ($exeDevices.iDevice.gamification.math.hasLatex(html)) {
+ $exeDevices.iDevice.gamification.math.updateLatex(
+ '.beforeafter-IDevice'
+ );
+ }
+ },
+
+ loadDataGame: function (data, sthis) {
+ const json = data.text(),
+ mOptions =
+ $exeDevices.iDevice.gamification.helpers.isJsonString(json),
+ $imagesLink = $('.beforeafter-LinkImages', sthis),
+ $imagesLinkBack = $('.beforeafter-LinkImagesBack', sthis);
+
+ mOptions.gameStarted = false;
+ mOptions.visiteds = 0;
+
+ $imagesLink.each(function () {
+ const iq = parseInt($(this).text());
+ if (!isNaN(iq) && iq < mOptions.cardsGame.length) {
+ const flipcard = mOptions.cardsGame[iq];
+ flipcard.url = $(this).attr('href');
+ if (flipcard.url.length < 4) {
+ flipcard.url = '';
+ }
+ }
+ });
+
+ $imagesLinkBack.each(function () {
+ const iq = parseInt($(this).text());
+ if (!isNaN(iq) && iq < mOptions.cardsGame.length) {
+ const flipcard = mOptions.cardsGame[iq];
+ flipcard.urlBk = $(this).attr('href');
+ if (flipcard.urlBk.length < 4) {
+ flipcard.urlBk = '';
+ }
+ }
+ });
+
+ mOptions.id = typeof mOptions.id === 'undefined' ? false : mOptions.id;
+ mOptions.hits = 0;
+ mOptions.score = 0;
+ mOptions.active = 0;
+ mOptions.obtainedClue = false;
+ mOptions.gameStarted = false;
+
+ for (let i = 0; i < mOptions.cardsGame.length; i++) {
+ mOptions.cardsGame[i].id = i;
+ mOptions.cardsGame[i].eText = mOptions.cardsGame[i].eText;
+ mOptions.cardsGame[i].eTextBk = mOptions.cardsGame[i].eTextBk;
+ }
+
+ mOptions.numberCards = mOptions.cardsGame.length;
+ mOptions.fullscreen = false;
+ return mOptions;
+ },
+
+ startGame: function (instance) {
+ let mOptions = $eXeBeforeAfter.options[instance];
+ if (mOptions.gameStarted) return;
+ mOptions.gameStarted = true;
+ mOptions.hits = 0;
+ mOptions.score = 0;
+ mOptions.gameOver = false;
+ mOptions.obtainedClue = false;
+ $('#bfafCubierta-' + instance).hide();
+ $('#bfafStartGame-' + instance).hide();
+ if (mOptions.isScorm > 0) {
+ $eXeBeforeAfter.sendScore(true, instance);
+ }
+ $eXeBeforeAfter.saveEvaluation(instance);
+ $eXeBeforeAfter.showClue(instance);
+ },
+
+ createInterfaceCards: function (instance) {
+ const path = $eXeBeforeAfter.idevicePath,
+ msgs = $eXeBeforeAfter.options[instance].msgs,
+ mOptions = $eXeBeforeAfter.options[instance],
+ html = `
+
+
+
+
+
+
+
+ ${$eXeBeforeAfter.getMainHtml(instance)}
+
+
+
+
+
+ ${$exeDevices.iDevice.gamification.scorm.addButtonScoreNew(mOptions, this.isInExe)}
+ `;
+ return html;
+ },
+
+ getMainHtml: function (instance) {
+ const mOptions = $eXeBeforeAfter.options[instance];
+ const msgs = mOptions.msgs;
+ const orientation = mOptions.cardsGame[mOptions.active].vertical
+ ? 'vertical'
+ : 'horizontal';
+ const html = `
`;
+ return html;
+ },
+
+ showImage: function (number, instance) {
+ const mOptions = $eXeBeforeAfter.options[instance];
+ const $imgAfter = $(`#bfafpImageAfter-${instance}`);
+ const $imgBefore = $(`#bfafpImageBefore-${instance}`);
+ const $Multimedia = $(`#bfafMultimedia-${instance}`);
+ const $overlay = $(`#bfafpOverlay-${instance}`);
+ const $slider = $(`#bfafpSlider-${instance}`);
+ const $nubmerInfo = $(`#bfafNumberInfo-${instance}`);
+ const $containerBA = $(`#bfafpContainerBA-${instance}`);
+ const $description = $(`#bfafpDescription-${instance}`);
+ const $titleAfter = $(`#bfafTitleAfter-${instance}`);
+ const $titleBefore = $(`#bfafTitleBefore-${instance}`);
+ mOptions.active = number;
+ mOptions.visiteds =
+ mOptions.visiteds < number ? number : mOptions.visiteds;
+
+ const isVertical = mOptions.cardsGame[number].vertical;
+
+ const orientation = isVertical ? 'vertical' : 'horizontal';
+ $containerBA.css('opacity', 0);
+ $containerBA.attr('data-orientation', orientation);
+ $description.html(mOptions.cardsGame[number].description);
+
+ const card = mOptions.cardsGame[number];
+ $imgAfter.attr('alt', card.alt);
+ $imgBefore.attr('alt', card.altBk);
+
+ // Handler for image load - extracted to fix cached image race condition
+ const handleImageLoad = function () {
+ let naturalWidth = this.naturalWidth;
+ let naturalHeight = this.naturalHeight;
+
+ let containerWidth = $Multimedia.width();
+ let containerHeight = $Multimedia.height();
+
+ let ratioAncho = naturalWidth / containerWidth;
+ let ratioAlto = naturalHeight / containerHeight;
+
+ if (ratioAncho > ratioAlto) {
+ let nuevoAlto =
+ naturalHeight * (containerWidth / naturalWidth);
+ $imgAfter.css({
+ width: containerWidth + 'px',
+ height: nuevoAlto + 'px',
+ });
+ $imgBefore.css({
+ width: containerWidth + 'px',
+ height: nuevoAlto + 'px',
+ });
+ $containerBA.css({
+ width: containerWidth + 'px',
+ height: nuevoAlto + 'px',
+ });
+ } else {
+ let nuevoAncho =
+ naturalWidth * (containerHeight / naturalHeight);
+ $imgAfter.css({
+ height: containerHeight + 'px',
+ width: nuevoAncho + 'px',
+ });
+ $imgBefore.css({
+ height: containerHeight + 'px',
+ width: nuevoAncho + 'px',
+ });
+ $containerBA.css({
+ height: containerHeight + 'px',
+ width: nuevoAncho + 'px',
+ });
+ }
+ const percentageInit = card.position;
+ const containerWidth1 = $containerBA.width();
+ const containerHeight1 = $containerBA.height();
+
+ const containerSize = isVertical
+ ? containerHeight1
+ : containerWidth1;
+
+ const pos = (percentageInit / 100) * containerSize;
+ $overlay.css({ border: '' });
+ $slider.css({ border: '' });
+ $titleBefore.removeClass(
+ 'BFAFP-TitleBefore BFAFP-TitleBeforeV'
+ );
+ $titleAfter.removeClass('BFAFP-TitleAfter BFAFP-TitleAfterV');
+ $titleBefore.hide();
+ $titleAfter.hide();
+
+ if (card.eText.length > 0) {
+ $titleAfter.html(card.eText).show();
+ }
+ if (card.eTextBk.length > 0) {
+ $titleBefore.html(card.eTextBk).show();
+ }
+ $nubmerInfo.text(
+ `${mOptions.msgs.msgImage}: ${number + 1}/${mOptions.cardsGame.length}`
+ );
+
+ if (mOptions.gameStarted && mOptions.isScorm > 0) {
+ $eXeBeforeAfter.sendScore(true, instance);
+ }
+ if (mOptions.gameStarted) {
+ $eXeBeforeAfter.saveEvaluation(instance);
+ $eXeBeforeAfter.showClue(instance);
+ }
+
+ if (isVertical) {
+ $overlay.height(pos);
+ $overlay.css({ 'border-bottom': '4px solid #555' });
+ $overlay.width(containerWidth1);
+ $slider.css({ left: 0, top: pos - 3 + 'px' });
+ $imgAfter.css({ cursor: 'n-resize' });
+ $imgBefore.css({ cursor: 's-resize' });
+ $titleBefore.addClass('BFAFP-TitleBeforeV');
+ $titleAfter.addClass('BFAFP-TitleAfterV');
+ } else {
+ $overlay.width(pos);
+ $overlay.css({ 'border-right': '4px solid #555' });
+ $overlay.height(containerHeight1);
+ $slider.css({ left: pos - 3 + 'px', top: 0 });
+ $imgAfter.css({ cursor: 'w-resize' });
+ $imgBefore.css({ cursor: 'e-resize' });
+ $titleBefore.addClass('BFAFP-TitleBefore');
+ $titleAfter.addClass('BFAFP-TitleAfter');
+ }
+ setTimeout(function () {
+ $eXeBeforeAfter.initComparison(number, instance);
+ $containerBA.animate({ opacity: 1 }, 500);
+ }, 200);
+ };
+
+ // Fix for cached images: attach handler BEFORE setting src
+ // This ensures the load event is captured even for cached images
+ $imgAfter.off('load').one('load', handleImageLoad);
+ $imgBefore.prop('src', card.urlBk);
+ $imgAfter.attr('src', card.url);
+
+ // For cached images, the load event may have already fired synchronously
+ // Use setTimeout(0) to check after the current execution context
+ setTimeout(function () {
+ if ($imgAfter[0].complete && $imgAfter[0].naturalWidth > 0) {
+ $imgAfter.trigger('load');
+ }
+ }, 0);
+ },
+
+ initComparison: function (number, instance) {
+ const mOptions = $eXeBeforeAfter.options[instance],
+ container = document.querySelector('#bfafpContainerBA-' + instance),
+ overlay = container.querySelector('.BFAFP-Overlay'),
+ slider = container.querySelector('.BFAFP-Slider'),
+ card = mOptions.cardsGame[number];
+
+ if (!overlay || !slider) return;
+
+ const isVertical = card.vertical;
+
+ if (slider._initComparisonHandlers) {
+ slider.removeEventListener(
+ 'mousedown',
+ slider._initComparisonHandlers.startSlide
+ );
+ slider.removeEventListener(
+ 'touchstart',
+ slider._initComparisonHandlers.startSlide
+ );
+ window.removeEventListener(
+ 'mouseup',
+ slider._initComparisonHandlers.stopSlide
+ );
+ window.removeEventListener(
+ 'touchend',
+ slider._initComparisonHandlers.stopSlide
+ );
+ window.removeEventListener(
+ 'mousemove',
+ slider._initComparisonHandlers.slideMove
+ );
+ window.removeEventListener(
+ 'touchmove',
+ slider._initComparisonHandlers.slideMove
+ );
+ window.removeEventListener(
+ 'touchmove',
+ slider._initComparisonHandlers.containerClick
+ );
+ }
+
+ let clicked = false;
+
+ const getContainerSize = () =>
+ isVertical ? container.offsetHeight : container.offsetWidth;
+
+ const getCursorPos = (e) => {
+ const point = e.touches ? e.touches[0] : e,
+ rect = container.getBoundingClientRect();
+ return isVertical
+ ? point.clientY - rect.top
+ : point.clientX - rect.left;
+ };
+
+ const slide = (pos) => {
+ const size = getContainerSize(),
+ clamped = Math.max(0, Math.min(pos, size)),
+ offset =
+ clamped -
+ (isVertical ? slider.offsetHeight : slider.offsetWidth) / 2;
+ if (isVertical) {
+ overlay.style.height = `${clamped}px`;
+ slider.style.top = `${offset - 3}px`;
+ } else {
+ overlay.style.width = `${clamped}px`;
+ slider.style.left = `${offset - 3}px`;
+ }
+ };
+
+ const slideMove = (e) => clicked && slide(getCursorPos(e));
+
+ const startSlide = (e) => {
+ e.preventDefault();
+ clicked = true;
+ slideMove(e);
+ window.addEventListener('mousemove', slideMove);
+ window.addEventListener('touchmove', slideMove, { passive: true });
+ };
+
+ const stopSlide = () => {
+ clicked = false;
+ window.removeEventListener('mousemove', slideMove);
+ window.removeEventListener('touchmove', slideMove);
+ };
+
+ slider._initComparisonHandlers = { startSlide, stopSlide, slideMove };
+
+ slider.addEventListener('mousedown', startSlide);
+ slider.addEventListener('touchstart', startSlide, { passive: true });
+ window.addEventListener('mouseup', stopSlide);
+ window.addEventListener('touchend', stopSlide);
+
+ if (
+ container._initComparisonHandlers &&
+ container._initComparisonHandlers.containerClick
+ ) {
+ container.removeEventListener(
+ 'click',
+ container._initComparisonHandlers.containerClick
+ );
+ }
+
+ const containerClick = (e) => {
+ if (e.target === slider) return;
+
+ const pos = getCursorPos(e);
+ const newOffset =
+ pos -
+ (isVertical ? slider.offsetHeight / 2 : slider.offsetWidth / 2);
+ if (isVertical) {
+ $(overlay).animate({ height: pos }, 500, 'swing');
+ $(slider).animate({ top: newOffset }, 500, 'swing');
+ } else {
+ $(overlay).animate({ width: pos }, 500, 'swing');
+ $(slider).animate({ left: newOffset }, 500, 'swing');
+ }
+ };
+
+ container._initComparisonHandlers =
+ container._initComparisonHandlers || {};
+ container._initComparisonHandlers.containerClick = containerClick;
+ container.addEventListener('click', containerClick);
+
+ const percentageInit =
+ mOptions.cardsGame[mOptions.active].position || 50;
+ const initPos = (percentageInit / 100) * getContainerSize();
+ slide(initPos);
+ },
+
+ showClue: function (instance) {
+ const mOptions = $eXeBeforeAfter.options[instance],
+ percentageHits =
+ (mOptions.visiteds * 10) / mOptions.cardsGame.length;
+ if (
+ mOptions.itinerary.showClue &&
+ percentageHits >= mOptions.itinerary.percentageClue &&
+ !mOptions.obtainedClue
+ ) {
+ mOptions.obtainedClue = true;
+ const msg = `${mOptions.msgs.msgInformation}: ${mOptions.itinerary.clueGame}`;
+ $eXeBeforeAfter.showMessage(2, msg, instance);
+ }
+ },
+
+ removeEvents: function (instance) {
+ $(`#bfafLinkMaximize-${instance}`).off('click touchstart');
+ $(`#bfafLinkMinimize-${instance}`).off('click touchstart');
+ $(`#bfafCodeAccessButton-${instance}`).off('click touchstart');
+ $(`#bfafCodeAccessE-${instance}`).off('keydown');
+ $(window).off('unload.eXeBeforeAfter beforeunload.eXeBeforeAfter');
+ },
+
+ addEvents: function (instance) {
+ const mOptions = $eXeBeforeAfter.options[instance];
+ const $bfafGameContainer = $('#bfafGameContainer-' + instance);
+
+ $eXeBeforeAfter.removeEvents(instance);
+
+ $('#bfafLinkMaximize-' + instance).on('click touchstart', function (e) {
+ e.preventDefault();
+ $bfafGameContainer.show();
+ $('#bfafGameMinimize-' + instance).hide();
+ });
+
+ $('#bfafLinkMinimize-' + instance).on('click touchstart', function (e) {
+ e.preventDefault();
+ $bfafGameContainer.hide();
+ $('#bfafGameMinimize-' + instance)
+ .css('visibility', 'visible')
+ .show();
+ });
+
+ $('#bfafCubierta-' + instance).hide();
+ $('#bfafCodeAccessDiv-' + instance).hide();
+
+ if (mOptions.itinerary && mOptions.itinerary.showCodeAccess) {
+ $('#bfafMesajeAccesCodeE-' + instance).text(
+ mOptions.itinerary.messageCodeAccess
+ );
+ $('#bfafCodeAccessDiv-' + instance).show();
+ $('#bfafShowClue-' + instance).hide();
+ $('#bfafCubierta-' + instance).show();
+ }
+
+ $('#bfafCodeAccessButton-' + instance).on(
+ 'click touchstart',
+ function (e) {
+ e.preventDefault();
+ $eXeBeforeAfter.enterCodeAccess(instance);
+ }
+ );
+
+ $('#bfafCodeAccessE-' + instance).on('keydown', function (event) {
+ if (event.which == 13 || event.keyCode == 13) {
+ $eXeBeforeAfter.enterCodeAccess(instance);
+ return false;
+ }
+ return true;
+ });
+
+ $('#beforeEPosition')
+ .on('keyup click', function () {
+ this.value = this.value.replace(/\D/g, '').substring(0, 3);
+ })
+ .on('focusout', function () {
+ let value =
+ this.value.trim() === '' ? 100 : parseInt(this.value, 10);
+ value = Math.max(0, Math.min(value, 100));
+ this.value = value;
+ });
+
+ $(window).on(
+ 'unload.eXeBeforeAfter beforeunload.eXeBeforeAfter',
+ function () {
+ if ($eXeBeforeAfter.mScorm) {
+ $exeDevices.iDevice.gamification.scorm.endScorm(
+ $eXeBeforeAfter.mScorm
+ );
+ }
+ }
+ );
+
+ if (mOptions.author.trim().length > 0 && !mOptions.fullscreen) {
+ $('#bfafAuthorGame-' + instance).html(
+ mOptions.msgs.msgAuthor + ': ' + mOptions.author
+ );
+ $('#bfafAuthorGame-' + instance).show();
+ }
+
+ if (mOptions.isScorm > 0) {
+ $exeDevices.iDevice.gamification.scorm.registerActivity(mOptions);
+ }
+
+ $('#bfafLinkFullScreen-' + instance).on(
+ 'click touchstart',
+ function (e) {
+ e.preventDefault();
+ const element = document.getElementById(
+ 'bfafGameContainer-' + instance
+ );
+ $exeDevices.iDevice.gamification.helpers.toggleFullscreen(
+ element
+ );
+ setTimeout(function () {
+ $eXeBeforeAfter.showImage(mOptions.active, instance);
+ }, 500);
+ }
+ );
+
+ $('#bfafNext-' + instance).on('click', function () {
+ mOptions.active =
+ mOptions.active < mOptions.cardsGame.length - 1
+ ? mOptions.active + 1
+ : mOptions.active;
+ $eXeBeforeAfter.showImage(mOptions.active, instance);
+ $eXeBeforeAfter.activeButton(mOptions.active, instance);
+ });
+
+ $('#bfafPrevious-' + instance).on('click', function () {
+ mOptions.active = mOptions.active > 0 ? mOptions.active - 1 : 0;
+ $eXeBeforeAfter.showImage(mOptions.active, instance);
+ $eXeBeforeAfter.activeButton(mOptions.active, instance);
+ });
+ $('#bfafMultimedia-' + instance).hide();
+
+ if (!mOptions.itinerary.showCodeAccess) {
+ $('#bfafMultimedia-' + instance).show();
+ $eXeBeforeAfter.showImage(0, instance);
+ $eXeBeforeAfter.activeButton(0, instance);
+ }
+
+ $('#bfafGameContainer-' + instance).on('click', function () {
+ if (!mOptions.gameStarted) {
+ $eXeBeforeAfter.startGame(instance);
+ }
+ });
+
+ setTimeout(() => {
+ $exeDevices.iDevice.gamification.report.updateEvaluationIcon(
+ mOptions,
+ this.isInExe
+ );
+ }, 500);
+ },
+
+ activeButton: function (number, instance) {
+ const mOptions = $eXeBeforeAfter.options[instance];
+ const path = $eXeBeforeAfter.idevicePath;
+
+ $('#bfafPrevious-' + instance)
+ .prop('disabled', false)
+ .find('img')
+ .attr('src', `${path}bfafprevious.png`);
+ $('#bfafNext-' + instance)
+ .prop('disabled', false)
+ .find('img')
+ .attr('src', `${path}bfafnext.png`);
+ $('#bfafPrevious-' + instance).css('cursor', 'pointer');
+ $('#bfafNext-' + instance).css('cursor', 'pointer');
+ if (number <= 0) {
+ $('#bfafPrevious-' + instance)
+ .prop('disabled', true)
+ .find('img')
+ .attr('src', `${path}bfafpreviousd.png`);
+ $('#bfafPrevious-' + instance).css('cursor', 'default');
+ }
+
+ if (number >= mOptions.cardsGame.length - 1) {
+ $('#bfafNext-' + instance)
+ .prop('disabled', true)
+ .find('img')
+ .attr('src', `${path}bfafnextd.png`);
+ $('#bfafNext-' + instance).css('cursor', 'default');
+ }
+
+ if (mOptions.cardsGame.length == 1) {
+ $('#bfafButtonsBar-' + instance).hide();
+ }
+ },
+
+ isMobile: function () {
+ return /Android|BlackBerry|iPhone|iPad|iPod|Opera Mini|IEMobile/i.test(
+ navigator.userAgent
+ );
+ },
+
+ enterCodeAccess: function (instance) {
+ const mOptions = $eXeBeforeAfter.options[instance],
+ codeInput = $(`#bfafCodeAccessE-${instance}`).val().toLowerCase(),
+ codeAccess = mOptions.itinerary.codeAccess.toLowerCase();
+ if (codeAccess === codeInput) {
+ $(
+ `#bfafCodeAccessDiv-${instance}, #bfafCubierta-${instance}`
+ ).hide();
+ $(`#bfafLinkMaximize-${instance}`).trigger('click');
+ $('#bfafMultimedia-' + instance).show();
+ $eXeBeforeAfter.showImage(0, instance);
+ $eXeBeforeAfter.activeButton(0, instance);
+ } else {
+ $(`#bfafMesajeAccesCodeE-${instance}`)
+ .fadeOut(300)
+ .fadeIn(200)
+ .fadeOut(300)
+ .fadeIn(200);
+ $(`#bfafCodeAccessE-${instance}`).val('');
+ }
+ },
+
+ showMessage: function (type, message, instance) {
+ const colors = [
+ '#555555',
+ $eXeBeforeAfter.borderColors.red,
+ $eXeBeforeAfter.borderColors.green,
+ $eXeBeforeAfter.borderColors.blue,
+ $eXeBeforeAfter.borderColors.yellow,
+ ],
+ color = colors[type],
+ $bfafMessage = $(`#bfafMessage-${instance}`);
+ $bfafMessage
+ .html(message)
+ .css({ color: color, 'font-style': 'bold' })
+ .show();
+ },
+
+ saveEvaluation: function (instance) {
+ const mOptions = $eXeBeforeAfter.options[instance];
+
+ mOptions.scorerp =
+ ((mOptions.visiteds + 1) * 10) / mOptions.cardsGame.length;
+ $exeDevices.iDevice.gamification.report.saveEvaluation(
+ mOptions,
+ $eXeBeforeAfter.isInExe
+ );
+ },
+
+ sendScore: function (auto, instance) {
+ const mOptions = $eXeBeforeAfter.options[instance];
+
+ mOptions.scorerp =
+ ((mOptions.visiteds + 1) * 10) / mOptions.cardsGame.length;
+ mOptions.previousScore = $eXeBeforeAfter.previousScore;
+ mOptions.userName = $eXeBeforeAfter.userName;
+
+ $exeDevices.iDevice.gamification.scorm.sendScoreNew(auto, mOptions);
+
+ $eXeBeforeAfter.previousScore = mOptions.previousScore;
+ },
+};
+$(function () {
+ $eXeBeforeAfter.init();
+});
diff --git a/vendor/exelearning/export-resources/idevices/beforeafter/export/bfafnext.png b/vendor/exelearning/export-resources/idevices/beforeafter/export/bfafnext.png
new file mode 100644
index 0000000..7688dcc
Binary files /dev/null and b/vendor/exelearning/export-resources/idevices/beforeafter/export/bfafnext.png differ
diff --git a/vendor/exelearning/export-resources/idevices/beforeafter/export/bfafnextd.png b/vendor/exelearning/export-resources/idevices/beforeafter/export/bfafnextd.png
new file mode 100644
index 0000000..e04853b
Binary files /dev/null and b/vendor/exelearning/export-resources/idevices/beforeafter/export/bfafnextd.png differ
diff --git a/vendor/exelearning/export-resources/idevices/beforeafter/export/bfafprevious.png b/vendor/exelearning/export-resources/idevices/beforeafter/export/bfafprevious.png
new file mode 100644
index 0000000..3b9d1dc
Binary files /dev/null and b/vendor/exelearning/export-resources/idevices/beforeafter/export/bfafprevious.png differ
diff --git a/vendor/exelearning/export-resources/idevices/beforeafter/export/bfafpreviousd.png b/vendor/exelearning/export-resources/idevices/beforeafter/export/bfafpreviousd.png
new file mode 100644
index 0000000..355ef37
Binary files /dev/null and b/vendor/exelearning/export-resources/idevices/beforeafter/export/bfafpreviousd.png differ
diff --git a/vendor/exelearning/export-resources/idevices/beforeafter/export/exequextbuttonko.svg b/vendor/exelearning/export-resources/idevices/beforeafter/export/exequextbuttonko.svg
new file mode 100644
index 0000000..433883d
--- /dev/null
+++ b/vendor/exelearning/export-resources/idevices/beforeafter/export/exequextbuttonko.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/vendor/exelearning/export-resources/idevices/beforeafter/export/exequextbuttonok.svg b/vendor/exelearning/export-resources/idevices/beforeafter/export/exequextbuttonok.svg
new file mode 100644
index 0000000..2dd0b17
--- /dev/null
+++ b/vendor/exelearning/export-resources/idevices/beforeafter/export/exequextbuttonok.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/vendor/exelearning/export-resources/idevices/beforeafter/export/exequextfull.svg b/vendor/exelearning/export-resources/idevices/beforeafter/export/exequextfull.svg
new file mode 100644
index 0000000..fa27df9
--- /dev/null
+++ b/vendor/exelearning/export-resources/idevices/beforeafter/export/exequextfull.svg
@@ -0,0 +1,3 @@
+
diff --git a/vendor/exelearning/export-resources/idevices/beforeafter/export/exequexthits.svg b/vendor/exelearning/export-resources/idevices/beforeafter/export/exequexthits.svg
new file mode 100644
index 0000000..0f8dd84
--- /dev/null
+++ b/vendor/exelearning/export-resources/idevices/beforeafter/export/exequexthits.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/vendor/exelearning/export-resources/idevices/beforeafter/export/exequextmin.svg b/vendor/exelearning/export-resources/idevices/beforeafter/export/exequextmin.svg
new file mode 100644
index 0000000..bee9919
--- /dev/null
+++ b/vendor/exelearning/export-resources/idevices/beforeafter/export/exequextmin.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/vendor/exelearning/export-resources/idevices/beforeafter/export/exequextnumber.svg b/vendor/exelearning/export-resources/idevices/beforeafter/export/exequextnumber.svg
new file mode 100644
index 0000000..8d989b0
--- /dev/null
+++ b/vendor/exelearning/export-resources/idevices/beforeafter/export/exequextnumber.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/vendor/exelearning/export-resources/idevices/beforeafter/export/exequextreply.png b/vendor/exelearning/export-resources/idevices/beforeafter/export/exequextreply.png
new file mode 100644
index 0000000..016de4b
Binary files /dev/null and b/vendor/exelearning/export-resources/idevices/beforeafter/export/exequextreply.png differ
diff --git a/vendor/exelearning/export-resources/idevices/beforeafter/export/exequextrerrors.svg b/vendor/exelearning/export-resources/idevices/beforeafter/export/exequextrerrors.svg
new file mode 100644
index 0000000..adb3571
--- /dev/null
+++ b/vendor/exelearning/export-resources/idevices/beforeafter/export/exequextrerrors.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/vendor/exelearning/export-resources/idevices/beforeafter/export/exequextscore.svg b/vendor/exelearning/export-resources/idevices/beforeafter/export/exequextscore.svg
new file mode 100644
index 0000000..b2ff7bd
--- /dev/null
+++ b/vendor/exelearning/export-resources/idevices/beforeafter/export/exequextscore.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/vendor/exelearning/export-resources/idevices/beforeafter/export/exequextsq.png b/vendor/exelearning/export-resources/idevices/beforeafter/export/exequextsq.png
new file mode 100644
index 0000000..1d93e55
Binary files /dev/null and b/vendor/exelearning/export-resources/idevices/beforeafter/export/exequextsq.png differ
diff --git a/vendor/exelearning/export-resources/idevices/beforeafter/export/exequexttime.svg b/vendor/exelearning/export-resources/idevices/beforeafter/export/exequexttime.svg
new file mode 100644
index 0000000..4f0ecb6
--- /dev/null
+++ b/vendor/exelearning/export-resources/idevices/beforeafter/export/exequexttime.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/vendor/exelearning/export-resources/idevices/casestudy/casestudy-icon.svg b/vendor/exelearning/export-resources/idevices/casestudy/casestudy-icon.svg
new file mode 100644
index 0000000..fde1da9
--- /dev/null
+++ b/vendor/exelearning/export-resources/idevices/casestudy/casestudy-icon.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/vendor/exelearning/export-resources/idevices/casestudy/config.xml b/vendor/exelearning/export-resources/idevices/casestudy/config.xml
new file mode 100644
index 0000000..7e25f8c
--- /dev/null
+++ b/vendor/exelearning/export-resources/idevices/casestudy/config.xml
@@ -0,0 +1,35 @@
+
+
+ Case study
+ casestudy
+ Information and presentation
+
+ casestudy-icon
+ casestudy-icon.svg
+ img
+
+ 1.0
+ 3.0
+ json
+ location
+ location type
+
+ casestudy.js
+
+
+ casestudy.css
+
+
+ casestudy.js
+
+
+ casestudy.css
+
+ casestudy.html
+ author
+ author url
+ license
+ license url
+
+ 0
+
diff --git a/vendor/exelearning/export-resources/idevices/casestudy/edition/casestudy.css b/vendor/exelearning/export-resources/idevices/casestudy/edition/casestudy.css
new file mode 100644
index 0000000..7d453ab
--- /dev/null
+++ b/vendor/exelearning/export-resources/idevices/casestudy/edition/casestudy.css
@@ -0,0 +1,126 @@
+#caseStudyForm .idevice-description {
+ border-bottom: 1px solid #a7a7a7;
+ margin-bottom: 15px;
+}
+
+#caseStudyForm .exe-field {
+ font-weight: bold;
+ padding: 5px;
+ margin-top: 5px;
+ margin-bottom: 5px;
+}
+
+#caseStudyForm .exe-field label.form-label {
+ color: rgb(0, 0, 0);
+}
+
+#caseStudyForm .exe-field label.form-label {
+ color: rgb(0, 0, 0);
+}
+
+#caseStudyForm .exe-field.form-check {
+ margin-top: 10px;
+ margin-left: 40px;
+}
+
+#caseStudyForm .exe-range-field label {
+ width: 100%;
+}
+
+#caseStudyForm .exe-range-field input {
+ max-width: 450px;
+}
+
+#caseStudyForm .exe-range-field span.value-number {
+ position: relative;
+ top: -8px;
+ margin-left: 5px;
+}
+
+#caseStudyForm .exe-datalist-field input {
+ max-width: 450px;
+}
+
+#caseStudyForm .exe-datalist-field input {
+ max-width: 450px;
+}
+
+#caseStudyForm .form-floating input {
+ max-width: 450px;
+ height: 30px;
+}
+
+#caseStudyForm .idevice-element-in-content {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ margin-left: auto;
+}
+
+#caseStudyForm fieldset .exe-text-legend {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ margin-right: auto;
+}
+
+#caseStudyForm legend a {
+ text-decoration: none !important;
+ color: var(--dark-exe-color);
+ font-weight: bold;
+ transition: var(--tr-02);
+ width: 100%;
+}
+
+#caseStudyForm .exe-button {
+ height: 16px;
+ font-size: 14px;
+ color: var(--dark-exe-color);
+ margin-left: var(--margin-m);
+ border: 2px solid var(--verde-cl);
+ border-radius: 5px;
+ padding: 2px;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ margin: auto;
+ margin-inline: 5px;
+ cursor: pointer;
+}
+
+#caseStudyForm .exe-button:hover {
+ color: var(--light-exe-color);
+ background-color: var(--dark-exe-color);
+ border-color: var(--dark-exe-color);
+}
+
+#caseStudyForm .exe-button.exe-button-remove {
+ position: absolute;
+ top: 0px;
+ right: -26px;
+ height: 40px;
+}
+
+#caseStudyForm .exe-button.exe-button-remove.exe-button-remove-fs-open {
+ right: -22px;
+}
+
+#caseStudyForm .exe-button.exe-button-remove:hover {
+ color: var(--light-exe-color);
+ background-color: var(--remove);
+ border-color: var(--remove);
+}
+
+#caseStudyForm .exe-parent {
+ position: relative;
+}
+
+#caseStudyForm .grid-container {
+ display: grid;
+ column-gap: 20px;
+ grid-template-columns: repeat(2, minmax(200px, 1fr));
+}
+
+#caseStudyForm .grid-container input {
+ width: calc(100% - var(--margin-l));
+}
\ No newline at end of file
diff --git a/vendor/exelearning/export-resources/idevices/casestudy/edition/casestudy.js b/vendor/exelearning/export-resources/idevices/casestudy/edition/casestudy.js
new file mode 100644
index 0000000..65cb7f1
--- /dev/null
+++ b/vendor/exelearning/export-resources/idevices/casestudy/edition/casestudy.js
@@ -0,0 +1,303 @@
+/* eslint-disable no-undef */
+/**
+ * Case study (editon code)
+ * Released under Attribution-ShareAlike 4.0 International License.
+ * Author: Manuel Narváez Martínez
+ * Graphic design: Ana María Zamora Moreno
+ * License: http://creativecommons.org/licenses/by-sa/4.0/
+ */
+var $exeDevice = {
+ i18n: {
+ name: _('Case study'),
+ },
+ ideviceBody: null,
+ idevicePath: '',
+ idevicePreviousData: null,
+ id: null,
+
+ init: function (element, previousData, path) {
+ this.ideviceBody = element;
+ this.idevicePreviousData = previousData;
+ this.idevicePath = path;
+ this.id = $(element).attr('idevice-id');
+ this.createForm();
+ },
+
+ createForm: function () {
+ const html = `
+
+ `;
+
+ this.ideviceBody.innerHTML = html;
+ this.enable();
+ },
+
+ createInfoHTML(
+ durationText,
+ durationValue,
+ participantsText,
+ participantsValue
+ ) {
+ return `
+
+ - ${durationText}
- ${durationValue}
+ - ${participantsText}
- ${participantsValue}
+
`;
+ },
+
+ getActivity: function () {
+ const id = this.generateUniqueId('activity');
+ return `
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ `;
+ },
+
+ enable: function () {
+ this.loadPreviousValues();
+ this.addEvents();
+ },
+
+ generateUniqueId: (function () {
+ let counter = 0;
+ return function (prefix = 'id') {
+ counter++;
+ return `${prefix}_${Date.now()}_${counter}`;
+ };
+ })(),
+
+ enable: function () {
+ this.loadPreviousValues();
+ this.addEvents();
+ },
+
+ addEvents: function () {
+ const self = this;
+ $('#cseAddActivity').on('click', function () {
+ $('#cseActivities').append(self.getActivity());
+ $exeTinyMCE.init('multiple-visible', '.exe-html-editor');
+ });
+
+ $('#cseActivities').on('click', '.CSE-DeleteActivity', function () {
+ const $activities = $('#cseActivities .CSE-Activity');
+ if ($activities.length > 1) {
+ eXe.app.confirm(
+ _('Attention'),
+ _('Do you want to delete this activity?'),
+ () => {
+ $(this).closest('.CSE-Activity').remove();
+ }
+ );
+ } else {
+ eXe.app.alert(
+ _('The case study must have at least one activity')
+ );
+ }
+ });
+ },
+ loadPreviousValues: function () {
+ const data = this.idevicePreviousData;
+ if (!data || Object.keys(data).length === 0) return;
+ $('#cseDurationValue').val(data.textInfoDurationInput);
+ $('#cseDurationText').val(data.textInfoDurationTextInput);
+ $('#cseParticipantsvalue').val(data.textInfoParticipantsInput);
+ $('#cseParticipantsText').val(data.textInfoParticipantsTextInput);
+ $('#textStoryTextarea').val(data.history);
+
+ const $container = $('#cseActivities').empty();
+
+ data.activities.forEach((act) => {
+ const $activity = $(this.getActivity());
+ const txtId = $activity
+ .find('textarea[id^="activityTextarea-"]')
+ .attr('id');
+ const fbId = $activity
+ .find('textarea[id^="activityFeedbackTextarea-"]')
+ .attr('id');
+ const btnId = $activity
+ .find('input[id^="activityButtonTextInput-"]')
+ .attr('id');
+ $activity.find(`#${txtId}`).val(act.activity);
+ $activity.find(`#${fbId}`).val(act.feedback);
+ $activity.find(`#${btnId}`).val(act.buttonCaption);
+ $container.append($activity);
+ });
+
+ const $title = $('#' + $exeDevice.id)
+ .closest('article')
+ .find('header h1.box-title');
+ if (
+ data.title &&
+ data.title == 'Case Study' &&
+ $title.text() == 'Case Study'
+ ) {
+ $title.text(_('Case study'));
+ }
+
+ $exeTinyMCE.init('multiple-visible', '.exe-html-editor');
+ },
+
+ save: function () {
+ const dataGame = this.validateData();
+ return dataGame || false;
+ },
+
+ validateData: function () {
+ const storyEditor = tinymce.get('textStoryTextarea');
+ const history = storyEditor ? storyEditor.getContent() : '';
+ let valid = true;
+
+ if (!storyEditor.getContent().trim()) {
+ eXe.app.alert(_('Please complete the history'));
+ return false;
+ }
+
+ const activities = [];
+ $('#cseActivities .CSE-Activity').each(function () {
+ const $act = $(this);
+ const textareaId = $act
+ .find('textarea[id^="activityTextarea-"]')
+ .attr('id');
+ const fbareaId = $act
+ .find('textarea[id^="activityFeedbackTextarea-"]')
+ .attr('id');
+ const btnInput = $act.find('input[id^="activityButtonTextInput-"]');
+
+ const activityEditor = tinymce.get(textareaId);
+ const feedbackEditor = tinymce.get(fbareaId);
+
+ const actTextPlain = activityEditor
+ .getContent({ format: 'text' })
+ .trim();
+ if (!actTextPlain) {
+ eXe.app.alert(_('You must provide the text for each activity'));
+ valid = false;
+ return;
+ }
+
+ const activity = activityEditor.getContent();
+ const feedback = feedbackEditor.getContent();
+ const buttonCaption = btnInput.val().trim();
+
+ activities.push({
+ activity: activity,
+ feedback: feedback,
+ buttonCaption: buttonCaption,
+ });
+ });
+
+ if (!valid) return false;
+
+ const textInfoDurationInput = $('#cseDurationValue').val().trim();
+ const textInfoDurationTextInput = $('#cseDurationText').val().trim();
+ const textInfoParticipantsInput = $('#cseParticipantsvalue')
+ .val()
+ .trim();
+ const textInfoParticipantsTextInput = $('#cseParticipantsText')
+ .val()
+ .trim();
+
+ return {
+ id: this.id,
+ typeGame: 'Case study',
+ history,
+ textInfoDurationInput,
+ textInfoDurationTextInput,
+ textInfoParticipantsInput,
+ textInfoParticipantsTextInput,
+ activities: activities,
+ };
+ },
+};
diff --git a/vendor/exelearning/export-resources/idevices/casestudy/export/casestudy.css b/vendor/exelearning/export-resources/idevices/casestudy/export/casestudy.css
new file mode 100644
index 0000000..d8c27d2
--- /dev/null
+++ b/vendor/exelearning/export-resources/idevices/casestudy/export/casestudy.css
@@ -0,0 +1,15 @@
+.caseStudyContent .inline {
+ display: flex;
+}
+
+.caseStudyContent dt {
+ margin: 0 0 0 auto;
+}
+
+.caseStudyContent dd {
+ margin-left: 10px;
+}
+
+.idevice_node.text .iDevice_buttons.feedback-button {
+ margin-bottom: 1em;
+}
\ No newline at end of file
diff --git a/vendor/exelearning/export-resources/idevices/casestudy/export/casestudy.html b/vendor/exelearning/export-resources/idevices/casestudy/export/casestudy.html
new file mode 100644
index 0000000..87bb21e
--- /dev/null
+++ b/vendor/exelearning/export-resources/idevices/casestudy/export/casestudy.html
@@ -0,0 +1,3 @@
+
+ {content}
+
diff --git a/vendor/exelearning/export-resources/idevices/casestudy/export/casestudy.js b/vendor/exelearning/export-resources/idevices/casestudy/export/casestudy.js
new file mode 100644
index 0000000..fcceaa1
--- /dev/null
+++ b/vendor/exelearning/export-resources/idevices/casestudy/export/casestudy.js
@@ -0,0 +1,147 @@
+/* eslint-disable no-undef */
+/**
+ * Case study (export code)
+ * Released under Attribution-ShareAlike 4.0 International License.
+ * Author: Manuel Narváez Martínez
+ * Graphic design: Ana María Zamora Moreno
+ * License: http://creativecommons.org/licenses/by-sa/4.0/
+ */
+var $casestudy = {
+ borderColors: {
+ black: '#1c1b1b',
+ blue: '#5877c6',
+ green: '#00a300',
+ red: '#ff0000',
+ white: '#f9f9f9',
+ yellow: '#f3d55a',
+ grey: '#777777',
+ incorrect: '#d9d9d9',
+ correct: '#00ff00',
+ },
+
+ userName: '',
+ previousScore: '',
+ initialScore: '',
+ mScorm: null,
+
+ msgs: {
+ msgNoImage: 'Sin imagen',
+ msgFeedback: 'Mostrar retroalimentación',
+ msgCaseStudy: 'Caso práctico',
+ },
+
+ init: function () {},
+
+ renderView: function (data, accesibility, template, ideviceId) {
+ data.msgs =
+ typeof data.msgs == 'undefined' ? $casestudy.msgs : data.msgs;
+ const htmlContent = this.createInterfaceCaseStudy(data);
+ return template.replace('{content}', htmlContent);
+ },
+
+ renderBehaviour: function (data, accesibility, ideviceId) {
+ data.msgs =
+ typeof data.msgs == 'undefined' ? $casestudy.msgs : data.msgs;
+ const $title = $('#' + data.ideviceId)
+ .closest('article')
+ .find('header h1.box-title');
+ if (
+ data.title &&
+ data.title == 'Case Study' &&
+ $title.text() == 'Case Study'
+ ) {
+ $title.text(data.msgs.msgCaseStudy);
+ }
+ this.addEvents(data);
+ const dataString = JSON.stringify(data);
+ if ($exeDevices.iDevice.gamification.math.hasLatex(dataString)) {
+ $exeDevices.iDevice.gamification.math.updateLatex(
+ '.exe-casestudy-container'
+ );
+ }
+ },
+
+ createInterfaceCaseStudy: function (data) {
+ const infoContentHTML = $casestudy.createInfoHTML(
+ data.textInfoDurationInput === ''
+ ? ''
+ : data.textInfoDurationTextInput,
+ data.textInfoDurationInput,
+ data.textInfoParticipantsInput === ''
+ ? ''
+ : data.textInfoParticipantsTextInput,
+ data.textInfoParticipantsInput
+ );
+ const history = data.history;
+ return `
+
+
+ ${infoContentHTML}
+
+
+ ${history}
+
+
+ ${this.generateActivities(data)}
+
+
+ `;
+ },
+
+ generateActivities: function (data) {
+ return data.activities
+ .map((activity, index) => {
+ const activity1 = activity.activity;
+ const feedback = activity.feedback;
+ const button = activity.buttonCaption || data.msgs.msgFeedback;
+ const bgClass = index % 2 ? 'CSP-ActivityDivBlack' : '';
+ const hasFeedback = feedback.trim().length > 0;
+
+ return `
+
+
+ ${activity1}
+
+ ${
+ hasFeedback
+ ? `
+
+
+
`
+ : ''
+ }
+
+ ${feedback}
+
+
+ `;
+ })
+ .join('');
+ },
+
+ createInfoHTML(
+ durationText,
+ durationValue,
+ participantsText,
+ participantsValue
+ ) {
+ return `
+
+ - ${durationText}
- ${durationValue}
+ - ${participantsText}
- ${participantsValue}
+
`;
+ },
+
+ addEvents: function (data) {
+ $(`.CSP-Activities`).off('click', '.CSP-FeedbackBtn');
+ $(`.CSP-Activities`).on('click', '.CSP-FeedbackBtn', function () {
+ const $activityDiv = $(this).closest('.CSP-ActivityDiv');
+ const $fb = $activityDiv.find('.CSP-FeedbackText');
+ $fb.slideToggle(200, function () {
+ $exeDevices.iDevice.gamification.math.updateLatex(
+ '.CSP-FeedbackText'
+ );
+ });
+ });
+ },
+};
diff --git a/vendor/exelearning/export-resources/idevices/challenge/challenge-icon.svg b/vendor/exelearning/export-resources/idevices/challenge/challenge-icon.svg
new file mode 100644
index 0000000..9b9f1ab
--- /dev/null
+++ b/vendor/exelearning/export-resources/idevices/challenge/challenge-icon.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/vendor/exelearning/export-resources/idevices/challenge/config.xml b/vendor/exelearning/export-resources/idevices/challenge/config.xml
new file mode 100644
index 0000000..0561a06
--- /dev/null
+++ b/vendor/exelearning/export-resources/idevices/challenge/config.xml
@@ -0,0 +1,12 @@
+
+
+ Challenge
+ challenge
+ Games
+
+ challenge-icon
+ challenge-icon.svg
+ img
+
+ 0
+
diff --git a/vendor/exelearning/export-resources/idevices/challenge/edition/challenge.css b/vendor/exelearning/export-resources/idevices/challenge/edition/challenge.css
new file mode 100644
index 0000000..97e364e
--- /dev/null
+++ b/vendor/exelearning/export-resources/idevices/challenge/edition/challenge.css
@@ -0,0 +1,393 @@
+#desafioIdeviceForm input[type=number] {
+ min-width: 4em;
+}
+
+#desafioIdeviceForm .desafio-EClue select {
+ width: 4em;
+}
+
+#desafioIdeviceForm label {
+ margin-right: 0.15em !important;
+}
+
+#desafioIdeviceForm input:is([type="checkbox"] [type="number"]) {
+ margin-right: 0.15em !important;
+}
+
+#desafioIdeviceForm #desafioEChallenges,
+#desafioIdeviceForm #desafioEClues {
+ display: none;
+}
+
+#desafioIdeviceForm input[type="radio"],
+#desafioIdeviceForm input[type="checkbox"],
+#desafioIdeviceForm input[type=button] {
+ cursor: pointer;
+}
+
+.desafio-EPanel {
+ margin: 0.7em auto;
+ padding: 0;
+ position: relative;
+ width: 100%;
+}
+
+
+.desafio-EClue {
+ display: flex;
+ justify-content: flex-start;
+ align-items: center;
+ width: 100%;
+
+}
+
+.desafio-EClue select {
+ width: 9ch !important;
+ min-width: 9ch !important;
+}
+
+.desafio-EClue input[type=text] {
+ flex-grow: 0;
+}
+
+.desafio-EClue label {
+ margin-right: 0.1em;
+ white-space: nowrap;
+}
+
+.desafio-DataDesafio {
+ display: flex;
+ justify-content: flex-start;
+ align-items: center;
+}
+
+.desafio-DataDesafio input[type=text] {
+ width: 100%;
+ min-width: 100px;
+ flex-grow: 0;
+}
+
+
+.desafio-EDataChallenger select {
+ width: 100px;
+}
+
+/*Numero Preguntas */
+
+.desafio-ENumQuestionDiv {
+ align-items: center;
+ display: flex;
+ height: 1.5em;
+ justify-content: center;
+ position: absolute;
+ right: 0;
+ top: .3em;
+ width: 3em;
+ z-index: 20;
+}
+
+.desafio-ENumQ {
+ background-image: url(quextIENumber.png);
+ background-size: 100% 100%;
+ display: inline-block;
+ height: 1.5em;
+ margin-right: 0px;
+ width: 1.5em;
+}
+
+.desafio-ENumQuestions {
+ font-weight: bold;
+ height: 1.5em;
+ text-align: center;
+ width: 2em;
+}
+
+/* Barra edición */
+
+.desafio-ENavigationButtons {
+ align-items: center;
+ display: flex;
+ justify-content: center;
+ margin-top: 1em;
+ width: 100%;
+}
+
+.desafio-ENavigationButton {
+ width: 1.7em;
+ height: 1.7em;
+ min-width: 1.7em;
+ -moz-transition: transform 0.3s;
+ -ms-transition: transform 0.3s;
+ -o-transition: transform 0.3s;
+ -webkit-transition: transform 0.3s;
+ transition: transform 0.3s;
+
+}
+
+.desafio-EButtonImage {
+ height: 100%;
+ width: 100%;
+ cursor: pointer;
+
+}
+
+.desafio-ENavigationButton:hover {
+ -moz-transform: scale(1.1);
+ -ms-transform: scale(1.1);
+ -o-transform: scale(1.1);
+ -webkit-transform: scale(1.1);
+ transform: scale(1.1);
+}
+
+.desafio-NumberQuestion {
+ text-align: center;
+ vertical-align: middle;
+ width: 2.2em;
+}
+
+@media screen and (max-width:500px) {
+ .desafio-DataDesafio {
+ flex-wrap: wrap;
+ }
+
+ .desafio-DataDesafio input[type=text] {
+ margin-bottom: 0.3em;
+ }
+}
+
+/* To review */
+.exe-block-info img {
+ vertical-align: middle;
+ margin-left: .2em
+}
+
+.exe-block-close {
+ position: absolute;
+ top: 6px;
+ right: 5px;
+}
+
+#desafioIdeviceFormTab1 p:first-child {
+ margin-top: 0;
+}
+
+#desafioIdeviceFormTab1 {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 2%;
+}
+
+#desafioIdeviceFormTab1>* {
+ flex: 0 0 48%;
+}
+
+#desafioIdeviceFormTab1> :first-child {
+ flex: 0 0 100%;
+}
+
+
+@media screen and (max-width:720px) {
+ #desafioIdeviceFormTab1>* {
+ flex: 0 0 100%;
+ }
+}
+
+#desafioIdeviceForm #desafioIdeviceFormTab1 label {
+ display: block;
+ margin-bottom: .2em;
+ color: #0BA1A1;
+ font-weight: 500;
+}
+
+#desafioIdeviceForm #desafioIdeviceFormTab1 input {
+ width: 100%;
+}
+
+/* Tabs (this should be common) */
+
+.exe-form-tabs {
+ margin: 0 0 1.5em 0;
+ padding: 0;
+ list-style: none
+}
+
+#main .exe-form-tabs li {
+ margin: 0;
+ padding: 0;
+ list-style: none;
+ list-style-image: none;
+ display: inline
+}
+
+.exe-form-tabs li:first-child a {
+ border-top-left-radius: 4px;
+ border-bottom-left-radius: 4px
+}
+
+.exe-form-tabs li:last-child a {
+ border-top-right-radius: 4px;
+ border-bottom-right-radius: 4px
+}
+
+.exe-form-tabs a {
+ display: inline-block;
+ padding: .5em 1em;
+ border: 1px solid #CCC;
+ background: #F9F9F9;
+ color: #666
+}
+
+.exe-form-tabs li:not(:last-child) a {
+ border-right: none;
+}
+
+.exe-form-tabs .exe-form-active-tab {
+ color: #000;
+ background: #FFF;
+ font-weight: 500
+}
+
+#desafioSCORMoptions {
+ visibility: hidden;
+ margin-left: 1.5em
+}
+
+label[for=desafioActivitySCORM] {
+ font-weight: bold
+}
+
+#desafioSCORMinstructionsButton {
+ display: none;
+ color: #777;
+ margin: 10px 0 0 25px
+}
+
+#desafioSCORMinstructionsButton ul {
+ margin: 1.5em 0 .7em 0;
+ padding: 0;
+ list-style: none
+}
+
+#desafioSCORMinstructionsButton ul li {
+ margin: 0 0 .5em 0;
+ padding: 0;
+ list-style-image: none
+}
+
+#desafioSCORMinstructionsAuto {
+ display: none;
+ color: #777;
+ margin: 10px 0 0 25px
+}
+
+#desafioSCORMinstructionsAuto ul {
+ margin: 1.5em 0 .7em 0;
+ padding: 0;
+ list-style: none
+}
+
+
+#desafioIdeviceForm .desafioToggle {
+ margin: 0 0 10px !important;
+ box-sizing: border-box !important;
+ font-size: 0 !important;
+ display: flex !important;
+ -webkit-box-orient: horizontal !important;
+ -webkit-box-direction: normal !important;
+ flex-flow: row nowrap !important;
+ -webkit-box-pack: start !important;
+ justify-content: flex-start !important;
+ -webkit-box-align: stretch !important;
+ align-items: stretch !important;
+}
+
+#desafioIdeviceForm .desafioToggle input {
+ width: 0 !important;
+ height: 0 !important;
+ position: absolute !important;
+ left: -9999px !important;
+}
+
+#desafioIdeviceForm .desafioToggle input+label {
+ cursor: pointer !important;
+ margin: 0 !important;
+ padding: .75rem 1.5rem !important;
+ box-sizing: border-box !important;
+ position: relative !important;
+ display: inline-block !important;
+ border: solid 1px #DDD !important;
+ background-color: #FFF !important;
+ font-size: 1rem !important;
+ line-height: 110% !important;
+ text-align: center !important;
+ box-shadow: 0 0 0 rgba(255, 255, 255, 0) !important;
+ -webkit-transition: border-color .15s ease-out, color .25s ease-out, background-color .15s ease-out, box-shadow .15s ease-out !important;
+ transition: border-color .15s ease-out, color .25s ease-out, background-color .15s ease-out, box-shadow .15s ease-out !important;
+}
+
+#desafioIdeviceForm .desafioToggle input+label:first-of-type {
+ border-radius: 6px 0 0 6px !important;
+ border-right: none !important;
+}
+
+#desafioIdeviceForm .desafioToggle input+label:last-of-type {
+ border-radius: 0 6px 6px 0 !important;
+ border-left: none !important;
+}
+
+#desafioIdeviceForm .desafioToggle input:hover+label {
+ border-color: var(--brand-primary, #0BA1A1) !important;
+}
+
+#desafioIdeviceForm .desafioToggle input:checked+label {
+ background-color: var(--brand-primary, #0BA1A1) !important;
+ color: #fff !important;
+ border-color: var(--brand-primary, #0BA1A1) !important;
+ z-index: 1 !important;
+}
+
+#desafioIdeviceForm .desafioToggle input:focus+label {
+ outline: dotted 1px #CCC !important;
+ outline-offset: .45rem !important;
+}
+
+#desafioIdeviceForm .js-hidden {
+ display: none !important;
+}
+
+@media (max-width: 400px) {
+ #desafioIdeviceForm .desafioToggle input+label {
+ padding: .75rem .25rem !important;
+ -webkit-box-flex: 0 !important;
+ flex: 0 0 50% !important;
+ display: -webkit-box !important;
+ display: flex !important;
+ -webkit-box-pack: center !important;
+ justify-content: center !important;
+ -webkit-box-align: center !important;
+ align-items: center !important;
+ flex-wrap: wrap !important;
+ }
+}
+
+
+.desafioTypeGameHelp {
+ display: none;
+ font-size: .95em
+}
+
+.Games-Reportdiv {
+ display: flex;
+ justify-content: flex-start;
+ align-items: center;
+ gap: 2px;
+}
+
+.GameModeHelpLink {
+ margin: 0 2px;
+ vertical-align: middle;
+}
+
+.GameModeLabel {
+ font-weight: normal
+}
\ No newline at end of file
diff --git a/vendor/exelearning/export-resources/idevices/challenge/edition/challenge.js b/vendor/exelearning/export-resources/idevices/challenge/edition/challenge.js
new file mode 100644
index 0000000..ca09843
--- /dev/null
+++ b/vendor/exelearning/export-resources/idevices/challenge/edition/challenge.js
@@ -0,0 +1,1130 @@
+/* eslint-disable no-undef */
+/**
+ * Challenge iDevice (edition code)
+ * Released under Attribution-ShareAlike 4.0 International License.
+ * Author: Manuel Narváez Martínez
+ * Graphic design: Ana María Zamora Moreno, Francisco Javier Pulido
+ * Testers: Ricardo Málaga Floriano, Francisco Muñoz de la Peña
+ * Translator: Antonio Juan Delgado García
+ * License: http://creativecommons.org/licenses/by-sa/4.0/
+ */
+var $exeDevice = {
+ // i18n
+ i18n: {
+ name: _('Challenge'),
+ },
+ idevicePath: '',
+ msgs: {},
+ classIdevice: 'challenge',
+ active: 0,
+ numberId: 0,
+ typeActive: 0,
+ challengesGame: [],
+ desafioTitle: '',
+ desafioTime: 40,
+ desafioSolution: '',
+ desafioDescription: '',
+ typeEdit: -1,
+ numberCutCuestion: -1,
+ desafioFeedBacks: [],
+ desafioVersion: 1,
+ clipBoard: '',
+ desafioID: 0,
+ id: false,
+ ci18n: {},
+
+ init: function (element, previousData, path) {
+ this.ideviceBody = element;
+ this.idevicePreviousData = previousData;
+ this.idevicePath = path;
+ this.desafioID = this.getId();
+ this.refreshTranslations();
+ this.setMessagesInfo();
+ this.createForm();
+ },
+
+ getId: function () {
+ return Math.round(new Date().getTime() + Math.random() * 100);
+ },
+
+ refreshTranslations: function () {
+ this.ci18n = {
+ msgStartGame: c_('Click here to start'),
+ msgSubmit: c_('Submit'),
+ msgInformationLooking: c_(
+ 'Cool! The information you were looking for'
+ ),
+ msgPlayStart: c_('Click here to play'),
+ msgMinimize: c_('Minimize'),
+ msgMaximize: c_('Maximize'),
+ msgTime: c_('Time per question'),
+ msgNoImage: c_('No picture question'),
+ msgSuccesses: c_(
+ 'Right! | Excellent! | Great! | Very good! | Perfect!'
+ ),
+ msgFailures: c_(
+ 'It was not that! | Incorrect! | Not correct! | Sorry! | Error!'
+ ),
+ msgInformation: c_('Information'),
+ mgsSolution: c_('Solution'),
+ msgDate: c_('Date'),
+ msgDesafio: c_('Challenge'), // Desafío in ES
+ msgChallenge: c_('Trial'), // Reto in ES
+ msgChallengesCompleted: c_('Completed trials'),
+ msgStartTime: c_('Starting time'),
+ msgReadTime: c_(
+ "Read the instructions and click on a trial when you're ready to play."
+ ),
+ msgChallengesAllCompleted: c_(
+ "You've completed all the trials! You can now complete the game."
+ ),
+ msgDesafioSolved: c_('You made it! You can restart to play again.'),
+ msgDesafioSolved1: c_('You solved the trial! Congratulations!'),
+ msgEndTime: c_('Time Over. Please restart to try again.'),
+ msgSolutionError: c_('Sorry. Wrong solution.'),
+ msgSolutionCError: c_('Sorry. The solution is wrong.'),
+ msgChallengeSolved: c_(
+ 'You solved this trial! Please select another one.'
+ ),
+ msgDesafioReboot: c_(
+ 'This will restart the game and reset its starting time. Do you want to continue?'
+ ),
+ msgCompleteAllChallenged: c_(
+ 'You must complete all the trials before facing the final challenge.'
+ ),
+ msgSolvedChallenge: c_('You already completed this trial.'),
+ msgWriteChallenge: c_('Complete the trial. Write the solution.'),
+ msgEndTimeRestart: c_('Time Over. Please restart to try again.'),
+ msgReboot: c_('Restart'),
+ msgHelp: c_('Help'),
+ msgScoreScorm: c_(
+ "The score can't be saved because this page is not part of a SCORM package."
+ ),
+ msgEndGameScore: c_(
+ 'Please start the game before saving your score.'
+ ),
+ msgOnlySaveScore: c_('You can only save the score once!'),
+ msgOnlySave: c_('You can only save once'),
+ msgYouScore: c_('Your score'),
+ msgAuthor: c_('Authorship'),
+ msgOnlySaveAuto: c_(
+ 'Your score will be saved after each question. You can only play once.'
+ ),
+ msgSaveAuto: c_(
+ 'Your score will be automatically saved after each question.'
+ ),
+ msgSeveralScore: c_(
+ 'You can save the score as many times as you want'
+ ),
+ msgYouLastScore: c_('The last score saved is'),
+ msgActityComply: c_('You have already done this activity.'),
+ msgPlaySeveralTimes: c_(
+ 'You can do this activity as many times as you want'
+ ),
+ msgUncompletedActivity: c_('Incomplete activity'),
+ msgSuccessfulActivity: c_('Activity: Passed. Score: %s'),
+ msgUnsuccessfulActivity: c_('Activity: Not passed. Score: %s'),
+ msgTypeGame: c_('Challenge'),
+ };
+ },
+
+ setMessagesInfo: function () {
+ const msgs = this.msgs;
+ msgs.msgESelectFile = _(
+ 'The selected file does not contain a valid game'
+ );
+ msgs.msgTitleDesafio = _('Please write the challenge title.');
+ msgs.msgDescriptionDesafio = _(
+ 'Please write the challenge description.'
+ );
+ msgs.msgSolutionDesafio = _('Please write the challenge solution.');
+ msgs.msgOneChallenge = _('Please add at least one trial.');
+ msgs.msgTenChallenges = _(
+ 'You can only add ten trials to a challenge.'
+ );
+ msgs.msgDataChanllenge = _(
+ 'Please write the title, description and solution of all the trials.'
+ );
+ msgs.msgNoSuportBrowser = _(
+ 'Your browser is not compatible with this tool.'
+ );
+ msgs.msgClue = _('Help');
+ msgs.msgIDLenght = _(
+ 'The report identifier must have at least 5 characters'
+ );
+ msgs.msgTitleAltImageWarning = _('Accessibility warning');
+ msgs.msgAltImageWarning = _(
+ 'At least one image has no description, are you sure you want to continue without including it? Without it the image may not be accessible to some users with disabilities, or to those using a text browser, or browsing the Web with images turned off.'
+ );
+ },
+
+ showMessage: function (msg) {
+ eXe.app.alert(msg);
+ },
+
+ addChallenge: function () {
+ $exeDevice.saveChallenge();
+
+ if ($exeDevice.challengesGame.length === 10) {
+ $exeDevice.showMessage($exeDevice.msgs.msgTenChallenges);
+ return;
+ }
+
+ $exeDevice.typeEdit = -1;
+ $exeDevice.numberId++;
+ $exeDevice.clearChallenge();
+ $exeDevice.challengesGame.push($exeDevice.getChallengeDefault());
+ $exeDevice.active = $exeDevice.challengesGame.length - 1;
+
+ $('#desafioENumberChallenge').text($exeDevice.active + 1);
+ $('#desafioEPaste').hide();
+ $('#desafioENumChallenges').text($exeDevice.challengesGame.length);
+ $('.desafio-EDivFeebBack').hide();
+ $('#desafioEDivFeebBack-' + $exeDevice.active).show();
+
+ if (tinyMCE.get('desafioEChallenge-' + $exeDevice.active)) {
+ tinyMCE
+ .get('desafioEChallenge-' + $exeDevice.active)
+ .setContent('');
+ } else {
+ $('desafioEChallenge-' + $exeDevice.active).val('');
+ }
+ },
+
+ clearChallenge: function () {
+ $('#desafioECTitle').val('');
+ $('#desafioECSolution').val('');
+ $('#desafioECMessage').val('');
+ $('#desafioECTime').val(5);
+ },
+
+ removeChallenge: function () {
+ if ($exeDevice.challengesGame.length < 2) {
+ $exeDevice.showMessage($exeDevice.msgs.msgOneChallenge);
+ return;
+ }
+
+ $exeDevice.challengesGame.splice($exeDevice.active, 1);
+
+ if ($exeDevice.active >= $exeDevice.challengesGame.length - 1) {
+ $exeDevice.active = $exeDevice.challengesGame.length - 1;
+ }
+
+ $exeDevice.typeEdit = -1;
+ $('#desafioEPaste').hide();
+ $('#desafioENumChallenges').text($exeDevice.challengesGame.length);
+ $('#desafioENumberChallenge').text($exeDevice.active + 1);
+
+ $exeDevice.updateFeedBack();
+ $exeDevice.showChallenge($exeDevice.active);
+ },
+
+ updateFeedBack: function () {
+ for (let i = 0; i < 10; i++) {
+ let text = '';
+ if (i < $exeDevice.challengesGame.length) {
+ text = $exeDevice.challengesGame[i].description;
+ }
+ if (tinyMCE.get('desafioEChallenge-' + i)) {
+ tinyMCE.get('desafioEChallenge-' + i).setContent(text);
+ } else {
+ $('desafioEChallenge-' + i).val(text);
+ }
+ }
+ },
+
+ copyChallenge: function () {
+ $exeDevice.saveChallenge();
+ $exeDevice.typeEdit = 0;
+ $exeDevice.clipBoard = JSON.parse(
+ JSON.stringify($exeDevice.challengesGame[$exeDevice.active])
+ );
+ $('#desafioEPaste').show();
+ },
+
+ cutChallenge: function () {
+ $exeDevice.saveChallenge();
+ $exeDevice.numberCutCuestion = $exeDevice.active;
+ $exeDevice.typeEdit = 1;
+ $('#desafioEPaste').show();
+ },
+
+ pasteChallenge: function () {
+ if ($exeDevice.challengesGame.length > 9 + $exeDevice.typeEdit) {
+ $('#desafioEPaste').hide();
+ $exeDevice.showMessage($exeDevice.msgs.msgTenChallenges);
+ return;
+ }
+
+ if ($exeDevice.typeEdit === 0) {
+ $exeDevice.active++;
+ $exeDevice.challengesGame.splice(
+ $exeDevice.active,
+ 0,
+ $exeDevice.clipBoard
+ );
+ $exeDevice.updateFeedBack();
+ $exeDevice.showChallenge($exeDevice.active);
+ } else if ($exeDevice.typeEdit === 1) {
+ $('#desafioEPaste').hide();
+ $exeDevice.typeEdit = -1;
+ $exeDevices.iDevice.gamification.helpers.arrayMove(
+ $exeDevice.challengesGame,
+ $exeDevice.numberCutCuestion,
+ $exeDevice.active
+ );
+ $exeDevice.updateFeedBack();
+ $exeDevice.showChallenge($exeDevice.active);
+ $('#desafioENumChallenges').text($exeDevice.challengesGame.length);
+ }
+ },
+
+ nextChallenge: function () {
+ $exeDevice.saveChallenge();
+
+ if ($exeDevice.active < $exeDevice.challengesGame.length - 1) {
+ $exeDevice.active++;
+ $exeDevice.showChallenge($exeDevice.active);
+ }
+ },
+
+ lastChallenge: function () {
+ $exeDevice.saveChallenge();
+
+ if ($exeDevice.active < $exeDevice.challengesGame.length - 1) {
+ $exeDevice.active = $exeDevice.challengesGame.length - 1;
+ $exeDevice.showChallenge($exeDevice.active);
+ }
+ },
+
+ previousChallenge: function () {
+ $exeDevice.saveChallenge();
+
+ if ($exeDevice.active > 0) {
+ $exeDevice.active--;
+ $exeDevice.showChallenge($exeDevice.active);
+ }
+ },
+
+ firstChallenge: function () {
+ $exeDevice.saveChallenge();
+
+ if ($exeDevice.active > 0) {
+ $exeDevice.active = 0;
+ $exeDevice.showChallenge($exeDevice.active);
+ }
+ },
+
+ showChallenge: function (i) {
+ let num = i < 0 ? 0 : i;
+ num =
+ num >= $exeDevice.challengesGame.length
+ ? $exeDevice.challengesGame.length - 1
+ : num;
+
+ const hide = (sel) => $(sel).addClass('js-hidden');
+ const show = (sel) => $(sel).removeClass('js-hidden');
+
+ hide('label[for="desafioEDSolution"], #desafioEDSolution');
+ hide('label[for="desafioEDTitle"], #desafioEDTitle');
+ show('label[for="desafioECTitle"], #desafioECTitle');
+ show('label[for="desafioECSolution"], #desafioECSolution');
+
+ $('#desafioENumQuestionDiv').show();
+ $('#desafioSelects').hide();
+
+ $('#desafioENavigationButtons').show();
+
+ const c = $exeDevice.challengesGame[num];
+ $('#desafioECTitle').val(c.title);
+ $('#desafioECSolution').val(c.solution);
+ $('#divDesafioEDescription').hide();
+ $('.desafio-EDivFeebBack').hide();
+ $('#desafioEDivFeebBack-' + i).show();
+ $('#desafioEChallenges').show();
+ $('#desafioENumChallenges').text($exeDevice.challengesGame.length);
+ $('#desafioENumberChallenge').text($exeDevice.active + 1);
+
+ if (typeof c.clues !== 'undefined') {
+ $('#desafioEClue1').val(c.clues[0].clue);
+ $('#desafioEClue2').val(c.clues[1].clue);
+ $('#desafioEClue3').val(c.clues[2].clue);
+ $('#desafioECTime1').val(c.clues[0].time);
+ $('#desafioECTime2').val(c.clues[1].time);
+ $('#desafioECTime3').val(c.clues[2].time);
+ }
+ },
+
+ createForm: function () {
+ const path = $exeDevice.idevicePath,
+ html = `
+
+ `;
+ this.ideviceBody.innerHTML = html;
+ $exeDevicesEdition.iDevice.tabs.init('desafioIdeviceForm');
+
+ $exeDevicesEdition.iDevice.gamification.scorm.init();
+
+ $exeDevice.loadPreviousValues();
+ $exeDevice.addEvents();
+ $exeDevice.showDesafio();
+ },
+ addEvents: function () {
+ if ($exeDevice.challengesGame.length == 0) {
+ $exeDevice.active = 0;
+ $exeDevice.challengesGame.push($exeDevice.getChallengeDefault());
+ }
+
+ $('#desafioENavigationButtons').hide();
+ $('#desafioEPaste').hide();
+ $('#desafioENumQuestionDiv').hide();
+
+ // Toggle switches: sync aria-checked and optional target visibility
+ $('#desafioIdeviceForm').on('change', '.toggle-input', function () {
+ const $toggle = $(this).closest('.toggle-item');
+ const checked = $(this).is(':checked');
+ $toggle.attr('aria-checked', checked ? 'true' : 'false');
+ const target = $toggle.data('target');
+ if (target) {
+ $('#' + target).toggle(checked);
+ }
+ });
+ // Initialize toggle states
+ const initToggle = function (inputSelector) {
+ const $input = $(inputSelector);
+ const $toggle = $input.closest('.toggle-item');
+ const checked = $input.is(':checked');
+ $toggle.attr('aria-checked', checked ? 'true' : 'false');
+ const target = $toggle.data('target');
+ if (target) {
+ $('#' + target).toggle(checked);
+ }
+ };
+ initToggle('#desafioEShowMinimize');
+ initToggle('#desafioEEvaluation');
+
+ $('#desafioEUseLives').on('change', function () {
+ const marcado = $(this).is(':checked');
+ $('#desafioENumberLives').prop('disabled', !marcado);
+ });
+
+ $('#desafioShowSolutions').on('change', function () {
+ const marcado = $(this).is(':checked');
+ $('#desafioTimeShowSolutions').prop('disabled', !marcado);
+ });
+
+ $('#desafioShowCodeAccess').on('change', function () {
+ const marcado = $(this).is(':checked');
+ $('#desafioCodeAccess').prop('disabled', !marcado);
+ $('#desafioMessageCodeAccess').prop('disabled', !marcado);
+ });
+
+ $('#desafioEAdd').on('click', function (e) {
+ e.preventDefault();
+ $exeDevice.addChallenge();
+ });
+
+ $('#desafioEFirst').on('click', function (e) {
+ e.preventDefault();
+ $exeDevice.firstChallenge();
+ });
+
+ $('#desafioEPrevious').on('click', function (e) {
+ e.preventDefault();
+ $exeDevice.previousChallenge();
+ });
+
+ $('#desafioENext').on('click', function (e) {
+ e.preventDefault();
+ $exeDevice.nextChallenge();
+ });
+
+ $('#desafioELast').on('click', function (e) {
+ e.preventDefault();
+ $exeDevice.lastChallenge();
+ });
+
+ $('#desafioEDelete').on('click', function (e) {
+ e.preventDefault();
+ $exeDevice.removeChallenge();
+ });
+
+ $('#desafioECopy').on('click', function (e) {
+ e.preventDefault();
+ $exeDevice.copyChallenge();
+ });
+
+ $('#desafioECut').on('click', function (e) {
+ e.preventDefault();
+ $exeDevice.cutChallenge();
+ });
+
+ $('#desafioEPaste').on('click', function (e) {
+ e.preventDefault();
+ $exeDevice.pasteChallenge();
+ });
+
+ $('#desafioEDesafio').on('click', function () {
+ if ($exeDevice.typeActive != 0) {
+ $exeDevice.typeActive = 0;
+ $exeDevice.saveChallenge();
+ $exeDevice.showDesafio();
+ $exeDevice.showClues(false);
+ }
+ });
+
+ $('#desafioEReto').on('click', function () {
+ if ($exeDevice.typeActive != 1) {
+ $exeDevice.typeActive = 1;
+ $exeDevice.saveDesafio();
+ $exeDevice.showChallenge($exeDevice.active);
+ $exeDevice.showClues(true);
+ }
+ });
+
+ $('#desafioEEvaluation').on('change', function () {
+ const marcado = $(this).is(':checked');
+ $('#desafioEEvaluationID').prop('disabled', !marcado);
+ });
+
+ $('#desafioEEvaluationHelpLnk').on('click', function () {
+ $('#desafioEEvaluationHelp').toggle();
+ return false;
+ });
+
+ if (
+ window.File &&
+ window.FileReader &&
+ window.FileList &&
+ window.Blob
+ ) {
+ $('#eXeGameExportImport').show();
+ $('#eXeGameImportGame').on('change', function (e) {
+ const file = e.target.files[0];
+ if (!file) {
+ return;
+ }
+ const reader = new FileReader();
+ reader.onload = function (e) {
+ $exeDevice.importGame(e.target.result);
+ };
+ reader.readAsText(file);
+ });
+ $('#eXeGameExportGame').on('click', function () {
+ $exeDevice.exportGame();
+ });
+ } else {
+ $('#eXeGameExportImport').hide();
+ }
+ },
+
+ getDivChallenges: function (num) {
+ let chs = '';
+ for (let j = 0; j < num; j++) {
+ const ch = `
+
+
+
+
+ `;
+ chs += ch;
+ }
+
+ return chs;
+ },
+
+ getDivClues: function () {
+ const chs = `
+
+
+
+
+
+
+
+
+
+
+
+
+
+
`;
+ return chs;
+ },
+
+ getChallengeDefault: function () {
+ return {
+ title: '',
+ solution: '',
+ description: '',
+ };
+ },
+
+ loadPreviousValues: function () {
+ let originalHTML = this.idevicePreviousData;
+
+ if (originalHTML && Object.keys(originalHTML).length > 0) {
+ $exeDevice.active = 0;
+ const wrapper = $('
');
+ wrapper.html(originalHTML);
+
+ let json = $('.desafio-DataGame', wrapper).text(),
+ version = $('.desafio-version', wrapper).text();
+
+ if (version.length === 1 || !json.startsWith('{')) {
+ json = $exeDevices.iDevice.gamification.helpers.decrypt(json);
+ }
+
+ const dataGame =
+ $exeDevices.iDevice.gamification.helpers.isJsonString(json);
+ $exeDevice.desafioTitle = dataGame.desafioTitle;
+ $exeDevice.active = 0;
+ $exeDevice.desafioSolution = dataGame.desafioSolution;
+ $exeDevice.desafioType = dataGame.desafioType;
+ $exeDevice.desafioTime = dataGame.desafioTime;
+ $exeDevice.desafioDescription = '';
+
+ let description = $('.desafio-EDescription', wrapper);
+ if (description.length === 1) {
+ description = description.html() || '';
+ $('#desafioEDescription').val(description);
+ $exeDevice.desafioDescription = description;
+ }
+
+ $('.desafio-ChallengeDescription', wrapper).each(function (i) {
+ dataGame.challengesGame[i].description = $(this).html();
+ $(`#desafioEChallenge-${i}`).val($(this).html());
+ });
+
+ $exeDevice.challengesGame = dataGame.challengesGame;
+
+ const c = $exeDevice.challengesGame[0];
+ $('#desafioECTitle').val(c.title);
+ $('#desafioECSolution').val(c.solution);
+
+ if (typeof c.clues !== 'undefined') {
+ $('#desafioEClue1').val(c.clues[0].clue);
+ $('#desafioEClue2').val(c.clues[1].clue);
+ $('#desafioEClue3').val(c.clues[2].clue);
+ $('#desafioECTime1').val(c.clues[0].time);
+ $('#desafioECTime2').val(c.clues[1].time);
+ $('#desafioECTime3').val(c.clues[2].time);
+ }
+
+ const instructions = $('.desafio-instructions', wrapper);
+ if (instructions.length === 1) {
+ $('#eXeGameInstructions').val(instructions.html());
+ }
+
+ $exeDevicesEdition.iDevice.gamification.common.setLanguageTabValues(
+ dataGame.msgs
+ );
+ $exeDevice.updateFieldGame(dataGame);
+ }
+ },
+
+ updateFieldGame: function (game) {
+ $exeDevice.desafioID =
+ typeof game.desafioID === 'undefined'
+ ? $exeDevice.desafioID
+ : game.desafioID;
+ game.evaluation =
+ typeof game.evaluation !== 'undefined' ? game.evaluation : false;
+ game.evaluationID =
+ typeof game.evaluationID !== 'undefined' ? game.evaluationID : '';
+ game.weighted =
+ typeof game.weighted !== 'undefined' ? game.weighted : 100;
+ $exeDevice.id = $exeDevice.getIdeviceID();
+
+ $('#desafioEShowMinimize').prop('checked', game.showMinimize);
+ $('#desafioEEvaluation').prop('checked', game.evaluation);
+ $('#desafioEEvaluationID').val(game.evaluationID);
+ $('#desafioEEvaluationID').prop('disabled', !game.evaluation);
+ $exeDevicesEdition.iDevice.gamification.scorm.setValues(
+ game.isScorm,
+ game.textButtonScorm,
+ game.repeatActivity,
+ game.weighted
+ );
+ $exeDevice.showDesafio();
+ },
+
+ escapeHtml: function (string) {
+ return String(string)
+ .replace(/&/g, '&')
+ .replace(//g, '>')
+ .replace(/"/g, '"')
+ .replace(/'/g, ''');
+ },
+
+ save: function () {
+ const dataGame = this.validateData();
+
+ if (!dataGame) return false;
+
+ const fields = this.ci18n,
+ i18n = fields;
+ for (const i in fields) {
+ const fVal = $('#ci18n_' + i).val();
+ if (fVal !== '') i18n[i] = fVal;
+ }
+
+ dataGame.msgs = i18n;
+ let json = JSON.stringify(dataGame);
+
+ json = $exeDevices.iDevice.gamification.helpers.encrypt(json);
+
+ const instructions = tinyMCE.get('eXeGameInstructions').getContent(),
+ description = tinyMCE.get('desafioEDescription').getContent();
+ let divContent = '';
+ if (instructions !== '') {
+ divContent =
+ '
' + instructions + '
';
+ }
+
+ let html = '
';
+ html += `
`;
+ html += divContent;
+ html +=
+ '
' +
+ $exeDevice.desafioVersion +
+ '
';
+ html += '
' + description + '
';
+ for (let i = 0; i < $exeDevice.challengesGame.length; i++) {
+ const df = tinyMCE.get(`desafioEChallenge-${i}`).getContent();
+ html +=
+ '
' + df + '
';
+ }
+ html += '
' + json + '
';
+
+ html +=
+ '
' +
+ $exeDevice.msgs.msgNoSuportBrowser +
+ '
';
+
+ html += '
';
+ return html;
+ },
+
+ saveChallenge: function () {
+ let message = '';
+ const p = {},
+ i = $exeDevice.active;
+
+ if (tinyMCE.get(`desafioEChallenge-${i}`)) {
+ p.description = tinyMCE.get(`desafioEChallenge-${i}`).getContent();
+ } else {
+ p.description = $(`desafioEChallenge-${i}`).val();
+ }
+
+ p.title = $('#desafioECTitle').val();
+ p.solution = $('#desafioECSolution').val();
+ p.timeShow = -1;
+
+ const clues = [
+ {
+ clue: $('#desafioEClue1').val(),
+ time: parseInt($('#desafioECTime1 option:selected').val(), 10),
+ },
+ {
+ clue: $('#desafioEClue2').val(),
+ time: parseInt($('#desafioECTime2 option:selected').val(), 10),
+ },
+ {
+ clue: $('#desafioEClue3').val(),
+ time: parseInt($('#desafioECTime3 option:selected').val(), 10),
+ },
+ ];
+ p.clues = clues;
+ $exeDevice.challengesGame[i] = p;
+ return message;
+ },
+
+ saveDesafio: function () {
+ $exeDevice.desafioTitle = $('#desafioEDTitle').val();
+ $exeDevice.desafioSolution = $('#desafioEDSolution').val();
+ $exeDevice.desafioType = parseInt(
+ $('#desafioEDType option:selected').val()
+ );
+ $exeDevice.desafioTime = parseInt(
+ $('#desafioEDTime option:selected').val()
+ );
+ $exeDevice.desafioDescription = '';
+
+ if (tinyMCE.get('desafioEDescription')) {
+ $exeDevice.desafioDescription = tinyMCE
+ .get('desafioEDescription')
+ .getContent();
+ } else {
+ $exeDevice.desafioDescription = $('#desafioEDescription').val();
+ }
+ },
+
+ exportGame: function () {
+ const dataGame = this.validateData();
+ if (!dataGame) {
+ return false;
+ }
+
+ const blob = JSON.stringify(dataGame),
+ newBlob = new Blob([blob], { type: 'text/plain' });
+ if (window.navigator && window.navigator.msSaveOrOpenBlob) {
+ window.navigator.msSaveOrOpenBlob(newBlob);
+ return;
+ }
+
+ const data = window.URL.createObjectURL(newBlob),
+ link = document.createElement('a');
+
+ link.href = data;
+ link.download = `${_('Game')}desafio.json`;
+ document.getElementById('desafioIdeviceForm').appendChild(link);
+ link.click();
+
+ setTimeout(() => {
+ document.getElementById('desafioIdeviceForm').removeChild(link);
+ window.URL.revokeObjectURL(data);
+ }, 100);
+ },
+
+ importGame: function (content) {
+ const game =
+ $exeDevices.iDevice.gamification.helpers.isJsonString(content);
+
+ if (!game || typeof game.typeGame === 'undefined') {
+ $exeDevice.showMessage($exeDevice.msgs.msgESelectFile);
+ return;
+ } else if (game.typeGame !== 'desafio') {
+ $exeDevice.showMessage($exeDevice.msgs.msgESelectFile);
+ return;
+ }
+
+ game.id = $exeDevice.getIdeviceID();
+ $exeDevice.active = 0;
+ $exeDevice.desafioTitle = game.desafioTitle;
+ $exeDevice.desafioSolution = game.desafioSolution;
+ $exeDevice.desafioDescription = game.desafioDescription;
+ $exeDevice.desafioType = game.desafioType;
+ $exeDevice.desafioTime = game.desafioTime;
+
+ $exeDevice.challengesGame = game.challengesGame;
+ $exeDevice.updateFieldGame(game);
+ const instructions = game.instructionsExe || game.instructions;
+ tinymce.editors[0].setContent(instructions);
+ //$('.exe-form-tabs li:first-child a').click();
+ },
+
+ getIdeviceID: function () {
+ const ideviceid =
+ $('#desafioIdeviceForm')
+ .closest(`div.idevice_node.${$exeDevice.classIdevice}`)
+ .attr('id') || '';
+
+ return ideviceid;
+ },
+
+ validateData: function () {
+ $exeDevice.saveDesafio();
+ $exeDevice.saveChallenge();
+
+ const instructions = $('#eXeGameInstructions').text(),
+ instructionsExe = tinyMCE.get('eXeGameInstructions').getContent(),
+ showMinimize = $('#desafioEShowMinimize').is(':checked'),
+ evaluation = $('#desafioEEvaluation').is(':checked'),
+ evaluationID = $('#desafioEEvaluationID').val(),
+ id = $exeDevice.getIdeviceID();
+
+ if ($exeDevice.desafioTitle.length === 0) {
+ $exeDevice.showMessage($exeDevice.msgs.msgTitleDesafio);
+ return false;
+ } else if ($exeDevice.desafioSolution.length === 0) {
+ $exeDevice.showMessage($exeDevice.msgs.msgSolutionDesafio);
+ return false;
+ } else if ($exeDevice.desafioDescription.length === 0) {
+ $exeDevice.showMessage($exeDevice.msgs.msgDescriptionDesafio);
+ return false;
+ }
+
+ if (evaluation && evaluationID.length < 5) {
+ eXe.app.alert($exeDevice.msgs.msgIDLenght);
+ return false;
+ }
+
+ const challengesGame = $exeDevice.challengesGame;
+ for (let i = 0; i < challengesGame.length; i++) {
+ const mChallenge = challengesGame[i];
+ if (
+ mChallenge.title.length === 0 ||
+ mChallenge.solution.length === 0 ||
+ mChallenge.description.length === 0
+ ) {
+ $exeDevice.showMessage($exeDevice.msgs.msgDataChanllenge);
+ return false;
+ }
+ }
+
+ const scorm = $exeDevicesEdition.iDevice.gamification.scorm.getValues();
+
+ return {
+ asignatura: '',
+ author: '',
+ typeGame: 'desafio',
+ desafioTitle: $exeDevice.desafioTitle,
+ desafioTime: $exeDevice.desafioTime,
+ desafioType: $exeDevice.desafioType,
+ desafioSolution: $exeDevice.desafioSolution,
+ desafioSolved: false,
+ desafioDescription: $exeDevice.desafioDescription,
+ instructionsExe: instructionsExe,
+ instructions: instructions,
+ showMinimize: showMinimize,
+ challengesGame: challengesGame,
+ title: '',
+ isScorm: scorm.isScorm,
+ textButtonScorm: scorm.textButtonScorm,
+ repeatActivity: scorm.repeatActivity,
+ weighted: scorm.weighted || 100,
+ desafioID: $exeDevice.desafioID,
+ evaluation: evaluation,
+ evaluationID: evaluationID,
+ id: id,
+ };
+ },
+ showClues: function (show) {
+ if (show) {
+ $('#desafioEClues').show();
+ } else {
+ $('#desafioEClues').hide();
+ }
+ },
+
+ showDesafio: function () {
+ const hide = (sel) => $(sel).addClass('js-hidden');
+ const show = (sel) => $(sel).removeClass('js-hidden');
+
+ show('label[for="desafioEDSolution"], #desafioEDSolution');
+ show('label[for="desafioEDTitle"], #desafioEDTitle');
+ hide('label[for="desafioECTitle"], #desafioECTitle');
+ hide('label[for="desafioECSolution"], #desafioECSolution');
+
+ $exeDevice.typeActive = 0;
+ $('#desafioSelects').css('display', 'flex');
+ $('#desafioENavigationButtons').hide();
+ $('#desafioENumQuestionDiv').hide();
+ $('#desafioEDTitle').val($exeDevice.desafioTitle);
+ $('#desafioEDSolution').val($exeDevice.desafioSolution);
+ $('#desafioEDTime').val($exeDevice.desafioTime);
+ $('#desafioEDType').val($exeDevice.desafioType);
+ $('#divDesafioEDescription').show();
+ $('#desafioEChallenges').hide();
+ },
+};
diff --git a/vendor/exelearning/export-resources/idevices/challenge/edition/challenge.test.js b/vendor/exelearning/export-resources/idevices/challenge/edition/challenge.test.js
new file mode 100644
index 0000000..307af6c
--- /dev/null
+++ b/vendor/exelearning/export-resources/idevices/challenge/edition/challenge.test.js
@@ -0,0 +1,480 @@
+/**
+ * Unit tests for challenge iDevice
+ *
+ * Tests pure functions that don't depend on DOM manipulation:
+ * - escapeHtml: HTML character escaping
+ * - getChallengeDefault: Default challenge object structure
+ * - getId: Unique ID generation
+ */
+
+/* eslint-disable no-undef */
+import { readFileSync } from 'fs';
+import { fileURLToPath } from 'url';
+import { dirname, join } from 'path';
+
+const __filename = fileURLToPath(import.meta.url);
+const __dirname = dirname(__filename);
+
+/**
+ * Helper to load iDevice file and expose $exeDevice globally.
+ * Replaces 'var $exeDevice' with 'global.$exeDevice' to make it accessible.
+ */
+function loadIdevice(code) {
+ // Replace 'var $exeDevice' with 'global.$exeDevice' anywhere in the code
+ const modifiedCode = code.replace(/var\s+\$exeDevice\s*=/, 'global.$exeDevice =');
+ // Execute the modified code using eval in global context
+ // eslint-disable-next-line no-eval
+ (0, eval)(modifiedCode);
+ return global.$exeDevice;
+}
+
+describe('challenge iDevice', () => {
+ let $exeDevice;
+
+ beforeEach(() => {
+ // Reset $exeDevice before loading
+ global.$exeDevice = undefined;
+
+ // Read and execute the iDevice file
+ const filePath = join(__dirname, 'challenge.js');
+ const code = readFileSync(filePath, 'utf-8');
+
+ // Load iDevice and get reference
+ $exeDevice = loadIdevice(code);
+ });
+
+ describe('escapeHtml', () => {
+ it('escapes ampersand', () => {
+ expect($exeDevice.escapeHtml('foo & bar')).toBe('foo & bar');
+ });
+
+ it('escapes less than', () => {
+ expect($exeDevice.escapeHtml('a < b')).toBe('a < b');
+ });
+
+ it('escapes greater than', () => {
+ expect($exeDevice.escapeHtml('a > b')).toBe('a > b');
+ });
+
+ it('escapes double quotes', () => {
+ expect($exeDevice.escapeHtml('say "hello"')).toBe('say "hello"');
+ });
+
+ it('escapes single quotes', () => {
+ expect($exeDevice.escapeHtml("it's")).toBe('it's');
+ });
+
+ it('escapes multiple special characters', () => {
+ const input = '';
+ const expected = '<script>alert("xss")</script>';
+ expect($exeDevice.escapeHtml(input)).toBe(expected);
+ });
+
+ it('returns empty string for empty input', () => {
+ expect($exeDevice.escapeHtml('')).toBe('');
+ });
+
+ it('handles string with no special characters', () => {
+ expect($exeDevice.escapeHtml('hello world')).toBe('hello world');
+ });
+ });
+
+ describe('getChallengeDefault', () => {
+ it('returns an object with title, solution and description', () => {
+ const challenge = $exeDevice.getChallengeDefault();
+ expect(challenge).toHaveProperty('title');
+ expect(challenge).toHaveProperty('solution');
+ expect(challenge).toHaveProperty('description');
+ });
+
+ it('returns empty strings for all properties', () => {
+ const challenge = $exeDevice.getChallengeDefault();
+ expect(challenge.title).toBe('');
+ expect(challenge.solution).toBe('');
+ expect(challenge.description).toBe('');
+ });
+
+ it('returns a new object each time', () => {
+ const c1 = $exeDevice.getChallengeDefault();
+ const c2 = $exeDevice.getChallengeDefault();
+ expect(c1).not.toBe(c2);
+ });
+ });
+
+ describe('getId', () => {
+ it('returns a number', () => {
+ const id = $exeDevice.getId();
+ expect(typeof id).toBe('number');
+ });
+
+ it('returns different IDs when time or random changes', () => {
+ // Mock Date and Math.random for deterministic testing
+ const originalDate = global.Date;
+ const originalRandom = Math.random;
+
+ // First call: timestamp 1000, random 0.5
+ global.Date = class extends originalDate {
+ getTime() {
+ return 1000;
+ }
+ };
+ Math.random = () => 0.5;
+ const id1 = $exeDevice.getId();
+ expect(id1).toBe(Math.round(1000 + 0.5 * 100)); // 1050
+
+ // Second call: different timestamp
+ global.Date = class extends originalDate {
+ getTime() {
+ return 2000;
+ }
+ };
+ Math.random = () => 0.5;
+ const id2 = $exeDevice.getId();
+ expect(id2).toBe(Math.round(2000 + 0.5 * 100)); // 2050
+
+ // IDs should be different
+ expect(id1).not.toBe(id2);
+
+ // Restore originals
+ global.Date = originalDate;
+ Math.random = originalRandom;
+ });
+
+ it('returns a positive number', () => {
+ const id = $exeDevice.getId();
+ expect(id).toBeGreaterThan(0);
+ });
+ });
+
+ describe('i18n', () => {
+ it('is defined', () => {
+ expect($exeDevice.i18n).toBeDefined();
+ });
+
+ it('has name defined', () => {
+ expect($exeDevice.i18n.name).toBeDefined();
+ });
+ });
+
+ describe('ci18n', () => {
+ it('is defined', () => {
+ expect($exeDevice.ci18n).toBeDefined();
+ });
+ });
+
+ describe('validateData', () => {
+ it('exists as a function', () => {
+ expect(typeof $exeDevice.validateData).toBe('function');
+ });
+ });
+
+ describe('showMessage', () => {
+ it('exists as a function', () => {
+ expect(typeof $exeDevice.showMessage).toBe('function');
+ });
+ });
+
+ describe('addChallenge', () => {
+ it('exists as a function', () => {
+ expect(typeof $exeDevice.addChallenge).toBe('function');
+ });
+ });
+
+ describe('removeChallenge', () => {
+ it('exists as a function', () => {
+ expect(typeof $exeDevice.removeChallenge).toBe('function');
+ });
+ });
+
+ describe('copyChallenge', () => {
+ it('exists as a function', () => {
+ expect(typeof $exeDevice.copyChallenge).toBe('function');
+ });
+ });
+
+ describe('cutChallenge', () => {
+ it('exists as a function', () => {
+ expect(typeof $exeDevice.cutChallenge).toBe('function');
+ });
+ });
+
+ describe('pasteChallenge', () => {
+ it('exists as a function', () => {
+ expect(typeof $exeDevice.pasteChallenge).toBe('function');
+ });
+ });
+
+ describe('clearChallenge', () => {
+ it('exists as a function', () => {
+ expect(typeof $exeDevice.clearChallenge).toBe('function');
+ });
+ });
+
+ // ============================================
+ // DOM Manipulation Tests
+ // ============================================
+
+ describe('clearChallenge - DOM', () => {
+ beforeEach(() => {
+ document.body.innerHTML = `
+
+
+
+
+ `;
+ });
+
+ it('clears title field', () => {
+ $exeDevice.clearChallenge();
+ expect($('#desafioECTitle').val()).toBe('');
+ });
+
+ it('clears solution field', () => {
+ $exeDevice.clearChallenge();
+ expect($('#desafioECSolution').val()).toBe('');
+ });
+
+ it('clears message field', () => {
+ $exeDevice.clearChallenge();
+ expect($('#desafioECMessage').val()).toBe('');
+ });
+
+ it('sets default time value to 5', () => {
+ $exeDevice.clearChallenge();
+ expect($('#desafioECTime').val()).toBe('5');
+ });
+ });
+
+ describe('addChallenge - DOM', () => {
+ beforeEach(() => {
+ document.body.innerHTML = `
+
1
+
1
+
+
+
+
+
+
+
+ `;
+ $exeDevice.challengesGame = [{ title: 'Test', solution: 'sol', description: '' }];
+ $exeDevice.active = 0;
+ $exeDevice.numberId = 0;
+ $exeDevice.typeEdit = -1;
+ $exeDevice.msgs = { msgTenChallenges: 'Max 10 challenges' };
+ // Mock saveChallenge to avoid TinyMCE calls
+ $exeDevice.saveChallenge = () => {};
+ });
+
+ it('adds new challenge to array', () => {
+ $exeDevice.addChallenge();
+ expect($exeDevice.challengesGame.length).toBe(2);
+ });
+
+ it('updates challenge counter', () => {
+ $exeDevice.addChallenge();
+ expect($('#desafioENumChallenges').text()).toBe('2');
+ });
+
+ it('updates current challenge number', () => {
+ $exeDevice.addChallenge();
+ expect($('#desafioENumberChallenge').text()).toBe('2');
+ });
+
+ it('hides paste button', () => {
+ $exeDevice.addChallenge();
+ expect($('#desafioEPaste').is(':visible')).toBe(false);
+ });
+
+ it('does not exceed 10 challenges', () => {
+ $exeDevice.challengesGame = Array(10).fill({ title: '', solution: '', description: '' });
+ const alertSpy = vi.spyOn(eXe.app, 'alert');
+ $exeDevice.addChallenge();
+ expect($exeDevice.challengesGame.length).toBe(10);
+ expect(alertSpy).toHaveBeenCalled();
+ });
+ });
+
+ describe('removeChallenge - DOM', () => {
+ beforeEach(() => {
+ document.body.innerHTML = `
+
2
+
3
+
+
+
+
+
+
+
+
+
+
+ `;
+ $exeDevice.challengesGame = [
+ { title: '1', solution: 's1', description: '' },
+ { title: '2', solution: 's2', description: '' },
+ { title: '3', solution: 's3', description: '' },
+ ];
+ $exeDevice.active = 1;
+ $exeDevice.typeEdit = -1;
+ $exeDevice.msgs = { msgOneChallenge: 'Need at least 1' };
+ // Mock functions
+ $exeDevice.saveChallenge = () => {};
+ $exeDevice.updateFeedBack = () => {};
+ });
+
+ it('removes challenge from array', () => {
+ $exeDevice.removeChallenge();
+ expect($exeDevice.challengesGame.length).toBe(2);
+ });
+
+ it('updates challenge counter', () => {
+ $exeDevice.removeChallenge();
+ expect($('#desafioENumChallenges').text()).toBe('2');
+ });
+
+ it('hides paste button', () => {
+ $exeDevice.removeChallenge();
+ expect($('#desafioEPaste').is(':visible')).toBe(false);
+ });
+
+ it('prevents removing last challenge', () => {
+ $exeDevice.challengesGame = [{ title: 'Only', solution: 's', description: '' }];
+ $exeDevice.active = 0;
+ const alertSpy = vi.spyOn(eXe.app, 'alert');
+ $exeDevice.removeChallenge();
+ expect($exeDevice.challengesGame.length).toBe(1);
+ expect(alertSpy).toHaveBeenCalled();
+ });
+ });
+
+ describe('copyChallenge - DOM', () => {
+ beforeEach(() => {
+ document.body.innerHTML = `
+
+ `;
+ $exeDevice.challengesGame = [
+ { title: 'Copy me', solution: 'sol', description: 'desc' },
+ ];
+ $exeDevice.active = 0;
+ $exeDevice.clipBoard = null;
+ $exeDevice.saveChallenge = () => {};
+ });
+
+ it('copies current challenge to clipboard', () => {
+ $exeDevice.copyChallenge();
+ expect($exeDevice.clipBoard.title).toBe('Copy me');
+ });
+
+ it('shows paste button', () => {
+ $exeDevice.copyChallenge();
+ // jQuery .show() sets display to empty string or block
+ expect($('#desafioEPaste').css('display')).not.toBe('none');
+ });
+
+ it('sets typeEdit to 0 (copy mode)', () => {
+ $exeDevice.copyChallenge();
+ expect($exeDevice.typeEdit).toBe(0);
+ });
+
+ it('creates a deep copy (not same reference)', () => {
+ $exeDevice.copyChallenge();
+ expect($exeDevice.clipBoard).not.toBe($exeDevice.challengesGame[0]);
+ });
+ });
+
+ describe('cutChallenge - DOM', () => {
+ beforeEach(() => {
+ document.body.innerHTML = `
+
+ `;
+ $exeDevice.challengesGame = [{ title: 'A' }, { title: 'B' }];
+ $exeDevice.active = 1;
+ $exeDevice.saveChallenge = () => {};
+ });
+
+ it('sets numberCutCuestion to active index', () => {
+ $exeDevice.cutChallenge();
+ expect($exeDevice.numberCutCuestion).toBe(1);
+ });
+
+ it('shows paste button', () => {
+ $exeDevice.cutChallenge();
+ // jQuery .show() sets display to empty string or block
+ expect($('#desafioEPaste').css('display')).not.toBe('none');
+ });
+
+ it('sets typeEdit to 1 (cut mode)', () => {
+ $exeDevice.cutChallenge();
+ expect($exeDevice.typeEdit).toBe(1);
+ });
+ });
+
+ describe('showChallenge - DOM', () => {
+ beforeEach(() => {
+ document.body.innerHTML = `
+
+
+
+
+
+
+
+
+
+
0
+
0
+
+
+
+
+
+
+ `;
+ $exeDevice.challengesGame = [
+ { title: 'Challenge 1', solution: 'Sol 1', description: 'Desc 1' },
+ { title: 'Challenge 2', solution: 'Sol 2', description: 'Desc 2' },
+ ];
+ $exeDevice.active = 0;
+ });
+
+ it('populates title field with challenge data', () => {
+ $exeDevice.showChallenge(0);
+ expect($('#desafioECTitle').val()).toBe('Challenge 1');
+ });
+
+ it('populates solution field with challenge data', () => {
+ $exeDevice.showChallenge(0);
+ expect($('#desafioECSolution').val()).toBe('Sol 1');
+ });
+
+ it('shows navigation buttons', () => {
+ $exeDevice.showChallenge(0);
+ // jQuery .show() sets display to empty string or block
+ expect($('#desafioENavigationButtons').css('display')).not.toBe('none');
+ });
+
+ it('shows correct feedback div for index', () => {
+ $exeDevice.showChallenge(1);
+ // jQuery .show() sets display to empty string or block
+ expect($('#desafioEDivFeebBack-1').css('display')).not.toBe('none');
+ });
+
+ it('updates challenge counter', () => {
+ $exeDevice.showChallenge(1);
+ expect($('#desafioENumChallenges').text()).toBe('2');
+ });
+
+ it('handles negative index by clamping to 0', () => {
+ $exeDevice.showChallenge(-5);
+ expect($('#desafioECTitle').val()).toBe('Challenge 1');
+ });
+
+ it('handles index beyond array length by clamping to last', () => {
+ $exeDevice.showChallenge(100);
+ expect($('#desafioECTitle').val()).toBe('Challenge 2');
+ });
+ });
+});
diff --git a/vendor/exelearning/export-resources/idevices/challenge/edition/quext-last.png b/vendor/exelearning/export-resources/idevices/challenge/edition/quext-last.png
new file mode 100644
index 0000000..2778d88
Binary files /dev/null and b/vendor/exelearning/export-resources/idevices/challenge/edition/quext-last.png differ
diff --git a/vendor/exelearning/export-resources/idevices/challenge/edition/quextIEAdd.png b/vendor/exelearning/export-resources/idevices/challenge/edition/quextIEAdd.png
new file mode 100644
index 0000000..c5280b6
Binary files /dev/null and b/vendor/exelearning/export-resources/idevices/challenge/edition/quextIEAdd.png differ
diff --git a/vendor/exelearning/export-resources/idevices/challenge/edition/quextIECopy.png b/vendor/exelearning/export-resources/idevices/challenge/edition/quextIECopy.png
new file mode 100644
index 0000000..57dab4f
Binary files /dev/null and b/vendor/exelearning/export-resources/idevices/challenge/edition/quextIECopy.png differ
diff --git a/vendor/exelearning/export-resources/idevices/challenge/edition/quextIECut.png b/vendor/exelearning/export-resources/idevices/challenge/edition/quextIECut.png
new file mode 100644
index 0000000..4af1b42
Binary files /dev/null and b/vendor/exelearning/export-resources/idevices/challenge/edition/quextIECut.png differ
diff --git a/vendor/exelearning/export-resources/idevices/challenge/edition/quextIEDelete.png b/vendor/exelearning/export-resources/idevices/challenge/edition/quextIEDelete.png
new file mode 100644
index 0000000..17346f8
Binary files /dev/null and b/vendor/exelearning/export-resources/idevices/challenge/edition/quextIEDelete.png differ
diff --git a/vendor/exelearning/export-resources/idevices/challenge/edition/quextIEFirst.png b/vendor/exelearning/export-resources/idevices/challenge/edition/quextIEFirst.png
new file mode 100644
index 0000000..9862605
Binary files /dev/null and b/vendor/exelearning/export-resources/idevices/challenge/edition/quextIEFirst.png differ
diff --git a/vendor/exelearning/export-resources/idevices/challenge/edition/quextIEHelp.png b/vendor/exelearning/export-resources/idevices/challenge/edition/quextIEHelp.png
new file mode 100644
index 0000000..a6475b4
Binary files /dev/null and b/vendor/exelearning/export-resources/idevices/challenge/edition/quextIEHelp.png differ
diff --git a/vendor/exelearning/export-resources/idevices/challenge/edition/quextIELast.png b/vendor/exelearning/export-resources/idevices/challenge/edition/quextIELast.png
new file mode 100644
index 0000000..2778d88
Binary files /dev/null and b/vendor/exelearning/export-resources/idevices/challenge/edition/quextIELast.png differ
diff --git a/vendor/exelearning/export-resources/idevices/challenge/edition/quextIENext.png b/vendor/exelearning/export-resources/idevices/challenge/edition/quextIENext.png
new file mode 100644
index 0000000..2ea0306
Binary files /dev/null and b/vendor/exelearning/export-resources/idevices/challenge/edition/quextIENext.png differ
diff --git a/vendor/exelearning/export-resources/idevices/challenge/edition/quextIENumber.png b/vendor/exelearning/export-resources/idevices/challenge/edition/quextIENumber.png
new file mode 100644
index 0000000..11f5fab
Binary files /dev/null and b/vendor/exelearning/export-resources/idevices/challenge/edition/quextIENumber.png differ
diff --git a/vendor/exelearning/export-resources/idevices/challenge/edition/quextIEPaste.png b/vendor/exelearning/export-resources/idevices/challenge/edition/quextIEPaste.png
new file mode 100644
index 0000000..f81506b
Binary files /dev/null and b/vendor/exelearning/export-resources/idevices/challenge/edition/quextIEPaste.png differ
diff --git a/vendor/exelearning/export-resources/idevices/challenge/edition/quextIEPlay.png b/vendor/exelearning/export-resources/idevices/challenge/edition/quextIEPlay.png
new file mode 100644
index 0000000..c321493
Binary files /dev/null and b/vendor/exelearning/export-resources/idevices/challenge/edition/quextIEPlay.png differ
diff --git a/vendor/exelearning/export-resources/idevices/challenge/edition/quextIEPrev.png b/vendor/exelearning/export-resources/idevices/challenge/edition/quextIEPrev.png
new file mode 100644
index 0000000..8beaa8f
Binary files /dev/null and b/vendor/exelearning/export-resources/idevices/challenge/edition/quextIEPrev.png differ
diff --git a/vendor/exelearning/export-resources/idevices/challenge/edition/quick-questions-multiple-choice.js b/vendor/exelearning/export-resources/idevices/challenge/edition/quick-questions-multiple-choice.js
new file mode 100644
index 0000000..e69de29
diff --git a/vendor/exelearning/export-resources/idevices/challenge/export/challenge.css b/vendor/exelearning/export-resources/idevices/challenge/export/challenge.css
new file mode 100644
index 0000000..2a587b0
--- /dev/null
+++ b/vendor/exelearning/export-resources/idevices/challenge/export/challenge.css
@@ -0,0 +1,596 @@
+.desafio-MainContainer a:link,
+.desafio-MainContainer a:link,
+.desafio-MainContainer a:visited,
+.desafio-MainContainer a:focus {
+ border: 0;
+ border-bottom: none;
+ border-width: 0;
+ outline: none;
+ outline-width: 0;
+ text-decoration: none !important;
+}
+
+/* Contenedor */
+
+.desafio-MainContainer {
+ font-size: 1em;
+ margin: 0 auto;
+ max-width: 900px;
+ padding: 0;
+ width: 100%;
+}
+
+.desafio-MainContainer * {
+ box-sizing: border-box;
+}
+
+.desafio-MainContainer p {
+ margin: 0 !important;
+ padding: 0 !important;
+}
+
+/* Instrucciones */
+
+.desafio-instructions {
+ margin: 0.3em auto;
+ width: 100%;
+}
+
+.desafio-instructions p {
+ font-size: 1em;
+}
+
+/* Minimizado */
+
+.desafio-LinkMaximize {
+ align-items: center;
+ display: flex;
+ justify-content: center;
+ width: 100%;
+}
+
+.desafio-GameMinimize {
+ margin: 0.3em auto;
+}
+
+.desafio-IconMinimize {
+ height: 2em;
+ margin-right: 0.3em;
+ width: 2em;
+}
+
+/* Juego */
+
+.desafio-GameContainer {
+ margin: 0.5em auto;
+ min-width: 220px;
+ padding: 0.3em;
+ position: relative;
+ width: 100%;
+}
+
+/* barra superior */
+
+.desafio-GameScoreBoard {
+ align-content: center;
+ align-items: center;
+ display: flex;
+ justify-content: space-between;
+ margin: 0.4em auto;
+ margin-bottom: 1em;
+ width: 98%;
+}
+
+.desafio-GameScoreBoard p {
+ font-size: 1.4em !important;
+ margin-right: 0.3em !important;
+ text-align: center;
+ vertical-align: middle;
+}
+
+.desafio-GameChallenges {
+ align-items: center;
+ display: flex;
+ flex-wrap: wrap;
+ justify-content: start;
+ width: 70%;
+}
+
+.desafio-LinkDesafio,
+.desafio-LinkChallenge {
+ display: inline-block;
+ margin-right: 0.2em;
+ width: 1.5em;
+ height: 1.5em;
+}
+
+.desafio-GameDesafio {
+ background-image: url(desafioicon2.png);
+ background-size: 100% 100%;
+ height: 1.5em;
+ width: 1.5em;
+}
+
+/* Reloj, Minimizar */
+
+.desafio-TimeNumber {
+ align-items: center;
+ display: flex;
+ justify-content: flex-end;
+}
+
+.desafio-LinkMinimize {
+ height: 1.5em;
+ width: 1.5em;
+}
+
+.desafio-PTime {
+ font-size: 1em;
+ margin: auto 0.3em;
+ min-width: 5em;
+ text-align: center;
+}
+
+.exeQuextRetos,
+.exeQuextIcons34 {
+ height: 1.5em;
+ margin-right: .3em;
+ width: 1.5em;
+}
+
+.desafio-GameScoreBoard .exeQuextIcons34 {
+ height: 1.5em;
+ width: 1.5em;
+}
+
+.desafio-GameScoreBoard .exeQuextIcons34-Time {
+ background-image: url(exequexttime.svg);
+ background-size: 100% 100%;
+}
+
+.desafio-GameScoreBoard .exeQuextIcons34-Minimize {
+ background-image: url(exequextmin.svg);
+ background-size: 100% 100%;
+}
+
+/* Multimedia */
+
+.desafio-Multimedia {
+ margin: 0.3em auto;
+ overflow: hidden;
+ position: relative;
+ width: 65%;
+}
+
+.desafio-Multimedia:before {
+ content: '';
+ display: block;
+ padding-top: 56%;
+}
+
+/* Game Over */
+
+.desafio-GameOver {
+ align-items: center;
+ display: none;
+ flex-direction: column;
+ height: 100%;
+ justify-content: center;
+ left: 0;
+ position: absolute;
+ top: 0;
+ width: 100%;
+ z-index: 20;
+}
+
+.desafio-SolvedChallenges {
+ height: 1.5em;
+ margin: 0.3em auto 0.3em auto;
+ width: 100%;
+}
+
+.desafio-SolvedChallenges p {
+ color: #00ab00;
+ height: 100%;
+ text-align: center;
+ width: 100%;
+}
+
+.desafio-DataImageGameOver {
+ height: 90%;
+ width: 100%;
+}
+
+.desafio-HistGGame {
+ background-image: url(exequextwon.png);
+ background-size: 100% 100%;
+}
+
+.desafio-LostGGame {
+ background-image: url(exequextlost.png);
+ background-size: 100% 100%;
+}
+
+.desafio-HistGGame,
+.desafio-LostGGame {
+ margin: 0.5em auto;
+ max-width: 250px;
+ width: 40%;
+}
+
+.desafio-HistGGame:before,
+.desafio-LostGGame:before {
+ content: '';
+ display: block;
+ padding-top: 100%;
+}
+
+/* Desafio y retos */
+
+.desafio-Title {
+ background-color: transparent;
+ display: none;
+ margin: 0.3em auto;
+ overflow: hidden;
+ text-align: center;
+ font-weight: bold;
+ width: 98%;
+ z-index: 1;
+}
+
+.desafio-Description,
+.desafio-FeedBacks {
+ display: none;
+ margin: 0.3em auto;
+ max-height: 2000px;
+ min-height: 100px;
+ overflow: hidden;
+ padding: 0.3em;
+ width: 98%;
+ z-index: 1;
+}
+
+.desafio-StartGameDiv {
+ background-color: transparent;
+ display: flex;
+ justify-content: center;
+ margin: 0.3em auto;
+ width: 100%;
+}
+
+.desafio-Images {
+ height: 100%;
+ left: 0;
+ position: absolute;
+ top: 0;
+ width: 100%;
+}
+
+/* Botón inicio */
+
+.desafio-StartGame {
+ margin: 0.4em auto;
+ min-height: 2em;
+ padding: 0.4em;
+ text-align: center;
+ width: 98%;
+}
+
+/* Solucion */
+
+.desafio-SolutionDiv {
+ align-items: center;
+ display: flex;
+ justify-content: center;
+ margin-top: .6em;
+ width: 100%;
+}
+
+.desafio-Solution {
+ margin: 0 .3em;
+ max-width: 350px;
+ width: 60%;
+ text-align: center;
+}
+
+.desafio-SolutionDiv a {
+ width: 1.5em;
+ height: 1.5em;
+}
+
+.desafio-SolutionDiv .exeQuextIcons-Submit {
+ background-image: url(exequextreply.png);
+ background-size: 100% 100%;
+ width: 100%;
+ height: 100%;
+}
+
+.desafio-Clues {
+ margin-top: 0.8em;
+ font-size: 0.9em;
+}
+
+/* Mensaje */
+
+.desafio-MessageInfo {
+ margin: .3em auto;
+ width: 100%;
+}
+
+.desafio-MessageInfo p {
+ text-align: center;
+ width: 100%;
+}
+
+/* Fecha */
+
+.desafio-DateDiv {
+ align-items: center;
+ display: flex;
+ justify-content: space-between;
+ margin: 1.4em auto 0.3em auto;
+ width: 98%;
+}
+
+.desafio-DateDiv p {
+ font-size: 0.8em;
+ line-height: 1.5em;
+ margin-right: 0.5em;
+ padding-left: 0;
+}
+
+/* Retos */
+
+.desafio-LinkReboot {
+ height: 24px;
+ width: 24px;
+ display: inline-block;
+}
+
+.exeDesafio-IconReboot {
+ background-image: url(exequextreload.png);
+ background-size: 100% 100%;
+ height: 100%;
+ width: 100%;
+}
+
+.exeQuextRetos-C0 {
+ background: url(exeRetosIcons.png) no-repeat 0 0;
+}
+
+.exeQuextRetos-C1 {
+ background: url(exeRetosIcons.png) no-repeat -24px 0;
+}
+
+.exeQuextRetos-C2 {
+ background: url(exeRetosIcons.png) no-repeat -48px 0;
+}
+
+.exeQuextRetos-C3 {
+ background: url(exeRetosIcons.png) no-repeat -72px 0;
+}
+
+.exeQuextRetos-C4 {
+ background: url(exeRetosIcons.png) no-repeat -96px 0;
+}
+
+.exeQuextRetos-C5 {
+ background: url(exeRetosIcons.png) no-repeat -120px 0;
+}
+
+.exeQuextRetos-C6 {
+ background: url(exeRetosIcons.png) no-repeat -144px 0;
+}
+
+.exeQuextRetos-C7 {
+ background: url(exeRetosIcons.png) no-repeat -168px 0;
+}
+
+.exeQuextRetos-C8 {
+ background: url(exeRetosIcons.png) no-repeat -192px 0;
+}
+
+.exeQuextRetos-C9 {
+ background: url(exeRetosIcons.png) no-repeat -216px 0;
+}
+
+.desafio-Activo {
+ -webkit-filter: drop-shadow(.12em .12em .12em rgba(0, 0, 0, 0.5));
+ filter: drop-shadow(.12em .12em .12em rgba(0, 0, 0, 0.5));
+ cursor: pointer;
+ -moz-transition: transform 0.3s;
+ -ms-transition: transform 0.3s;
+ -o-transition: transform 0.3s;
+ -webkit-transition: transform 0.3s;
+ transition: transform 0.3s;
+}
+
+.desafio-Activo:hover {
+ -moz-transform: scale(1.1);
+ -ms-transform: scale(1.1);
+ -o-transform: scale(1.1);
+ -webkit-transform: scale(1.1);
+ transform: scale(1.1);
+}
+
+.desafio-BottonContainerDiv,
+.Games-BottonContainer {
+ align-items: center;
+ display: flex;
+ justify-content: flex-end;
+ margin: 0.1em auto;
+ padding: 0;
+ width: 100%;
+}
+
+.desafio-BottonContainerDivEnd {
+ justify-content: flex-end;
+}
+
+.Games-GetScore input[type=button] {
+ padding: 0.3em 0.5em;
+ margin-right: .5em;
+ width: auto;
+}
+
+.Games-GetScore span {
+ display: block;
+}
+
+.Games-GetScore form {
+ align-items: center;
+ display: flex;
+ justify-content: center;
+}
+
+.Games-BottonContainer {
+ margin: 0;
+ padding: 0;
+ width: 100%;
+}
+
+.Games-BottonContainer * {
+ margin: 0;
+ padding: 0;
+}
+
+
+.Games-GetScore {
+ align-items: center;
+ display: flex;
+ justify-content: center;
+ width: 100%;
+ margin-top: 1em
+}
+
+.Games-GetScore span {
+ display: block;
+}
+
+.Games-ReportIconDiv {
+ display: flex;
+ justify-content: flex-start;
+ align-items: center;
+ gap: 0.1em;
+ width: 100%;
+ margin-bottom: 6px;
+
+}
+
+.Games-ReportIconDiv img {
+ width: 16px;
+ height: 16px;
+ display: block;
+}
+
+.Games-ReportIconDiv span {
+ font-size: 0.9em;
+}
+
+@media screen and (max-width: 800px) {
+ .desafio-GameContainer {
+ font-size: 0.9rem;
+ }
+
+ .desafio-LinkDesafio,
+ .desafio-LinkMinimize,
+ .exeQuextIcons-Submit {
+ height: 24px;
+ width: 24px;
+ }
+}
+
+@media screen and (max-width:650px) {
+ .desafio-StartGame {
+ margin: 1em auto;
+ }
+
+ .desafio-GameScoreBoard {
+ align-items: center;
+ display: flex;
+ flex-direction: column-reverse;
+ flex-wrap: wrap;
+ justify-content: center;
+ margin-top: 0.1em;
+ width: 100%;
+ }
+
+ .desafio-LinkDesafio,
+ .desafio-LinkChallenge {
+ margin: .5em .3em 0 0;
+ }
+
+ .desafio-GameChallenges {
+ align-items: initial;
+ display: flex;
+ flex-wrap: wrap;
+ justify-content: center;
+ margin: 0 .3em;
+ margin-top: 0.6em;
+ width: 100%;
+ }
+
+ .desafio-HistGGame,
+ .desafio-LostGGame {
+ margin: 0.2em auto;
+ }
+}
+
+@media screen and (max-width:550px) {
+ .desafio-GameContainer {
+ font-size: 0.8rem;
+ }
+
+ .desafio-StartGame {
+ margin: 0.6em auto;
+ }
+
+ .desafio-instructions {
+ margin: 0.1em auto;
+ }
+
+ .desafio-instructions p {
+ font-size: 0.8em;
+ margin: 0 auto;
+ }
+
+ .desafio-GameContainer input[type="text"] {
+ background: #fdfdfd;
+ border: 1px solid #828282;
+ border-radius: 0.1em;
+ box-sizing: border-box;
+ display: inline-block;
+ font-size: 0.9em;
+ line-height: 1.1em;
+ padding: 0.1em 0.1em;
+ }
+
+ .desafio-GameContainer input[type="text"]:active,
+ .desafio-GameContainer input[type="text"]:focus {
+ background: #fdfdfd;
+ border: 1px solid #398ee7;
+ border-radius: 0.1em;
+ }
+}
+
+@media screen and (max-width:450px) {
+ .desafio-GameContainer {
+ font-size: 0.8rem;
+ }
+
+ .desafio-StartGame {
+ margin: 1em auto;
+ }
+}
+
+@media screen and (max-width:370px) {
+ .desafio-GameContainer {
+ font-size: 0.8rem;
+ }
+}
+
+@media screen and (max-width:250px) {
+ .desafio-GameContainer {
+ font-size: 0.6rem;
+ }
+}
\ No newline at end of file
diff --git a/vendor/exelearning/export-resources/idevices/challenge/export/challenge.js b/vendor/exelearning/export-resources/idevices/challenge/export/challenge.js
new file mode 100644
index 0000000..739f91c
--- /dev/null
+++ b/vendor/exelearning/export-resources/idevices/challenge/export/challenge.js
@@ -0,0 +1,1157 @@
+/* eslint-disable no-undef */
+/**
+ * QuExt Activity iDevice (export code)
+ * Released under Attribution-ShareAlike 4.0 International License.
+ * Author: Manuel Narváez Martínez
+ * Graphic design: Ana María Zamora Moreno, Francisco Javier Pulido
+ * License: http://creativecommons.org/licenses/by-sa/4.0/
+ */
+var $eXeDesafio = {
+ idevicePath: '',
+ borderColors: {
+ black: '#1c1b1b',
+ blue: '#5877c6',
+ green: '#2a9315',
+ red: '#ff0000',
+ white: '#ffffff',
+ yellow: '#f3d55a',
+ },
+ colors: {
+ black: '#1c1b1b',
+ blue: '#d5dcec',
+ green: '#cce1c8',
+ red: '#f7c4c4',
+ white: '#ffffff',
+ yellow: '#f5efd6',
+ },
+ image: '',
+ widthImage: 0,
+ heightImage: 0,
+ options: {},
+ msgs: '',
+ fontSize: '1em',
+ isInExe: false,
+ userName: '',
+ hasSCORMbutton: false,
+ previousScore: '',
+ initialScore: '',
+ scormAPIwrapper: 'libs/SCORM_API_wrapper.js',
+ scormFunctions: 'libs/SCOFunctions.js',
+ mScorm: null,
+
+ init: function () {
+ $exeDevices.iDevice.gamification.initGame(
+ this,
+ 'Challenge',
+ 'challenge',
+ 'desafio-IDevice'
+ );
+ },
+
+ saveEvaluation: function (instance) {
+ const mOptions = $eXeDesafio.options[instance],
+ points = mOptions.desafioSolved
+ ? mOptions.solvedsChallenges.length + 1
+ : mOptions.solvedsChallenges.length,
+ score = 10 * (points / (mOptions.challengesGame.length + 1));
+
+ mOptions.scorerp = score;
+
+ $exeDevices.iDevice.gamification.report.saveEvaluation(
+ mOptions,
+ $eXeDesafio.isInExe
+ );
+ },
+
+ sendScore: function (auto, instance) {
+ const mOptions = $eXeDesafio.options[instance],
+ points = mOptions.desafioSolved
+ ? mOptions.solvedsChallenges.length + 1
+ : mOptions.solvedsChallenges.length,
+ score = 10 * (points / (mOptions.challengesGame.length + 1));
+
+ mOptions.scorerp = score;
+ mOptions.previousScore = $eXeDesafio.previousScore;
+ mOptions.userName = $eXeDesafio.userName;
+
+ $exeDevices.iDevice.gamification.scorm.sendScoreNew(auto, mOptions);
+
+ $eXeDesafio.previousScore = mOptions.previousScore;
+ },
+
+ enable: function () {
+ $eXeDesafio.loadGame();
+ },
+
+ loadGame: function () {
+ $eXeDesafio.options = [];
+
+ $eXeDesafio.activities.each(function (i) {
+ const version = $('.desafio-version', this).eq(0).text(),
+ dl = $('.desafio-DataGame', this),
+ mOption = $eXeDesafio.loadDataGame(dl, version),
+ msg = mOption.msgs.msgPlayStart;
+
+ mOption.scorerp = 0;
+ mOption.idevicePath = $eXeDesafio.idevicePath;
+ mOption.main = 'desafioMainContainer-' + i;
+ mOption.idevice = 'desafio-IDevice';
+
+ $eXeDesafio.options.push(mOption);
+
+ const desafio = $eXeDesafio.createInterfaceChallenger(i);
+
+ dl.before(desafio).remove();
+ $('#desafioGameMinimize-' + i).show();
+ $('#desafioGameContainer-' + i).show();
+ if (mOption.showMinimize) {
+ $('#desafioGameContainer-' + i).hide();
+ } else {
+ $('#desafioGameMinimize-' + i).hide();
+ }
+
+ $('#desafioMessageMaximize-' + i).text(msg);
+ $('#desafioDescription-' + i).append(
+ $('.desafio-EDescription', this)
+ );
+ $('.desafio-ChallengeDescription', this).each(function () {
+ $('#desafioFeedBacks-' + i).append($(this));
+ });
+ $('#desafioDescription-' + i).hide();
+ $('#desafioFeedBacks-' + i).hide();
+
+ $eXeDesafio.addEvents(i);
+ });
+
+ let node = document.querySelector('.page-content');
+ if (this.isInExe) {
+ node = document.getElementById('node-content');
+ }
+ if (node)
+ $exeDevices.iDevice.gamification.observers.observeResize(
+ $eXeDesafio,
+ node
+ );
+
+ const html = $('.desafio-IDevice').html();
+ if ($exeDevices.iDevice.gamification.math.hasLatex(html)) {
+ $exeDevices.iDevice.gamification.math.updateLatex(
+ '.desafio-IDevice'
+ );
+ }
+ },
+
+ createInterfaceChallenger: function (instance) {
+ const path = $eXeDesafio.idevicePath,
+ mOptions = $eXeDesafio.options[instance],
+ msgs = $eXeDesafio.options[instance].msgs,
+ html = `
+
+ ${$exeDevices.iDevice.gamification.scorm.addButtonScoreNew(mOptions, this.isInExe)}
+ `;
+
+ return html;
+ },
+
+ createDesafiosLink: function (msgs, instance) {
+ const options = [...Array(10).keys()]
+ .map(
+ (i) => `
+
+ ${msgs.msgChallenge}:
+
+ `
+ )
+ .join('');
+ return options;
+ },
+
+ createArrayStateChallenges: function (type, mlength) {
+ let chs = [];
+ for (let i = 0; i < mlength; i++) {
+ let state = 0;
+ if (i === 0) {
+ state = 3;
+ } else if (type === 1) {
+ state = 1;
+ }
+ const p = {
+ solved: 0,
+ state: state,
+ };
+ chs.push(p);
+ }
+ return chs;
+ },
+
+ checkWord: function (word, answord) {
+ let sWord = word
+ .trim()
+ .replace(/\s+/g, ' ')
+ .toUpperCase()
+ .replace(/\.$/, '')
+ .replace(/,$/, '')
+ .replace(/;$/, ''),
+ sAnsWord = answord
+ .trim()
+ .replace(/\s+/g, ' ')
+ .toUpperCase()
+ .replace(/\.$/, '')
+ .replace(/,$/, '')
+ .replace(/;$/, '');
+
+ sWord = sWord.trim();
+ sAnsWord = sAnsWord.trim();
+
+ if (sWord.indexOf('|') === -1) return sWord === sAnsWord;
+
+ const words = sWord.split('|');
+ for (let i = 0; i < words.length; i++) {
+ const mword = words[i]
+ .trim()
+ .replace(/\.$/, '')
+ .replace(/,$/, '')
+ .replace(/;$/, '');
+ if (mword === sAnsWord) {
+ return true;
+ }
+ }
+ return false;
+ },
+
+ loadDataGame: function (data, version) {
+ let json = data.text();
+
+ if (version === 1 || !json.startsWith('{')) {
+ json = $exeDevices.iDevice.gamification.helpers.decrypt(json);
+ }
+
+ const mOptions =
+ $exeDevices.iDevice.gamification.helpers.isJsonString(json);
+
+ mOptions.gameOver = false;
+ mOptions.numberQuestions = mOptions.challengesGame.length;
+ mOptions.typeQuestion = 0;
+ mOptions.activeChallenge = 0;
+ mOptions.desafioDate = '';
+ mOptions.started = false;
+ mOptions.counter = 0;
+ mOptions.endGame = false;
+ mOptions.desafioSolved = false;
+ mOptions.solvedsChallenges = [];
+ mOptions.timesShow = [];
+ mOptions.stateChallenges = $eXeDesafio.createArrayStateChallenges(
+ mOptions.desafioType,
+ mOptions.challengesGame.length
+ );
+ mOptions.clueTimes = [];
+ mOptions.desafioID =
+ typeof mOptions.desafioID === 'undefined' ? 0 : mOptions.desafioID;
+ mOptions.evaluation =
+ typeof mOptions.evaluation === 'undefined'
+ ? false
+ : mOptions.evaluation;
+ mOptions.evaluationID =
+ typeof mOptions.evaluationID === 'undefined'
+ ? ''
+ : mOptions.evaluationID;
+ mOptions.id = typeof mOptions.id === 'undefined' ? false : mOptions.id;
+
+ for (let i = 0; i < mOptions.challengesGame.length; i++) {
+ mOptions.challengesGame[i].clueTimes = [];
+ mOptions.challengesGame[i].clueTexts = [];
+ mOptions.timesShow.push(10000000);
+ if (typeof mOptions.challengesGame[i].clues !== 'undefined') {
+ for (
+ let z = 0;
+ z < mOptions.challengesGame[i].clues.length;
+ z++
+ ) {
+ if (mOptions.challengesGame[i].clues[z].clue.length > 0) {
+ mOptions.challengesGame[i].clueTimes.push(
+ mOptions.challengesGame[i].clues[z].time * 60
+ );
+ mOptions.challengesGame[i].clueTexts.push(
+ mOptions.challengesGame[i].clues[z].clue
+ );
+ }
+ }
+ }
+ }
+
+ return mOptions;
+ },
+
+ changeImageButtonState: function (instance, type) {
+ const mOptions = $eXeDesafio.options[instance];
+
+ let imgDesafio = 'desafioicon0.png';
+
+ if (type === 0) imgDesafio = 'desafioicon1.png';
+
+ imgDesafio = `url(${$eXeDesafio.idevicePath}${imgDesafio}) no-repeat`;
+ $(`#desafioDesafio-${instance}`).find('.desafio-GameDesafio').css({
+ background: imgDesafio,
+ 'background-size': '100% 100%',
+ });
+
+ const $buttonChalleng = $(`#desafioGameChallenges-${instance}`).find(
+ '.desafio-LinkChallenge'
+ ),
+ l = 24,
+ t = 24,
+ file = 'exequextretosicos.png';
+
+ $(`#desafioDesafio-${instance}`)
+ .find('.desafio-GameDesafio')
+ .css({
+ background: imgDesafio,
+ 'background-size': '100% 100%',
+ width: `${l}px`,
+ height: `${t}px`,
+ });
+
+ $buttonChalleng.each(function (i) {
+ if (i < mOptions.stateChallenges.length) {
+ const state = mOptions.stateChallenges[i].state;
+ const left = `${-l * i}px`;
+ const top = `${-t * state}px`;
+ const mcss = `url(${$eXeDesafio.idevicePath}${file}) no-repeat ${left} ${top}`;
+ $(this)
+ .find('.exeQuextRetos')
+ .css({
+ background: mcss,
+ width: `${l}px`,
+ height: `${t}px`,
+ 'flex-grow': 0,
+ });
+ }
+ });
+ },
+
+ addZero: function (i) {
+ return i < 10 ? `0${i}` : i.toString();
+ },
+
+ getActualFullDate: function () {
+ const d = new Date(),
+ day = $eXeDesafio.addZero(d.getDate()),
+ month = $eXeDesafio.addZero(d.getMonth() + 1),
+ year = $eXeDesafio.addZero(d.getFullYear()),
+ h = $eXeDesafio.addZero(d.getHours()),
+ m = $eXeDesafio.addZero(d.getMinutes()),
+ s = $eXeDesafio.addZero(d.getSeconds());
+ return `${day}/${month}/${year} (${h}:${m}:${s})`;
+ },
+
+ addEvents: function (instance) {
+ const mOptions = $eXeDesafio.options[instance];
+
+ $eXeDesafio.removeEvents(instance);
+
+ $(window).on('unload.eXeChallenger beforeunload.eXeChallenger', () => {
+ if (mOptions.gameStarted || mOptions.gameOver) {
+ $eXeDesafio.saveDataStorage(instance);
+ $exeDevices.iDevice.gamification.scorm.endScorm(
+ $eXeDesafio.mScorm
+ );
+ }
+ });
+ $(`#desafioSolutionDiv-${instance}`).hide();
+
+ const $buttonChalleng = $(`#desafioGameChallenges-${instance}`).find(
+ '.desafio-LinkChallenge'
+ );
+
+ $buttonChalleng.each(function (i) {
+ $(this).hide();
+ if (i < mOptions.challengesGame.length) {
+ $(this).show();
+ }
+ });
+
+ $(`#desafioGamerOver-${instance}`).css('display', 'flex');
+
+ $(`#desafioLinkMaximize-${instance}`).on(
+ 'click touchstart',
+ function (e) {
+ e.preventDefault();
+ $(`#desafioGameContainer-${instance}`).show();
+ $(`#desafioGameMinimize-${instance}`).hide();
+ }
+ );
+
+ $(`#desafioLinkMinimize-${instance}`).on(
+ 'click touchstart',
+ function (e) {
+ e.preventDefault();
+ $(`#desafioGameContainer-${instance}`).hide();
+ $(`#desafioGameMinimize-${instance}`)
+ .css('visibility', 'visible')
+ .show();
+ }
+ );
+
+ $(`#desafioGamerOver-${instance}`).hide();
+ $(`#desafioVideo-${instance}`).hide();
+ $(`#desafioImagen-${instance}`).hide();
+ $(`#desafioCursor-${instance}`).hide();
+ $(`#desafioCover-${instance}`).show();
+
+ $(`#desafioSolution-${instance}`).on('keydown', function (event) {
+ const dstate = $(`#desafioSolution-${instance}`).prop('readonly');
+ if (dstate) return;
+ if (event.which === 13 || event.keyCode === 13) {
+ $eXeDesafio.answerChallenge(instance);
+ return false;
+ }
+ return true;
+ });
+
+ $(`#desafioGameChallenges-${instance}`).on(
+ 'click touchstart',
+ '.desafio-LinkChallenge',
+ function (e) {
+ e.preventDefault();
+ if (!mOptions.gameStarted) {
+ return;
+ }
+ const number = parseInt($(this).data('number'));
+ $eXeDesafio.showChallenge(number, instance);
+ }
+ );
+
+ $(`#desafioDesafio-${instance}`).on('click touchstart', function (e) {
+ e.preventDefault();
+ if (mOptions.gameStarted) {
+ $eXeDesafio.showDesafio(instance);
+ }
+ });
+
+ $(`#desafioRebootButton-${instance}`).on(
+ 'click touchstart',
+ function (e) {
+ e.preventDefault();
+ if (window.confirm(mOptions.msgs.msgDesafioReboot)) {
+ $eXeDesafio.rebootGame(instance);
+ }
+ }
+ );
+
+ $(`#desafioStartGame-${instance}`).text(mOptions.msgs.msgPlayStart);
+
+ $(`#desafioStartGame-${instance}`).on('click', function (e) {
+ e.preventDefault();
+ $eXeDesafio.startGame(instance, 0);
+ });
+
+ $(`#desafioSolutionButton-${instance}`).on(
+ 'click touchstart',
+ function (e) {
+ e.preventDefault();
+ const dstate = $(`#desafioSolution-${instance}`).prop(
+ 'readonly'
+ );
+ if (dstate) return;
+ $eXeDesafio.answerChallenge(instance);
+ }
+ );
+
+ $(`#desafioInstructions-${instance}`).text(mOptions.instructions);
+ $(`#desafioPNumber-${instance}`).text(mOptions.numberQuestions);
+ $(`#desafioInstruction-${instance}`).text(mOptions.instructions);
+
+ document.title = mOptions.title;
+
+ $('meta[name=author]').attr('content', mOptions.author);
+
+ mOptions.gameOver = false;
+ mOptions.counter = parseInt(mOptions.desafioTime) * 60;
+ mOptions.activeChallenge = 0;
+
+ if (typeof mOptions.desafioID !== 'undefined') {
+ const dataDesafio = $eXeDesafio.getDesafioStorage(
+ mOptions.desafioID
+ );
+ if (dataDesafio) {
+ if (
+ mOptions.desafioType !== dataDesafio.desafioType ||
+ dataDesafio.numberChallenges !==
+ mOptions.challengesGame.length ||
+ dataDesafio.desafioTime !== mOptions.desafioTime
+ ) {
+ localStorage.removeItem(
+ `dataDesafio-${mOptions.desafioID}`
+ );
+ } else {
+ $eXeDesafio.reloadGame(instance, dataDesafio);
+ }
+ }
+ }
+
+ $eXeDesafio.changeImageButtonState(instance, mOptions.typeQuestion);
+
+ if (mOptions.isScorm > 0) {
+ $exeDevices.iDevice.gamification.scorm.registerActivity(mOptions);
+ }
+
+ $('#desafioMainContainer-' + instance)
+ .closest('.idevice_node')
+ .on('click', '.Games-SendScore', function (e) {
+ e.preventDefault();
+ $eXeDesafio.sendScore(false, instance);
+ $eXeDesafio.saveEvaluation(instance);
+ });
+
+ setTimeout(() => {
+ $exeDevices.iDevice.gamification.report.updateEvaluationIcon(
+ mOptions,
+ this.isInExe
+ );
+ }, 500);
+ },
+
+ refreshGame: function (instance) {
+ const mOptions = $eXeDesafio.options[instance];
+
+ if (!mOptions) return;
+
+ $eXeDesafio.changeImageButtonState(instance, mOptions.typeQuestion);
+ },
+
+ removeEvents: function (instance) {
+ $(window).off('unload.eXeChallenger beforeunload.eXeChallenger');
+ $(`#desafioLinkMaximize-${instance}`).off('click touchstart');
+ $(`#desafioLinkMinimize-${instance}`).off('click touchstart');
+ $(`#desafioSolution-${instance}`).off('keydown');
+ $(`#desafioGameChallenges-${instance}`).off(
+ 'click touchstart',
+ '.desafio-LinkChallenge'
+ );
+ $(`#desafioDesafio-${instance}`).off('click touchstart');
+ $(`#desafioRebootButton-${instance}`).off('click touchstart');
+ $(`#desafioStartGame-${instance}`).off('click');
+ $(`#desafioSolutionButton-${instance}`).off('click touchstart');
+ $('#desafioMainContainer-' + instance)
+ .closest('.idevice_node')
+ .off('click', '.Games-SendScore');
+ },
+
+ rebootGame: function (instance) {
+ const mOptions = $eXeDesafio.options[instance];
+
+ clearInterval(mOptions.counterClock);
+
+ localStorage.removeItem('dataDesafio-' + mOptions.desafioID);
+ mOptions.stateChallenges = $eXeDesafio.createArrayStateChallenges(
+ mOptions.desafioType,
+ mOptions.challengesGame.length
+ );
+
+ mOptions.gameOver = false;
+ mOptions.counter = parseInt(mOptions.desafioTime, 10) * 60;
+ mOptions.activeChallenge = 0;
+
+ localStorage.removeItem('dataEvaluation-' + instance);
+
+ mOptions.gameStarted = false;
+ mOptions.started = false;
+ mOptions.endGame = false;
+ mOptions.desafioDate = '';
+ mOptions.desafioSolved = false;
+ mOptions.typeQuestion = 0;
+ mOptions.solvedsChallenges = [];
+ mOptions.timesShow = [];
+
+ for (let i = 0; i < mOptions.challengesGame.length; i++) {
+ mOptions.timesShow.push(10000000);
+ }
+ $eXeDesafio.startGame(
+ instance,
+ mOptions.typeQuestion,
+ mOptions.activeChallenge
+ );
+ },
+
+ showDesafio: function (instance) {
+ const mOptions = $eXeDesafio.options[instance];
+ let message = mOptions.msgs.msgChallengesAllCompleted,
+ type = 2;
+
+ mOptions.typeQuestion = 0;
+ mOptions.activeChallenge = 0;
+
+ $('#desafioSolution-' + instance)
+ .prop('readonly', false)
+ .val('');
+ $('#desafioSolutionDiv-' + instance).show();
+ $('#desafioTitle-' + instance).text(mOptions.desafioTitle);
+ $('#desafioDescription-' + instance).show();
+ $('#desafioFeedBacks-' + instance).hide();
+
+ for (let i = 0; i < mOptions.stateChallenges.length; i++) {
+ if (i < mOptions.challengesGame.length) {
+ const mc = mOptions.stateChallenges[i];
+ if (mc.state > 0) {
+ if (mc.solved === 0) {
+ mc.state = 1;
+ type = 1;
+ $('#desafioSolution-' + instance).prop(
+ 'readonly',
+ true
+ );
+ $('#desafioSolutionDiv-' + instance).hide();
+ message = mOptions.msgs.msgCompleteAllChallenged;
+ } else {
+ mc.state = 2;
+ }
+ }
+ }
+ }
+
+ $eXeDesafio.showMessage(type, message, instance);
+ $eXeDesafio.changeImageButtonState(instance, mOptions.typeQuestion);
+ $('#desafioClues-' + instance).html('');
+ const desafioHtml = $('.desafio-IDevice').html();
+ if ($exeDevices.iDevice.gamification.math.hasLatex(desafioHtml)) {
+ $exeDevices.iDevice.gamification.math.updateLatex(
+ '.desafio-IDevice'
+ );
+ }
+ },
+
+ showChallenge: function (number, instance) {
+ const mOptions = $eXeDesafio.options[instance],
+ solution = mOptions.challengesGame[number].solution,
+ title = mOptions.challengesGame[number].title,
+ solved = mOptions.stateChallenges[number].solved;
+
+ let type = 0,
+ message = mOptions.msgs.msgWriteChallenge;
+
+ if (mOptions.stateChallenges[number].state === 0) {
+ return;
+ }
+ if (mOptions.timesShow[number] === 10000000) {
+ mOptions.timesShow[number] = mOptions.counter;
+ }
+ $eXeDesafio.changeStateButton(instance);
+ $('#desafioSolutionDiv-' + instance).show();
+
+ mOptions.typeQuestion = 1;
+ mOptions.activeChallenge = number;
+ mOptions.stateChallenges[number].state = 3;
+
+ $('#desafioSolution-' + instance)
+ .prop('readonly', false)
+ .val('');
+ $('#desafioTitle-' + instance).text(title);
+ $('#desafioFeedBacks-' + instance).show();
+
+ const $chs = $('#desafioFeedBacks-' + instance).children('div');
+ $chs.hide();
+ $chs.eq(number).show();
+ $('#desafioDescription-' + instance).hide();
+
+ if (solved === 1) {
+ $('#desafioSolution-' + instance)
+ .val(solution)
+ .prop('readonly', true);
+ type = 1;
+ message = mOptions.msgs.msgSolvedChallenge;
+ }
+
+ $eXeDesafio.showMessage(type, message, instance);
+ $eXeDesafio.changeImageButtonState(instance, mOptions.typeQuestion);
+ $eXeDesafio.showClues(number, instance);
+ const desafioHtml = $('.desafio-IDevice').html();
+ if ($exeDevices.iDevice.gamification.math.hasLatex(desafioHtml)) {
+ $exeDevices.iDevice.gamification.math.updateLatex(
+ '.desafio-IDevice'
+ );
+ }
+ },
+
+ showClues(number, instance) {
+ const mOptions = $eXeDesafio.options[instance];
+ let text = '';
+
+ if (typeof mOptions.challengesGame[number].clueTimes !== 'undefined') {
+ const tmp = mOptions.timesShow[number] - mOptions.counter;
+ for (
+ let i = 0;
+ i < mOptions.challengesGame[number].clueTimes.length;
+ i++
+ ) {
+ if (mOptions.challengesGame[number].clueTimes[i] <= tmp) {
+ text += `
${mOptions.msgs.msgHelp} ${i + 1}: ${mOptions.challengesGame[number].clueTexts[i]}
`;
+ }
+ }
+ }
+
+ $('#desafioClues-' + instance).html(text);
+ if ($exeDevices.iDevice.gamification.math.hasLatex(text)) {
+ $exeDevices.iDevice.gamification.math.updateLatex(
+ '.desafio-IDevice'
+ );
+ }
+ },
+
+ saveDataStorage: function (instance) {
+ const mOptions = $eXeDesafio.options[instance];
+ if (typeof mOptions.desafioID === 'undefined') return;
+
+ if (mOptions.desafioDate === '') {
+ mOptions.desafioDate = $eXeDesafio.getActualFullDate();
+ $('#desafioDate-' + instance).text(
+ `${mOptions.msgs.msgStartTime}: ${mOptions.desafioDate}`
+ );
+ }
+
+ const data = {
+ desafioID: mOptions.desafioID,
+ started: mOptions.gameStarted || mOptions.gameOver,
+ endGame: mOptions.endGame,
+ desafioSolved: mOptions.desafioSolved,
+ counter: mOptions.counter,
+ desafioDate: mOptions.desafioDate,
+ desafioTime: mOptions.desafioTime,
+ activeChallenge: mOptions.activeChallenge,
+ desafioType: mOptions.desafioType,
+ numberChallenges: mOptions.challengesGame.length,
+ typeQuestion: mOptions.typeQuestion,
+ solvedsChallenges: mOptions.solvedsChallenges,
+ stateChallenges: mOptions.stateChallenges,
+ timesShow: mOptions.timesShow,
+ };
+
+ if (mOptions.isScorm === 1) {
+ const points = mOptions.desafioSolved
+ ? mOptions.solvedsChallenges.length + 1
+ : mOptions.solvedsChallenges.length;
+ let score = (
+ 10 *
+ (points / (mOptions.challengesGame.length + 1))
+ ).toFixed(2);
+ $eXeDesafio.sendScore(true, instance);
+ $('#desafioRepeatActivity-' + instance).text(
+ `${mOptions.msgs.msgYouScore}: ${score}`
+ );
+ }
+ localStorage.setItem(
+ 'dataDesafio-' + mOptions.desafioID,
+ JSON.stringify(data)
+ );
+ },
+
+ changeStateButton: function (instance) {
+ const mOptions = $eXeDesafio.options[instance];
+ for (let i = 0; i < mOptions.stateChallenges.length; i++) {
+ if (mOptions.desafioType === 0) {
+ if (i < mOptions.solvedsChallenges.length) {
+ mOptions.stateChallenges[i].state = 2;
+ } else if (
+ mOptions.solvedsChallenges.length <
+ mOptions.stateChallenges.length
+ ) {
+ mOptions.stateChallenges[
+ mOptions.solvedsChallenges.length
+ ].state = 1;
+ }
+ } else {
+ if (mOptions.stateChallenges[i].state > 0) {
+ mOptions.stateChallenges[i].state = 1;
+ if (mOptions.stateChallenges[i].solved === 1) {
+ mOptions.stateChallenges[i].state = 2;
+ }
+ }
+ }
+ }
+ },
+
+ getDesafioStorage: function (id) {
+ return $exeDevices.iDevice.gamification.helpers.isJsonString(
+ localStorage.getItem('dataDesafio-' + id)
+ );
+ },
+
+ showScoreGame: function (type, instance) {
+ const mOptions = $eXeDesafio.options[instance],
+ msgs = mOptions.msgs,
+ $desafioHistGGame = $('#desafioHistGGame-' + instance),
+ $desafioLostGGame = $('#desafioLostGGame-' + instance),
+ $desafioOverPoint = $('#desafioOverScore-' + instance),
+ $desafioGamerOver = $('#desafioGamerOver-' + instance);
+
+ let message = '',
+ mtype = 2;
+
+ $desafioHistGGame.hide();
+ $desafioLostGGame.hide();
+ $desafioOverPoint.show();
+
+ switch (parseInt(type, 10)) {
+ case 0:
+ message = `${$eXeDesafio.getRetroFeedMessages(true, instance)} ${msgs.msgDesafioSolved}`;
+ $desafioHistGGame.show();
+ break;
+ case 1:
+ mtype = 1;
+ message = msgs.msgEndTimeRestart;
+ $desafioLostGGame.show();
+ break;
+ case 2:
+ message = msgs.msgInformationLooking;
+ $desafioOverPoint.hide();
+ break;
+ default:
+ break;
+ }
+
+ $eXeDesafio.showMessage(mtype, message, instance);
+ $desafioOverPoint.text(
+ `${msgs.msgChallengesCompleted}: ${mOptions.solvedsChallenges.length}`
+ );
+ $desafioGamerOver.show();
+ $('#desafioDescription-' + instance).hide();
+ },
+
+ reloadGame: function (instance, dataDesafio) {
+ const mOptions = $eXeDesafio.options[instance];
+ let colorMessage = 1;
+
+ mOptions.started = dataDesafio.started;
+ mOptions.counter = dataDesafio.counter;
+ mOptions.activeChallenge = dataDesafio.activeChallenge;
+ mOptions.desafioDate = dataDesafio.desafioDate;
+ mOptions.typeQuestion = dataDesafio.typeQuestion;
+ mOptions.endGame = dataDesafio.endGame;
+ mOptions.desafioSolved = dataDesafio.desafioSolved;
+ mOptions.stateChallenges = dataDesafio.stateChallenges;
+ mOptions.solvedsChallenges = dataDesafio.solvedsChallenges;
+
+ if (typeof dataDesafio.timesShow !== 'undefined') {
+ mOptions.timesShow = dataDesafio.timesShow;
+ }
+
+ $('#desafioDate-' + instance).text(
+ `${mOptions.msgs.msgStartTime}: ${dataDesafio.desafioDate}`
+ );
+
+ const ds = dataDesafio.desafioSolved ? 0 : 1;
+
+ if (mOptions.endGame) {
+ let message = mOptions.msgs.msgDesafioSolved;
+ colorMessage = 2;
+
+ if (!dataDesafio.desafioSolved) {
+ message = mOptions.msgs.msgEndTimeRestart;
+ colorMessage = 1;
+ }
+ $eXeDesafio.gameOver(ds, instance);
+ $('#desafioStartGameDiv-' + instance).hide();
+ $eXeDesafio.showMessage(colorMessage, message, instance);
+ } else {
+ $eXeDesafio.startGame(
+ instance,
+ mOptions.typeQuestion,
+ mOptions.activeChallenge
+ );
+ }
+ },
+
+ startGame: function (instance, type, numberButton) {
+ const mOptions = $eXeDesafio.options[instance];
+
+ if (mOptions.gameStarted) {
+ return;
+ }
+
+ let imgDesafio = 'desafioicon0.png';
+ imgDesafio = `url(${$eXeDesafio.idevicePath}${imgDesafio}) no-repeat`;
+
+ $(`desafioDesafio-${instance}`).css({
+ background: imgDesafio,
+ 'background-size': 'cover',
+ });
+
+ $(`#desafioDescription-${instance}`).show();
+ $(`#desafioTitle-${instance}`).show();
+ $(`#desafioMultimedia-${instance}`).hide();
+ $(`#desafioStartGameDiv-${instance}`).hide();
+
+ mOptions.gameActived = false;
+ mOptions.gameStarted = false;
+ $eXeDesafio.updateTime(0, instance);
+
+ $(`#desafioGamerOver-${instance}`).hide();
+ let message = mOptions.msgs.msgReadTime;
+
+ if (type === 0) {
+ if (
+ mOptions.solvedsChallenges.length >=
+ mOptions.challengesGame.length
+ ) {
+ message = mOptions.msgs.msgChallengesAllCompleted;
+ }
+ $eXeDesafio.showDesafio(instance);
+ $eXeDesafio.showMessage(2, message, instance);
+ } else if (type === 1) {
+ $eXeDesafio.showChallenge(numberButton, instance);
+ }
+
+ mOptions.counterClock = setInterval(() => {
+ if (mOptions.gameStarted) {
+ let $node = $('#desafioMainContainer-' + instance);
+ let $content = $('#node-content');
+ if (
+ !$node.length ||
+ ($content.length && $content.attr('mode') === 'edition')
+ ) {
+ clearInterval(mOptions.counterClock);
+ return;
+ }
+ mOptions.counter--;
+ $eXeDesafio.updateTime(mOptions.counter, instance);
+ if (mOptions.counter <= 0) {
+ $eXeDesafio.gameOver(1, instance);
+ }
+ if (mOptions.typeQuestion === 1) {
+ const tmp =
+ mOptions.timesShow[mOptions.activeChallenge] -
+ mOptions.counter;
+ if (
+ mOptions.challengesGame[
+ mOptions.activeChallenge
+ ].clueTimes.indexOf(tmp) !== -1
+ ) {
+ $eXeDesafio.showClues(
+ mOptions.activeChallenge,
+ instance
+ );
+ }
+ }
+ }
+ }, 1000);
+
+ mOptions.gameStarted = true;
+ mOptions.gameActived = true;
+ $eXeDesafio.saveDataStorage(instance);
+ },
+
+ updateTime: function (tiempo, instance) {
+ const mTime = $eXeDesafio.getTimeToString(tiempo);
+ $('#desafioPTime-' + instance).text(mTime);
+ },
+
+ getTimeToString: function (iTime) {
+ let mHours = Math.floor(parseInt(iTime) / 3600);
+ let mMinutes = parseInt(iTime / 60) % 60;
+ let mSeconds = iTime % 60;
+ return (
+ (mHours < 10 ? '0' + mHours : mHours) +
+ ':' +
+ (mMinutes < 10 ? '0' + mMinutes : mMinutes) +
+ ':' +
+ (mSeconds < 10 ? '0' + mSeconds : mSeconds)
+ );
+ },
+
+ gameOver: function (type, instance) {
+ const mOptions = $eXeDesafio.options[instance];
+
+ mOptions.gameStarted = false;
+ mOptions.gameActived = false;
+
+ clearInterval(mOptions.counterClock);
+
+ $(`#desafioTitle-${instance}`).hide();
+ $(`#desafioDescription-${instance}`).hide();
+ $(`#desafioSolutionDiv-${instance}`).hide();
+ $(`#desafioMultimedia-${instance}`).show();
+ $(`#desafioCover-${instance}`).hide();
+ $(`#desafioImagen-${instance}`).hide();
+ $(`#desafioFeedBacks-${instance}`).hide();
+ $(`#desafioClues-${instance}`).html('');
+
+ const message =
+ type === 0
+ ? mOptions.msgs.msgDesafioSolved
+ : mOptions.msgs.msgEndTime;
+ $eXeDesafio.showMessage(2, message, instance);
+ $eXeDesafio.showScoreGame(type, instance);
+ mOptions.gameOver = true;
+ mOptions.endGame = true;
+ },
+
+ getRetroFeedMessages: function (iHit, instance) {
+ const msgs = $eXeDesafio.options[instance].msgs;
+ let sMessages = iHit ? msgs.msgSuccesses : msgs.msgFailures;
+
+ sMessages = sMessages.split('|');
+ return sMessages[Math.floor(Math.random() * sMessages.length)];
+ },
+
+ answerChallenge: function (instance) {
+ const mOptions = $eXeDesafio.options[instance],
+ challengeGame = mOptions.challengesGame[mOptions.activeChallenge],
+ active = mOptions.activeChallenge;
+
+ let answord = $(`#desafioSolution-${instance}`).val().toUpperCase(),
+ message = '',
+ typeMessage = 0;
+
+ answord = answord.replace(/\s+/g, ' ').trim();
+
+ if (!mOptions.gameStarted) {
+ return;
+ }
+
+ if (answord.length === 0) {
+ $eXeDesafio.showMessage(1, mOptions.msgs.msgIndicateWord, instance);
+ return;
+ }
+
+ if (mOptions.typeQuestion === 0) {
+ if ($eXeDesafio.checkWord(mOptions.desafioSolution, answord)) {
+ message = `${$eXeDesafio.getRetroFeedMessages(true, instance)}${mOptions.msgs.msgDesafioSolved}`;
+ typeMessage = 1;
+ mOptions.desafioSolved = true;
+ $eXeDesafio.saveDataStorage(instance);
+ $eXeDesafio.saveEvaluation(instance);
+ $eXeDesafio.gameOver(0, instance);
+ return;
+ } else {
+ message = `${$eXeDesafio.getRetroFeedMessages(false, instance)}${mOptions.msgs.msgSolutionError}`;
+ $(`#desafioSolution-${instance}`).val('');
+ typeMessage = 0;
+ }
+ } else {
+ if ($eXeDesafio.checkWord(challengeGame.solution, answord)) {
+ typeMessage = 2;
+ mOptions.stateChallenges[active].solved = 1;
+ mOptions.solvedsChallenges.push(active);
+ if (mOptions.desafioType === 0) {
+ if (active < mOptions.challengesGame.length - 1) {
+ message = `${$eXeDesafio.getRetroFeedMessages(true, instance)}${mOptions.msgs.msgChallengeSolved}`;
+ $eXeDesafio.showChallenge(active, instance);
+ } else {
+ $eXeDesafio.showDesafio(instance);
+ message = `${$eXeDesafio.getRetroFeedMessages(true, instance)}${mOptions.msgs.msgChallengesAllCompleted}`;
+ $(`#desafioSolution-${instance}`).val('');
+ }
+ } else if (mOptions.desafioType === 1) {
+ if (
+ mOptions.solvedsChallenges.length >=
+ mOptions.challengesGame.length
+ ) {
+ $eXeDesafio.showDesafio(instance);
+ message = `${$eXeDesafio.getRetroFeedMessages(true, instance)}${mOptions.msgs.msgChallengesAllCompleted}`;
+ $(`#desafioSolution-${instance}`).val('');
+ } else {
+ $eXeDesafio.showChallenge(active, instance);
+ message = `${$eXeDesafio.getRetroFeedMessages(true, instance)}${mOptions.msgs.msgChallengeSolved}`;
+ }
+ }
+ $eXeDesafio.saveDataStorage(instance);
+ $eXeDesafio.saveEvaluation(instance);
+ } else {
+ message = `${$eXeDesafio.getRetroFeedMessages(false, instance)}${mOptions.msgs.msgSolutionCError}`;
+ typeMessage = 1;
+ $(`#desafioSolution-${instance}`).val('');
+ }
+ }
+
+ $eXeDesafio.showMessage(typeMessage, message, instance);
+ },
+
+ showMessageAlert: function (tmsg) {
+ window.alert(tmsg);
+ },
+
+ showMessage: function (type, message, instance) {
+ const colors = [
+ '#555555',
+ $eXeDesafio.borderColors.red,
+ $eXeDesafio.borderColors.green,
+ $eXeDesafio.borderColors.blue,
+ $eXeDesafio.borderColors.yellow,
+ ],
+ color = colors[type];
+
+ $(`#desafioPInformation-${instance}`).text(message).css({
+ color: color,
+ 'font-weight': 'normal',
+ 'font-size': $eXeDesafio.fontSize,
+ });
+ },
+};
+$(function () {
+ $eXeDesafio.init();
+});
diff --git a/vendor/exelearning/export-resources/idevices/challenge/export/challenge.test.js b/vendor/exelearning/export-resources/idevices/challenge/export/challenge.test.js
new file mode 100644
index 0000000..2346b39
--- /dev/null
+++ b/vendor/exelearning/export-resources/idevices/challenge/export/challenge.test.js
@@ -0,0 +1,194 @@
+/**
+ * Unit tests for challenge iDevice (export/runtime)
+ *
+ * Tests pure functions that don't depend on DOM manipulation:
+ * - createArrayStateChallenges: Creates array of challenge states
+ * - checkWord: Compares words with normalization
+ * - addZero: Pads single digit numbers
+ * - getTimeToString: Formats time to hh:mm:ss
+ */
+
+/* eslint-disable no-undef */
+import { readFileSync } from 'fs';
+import { fileURLToPath } from 'url';
+import { dirname, join } from 'path';
+
+const __filename = fileURLToPath(import.meta.url);
+const __dirname = dirname(__filename);
+
+/**
+ * Helper to load export iDevice file and expose $eXeDesafio globally.
+ * Also removes the auto-init call at the end to prevent side effects.
+ */
+function loadExportIdevice(code) {
+ let modifiedCode = code.replace(/var\s+\$eXeDesafio\s*=/, 'global.$eXeDesafio =');
+ // Remove auto-init call: $(function () { $eXeDesafio.init(); });
+ modifiedCode = modifiedCode.replace(/\$\(function\s*\(\)\s*\{\s*\$eXeDesafio\.init\(\);\s*\}\);?/g, '');
+ // eslint-disable-next-line no-eval
+ (0, eval)(modifiedCode);
+ return global.$eXeDesafio;
+}
+
+describe('challenge iDevice export', () => {
+ let $eXeDesafio;
+
+ beforeEach(() => {
+ global.$eXeDesafio = undefined;
+
+ const filePath = join(__dirname, 'challenge.js');
+ const code = readFileSync(filePath, 'utf-8');
+
+ $eXeDesafio = loadExportIdevice(code);
+ });
+
+ describe('createArrayStateChallenges', () => {
+ it('creates array with correct length', () => {
+ const result = $eXeDesafio.createArrayStateChallenges(0, 5);
+ expect(result).toHaveLength(5);
+ });
+
+ it('sets first challenge state to 3 (active)', () => {
+ const result = $eXeDesafio.createArrayStateChallenges(0, 3);
+ expect(result[0].state).toBe(3);
+ });
+
+ it('sets subsequent challenges to 0 when type is 0', () => {
+ const result = $eXeDesafio.createArrayStateChallenges(0, 3);
+ expect(result[1].state).toBe(0);
+ expect(result[2].state).toBe(0);
+ });
+
+ it('sets subsequent challenges to 1 when type is 1', () => {
+ const result = $eXeDesafio.createArrayStateChallenges(1, 3);
+ expect(result[1].state).toBe(1);
+ expect(result[2].state).toBe(1);
+ });
+
+ it('initializes all challenges with solved = 0', () => {
+ const result = $eXeDesafio.createArrayStateChallenges(0, 3);
+ result.forEach(challenge => {
+ expect(challenge.solved).toBe(0);
+ });
+ });
+
+ it('handles single challenge', () => {
+ const result = $eXeDesafio.createArrayStateChallenges(0, 1);
+ expect(result).toHaveLength(1);
+ expect(result[0].state).toBe(3);
+ });
+
+ it('handles empty array', () => {
+ const result = $eXeDesafio.createArrayStateChallenges(0, 0);
+ expect(result).toHaveLength(0);
+ });
+ });
+
+ describe('checkWord', () => {
+ it('returns true for identical words', () => {
+ expect($eXeDesafio.checkWord('hello', 'hello')).toBe(true);
+ });
+
+ it('is case insensitive', () => {
+ expect($eXeDesafio.checkWord('Hello', 'HELLO')).toBe(true);
+ expect($eXeDesafio.checkWord('WORLD', 'world')).toBe(true);
+ });
+
+ it('trims whitespace', () => {
+ expect($eXeDesafio.checkWord(' hello ', 'hello')).toBe(true);
+ });
+
+ it('normalizes multiple spaces', () => {
+ expect($eXeDesafio.checkWord('hello world', 'hello world')).toBe(true);
+ });
+
+ it('removes trailing punctuation', () => {
+ expect($eXeDesafio.checkWord('hello.', 'hello')).toBe(true);
+ expect($eXeDesafio.checkWord('hello,', 'hello')).toBe(true);
+ expect($eXeDesafio.checkWord('hello;', 'hello')).toBe(true);
+ });
+
+ it('returns false for different words', () => {
+ expect($eXeDesafio.checkWord('hello', 'world')).toBe(false);
+ });
+
+ it('handles pipe-separated alternatives in answer', () => {
+ expect($eXeDesafio.checkWord('cat|dog|bird', 'cat')).toBe(true);
+ expect($eXeDesafio.checkWord('cat|dog|bird', 'dog')).toBe(true);
+ expect($eXeDesafio.checkWord('cat|dog|bird', 'bird')).toBe(true);
+ expect($eXeDesafio.checkWord('cat|dog|bird', 'fish')).toBe(false);
+ });
+
+ it('handles empty strings', () => {
+ expect($eXeDesafio.checkWord('', '')).toBe(true);
+ });
+ });
+
+ describe('addZero', () => {
+ it('adds zero to single digit numbers', () => {
+ expect($eXeDesafio.addZero(0)).toBe('00');
+ expect($eXeDesafio.addZero(5)).toBe('05');
+ expect($eXeDesafio.addZero(9)).toBe('09');
+ });
+
+ it('returns string for double digit numbers', () => {
+ expect($eXeDesafio.addZero(10)).toBe('10');
+ expect($eXeDesafio.addZero(59)).toBe('59');
+ });
+
+ it('handles larger numbers', () => {
+ expect($eXeDesafio.addZero(100)).toBe('100');
+ });
+ });
+
+ describe('getTimeToString', () => {
+ it('formats zero seconds', () => {
+ expect($eXeDesafio.getTimeToString(0)).toBe('00:00:00');
+ });
+
+ it('formats seconds only', () => {
+ expect($eXeDesafio.getTimeToString(30)).toBe('00:00:30');
+ expect($eXeDesafio.getTimeToString(59)).toBe('00:00:59');
+ });
+
+ it('formats minutes and seconds', () => {
+ expect($eXeDesafio.getTimeToString(60)).toBe('00:01:00');
+ expect($eXeDesafio.getTimeToString(90)).toBe('00:01:30');
+ expect($eXeDesafio.getTimeToString(3599)).toBe('00:59:59');
+ });
+
+ it('formats hours, minutes, and seconds', () => {
+ expect($eXeDesafio.getTimeToString(3600)).toBe('01:00:00');
+ expect($eXeDesafio.getTimeToString(3661)).toBe('01:01:01');
+ expect($eXeDesafio.getTimeToString(7200)).toBe('02:00:00');
+ });
+
+ it('pads single digits with zeros', () => {
+ expect($eXeDesafio.getTimeToString(3723)).toBe('01:02:03');
+ });
+ });
+
+ describe('borderColors', () => {
+ it('has required color definitions', () => {
+ expect($eXeDesafio.borderColors).toBeDefined();
+ expect($eXeDesafio.borderColors.black).toBe('#1c1b1b');
+ expect($eXeDesafio.borderColors.blue).toBe('#5877c6');
+ expect($eXeDesafio.borderColors.green).toBe('#2a9315');
+ expect($eXeDesafio.borderColors.red).toBe('#ff0000');
+ expect($eXeDesafio.borderColors.white).toBe('#ffffff');
+ expect($eXeDesafio.borderColors.yellow).toBe('#f3d55a');
+ });
+ });
+
+ describe('colors', () => {
+ it('has required color definitions', () => {
+ expect($eXeDesafio.colors).toBeDefined();
+ expect($eXeDesafio.colors.black).toBe('#1c1b1b');
+ });
+ });
+
+ describe('options', () => {
+ it('is defined', () => {
+ expect($eXeDesafio.options).toBeDefined();
+ });
+ });
+});
diff --git a/vendor/exelearning/export-resources/idevices/challenge/export/desafioHome.png b/vendor/exelearning/export-resources/idevices/challenge/export/desafioHome.png
new file mode 100644
index 0000000..4e56dae
Binary files /dev/null and b/vendor/exelearning/export-resources/idevices/challenge/export/desafioHome.png differ
diff --git a/vendor/exelearning/export-resources/idevices/challenge/export/desafioicon.png b/vendor/exelearning/export-resources/idevices/challenge/export/desafioicon.png
new file mode 100644
index 0000000..9aa1f83
Binary files /dev/null and b/vendor/exelearning/export-resources/idevices/challenge/export/desafioicon.png differ
diff --git a/vendor/exelearning/export-resources/idevices/challenge/export/desafioicon0.png b/vendor/exelearning/export-resources/idevices/challenge/export/desafioicon0.png
new file mode 100644
index 0000000..c3728ae
Binary files /dev/null and b/vendor/exelearning/export-resources/idevices/challenge/export/desafioicon0.png differ
diff --git a/vendor/exelearning/export-resources/idevices/challenge/export/desafioicon1.png b/vendor/exelearning/export-resources/idevices/challenge/export/desafioicon1.png
new file mode 100644
index 0000000..9aa1f83
Binary files /dev/null and b/vendor/exelearning/export-resources/idevices/challenge/export/desafioicon1.png differ
diff --git a/vendor/exelearning/export-resources/idevices/challenge/export/desafioicon2.png b/vendor/exelearning/export-resources/idevices/challenge/export/desafioicon2.png
new file mode 100644
index 0000000..084f454
Binary files /dev/null and b/vendor/exelearning/export-resources/idevices/challenge/export/desafioicon2.png differ
diff --git a/vendor/exelearning/export-resources/idevices/challenge/export/exeRetosIcons.png b/vendor/exelearning/export-resources/idevices/challenge/export/exeRetosIcons.png
new file mode 100644
index 0000000..b776a6f
Binary files /dev/null and b/vendor/exelearning/export-resources/idevices/challenge/export/exeRetosIcons.png differ
diff --git a/vendor/exelearning/export-resources/idevices/challenge/export/exequextfull.svg b/vendor/exelearning/export-resources/idevices/challenge/export/exequextfull.svg
new file mode 100644
index 0000000..fa27df9
--- /dev/null
+++ b/vendor/exelearning/export-resources/idevices/challenge/export/exequextfull.svg
@@ -0,0 +1,3 @@
+
diff --git a/vendor/exelearning/export-resources/idevices/challenge/export/exequexthits.png b/vendor/exelearning/export-resources/idevices/challenge/export/exequexthits.png
new file mode 100644
index 0000000..efe3955
Binary files /dev/null and b/vendor/exelearning/export-resources/idevices/challenge/export/exequexthits.png differ
diff --git a/vendor/exelearning/export-resources/idevices/challenge/export/exequexthits.svg b/vendor/exelearning/export-resources/idevices/challenge/export/exequexthits.svg
new file mode 100644
index 0000000..0f8dd84
--- /dev/null
+++ b/vendor/exelearning/export-resources/idevices/challenge/export/exequexthits.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/vendor/exelearning/export-resources/idevices/challenge/export/exequextlost.png b/vendor/exelearning/export-resources/idevices/challenge/export/exequextlost.png
new file mode 100644
index 0000000..ae97ebc
Binary files /dev/null and b/vendor/exelearning/export-resources/idevices/challenge/export/exequextlost.png differ
diff --git a/vendor/exelearning/export-resources/idevices/challenge/export/exequextmin.svg b/vendor/exelearning/export-resources/idevices/challenge/export/exequextmin.svg
new file mode 100644
index 0000000..bee9919
--- /dev/null
+++ b/vendor/exelearning/export-resources/idevices/challenge/export/exequextmin.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/vendor/exelearning/export-resources/idevices/challenge/export/exequextnumber.svg b/vendor/exelearning/export-resources/idevices/challenge/export/exequextnumber.svg
new file mode 100644
index 0000000..8d989b0
--- /dev/null
+++ b/vendor/exelearning/export-resources/idevices/challenge/export/exequextnumber.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/vendor/exelearning/export-resources/idevices/challenge/export/exequextplayvideo.png b/vendor/exelearning/export-resources/idevices/challenge/export/exequextplayvideo.png
new file mode 100644
index 0000000..90f4405
Binary files /dev/null and b/vendor/exelearning/export-resources/idevices/challenge/export/exequextplayvideo.png differ
diff --git a/vendor/exelearning/export-resources/idevices/challenge/export/exequextreload.png b/vendor/exelearning/export-resources/idevices/challenge/export/exequextreload.png
new file mode 100644
index 0000000..074e6ef
Binary files /dev/null and b/vendor/exelearning/export-resources/idevices/challenge/export/exequextreload.png differ
diff --git a/vendor/exelearning/export-resources/idevices/challenge/export/exequextreply.png b/vendor/exelearning/export-resources/idevices/challenge/export/exequextreply.png
new file mode 100644
index 0000000..016de4b
Binary files /dev/null and b/vendor/exelearning/export-resources/idevices/challenge/export/exequextreply.png differ
diff --git a/vendor/exelearning/export-resources/idevices/challenge/export/exequextrerrors.svg b/vendor/exelearning/export-resources/idevices/challenge/export/exequextrerrors.svg
new file mode 100644
index 0000000..adb3571
--- /dev/null
+++ b/vendor/exelearning/export-resources/idevices/challenge/export/exequextrerrors.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/vendor/exelearning/export-resources/idevices/challenge/export/exequextretosicos.png b/vendor/exelearning/export-resources/idevices/challenge/export/exequextretosicos.png
new file mode 100644
index 0000000..b776a6f
Binary files /dev/null and b/vendor/exelearning/export-resources/idevices/challenge/export/exequextretosicos.png differ
diff --git a/vendor/exelearning/export-resources/idevices/challenge/export/exequextscore.svg b/vendor/exelearning/export-resources/idevices/challenge/export/exequextscore.svg
new file mode 100644
index 0000000..b2ff7bd
--- /dev/null
+++ b/vendor/exelearning/export-resources/idevices/challenge/export/exequextscore.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/vendor/exelearning/export-resources/idevices/challenge/export/exequextsq.png b/vendor/exelearning/export-resources/idevices/challenge/export/exequextsq.png
new file mode 100644
index 0000000..1d93e55
Binary files /dev/null and b/vendor/exelearning/export-resources/idevices/challenge/export/exequextsq.png differ
diff --git a/vendor/exelearning/export-resources/idevices/challenge/export/exequexttime.svg b/vendor/exelearning/export-resources/idevices/challenge/export/exequexttime.svg
new file mode 100644
index 0000000..4f0ecb6
--- /dev/null
+++ b/vendor/exelearning/export-resources/idevices/challenge/export/exequexttime.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/vendor/exelearning/export-resources/idevices/challenge/export/exequextwon.png b/vendor/exelearning/export-resources/idevices/challenge/export/exequextwon.png
new file mode 100644
index 0000000..624cbf8
Binary files /dev/null and b/vendor/exelearning/export-resources/idevices/challenge/export/exequextwon.png differ
diff --git a/vendor/exelearning/export-resources/idevices/checklist/checklist-icon.svg b/vendor/exelearning/export-resources/idevices/checklist/checklist-icon.svg
new file mode 100644
index 0000000..ade82f3
--- /dev/null
+++ b/vendor/exelearning/export-resources/idevices/checklist/checklist-icon.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/vendor/exelearning/export-resources/idevices/checklist/config.xml b/vendor/exelearning/export-resources/idevices/checklist/config.xml
new file mode 100644
index 0000000..2b31769
--- /dev/null
+++ b/vendor/exelearning/export-resources/idevices/checklist/config.xml
@@ -0,0 +1,12 @@
+
+
+ Checklist
+ checklist
+ Assessment and tracking
+
+ checklist-icon
+ checklist-icon.svg
+ img
+
+ 0
+
diff --git a/vendor/exelearning/export-resources/idevices/checklist/edition/checklist.css b/vendor/exelearning/export-resources/idevices/checklist/edition/checklist.css
new file mode 100644
index 0000000..f9e96e6
--- /dev/null
+++ b/vendor/exelearning/export-resources/idevices/checklist/edition/checklist.css
@@ -0,0 +1,341 @@
+.CTJ-table-container {
+ width: 100%;
+ background-color: #fff;
+ border-radius: 5px;
+ box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.1);
+ overflow: hidden;
+
+}
+
+.CTJ-Instructions {
+ width: 100%;
+ display: flex;
+ flex-direction: column;
+ margin-bottom: 20px;
+ align-items: flex-start;
+}
+
+.CTJ-inputs-container {
+ width: 100%;
+ margin-bottom: 30px;
+ margin-bottom: 1em;
+}
+
+.CTJ-Table {
+ width: 100%;
+ table-layout: fixed;
+ border-collapse: collapse;
+}
+
+.CTJ-header-row th,
+.CTJ-data-row td {
+ padding: 10px;
+ text-align: left;
+ border-right: 1px solid #ccc;
+}
+
+.CTJ-header-row th {
+ text-align: center;
+}
+
+.CTJ-TypeColumn,
+.CTJ-Types {
+ width: 130px;
+ white-space: nowrap;
+}
+
+.CTJ-Points-column,
+.CTJ-Points {
+ width: 75px;
+}
+
+.CTJ-editar-column,
+.CTJ-Editions {
+ width: 200px;
+ white-space: nowrap;
+}
+
+.CTJ-Editions button {
+ margin-right: 0.1em;
+ min-width: 50px;
+}
+
+.CTJ-Types {
+ text-align: left;
+}
+
+.CTJ-header-row th {
+ background-color: #007BFF;
+ color: #fff;
+}
+
+.CTJ-data-row:nth-child(even) {
+ background-color: #eeeeee;
+}
+
+.CTJ-Add,
+.CTJ-Delete {
+ background-color: #007BFF;
+ color: #fff;
+ border: none;
+ border-radius: 5px;
+ padding: 5px 10px;
+ cursor: pointer;
+}
+
+.CTJ-Add:hover,
+.CTJ-Delete:hover {
+ background-color: #0056b3;
+}
+
+.CTJ-Editions:last-child {
+ border-right: none;
+}
+
+.CTJP-Item {
+ display: flex;
+ justify-content: flex-start;
+ align-items: center;
+ gap: 0.1em;
+ margin-bottom: 1em;
+}
+
+.CTJ-EPanel {
+ margin: 0.7em auto;
+ padding: 0;
+ position: relative;
+ width: 100%;
+}
+
+.CTJ-EOptionsMedia {
+ align-items: center;
+ display: flex;
+ justify-content: space-between;
+ margin-bottom: 1em;
+ width: 100%;
+}
+
+.CTJ-Logo {
+ width: 400px;
+ height: 277px;
+ display: none;
+}
+
+.CTJ-Images {
+ border-radius: .4em;
+ width: 400px;
+ height: 227px;
+ position: relative;
+ margin: 0.6em 0;
+}
+
+.CTJ-EMedia {
+ border: 1px solid #cccccc;
+ border-radius: .5em;
+ height: 100%;
+ left: 0;
+ position: absolute;
+ top: 0;
+ width: 100%;
+}
+
+.CTJ-InputImage {
+ margin-top: 10px;
+ align-items: center;
+ display: flex;
+ flex-wrap: nowrap;
+ justify-content: flex-start;
+ width: 400px;
+}
+
+.CTJ-InputImage input[type=text] {
+ flex-flow: 1;
+ margin-right: 0.2em;
+ min-width: 200px;
+ width: 100%;
+}
+
+.CTJ-InputImage input[type=button] {
+ flex-shrink: 0;
+}
+
+.CTJ-EURLImage {
+ width: 200px !important;
+}
+
+/* To review */
+#gameQEIdeviceForm .exe-block-info img {
+ margin-left: .2em;
+ vertical-align: middle;
+}
+
+.exe-block-close {
+ position: absolute;
+ top: 6px;
+ right: 5px;
+}
+
+
+#gameQEIdeviceFormTab1 p:first-child {
+ margin-top: 0;
+}
+
+#gameQEIdeviceFormTab1 {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 2%;
+}
+
+#gameQEIdeviceFormTab1>* {
+ flex: 0 0 48%;
+}
+
+#gameQEIdeviceFormTab1> :first-child {
+ flex: 0 0 100%;
+}
+
+
+@media screen and (max-width:720px) {
+ #gameQEIdeviceFormTab1>* {
+ flex: 0 0 100%;
+ }
+}
+
+#gameQEIdeviceForm #gameQEIdeviceFormTab1 label {
+ display: block;
+ margin-bottom: .2em;
+ color: #0BA1A1;
+ font-weight: 500;
+}
+
+#gameQEIdeviceForm #gameQEIdeviceFormTab1 input {
+ width: 100%;
+}
+
+/* Tabs (this should be common) */
+.exe-form-tabs {
+ list-style: none;
+ margin: 0 0 1.5em 0;
+ padding: 0;
+}
+
+#main .exe-form-tabs li {
+ display: inline;
+ list-style: none;
+ list-style-image: none;
+ margin: 0;
+ padding: 0;
+}
+
+.exe-form-tabs li:first-child a {
+ border-bottom-left-radius: 4px;
+ border-top-left-radius: 4px;
+}
+
+.exe-form-tabs li:last-child a {
+ border-bottom-right-radius: 4px;
+ border-top-right-radius: 4px;
+}
+
+.exe-form-tabs a {
+ background: #F9F9F9;
+ border: 1px solid #CCC;
+ color: #666;
+ display: inline-block;
+ padding: .5em 1em;
+}
+
+.exe-form-tabs li:not(:last-child) a {
+ border-right: none;
+}
+
+.exe-form-tabs .exe-form-active-tab {
+ background: #FFF;
+ color: #000;
+ font-weight: 500;
+}
+
+#gameQESCORMoptions {
+ margin-left: 1.5em;
+ visibility: hidden;
+}
+
+label[for=gameQEActivitySCORM] {
+ font-weight: bold;
+}
+
+#gameQESCORMinstructionsButton {
+ color: #777;
+ display: none;
+ margin: 10px 0 0 25px;
+}
+
+#gameQESCORMinstructionsButton ul {
+ list-style: none;
+ margin: 1.5em 0 .7em 0;
+ padding: 0;
+}
+
+#gameQESCORMinstructionsButton ul li {
+ list-style-image: none;
+ margin: 0 0 .5em 0;
+ padding: 0;
+}
+
+#gameQESCORMinstructionsAuto {
+ color: #777;
+ display: none;
+ margin: 10px 0 0 25px;
+}
+
+#gameQESCORMinstructionsAuto ul {
+ list-style: none;
+ margin: 1.5em 0 .7em 0;
+ padding: 0;
+}
+
+.CTJ-ELogos {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+}
+
+.CTJ-ELogo {
+ width: 33%;
+}
+
+.CTJ-EImages {
+ position: relative;
+ width: 100%;
+ height: 200px;
+}
+
+.CTJ-EImage {
+ position: absolute;
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ width: 100%;
+ height: 100%;
+ margin-top: 0.5em;
+}
+
+.CTJ-EButtom {
+ padding: auto;
+ display: flex;
+ justify-content: flex-start;
+ align-items: center;
+ width: 100%;
+ gap: 0.1em;
+ margin-top: 0.5em;
+ background-color: blue;
+}
+
+.CTJ-EButtom img {
+ display: block;
+}
+
+.CTJ-EURLImage {
+ width: 100px !important;
+}
\ No newline at end of file
diff --git a/vendor/exelearning/export-resources/idevices/checklist/edition/checklist.js b/vendor/exelearning/export-resources/idevices/checklist/edition/checklist.js
new file mode 100644
index 0000000..3642ea2
--- /dev/null
+++ b/vendor/exelearning/export-resources/idevices/checklist/edition/checklist.js
@@ -0,0 +1,1062 @@
+/* eslint-disable no-undef */
+/**
+/**
+ * Checklist Activity iDevice (edition code)
+ *
+ * Released under Attribution-ShareAlike 4.0 International License.
+ * Author: Manuel Narvaez Martinez y Javier Cayetano Rodríguez
+ * Ana María Zamora Moreno
+ * License: http://creativecommons.org/licenses/by-sa/4.0/
+ */
+var $exeDevice = {
+ i18n: {
+ category: _('Assessment and tracking'),
+ name: _('Checklist'),
+ },
+ msgs: {},
+ classIdevice: 'checklist',
+ id: false,
+ idevicePath: '',
+
+ ci18n: {},
+
+ init: function (element, previousData, path) {
+ this.ideviceBody = element;
+ this.idevicePreviousData = previousData;
+ this.idevicePath = path;
+ this.refreshTranslations();
+ this.createForm();
+ this.addEvents();
+ },
+ setMessagesInfo: function () {
+ const msgs = this.msgs;
+ msgs.msgEProvideID = _('Please provide the ID of this progress report');
+ },
+
+ refreshTranslations: function () {
+ this.ci18n = {
+ msgComplit: c_('Completed'),
+ msgDone: c_('Done'),
+ msgInProgress: c_('In progress'),
+ msgUnrealized: c_('Not completed'),
+ msgtaskNumber: c_('Number of tasks'),
+ msgName: c_('Name'),
+ msgDate: c_('Date'),
+ msgSave: c_('Download'),
+ msgList: c_('checklist'),
+ msgScore: c_('Score'),
+ msgWeight: c_('Weight'),
+ msgPoints: c_('points'),
+ msgPoint: c_('point'),
+ msgReboot: c_('Restart'),
+ msgDelete: c_('Are you sure you want clear all form fields?'),
+ };
+ },
+
+ createForm: function () {
+ const html = `
+
+ `;
+ this.ideviceBody.innerHTML = html;
+ $exeDevicesEdition.iDevice.tabs.init('gameQEIdeviceForm');
+ $('.CTJ-Table .CTJ-Points-column, .CTJ-Table .CTJ-Points').hide();
+
+ $exeDevice.loadPreviousValues();
+ },
+
+ loadPreviousValues: function () {
+ const originalHTML = this.idevicePreviousData;
+
+ if (originalHTML && Object.keys(originalHTML).length > 0) {
+ const wrapper = $('
');
+ wrapper.html(originalHTML);
+ let json = $('.listacotejo-DataGame', wrapper).text();
+ json = $exeDevices.iDevice.gamification.helpers.decrypt(json);
+
+ const dataGame =
+ $exeDevices.iDevice.gamification.helpers.isJsonString(json);
+
+ let img = $('.listacotejo-LinkLogo', wrapper);
+ if (img.length === 1) {
+ img = img.attr('src') || '';
+ dataGame.urlLogo = img;
+ }
+
+ img = $('.listacotejo-LinkCommunity', wrapper);
+ if (img.length == 1) {
+ img = img.attr('src') || '';
+ dataGame.urlCommunity = img;
+ }
+
+ img = $('.listacotejo-LinkDecorative', wrapper);
+ if (img.length == 1) {
+ img = img.attr('src') || '';
+ dataGame.urlDecorative = img;
+ }
+
+ $exeDevice.updateFieldGame(dataGame);
+
+ const instructions = $('.listacotejo-instructions', wrapper);
+ if (instructions.length == 1)
+ $('#eXeGameInstructions').val(instructions.html());
+
+ const textAfter = $('.listacotejo-extra-content', wrapper);
+ if (textAfter.length == 1)
+ $('#eXeIdeviceTextAfter').val(textAfter.html());
+ }
+ },
+
+ updateTable: function (arrayLevels) {
+ const tbody = $('.CTJ-Table tbody'),
+ useScore = $('#ctjUseScore').is(':checked');
+
+ tbody.empty();
+
+ arrayLevels.forEach((obj) => {
+ const row = $('
|
').addClass('CTJ-data-row'),
+ select = $('
').addClass('CTJ-Select');
+
+ [_('Box'), _('Text'), _('Choose'), _('Do not mark')].forEach(
+ (option, index) => {
+ const optElement = $('
')
+ .attr('value', index)
+ .html(option);
+ if (index == obj.type) {
+ optElement.prop('selected', true);
+ }
+ select.append(optElement);
+ }
+ );
+
+ const selectCell = $('
| ').append(select);
+
+ row.append(selectCell);
+ let edit = obj.type != 3;
+ edit = edit.toString();
+ const text = obj.type != 3 ? obj.points : '',
+ points = $('
| ')
+ .addClass('CTJ-Points')
+ .attr('contenteditable', edit);
+
+ points.html(text);
+ row.append(points);
+
+ for (let i = 0; i < 4; i++) {
+ const cell = $('
| ')
+ .addClass(`CTJ-Level${i + 1} CTJ-Levels`)
+ .attr('contenteditable', 'true');
+ if (i == obj.nivel) {
+ cell.html(obj.item);
+ }
+ row.append(cell);
+ }
+ const addButton = $('
').addClass(
+ 'CTJ-Add'
+ ),
+ deleteButton = $(
+ '
'
+ ).addClass('CTJ-Delete'),
+ editCell = $('
| ')
+ .addClass('CTJ-Editions')
+ .append(addButton, deleteButton);
+
+ row.append(editCell);
+ tbody.append(row);
+ });
+
+ if (useScore) {
+ $('.CTJ-Table .CTJ-Points-column, .CTJ-Table .CTJ-Points').show();
+ } else {
+ $('.CTJ-Table .CTJ-Points-column, .CTJ-Table .CTJ-Points').hide();
+ }
+ },
+
+ save: function () {
+ const dataGame = $exeDevice.validateData();
+
+ if (!dataGame) return false;
+
+ const fields = this.ci18n,
+ i18n = fields;
+ for (let i in fields) {
+ let fVal = $('#ci18n_' + i).val();
+ if (fVal != '') i18n[i] = fVal;
+ }
+
+ dataGame.msgs = i18n;
+
+ let json = JSON.stringify(dataGame),
+ divContent = '';
+ json = $exeDevices.iDevice.gamification.helpers.encrypt(json);
+
+ let html = '
';
+ const instructions = tinyMCE.get('eXeGameInstructions').getContent();
+ if (instructions !== '') {
+ divContent =
+ '
' +
+ instructions +
+ '
';
+ }
+
+ html += divContent;
+ html +=
+ '
' + json + '
';
+ html +=
+ '
' +
+ _('Unsupported browser') +
+ '
';
+
+ const textAfter = tinyMCE.get('eXeIdeviceTextAfter').getContent();
+ if (textAfter != '') {
+ html +=
+ '';
+ }
+ let img = $('#ctjEURLLogo').val();
+ if (img.trim().length > 0) {
+ img =
+ '

';
+ html += img;
+ }
+
+ img = $('#ctjEURLCommunity').val();
+ if (img.trim().length > 0) {
+ img =
+ '';
+ html += img;
+ }
+
+ img = $('#ctjEURLDecorative').val();
+ if (img.trim().length > 0) {
+ img =
+ '

';
+ html += img;
+ }
+ html += '
';
+ return html;
+ },
+
+ showMessage: function (msg) {
+ eXe.app.alert(msg);
+ },
+
+ getIdeviceID: function () {
+ const ideviceid =
+ $('#gameQEIdeviceForm')
+ .closest(`div.idevice_node.${$exeDevice.classIdevice}`)
+ .attr('id') || '';
+
+ return ideviceid;
+ },
+
+ validateData: function () {
+ const title = $('#ctjTitle').val().trim(),
+ subtitle = $('#ctjSubTitle').val().trim(),
+ hasLogo = $('#ctjLogo').is(':checked'),
+ urlLogo = $('#ctjEURLLogo').val().trim(),
+ hasCommunity = $('#ctjCommunity').is(':checked'),
+ urlCommunity = $('#ctjEURLCommunity').val().trim(),
+ hasDecorative = $('#ctjDecorative').is(':checked'),
+ urlDecorative = $('#ctjEURLDecorative').val().trim(),
+ footer = $('#ctjFooter').val().trim(),
+ saveData = $('#ctjSaveData').is(':checked'),
+ userData = $('#ctjUserData').is(':checked'),
+ useScore = $('#ctjUseScore').is(':checked');
+
+ let isLevelComplete = false,
+ isMoreThanOneLevelFilled = false;
+
+ if (title === '') {
+ $exeDevice.showMessage(_('Indicate a title for the checklist'));
+ return false;
+ }
+
+ $('.CTJ-data-row').each(function () {
+ const $row = $(this),
+ filledLevels = $row
+ .find('.CTJ-Level1, .CTJ-Level2, .CTJ-Level3, .CTJ-Level4')
+ .filter(function () {
+ return $(this).text().trim() !== '';
+ }).length;
+
+ if (filledLevels === 0) {
+ $exeDevice.showMessage(_('No empty items can be left'));
+ return false;
+ }
+
+ if (filledLevels > 0) {
+ isLevelComplete = true;
+ }
+
+ if (filledLevels > 1) {
+ isMoreThanOneLevelFilled = true;
+ return false;
+ }
+ });
+
+ if (!isLevelComplete) {
+ return false;
+ }
+ if (isMoreThanOneLevelFilled) {
+ $exeDevice.showMessage(
+ _(`You can only use text at this item's level`)
+ );
+ return false;
+ }
+
+ let arrayLevels = [];
+ let scoreError = 0;
+ $('.CTJ-Table .CTJ-data-row').each(function () {
+ const $fila = $(this),
+ type = $fila.find('.CTJ-Select option:selected').val(),
+ points = $fila.find('.CTJ-Points').eq(0).text();
+
+ let nivel = '',
+ item = '';
+
+ $fila.find('.CTJ-Levels').each(function () {
+ if ($(this).text().trim() !== '') {
+ nivel = $('.CTJ-Table th')
+ .eq($(this).index())
+ .attr('data-nivel');
+ item = $(this).html();
+ return false;
+ }
+ });
+
+ if (useScore) {
+ if (type == 3 && points.trim().length > 0) {
+ scoreError = 2;
+ return false;
+ }
+ }
+
+ const obj = {
+ type: type,
+ nivel: nivel,
+ item: item,
+ points: points,
+ };
+ arrayLevels.push(obj);
+ });
+
+ if (scoreError == 1) {
+ $exeDevice.showMessage(
+ _(
+ 'You must indicate the number of points for each item to be assesed'
+ )
+ );
+ return false;
+ } else if (scoreError == 2) {
+ $exeDevice.showMessage(
+ _('You cannot indicate a score for this type of boxes')
+ );
+ return false;
+ }
+
+ return (data = {
+ typeGame: 'Cotejo',
+ id: $exeDevice.id,
+ title: title,
+ subtitle: subtitle,
+ levels: arrayLevels,
+ hasLogo: hasLogo,
+ urlLogo: urlLogo,
+ hasCommunity: hasCommunity,
+ urlCommunity: urlCommunity,
+ hasDecorative: hasDecorative,
+ urlDecorative: urlDecorative,
+ saveData: saveData,
+ userData: userData,
+ footer: footer,
+ useScore: useScore,
+ });
+ },
+ isNumberInteger: function (str) {
+ return Number.isInteger(Number(str)) && Number(str) >= 0;
+ },
+ addEvents1: function () {
+ $('.CTJ-Add').click(function (e) {
+ e.preventDefault();
+ const parentRow = $(this).closest('.CTJ-data-row'),
+ clonedRow = parentRow.clone(true);
+
+ clonedRow
+ .find('.CTJ-Level1, .CTJ-Level2, .CTJ-Level3, .CTJ-Level4')
+ .html('');
+ clonedRow.insertAfter(parentRow);
+ });
+
+ $('.CTJ-Delete').click(function (e) {
+ e.preventDefault();
+ if ($('.CTJ-data-row').length > 1) {
+ if (confirm('¿Desea eliminar esta fila?')) {
+ $(this).closest('.CTJ-data-row').remove();
+ }
+ } else {
+ $exeDevice.showMessage(_('There must be at least one row.'));
+ }
+ });
+
+ $('#ctjEURLLogo').on('change', function () {
+ const validExt = ['jpg', 'png', 'gif', 'jpeg', 'svg', 'webp`'],
+ selectedFile = $(this).val(),
+ ext = selectedFile.split('.').pop().toLowerCase();
+ if (
+ selectedFile.indexOf('files') == 0 &&
+ validExt.indexOf(ext) == -1
+ ) {
+ $exeDevice.showMessage(
+ _('Supported formats') + ': jpg, jpeg, gif, png, svg, webp'
+ );
+ return false;
+ }
+ let url = selectedFile,
+ alt = _('Project logo');
+ $exeDevice.showImage(
+ '#ctjEImageLogo',
+ '#ctjEImageNoLogo',
+ url,
+ alt
+ );
+ });
+
+ $('#ctjEPlayLogo').on('click', function (e) {
+ e.preventDefault();
+ const validExt = ['jpg', 'png', 'gif', 'jpeg', 'svg', 'webp'],
+ selectedFile = $('#ctjEURLLogo').val(),
+ ext = selectedFile.split('.').pop().toLowerCase();
+ if (
+ selectedFile.indexOf('files') == 0 &&
+ validExt.indexOf(ext) == -1
+ ) {
+ $exeDevice.showMessage(
+ _('Supported formats') + ': jpg, jpeg, gif, png, svg, webp'
+ );
+ return false;
+ }
+ const url = selectedFile,
+ alt = _('Project logo');
+ $exeDevice.showImage(
+ '#ctjEImageLogo',
+ '#ctjEImageNoLogo',
+ url,
+ alt
+ );
+ });
+
+ $('#ctjEURLCommunity').on('change', function () {
+ const validExt = ['jpg', 'png', 'gif', 'jpeg', 'svg', 'web`'],
+ selectedFile = $(this).val(),
+ ext = selectedFile.split('.').pop().toLowerCase();
+ if (
+ selectedFile.indexOf('files') == 0 &&
+ validExt.indexOf(ext) == -1
+ ) {
+ $exeDevice.showMessage(
+ _('Supported formats') + ': jpg, jpeg, gif, png, svg, webp'
+ );
+ return false;
+ }
+ const url = selectedFile,
+ alt = _('Community/Company');
+ $exeDevice.showImage(
+ '#ctjEImageCommunity',
+ '#ctjEImageNoCommunity',
+ url,
+ alt
+ );
+ });
+
+ $('#ctjEPlayCommunity').on('click', function (e) {
+ e.preventDefault();
+ const validExt = ['jpg', 'png', 'gif', 'jpeg', 'svg', 'web`'],
+ selectedFile = $('#ctjEURLCommunity').val(),
+ ext = selectedFile.split('.').pop().toLowerCase();
+ if (
+ selectedFile.indexOf('files') == 0 &&
+ validExt.indexOf(ext) == -1
+ ) {
+ $exeDevice.showMessage(
+ _('Supported formats') + ': jpg, jpeg, gif, png, svg, webp'
+ );
+ return false;
+ }
+ const url = selectedFile,
+ alt = _('Community/Company');
+ $exeDevice.showImage(
+ '#ctjEImageCommunity',
+ '#ctjEImageNoCommunity',
+ url,
+ alt
+ );
+ });
+
+ $('#ctjEURLDecorative').on('change', function () {
+ const validExt = ['jpg', 'png', 'gif', 'jpeg', 'svg', 'web`'],
+ selectedFile = $(this).val(),
+ ext = selectedFile.split('.').pop().toLowerCase();
+
+ if (
+ selectedFile.indexOf('files') == 0 &&
+ validExt.indexOf(ext) == -1
+ ) {
+ $exeDevice.showMessage(
+ _('Supported formats') + ': jpg, jpeg, gif, png, svg, webp'
+ );
+ return false;
+ }
+ const url = selectedFile,
+ alt = _('Decoration');
+ $exeDevice.showImage(
+ '#ctjEImageDecorative',
+ '#ctjEImageNoDecorative',
+ url,
+ alt
+ );
+ });
+
+ $('#ctjEPlayDecorative').on('click', function (e) {
+ e.preventDefault();
+ const validExt = ['jpg', 'png', 'gif', 'jpeg', 'svg', 'web`'],
+ selectedFile = $('#ctjEURLDecorative').val(),
+ ext = selectedFile.split('.').pop().toLowerCase();
+ if (
+ selectedFile.indexOf('files') == 0 &&
+ validExt.indexOf(ext) == -1
+ ) {
+ $exeDevice.showMessage(
+ _('Supported formats') + ': jpg, jpeg, gif, png, svg, webp'
+ );
+ return false;
+ }
+ const url = selectedFile,
+ alt = _('Decoration');
+ $exeDevice.showImage(
+ '#ctjEImageDecorative',
+ '#ctjEImageNoDecorative',
+ url,
+ alt
+ );
+ });
+
+ $('#ctjCommunity').change(function () {
+ if ($(this).is(':checked')) {
+ $('#ctjcommunitylogo').show();
+ } else {
+ $('#ctjcommunitylogo').hide();
+ }
+ });
+
+ $('#ctjLogo').change(function () {
+ if ($(this).is(':checked')) {
+ $('#ctjlogologo').show();
+ } else {
+ $('#ctjlogologo').hide();
+ }
+ });
+
+ $('#ctjDecorative').change(function () {
+ if ($(this).is(':checked')) {
+ $('#ctjdecorativelogo').show();
+ } else {
+ $('#ctjdecorativelogo').hide();
+ }
+ });
+
+ $('#ctjUseScore').change(function () {
+ if ($(this).is(':checked')) {
+ $(
+ '.CTJ-Table .CTJ-Points-column, .CTJ-Table .CTJ-Points'
+ ).show();
+ } else {
+ $(
+ '.CTJ-Table .CTJ-Points-column, .CTJ-Table .CTJ-Points'
+ ).hide();
+ }
+ });
+
+ $('.CTJ-Table')
+ .on('change', 'select.CTJ-Select', function () {
+ const selectedOptionIndex = $(this).val();
+ const pointsCell = $(this).closest('tr').find('.CTJ-Points');
+ if (selectedOptionIndex == '3') {
+ pointsCell.text('');
+ pointsCell.attr('contenteditable', 'false');
+ } else {
+ pointsCell.attr('contenteditable', 'true');
+ }
+ })
+ .trigger('change');
+
+ $('.CTJ-Table').on('keypress', '.CTJ-Points', function (event) {
+ const charCode = event.which ? event.which : event.keyCode;
+ if (charCode > 31 && (charCode < 48 || charCode > 57)) {
+ event.preventDefault();
+ }
+ });
+ },
+ addEvents() {
+ // Generic toggle handler: sync aria and show/hide target
+ $('#gameQEIdeviceForm').on('change', '.toggle-input', function () {
+ const $toggle = $(this).closest('.toggle-item');
+ const checked = $(this).is(':checked');
+ $toggle.attr('aria-checked', checked ? 'true' : 'false');
+ const target = $toggle.data('target');
+ if (target) {
+ $('#' + target).toggle(checked);
+ }
+ });
+ const initToggle = (selector) => {
+ const $input = $(selector);
+ if ($input.length === 0) return;
+ const $toggle = $input.closest('.toggle-item');
+ const checked = $input.is(':checked');
+ $toggle.attr('aria-checked', checked ? 'true' : 'false');
+ const target = $toggle.data('target');
+ if (target) {
+ $('#' + target).toggle(checked);
+ }
+ };
+ initToggle('#ctjUserData');
+ initToggle('#ctjSaveData');
+ initToggle('#ctjUseScore');
+ initToggle('#ctjCommunity');
+ initToggle('#ctjLogo');
+ initToggle('#ctjDecorative');
+ const handleImageChange = (
+ selectorInput,
+ selectorImage,
+ selectorNoImage,
+ altText
+ ) => {
+ const validExt = ['jpg', 'png', 'gif', 'jpeg', 'svg', 'webp'],
+ selectedFile = $(selectorInput).val(),
+ ext = selectedFile.split('.').pop().toLowerCase();
+
+ if (selectedFile.startsWith('files') && !validExt.includes(ext)) {
+ $exeDevice.showMessage(
+ `${_('Supported formats')}: jpg, jpeg, gif, png, svg, webp`
+ );
+ return false;
+ }
+ $exeDevice.showImage(
+ selectorImage,
+ selectorNoImage,
+ selectedFile,
+ altText
+ );
+ return true;
+ };
+
+ $('.CTJ-Table').on('click', '.CTJ-Add', function (e) {
+ e.preventDefault();
+ const parentRow = $(this).closest('.CTJ-data-row'),
+ clonedRow = parentRow.clone(true);
+
+ clonedRow
+ .find('.CTJ-Level1, .CTJ-Level2, .CTJ-Level3, .CTJ-Level4')
+ .html('');
+ clonedRow.insertAfter(parentRow);
+ });
+
+ $('.CTJ-Table').on('click', '.CTJ-Delete', function (e) {
+ e.preventDefault();
+ if ($('.CTJ-data-row').length > 1) {
+ if (confirm(_('Do you want to delete this row?'))) {
+ $(this).closest('.CTJ-data-row').remove();
+ }
+ } else {
+ $exeDevice.showMessage(_('There must be at least one row.'));
+ }
+ });
+ const imageConfig = [
+ {
+ inputSelector: '#ctjEURLLogo',
+ playButtonSelector: '#ctjEPlayLogo',
+ imageSelector: '#ctjEImageLogo',
+ noImageSelector: '#ctjEImageNoLogo',
+ altText: _('Project logo'),
+ },
+ {
+ inputSelector: '#ctjEURLCommunity',
+ playButtonSelector: '#ctjEPlayCommunity',
+ imageSelector: '#ctjEImageCommunity',
+ noImageSelector: '#ctjEImageNoCommunity',
+ altText: _('Community/Company'),
+ },
+ {
+ inputSelector: '#ctjEURLDecorative',
+ playButtonSelector: '#ctjEPlayDecorative',
+ imageSelector: '#ctjEImageDecorative',
+ noImageSelector: '#ctjEImageNoDecorative',
+ altText: _('Decoration'),
+ },
+ ];
+
+ imageConfig.forEach((config) => {
+ const {
+ inputSelector,
+ playButtonSelector,
+ imageSelector,
+ noImageSelector,
+ altText,
+ } = config;
+
+ $(inputSelector).on('change', () => {
+ handleImageChange(
+ inputSelector,
+ imageSelector,
+ noImageSelector,
+ altText
+ );
+ });
+
+ $(playButtonSelector).on('click', (e) => {
+ e.preventDefault();
+ handleImageChange(
+ inputSelector,
+ imageSelector,
+ noImageSelector,
+ altText
+ );
+ });
+ });
+
+ const checkboxConfig = [
+ {
+ checkboxSelector: '#ctjCommunity',
+ targetSelector: '#ctjcommunitylogo',
+ },
+ { checkboxSelector: '#ctjLogo', targetSelector: '#ctjlogologo' },
+ {
+ checkboxSelector: '#ctjDecorative',
+ targetSelector: '#ctjdecorativelogo',
+ },
+ ];
+
+ checkboxConfig.forEach((config) => {
+ const { checkboxSelector, targetSelector } = config;
+ $(checkboxSelector).on('change', function () {
+ $(targetSelector).toggle($(this).is(':checked'));
+ });
+ });
+
+ $('#ctjUseScore').on('change', function () {
+ const display = $(this).is(':checked') ? 'show' : 'hide';
+ $('.CTJ-Table .CTJ-Points-column, .CTJ-Table .CTJ-Points')[
+ display
+ ]();
+ });
+
+ $('.CTJ-Table').on('change', 'select.CTJ-Select', function () {
+ const selectedOptionIndex = $(this).val(),
+ pointsCell = $(this).closest('tr').find('.CTJ-Points');
+ if (selectedOptionIndex === '3') {
+ pointsCell.text('').attr('contenteditable', 'false');
+ } else {
+ pointsCell.attr('contenteditable', 'true');
+ }
+ });
+
+ $('.CTJ-Table').on('keypress', '.CTJ-Points', function (event) {
+ charCode = event.which || event.keyCode;
+ if (charCode > 31 && (charCode < 48 || charCode > 57)) {
+ event.preventDefault();
+ }
+ });
+ },
+
+ showImage: function (img, noimg, url, alt) {
+ const $image = $(img);
+ $image.hide();
+ $image.attr('alt', alt);
+ $(noimg).show();
+ url = $exeDevices.iDevice.gamification.media.extractURLGD(url);
+ $image
+ .prop('src', url)
+ .on('load', function () {
+ if (
+ !this.complete ||
+ typeof this.naturalWidth == 'undefined' ||
+ this.naturalWidth == 0
+ ) {
+ return false;
+ } else {
+ const mData = $exeDevice.placeImageWindows(
+ this,
+ this.naturalWidth,
+ this.naturalHeight
+ );
+ $exeDevice.drawImage(this, mData);
+ $image.show();
+ $(noimg).hide();
+ return true;
+ }
+ })
+ .on('error', function () {
+ return false;
+ });
+ },
+
+ placeImageWindows: function (image, naturalWidth, naturalHeight) {
+ const wDiv =
+ $(image).parent().width() > 0 ? $(image).parent().width() : 1,
+ hDiv =
+ $(image).parent().height() > 0 ? $(image).parent().height() : 1,
+ varW = naturalWidth / wDiv,
+ varH = naturalHeight / hDiv;
+
+ let wImage = wDiv,
+ hImage = hDiv,
+ xImagen = 0,
+ yImagen = 0;
+
+ if (varW > varH) {
+ wImage = parseInt(wDiv);
+ hImage = parseInt(naturalHeight / varW);
+ yImagen = parseInt((hDiv - hImage) / 2);
+ } else {
+ wImage = parseInt(naturalWidth / varH);
+ hImage = parseInt(hDiv);
+ xImagen = parseInt((wDiv - wImage) / 2);
+ }
+ return {
+ w: wImage,
+ h: hImage,
+ x: xImagen,
+ y: yImagen,
+ };
+ },
+
+ updateFieldGame: function (game) {
+ game.userData =
+ typeof game.userData == 'undefined' ? false : game.userData;
+ game.useScore =
+ typeof game.useScore == 'undefined' ? false : game.useScore;
+ game.weighted =
+ typeof game.weighted !== 'undefined' ? game.weighted : 100;
+ $exeDevice.id = $exeDevice.getIdeviceID();
+
+ $('#ctjTitle').val(game.title);
+ $('#ctjSubTitle').val(game.subtitle);
+ $('#ctjSaveData').prop('checked', game.saveData);
+ $('#ctjUserData').prop('checked', game.userData);
+ $('#ctjLogo').prop('checked', game.hasLogo);
+ $('#ctjCommunity').prop('checked', game.hasCommunity);
+ $('#ctjDecorative').prop('checked', game.hasDecorative);
+ $('#ctjEURLCommunity').val(game.urlCommunity);
+ $('#ctjEURLLogo').val(game.urlLogo);
+ $('#ctjEURLDecorative').val(game.urlDecorative);
+ $('#ctjFooter').val(game.footer);
+ $('#ctjUseScore').prop('checked', game.useScore);
+
+ if (game.hasLogo) $('#ctjlogologo').show();
+ if (game.hasCommunity) $('#ctjcommunitylogo').show();
+ if (game.hasDecorative) $('#ctjdecorativelogo').show();
+
+ for (let i = 0, len = game.levels.length; i < len; i++) {
+ game.levels[i].points =
+ game.levels[i].points === undefined
+ ? ''
+ : game.levels[i].points;
+ }
+
+ $exeDevice.updateTable(game.levels);
+
+ $exeDevice.showImage(
+ '#ctjEImageLogo',
+ '#ctjEImageNoLogo',
+ game.urlLogo,
+ _('Project logo')
+ );
+
+ $exeDevice.showImage(
+ '#ctjEImageCommunity',
+ '#ctjEImageNoCommunity',
+ game.urlCommunity,
+ _('Community/Company')
+ );
+
+ $exeDevice.showImage(
+ '#ctjEImageDecorative',
+ '#ctjEImageNoDecorative',
+ game.urlDecorative,
+ _('Decorative image')
+ );
+ },
+
+ drawImage: function (image, mData) {
+ $(image).css({
+ left: mData.x + 'px',
+ top: mData.y + 'px',
+ width: mData.w + 'px',
+ height: mData.h + 'px',
+ });
+ },
+};
diff --git a/vendor/exelearning/export-resources/idevices/checklist/edition/codejocomunidad.png b/vendor/exelearning/export-resources/idevices/checklist/edition/codejocomunidad.png
new file mode 100644
index 0000000..325fd6e
Binary files /dev/null and b/vendor/exelearning/export-resources/idevices/checklist/edition/codejocomunidad.png differ
diff --git a/vendor/exelearning/export-resources/idevices/checklist/edition/cotejodecorative.png b/vendor/exelearning/export-resources/idevices/checklist/edition/cotejodecorative.png
new file mode 100644
index 0000000..5fd1252
Binary files /dev/null and b/vendor/exelearning/export-resources/idevices/checklist/edition/cotejodecorative.png differ
diff --git a/vendor/exelearning/export-resources/idevices/checklist/edition/cotejologo.png b/vendor/exelearning/export-resources/idevices/checklist/edition/cotejologo.png
new file mode 100644
index 0000000..afddf32
Binary files /dev/null and b/vendor/exelearning/export-resources/idevices/checklist/edition/cotejologo.png differ
diff --git a/vendor/exelearning/export-resources/idevices/checklist/edition/logoCotejo.png b/vendor/exelearning/export-resources/idevices/checklist/edition/logoCotejo.png
new file mode 100644
index 0000000..b9bc8c4
Binary files /dev/null and b/vendor/exelearning/export-resources/idevices/checklist/edition/logoCotejo.png differ
diff --git a/vendor/exelearning/export-resources/idevices/checklist/edition/quextIEHelp.gif b/vendor/exelearning/export-resources/idevices/checklist/edition/quextIEHelp.gif
new file mode 100644
index 0000000..8510195
Binary files /dev/null and b/vendor/exelearning/export-resources/idevices/checklist/edition/quextIEHelp.gif differ
diff --git a/vendor/exelearning/export-resources/idevices/checklist/edition/quextIEPlay.png b/vendor/exelearning/export-resources/idevices/checklist/edition/quextIEPlay.png
new file mode 100644
index 0000000..99d9cef
Binary files /dev/null and b/vendor/exelearning/export-resources/idevices/checklist/edition/quextIEPlay.png differ
diff --git a/vendor/exelearning/export-resources/idevices/checklist/export/checklist.css b/vendor/exelearning/export-resources/idevices/checklist/export/checklist.css
new file mode 100644
index 0000000..16aeb83
--- /dev/null
+++ b/vendor/exelearning/export-resources/idevices/checklist/export/checklist.css
@@ -0,0 +1,340 @@
+.CTJP-MainContainer a,
+.CTJP-MainContainer a:visited,
+.CTJP-MainContainer a:focus {
+ border: 0;
+ border-bottom: none;
+ border-width: 0;
+ text-decoration: none !important;
+}
+
+/* Contenedor */
+
+.CTJP-MainContainer {
+ margin: 1em auto;
+ width: 100%;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+}
+
+.CTJP-Message {
+ width: 100%;
+}
+
+.CTJP-MainContainer * {
+ box-sizing: border-box;
+}
+
+.CTJP-MainContainer p {
+ margin: 0 !important;
+ padding: 0 !important;
+}
+
+.CTJP-GameContainer {
+ width: 100%;
+ max-width: 1000px;
+}
+
+.CTJP-List {
+ margin-top: 2em;
+ width: 100%;
+ background-color: #fff;
+ border-radius: 0.3em;
+ padding: 1.4em 1em 2em 1em;
+ border: 1px solid #ccc;
+
+}
+
+.CTJP-List * {
+ background-color: #fff !important;
+}
+
+.CTJP-Capture {
+ display: flex;
+ justify-content: flex-end;
+ margin: 1em 0 2em 0;
+ width: 100%;
+}
+
+
+.CTJP-Capture .btn {
+ margin-left: 0.5rem !important;
+}
+
+.CTJP-Capture .btn:first-child {
+ margin-left: 0 !important;
+}
+
+.CTJP-Header {
+ width: 100%;
+ display: flex;
+ justify-content: space-between;
+ text-align: center;
+ flex-wrap: wrap;
+ margin-bottom: 1.3em;
+ margin-bottom: 2em;
+}
+
+.CTJP-Footer {
+ width: 100%;
+ text-align: center;
+ margin-top: 3em;
+ color: #071717;
+}
+
+.CTJP-Images {
+ position: relative;
+ width: 200px;
+ height: 100px;
+ background-position: top center;
+ background-repeat: no-repeat;
+ background-size: contain;
+}
+
+.CTJP-ImgDecorative {
+ position: relative;
+ width: 250px;
+ height: 250px;
+ background-position: top center;
+ background-repeat: no-repeat;
+ background-size: contain;
+ position: absolute;
+ top: 1em;
+ right: 1em
+}
+
+
+.CTJP-Title {
+ width: 100%;
+ text-align: center;
+ font-size: 1.6em;
+ font-weight: 900;
+ color: #4A86E8;
+ margin-bottom: .3em;
+}
+
+.CTJP-SubTitle {
+ width: 100%;
+ text-align: center;
+ font-size: 1.3em;
+ font-weight: bold;
+ color: #071717;
+
+}
+
+.CTJP-Line {
+ width: 100%;
+ display: flex;
+ justify-content: center;
+ font-size: 2em;
+ font-weight: bold;
+ color: #071717;
+
+}
+
+.CTJP-Data {
+ padding-top: 2em;
+ width: 100%;
+ position: relative;
+ min-height: 300px;
+}
+
+.CTJP-Icon {
+ width: 250px;
+ position: absolute;
+ top: 2em;
+ right: 1em;
+
+}
+
+.CTJP-Counters {
+ display: flex;
+ justify-content: flex-start;
+ align-items: center;
+ gap: 4px
+}
+
+.CTJP-Items {
+ width: 100%;
+ margin-bottom: .8em;
+ text-align: left;
+}
+
+.CTJP-Item {
+ display: flex;
+ justify-content: flex-start;
+ align-items: center;
+ gap: 0.1em;
+ margin-bottom: 0.6em;
+ font-size: 1em;
+}
+
+.CTJP-Points {
+ margin-left: 5px;
+ font-weight: 600;
+ color: #01343f
+}
+
+.CTJP-Item * {
+ font-size: 1em !important;
+}
+
+.CTJP-Item select {
+ margin-right: 0.15em;
+ cursor: pointer;
+}
+
+.CTJP-Item input[type=checkbox] {
+ cursor: pointer;
+ margin-right: 3px !important;
+}
+
+.CTJP-Item input[type=text] {
+ margin-left: 0.15em;
+ cursor: pointer;
+
+}
+
+.CTJP-UserData {
+ display: flex;
+ justify-content: space-between;
+ flex-wrap: nowrap;
+ align-items: center;
+ margin: 1em 0;
+ gap: 1em;
+ min-width: 350px;
+}
+
+.CTJP-UserData>div {
+ display: flex;
+ align-items: center;
+ justify-content: flex-start;
+ gap: 0.15em;
+ flex-wrap: wrap;
+}
+
+.CTJP-UserName {
+ flex-grow: 1;
+ width: 50%;
+}
+
+.CTJP-UserDate {
+ flex-grow: 0;
+ justify-content: flex-end;
+ flex-wrap: nowrap;
+}
+
+.CTJP-UserDate label {
+ display: block;
+}
+
+.CTJP-UserDate input {
+ flex-grow: 1;
+ min-width: 150px;
+ border: none;
+ border-bottom: 1px dotted #333;
+}
+
+@media screen and (max-width: 1000px) {
+ .CTJP-ImgDecorative {
+ display: none;
+ }
+}
+
+
+.CTJP-MainContainer .toggle-item {
+ display: flex;
+ align-items: center;
+ justify-content: flex-start;
+ padding: 0;
+ flex-wrap: wrap;
+ gap: .1rem;
+}
+
+.CTJP-MainContainer .toggle-item+.toggle-item {
+ border-top: 1px solid rgba(0, 0, 0, .04);
+}
+
+.CTJP-MainContainer .toggle-label {
+ cursor: pointer;
+ margin-right: 3px;
+ margin-top: 0;
+}
+
+.CTJP-MainContainer .toggle-control {
+ position: relative;
+ display: inline-flex;
+ align-items: center;
+ /* Tamaño explícito del switch para asegurar el área clicable */
+ width: 36px;
+ height: 20px;
+}
+
+.CTJP-MainContainer .toggle-input {
+ position: absolute;
+ opacity: 0;
+ /* Usar top/left/right/bottom para compatibilidad amplia en vez de inset */
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ width: 100%;
+ height: 100%;
+ cursor: pointer;
+ z-index: 1;
+}
+
+.CTJP-MainContainer .toggle-visual {
+ display: inline-block;
+ width: 36px;
+ height: 20px;
+ border-radius: 999px;
+ background: var(--gray-400, #ccc);
+ box-shadow: inset 0 0 0 1px rgba(0, 0, 0, .06);
+ transition: background 160ms ease, box-shadow 160ms ease;
+ position: relative;
+ cursor: pointer;
+ pointer-events: none;
+}
+
+.CTJP-MainContainer .toggle-visual::after {
+ content: "";
+ position: absolute;
+ top: 2px;
+ left: 2px;
+ width: 16px;
+ height: 16px;
+ border-radius: 50%;
+ background: #fff;
+ box-shadow: 0 1px 2px rgba(0, 0, 0, .15);
+ transition: transform 160ms ease;
+}
+
+.CTJP-MainContainer .toggle-input:checked+.toggle-visual {
+ background: var(--bs-blue, #0d6efd) !important;
+}
+
+.CTJP-MainContainer .toggle-input:checked+.toggle-visual::after {
+ transform: translateX(16px);
+}
+
+.CTJP-MainContainer .toggle-input:disabled+.toggle-visual {
+ opacity: .5;
+ filter: grayscale(.3);
+ cursor: not-allowed;
+}
+
+
+.CTJP-List .toggle-visual {
+ background: var(--gray-400, #ccc) !important;
+}
+.CTJP-List .toggle-input:checked + .toggle-visual {
+ background: var(--bs-blue, #0d6efd) !important;
+}
+
+.CTJP-MainContainer .toggle-related label>input[type=number] {
+ display: inline-block;
+ width: 60px;
+ margin: 0 4px;
+ vertical-align: middle;
+}
\ No newline at end of file
diff --git a/vendor/exelearning/export-resources/idevices/checklist/export/checklist.js b/vendor/exelearning/export-resources/idevices/checklist/export/checklist.js
new file mode 100644
index 0000000..de87795
--- /dev/null
+++ b/vendor/exelearning/export-resources/idevices/checklist/export/checklist.js
@@ -0,0 +1,639 @@
+/* eslint-disable no-undef */
+/**
+ * Lista cotejo activity (Export)
+ *
+ * Released under Attribution-ShareAlike 4.0 International License.
+ * Author: Manuel Narváez Martínez y Javier Cayetano Rodríguez
+ * Ana María Zamora Moreno
+ * License: http://creativecommons.org/licenses/by-sa/4.0/
+ *
+ */
+var $eXeListaCotejo = {
+ idevicePath: '',
+ options: [],
+ isInExe: false,
+ data: null,
+ init: function () {
+ this.isInExe = eXe.app.isInExe(); //eXe 3.0
+ this.idevicePath = this.isInExe
+ ? eXe.app.getIdeviceInstalledExportPath('checklist')
+ : $('.idevice_node.checklist').eq(0).attr('data-idevice-path');
+
+ this.activities = $('.listacotejo-IDevice');
+
+ if (this.activities.length == 0) {
+ $('.ctj-IDevice').hide();
+ return;
+ }
+ if (
+ !$exeDevices.iDevice.gamification.helpers.supportedBrowser(
+ 'Checklist'
+ )
+ )
+ return;
+
+ if ($('#exe-submitButton').length > 0) {
+ this.activities.hide();
+ if (typeof _ != 'undefined')
+ this.activities.before('
' + _('Checklist') + '
');
+ return;
+ }
+
+ this.enable();
+ },
+
+ enable: function () {
+ $eXeListaCotejo.loadGame();
+ },
+
+ loadGame: function () {
+ $eXeListaCotejo.options = [];
+
+ $eXeListaCotejo.activities.each(function (i) {
+ const dl = $('.listacotejo-DataGame', this);
+
+ let img = $('.listacotejo-LinkCommunity', this);
+ if (img.length == 1) {
+ img = img.attr('src') || '';
+ } else {
+ img = '';
+ }
+
+ let img1 = $('.listacotejo-LinkLogo', this);
+ if (img1.length == 1) {
+ img1 = img1.attr('src') || '';
+ } else {
+ img1 = '';
+ }
+
+ let img2 = $('.listacotejo-LinkDecorative', this);
+ if (img2.length == 1) {
+ img2 = img2.attr('src') || '';
+ } else {
+ img2 = '';
+ }
+
+ const mOption = $eXeListaCotejo.loadDataGame(dl, img, img1, img2);
+ $eXeListaCotejo.options.push(mOption);
+
+ const ctj = $eXeListaCotejo.createInterfaceListaCotejo(i);
+ dl.before(ctj).remove();
+
+ $eXeListaCotejo.addEvents(i);
+
+ $('#ctjMainContainer-' + i).show();
+ });
+ const html = $('.listacotejo-IDevice').html();
+ if ($exeDevices.iDevice.gamification.math.hasLatex(html)) {
+ $exeDevices.iDevice.gamification.math.updateLatex(
+ '.listacotejo-IDevice'
+ );
+ }
+ },
+
+ loadDataGame: function (data, imglink, imglink1, imglink2) {
+ let json = data.text();
+ json = $exeDevices.iDevice.gamification.helpers.decrypt(json);
+
+ const mOptions =
+ $exeDevices.iDevice.gamification.helpers.isJsonString(json);
+
+ mOptions.urlCommunity = imglink;
+ mOptions.urlLogo = imglink1;
+ mOptions.urlDecorative = imglink2;
+ mOptions.id = typeof mOptions.id == 'undefined' ? false : mOptions.id;
+ mOptions.useScore =
+ typeof mOptions.useScore == 'undefined' ? false : mOptions.useScore;
+ mOptions.save = true;
+ mOptions.showCounter = true;
+ mOptions.points = 0;
+ mOptions.totalPoints = 0;
+
+ for (let i = 0; i < mOptions.levels.length; i++) {
+ mOptions.levels[i].points =
+ typeof mOptions.levels[i].points == 'undefined'
+ ? ''
+ : mOptions.levels[i].points;
+ const parsedPoints = parseInt(mOptions.levels[i].points);
+ if (!isNaN(parsedPoints)) {
+ mOptions.totalPoints += parsedPoints;
+ }
+ }
+ return mOptions;
+ },
+
+ saveCotejo: function (instance) {
+ const mOptions = $eXeListaCotejo.options[instance];
+
+ if (mOptions.id && mOptions.saveData && mOptions.save) {
+ const name = $('#ctjUserName-' + instance).val() || '',
+ date = $('#ctjUserDate-' + instance).val() || '';
+ let data = {
+ name: name,
+ date: date,
+ items: [],
+ };
+ let arr = [];
+ $('#ctjItems-' + instance)
+ .find('.CTJP-Item')
+ .each(function () {
+ let obj = {};
+ const $checkbox = $(this).find("input[type='checkbox']"),
+ $inputText = $(this).find("input[type='text']"),
+ $select = $(this).find('select');
+
+ if ($checkbox.length > 0 && $inputText.length > 0) {
+ obj.type = 1;
+ obj.state = $checkbox.is(':checked') ? 1 : 0;
+ obj.text = $inputText.val();
+ } else if ($checkbox.length > 0) {
+ obj.type = 0;
+ obj.state = $checkbox.is(':checked') ? 1 : 0;
+ obj.text = '';
+ } else if ($select.length > 0) {
+ obj.type = 2;
+ obj.state = $select.val();
+ obj.text = $select.find('option:selected').text();
+ } else {
+ obj.type = 3;
+ obj.state = false;
+ obj.text = '';
+ }
+ arr.push(obj);
+ });
+
+ data.items = arr;
+ data = JSON.stringify(data);
+ localStorage.setItem('dataCotejo-' + mOptions.id, data);
+ }
+ },
+ updateItems: function (id, instance) {
+ const data = $eXeListaCotejo.getDataStorage(id);
+
+ if (!data) return;
+
+ let arr = data.items || [];
+ $('#ctjUserName-' + instance).val(data.name || '');
+ $('#ctjUserDate-' + instance).val(data.date || '');
+ $('#ctjItems-' + instance)
+ .find('.CTJP-Item')
+ .each(function (index) {
+ const obj = arr[index];
+ if (!obj) return;
+ const $checkbox = $(this).find("input[type='checkbox']"),
+ $inputText = $(this).find("input[type='text']"),
+ $select = $(this).find('select');
+ switch (obj.type) {
+ case 0:
+ if ($checkbox.length > 0) {
+ $checkbox.prop('checked', obj.state === 1);
+ }
+ break;
+ case 1:
+ if ($checkbox.length > 0) {
+ $checkbox.prop('checked', obj.state === 1);
+ }
+ if ($inputText.length > 0) {
+ $inputText.val(obj.text);
+ }
+ break;
+ case 2:
+ if ($select.length > 0) {
+ $select.val(obj.state);
+ }
+ break;
+ case 3:
+ break;
+ }
+ });
+ },
+
+ getDataStorage: function (id) {
+ return $exeDevices.iDevice.gamification.helpers.isJsonString(
+ localStorage.getItem('dataCotejo-' + id)
+ );
+ },
+
+ createInterfaceListaCotejo: function (instance) {
+ const mOptions = $eXeListaCotejo.options[instance],
+ urll =
+ mOptions.urlLogo ||
+ `${$eXeListaCotejo.idevicePath}cotejologo.png`,
+ urlc =
+ mOptions.urlCommunity ||
+ `${$eXeListaCotejo.idevicePath}cotejologocomunidad.png`,
+ urld =
+ mOptions.urlDecorative ||
+ `${$eXeListaCotejo.idevicePath}cotejoicon.png`,
+ isMobile =
+ /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(
+ navigator.userAgent
+ ),
+ dl = mOptions.hasLogo ? 'block' : 'none',
+ dc = mOptions.hasCommunity ? 'block' : 'none',
+ dd = mOptions.hasDecorative && !isMobile ? 'block' : 'none',
+ footer = mOptions.footer || '',
+ df = footer ? 'block' : 'none',
+ ud = mOptions.userData ? 'flex' : 'none',
+ us = mOptions.userScore ? 'block' : 'none',
+ html = `
+
+
+
+
+
${mOptions.title}
+
${mOptions.subtitle}
+
+
+
+
${mOptions.msgs.msgComplit}
+
${mOptions.msgs.msgScore}
+
+
+
${$eXeListaCotejo.createItems(instance)}
+
+
+
+
+
+
+
+
+
+
`;
+ return html;
+ },
+
+ addEvents: function (instance) {
+ const mOptions = $eXeListaCotejo.options[instance];
+
+ $('#ctjCapture-' + instance).on('click', function (e) {
+ e.preventDefault();
+ $eXeListaCotejo.saveReport(instance);
+ });
+
+ $('#ctjItems-' + instance)
+ .find('.CTJP-Item')
+ .on(
+ 'input',
+ "input[type='checkbox'], input[type='text']",
+ function () {
+ $eXeListaCotejo.saveCotejo(instance);
+ $eXeListaCotejo.counter(instance);
+ }
+ );
+
+ $('#ctjItems-' + instance)
+ .find('.CTJP-Item')
+ .on('change', 'select', function () {
+ $eXeListaCotejo.saveCotejo(instance);
+ $eXeListaCotejo.counter(instance);
+ });
+
+ $('#ctjUserName-' + instance).on('change', function () {
+ $eXeListaCotejo.saveCotejo(instance);
+ });
+
+ $('#ctjUserDate-' + instance).on('change', function () {
+ $eXeListaCotejo.saveCotejo(instance);
+ });
+
+ mOptions.save = false;
+
+ if (mOptions.saveData && mOptions.id) {
+ $eXeListaCotejo.updateItems(mOptions.id, instance);
+ mOptions.save = true;
+ }
+
+ $eXeListaCotejo.counter(instance);
+
+ const containerHtml = $('#ctjGameContainer-' + instance).html();
+ if ($exeDevices.iDevice.gamification.math.hasLatex(containerHtml)) {
+ $exeDevices.iDevice.gamification.math.updateLatex(
+ '#ctjGameContainer-' + instance
+ );
+ }
+
+ $('#ctjReboot-' + instance).on('click', function (e) {
+ e.preventDefault();
+ if (confirm(mOptions.msgs.msgDelete)) {
+ localStorage.removeItem('dataCotejo-' + mOptions.id);
+ mOptions.points = 0;
+ mOptions.totalPoints = 0;
+ $('#ctjUserName-' + instance).val('');
+ $('#ctjUserDate-' + instance).val('');
+ $('#ctjItems-' + instance).empty();
+ $('#ctjItems-' + instance).append(
+ $eXeListaCotejo.createItems(instance)
+ );
+ $eXeListaCotejo.counter(instance);
+ }
+ });
+ },
+
+ counter: function (instance) {
+ const mOptions = $eXeListaCotejo.options[instance];
+ let completados = 0,
+ en_proceso = 0,
+ total_items = 0,
+ points = 0;
+
+ $('#ctjItems-' + instance)
+ .find('.CTJP-Item')
+ .each(function (i) {
+ if ($(this).find('input[type="checkbox"], select').length > 0) {
+ total_items++;
+ }
+ if ($(this).find('input[type="checkbox"]:checked').length > 0) {
+ completados++;
+ points += $eXeListaCotejo.convertToNumber(
+ mOptions.levels[i].points
+ );
+ }
+ if (
+ $(this).find('select option[value="1"]:selected').length > 0
+ ) {
+ completados++;
+ points += $eXeListaCotejo.convertToNumber(
+ mOptions.levels[i].points
+ );
+ }
+ if (
+ $(this).find('select option[value="2"]:selected').length > 0
+ ) {
+ en_proceso++;
+ points +=
+ $eXeListaCotejo.convertToNumber(
+ mOptions.levels[i].points
+ ) / 2;
+ }
+ });
+
+ mOptions.points = points;
+
+ $('#ctjCounter-' + instance).hide();
+ if (mOptions.showCounter) {
+ let ct =
+ mOptions.msgs.msgComplit +
+ ': ' +
+ completados +
+ '/' +
+ total_items +
+ '. ';
+ if (en_proceso > 0) {
+ ct +=
+ mOptions.msgs.msgInProgress +
+ ': ' +
+ en_proceso +
+ '/' +
+ total_items +
+ '.';
+ }
+ if (completados == 0 && en_proceso == 0) {
+ ct = mOptions.msgs.msgtaskNumber + ': ' + total_items;
+ }
+ $('#ctjCounter-' + instance).text(ct);
+ $('#ctjCounter-' + instance).show();
+ }
+
+ $('#ctjScore-' + instance).hide();
+
+ if (mOptions.useScore && mOptions.totalPoints > 0) {
+ const ctj =
+ mOptions.msgs.msgScore +
+ ': ' +
+ mOptions.points +
+ '/' +
+ mOptions.totalPoints +
+ '.';
+ $('#ctjScore-' + instance).text(ctj);
+ $('#ctjScore-' + instance).show();
+ }
+ },
+
+ convertToNumber: function (str) {
+ let num = parseInt(str);
+ return isNaN(num) ? 0 : num;
+ },
+
+ saveReport: function (instance) {
+ const mOptions = $eXeListaCotejo.options[instance],
+ divElement = document.getElementById('ctjList-' + instance);
+
+ if (!divElement) {
+ console.error(
+ 'No se encontró el elemento con el ID proporcionado.'
+ );
+ return;
+ }
+
+ const mmls = $('#ctjList-' + instance).find('mjx-assistive-mml');
+ const originalOpacities = [];
+ mmls.each(function (idx) {
+ originalOpacities[idx] = $(this).css('opacity');
+ $(this).css('opacity', '0.0');
+ });
+
+ html2canvas(divElement)
+ .then(function (canvas) {
+ const imgData = canvas.toDataURL('image/png');
+
+ const fallbackPng = function () {
+ try {
+ const link = document.createElement('a');
+ link.href = imgData;
+ link.download =
+ (mOptions.msgs && mOptions.msgs.msgList
+ ? mOptions.msgs.msgList
+ : 'lista') + '.png';
+ link.click();
+ } catch (e) {
+ console.error('Error al descargar la imagen:', e);
+ }
+ };
+
+ const doPdf = function () {
+ try {
+ if (!window.jspdf || !window.jspdf.jsPDF) return false;
+ const pdf = new window.jspdf.jsPDF('p', 'mm', 'a4');
+ const imgProps = pdf.getImageProperties(imgData);
+ const pdfWidth = pdf.internal.pageSize.getWidth();
+ const pdfHeight = pdf.internal.pageSize.getHeight();
+ const imgHeight =
+ (imgProps.height * pdfWidth) / imgProps.width;
+
+ let heightLeft = imgHeight;
+ let position = 0;
+
+ pdf.addImage(
+ imgData,
+ 'PNG',
+ 0,
+ position,
+ pdfWidth,
+ imgHeight
+ );
+ heightLeft -= pdfHeight;
+
+ while (heightLeft > 0) {
+ position -= pdfHeight;
+ pdf.addPage();
+ pdf.addImage(
+ imgData,
+ 'PNG',
+ 0,
+ position,
+ pdfWidth,
+ imgHeight
+ );
+ heightLeft -= pdfHeight;
+ }
+
+ const fileName =
+ (mOptions.msgs && mOptions.msgs.msgList
+ ? mOptions.msgs.msgList
+ : 'lista') + '.pdf';
+ pdf.save(fileName);
+ return true;
+ } catch (e) {
+ console.error('Error al generar el PDF: ', e);
+ return false;
+ }
+ };
+
+ if (window.jspdf && window.jspdf.jsPDF) {
+ if (!doPdf()) fallbackPng();
+ } else {
+ $eXeListaCotejo.ensureJsPDF(
+ function onReady() {
+ if (!doPdf()) fallbackPng();
+ },
+ function onError() {
+ fallbackPng();
+ }
+ );
+ }
+ })
+ .catch(function (error) {
+ console.error('Error al generar la captura: ', error);
+ })
+ .finally(function () {
+ mmls.each(function (idx) {
+ $(this).css('opacity', originalOpacities[idx]);
+ });
+ });
+ },
+
+ createItems: function (instance) {
+ const mOptions = $eXeListaCotejo.options[instance];
+ let html = '';
+ for (let i = 0; i < mOptions.levels.length; i++) {
+ const level = mOptions.levels[i];
+ const marginLeft = 1.5 * parseInt(level.nivel) + 0.5,
+ msgp =
+ level.points.trim() == '1'
+ ? mOptions.msgs.msgPoint
+ : mOptions.msgs.msgPoints,
+ msg = '(' + level.points + ' ' + msgp + ')',
+ points =
+ mOptions.useScore && level.points.trim().length > 0
+ ? msg
+ : '';
+
+ if (level.type === '0') {
+ const cid = `ctjToggle-${instance}-${i}`;
+ html += `
+
+
+
+
+
+
${points}
+
`;
+ } else if (level.type === '1') {
+ const cid = `ctjToggle-${instance}-${i}`;
+ html += `
+
+
+ ${points}
+
+
+
`;
+ }
+ }
+ return html;
+ },
+
+ ensureJsPDF: function (onReady, onError) {
+ try {
+ if (window.jspdf && window.jspdf.jsPDF) {
+ onReady && onReady();
+ return;
+ }
+ } catch (_) {}
+
+ const scriptId = 'jspdf-umd-loader';
+ const existing = document.getElementById(scriptId);
+ if (existing) {
+ let tries = 0;
+ const iv = setInterval(function () {
+ tries++;
+ if (window.jspdf && window.jspdf.jsPDF) {
+ clearInterval(iv);
+ onReady && onReady();
+ } else if (tries > 50) {
+ clearInterval(iv);
+ onError && onError();
+ }
+ }, 100);
+ return;
+ }
+
+ const s = document.createElement('script');
+ s.id = scriptId;
+ s.src = 'https://cdn.jsdelivr.net/npm/jspdf/dist/jspdf.umd.min.js';
+ s.async = true;
+ s.onload = function () {
+ onReady && onReady();
+ };
+ s.onerror = function () {
+ onError && onError();
+ };
+ document.head.appendChild(s);
+ },
+};
+$(function () {
+ $eXeListaCotejo.init();
+});
diff --git a/vendor/exelearning/export-resources/idevices/checklist/export/cotejoicon.png b/vendor/exelearning/export-resources/idevices/checklist/export/cotejoicon.png
new file mode 100644
index 0000000..365de44
Binary files /dev/null and b/vendor/exelearning/export-resources/idevices/checklist/export/cotejoicon.png differ
diff --git a/vendor/exelearning/export-resources/idevices/checklist/export/cotejologo.png b/vendor/exelearning/export-resources/idevices/checklist/export/cotejologo.png
new file mode 100644
index 0000000..d9b76f6
Binary files /dev/null and b/vendor/exelearning/export-resources/idevices/checklist/export/cotejologo.png differ
diff --git a/vendor/exelearning/export-resources/idevices/checklist/export/cotejologocomunidad.png b/vendor/exelearning/export-resources/idevices/checklist/export/cotejologocomunidad.png
new file mode 100644
index 0000000..8895395
Binary files /dev/null and b/vendor/exelearning/export-resources/idevices/checklist/export/cotejologocomunidad.png differ
diff --git a/vendor/exelearning/export-resources/idevices/checklist/export/html2canvas.js b/vendor/exelearning/export-resources/idevices/checklist/export/html2canvas.js
new file mode 100644
index 0000000..72411e9
--- /dev/null
+++ b/vendor/exelearning/export-resources/idevices/checklist/export/html2canvas.js
@@ -0,0 +1,11310 @@
+/*!
+ * html2canvas 1.4.1