From ac6f4340ce1c42032331b6d4ff5b772daf87bceb Mon Sep 17 00:00:00 2001 From: Alexander Marenich Date: Tue, 3 Jan 2017 18:10:35 +0200 Subject: [PATCH] Enabling/disabling of interactive transcripts --- video_xblock/static/css/videojs.css | 36 ++++++++++++++++++++ video_xblock/static/js/player_state.js | 6 +++- video_xblock/static/js/toggle-button.js | 4 +-- video_xblock/static/js/videojs-transcript.js | 25 ++++++++++++-- video_xblock/video_xblock.py | 13 +++++-- 5 files changed, 77 insertions(+), 7 deletions(-) diff --git a/video_xblock/static/css/videojs.css b/video_xblock/static/css/videojs.css index ec903c08..68ae627a 100644 --- a/video_xblock/static/css/videojs.css +++ b/video_xblock/static/css/videojs.css @@ -1,5 +1,6 @@ body { margin: 0; + display: flex; } .video-js .vjs-has-started.vjs-user-inactive.vjs-playing .vjs-control-bar { @@ -318,3 +319,38 @@ body { background-color: #171a1b; color: #0ea6ec; } + +#transcript { + max-height: 100%; + overflow: scroll; + padding: 0 0 0 20px; + font-family: "Open Sans","Helvetica Neue",Helvetica,Arial,sans-serif; + font-size: 14px; + background-color: inherit; +} + +.transcript-line { + margin-bottom: 8px; + border: 0; + padding: 0; + color: #0074b5; + line-height: 1.41575em; +} + +.transcript-line.is-active { + color: #333; + font-weight: 700; +} + +.transcript-line:hover { + text-decoration: underline; + cursor: pointer; +} + +.transcript-timestamp { + display: none; +} + +.is-hidden { + display: none !important; +} diff --git a/video_xblock/static/js/player_state.js b/video_xblock/static/js/player_state.js index 6b63beaf..8b9b54f4 100644 --- a/video_xblock/static/js/player_state.js +++ b/video_xblock/static/js/player_state.js @@ -24,6 +24,7 @@ var player_state = { 'currentTime': {{ player_state.current_time }}, 'playbackRate': {{ player_state.playback_rate }}, 'muted': {{ player_state.muted | yesno:"true,false" }}, + 'transcriptsEnabled': {{ player_state.transcripts_enabled | yesno:"true,false" }} }; var xblockUsageId = window.location.hash.slice(1); @@ -46,6 +47,7 @@ var setInitialState = function (player, state) { .volume(state.volume) .muted(state.muted) .playbackRate(state.playbackRate); + player.transcriptsEnabled = state.transcriptsEnabled; }; /** @@ -59,6 +61,7 @@ var saveState = function(){ 'currentTime': player.ended()? 0 : Math.floor(player.currentTime()), 'playbackRate': player.playbackRate(), 'muted': player.muted(), + 'transcriptsEnabled': player.transcriptsEnabled }; if (JSON.stringify(new_state) !== JSON.stringify(player_state)) { @@ -97,7 +100,8 @@ domReady(function() { .on('ratechange', saveState) .on('play', saveState) .on('pause', saveState) - .on('ended', saveState); + .on('ended', saveState) + .on('transcriptstatechanged', saveState); }); }); diff --git a/video_xblock/static/js/toggle-button.js b/video_xblock/static/js/toggle-button.js index 14e310b3..115458a4 100644 --- a/video_xblock/static/js/toggle-button.js +++ b/video_xblock/static/js/toggle-button.js @@ -37,8 +37,8 @@ domReady(function() { onClick: function onClick(event) { var el = event.currentTarget; el.classList.toggle('vjs-control-enabled'); - var _event = this.hasClass('vjs-control-enabled') ? this.enabledEventName() : this.disabledEventName(); - this.trigger(_event); + var eventName = this.hasClass('vjs-control-enabled') ? this.enabledEventName() : this.disabledEventName(); + this.player_.trigger(eventName); }, }); diff --git a/video_xblock/static/js/videojs-transcript.js b/video_xblock/static/js/videojs-transcript.js index 2af98219..fcb42476 100644 --- a/video_xblock/static/js/videojs-transcript.js +++ b/video_xblock/static/js/videojs-transcript.js @@ -3,24 +3,45 @@ domReady(function() { // fire up the plugin var transcript = this.transcript({ - 'showTrackSelector': false + 'showTrackSelector': false, + 'showTitle': false }); // attach the widget to the page var transcriptContainer = document.getElementById('transcript'); + + // Show or hide the transcripts block depending on the transcript state + if (!this.transcriptsEnabled){ + transcriptContainer.className += " is-hidden"; + }; transcriptContainer.appendChild(transcript.el()); + this.on('transcriptenabled', function(){ + transcriptContainer.classList.toggle('is-hidden'); + this.transcriptsEnabled = true; + this.trigger('transcriptstatechanged'); + }); + this.on('transcriptdisabled', function(){ + transcriptContainer.classList.toggle('is-hidden'); + this.transcriptsEnabled = false; + this.trigger('transcriptstatechanged'); + }); + this.toggleButton({ style: "fa-cc", enabledEvent: "captionenabled", disabledEvent: "captiondisabled", cssClasses: "vjs-custom-caption-button vjs-control", }); + var cssClasses = "vjs-custom-transcript-button vjs-control"; + if (this.transcriptsEnabled){ + cssClasses += ' vjs-control-enabled'; + }; this.toggleButton({ style: "fa-quote-left", enabledEvent: "transcriptenabled", disabledEvent: "transcriptdisabled", - cssClasses: "vjs-custom-transcript-button vjs-control", + cssClasses: cssClasses, }); }); }); diff --git a/video_xblock/video_xblock.py b/video_xblock/video_xblock.py index f4440c7e..20bf4042 100644 --- a/video_xblock/video_xblock.py +++ b/video_xblock/video_xblock.py @@ -116,6 +116,12 @@ class VideoXBlock(StudioEditableXBlockMixin, XBlock): help=_("Video muted or not") ) + transcripts_enabled = Boolean( + default=False, + scope=Scope.preferences, + help=_("Transcript is enabled or not") + ) + handout = String( default='', scope=Scope.content, @@ -131,7 +137,7 @@ class VideoXBlock(StudioEditableXBlockMixin, XBlock): ) editable_fields = ('display_name', 'href', 'start_time', 'end_time', 'account_id', 'handout', 'transcripts', 'player_id') - player_state_fields = ('current_time', 'muted', 'playback_rate', 'volume') + player_state_fields = ('current_time', 'muted', 'playback_rate', 'volume', 'transcripts_enabled') @property def player_state(self): @@ -144,6 +150,7 @@ def player_state(self): 'playback_rate': self.playback_rate, 'volume': self.volume, 'transcripts': json.loads(self.transcripts) if self.transcripts else [], + 'transcripts_enabled': self.transcripts_enabled } @staticmethod @@ -166,6 +173,7 @@ def player_state(self, state): self.playback_rate = state.get('playback_rate', self.playback_rate) self.volume = state.get('volume', self.volume) self.transcripts = state.get('transcripts', self.transcripts) + self.transcripts_enabled = state.get('transcripts_enabled', self.transcripts_enabled) def validate_field_data(self, validation, data): """ @@ -306,7 +314,8 @@ def save_player_state(self, request, suffix=''): 'playback_rate': request['playbackRate'], 'volume': request['volume'], 'muted': request['muted'], - 'transcripts': self.transcripts + 'transcripts': self.transcripts, + 'transcripts_enabled': request['transcriptsEnabled'] } self.player_state = player_state return {'success': True}