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

Added Common Methods and Properties #4

Merged
merged 11 commits into from
Jan 2, 2023
172 changes: 106 additions & 66 deletions src/Blazored.Video/BlazoredVideo.razor
Original file line number Diff line number Diff line change
@@ -1,80 +1,120 @@
@*
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As this code is required for the component to work, the default result of this is more work for the end developer and a breaking change for existing projects.

While I can see that some devs might want the JS separate, I think it would be best if this was controlled by an optional parameter on the component, leaving the default behaviour as it is now, but enabling those devs who want to control the JS externally with that ability.

I would want something like this in BlazoredVideo.razor.cs

[Parameter] public bool UseExternalJavaScript { get; set; } = false;

and then in this file,

@if (!Configured && !UseExternalJavaScript)
{
...
}

It would then also be of benefit to raise a decent error if the developer has not included the JS required for this to run.

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
}
}
*@
<video id="@UniqueKey" @key="UniqueKey" @ref="videoRef" @attributes=@Attributes @onchange=@OnChange>@ChildContent</video>
@if (!Configured)
{
Configured = true;
<script suppress-error="BL9992">
if (!window['Blazored']) {
window['Blazored'] = {}
}
Configured = true;
<script suppress-error="BL9992">
if (!window['Blazored']) {
window['Blazored'] = {}
}

window['Blazored']['registerCustomEventHandler'] = function (el, eventName, payload) {
if (!(el && eventName)) {
return false
}
if (!el.hasOwnProperty('customEvent')) {
el['customEvent'] = function (eventName, payload) {
window['Blazored'].setProperty = function (el, name, value) {
if (!el) {
return;
}
try {
el[name] = value;
} catch (e) {
console.error(e);
}
};

this['value'] = getJSON(this, eventName, payload)
window['Blazored'].getProperty = function (el, name) {
if (!el) {
return null;
}
try {
return el[name];
} catch (e) {
console.error(e);
return null;
}
};

var event
if (typeof (Event) === 'function') {
event = new Event('change')
} else {
event = document.createEvent('Event')
event.initEvent('change', true, true)
}
window['Blazored'].invoke = function (el, name, ...arguments) {
if (!el) {
return null;
}
try {
return el[name](name, ...arguments);
} catch (e) {
console.error(e);
return null;
}
};

this.dispatchEvent(event)
}
}
window['Blazored']['registerCustomEventHandler'] = function (el, eventName, payload) {
if (!(el && eventName)) {
return false
}
if (!el.hasOwnProperty('customEvent')) {
el['customEvent'] = function (eventName, payload) {

el.addEventListener(eventName, function () { el.customEvent(eventName, payload) });
this['value'] = getJSON(this, 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]
}
}
var event
if (typeof (Event) === 'function') {
event = new Event('change')
} else {
event = document.createEvent('Event')
event.initEvent('change', true, true)
}

// 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 }
)
}
}
}
</script>
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 }
)
}
}
}
</script>
}
28 changes: 28 additions & 0 deletions src/Blazored.Video/BlazoredVideo.razor.Methods.cs
Original file line number Diff line number Diff line change
@@ -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<bool> CanPlayMediaType(string mediaType)
{
return await JS.InvokeAsync<bool>("Blazored.invoke", videoRef, "canPlayType", mediaType);
}
}
}
Loading