Videojs custom TextTrackDisplay not working - reactjs

I have requirement in my project to customize player controls. I found a lot documentation how to make it possible, except TextTrackDisplay component. For some reason this component has been rendered by videojs, but rendered code seems have no clue about any existing text tracks of standard hls stream (bip-bop).
I've created sample of code where play button successfully customized, but TextTrackDisplay wasn't for some reason...
https://codepen.io/jurij-sergeewich-gerc/pen/xxxwPmN
class Player extends React.Component {
init = (videoRef) => {
const videoJsOptions = {
controls: false,
html5: {nativeTextTracks: false},
};
const player = videojs(videoRef, videoJsOptions, () => {
const type = 'application/x-mpegURL';
const src = 'https://d2zihajmogu5jn.cloudfront.net/bipbop-advanced/bipbop_16x9_variant.m3u8'
player.pause();
player.src({type, src});
player.play();
this.connectPlayButton(player);
this.connectTextTracks(player);
});
}
connectPlayButton = (player) => {
const selector = '[data-play-btn]';
const allElements = Array.from(document.querySelectorAll(selector));
allElements.forEach((box) => {
const PlayToggle = videojs.getComponent('PlayToggle');
const playToggle = new PlayToggle(player);
box.appendChild(playToggle.el());
});
};
connectTextTracks = (player) => {
const selector = '[data-text-tracks]';
const allElements = Array.from(document.querySelectorAll(selector));
allElements.forEach((box) => {
const TextTrackDisplay = videojs.getComponent('TextTrackDisplay');
const textTrackDisplay = new TextTrackDisplay(player);
box.appendChild(textTrackDisplay.el());
});
};
render () {
return (
<div data-vjs-player>
<video ref={this.init} className="video-js-video">
</video>
<div data-play-btn></div>
<div data-text-tracks></div>
</div>
)
}
}
ReactDOM.render(
<Player/>,
document.getElementById('root')
);
Could any one help me please :))

I just was tired at night yesterday, this is stupid, but for show "cc" in control panel, we need to use not 'TextTrackDisplay' component but 'SubtitlesButton'.

Related

state doesn't update when linking to a url from toolbar in react-draft-wysiwyg

I am using react-draft-wysiwyg in my project. It works fine most cases.
Only problem is, when I try to link a text to url. In that case it doesn't update the state.
Let's say, I already have a text "Hello world!". Now if I add more text in this e.g. "Hello world! newText". I want to link this "newText" to url using link option from toolbar and click save. It doesn't update the state with the link and goes back previous text "Hello world!"
Interesting thing is that after adding a link if I add more text to that, it works just fine.
const createStateFromHtml = (html: string) => {
const blocksFromHtml = htmlToDraft(html)
const { contentBlocks, entityMap } = blocksFromHtml
const contentState = ContentState.createFromBlockArray(contentBlocks, entityMap)
return EditorState.createWithContent(contentState)
}
const createHtmlFromState = (editorState: EditorState) => {
const rawContentState = convertToRaw(editorState.getCurrentContent())
return draftToHtml(rawContentState)
}
const htmlSanitizeSettings = {
ADD_TAGS: ['iframe'],
ADD_ATTR: ['allowfullscreen'],
}
const BodyEditor = (props: BodyEditorProps) => {
DOMPurify.setConfig(htmlSanitizeSettings)
const initialState = props.html && props.html !== '' ? createStateFromHtml(props.html) : EditorState.createEmpty()
const [editorState, setEditorState] = React.useState(initialState)
const setEditorHtml = () => {
const html = createHtmlFromState(editorState)
const htmlWithIframeSettings = addPropertiesToIframes(html)
const purifiedHtml = DOMPurify.sanitize(htmlWithIframeSettings)
props.setBody(purifiedHtml)
}
/*
* Adds a div element around iframes and adds class="embedded-video" around so we can use CSS to make iframes reponsive
*/
const addPropertiesToIframes = (html: string) => {
return (
html
// Let's assume embedded iframes are videos
.replace(/<iframe/g, '<div class="iframe-container"><iframe class="embedded-video"')
.replace(/<\/iframe>/g, '</iframe></div>')
.replace(/iframe width=/g, 'iframe allowfullscreen width=')
// Let's remove embedded-video class from embedded spotify iframes
// This should be done for all non-video embeds because otherwise the iframe are made to have 16:9 aspect ratio
.replace(
// eslint-disable-next-line no-useless-escape
/class=\"embedded-video\" src=\"https:\/\/open\.spotify\.com/g,
'src="https://open.spotify.com',
)
)
}
return props.editable ? (
<Editor
editorStyle={editorStyle}
editorState={editorState}
onEditorStateChange={setEditorState}
onBlur={setEditorHtml}
toolbar={{
options: toolbarOptions,
image: {
...imageOptions,
uploadCallback: props.imageUploadCallback,
},
link: {
...linkOptions,
},
embedded: {
...embeddedOptions,
},
}}
placeholder={props.placeholder}
/>
) : (
<div
onClick={() => props.toggleEditable(props.name)}
dangerouslySetInnerHTML={
props.html
? { __html: DOMPurify.sanitize(props.html!) }
: { __html: DOMPurify.sanitize(props.placeholder!) }
}
/>
)
}
export default BodyEditor
Any help would be highly appreciated. I am stuck on this for a very long time.
I used this combine. It is working properly.
import { Editor } from "react-draft-wysiwyg";
import { useEffect } from "react";
import {convertToRaw } from 'draft-js';
import draftToHtml from 'draftjs-to-html';
Maybe, you can try that.
For Example:
You can use to the state initial value below:
EditorState.createWithContent(
ContentState.createFromBlockArray(
convertFromHTML(<your_data>)
)
)
You can use to store the HTML data below:
draftToHtml(convertToRaw(<your_state>.getCurrentContent()))

