I have tried to add "AudioBlot" in ionic 4 Mobile application using the below codes and added successfully.I can do all the manipulation in the audio.
When I am trying to remove(using keyboard) the audio, it won't get remove.
In the html(while debuging), it added like <p><audio src="agjdfj..."></audio></p>.
How to remove the audio tag as similar to the text removal from the editor?
I am trying to type, It wont add it after the audio tag.
import * as Quill from 'quill';
const BlockEmbed = Quill.import('blots/embed');
class CustomAudioBlot extends BlockEmbed {
static blotName: string;
static tagName: string;
static create(url) {
let node: any= super.create(url);
node.setAttribute('src', url);
return node;
}
static value(node) {
return node.getAttribute('src');
}
}
AudioBlot.blotName = 'audio';
AudioBlot.tagName = 'audio';
Quill.register(CustomAudioBlot);
Adding the custom audio by using the below code
Option 1 : (data) means - Base 64 contetent
const audio = "<audio controls controlslist='nodownload' src='" + data + "'></audio>";
this.quillEditorRef.clipboard.dangerouslyPasteHTML(this.index, audio, 'user');
Option 2:
this.quillEditorRef.insertEmbed(this.index, 'audio', data,'user');
Related
I'm attempting to display Video.js captions on a custom DOM element, outside of the video playing. This works as intended and below are snippets showing this.
Unfortunately, I can't seem to disable captions appearing also on top of the video too. Is there a way to disable captions appearing/showing on top of the video and only in the TextTrackDisplay element?
Any setting in the caption options (addRemoteTextTrack(options)) and textTrackSettings.setValues() seems to affect both on-video and custom captions.
let captionOption = {
kind: 'captions',
srclang: 'en',
label: 'English',
src: subURL,
mode: 'showing',
};
connectTextTracks = (player) => {
const TextTrackDisplay = videojs.getComponent('TextTrackDisplay');
const textTrackDisplay = new TextTrackDisplay(player);
subtitleDiv.appendChild(textTrackDisplay.el());
}
player.ready(function () {
player.addRemoteTextTrack(captionOption);
const tracks = player.remoteTextTracks();
console.log(tracks.length); // print out greater than 0 if captions exists
var settings = this.textTrackSettings;
settings.setValues({
backgroundColor: '#000',
backgroundOpacity: '1',
edgeStyle: 'uniform',
});
settings.updateDisplay();
connectTextTracks(player);
});
I ended up just hiding the on-video text track display, before creating a new TextTrackDisplay, like so:
// First hide main text track display (on-video)
const mainTextTrackDisplay = player.getChild('TextTrackDisplay');
mainTextTrackDisplay.setAttribute("hidden", true);
// Add new text track display
const TextTrackDisplay = videojs.getComponent('TextTrackDisplay');
const newTextTrackDisplay = new TextTrackDisplay(player);
const newTextTrackDisplayEl = newTextTrackDisplay.el();
// Append new text track display to subdiv element
const subDiv = document.querySelector("#subdiv");
subDiv.append(newTextTrackDisplayEl);
Full example here:
https://codepen.io/avtconnect/pen/poOvEyj
I am using bokeh and panel to create an animated plot together with some navigation controls like a slider, play/pause, skip 5s, etc.
At the same time, there is video footage which I would like to display in sync with that animation. I started playing around with dash.js and managed to prepare the video accordingly and display it in a standalone page. (yay!)
Since I don't know much javascript, I was wondering: Is there a solution out there for synchronizing these two things?
(A dream scenario: A panel widget for displaying and controlling a dash.js video player from python. Well, one can hope, right? But I'll take any hints, advice, ideas.)
Answering my own question, just in case it may save anyone a bit of trial&error.
After walking into a few dead ends, I wrote a small custom bokeh widget that does what I need.
Here's the code:
from bokeh.core.properties import Bool, String, Float
from bokeh.models import Div
DASH_URL = <url to the dash.js lib>
JS_CODE = """
import * as p from "core/properties"
import {Div, DivView} from "models/widgets/div"
declare var dashjs: any
export type DashViewerData = {from: number, to: number}
export class DashViewerView extends DivView {
model: DashViewer
private video_el: HTMLElement
private player: any
render(): void {
super.render()
this.video_el = document.createElement('video')
this.video_el.id = this.model.video_element_id
this.video_el.setAttribute('width', "1120px")
this.video_el.setAttribute('height', "630px")
this.video_el.setAttribute('controls', '')
this.el.appendChild(this.video_el)
this.el.appendChild(document.createTextNode(this.model.url))
document.createElement('script')
this.player = dashjs.MediaPlayer().create();
this.player.initialize(this.video_el, this.model.url, this.model.is_playing);
}
play_listener(){
if (this.model.is_playing){
this.player.play()
}
else {
this.player.pause()
}
}
connect_signals(): void {
this.connect(this.model.properties.is_playing.change, this.play_listener);
this.connect(this.model.properties.time.change, ()=>this.player.seek(this.model.time));
}
}
export namespace DashViewer {
export type Attrs = p.AttrsOf<Props>
export type Props = Div.Props & {
video_element_id: p.Property<string>
url: p.Property<string>
is_playing: p.Property<boolean>
time: p.Property<number>
}
}
export interface DashViewer extends DashViewer.Attrs {}
export class DashViewer extends Div {
properties: DashViewer.Props
__view_type__: DashViewerView
constructor(attrs?: Partial<DashViewer.Attrs>) {
super(attrs)
}
static init_DashViewer(): void {
this.prototype.default_view = DashViewerView
this.define<DashViewer.Props>({
video_element_id: [p.String, 'dashviewer_video'],
url: [p.String, ''],
is_playing: [p.Boolean, false],
time: [p.Number, 0.0]
})
}
}
"""
class DashViewer(Div):
__implementation__ = JS_CODE
__javascript__ = [DASH_URL]
__css__ = []
video_element_id = String(default='dash_player', help="id of the video element in the DOM")
url = String(help="The URL from which to load the video. (This should point to an mpd file.)")
is_playing = Bool(default=False)
time = Float(default=0.0, help="Time in seconds. Change this to make the player jump to that time.")
I have a utilities plugin for Nuxt.js that I created with a method to parse hashtags and mentions and replace them with <nuxt-link>. I am then using v-html to inject the converted data back into the template. My issue is that the <nuxt-link> are not being parsed with v-html.
import Vue from 'vue';
Vue.mixin({
methods: {
replaceMentions(data) {
// Tags
const tagRegEx = /\[#tag:[a-zA-Z0-9_-]*\]/g;
let tagMatch;
while ((tagMatch = tagRegEx.exec(data)) !== null) {
const tag = Array.from(tagMatch[0].matchAll(/\[#tag:(.*?)\]/g));
data = data.replace(tag[0][0], '<nuxt-link to="/search?q=' + tag[0][1] + '">#' + tag[0][1] + '</a>');
};
// Users
const userRegEx = /\[#user:[a-zA-Z0-9_-]*\]/g;
let userMatch;
while ((userMatch = userRegEx.exec(data)) !== null) {
const user = Array.from(userMatch[0].matchAll(/\[#user:(.*?)\]/g));
data = data.replace(user[0][0], '<nuxt-link to="/users/' + user[0][1] + '">#' + user[0][1] + '</>');
};
return data;
}
}
});
Does anyone have any tips for how I could make these work as proper nuxt compatible links? I already tried using <a> and it works fine, I would just prefer to utilize proper nuxt compatible links.
I think the discussion here basically answers the question: https://github.com/nuxt-community/modules/issues/185
Summarized, there are two options:
Render the HTML with a full Vue build and then attach the rendered node.
(Preferred) Find the links in the HTML and make them call router push instead of their default action.
I'm trying to create a simple widget test in Flutter. I have a custom widget that receives some values, composes a string and shows a Text with that string. I got to create the widget and it works, but I'm having trouble reading the value of the Text component to assert that the generated text is correct.
I created a simple test that illustrates the issue. I want to get the text value, which is "text". I tried several ways, if I get the finder asString() I could interpret the string to get the value, but I don't consider that a good solution. I wanted to read the component as a Text so that I have access to all the properties.
So, how would I read the Text widget so that I can access the data property?
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
void main() {
testWidgets('my first widget test', (WidgetTester tester) async {
await tester
.pumpWidget(MaterialApp(home: Text("text", key: Key('unit_text'))));
// This works and prints: (Text-[<'unit_text'>]("text"))
var finder = find.byKey(Key("unit_text"));
print(finder.evaluate().first);
// This also works and prints: (Text-[<'unit_text'>]("text"))
var finderByType = find.byType(Text);
print(finderByType.evaluate().first);
// This returns empty
print(finder.first.evaluate().whereType<Text>());
// This throws: type 'StatelessElement' is not a subtype of type 'Text' in type cast
print(finder.first.evaluate().cast<Text>().first);
});
}
I got it working. I had to access the widget property of the Element, and then cast it as text:
var text = finder.evaluate().single.widget as Text;
print(text.data);
Please check this simple example.
testWidgets('Test name', (WidgetTester tester) async {
// findig the widget
var textFind = find.text("text_of_field");
// checking widget present or not
expect(textFind, findsOneWidget);
//getting Text object
Text text = tester.firstWidget(textFind);
// validating properies
expect(text.style.color, Colors.black);
...
...
}
You can use find.text
https://flutter.io/docs/cookbook/testing/widget/finders#1-find-a-text-widget
testWidgets('finds a Text Widget', (WidgetTester tester) async {
// Build an App with a Text Widget that displays the letter 'H'
await tester.pumpWidget(MaterialApp(
home: Scaffold(
body: Text('H'),
),
));
// Find a Widget that displays the letter 'H'
expect(find.text('H'), findsOneWidget);
});
What is the best way to use HLS.js to make a custom license request to play encrypted HLS content? What I'm looking for is to override the AES URI that's in the manifest with one of my own, a.k.a. overriding the LAURL
const vid = document.getElementsByTagName('video')[0];
const config = {
debug: true,
startPosition: 100,
maxBufferHole: 0.5,
maxSeekHole: 2,
};
const hls = new Hls(config);
hls.attachMedia(vid);
hls.on(Hls.Events.MEDIA_ATTACHED, function () {
console.log('hls and videojs are bound together');
hls.loadSource('https://example.com/movie.m3u8');
hls.on(Hls.Events.MANIFEST_PARSED, function (event, data) {
console.log('manifest parsed, found ' + data.levels.length + ' quality levels');
});
});
Should I be using HLS.js's custom loader?