From eca9f00cd815d7d0d69826bd340064816cc3255c Mon Sep 17 00:00:00 2001 From: Guodong Su <stephen.su66@gmail.com> Date: Mon, 20 Jan 2025 13:35:39 +0800 Subject: [PATCH] feat(video):add video file --- .../dialog/add-video-link-dialog.js | 95 +++++++++++++++++++ .../sdoc/sdoc-editor/external-operations.js | 29 +++++- 2 files changed, 123 insertions(+), 1 deletion(-) create mode 100644 frontend/src/components/dialog/add-video-link-dialog.js diff --git a/frontend/src/components/dialog/add-video-link-dialog.js b/frontend/src/components/dialog/add-video-link-dialog.js new file mode 100644 index 00000000000..1838be21a3f --- /dev/null +++ b/frontend/src/components/dialog/add-video-link-dialog.js @@ -0,0 +1,95 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import { Button, Modal, Input, ModalBody, ModalFooter, Form, FormGroup, Label, Alert } from 'reactstrap'; +import { gettext } from '../../utils/constants'; +import SeahubModalHeader from '@/components/common/seahub-modal-header'; + +const propTypes = { + onAddLink: PropTypes.func.isRequired, + toggleDialog: PropTypes.func.isRequired, +}; + +class AddVideoLink extends React.Component { + constructor(props) { + super(props); + this.state = { + videoLink: '', + errMessage: '', + isSubmitBtnActive: false, + }; + this.newInput = React.createRef(); + } + + isValidVideoLink = (link) => { + // const videoRegex = /\.(mp4|mov|avi|mkv|webm|ogv)$/i; + // return videoRegex.test(link); + return link; + }; + + handleChange = (e) => { + const videoLink = e.target.value.trim(); + const isValid = this.isValidVideoLink(videoLink); + + if (!e.target.value.trim()) { + this.setState({ isSubmitBtnActive: false }); + } + + this.setState({ + videoLink: videoLink, + isSubmitBtnActive: isValid, + errMessage: isValid ? '' : gettext('Please enter a valid video URL ending in .mp4, .mov, etc.'), + }); + + }; + + handleSubmit = () => { + if (!this.state.isSubmitBtnActive) return; + this.props.onAddLink(this.state.videoLink); + this.props.toggleDialog(); + }; + + handleKeyDown = (e) => { + if (e.key === 'Enter') { + this.handleSubmit(); + e.preventDefault(); + } + }; + + onAfterModelOpened = () => { + if (!this.newInput.current) return; + this.newInput.current.focus(); + this.newInput.current.setSelectionRange(0, 0); + }; + + render() { + const { toggleDialog } = this.props; + return ( + <Modal isOpen={true} toggle={toggleDialog} onOpened={this.onAfterModelOpened}> + <SeahubModalHeader toggle={toggleDialog}>{gettext('Insert_link')}</SeahubModalHeader> + <ModalBody> + <Form> + <FormGroup> + <Label for='videoLink'>{gettext('Link_address')}</Label> + <Input + id='videoLink' + onKeyDown={this.handleKeyDown} + innerRef={this.newInput} + value={this.state.videoLink} + onChange={this.handleChange} + /> + </FormGroup> + </Form> + {this.state.errMessage && <Alert color='danger' className='mt-2'>{this.state.errMessage}</Alert>} + </ModalBody> + <ModalFooter> + <Button color='secondary' onClick={toggleDialog}>{gettext('Cancel')}</Button> + <Button color='primary' onClick={this.handleSubmit} disabled={!this.state.isSubmitBtnActive}>{gettext('Submit')}</Button> + </ModalFooter> + </Modal> + ); + } +} + +AddVideoLink.propTypes = propTypes; + +export default AddVideoLink; diff --git a/frontend/src/pages/sdoc/sdoc-editor/external-operations.js b/frontend/src/pages/sdoc/sdoc-editor/external-operations.js index e1918e2fc07..67f7c994b44 100644 --- a/frontend/src/pages/sdoc/sdoc-editor/external-operations.js +++ b/frontend/src/pages/sdoc/sdoc-editor/external-operations.js @@ -7,6 +7,7 @@ import toaster from '../../../components/toast'; import InternalLinkDialog from '../../../components/dialog/internal-link-dialog'; import ShareDialog from '../../../components/dialog/share-dialog'; import CreateFile from '../../../components/dialog/create-file-dialog'; +import AddVideoLink from '../../../components/dialog/add-video-link-dialog'; const propTypes = { repoID: PropTypes.string.isRequired, @@ -33,6 +34,8 @@ class ExternalOperations extends React.Component { fileType: '.sdoc', editor: null, insertSdocFileLink: null, + isShowAddVideoLinkDialog: false, + insertVideo: null }; } @@ -46,6 +49,7 @@ class ExternalOperations extends React.Component { this.unsubscribeNewNotification = eventBus.subscribe(EXTERNAL_EVENT.NEW_NOTIFICATION, this.onNewNotification); this.unsubscribeClearNotification = eventBus.subscribe(EXTERNAL_EVENT.CLEAR_NOTIFICATION, this.onClearNotification); this.unsubscribeCreateSdocFile = eventBus.subscribe(EXTERNAL_EVENT.CREATE_SDOC_FILE, this.onCreateSdocFile); + this.unsubscribeAddVideoLink = eventBus.subscribe(EXTERNAL_EVENT.ADD_VIDEO_LINK, this.onAddVideoLink); } componentWillUnmount() { @@ -58,8 +62,18 @@ class ExternalOperations extends React.Component { this.unsubscribeNewNotification(); this.unsubscribeCreateSdocFile(); this.unsubscribeClearNotification(); + this.unsubscribeAddVideoLink(); } + onAddVideoLink = (params) => { + if (params?.editor && params?.insertVideo) { + this.setState({ editor: params.editor, insertVideo: params.insertVideo }); + } + this.setState({ + isShowAddVideoLinkDialog: !this.state.isShowAddVideoLinkDialog + }); + }; + onInternalLinkToggle = (options) => { if (options && options.internalLink) { this.setState({ internalLink: options.internalLink }); @@ -164,9 +178,16 @@ class ExternalOperations extends React.Component { }); }; + onAddLink = (videoLink) => { + const { insertVideo, editor } = this.state; + if (insertVideo && editor) { + insertVideo(editor, [{ isEmbeddableLink: true }], [videoLink]); + } + }; + render() { const { repoID, docPath, docName, docPerm, dirPath } = this.props; - const { isShowInternalLinkDialog, isShowShareDialog, internalLink, isShowCreateFileDialog, fileType } = this.state; + const { isShowInternalLinkDialog, isShowShareDialog, internalLink, isShowCreateFileDialog, fileType, isShowAddVideoLinkDialog } = this.state; return ( <> {isShowInternalLinkDialog && ( @@ -196,6 +217,12 @@ class ExternalOperations extends React.Component { toggleDialog={this.onCreateSdocFile} /> )} + {isShowAddVideoLinkDialog && ( + <AddVideoLink + onAddLink={this.onAddLink} + toggleDialog={this.onAddVideoLink} + /> + )} </> ); }