PageSourceSearch

https://elviajedelili.netlify.app/libs/exe_export.js

js elviajedelili.netlify.app collected 2026-10-03 10:41:45 UTC 19,291 bytes, 512 lines download raw bytes

1$exeExport = {
2
3    isTogglingBox: false,
4    delayLoadingPageTime: 200,
5    delayLoadingIdevicesJson: 50,
6    delayLoadScorm: 50,
7    scormAPIwrapper: 'SCORM_API_wrapper.js',
8    scormFunctions: 'SCOFunctions.js',
9
10    init: function () {
11        try {
12            this.addBoxToggleEvent();
13        } catch (err) {
14            console.error('Error: Failed to initialize box toggle events');
15        }
16        try {
17            this.setExe();
18            this.initExe();
19            this.initJsonIdevices();
20        } catch (err) {
21            console.error('Error: Failed to initialize content');
22        }
23        try {
24            this.loadScorm();
25        } catch (err) {
26            console.error('Error: Failed to initialize SCORM');
27        }
28        // setTimeout to allow custom button in style
29        setTimeout(function(){
30            try {
31                $exeExport.teacherMode.init();
32            } catch (err) {
33                console.error('Error: Failed to initialize Teacher Mode');
34            }
35        }, 100);
36        setTimeout(() => { this.addClassJsExecutedToExeContent() }, this.delayLoadingPageTime);
37        setTimeout(() => {
38            try {
39                this.triggerPrintIfRequested();
40            } catch (err) {
41                console.error('Error: Failed to trigger print dialog');
42            }
43        }, this.delayLoadingPageTime);
44    },
45
46    /**
47     * Set eXe object
48     */
49    setExe: function () {
50        window.eXe = {};
51        window.eXe.app = $exe;
52    },
53
54    /**
55     * Init legacy $exe object
56     */
57    initExe: function () {
58        window.eXe.app.init();
59    },
60    
61    /**
62     * Teacher Mode
63     */
64    teacherMode : {
65        STORAGE_KEY : 'exeTeacherMode',
66        init : function(){
67            if (typeof(localStorage)!='object') return;
68            if ($(".box.teacher-only").length==0 && $(".idevice_node.teacher-only").length==0) return;
69            if (document.getElementById("teacher-mode-toggler")) return;
70            if ($("body").hasClass("exe-epub")) return;
71            document.body.classList.add('exe-teacher-mode-toggler');
72            var btn = '<div class="form-check form-switch" id="teacher-mode-toggler-wrapper"><input class="form-check-input" type="checkbox" role="switch" id="teacher-mode-toggler"><label class="form-check-label" for="teacher-mode-toggler">'+$exe_i18n.teacher_mode+'</label></div>';
73            $(".package-header").prepend(btn);
74            this.toggler = $("#teacher-mode-toggler");
75            var enabled = this.isEnabled();
76            if (enabled) {
77                this.toggler.prop("checked", true);
78                document.documentElement.classList.add('mode-teacher');
79            }
80            this.toggler.on("change", function(){
81                var root = document.documentElement;
82                var key = $exeExport.teacherMode.STORAGE_KEY;
83                if (this.checked) {
84                    localStorage.setItem(key, '1');
85                    root.classList.add('mode-teacher');
86                } else {
87                    localStorage.removeItem(key);
88                    root.classList.remove('mode-teacher');
89                }
90            });
91        },
92        isEnabled : function(){
93            try {
94                return localStorage.getItem(this.STORAGE_KEY) === '1';
95            } catch (e) {
96                return false;
97            }
98        }
99    },
100
101    /**
102     * Load SCO functions
103     */
104    loadScorm: function () {
105        if (document.querySelector('body').classList.contains('exe-scorm')) {
106            var loadScormScriptInterval = setInterval(() => {
107                if (typeof window.scorm != 'undefined' && typeof window.loadPage == 'function') {
108                    this.initScorm();
109                    clearInterval(loadScormScriptInterval);
110                }
111            }, this.delayLoadScorm)
112        }
113    },
114
115    /**
116     * Load scorm page item
117     */
118    initScorm: function () {
119        if (typeof window.scorm != 'undefined' && typeof window.loadPage == 'function') {
120            var isSCORM = false;
121            // We go through the activities to see if any save scorm data
122            let idevicesNodes = document.querySelectorAll('.idevice_node');
123            idevicesNodes.forEach(ideviceNode => {
124                let ideviceComponentType = ideviceNode.getAttribute('data-idevice-component-type');
125                let ideviceType = ideviceNode.getAttribute('data-idevice-type');
126                let ideviceObject = this.getIdeviceObject(ideviceType);
127                if (ideviceObject) {
128                    // Check if idevice save scorm data
129                    switch (ideviceComponentType) {
130                        case 'js':
131                            if (ideviceObject.options) {
132                                ideviceObject.options.forEach(instanteOptions => {
133                                    if (instanteOptions.isScorm) isSCORM = true;
134                                })
135                            }
136                            break;
137                        case 'json':
138                            let jsonDataText = ideviceNode.getAttribute('data-idevice-json-data');
139                            let jsonData = null;
140
141                            // Parse JSON data (sanitized) or create empty object if not valid
142                            try {
143                                if (jsonDataText) {
144                                    const sanitized =
145                                        $exeDevices.iDevice.gamification.helpers.sanitizeJSONString(
146                                            jsonDataText
147                                        );
148                                    jsonData = JSON.parse(sanitized);
149                                }
150                            } catch (e) {
151                                jsonData = null;
152                            }
153
154                            // Check for SCORM data if jsonData is valid
155                            if (jsonData && jsonData.exportScorm && jsonData.exportScorm.saveScore) {
156                                isSCORM = true;
157                            }
158                            break;
159                    }
160                }
161            })
162            window.loadPage()
163            window.addEventListener('unload', () => window.unloadPage(isSCORM));
164        }
165    },
166
167    /**
168     * Init export json idevices
169     */
170    initJsonIdevices: function () {
171        // Get idevices
172        let idevicesTypes = {};
173        let idevicesNodes = document.querySelectorAll('.idevice_node');
174        idevicesNodes.forEach(ideviceNode => {
175            let ideviceComponentType = ideviceNode.getAttribute('data-idevice-component-type');
176            if (ideviceComponentType == 'json') {
177                let ideviceType = ideviceNode.getAttribute('data-idevice-type');
178                idevicesTypes[ideviceType] = true;
179            }
180        })
181        // Init idevices
182        Object.keys(idevicesTypes).forEach(ideviceType => {
183            this.initJsonIdeviceInterval(ideviceType);
184        })
185    },
186
187    /**
188     * Init init export json idevice interval
189     *
190     * @param {*} ideviceType
191     */
192    initJsonIdeviceInterval: function (ideviceType) {
193        let intervalName = 'eXe_idevice_init_interval_' + ideviceType;
194        window[intervalName] = setInterval(
195            () => this.initJsonIdevice(ideviceType, intervalName),
196            this.delayLoadingIdevicesJson);
197    },
198
199    /**
200     * Init export json idevice
201     *
202     * @param {*} ideviceType
203     */
204    initJsonIdevice: function (ideviceType, intervalName) {
205        // Idevice export object
206        let exportIdevice = this.getIdeviceObject(ideviceType);
207        if (exportIdevice === undefined) return false;
208        // Get json data and initializes each page component of the indicated type
209        let idevicesNodes = document.querySelectorAll(`.idevice_node.${ideviceType}`);
210        idevicesNodes.forEach(ideviceNode => {
211            // Loading class
212            ideviceNode.classList.add('loading');
213            // Get json data
214            let jsonDataText = ideviceNode.getAttribute('data-idevice-json-data');
215            let jsonData = null;
216
217            // Parse JSON data or create empty object if not valid
218            try {
219                if (jsonDataText) {
220                    const sanitized =
221                        $exeDevices.iDevice.gamification.helpers.sanitizeJSONString(
222                            jsonDataText
223                        );
224                    jsonData = JSON.parse(sanitized);
225                }
226            } catch (e) {
227                jsonData = null;
228            }
229
230            // If jsonData is not an object, create an empty one
231            if (!jsonData || typeof jsonData !== 'object' || Array.isArray(jsonData)) {
232                jsonData = {};
233            }
234
235            jsonData.ideviceId = ideviceNode.id;
236            // Get accesibility
237            let accesibility = null;
238            // Get template
239            let template = ideviceNode.getAttribute('data-idevice-template');
240            // Idevice export function 1: renderView
241            if (ideviceNode.classList.contains('db-no-data')) {
242                let htmlIdevice = exportIdevice.renderView(jsonData, accesibility, template);
243                if (htmlIdevice) ideviceNode.innerHTML = htmlIdevice;
244            }
245            // Idevice export function 2: renderBehaviour
246            exportIdevice.renderBehaviour(jsonData, accesibility);
247            // Idevice export function 3: init
248            exportIdevice.init(jsonData, accesibility);
249            // Loaded
250            ideviceNode.classList.add('loaded');
251            setTimeout(() => { ideviceNode.classList.remove('loading') }, 100);
252        })
253        // Clear interval
254        clearInterval(window[intervalName]);
255    },
256
257
258    /**
259     * Get idevice export object
260     *
261     * @param {*} ideviceType
262     */
263    getIdeviceObject: function (ideviceType) {
264        let exportIdeviceKey = this.getIdeviceObjectKey(ideviceType);
265        let exportIdevice = window[exportIdeviceKey];
266        return exportIdevice;
267    },
268
269    /**
270     * Get idevice export object key
271     *
272     * @param {*} ideviceType
273     */
274    getIdeviceObjectKey: function (ideviceType) {
275        let exportIdeviceKey = `$${ideviceType.split("-").join("")}`;
276        return exportIdeviceKey;
277    },
278
279    /**
280     * Add functionality to the boxes toggle button
281     */
282    addBoxToggleEvent: function () {
283        
284        $('article.box .box-head .box-toggle').on('click', function(){
285            if ($exeExport.isTogglingBox) return;
286            $exeExport.isTogglingBox = true;
287            let box = $(this).parents('article.box');
288            if (box.hasClass("minimized")) {
289                box.removeClass('minimized');
290                $('.box-content', box).slideDown(function(){
291                    $exeExport.isTogglingBox = false;
292                });
293            } else {
294                $('.box-content', box).slideUp(function(){
295                    box.addClass('minimized');
296                    $exeExport.isTogglingBox = false;
297                });
298            }
299        });
300        $('article.box .box-head').css('cursor', 'pointer').on('click', function(e){
301            let t = $(e.target);
302            if (t.hasClass('box-toggle')) return false;
303            $('.box-toggle', this).trigger('click');
304        });
305        
306    },
307
308    /**
309     * Add class to page
310     */
311    addClassJsExecutedToExeContent: function () {
312        let eXeContent = document.querySelector('.exe-content');
313        if (eXeContent) {
314            eXeContent.classList.add('post-js');
315            eXeContent.classList.remove('pre-js');
316        }
317    },
318
319    /**
320     * Trigger browser print dialog when `print=1` query parameter is present.
321     */
322    triggerPrintIfRequested: function () {
323        const params = new URLSearchParams(window.location.search);
324        if (params.get('print') === '1' && typeof window.print === 'function') {
325            window.print();
326        }
327    }
328}
329
330$(function () {
331    $exeExport.init();
332});
333
334/* To review: This should be in a different file (exe_search.js) */
335$exeExport.searchBar = {
336    deepLinking : false,
337    markResults : false,
338    query : '',
339    init : function(){
340        var searchWrapper = $('#exe-client-search');
341        if (searchWrapper.length != 1) return;
342        $("body").addClass('exe-search-on');
343        this.isIndex = $("html").attr('id') == 'exe-index';
344        this.isPreview = window.location.href.indexOf('/file/resources?resource=/tmp/') != -1;
345        this.createSearchForm();
346        this.data = JSON.parse(searchWrapper.attr('data-pages'));
347
348        let page = document.querySelector('.exe-content > .page');
349        let searchContainer = document.querySelector('#exe-client-search');
350        if (searchContainer) {
351            let searchForm = document.querySelector('form#exe-client-search-form');
352            if (searchForm) {
353                searchForm.addEventListener('submit', event => {
354                    event.preventDefault();
355                    let searchText = event.target.querySelector('#exe-client-search-text');
356                    if (searchText) {
357                        let valueSearch = searchText.value;
358                        let valueSearchTempElement = document.createElement("div");
359                        valueSearchTempElement.innerHTML = valueSearch;
360                        valueSearch = valueSearchTempElement.textContent;
361                        if (valueSearch) {
362                            $exeExport.searchBar.query = valueSearch;
363                            this.doSearch();
364                            page.classList.add('exe-client-search-results');
365                        }
366                    }
367                });
368            }
369            let searchHide = document.querySelector('#exe-client-search #exe-client-search-reset');
370            if (searchHide) {
371                searchHide.addEventListener('click', event => {
372                    event.preventDefault();
373                    $("main > header, main div.page-content").show();
374                    $("#exe-client-search-reset").removeClass("visible");
375                    $('#exe-client-search-results-list').html('');
376                })
377            }
378        }
379    },
380    createSearchForm : function(){
381        if (document.getElementById("exe-client-search-form")) return;
382        let html = `
383            <form id="exe-client-search-form" action="#" method="GET">
384                <p>
385                    <label for="exe-client-search-text" class="sr-av">${$exe_i18n.search}</label>
386                    <input id="exe-client-search-text" type="text" placeholder="${$exe_i18n.search}">
387                    <input id="exe-client-search-submit" type="submit" value="Búsqueda">
388                    <a id="exe-client-search-reset" href="#main" title="${$exe_i18n.hide}"><span>${$exe_i18n.hide}</span></a>
389                </p>
390            </form>
391        `;
392        $("#exe-client-search").prepend(html);
393        html = `
394            <div id="exe-client-search-results">
395                <div id="exe-client-search-results-list">
396                </div>
397            </div>
398        `;
399        $("#exe-client-search").append(html);
400    },
401    doSearch : function(){
402        this.results = [];
403        var i;
404        let res = '';
405        let str = $exeExport.searchBar.query;
406        str = str.toLowerCase();
407        let data = this.data;
408        for (i in data) {
409            var node = data[i];
410            var nodeTitle = node.name;
411            var nodetitle = nodeTitle.toLowerCase();
412            if (nodetitle.indexOf(str) != -1) {
413                this.results.push(i);
414                let lnk = this.getLink(node.fileUrl);
415                res += '<li><a href="' + lnk +'">' + nodeTitle + '</a><span> ' + this.searchInBlocks(i, str, false) + '</span></li>';
416            } else {
417                res += this.searchInBlocks(i, str, true);
418            }
419        }
420        if (res != '') {
421            res = '<ul>' + res + '</ul>';
422        } else {
423            res = '<p>'+$("#exe-client-search").attr("data-no-results-string")+'</p>';
424        }
425        $("#exe-client-search-results-list").html(res);
426        $("main > header, main div.page-content").hide();
427        $("#exe-client-search-reset").addClass("visible");
428        this.checkBlockLinks();
429    },
430    getLink : function(lnk){
431        if (this.isPreview) return lnk;
432        if (!this.isIndex) {
433            lnk = lnk.replace('html/','');
434            if (lnk == 'index.html') lnk = '../' + lnk;
435        }
436        return lnk;
437    },
438    checkBlockLinks : function(){
439        let spans = $("#exe-client-search-results-list span");
440        if (this.deepLinking) {
441            spans.each(function(){
442                var e = $(this);
443                var h = e.html();
444                if (h != " ") {
445                    h = h.replace(', ', '(');
446                    if (!h.endsWith(')')) h = h + ')';
447                    e.html(h);
448                } else {
449                    e.remove();
450                }
451            });
452        } else {
453            spans.remove();
454        }
455        $("#exe-client-search-results-list a").on("click", function(){
456            if (!$("#siteNav").is(":visible")) this.href += '?nav=false';
457        });
458    },
459    searchInBlocks : function(i, str, fullLink) {
460        if (this.deepLinking == false && this.results.indexOf(i) != -1) {
461            return '';
462        }
463        var x, z;
464        let res = '';
465        var node = this.data[i];
466        var nodeTitle = node.name;
467        var boxes = node.blocks;
468        var boxCounter = 0;
469        for (x in boxes) {
470            boxCounter ++;
471        }
472        for (x in boxes) {
473            var box = boxes[x];
474            var boxOrder = box.order;
475            var boxTitle = box.name;
476            var boxtitle = boxTitle.toLowerCase();
477
478            // Add the HTML of the iDevices to boxtitle so it searches there too
479            var iDevices = box.idevices;
480            for (z in iDevices) {
481                var iDevice = iDevices[z];
482                if (typeof(iDevice.htmlView) == 'string') {
483                    var iDeviceHTML = iDevice.htmlView;
484                        iDeviceHTML = iDeviceHTML.replace(/<\/?[^>]+(>|$)/g, "");
485                    var tmp = $("<div></div>");
486                        tmp.html(iDeviceHTML);
487                    var iDeviceText = tmp.text();
488                        iDeviceText = iDeviceText.toLowerCase();
489                    boxtitle += ' ' + iDeviceText;
490                }
491            }
492
493            if (boxtitle.indexOf(str) != -1) {
494                this.results.push(i);
495                let lnk = this.getLink(node.fileUrl);
496                if (fullLink) {
497                    if (this.deepLinking) lnk += '#' + x;
498                    res += '<li><a href="' + lnk+ '">' + nodeTitle + '</a>';
499                    if (boxCounter > 1) res += '<span> (bloque ' + boxOrder + ')</span></li>';
500                }
501                else {
502                    if (boxCounter > 1) res += ', <a href="' + lnk +'#' + x + '">bloque ' + boxOrder + '</a>';
503                }
504            }
505        }
506        return res;
507    }
508};
509
510$(function(){
511    $exeExport.searchBar.init();
512});

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.