Proyectos de Subversion Moodle

Rev

| Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1 efrain 1
/**
2
 * Collect results from xAPI events
3
 */
4
(function($) {
5
 
6
    /**
7
     * Finds a H5P library instance in an array based on the content ID
8
     *
9
     * @param  {Array} instances
10
     * @param  {number} contentId
11
     * @returns {Object|undefined} Content instance
12
     */
13
    function findInstanceInArray(instances, contentId) {
14
        if (instances !== undefined && contentId !== undefined) {
15
            for (var i = 0; i < instances.length; i++) {
16
                if (instances[i].contentId === contentId) {
17
                    return instances[i];
18
                }
19
            }
20
        }
21
        return undefined;
22
    }
23
 
24
    /**
25
     * Finds the global instance from content id by looking through the DOM
26
     *
27
     * @param {number} [contentId] Content identifier
28
     * @returns {Object} Content instance
29
     */
30
    function getH5PInstance(contentId) {
31
        var iframes;
32
        var instance = null; // Returning null means no instance is found.
33
 
34
        // No content id given, search for instance.
35
        if (!contentId) {
36
            instance = H5P.instances[0];
37
            if (!instance) {
38
                iframes = document.getElementsByClassName('h5p-iframe');
39
                // Assume first iframe.
40
                instance = iframes[0].contentWindow.H5P.instances[0];
41
            }
42
        } else {
43
            // Try this documents instances.
44
            instance = findInstanceInArray(H5P.instances, contentId);
45
            if (!instance) {
46
                // Locate iframes.
47
                iframes = document.getElementsByClassName('h5p-iframe');
48
                for (var i = 0; i < iframes.length; i++) {
49
                    // Search through each iframe for content.
50
                    instance = findInstanceInArray(iframes[i].contentWindow.H5P.instances, contentId);
51
                    if (instance) {
52
                        break;
53
                    }
54
                }
55
            }
56
        }
57
 
58
        return instance;
59
    }
60
 
61
    function getIframe(contentId) {
62
        let iFrames;
63
 
64
        // No content id given.
65
        if (!contentId) {
66
            iFrames = document.getElementsByClassName('h5p-iframe');
67
            // Assume first iframe.
68
            return iFrames[0];
69
        }
70
 
71
        // Locate iFrames.
72
        iFrames = document.getElementsByClassName('h5p-iframe');
73
        for (let i = 0; i < iFrames.length; i++) {
74
            // Search through each iframe for content.
75
            if (findInstanceInArray(iFrames[i].contentWindow.H5P.instances, contentId)) {
76
                return iFrames[i];
77
            }
78
        }
79
 
80
        return null;
81
    }
82
 
83
    /**
84
     * Get xAPI data for content type and send off.
85
     *
86
     * @param {number} contentId Content id
87
     * @param {Object} event Original xAPI event
88
     */
89
    function storeXAPIData(contentId, event) {
90
        var xAPIData;
91
        var instance = getH5PInstance(contentId);
92
 
93
        // Use getXAPIData contract, needed to get children.
94
        if (instance && instance.getXAPIData) {
95
            xAPIData = instance.getXAPIData();
96
        } else {
97
            // Fallback to event data.
98
            xAPIData = {
99
                statement: event.data.statement
100
            };
101
        }
102
 
103
        // Ship the xAPI result.
104
        var data = {
105
            contentId: contentId,
106
            xAPIResult: JSON.stringify(xAPIData)
107
        };
108
        $.post(H5PIntegration.ajax.xAPIResult, data).done(function (data) {
109
            if (data.error) {
110
                console.error('Storing xAPI results failed with error message:', data);
111
            }
112
        }).fail(function () {
113
            if (H5P.offlineRequestQueue) {
114
                H5P.offlineRequestQueue.add(H5PIntegration.ajax.xAPIResult, data);
115
                return;
116
            }
117
 
118
            // Let H5P iframe know that we want to queue the request for late transmission.
119
            const iframe = getIframe(contentId);
120
            if (!iframe) {
121
                return;
122
            }
123
            iframe.contentWindow.postMessage( {
124
                url: H5PIntegration.ajax.xAPIResult,
125
                data: data,
126
                context: 'h5p',
127
                action: 'queueRequest',
128
            });
129
        });
130
    }
131
 
132
    $(document).ready(function() {
133
        // No external dispatcher.
134
        if (!(window.H5P && H5P.externalDispatcher)) {
135
            console.error('External dispatcher not found');
136
            return;
137
        }
138
 
139
        // No ajax path.
140
        if (!(window.H5PIntegration && H5PIntegration.ajax && H5PIntegration.ajax.xAPIResult)) {
141
            console.error('No ajax path found');
142
            return;
143
        }
144
 
145
        // Get emitted xAPI data.
146
        H5P.externalDispatcher.on('xAPI', function(event) {
147
            // Skip malformed events.
148
            var hasStatement = event && event.data && event.data.statement;
149
            if (!hasStatement) {
150
                return;
151
            }
152
 
153
            var statement = event.data.statement;
154
            var validVerb = statement.verb && statement.verb.display && statement.verb.display['en-US'];
155
            if (!validVerb) {
156
                return;
157
            }
158
 
159
            var isCompleted = statement.verb.display['en-US'] === 'answered' ||
160
                statement.verb.display['en-US'] === 'completed';
161
            var isChild = statement.context && statement.context.contextActivities &&
162
                statement.context.contextActivities.parent &&
163
                statement.context.contextActivities.parent[0] &&
164
                statement.context.contextActivities.parent[0].id;
165
 
166
            // Store only completed root events.
167
            if (isCompleted && !isChild) {
168
                // Get xAPI data with children if possible.
169
                storeXAPIData(this.contentId, event);
170
            }
171
        });
172
    });
173
})(H5P.jQuery);