diff --git a/frontend/editable-ui/src/components/shared/tiptap-custom-extensions/custom-image-extension.jsx b/frontend/editable-ui/src/components/shared/tiptap-custom-extensions/custom-image-extension.jsx old mode 100644 new mode 100755 index 24ce9e9..f3ff021 --- a/frontend/editable-ui/src/components/shared/tiptap-custom-extensions/custom-image-extension.jsx +++ b/frontend/editable-ui/src/components/shared/tiptap-custom-extensions/custom-image-extension.jsx @@ -1,50 +1,109 @@ -/* - extension credits: Angelika Tyborska: https://angelika.me/2023/02/26/how-to-add-editing-image-alt-text-tiptap/ -*/ - -import Image from '@tiptap/extension-image' import { NodeViewWrapper, ReactNodeViewRenderer } from '@tiptap/react'; -import { - Button -} from 'reactstrap'; +import Image from '@tiptap/extension-image'; +import { Button } from 'reactstrap'; +import CustomImagePropertiesModal from './custom-image-properties-modal.jsx'; +import { useState, useRef, useEffect } from 'react'; + +const CustomImageExtension = Image.extend({ + addAttributes() { + return { + ...this.parent?.(), + height: { + default: '300', + parseHTML: element => element.getAttribute('height'), + renderHTML: attributes => { + if (!attributes.height) { + return {}; + } + return { height: attributes.height }; + }, + }, + width: { + default: '300', + parseHTML: element => element.getAttribute('width'), + renderHTML: attributes => { + if (!attributes.width) { + return {}; + } + return { width: attributes.width }; + }, + }, + }; + }, + addNodeView() { + return ReactNodeViewRenderer(ImageNode); + }, +}); function ImageNode(props) { - const { src, alt } = props.node.attrs - const { updateAttributes } = props - const onEditAlt = () => { - const newAlt = prompt('Set alt text:', alt || '') - updateAttributes({ alt: newAlt }) - } + const imageRef = useRef(null); + const [modal, setModal] = useState(false); + const [height, setHeight] = useState(props.node.attrs.height || ''); + const [width, setWidth] = useState(props.node.attrs.width || ''); - let className = 'image' - if (props.selected) { className += ' ProseMirror-selectednode'} + const toggle = () => setModal(!modal); + + const { src, alt } = props.node.attrs; + const { updateAttributes } = props; + + const setAlt = (alt) => { + updateAttributes({ alt }); + }; + + const handleSetWidth = (width) => { + setWidth(width); + updateAttributes({ width }); + }; + + const handleSetHeight = (height) => { + setHeight(height); + updateAttributes({ height }); + }; + + useEffect(() => { + if (imageRef.current) { + imageRef.current.height = height; + imageRef.current.width = width; + } + }, [height, width]); + + useEffect(() => { + if (imageRef.current) { + if (imageRef.current.height !== ''){ + setHeight(imageRef.current.height) + } + if (imageRef.current.width !== ''){ + setWidth(imageRef.current.width) + } + } + }); + + let className = 'image'; + if (props.selected) className += ' ProseMirror-selectednode'; return ( -
- {alt} + +
+ {alt}
- { alt ? - : - ! - } - { alt ? - Alt text: “{alt}“.: - Alt text missing. - } -
- ) + ); } -export default Image.extend({ - addNodeView() { - return ReactNodeViewRenderer(ImageNode) - } -}) \ No newline at end of file +export default CustomImageExtension; diff --git a/frontend/editable-ui/src/components/shared/tiptap-custom-extensions/custom-image-properties-modal.jsx b/frontend/editable-ui/src/components/shared/tiptap-custom-extensions/custom-image-properties-modal.jsx new file mode 100755 index 0000000..535677b --- /dev/null +++ b/frontend/editable-ui/src/components/shared/tiptap-custom-extensions/custom-image-properties-modal.jsx @@ -0,0 +1,34 @@ +import { Button, Modal, ModalHeader, ModalBody, ModalFooter, InputGroup, InputGroupText, Input } from 'reactstrap'; +import RangeSlider from './range-slider.jsx'; +import { useRef } from 'react'; + +function CustomImagePropertiesModal(props) { + + const altField = useRef(null) + + return ( +
+ + Change Image Properties + + + + Image Alt Text + + props.setAlt(altField.current.value)} /> + + + + + + {' '} + + +
+ ); + +} + +export default CustomImagePropertiesModal; diff --git a/frontend/editable-ui/src/components/shared/tiptap-custom-extensions/range-slider.jsx b/frontend/editable-ui/src/components/shared/tiptap-custom-extensions/range-slider.jsx new file mode 100755 index 0000000..68091d7 --- /dev/null +++ b/frontend/editable-ui/src/components/shared/tiptap-custom-extensions/range-slider.jsx @@ -0,0 +1,30 @@ +import React, { useState } from 'react'; +import { Input, Label, FormGroup, Container } from 'reactstrap'; +function RangeSlider (props) { + const [value, setValue] = useState(props.defaultValue || props.min); + + const handleChange = (e) => { + setValue(e.target.value); + props.setRange(e.target.value) + }; + + return ( + + + + + + + ); +} + +export default RangeSlider; \ No newline at end of file diff --git a/frontend/editable-ui/src/components/shared/tiptap.jsx b/frontend/editable-ui/src/components/shared/tiptap.jsx index 0b87778..0fdcf71 100755 --- a/frontend/editable-ui/src/components/shared/tiptap.jsx +++ b/frontend/editable-ui/src/components/shared/tiptap.jsx @@ -348,7 +348,9 @@ const extensions = [ }), Underline, Blockquote, - CustomImageExtension, + CustomImageExtension.configure({ + htmlAttributes: ['height', 'width'] + }), TextAlign.configure({ types: ['heading', 'paragraph'], }), diff --git a/frontend/editable-ui/src/index.css b/frontend/editable-ui/src/index.css index b9e3df9..f01c037 100755 --- a/frontend/editable-ui/src/index.css +++ b/frontend/editable-ui/src/index.css @@ -35,7 +35,6 @@ a { display: flex; justify-content: center; align-items: center; - width: 70%; } .image-container { diff --git a/frontend/viewable-ui/src/index.css b/frontend/viewable-ui/src/index.css index 8d8fe71..ae8002c 100755 --- a/frontend/viewable-ui/src/index.css +++ b/frontend/viewable-ui/src/index.css @@ -25,7 +25,7 @@ a { display: flex; justify-content: center; align-items: center; - width: 65%; + width: 100%; } @media only screen and (max-width: 765px){