Edit iframe DOM from window

When i try to manipulate iframe i always get the cors issue permission denied to access property document on cross-origin, same goes when i try to attach event listener.
So is it possible to manipulate DOM elements inside iframe that is coming from different origin?
I'm happy to somehow also take a copy of iframe and just have it in my code as long as it allows me to edit it later, but unsure how?
import { useEffect } from 'react';
const post = () => {
const iframe = document.querySelector('iframe');
const message = { type: 'modifyDOM', text: 'Hello World!' };
// window.postMessage(message);
if (iframe?.contentWindow) {
iframe.contentWindow.postMessage(message, 'http://example.com');
}
};
export const IFrame = () => {
useEffect(() => {
const iframe = document.querySelector('iframe');
const receiveMessage = (e: MessageEvent) => {
if (e.data.type === 'modifyDOM') {
console.log(e.data);
// window.document.body.innerHTML = '<h1>Hello World!</h1>';
if (iframe?.contentWindow) {
iframe.contentWindow.document.body.innerHTML = '<h1>Hello World!</h1>';
}
}
};
window.addEventListener('message', receiveMessage);
return () => {
window.removeEventListener('message', receiveMessage);
};
}, []);
return (
<div>
<button onClick={post}>Post</button>
<iframe src="http://example.com" />
</div>
);
};

TypeError _this2.flipBook.getPageFlip is not a function

