Allow intercept of audioparser by widget and pass attributes (#9024)

* Initial Commit

* Removes Function wrapper

* Remove Function wrapper from parser

* Convert spaces to tabs in audio.js widget

* Fix indentation

---------

Co-authored-by: Saq Imtiaz <saq.imtiaz@gmail.com>
This commit is contained in:
well-noted 2025-10-29 05:19:09 -07:00 committed by GitHub
parent 135e685811
commit 485051951e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 118 additions and 3 deletions

View file

@ -7,23 +7,34 @@ The audio parser parses an audio tiddler into an embeddable HTML element
\*/
/*jslint node: true, browser: true */
/*global $tw: false */
"use strict";
var AudioParser = function(type,text,options) {
var element = {
type: "element",
tag: "audio",
tag: "$audio", // Using $audio to enable widget interception
attributes: {
controls: {type: "string", value: "controls"},
style: {type: "string", value: "width: 100%; object-fit: contain"}
}
},
src;
};
// Pass through source information
if(options._canonical_uri) {
element.attributes.src = {type: "string", value: options._canonical_uri};
element.attributes.type = {type: "string", value: type};
} else if(text) {
element.attributes.src = {type: "string", value: "data:" + type + ";base64," + text};
element.attributes.type = {type: "string", value: type};
}
// Pass through tiddler title if available
if(options.title) {
element.attributes.tiddler = {type: "string", value: options.title};
}
this.tree = [element];
this.source = text;
this.type = type;
@ -33,3 +44,4 @@ exports["audio/ogg"] = AudioParser;
exports["audio/mpeg"] = AudioParser;
exports["audio/mp3"] = AudioParser;
exports["audio/mp4"] = AudioParser;

View file

@ -0,0 +1,103 @@
/*\
title: $:/core/modules/widgets/audio.js
type: application/javascript
module-type: widget
Basic Audio widget for displaying audio files.
This is a simple implementation that can be overridden by plugins
for more advanced functionality.
\*/
/*jslint node: true, browser: true */
/*global $tw: false */
"use strict";
var Widget = require("$:/core/modules/widgets/widget.js").widget;
var AudioWidget = function(parseTreeNode,options) {
this.initialise(parseTreeNode,options);
};
/*
Inherit from the base widget class
*/
AudioWidget.prototype = new Widget();
/*
Render this widget into the DOM
*/
AudioWidget.prototype.render = function(parent,nextSibling) {
this.parentDomNode = parent;
this.computeAttributes();
this.execute();
// Create audio element
var audioElement = this.document.createElement("audio");
audioElement.setAttribute("controls", this.getAttribute("controls", "controls"));
audioElement.setAttribute("style", this.getAttribute("style", "width: 100%; object-fit: contain"));
audioElement.className = "tw-audio-element";
// Set source
if(this.audioSource) {
if (this.audioSource.indexOf("data:") === 0) {
audioElement.setAttribute("src", this.audioSource);
} else {
var sourceElement = this.document.createElement("source");
sourceElement.setAttribute("src", this.audioSource);
if(this.audioType) {
sourceElement.setAttribute("type", this.audioType);
}
audioElement.appendChild(sourceElement);
}
}
// Insert the audio into the DOM
parent.insertBefore(audioElement, nextSibling);
this.domNodes.push(audioElement);
};
/*
Compute the internal state of the widget
*/
AudioWidget.prototype.execute = function() {
// Get the audio source and type
this.audioSource = this.getAttribute("src");
this.audioType = this.getAttribute("type");
this.audioControls = this.getAttribute("controls", "controls");
// Try to get from tiddler attribute
if(!this.audioSource && this.getAttribute("tiddler")) {
var tiddlerTitle = this.getAttribute("tiddler");
var tiddler = this.wiki.getTiddler(tiddlerTitle);
if(tiddler) {
if(tiddler.fields._canonical_uri) {
this.audioSource = tiddler.fields._canonical_uri;
this.audioType = tiddler.fields.type;
} else if(tiddler.fields.text) {
this.audioSource = "data:" + tiddler.fields.type + ";base64," + tiddler.fields.text;
this.audioType = tiddler.fields.type;
}
}
}
// Make sure we have a tiddler for saving timestamps
this.tiddlerTitle = this.getAttribute("tiddler");
};
/*
Selectively refreshes the widget if needed. Returns true if the widget or any of its children needed re-rendering
*/
AudioWidget.prototype.refresh = function(changedTiddlers) {
var changedAttributes = this.computeAttributes();
if(changedAttributes.src || changedAttributes.type || changedAttributes.controls || changedAttributes.tiddler) {
this.refreshSelf();
return true;
} else {
return false;
}
};
exports.audio = AudioWidget;