From 6d4877a3cd3c3441e29b74f7ec031fea9ceac319 Mon Sep 17 00:00:00 2001 From: Jean-Pierre Bachmann Date: Mon, 30 Nov 2020 15:08:33 +0100 Subject: [PATCH 01/11] Added Common Methods and Properties --- src/Blazored.Video/BlazoredVideo.razor | 26 +++ .../BlazoredVideo.razor.Methods.cs | 28 +++ .../BlazoredVideo.razor.Properties.cs | 209 ++++++++++++++++++ 3 files changed, 263 insertions(+) create mode 100644 src/Blazored.Video/BlazoredVideo.razor.Methods.cs create mode 100644 src/Blazored.Video/BlazoredVideo.razor.Properties.cs diff --git a/src/Blazored.Video/BlazoredVideo.razor b/src/Blazored.Video/BlazoredVideo.razor index 679574f..3a8bfef 100644 --- a/src/Blazored.Video/BlazoredVideo.razor +++ b/src/Blazored.Video/BlazoredVideo.razor @@ -28,6 +28,32 @@ window['Blazored'] = {} } + window['Blazored'].setProperty = function (el, name, value) { + try { + el[name] = value; + } catch (e) { + console.error(e); + } + }; + + window['Blazored'].getProperty = function (el, name) { + try { + return el[name]; + } catch (e) { + console.error(e); + return null; + } + }; + + window['Blazored'].invoke = function (el, name, ...arguments) { + try { + return el[name](name, ...arguments); + } catch (e) { + console.error(e); + return null; + } + }; + window['Blazored']['registerCustomEventHandler'] = function (el, eventName, payload) { if (!(el && eventName)) { return false diff --git a/src/Blazored.Video/BlazoredVideo.razor.Methods.cs b/src/Blazored.Video/BlazoredVideo.razor.Methods.cs new file mode 100644 index 0000000..3df9529 --- /dev/null +++ b/src/Blazored.Video/BlazoredVideo.razor.Methods.cs @@ -0,0 +1,28 @@ +using System.Threading.Tasks; +using Microsoft.JSInterop; + +namespace Blazored.Video +{ + public partial class BlazoredVideo + { + public async Task StartPlayback() + { + await JS.InvokeVoidAsync("Blazored.invoke", videoRef, "play"); + } + + public async Task PausePlayback() + { + await JS.InvokeVoidAsync("Blazored.invoke", videoRef, "pause"); + } + + public async Task ReloadControl() + { + await JS.InvokeVoidAsync("Blazored.invoke", videoRef, "load"); + } + + public async Task CanPlayMediaType(string mediaType) + { + return await JS.InvokeAsync("Blazored.invoke", videoRef, "canPlayType", mediaType); + } + } +} \ No newline at end of file diff --git a/src/Blazored.Video/BlazoredVideo.razor.Properties.cs b/src/Blazored.Video/BlazoredVideo.razor.Properties.cs new file mode 100644 index 0000000..7cada19 --- /dev/null +++ b/src/Blazored.Video/BlazoredVideo.razor.Properties.cs @@ -0,0 +1,209 @@ +using System; +using System.Runtime.CompilerServices; +using Blazored.Video.Support; +using Microsoft.JSInterop; + +namespace Blazored.Video +{ + public partial class BlazoredVideo + { + public bool Autoplay + { + get { return GetValue(); } + set { SetValue(value); } + } + + public object AudioTracks + { + get { throw new NotSupportedException("No Browser supports this api yet"); } + } + + public TimeRanges[] Buffered + { + get { throw new NotImplementedException("The Buffered Property is not yet implemented"); } + } + + public class TimeRanges + { + public int Length { get; set; } + + public int Start(int index) + { + throw new NotImplementedException(); + } + + public int End(int index) + { + throw new NotImplementedException(); + } + } + + public bool Controls + { + get { return GetValue(); } + set { SetValue(value); } + } + + public string CurrentSrc + { + get { return GetValue(); } + set { SetValue(value); } + } + + public int CurrentTime + { + get { return GetValue(); } + set { SetValue(value); } + } + + public bool DefaultMuted + { + get { return GetValue(); } + set { SetValue(value); } + } + + public double DefaultPlaybackRate + { + get { return GetValue(); } + set { SetValue(value); } + } + + public int Duration + { + get { return GetValue(); } + set { SetValue(value); } + } + + public bool HasEnded + { + get { return GetValue("ended"); } + set { SetValue(value); } + } + + public bool Loop + { + get { return GetValue(); } + set { SetValue(value); } + } + + public string MediaGroup + { + get { return GetValue(); } + set { SetValue(value); } + } + + public bool Muted + { + get { return GetValue(); } + set { SetValue(value); } + } + + public NetworkStateTypes NetworkState + { + get { return GetValue(); } + set { SetValue((int)value); } + } + + /// + /// https://www.w3schools.com/tags/av_prop_networkstate.asp + /// + public enum NetworkStateTypes + { + Empty, + Idle, + Loading, + NoSource + } + + public bool Paused + { + get { return GetValue(); } + set { SetValue(value); } + } + + public double PlaybackRate + { + get { return GetValue(); } + set { SetValue(value); } + } + + public TimeRanges[] Played + { + get { throw new NotImplementedException("The Played Property is not yet implemented"); } + } + + public bool Preload + { + get { return GetValue(); } + set { SetValue(value); } + } + + public ReadyState ReadyState + { + get { return GetValue(); } + set { SetValue(value); } + } + + public bool Seekable + { + get { return GetValue(); } + set { SetValue(value); } + } + + public bool IsSeeking + { + get { return GetValue("seeking"); } + set { SetValue(value); } + } + + public string Src + { + get { return GetValue(); } + set { SetValue(value); } + } + + public DateTime StartDate + { + get { throw new NotSupportedException("No Browser supports this api yet"); } + } + + public object TextTracks + { + get { throw new NotSupportedException("No Browser supports this api yet"); } + } + + public object VideoTracks + { + get { throw new NotSupportedException("No Browser supports this api yet"); } + } + + public double Volume + { + get { return GetValue(); } + set { SetValue(value); } + } + + private T GetValue([CallerMemberName]string name = null) + { + name = char.ToLower(name[0]) + name.Substring(1); + if (JS is IJSInProcessRuntime inProcessRuntime) + { + return inProcessRuntime.Invoke("Blazored.getProperty", videoRef, name); + } + + return JS.InvokeAsync("Blazored.getProperty", videoRef, name).GetAwaiter().GetResult(); + } + + private void SetValue(T value, [CallerMemberName]string name = null) + { + name = char.ToLower(name[0]) + name.Substring(1); + if (JS is IJSInProcessRuntime inProcessRuntime) + { + inProcessRuntime.InvokeVoid("Blazored.setProperty", videoRef, name, value); + return; + } + + JS.InvokeVoidAsync("Blazored.setProperty", videoRef, name, value).GetAwaiter().GetResult(); + } + } +} \ No newline at end of file From 022d1e7e0e221ae1e211df9d8247f64a5ac179be Mon Sep 17 00:00:00 2001 From: Jean-Pierre Bachmann Date: Thu, 3 Dec 2020 18:37:05 +0100 Subject: [PATCH 02/11] Added Check in js methods for disposed element Use Jquery if present for event listener --- src/Blazored.Video/BlazoredVideo.razor | 182 +++++++++++++------------ 1 file changed, 98 insertions(+), 84 deletions(-) diff --git a/src/Blazored.Video/BlazoredVideo.razor b/src/Blazored.Video/BlazoredVideo.razor index 3a8bfef..06b9e8a 100644 --- a/src/Blazored.Video/BlazoredVideo.razor +++ b/src/Blazored.Video/BlazoredVideo.razor @@ -1,106 +1,120 @@ @* - Media Events don't work in Blazor - I believe because they don't bubble. - Blazor attaches it's event handlers to the document, and does not register - these events as they don't bubble up to the document. - So, this uses onchange and forces the video element to have a 'value' property, - which it doesn't normally have. - I then populate the 'value' with a JSON string containing the requested data - and the event name. + Media Events don't work in Blazor - I believe because they don't bubble. + Blazor attaches it's event handlers to the document, and does not register + these events as they don't bubble up to the document. + So, this uses onchange and forces the video element to have a 'value' property, + which it doesn't normally have. + I then populate the 'value' with a JSON string containing the requested data + and the event name. - Sample JSON data for an event: - { - "name":"Suspend", - "data": - { - "Autoplay":false, - "Controls":true, - "CurrentSrc":"https://res.cloudinary.com/blazoredgitter/video/upload/v1557015491/samples/elephants.mp4", - "CurrentTime":2.758966 - } - } + Sample JSON data for an event: + { + "name":"Suspend", + "data": + { + "Autoplay":false, + "Controls":true, + "CurrentSrc":"https://res.cloudinary.com/blazoredgitter/video/upload/v1557015491/samples/elephants.mp4", + "CurrentTime":2.758966 + } + } *@ @if (!Configured) { - Configured = true; - + // Craft a bespoke json string to serve as a payload for the event + function getJSON(el, eventName, payload) { + if (payload && payload.length > 0) { + // this syntax copies just the properties we request from the source element + // IE 11 compatible + let data = {}; + for (var obj in payload) { + var item = payload[obj]; + if (el[item]) { + data[item] = el[item] + } + } + + // this stringify overload eliminates undefined/null/empty values + return JSON.stringify( + { name: eventName, state: data } + , function (k, v) { return (v === undefined || v == null || v.length === 0) ? undefined : v } + ) + } else { + return JSON.stringify( + { name: eventName } + ) + } + } + } + } From 2eb2a22bb5dfdd67a59c13244926ea5fad41d235 Mon Sep 17 00:00:00 2001 From: Jean-Pierre Bachmann Date: Thu, 3 Dec 2020 18:37:50 +0100 Subject: [PATCH 03/11] Changed method accessability for better extentability --- src/Blazored.Video/BlazoredVideo.razor.cs | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src/Blazored.Video/BlazoredVideo.razor.cs b/src/Blazored.Video/BlazoredVideo.razor.cs index c03d460..7083c74 100644 --- a/src/Blazored.Video/BlazoredVideo.razor.cs +++ b/src/Blazored.Video/BlazoredVideo.razor.cs @@ -15,8 +15,11 @@ namespace Blazored.Video /// public partial class BlazoredVideo { - [Inject] ILoggerFactory LoggerFactory { get; set; } - [Inject] IJSRuntime JS { get; set; } + [Inject] + ILoggerFactory LoggerFactory { get; set; } + + [Inject] + protected IJSRuntime JS { get; set; } /// /// Allows you to put the same content inside this component as you would @@ -39,11 +42,11 @@ public partial class BlazoredVideo /// [Parameter] public Dictionary VideoEventOptions { get; set; } - private string UniqueKey = Guid.NewGuid().ToString("N"); + protected string UniqueKey = Guid.NewGuid().ToString("N"); #pragma warning disable CS0649 #pragma warning disable CS0414 - private ElementReference videoRef; - private bool Configured = false; + protected ElementReference videoRef; + protected bool Configured = false; #pragma warning restore CS0414 #pragma warning restore CS0649 private readonly JsonSerializerOptions serializationOptions = new JsonSerializerOptions { IgnoreNullValues = true, PropertyNameCaseInsensitive = true }; @@ -183,7 +186,7 @@ async Task Implement(VideoEvents eventName) /// We force one and a use it as a proxy for all the Media Events. /// /// The event args - Value contains our JSON - void OnChange(ChangeEventArgs args) + protected virtual void OnChange(ChangeEventArgs args) { var ThisEvent = args?.Value?.ToString(); VideoEventData videoData = new VideoEventData(); From 6fe092ceefb56a09f445f0c9853093448beede2f Mon Sep 17 00:00:00 2001 From: Jean-Pierre Bachmann Date: Thu, 3 Dec 2020 18:41:55 +0100 Subject: [PATCH 04/11] Added Missing Poster property --- src/Blazored.Video/BlazoredVideo.razor.Properties.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/Blazored.Video/BlazoredVideo.razor.Properties.cs b/src/Blazored.Video/BlazoredVideo.razor.Properties.cs index 7cada19..5158e52 100644 --- a/src/Blazored.Video/BlazoredVideo.razor.Properties.cs +++ b/src/Blazored.Video/BlazoredVideo.razor.Properties.cs @@ -137,6 +137,12 @@ public bool Preload get { return GetValue(); } set { SetValue(value); } } + + public string Poster + { + get { return GetValue(); } + set { SetValue(value); } + } public ReadyState ReadyState { From 2a9dd6a915da977a7b4c5fd38b5782ea47fcd33b Mon Sep 17 00:00:00 2001 From: Jean-Pierre Bachmann Date: Sat, 12 Dec 2020 13:55:00 +0100 Subject: [PATCH 05/11] Added Method documentation Made GetValue and SetValue protected Fixed setters present on readonly properties --- .../BlazoredVideo.razor.Properties.cs | 138 +++++++++++++++--- src/Blazored.Video/Support/AudioTrack.cs | 12 +- src/Blazored.Video/Support/TextTrack.cs | 5 + src/Blazored.Video/Support/VideoTrack.cs | 8 +- 4 files changed, 138 insertions(+), 25 deletions(-) diff --git a/src/Blazored.Video/BlazoredVideo.razor.Properties.cs b/src/Blazored.Video/BlazoredVideo.razor.Properties.cs index 5158e52..6a21446 100644 --- a/src/Blazored.Video/BlazoredVideo.razor.Properties.cs +++ b/src/Blazored.Video/BlazoredVideo.razor.Properties.cs @@ -5,20 +5,35 @@ namespace Blazored.Video { + /// + /// Implements all properties of an video object according to: + /// https://www.w3schools.com/tags/ref_av_dom.asp + /// public partial class BlazoredVideo { + /// + /// Sets or returns whether the audio/video should start playing as soon as it is loaded + /// public bool Autoplay { get { return GetValue(); } set { SetValue(value); } } - - public object AudioTracks + + /// + /// Returns an AudioTrackList object representing available audio tracks + /// + [Obsolete("No Browser supports this api yet", true)] + public AudioTrackList AudioTracks { get { throw new NotSupportedException("No Browser supports this api yet"); } } - public TimeRanges[] Buffered + /// + /// Returns a TimeRanges object representing the buffered parts of the audio/video + /// + [Obsolete("No Browser supports this api yet", true)] + public TimeRanges Buffered { get { throw new NotImplementedException("The Buffered Property is not yet implemented"); } } @@ -38,70 +53,99 @@ public int End(int index) } } + /// + /// Sets or returns whether the audio/video should display controls (like play/pause etc.) + /// public bool Controls { get { return GetValue(); } set { SetValue(value); } } + /// + /// Returns the URL of the current audio/video + /// public string CurrentSrc { get { return GetValue(); } - set { SetValue(value); } } + /// + /// Sets or returns the current playback position in the audio/video (in seconds) + /// public int CurrentTime { get { return GetValue(); } set { SetValue(value); } } + /// + /// Sets or returns whether the audio/video should be muted by default + /// public bool DefaultMuted { get { return GetValue(); } set { SetValue(value); } } + /// + /// Sets or returns the default speed of the audio/video playback + /// public double DefaultPlaybackRate { get { return GetValue(); } set { SetValue(value); } } + /// + /// Returns the length of the current audio/video (in seconds) + /// public int Duration { get { return GetValue(); } - set { SetValue(value); } } + /// + /// Returns whether the playback of the audio/video has ended or not + /// public bool HasEnded { get { return GetValue("ended"); } - set { SetValue(value); } } + /// + /// Sets or returns whether the audio/video should start over again when finished + /// public bool Loop { get { return GetValue(); } set { SetValue(value); } } + /// + /// Sets or returns the group the audio/video belongs to (used to link multiple audio/video elements) + /// public string MediaGroup { get { return GetValue(); } set { SetValue(value); } } + /// + /// Sets or returns whether the audio/video is muted or not + /// public bool Muted { get { return GetValue(); } set { SetValue(value); } } + /// + /// Returns the current network state of the audio/video + /// public NetworkStateTypes NetworkState { get { return GetValue(); } - set { SetValue((int)value); } } /// @@ -115,81 +159,129 @@ public enum NetworkStateTypes NoSource } + /// + /// Returns whether the audio/video is paused or not + /// public bool Paused { get { return GetValue(); } - set { SetValue(value); } } + /// + /// Sets or returns the speed of the audio/video playback + /// + /// + /// 1.0 is normal speed, + /// 0.5 is half speed (slower), + /// 2.0 is double speed (faster), + /// -1.0 is backwards; normal speed, + /// -0.5 is backwards; half speed, + /// + /// + /// public double PlaybackRate { get { return GetValue(); } set { SetValue(value); } } - public TimeRanges[] Played + /// + /// Returns a TimeRanges object representing the played parts of the audio/video + /// + public TimeRanges Played { - get { throw new NotImplementedException("The Played Property is not yet implemented"); } + get { return GetValue(); } } - public bool Preload + /// + /// Sets or returns whether the audio/video should be loaded when the page loads + /// + public PreloadTypes Preload { - get { return GetValue(); } + get { return GetValue(); } set { SetValue(value); } } + public enum PreloadTypes + { + Auto, + Metadata, + None + } + + /// + /// The poster attribute specifies an image to be shown while the video is downloading, or until the user hits the play button. If this is not included, the first frame of the video will be used instead. + /// public string Poster { get { return GetValue(); } set { SetValue(value); } } + /// + /// Returns the current ready state of the audio/video + /// public ReadyState ReadyState { get { return GetValue(); } - set { SetValue(value); } } - public bool Seekable + /// + /// Returns a TimeRanges object representing the seekable parts of the audio/video + /// + public TimeRanges Seekable { - get { return GetValue(); } + get { return GetValue(); } set { SetValue(value); } } + /// + /// Returns whether the user is currently seeking in the audio/video + /// public bool IsSeeking { get { return GetValue("seeking"); } - set { SetValue(value); } } + /// + /// Sets or returns the current source of the audio/video element + /// public string Src { get { return GetValue(); } set { SetValue(value); } } - + + [Obsolete("No Browser supports this api yet", true)] public DateTime StartDate { get { throw new NotSupportedException("No Browser supports this api yet"); } } - public object TextTracks + /// + /// Returns a TextTrackList object representing the available text tracks + /// + public TextTracks TextTracks { - get { throw new NotSupportedException("No Browser supports this api yet"); } + get { return GetValue(); } } - - public object VideoTracks + + [Obsolete("No Browser supports this api yet", true)] + public VideoTracks VideoTracks { get { throw new NotSupportedException("No Browser supports this api yet"); } } + /// + /// Sets or returns the volume of the audio/video + /// public double Volume { get { return GetValue(); } set { SetValue(value); } } - private T GetValue([CallerMemberName]string name = null) + protected virtual T GetValue([CallerMemberName]string name = null) { name = char.ToLower(name[0]) + name.Substring(1); if (JS is IJSInProcessRuntime inProcessRuntime) @@ -200,7 +292,7 @@ private T GetValue([CallerMemberName]string name = null) return JS.InvokeAsync("Blazored.getProperty", videoRef, name).GetAwaiter().GetResult(); } - private void SetValue(T value, [CallerMemberName]string name = null) + protected virtual void SetValue(T value, [CallerMemberName]string name = null) { name = char.ToLower(name[0]) + name.Substring(1); if (JS is IJSInProcessRuntime inProcessRuntime) diff --git a/src/Blazored.Video/Support/AudioTrack.cs b/src/Blazored.Video/Support/AudioTrack.cs index fd785d3..545a6f8 100644 --- a/src/Blazored.Video/Support/AudioTrack.cs +++ b/src/Blazored.Video/Support/AudioTrack.cs @@ -1,4 +1,6 @@ -namespace Blazored.Video.Support +using System.Collections.Generic; + +namespace Blazored.Video.Support { /// /// Not in active use - JSON.stringify doesn't give us the AudioTracks for some reason @@ -28,4 +30,12 @@ public class AudioTrack /// public bool Enabled { get; set; } } + + public class AudioTrackList : List + { + public AudioTrackList() + { + + } + } } diff --git a/src/Blazored.Video/Support/TextTrack.cs b/src/Blazored.Video/Support/TextTrack.cs index 35afd76..7efe232 100644 --- a/src/Blazored.Video/Support/TextTrack.cs +++ b/src/Blazored.Video/Support/TextTrack.cs @@ -35,4 +35,9 @@ public class TextTrack /// public List ActiveCues { get; set; } } + + public class TextTracks : List + { + + } } \ No newline at end of file diff --git a/src/Blazored.Video/Support/VideoTrack.cs b/src/Blazored.Video/Support/VideoTrack.cs index 39df76e..a50d79d 100644 --- a/src/Blazored.Video/Support/VideoTrack.cs +++ b/src/Blazored.Video/Support/VideoTrack.cs @@ -1,4 +1,5 @@ -using System.Text.Json.Serialization; +using System.Collections.Generic; +using System.Text.Json.Serialization; namespace Blazored.Video.Support { @@ -30,4 +31,9 @@ public class VideoTrack /// public bool Selected { get; set; } } + + public class VideoTracks : List + { + + } } From 1129cad18ca3b0a06bd0d2a73aa6f862e63d419c Mon Sep 17 00:00:00 2001 From: Jean-Pierre Bachmann Date: Sat, 12 Dec 2020 13:56:09 +0100 Subject: [PATCH 06/11] Removed non-dynamic setters --- src/Blazored.Video/BlazoredVideo.razor.Properties.cs | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/Blazored.Video/BlazoredVideo.razor.Properties.cs b/src/Blazored.Video/BlazoredVideo.razor.Properties.cs index 6a21446..cbfe134 100644 --- a/src/Blazored.Video/BlazoredVideo.razor.Properties.cs +++ b/src/Blazored.Video/BlazoredVideo.razor.Properties.cs @@ -85,7 +85,6 @@ public int CurrentTime public bool DefaultMuted { get { return GetValue(); } - set { SetValue(value); } } /// @@ -94,7 +93,6 @@ public bool DefaultMuted public double DefaultPlaybackRate { get { return GetValue(); } - set { SetValue(value); } } /// @@ -199,7 +197,6 @@ public TimeRanges Played public PreloadTypes Preload { get { return GetValue(); } - set { SetValue(value); } } public enum PreloadTypes From 19b6145a8a30f5b3265669ed744fb7e2213d9dcf Mon Sep 17 00:00:00 2001 From: Jean-Pierre Bachmann Date: Sat, 12 Dec 2020 14:49:45 +0100 Subject: [PATCH 07/11] Fixed seekable not been readonly --- .../BlazoredVideo.razor.Properties.cs | 22 ++++++++----------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/src/Blazored.Video/BlazoredVideo.razor.Properties.cs b/src/Blazored.Video/BlazoredVideo.razor.Properties.cs index cbfe134..c1d44ab 100644 --- a/src/Blazored.Video/BlazoredVideo.razor.Properties.cs +++ b/src/Blazored.Video/BlazoredVideo.razor.Properties.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.Runtime.CompilerServices; using Blazored.Video.Support; using Microsoft.JSInterop; @@ -35,22 +36,18 @@ public AudioTrackList AudioTracks [Obsolete("No Browser supports this api yet", true)] public TimeRanges Buffered { - get { throw new NotImplementedException("The Buffered Property is not yet implemented"); } + get { return GetValue(); } } - public class TimeRanges + public class TimeRanges : List { - public int Length { get; set; } - - public int Start(int index) - { - throw new NotImplementedException(); - } + } - public int End(int index) - { - throw new NotImplementedException(); - } + public class TimeRange + { + public int Index { get; set; } + public double Start { get; set; } + public double End { get; set; } } /// @@ -229,7 +226,6 @@ public ReadyState ReadyState public TimeRanges Seekable { get { return GetValue(); } - set { SetValue(value); } } /// From 949031ebb604c2ecf533e1a06a98f422cd459454 Mon Sep 17 00:00:00 2001 From: Jean-Pierre Bachmann Date: Sat, 12 Dec 2020 16:17:26 +0100 Subject: [PATCH 08/11] Moved blazoredVideo to be complient with standard razor component behavior Changed name of js object to be BlazoredVideo to avoid possible nameing conflics Enabled package generation on build --- src/Blazored.Video/Blazored.Video.csproj | 3 + src/Blazored.Video/BlazoredVideo.razor | 100 +------------------ src/Blazored.Video/BlazoredVideo.razor.cs | 5 +- src/Blazored.Video/wwwroot/blazoredVideo.js | 102 ++++++++++++++++++++ 4 files changed, 108 insertions(+), 102 deletions(-) create mode 100644 src/Blazored.Video/wwwroot/blazoredVideo.js diff --git a/src/Blazored.Video/Blazored.Video.csproj b/src/Blazored.Video/Blazored.Video.csproj index 9b42e52..e37027b 100644 --- a/src/Blazored.Video/Blazored.Video.csproj +++ b/src/Blazored.Video/Blazored.Video.csproj @@ -25,10 +25,13 @@ true true Initial Release + 1.1.0 + true + diff --git a/src/Blazored.Video/BlazoredVideo.razor b/src/Blazored.Video/BlazoredVideo.razor index 06b9e8a..5c5a5a0 100644 --- a/src/Blazored.Video/BlazoredVideo.razor +++ b/src/Blazored.Video/BlazoredVideo.razor @@ -19,102 +19,4 @@ } } *@ - -@if (!Configured) -{ - Configured = true; - -} + \ No newline at end of file diff --git a/src/Blazored.Video/BlazoredVideo.razor.cs b/src/Blazored.Video/BlazoredVideo.razor.cs index 7083c74..75f34af 100644 --- a/src/Blazored.Video/BlazoredVideo.razor.cs +++ b/src/Blazored.Video/BlazoredVideo.razor.cs @@ -72,9 +72,8 @@ protected override async Task OnAfterRenderAsync(bool firstRender) } } - private async Task ConfigureEvents() + protected virtual async Task ConfigureEvents() { - var registerAllEvents = RegisterEventFired; if (registerAllEvents || RegisterAbort) @@ -178,7 +177,7 @@ async Task Implement(VideoEvents eventName) { VideoStateOptions options = default; VideoEventOptions?.TryGetValue(eventName, out options); - await JS.InvokeVoidAsync("Blazored.registerCustomEventHandler", videoRef, eventName.ToString().ToLower(), options.GetPayload()); + await JS.InvokeVoidAsync("BlazoredVideo.registerCustomEventHandler", videoRef, eventName.ToString().ToLower(), options.GetPayload()); } /// diff --git a/src/Blazored.Video/wwwroot/blazoredVideo.js b/src/Blazored.Video/wwwroot/blazoredVideo.js new file mode 100644 index 0000000..5ef3925 --- /dev/null +++ b/src/Blazored.Video/wwwroot/blazoredVideo.js @@ -0,0 +1,102 @@ +if (!window.BlazoredVideo) { + window.BlazoredVideo = { + setProperty: function(el, name, value) { + if (!el) { + return; + } + try { + el[name] = value; + } catch (e) { + console.error(e); + } + }, + getProperty: function(el, name) { + if (!el) { + return null; + } + try { + var value = el[name]; + if (value instanceof TimeRanges) { + var ranges = new Array(); + for (var i = 0; i < value.length; i++) { + var range = { + index: i, + start: value.start(i), + end: value.end(i) + }; + ranges.push(range); + } + value = ranges; + } + return value; + } catch (e) { + console.error(e); + return null; + } + }, + invoke: function(el, name, ...arguments) { + if (!el) { + return null; + } + try { + return el[name](name, ...arguments); + } catch (e) { + console.error(e); + return null; + } + }, + registerCustomEventHandler: function(el, eventName, payload) { + if (!(el && eventName)) { + return false; + } + if (!el.hasOwnProperty("customEvent")) { + el["customEvent"] = function(eventName, payload) { + + this["value"] = getJSON(this, eventName, payload); + + var event; + if (typeof (Event) === "function") { + event = new Event("change"); + } else { + event = document.createEvent("Event"); + event.initEvent("change", true, true); + } + + this.dispatchEvent(event); + }; + } + + if ($) { + $(el).on(eventName, function() { el.customEvent(eventName, payload) }); + } else { + el.addEventListener(eventName, function() { el.customEvent(eventName, payload) }); + } + + + // Craft a bespoke json string to serve as a payload for the event + function getJSON(el, eventName, payload) { + if (payload && payload.length > 0) { + // this syntax copies just the properties we request from the source element + // IE 11 compatible + let data = {}; + for (var obj in payload) { + var item = payload[obj]; + if (el[item]) { + data[item] = el[item]; + } + } + + // this stringify overload eliminates undefined/null/empty values + return JSON.stringify( + { name: eventName, state: data }, + function(k, v) { return (v === undefined || v == null || v.length === 0) ? undefined : v } + ); + } else { + return JSON.stringify( + { name: eventName } + ); + } + } + } + }; +} \ No newline at end of file From a8199b5a4188821c2838bd73c814bb281a272832 Mon Sep 17 00:00:00 2001 From: Jean-Pierre Bachmann Date: Sat, 12 Dec 2020 16:18:05 +0100 Subject: [PATCH 09/11] Changed Blazored js object name reference in method calls --- src/Blazored.Video/BlazoredVideo.razor.Methods.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Blazored.Video/BlazoredVideo.razor.Methods.cs b/src/Blazored.Video/BlazoredVideo.razor.Methods.cs index 3df9529..d6952fd 100644 --- a/src/Blazored.Video/BlazoredVideo.razor.Methods.cs +++ b/src/Blazored.Video/BlazoredVideo.razor.Methods.cs @@ -7,22 +7,22 @@ public partial class BlazoredVideo { public async Task StartPlayback() { - await JS.InvokeVoidAsync("Blazored.invoke", videoRef, "play"); + await JS.InvokeVoidAsync("BlazoredVideo.invoke", videoRef, "play"); } public async Task PausePlayback() { - await JS.InvokeVoidAsync("Blazored.invoke", videoRef, "pause"); + await JS.InvokeVoidAsync("BlazoredVideo.invoke", videoRef, "pause"); } public async Task ReloadControl() { - await JS.InvokeVoidAsync("Blazored.invoke", videoRef, "load"); + await JS.InvokeVoidAsync("BlazoredVideo.invoke", videoRef, "load"); } public async Task CanPlayMediaType(string mediaType) { - return await JS.InvokeAsync("Blazored.invoke", videoRef, "canPlayType", mediaType); + return await JS.InvokeAsync("BlazoredVideo.invoke", videoRef, "canPlayType", mediaType); } } } \ No newline at end of file From 8b6428867ca7c2492b0ce3769f58a6111a41aa13 Mon Sep 17 00:00:00 2001 From: Jean-Pierre Bachmann Date: Sat, 12 Dec 2020 16:18:41 +0100 Subject: [PATCH 10/11] Changed Blazored js object call in properties --- Blazored.Video.sln | 2 +- src/Blazored.Video/BlazoredVideo.razor.Properties.cs | 9 ++++----- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/Blazored.Video.sln b/Blazored.Video.sln index b2852c1..de32a6b 100644 --- a/Blazored.Video.sln +++ b/Blazored.Video.sln @@ -21,7 +21,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Blazored.Video", "src\Blazo EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BlazorServer", "samples\BlazorServer\BlazorServer.csproj", "{ADF25F83-3102-4E94-9635-77752622C0E5}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BlazorWebAssembly", "samples\BlazorWebAssembly\BlazorWebAssembly.csproj", "{237424CD-14E6-4184-8374-074416E6ADAD}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BlazorWebAssembly", "samples\BlazorWebAssembly\BlazorWebAssembly.csproj", "{237424CD-14E6-4184-8374-074416E6ADAD}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution diff --git a/src/Blazored.Video/BlazoredVideo.razor.Properties.cs b/src/Blazored.Video/BlazoredVideo.razor.Properties.cs index c1d44ab..ab6df84 100644 --- a/src/Blazored.Video/BlazoredVideo.razor.Properties.cs +++ b/src/Blazored.Video/BlazoredVideo.razor.Properties.cs @@ -33,7 +33,6 @@ public AudioTrackList AudioTracks /// /// Returns a TimeRanges object representing the buffered parts of the audio/video /// - [Obsolete("No Browser supports this api yet", true)] public TimeRanges Buffered { get { return GetValue(); } @@ -279,10 +278,10 @@ protected virtual T GetValue([CallerMemberName]string name = null) name = char.ToLower(name[0]) + name.Substring(1); if (JS is IJSInProcessRuntime inProcessRuntime) { - return inProcessRuntime.Invoke("Blazored.getProperty", videoRef, name); + return inProcessRuntime.Invoke("BlazoredVideo.getProperty", videoRef, name); } - return JS.InvokeAsync("Blazored.getProperty", videoRef, name).GetAwaiter().GetResult(); + return JS.InvokeAsync("BlazoredVideo.getProperty", videoRef, name).GetAwaiter().GetResult(); } protected virtual void SetValue(T value, [CallerMemberName]string name = null) @@ -290,11 +289,11 @@ protected virtual void SetValue(T value, [CallerMemberName]string name = null name = char.ToLower(name[0]) + name.Substring(1); if (JS is IJSInProcessRuntime inProcessRuntime) { - inProcessRuntime.InvokeVoid("Blazored.setProperty", videoRef, name, value); + inProcessRuntime.InvokeVoid("BlazoredVideo.setProperty", videoRef, name, value); return; } - JS.InvokeVoidAsync("Blazored.setProperty", videoRef, name, value).GetAwaiter().GetResult(); + JS.InvokeVoidAsync("BlazoredVideo.setProperty", videoRef, name, value).GetAwaiter().GetResult(); } } } \ No newline at end of file From 392552cd307ce7c38e2572ab8456210f06b77a3e Mon Sep 17 00:00:00 2001 From: Jean-Pierre Bachmann Date: Sat, 12 Dec 2020 16:26:12 +0100 Subject: [PATCH 11/11] Added TextTracks converter --- .../BlazoredVideo.razor.Properties.cs | 11 ---------- src/Blazored.Video/Support/TimeRanges.cs | 15 +++++++++----- src/Blazored.Video/wwwroot/blazoredVideo.js | 20 +++++++++++++++---- 3 files changed, 26 insertions(+), 20 deletions(-) diff --git a/src/Blazored.Video/BlazoredVideo.razor.Properties.cs b/src/Blazored.Video/BlazoredVideo.razor.Properties.cs index ab6df84..710cc30 100644 --- a/src/Blazored.Video/BlazoredVideo.razor.Properties.cs +++ b/src/Blazored.Video/BlazoredVideo.razor.Properties.cs @@ -38,17 +38,6 @@ public TimeRanges Buffered get { return GetValue(); } } - public class TimeRanges : List - { - } - - public class TimeRange - { - public int Index { get; set; } - public double Start { get; set; } - public double End { get; set; } - } - /// /// Sets or returns whether the audio/video should display controls (like play/pause etc.) /// diff --git a/src/Blazored.Video/Support/TimeRanges.cs b/src/Blazored.Video/Support/TimeRanges.cs index 9add5bd..b178a66 100644 --- a/src/Blazored.Video/Support/TimeRanges.cs +++ b/src/Blazored.Video/Support/TimeRanges.cs @@ -1,10 +1,15 @@ -namespace Blazored.Video.Support +using System.Collections.Generic; + +namespace Blazored.Video.Support { - public class TimeRanges + public class TimeRanges : List { - public double[] Start { get; set; } - public double[] End { get; set; } - public int Length { get; set; } + } + public class TimeRange + { + public int Index { get; set; } + public double Start { get; set; } + public double End { get; set; } } } diff --git a/src/Blazored.Video/wwwroot/blazoredVideo.js b/src/Blazored.Video/wwwroot/blazoredVideo.js index 5ef3925..d390c23 100644 --- a/src/Blazored.Video/wwwroot/blazoredVideo.js +++ b/src/Blazored.Video/wwwroot/blazoredVideo.js @@ -16,17 +16,29 @@ } try { var value = el[name]; + + // the default TimeRanges and TextTracks array are custom enumerations and cannot be processed by the json serializer + // therefor we must convert them to plain objects + if (value instanceof TimeRanges) { - var ranges = new Array(); + let items = new Array(); for (var i = 0; i < value.length; i++) { - var range = { + let item = { index: i, start: value.start(i), end: value.end(i) }; - ranges.push(range); + items.push(item); + } + value = items; + } + if (value instanceof TextTracks) { + let items = new Array(); + for (var i = 0; i < value.length; i++) { + let item = value[i]; + items.push(item); } - value = ranges; + value = items; } return value; } catch (e) {