Files
mediacms/frontend/src/static/js/components/media-actions/MediaShareOptions.jsx
MrPercheul e7ae2833d9 Timestamp (#430)
* Test

Messing around to figure out docker and whatnot

* Revert "Test"

This reverts commit 43b76932c5.

* Update docker dev yaml

Update the docker to the environement with the latest version of selenium (and their new arguments), and to be on firefox

* Timestamp on play

Adds the a one time event that jumps to a timestamp if there is a t parameter in the URL

* Timestamp when sharing DRAFT

First draft to show the timestamp when sharing. Missing checkbox and appending the get param to shown link

* Checkbox and update share url

Checkbox show a clean timestamp and the media URL updates with the correct timestamp upon selection

* Cleaning before PR

removing un-necessary modified  files

* Clean up before PR - remove statics

* Timestamp in comments

Parse the comments to wrap timestamps with an appropriate anchor

* Forgotten comments and console.logs

* Last touch for PR

- Cleaning media.js for PR
- Using  MediaPageStore instead of window.location when wrapping the timestamp in comments

* Screenshot

Adding the screenshot for the user_docs

* PR amends

Amending VideoPlayer componnent to take check if the Get param 't' is a number, and to keep it within the duration of the video.
Required to change the listener from 'play' to 'loadedmetadata' to have access to the video duration (otherwise it was too early)

Also changed the User_doc file to inform users of the timestamp function
2022-03-23 17:38:02 +02:00

333 lines
9.9 KiB
JavaScript

import React, { useRef, useState, useEffect } from 'react';
import { ShareOptionsContext } from '../../utils/contexts/';
import { PageStore, MediaPageStore } from '../../utils/stores/';
import { PageActions, MediaPageActions } from '../../utils/actions/';
import ItemsInlineSlider from '../item-list/includes/itemLists/ItemsInlineSlider';
import { CircleIconButton } from '../_shared/';
function shareOptionsList() {
const socialMedia = ShareOptionsContext._currentValue;
const mediaUrl = MediaPageStore.get('media-url');
const mediaTitle = MediaPageStore.get('media-data').title;
const ret = {};
let i = 0;
while (i < socialMedia.length) {
switch (socialMedia[i]) {
case 'embed':
if ('video' === MediaPageStore.get('media-data').media_type) {
ret[socialMedia[i]] = {};
}
break;
case 'email':
ret[socialMedia[i]] = {
title: 'Email',
shareUrl: 'mailto:?body=' + mediaUrl,
};
break;
case 'fb':
ret[socialMedia[i]] = {
title: 'Facebook',
shareUrl: 'https://www.facebook.com/sharer.php?u=' + mediaUrl,
};
break;
case 'tw':
ret[socialMedia[i]] = {
title: 'Twitter',
shareUrl: 'https://twitter.com/intent/tweet?url=' + mediaUrl,
};
break;
case 'reddit':
ret[socialMedia[i]] = {
title: 'reddit',
shareUrl: 'https://reddit.com/submit?url=' + mediaUrl + '&title=' + mediaTitle,
};
break;
case 'tumblr':
ret[socialMedia[i]] = {
title: 'Tumblr',
shareUrl: 'https://www.tumblr.com/widgets/share/tool?canonicalUrl=' + mediaUrl + '&title=' + mediaTitle,
};
break;
case 'pinterest':
ret[socialMedia[i]] = {
title: 'Pinterest',
shareUrl: 'http://pinterest.com/pin/create/link/?url=' + mediaUrl,
};
break;
case 'vk':
ret[socialMedia[i]] = {
title: 'ВКонтакте',
shareUrl: 'http://vk.com/share.php?url=' + mediaUrl + '&title=' + mediaTitle,
};
break;
case 'linkedin':
ret[socialMedia[i]] = {
title: 'LinkedIn',
shareUrl: 'https://www.linkedin.com/shareArticle?mini=true&url=' + mediaUrl,
};
break;
case 'mix':
ret[socialMedia[i]] = {
title: 'Mix',
shareUrl: 'https://mix.com/add?url=' + mediaUrl,
};
break;
case 'whatsapp':
ret[socialMedia[i]] = {
title: 'WhatsApp',
shareUrl: 'whatsapp://send?text=' + mediaUrl,
};
break;
case 'telegram':
ret[socialMedia[i]] = {
title: 'Telegram',
shareUrl: 'https://t.me/share/url?url=' + mediaUrl + '&text=' + mediaTitle,
};
break;
}
i += 1;
}
return ret;
}
function ShareOptions() {
const shareOptions = shareOptionsList();
const compList = [];
for (let k in shareOptions) {
if (shareOptions.hasOwnProperty(k)) {
if (k === 'embed') {
compList.push(
<div key={'share-' + k} className={'sh-option share-' + k + '-opt'}>
<button className="sh-option change-page" data-page-id="shareEmbed">
<span>
<i className="material-icons">code</i>
</span>
<span>Embed</span>
</button>
</div>
);
} else if (k === 'whatsapp') {
compList.push(
<div key={'share-' + k} className={'sh-option share-' + k}>
<a
href={shareOptions[k].shareUrl}
title=""
target="_blank"
data-action="share/whatsapp/share"
rel="noreferrer"
>
<span></span>
<span>{shareOptions[k].title}</span>
</a>
</div>
);
} else if (k === 'email') {
compList.push(
<div key="share-email" className="sh-option share-email">
<a href={shareOptions[k].shareUrl} title="">
<span>
<i className="material-icons">email</i>
</span>
<span>{shareOptions[k].title}</span>
</a>
</div>
);
} else {
compList.push(
<div key={'share-' + k} className={'sh-option share-' + k}>
<a href={shareOptions[k].shareUrl} title="" target="_blank" rel="noreferrer">
<span></span>
<span>{shareOptions[k].title}</span>
</a>
</div>
);
}
}
}
return compList;
}
function NextSlideButton({ onClick }) {
return (
<span className="next-slide">
<CircleIconButton buttonShadow={true} onClick={onClick}>
<i className="material-icons">keyboard_arrow_right</i>
</CircleIconButton>
</span>
);
}
function PreviousSlideButton({ onClick }) {
return (
<span className="previous-slide">
<CircleIconButton buttonShadow={true} onClick={onClick}>
<i className="material-icons">keyboard_arrow_left</i>
</CircleIconButton>
</span>
);
}
function updateDimensions() {
return {
maxFormContentHeight: window.innerHeight - (56 + 4 * 24 + 44),
maxPopupWidth: 518 > window.innerWidth - 2 * 40 ? window.innerWidth - 2 * 40 : null,
};
}
function getTimestamp() {
const videoPlayer = document.getElementsByTagName("video");
return videoPlayer[0]?.currentTime;
}
function ToHHMMSS (timeInt) {
let sec_num = parseInt(timeInt, 10);
let hours = Math.floor(sec_num / 3600);
let minutes = Math.floor((sec_num - (hours * 3600)) / 60);
let seconds = sec_num - (hours * 3600) - (minutes * 60);
if (hours < 10) {hours = "0"+hours;}
if (minutes < 10) {minutes = "0"+minutes;}
if (seconds < 10) {seconds = "0"+seconds;}
return hours >= 1 ? hours + ':' + minutes + ':' + seconds : minutes + ':' + seconds;
}
export function MediaShareOptions(props) {
const containerRef = useRef(null);
const shareOptionsInnerRef = useRef(null);
const mediaUrl = MediaPageStore.get('media-url');
const [inlineSlider, setInlineSlider] = useState(null);
const [sliderButtonsVisible, setSliderButtonsVisible] = useState({ prev: false, next: false });
const [dimensions, setDimensions] = useState(updateDimensions());
const [shareOptions] = useState(ShareOptions());
const [timestamp, setTimestamp] = useState(0);
const [formattedTimestamp, setFormattedTimestamp] = useState(0);
const [startAtSelected, setStartAtSelected] = useState(false);
const [shareMediaLink, setShareMediaLink] = useState(mediaUrl);
function onWindowResize() {
setDimensions(updateDimensions());
}
function onClickCopyMediaLink() {
MediaPageActions.copyShareLink(containerRef.current.querySelector('.copy-field input'));
}
function onCompleteCopyMediaLink() {
// FIXME: Without delay throws conflict error [ Uncaught Error: Dispatch.dispatch(...): Cannot dispatch in the middle of a dispatch. ].
setTimeout(function () {
PageActions.addNotification('Link copied to clipboard', 'clipboardLinkCopy');
}, 100);
}
function updateSlider() {
inlineSlider.scrollToCurrentSlide();
updateSliderButtonsView();
}
function updateSliderButtonsView() {
setSliderButtonsVisible({
prev: inlineSlider.hasPreviousSlide(),
next: inlineSlider.hasNextSlide(),
});
}
function updateStartAtCheckbox() {
setStartAtSelected(!startAtSelected);
updateShareMediaLink();
}
function updateShareMediaLink()
{
const newLink = startAtSelected ? mediaUrl : mediaUrl + "&t=" + Math.trunc(timestamp);
setShareMediaLink(newLink);
}
function nextSlide() {
inlineSlider.nextSlide();
updateSlider();
}
function prevSlide() {
inlineSlider.previousSlide();
updateSlider();
}
useEffect(() => {
setInlineSlider(new ItemsInlineSlider(shareOptionsInnerRef.current, '.sh-option'));
}, [shareOptions]);
useEffect(() => {
if (inlineSlider) {
inlineSlider.updateDataStateOnResize(shareOptions.length, true, true);
updateSlider();
}
}, [dimensions, inlineSlider]);
useEffect(() => {
PageStore.on('window_resize', onWindowResize);
MediaPageStore.on('copied_media_link', onCompleteCopyMediaLink);
const localTimestamp = getTimestamp();
setTimestamp(localTimestamp);
setFormattedTimestamp(ToHHMMSS(localTimestamp));
return () => {
PageStore.removeListener('window_resize', onWindowResize);
MediaPageStore.removeListener('copied_media_link', onCompleteCopyMediaLink);
setInlineSlider(null);
};
}, []);
return (
<div
ref={containerRef}
style={null !== dimensions.maxPopupWidth ? { maxWidth: dimensions.maxPopupWidth + 'px' } : null}
>
<div
className="scrollable-content"
style={null !== dimensions.maxFormContentHeight ? { maxHeight: dimensions.maxFormContentHeight + 'px' } : null}
>
<div className="share-popup-title">Share media</div>
{shareOptions.length ? (
<div className="share-options">
{sliderButtonsVisible.prev ? <PreviousSlideButton onClick={prevSlide} /> : null}
<div ref={shareOptionsInnerRef} className="share-options-inner">
{shareOptions}
</div>
{sliderButtonsVisible.next ? <NextSlideButton onClick={nextSlide} /> : null}
</div>
) : null}
</div>
<div className="copy-field">
<div>
<input type="text" readOnly value={shareMediaLink} />
<button onClick={onClickCopyMediaLink}>COPY</button>
</div>
</div>
<div className="start-at">
<label>
<input
type="checkbox"
name="start-at-checkbox"
id="id-start-at-checkbox"
checked={startAtSelected}
onChange={updateStartAtCheckbox}
/>
Start at {formattedTimestamp}
</label>
</div>
</div>
);
}