Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add xapi video verbs #17

Open
wants to merge 149 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
149 commits
Select commit Hold shift + click to select a range
fa94009
Added Seeked Functionailty
KirkJohnson Nov 6, 2017
6aea788
Added xAPI extending functionality
KirkJohnson Nov 6, 2017
28c3266
Added xAPI for Youtube
KirkJohnson Nov 7, 2017
6df9a91
xAPI on Youtube, html5, and videojs
KirkJohnson Nov 7, 2017
ba72e7d
changes to get Seek working correctly
KirkJohnson Nov 7, 2017
3ffd605
Fixed seeked on Youtube player
KirkJohnson Nov 8, 2017
3a19499
Got Context added to xAPI statements
KirkJohnson Nov 8, 2017
910f714
Adjusted Youtube’s Seek capabilities
KirkJohnson Nov 8, 2017
749f896
Removed unused variables from Youtube
KirkJohnson Nov 8, 2017
73f9072
Ensured Session ID was in every call for each video player
KirkJohnson Nov 8, 2017
9ee8c07
Ensure xAPI played event sent appropriately
KirkJohnson Nov 8, 2017
6cc6009
Moved Competion Prams into a function
KirkJohnson Nov 9, 2017
fff638d
Reverted Changes on Video JS
KirkJohnson Nov 9, 2017
68c2482
Modifying for seek
KirkJohnson Nov 14, 2017
3b357b4
Modified Seek Event for YouTube
KirkJohnson Nov 14, 2017
8680f05
Format Float on played segments
KirkJohnson Nov 14, 2017
b559407
Fix whitespace
figureone Nov 17, 2017
2cb2dce
Add documentation and reorganize
figureone Nov 17, 2017
920f80e
Made Code DRY
KirkJohnson Nov 17, 2017
3527921
Whitespace
figureone Nov 20, 2017
847bd71
Cleaner logic
figureone Nov 20, 2017
157f527
Whitespace (indentation)
figureone Nov 20, 2017
60015e7
Refactor xAPI object function names
figureone Nov 20, 2017
871fb29
Refactor xAPI function names
figureone Nov 20, 2017
e52a8dd
Fix for misnamed variable
figureone Nov 20, 2017
449df2d
Refactor var names (use camelCase, not snake case)
figureone Nov 20, 2017
4924b66
Set default value of getArgsXAPIInitialized param
figureone Nov 20, 2017
8c66406
Added Seeked Functionailty
KirkJohnson Nov 6, 2017
8ef5ba9
Added xAPI extending functionality
KirkJohnson Nov 6, 2017
e08d9c5
Added xAPI for Youtube
KirkJohnson Nov 7, 2017
1c102c7
xAPI on Youtube, html5, and videojs
KirkJohnson Nov 7, 2017
2b5ed92
changes to get Seek working correctly
KirkJohnson Nov 7, 2017
9e8aa9b
Fixed seeked on Youtube player
KirkJohnson Nov 8, 2017
9f22a59
Got Context added to xAPI statements
KirkJohnson Nov 8, 2017
828611e
Adjusted Youtube’s Seek capabilities
KirkJohnson Nov 8, 2017
c16cc62
Removed unused variables from Youtube
KirkJohnson Nov 8, 2017
1988a2d
Ensured Session ID was in every call for each video player
KirkJohnson Nov 8, 2017
6b57fc4
Ensure xAPI played event sent appropriately
KirkJohnson Nov 8, 2017
7245458
Moved Competion Prams into a function
KirkJohnson Nov 9, 2017
25ede9a
Reverted Changes on Video JS
KirkJohnson Nov 9, 2017
778330f
Modifying for seek
KirkJohnson Nov 14, 2017
7561c34
Modified Seek Event for YouTube
KirkJohnson Nov 14, 2017
a640440
Format Float on played segments
KirkJohnson Nov 14, 2017
dd3cefc
Fix whitespace
figureone Nov 17, 2017
18be43b
Add documentation and reorganize
figureone Nov 17, 2017
c4e2861
Made Code DRY
KirkJohnson Nov 17, 2017
3c6e0a9
Whitespace
figureone Nov 20, 2017
1434112
Cleaner logic
figureone Nov 20, 2017
129d56e
Whitespace (indentation)
figureone Nov 20, 2017
ebadcc9
Refactor xAPI object function names
figureone Nov 20, 2017
c16d0fd
Refactor xAPI function names
figureone Nov 20, 2017
a95ae2c
Fix for misnamed variable
figureone Nov 20, 2017
b85a5ec
Refactor var names (use camelCase, not snake case)
figureone Nov 20, 2017
7100eb6
Set default value of getArgsXAPIInitialized param
figureone Nov 20, 2017
6c8dffa
Merge branch 'add-xapi-video-verbs' of https://github.com/uhm-coe/h5p…
figureone Nov 22, 2017
954f51f
Change Completed to Finished
KirkJohnson Nov 22, 2017
f82c2cb
Got finished working
KirkJohnson Nov 22, 2017
a8e7b3f
Fix whitespace
figureone Nov 22, 2017
215da89
Whitespace
figureone Nov 23, 2017
52256cc
Mark verbs not currently working
figureone Nov 23, 2017
15473c2
Fix html5 player firing paused before finished
figureone Nov 23, 2017
15a58c8
Moved statement creation to separate file
KirkJohnson Feb 12, 2018
b1e9a27
Move of xapi statement to new file
KirkJohnson Feb 13, 2018
28b9654
Rename class VideoXapi to VideoXAPI to match capitalization rules
figureone Feb 21, 2018
5eb7492
Bugfix in seekedTo time calculation
figureone Feb 21, 2018
9fe5f95
Don’t include extensions for non set variables
KirkJohnson Feb 22, 2018
58d5638
Changed Finished to Completed
KirkJohnson Feb 22, 2018
02607f0
Adjustments to xapi statements
KirkJohnson Feb 22, 2018
a3d024c
Convert duration in completed to ISO8601
KirkJohnson Feb 22, 2018
c516b82
Refactor VideoXAPI to a helper object
figureone Feb 23, 2018
a35b66c
Fix for video description in xAPI statement
figureone Feb 24, 2018
56d8f0d
Add comments
KirkJohnson Feb 26, 2018
35daa0a
Fix bug with small video durations
figureone Feb 27, 2018
57f9e75
Whitespace
figureone Feb 27, 2018
d292a6f
Remove irrelevant hasOwnProperty() check
figureone Mar 6, 2018
4086a79
guid() is unneeded because of H5P.createUUID()
figureone Mar 6, 2018
66a7928
Remove redundant logic
figureone Mar 6, 2018
735bf09
Fix typo
figureone Mar 6, 2018
745ab2a
Remove unecessary class variable seekStart
figureone Mar 6, 2018
44a36df
Replace obsolete HTML feature Document.fullscreen
figureone Mar 6, 2018
c9a68cf
Whitespace
figureone Mar 6, 2018
5ab4d28
Update completed verb to match change in spec
figureone Mar 6, 2018
cb1b90e
Annotate spec format for progress extension
figureone Mar 6, 2018
0ef32d9
Standardize on 3-decimal precision for floats
figureone Mar 7, 2018
f210eba
Remove unecessary local variables
figureone Mar 7, 2018
467ee4c
Whitespace
figureone Mar 7, 2018
4cf8602
Replace obsolete HTML feature Document.fullscreen
figureone Mar 7, 2018
2012f5b
Remove unused local variable
figureone Mar 7, 2018
ca9a196
Adjusting getProgress()
KirkJohnson Mar 7, 2018
48f51e1
Merge branch 'add-xapi-video-verbs' of https://github.com/uhm-coe/h5p…
KirkJohnson Mar 7, 2018
ca6cd81
Remove unused variable playedSegmentsSegmentEnd
figureone Mar 7, 2018
080f2ce
Rename local variable playedSegmentsSegmentStart to playingSegmentStart
figureone Mar 7, 2018
09583ab
Docs update and whitespace
figureone Mar 7, 2018
a00b8b5
Refactor endPlayedSegment(), getProgress(), and playedSegments
figureone Mar 7, 2018
a4e7dd6
Mark optional params in function headers
figureone Mar 7, 2018
ff3ffb8
Formatting (match H5P code guidelines)
figureone Mar 8, 2018
af8e985
Set quality param to height if not provided
figureone Mar 8, 2018
5558d8f
Lint (redeclaration)
figureone Mar 8, 2018
ff9f1c0
Lint (whitespace)
figureone Mar 8, 2018
ec75b45
Lint (semicolons)
figureone Mar 8, 2018
719add4
Fix syntax in getWidthOrHeight() function
figureone Mar 8, 2018
ef6aef4
Lint (remove ES6 syntax)
figureone Mar 8, 2018
4995735
Fix for played segments
figureone Mar 8, 2018
2eb31e9
Lowered threshold of time for endPlayedSegment
KirkJohnson Mar 8, 2018
7fc4d18
Revert to previous version to accomodate pull
KirkJohnson Mar 8, 2018
31ce7e6
Merge branch 'add-xapi-video-verbs' of https://github.com/uhm-coe/h5p…
KirkJohnson Mar 8, 2018
c8940b2
Re-Add EOF line deleted in last commit
KirkJohnson Mar 8, 2018
a88c17b
HFP-1779 Refactor xAPI statement building
otacke Mar 14, 2018
f3581ac
HFP-1779 Allow false for full-screen extension on init
otacke Mar 14, 2018
0585bbb
HFP-1779 Build xAPIObject with base information only once
otacke Mar 14, 2018
94aa8c2
HFP-1779 Move xAPI trigger to video.js
otacke Mar 14, 2018
40db1c3
HFP-1779 Move video state variables to video object
otacke Mar 14, 2018
4346b92
Fix for uncaught error when editing a new video
figureone Mar 14, 2018
6c0dbf9
Cache result of getXAPIObject (optimization)
figureone Mar 14, 2018
2224edd
Whitespace
figureone Mar 14, 2018
d0bc373
HFP-1779 Allow different verb definition origins
otacke Mar 18, 2018
83c472a
Merge remote-tracking branch 'upstream/add-xapi-video-verbs' into add…
otacke Mar 18, 2018
f132369
Merge pull request #1 from otacke/add-xapi-video-verbs
figureone Mar 23, 2018
f3ed616
Implement volumechange event in youtube.js
figureone Mar 23, 2018
d6e4f24
Whitespace
figureone Mar 23, 2018
91936f3
Add note about fullscreen event not implemented
figureone Mar 23, 2018
166c8d3
Trigger completed statement at 95% or more watched
figureone Mar 23, 2018
5c1f995
HFP-1779 Move videoXAPI variable to video.js
otacke Apr 1, 2018
1f18bdb
HFP-1779 Prevent triggering paused before seeked
otacke Apr 1, 2018
f977a64
HFP-1779 Clean up code
otacke Apr 1, 2018
283f2e3
HFP-1779 Clean code
otacke Apr 1, 2018
6dd68ac
HFP-1779 Stop setting segment start time on play event
otacke Apr 1, 2018
8223c20
HFP-1779 Move finished threshold to variable
otacke Apr 1, 2018
12912a8
Add Completion Threshold to initializes extensions
KirkJohnson Apr 4, 2018
cbef273
Merge pull request #2 from otacke/add-xapi-video-verbs
figureone Apr 9, 2018
4f70c16
Add video length to initialized statement
KirkJohnson Apr 23, 2018
94ff7b3
Merge branch 'add-xapi-video-verbs' of https://github.com/uhm-coe/h5p…
KirkJohnson Apr 23, 2018
035d23a
Use Youtube API to pass correct duration
Apr 25, 2018
3707be2
Don’t report video-playback-size if not defined
figureone Apr 26, 2018
d243bb1
Fix logic error in determining isFullscreen
figureone Apr 26, 2018
5501579
Whitespace
figureone Apr 26, 2018
7ab090b
Don’t report video length if not defined
figureone Apr 26, 2018
e1af0c1
Replay 5c1f995 due to incorrect merge conflict resolution in 94ff7b3
figureone May 25, 2018
9d612b7
Replay 1f18bdb due to incorrect merge conflict resolution in 94ff7b3
figureone May 25, 2018
3e6a584
Replay f977a64 due to incorrect merge conflict resolution in 94ff7b3
figureone May 25, 2018
85b0b86
Replay 8223c20 due to incorrect merge conflict resolution in 94ff7b3
figureone May 25, 2018
ef6d166
Add existence check to completion-threshold extension
figureone May 25, 2018
4f595f7
Comments (update function doc header)
figureone May 25, 2018
26b8f94
Revert 6dd68ac
figureone May 25, 2018
0ea01a7
Merge remote-tracking branch 'upstream/master'
figureone May 25, 2018
17052be
Merge remote-tracking branch 'upstream/master' into add-xapi-video-verbs
figureone May 25, 2018
d9d2202
Merge remote-tracking branch 'upstream/master'
figureone Jun 20, 2018
706855d
Merge remote-tracking branch 'origin/master' into add-xapi-video-verbs
figureone Jun 20, 2018
9bc078a
Merge remote-tracking branch 'upstream/master' into add-xapi-video-verbs
figureone Jul 25, 2018
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions library.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@
"minorVersion": 4
},
"preloadedJs": [
{
"path": "scripts/x-api.js"
},
{
"path": "scripts/youtube.js"
},
Expand Down
111 changes: 107 additions & 4 deletions scripts/html5.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
/** @namespace H5P */
H5P.VideoHtml5 = (function ($) {
'use strict';

/**
* HTML5 video player for H5P.
Expand Down Expand Up @@ -35,6 +36,12 @@ H5P.VideoHtml5 = (function ($) {
var stateBeforeChangingQuality;
var currentTimeBeforeChangingQuality;

/**
* Track xAPI statement data for video events.
* @private
*/
var lastSend = null;

/**
* Avoids firing the same event twice.
* @private
Expand Down Expand Up @@ -143,6 +150,27 @@ H5P.VideoHtml5 = (function ($) {
}
});

/**
* Create the xAPI object for the 'Initialized' event.
*/
var getLoadedParams = function () {
var ccEnabled = false;
var ccLanguage;

for (var i = 0; i < video.textTracks.length; i++) {
if (video.textTracks[i].mode === 'showing') {
ccEnabled = true;
ccLanguage = video.textTracks[i].language;
}
}

return self.videoXAPI.getArgsXAPIInitialized(video.videoWidth, video.videoHeight, video.playbackRate, video.volume, ccEnabled, ccLanguage, video.videoHeight, video.duration);

};

// Set duration used for xAPI statements.
self.duration = video.duration;

/**
* Helps registering events.
*
Expand All @@ -153,6 +181,8 @@ H5P.VideoHtml5 = (function ($) {
*/
var mapEvent = function (native, h5p, arg) {
video.addEventListener(native, function () {
var extraArg = null;
var extraTrigger = null;
switch (h5p) {
case 'stateChange':
if (lastState === arg) {
Expand All @@ -165,8 +195,63 @@ H5P.VideoHtml5 = (function ($) {
delete options.startAt;
}

break;
if (arg === H5P.Video.PLAYING) {
if (lastSend !== 'play') {
extraArg = self.videoXAPI.getArgsXAPIPlayed(video.currentTime);
extraTrigger = 'play';
lastSend = 'play';
}
}

if (arg === H5P.Video.PAUSED) {
// Put together extraArg for sending to xAPI statement.
if (!video.seeking && self.seeking === false && video.currentTime !== video.duration && self.previousState !== H5P.Video.BUFFERING) {
extraTrigger = 'paused';
extraArg = self.videoXAPI.getArgsXAPIPaused(video.currentTime, video.duration);
lastSend = 'paused';
}
}

if (arg === H5P.Video.ENDED) {
// Send extra trigger for giving progress on ended call to xAPI.
var length = video.duration;
if (length > 0) {
// Length passed in as current time, because at end of video when this is fired currentTime reset to 0 if on loop
var progress = self.videoXAPI.getProgress(length, length);
if (progress >= self.finishedThreshold) {
extraTrigger = 'finished';
extraArg = self.videoXAPI.getArgsXAPICompleted(video.currentTime, video.duration, progress);
lastSend = 'finished';
}
}
}
break;
case 'seeked':
return; // Seek is tracked differently based on time difference in timeupdate.
break;
case 'seeking':
return; // Just need to store current time for seeked event.
break;
case 'volumechange' :
arg = self.videoXAPI.getArgsXAPIVolumeChanged(video.currentTime, video.muted, video.volume);
lastSend = 'volumechange';
break;
case 'play':
if (self.seeking === false && lastSend !== h5p) {
arg = self.videoXAPI.getArgsXAPIPlayed(video.currentTime);
lastSend = h5p;
}
else {
arg = self.videoXAPI.getArgsXAPISeeked(self.seekedTo);
lastSend = 'seeked';
self.seeking = false;
h5p = 'seeked';
}
break;
case 'fullscreen':
arg = self.videoXAPI.getArgsXAPIFullScreen(video.currentTime, video.videoWidth, video.videoHeight);
lastSend = h5p;
break;
case 'loaded':
isLoaded = true;

Expand All @@ -188,8 +273,12 @@ H5P.VideoHtml5 = (function ($) {
video.addEventListener('durationchange', andLoaded, false);
return;
}
break;

extraTrigger = 'xAPIloaded';
extraArg = getLoadedParams();
lastSend = 'xAPIloaded';

break;
case 'error':
// Handle error and get message.
arg = error(arguments[0], arguments[1]);
Expand All @@ -213,7 +302,13 @@ H5P.VideoHtml5 = (function ($) {
arg = self.getPlaybackRate();
break;
}
self.previousState = arg;
self.trigger(h5p, arg);

// Make extra calls for events with needed values for xAPI statement.
if (extraTrigger !== null && extraArg !== null) {
self.trigger(extraTrigger, extraArg);
}
}, false);
};

Expand Down Expand Up @@ -425,8 +520,12 @@ H5P.VideoHtml5 = (function ($) {
video.play();
video.pause();
}

if (self.seeking === false) {
self.previousTime = video.currentTime;
}
video.currentTime = time;
self.seeking = true;
self.seekedTo = time;
};

/**
Expand Down Expand Up @@ -596,14 +695,18 @@ H5P.VideoHtml5 = (function ($) {
mapEvent('loadedmetadata', 'loaded');
mapEvent('error', 'error');
mapEvent('ratechange', 'playbackRateChange');
mapEvent('seeking','seeking', H5P.Video.PAUSED);
mapEvent('timeupdate', 'timeupdate', H5P.Video.PLAYING);
mapEvent('volumechange', 'volumechange');
mapEvent('play', 'play', H5P.Video.PLAYING);
mapEvent('webkitfullscreenchange mozfullscreenchange fullscreenchange MSFullscreenChange', 'fullscreen');

if (!video.controls) {
// Disable context menu(right click) to prevent controls.
video.addEventListener('contextmenu', function (event) {
event.preventDefault();
}, false);
}

// Display throbber when buffering/loading video.
self.on('stateChange', function (event) {
var state = event.data;
Expand Down
57 changes: 57 additions & 0 deletions scripts/video.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
/** @namespace H5P */
H5P.Video = (function ($, ContentCopyrights, MediaCopyright, handlers) {
'use strict';

/**
* The ultimate H5P video player!
Expand All @@ -15,9 +16,36 @@ H5P.Video = (function ($, ContentCopyrights, MediaCopyright, handlers) {
function Video(parameters, id) {
var self = this;

self.videoXAPI = new H5P.VideoXAPI(self);

// Ref youtube.js - ipad & youtube - issue
self.pressToPlay = false;

self.finishedThreshold = 0.95;

// Values needed for xAPI triggering, set by handlers
self.previousTime = 0;
self.seeking = false;
self.seekedTo = 0;
self.duration = 0;
self.previousState = -1;
self.mousedown = false;

/*
* Used to distinguish seeking from pausing
* TODO: This might be much cleaner with refactoring IV, video and the handlers
*/
document.addEventListener('mousedown', function() {
self.mousedown = true;
});
document.addEventListener('mouseup', function() {
if (self.seeking) {
self.trigger('seeked', self.videoXAPI.getArgsXAPISeeked(self.seekedTo));
self.seeking = false;
}
self.mousedown = false;
});

// Reference to the handler
var handlerName = '';

Expand Down Expand Up @@ -128,6 +156,35 @@ H5P.Video = (function ($, ContentCopyrights, MediaCopyright, handlers) {
self.on('loaded', function () {
self.trigger('resize');
});
// xAPI extension events for video.
self.on('seeked', function (event) {
self.triggerXAPI('seeked', event.data);
});
self.on('volumechange', function (event) {
self.triggerXAPI('interacted', event.data);
});
self.on('finished', function (event) {
// Triggered as finished to be seperate from H5Ps completed,
// but statement is sent as completed and differentiated by object.id
self.triggerXAPI('completed', event.data);
});
self.on('fullscreen', function (event) {
// Note: youtube.js and html5.js players do not fire this event.
self.triggerXAPI('interacted', event.data);
});
self.on('play', function (event) {
self.triggerXAPI('played', event.data);
});
self.on('xAPIloaded', function (event) {
self.duration = self.getDuration();
self.triggerXAPI('initialized', event.data);
});
self.on('paused', function (event) {
// if mouse button is down, we're seeking
if (self.mousedown === false) {
self.triggerXAPI('paused', event.data);
}
});

// Find player for video sources
if (sources.length) {
Expand Down
Loading