I used to use react-pageflip on Reactjs exactly like the code below and it worked fine. When I copied the same component, I got this error in the nextjs project.
error:
TypeError: _this2.flipBook.getPageFlip is not a function
code:
import HTMLFlipBook from "react-pageflip";
class Book extends Component {
...
onFlip(data) {
this.setState({ page : data});
}
nextButtonClick = () => {
this.flipBook.getPageFlip().flipNext();
};
prevButtonClick = () => {
this.flipBook.getPageFlip().flipPrev();
};
rendr(){
return(
<HTMLFlipBook maxShadowOpacity={1} mobileScrollSupport={true}
className="demo-book"
drawShadow={true}
onFlip={(e) => this.onFlip(e.data)}
changeOrientation="portrait"
ref={(el) => (this.flipBook = el)}
>
<div classname={page1}>
page1
</div>
<div classname={page2}>
page2
</div>
</HTMLFlipBook>
)
}
this.flipBook.getPageFlip().flipNext(); in the block inside the nextButtonClick and prevButtonClick functions, you should use this.flipBook.pageFlip().flipNext() by flipping. It worked for me, I hope it works for you too.
nextButtonClick = () => {
this.flipBook.pageFlip().flipNext()
};
prevButtonClick = () => {
this.flipBook.pageFlip().flipPrev();
};
For function components
This work for me
const bookRef = useRef(null)
const nextButtonClick = () => {
bookRef.current.pageFlip().flipNext()
}
const prevButtonClick = () => {
bookRef.current.pageFlip().flipPrev()
}
<HTMLFlipBook
onFlip={onFlip}
width={616}
height={872}
showCover={true}
ref={bookRef}
>
// ...my render page
</HTMLFlipBook>

Testing State variable using Jest

I am learning to test React app using jest and Enzyme . I have created a component and using redux to maintain and update the state . The component code is below .
Now i want to write the test to check initial value of prodOverviewAccordion which we are setting as true in context file.
I have tried writing , but getting error . Sharing the test code also . Please help
const ProdOverview = () => {
const {
productState,
setProdOverviewAccordion
} = React.useContext(ProductContext);
const {prodOverviewAccordion } = productState;
const [completeStatusprod, setCompleteStatusprod] = useState(false);
return (
<div onClick={toggleTriggerProd}>
<s-box>
<Collapsible
trigger={
<Accordion
name={ProductConfig.accordionTriggerLabels.prodOverviewLabel}
completeStatusIcon={completeStatusprod ? 'check-circle' : 'alert-triangle'}
completeStatus={completeStatusprod}
/>
}
easing='ease-out'
handleTriggerClick={() => {
if (!prodOverviewAccordion) {
setProdOverviewAccordion(true);
} else {
setProdOverviewAccordion(false);
}
}}
open={prodOverviewAccordion}
data-test='prodOverViewCollapsible'
>
<p>Test</p>
</Collapsible>
</s-box>
</div>
);
};
export default ProdOverview;
const prodsetup = (props = {}) => {
return shallow(<ProdOverview />);
};
describe('Product Overview panel Test', () => {
const mockSetCurrentGuess = jest.fn();
beforeEach(() => {
mockSetCurrentGuess.mockClear();
});
test('should render Collapsible panel', () => {
const wrapper = prodsetup();
const component = findByTestAttr(wrapper, 'prodOverViewCollapsible');
expect(component.length).toBe(1);
});
test('Product Overview Panel should be in open state', () => {
const wrapper = prodsetup();
expect(wrapper.state().prodOverviewAccordion.to.equal(true));
});
});

How to change styling for only one of same children depend on prop

I am trying to implement star voting with font awesome icons,
on Product.js i have 2 component , problem is when i change styling for a component that has prop, naturally it changes other component because of querySelectorAll, so how can i change the class for only component which has props i pass.
Product.js
const [rating, setRating] = useState(0);
const ratingHandler = (e) => {
setRating(e);
};
<Rating handleRating={ratingHandler} />
<Rating />
for first child i want to add some styling like when i mouse over star ,it lights up etc. So i want to make it based on handleRating props.
Rating.js
const Rating = (handleRating = false) => {
useEffect(() => {
if (handleRating) {
hover();
}
}, []);
function hover() {
const spans = document.querySelectorAll(".ratinger span:not(.texting)");
console.log(spans);
spans.forEach((spanon) => {
const onStar = parseInt(spanon.dataset.value, 10);
spanon.onmouseover = () => {
spans.forEach((span) =>
span.dataset.value <= onStar
? span.classList.add("hover")
: span.classList.remove("hover")
);
};
spanon.onmouseout = () => {
spans.forEach((span) => {
span.classList.remove("hover");
});
};
spanon.onclick = () => {
spans.forEach((span) =>
span.dataset.value <= onStar
? span.classList.add("onclick")
: span.classList.remove("onclick")
);
handleRating(parseInt(spanon.dataset.value, 10));
};
});
}
i didnt add unnecessary parts on below i have icons within a div.
Try:
const node = ReactDOM.findDOMNode(this);
const spans = node.querySelectorAll('...');

Resources