<video src="video.mp4" onclick="this.paused ? this.play() : this.pause();"></video>
I don’t want to show video controls but still allow play/pause by clicking on the video. Can someone please advice if this is possible, and if so, how?
<video src="video.mp4" onclick="this.paused ? this.play() : this.pause();"></video>
I don’t want to show video controls but still allow play/pause by clicking on the video. Can someone please advice if this is possible, and if so, how?
This is what’s the following solution does and more Youtube macro - looking for feedbacks - #12 by telumire
Thank you! I hope this works but I’m not very familiar with TW yet.
I imported the macro+demo.json and replaced the macro with the updated version. I entered video.mp4
into the url field of the “Demo macro video” tiddler but it doesn’t show anything. I also tried with file:///path/to/video.mp4
which also did not work.
This is my tiddler with the video (a local file):
<video src="video.mp4"></video>
Sorry, @devon assumed you were linking to YouTube videos on line.
By the way welcome to talk.tiddlywiki, even silly questions are allowed, but I am sure we can find you a perfect solution.
If you can get a free account to host your videos online then embed that video, visitors to your site will not use too much of your websites bandwidth.
If the video is local to your device, a file, and only for you another approach is using the external content. There are plenty of existing discussions about this for example How to embed video like [img[xxx]]
No problem and thanks for your suggestions. I’m only using this offline for myself so I have set “excludeEventAttributes” to false so that the onscript attribute is not removed.
Here’s one way to do it:
<iframe style="aspect-ratio:16/9;width:100%;border:0;" srcdoc='
<style>
video{
position:fixed;
inset:0;
width:100%;
height:100%;
object-fit:contain;
background: black;
}
</style>
<video src="your video url here." onclick="this.controls=0; this.paused || this.ended ? this.play() : this.pause();" >'/>
Isn’t this “sanitised” by tiddlywiki
That seems to work pretty well, thank you! The only limitation is that the iframe requires the aspect ratio of the video.
TW doesn’t seem to check the content of the srcdoc attribute for unsafe attributes.
yes, IMO the only other way to solve this particular problem is to create a custom widget to be able to handle the javascript (since you can’t change the state of a video without controls without using js). Note that the aspect-ratio attribute is not strictly needed if you do not care about the size of the black bars around the video, you can put an arbitrary height and the video will adapt to it.
I asked chatgpt to help with that, here’s the code it gave me:
/*\
title: $:/core/modules/widgets/video.js
type: application/javascript
module-type: widget
The video widget embeds a video from an external URI, a local tiddler title, or base64-encoded video data contained within a tiddler, with custom play/pause on click.
Usage:
<$video src="TiddlerTitle" width="320" height="240"></$video>
Attributes:
src: The source of the video. Can be a tiddler title, a URL to an external video, or a tiddler with base64-encoded video data.
width: Width of the video element.
height: Height of the video element.
controls: If true, shows video controls. Custom play/pause functionality allows controls to be hidden but still provides user interaction.
\*/
(function(){
/*jslint node: true, browser: true */
/*global $tw: false */
"use strict";
var Widget = require("$:/core/modules/widgets/widget.js").widget;
var VideoWidget = function(parseTreeNode,options) {
this.initialise(parseTreeNode,options);
};
/*
Inherit from the base widget class
*/
VideoWidget.prototype = new Widget();
/*
Render this widget into the DOM
*/
VideoWidget.prototype.render = function(parent,nextSibling) {
this.parentDomNode = parent;
this.computeAttributes();
this.execute();
// Create the video element
var videoNode = this.document.createElement("video");
this.assignAttributes(videoNode);
// Handle video source
var tiddler = this.wiki.getTiddler(this.src);
if(tiddler) {
if(tiddler.fields._canonical_uri) {
this.createSourceElement(videoNode, tiddler.fields._canonical_uri, tiddler.fields.type);
} else if(tiddler.fields.text) {
var base64src = "data:" + tiddler.fields.type + ";base64," + tiddler.fields.text;
this.createSourceElement(videoNode, base64src, tiddler.fields.type);
}
} else if(this.src) {
this.createSourceElement(videoNode, this.src);
}
// Custom play/pause on click
this.addPlayPauseOnClick(videoNode);
// Insert the video element
parent.insertBefore(videoNode, nextSibling);
this.domNodes.push(videoNode);
};
VideoWidget.prototype.assignAttributes = function(videoNode) {
videoNode.setAttribute("width", this.width);
videoNode.setAttribute("height", this.height);
if(this.controls === "true") {
videoNode.setAttribute("controls", "");
}
};
VideoWidget.prototype.createSourceElement = function(videoNode, src, type) {
var sourceNode = this.document.createElement("source");
sourceNode.setAttribute("src", src);
if(type) {
sourceNode.setAttribute("type", type);
}
videoNode.appendChild(sourceNode);
};
VideoWidget.prototype.addPlayPauseOnClick = function(videoNode) {
videoNode.addEventListener("click", function() {
if (this.paused || this.ended) {
this.play();
} else {
this.pause();
}
});
};
/*
Compute the internal state of the widget
*/
VideoWidget.prototype.execute = function() {
this.src = this.getAttribute("src");
this.width = this.getAttribute("width", "320");
this.height = this.getAttribute("height", "240");
this.controls = this.getAttribute("controls", "false");
};
/*
Selectively refreshes the widget if needed. Returns true if the widget or any of its children needed re-rendering
*/
VideoWidget.prototype.refresh = function(changedTiddlers) {
var changedAttributes = this.computeAttributes();
if(changedAttributes.src || changedAttributes.width || changedAttributes.height || changedAttributes.controls || changedTiddlers[this.src]) {
this.refreshSelf();
return true;
}
return false;
};
exports.video = VideoWidget;
})();
Seems to work, but probably needs to be tweaked to be good code. Would be nice to add support for subtitles synchronisations (translations, timestamps, etc), read aloud voice over for blind people, binding the progress to a field, custom player buttons, themes, playlists, embeding videos url from popular websites such as youtube, etc. Maybe one day, if I manage to actually understand how widgets works lol
Demo: Video widget — a non-linear personal web notebook (tiddlyhost.com)
I have started writing widgets and filter operators with javascript and chat gpt as well. Eg [sum-field[fieldname]]
the input is titles. And [extend[qtyfield],[ pricefield]]