Commit 8c845e28 by Яков

update iframe and video

parent e1b05324
{
"name": "react-ag-qeditor",
"version": "1.1.24",
"version": "1.1.25",
"description": "WYSIWYG html editor",
"author": "atma",
"license": "MIT",
......
......@@ -18,8 +18,17 @@ const getStyleForAlign = (align) => {
return style
}
const getOuterAlignStyle = (align) => {
return {
width: '100%',
display: 'block',
textAlign: align === 'center' ? 'center' : align === 'right' ? 'right' : 'left',
}
}
const ResizableIframeView = ({ editor, node, updateAttributes, getPos, selected }) => {
const wrapperRef = useRef(null)
const outerRef = useRef(null)
const innerRef = useRef(null)
const iframeRef = useRef(null)
const [showAlignMenu, setShowAlignMenu] = useState(false)
......@@ -36,10 +45,9 @@ const ResizableIframeView = ({ editor, node, updateAttributes, getPos, selected
const paddingRight = parseFloat(editorStyles.paddingRight) || 0
const availableEditorWidth = fullEditorWidth - paddingLeft - paddingRight
// важно: стартуем от parentElement, чтобы не схватить wrapperRef.current
const startEl = wrapperRef.current?.parentElement || editorContent
const container =
startEl.closest('li, blockquote, td, p, div') || editorContent
// важно: стартуем от parentElement, чтобы не схватить innerRef.current
const startEl = outerRef.current?.parentElement || editorContent
const container = startEl.closest('li, blockquote, td, p, div') || editorContent
const containerStyles = window.getComputedStyle(container)
const containerPaddingLeft = parseFloat(containerStyles.paddingLeft) || 0
......@@ -49,7 +57,6 @@ const ResizableIframeView = ({ editor, node, updateAttributes, getPos, selected
return { width: containerWidth, availableSpace: availableEditorWidth }
}
const safeUpdateAttributes = (newAttrs) => {
const { width: containerWidth, availableSpace } = getEditorDimensions()
......@@ -57,7 +64,8 @@ const ResizableIframeView = ({ editor, node, updateAttributes, getPos, selected
let height = newAttrs.height ?? node.attrs.height
if (typeof width === 'number' && typeof height === 'number') {
const maxWidth = node.attrs.align === 'center' ? containerWidth : availableSpace
const maxWidth = (newAttrs.align ?? node.attrs.align) === 'center' ? containerWidth : availableSpace
if (width > maxWidth) {
const ratio = maxWidth / width
width = maxWidth
......@@ -117,14 +125,14 @@ const ResizableIframeView = ({ editor, node, updateAttributes, getPos, selected
console.warn('getPos() failed:', err)
}
const startWidth = node.attrs.width || iframeRef.current?.clientWidth || 560
const startHeight = node.attrs.height || iframeRef.current?.clientHeight || 315
const startWidth = node.attrs.width || innerRef.current?.clientWidth || 560
const startHeight = node.attrs.height || innerRef.current?.clientHeight || 315
const aspectRatio = startWidth / startHeight
const startX = e.clientX
const startY = e.clientY
const { width: containerWidth, availableSpace } = getEditorDimensions()
const maxWidth = node.attrs.align === 'center' ? containerWidth : availableSpace
const maxWidth = (node.attrs.align || 'left') === 'center' ? containerWidth : availableSpace
const onMouseMove = (ev) => {
requestAnimationFrame(() => {
......@@ -177,145 +185,139 @@ const ResizableIframeView = ({ editor, node, updateAttributes, getPos, selected
const align = node.attrs.align || 'left'
const wrapperStyle = {
const outerStyle = getOuterAlignStyle(align)
const innerStyle = {
position: 'relative',
display: 'inline-block',
width: node.attrs.width ? `${node.attrs.width}px` : undefined,
height: node.attrs.height ? `${node.attrs.height}px` : undefined,
// align styles inside editor
display: align === 'center' ? 'block' : 'inline-block',
marginLeft: align === 'center' ? 'auto' : undefined,
marginRight: align === 'center' ? 'auto' : undefined,
float: align === 'left' ? 'left' : align === 'right' ? 'right' : 'none',
// чтобы текст красиво обтекал
marginInlineEnd: align === 'left' ? '1rem' : undefined,
marginInlineStart: align === 'right' ? '1rem' : undefined,
}
return (
<NodeViewWrapper
ref={wrapperRef}
ref={outerRef}
as="div"
className="atma-iframe-wrapper"
style={wrapperStyle}
data-align={node.attrs.align || 'left'}
style={outerStyle}
data-align={align}
>
<iframe
ref={iframeRef}
src={node.attrs.src}
frameBorder={node.attrs.frameborder ?? 0}
allowFullScreen
allow="fullscreen"
style={{
width: '100%',
height: '100%',
pointerEvents: editor.isEditable ? 'none' : 'auto',
}}
/>
{(selected || isResizing) && (
<Fragment>
<button
type="button"
onClick={deleteNode}
style={{
position: 'absolute',
top: 4,
right: 4,
zIndex: 30,
backgroundColor: 'white',
border: '1px solid #d9d9d9',
borderRadius: '50%',
width: 20,
height: 20,
fontSize: 12,
lineHeight: 1,
padding: '0px 0px 2px 0px',
cursor: 'pointer',
}}
>
×
</button>
{['nw', 'ne', 'sw', 'se'].map((d) => (
<div
key={d}
onMouseDown={handleResizeStart(d)}
<div ref={innerRef} style={innerStyle}>
<iframe
ref={iframeRef}
src={node.attrs.src}
frameBorder={node.attrs.frameborder ?? 0}
allowFullScreen
allow="fullscreen"
style={{
width: '100%',
height: '100%',
pointerEvents: editor.isEditable ? 'none' : 'auto',
}}
/>
{(selected || isResizing) && (
<Fragment>
<button
type="button"
onClick={deleteNode}
style={{
position: 'absolute',
width: 12,
height: 12,
backgroundColor: BORDER_COLOR,
border: '1px solid white',
[d[0] === 'n' ? 'top' : 'bottom']: -6,
[d[1] === 'w' ? 'left' : 'right']: -6,
cursor: `${d}-resize`,
zIndex: 10,
top: 4,
right: 4,
zIndex: 30,
backgroundColor: 'white',
border: '1px solid #d9d9d9',
borderRadius: '50%',
width: 20,
height: 20,
fontSize: 12,
lineHeight: 1,
padding: '0px 0px 2px 0px',
cursor: 'pointer',
}}
>
×
</button>
{['nw', 'ne', 'sw', 'se'].map((d) => (
<div
key={d}
onMouseDown={handleResizeStart(d)}
style={{
position: 'absolute',
width: 12,
height: 12,
backgroundColor: BORDER_COLOR,
border: '1px solid white',
[d[0] === 'n' ? 'top' : 'bottom']: -6,
[d[1] === 'w' ? 'left' : 'right']: -6,
cursor: `${d}-resize`,
zIndex: 10,
}}
/>
))}
{showAlignMenu && (
<div
style={{
position: 'absolute',
top: -40,
left: '50%',
transform: 'translateX(-50%)',
backgroundColor: 'white',
boxShadow: '0 2px 8px rgba(0,0,0,0.15)',
borderRadius: 4,
padding: 4,
zIndex: 20,
display: 'flex',
}}
>
{ALIGN_OPTIONS.map((a) => (
<button
type="button"
key={a}
onClick={() => handleAlign(a)}
style={{
margin: '0 2px',
padding: '10px 8px',
background: align === a ? '#e6f7ff' : 'transparent',
border: '1px solid #d9d9d9',
borderRadius: 2,
cursor: 'pointer',
}}
>
{a}
</button>
))}
</div>
)}
<button
type="button"
onClick={(e) => {
e.stopPropagation()
setShowAlignMenu((v) => !v)
}}
/>
))}
{showAlignMenu && (
<div
style={{
position: 'absolute',
top: -40,
left: '50%',
top: -30,
left: 'calc(50% - 6px)',
transform: 'translateX(-50%)',
backgroundColor: 'white',
boxShadow: '0 2px 8px rgba(0,0,0,0.15)',
border: `1px solid ${BORDER_COLOR}`,
borderRadius: 4,
padding: 4,
zIndex: 20,
display: 'flex',
padding: '8px 8px',
cursor: 'pointer',
fontSize: 12,
zIndex: 10,
}}
>
{ALIGN_OPTIONS.map((align) => (
<button
type="button"
key={align}
onClick={() => handleAlign(align)}
style={{
margin: '0 2px',
padding: '10px 8px',
background: node.attrs.align === align ? '#e6f7ff' : 'transparent',
border: '1px solid #d9d9d9',
borderRadius: 2,
cursor: 'pointer',
}}
>
{align}
</button>
))}
</div>
)}
<button
type="button"
onClick={(e) => {
e.stopPropagation()
setShowAlignMenu((v) => !v)
}}
style={{
position: 'absolute',
top: -30,
left: 'calc(50% - 6px)',
transform: 'translateX(-50%)',
backgroundColor: 'white',
border: `1px solid ${BORDER_COLOR}`,
borderRadius: 4,
padding: '8px 8px',
cursor: 'pointer',
fontSize: 12,
zIndex: 10,
}}
>
Align
</button>
</Fragment>
)}
Align
</button>
</Fragment>
)}
</div>
</NodeViewWrapper>
)
}
......
......@@ -18,8 +18,17 @@ const getStyleForAlign = (align) => {
return style
}
const getOuterAlignStyle = (align) => {
return {
width: '100%',
display: 'block',
textAlign: align === 'center' ? 'center' : align === 'right' ? 'right' : 'left',
}
}
const ResizableVideoView = ({ editor, node, updateAttributes, getPos, selected }) => {
const wrapperRef = useRef(null)
const outerRef = useRef(null)
const innerRef = useRef(null)
const videoRef = useRef(null)
const [showAlignMenu, setShowAlignMenu] = useState(false)
......@@ -36,7 +45,9 @@ const ResizableVideoView = ({ editor, node, updateAttributes, getPos, selected }
const paddingRight = parseFloat(editorStyles.paddingRight) || 0
const availableEditorWidth = fullEditorWidth - paddingLeft - paddingRight
const container = wrapperRef.current?.closest('li, blockquote, td, p, div') || editorContent
const startEl = outerRef.current?.parentElement || editorContent
const container = startEl.closest('li, blockquote, td, p, div') || editorContent
const containerStyles = window.getComputedStyle(container)
const containerPaddingLeft = parseFloat(containerStyles.paddingLeft) || 0
const containerPaddingRight = parseFloat(containerStyles.paddingRight) || 0
......@@ -52,7 +63,8 @@ const ResizableVideoView = ({ editor, node, updateAttributes, getPos, selected }
let height = newAttrs.height ?? node.attrs.height
if (typeof width === 'number' && typeof height === 'number') {
const maxWidth = node.attrs.align === 'center' ? containerWidth : availableSpace
const maxWidth = (newAttrs.align ?? node.attrs.align) === 'center' ? containerWidth : availableSpace
if (width > maxWidth) {
const ratio = maxWidth / width
width = maxWidth
......@@ -112,14 +124,14 @@ const ResizableVideoView = ({ editor, node, updateAttributes, getPos, selected }
console.warn('getPos() failed:', err)
}
const startWidth = node.attrs.width || videoRef.current?.clientWidth || 640
const startHeight = node.attrs.height || videoRef.current?.clientHeight || 360
const startWidth = node.attrs.width || innerRef.current?.clientWidth || 640
const startHeight = node.attrs.height || innerRef.current?.clientHeight || 360
const aspectRatio = startWidth / startHeight
const startX = e.clientX
const startY = e.clientY
const { width: containerWidth, availableSpace } = getEditorDimensions()
const maxWidth = node.attrs.align === 'center' ? containerWidth : availableSpace
const maxWidth = (node.attrs.align || 'left') === 'center' ? containerWidth : availableSpace
const onMouseMove = (ev) => {
requestAnimationFrame(() => {
......@@ -170,134 +182,140 @@ const ResizableVideoView = ({ editor, node, updateAttributes, getPos, selected }
}
}
const wrapperStyle = {
const align = node.attrs.align || 'left'
const outerStyle = getOuterAlignStyle(align)
const innerStyle = {
position: 'relative',
display: node.attrs.align === 'center' ? 'block' : 'inline-block',
display: 'inline-block',
width: node.attrs.width ? `${node.attrs.width}px` : undefined,
height: node.attrs.height ? `${node.attrs.height}px` : undefined,
}
return (
<NodeViewWrapper
ref={wrapperRef}
ref={outerRef}
as="div"
className="atma-video-wrapper"
style={wrapperStyle}
data-align={node.attrs.align || 'left'}
style={outerStyle}
data-align={align}
>
<video
ref={videoRef}
src={node.attrs.src}
poster={node.attrs.poster}
controls={node.attrs.controls !== false}
style={{
width: '100%',
height: '100%',
pointerEvents: editor.isEditable ? 'none' : 'auto',
}}
/>
{(selected || isResizing) && (
<Fragment>
<button
type="button"
onClick={deleteNode}
style={{
position: 'absolute',
top: 4,
right: 4,
zIndex: 30,
backgroundColor: 'white',
border: '1px solid #d9d9d9',
borderRadius: '50%',
width: 20,
height: 20,
fontSize: 12,
lineHeight: 1,
padding: '0px 0px 2px 0px',
cursor: 'pointer',
}}
>
×
</button>
{['nw', 'ne', 'sw', 'se'].map((d) => (
<div
key={d}
onMouseDown={handleResizeStart(d)}
<div ref={innerRef} style={innerStyle}>
<video
ref={videoRef}
src={node.attrs.src}
poster={node.attrs.poster}
controls={node.attrs.controls !== false}
style={{
width: '100%',
height: '100%',
pointerEvents: editor.isEditable ? 'none' : 'auto',
}}
/>
{(selected || isResizing) && (
<Fragment>
<button
type="button"
onClick={deleteNode}
style={{
position: 'absolute',
width: 12,
height: 12,
backgroundColor: BORDER_COLOR,
border: '1px solid white',
[d[0] === 'n' ? 'top' : 'bottom']: -6,
[d[1] === 'w' ? 'left' : 'right']: -6,
cursor: `${d}-resize`,
zIndex: 10,
top: 4,
right: 4,
zIndex: 30,
backgroundColor: 'white',
border: '1px solid #d9d9d9',
borderRadius: '50%',
width: 20,
height: 20,
fontSize: 12,
lineHeight: 1,
padding: '0px 0px 2px 0px',
cursor: 'pointer',
}}
>
×
</button>
{['nw', 'ne', 'sw', 'se'].map((d) => (
<div
key={d}
onMouseDown={handleResizeStart(d)}
style={{
position: 'absolute',
width: 12,
height: 12,
backgroundColor: BORDER_COLOR,
border: '1px solid white',
[d[0] === 'n' ? 'top' : 'bottom']: -6,
[d[1] === 'w' ? 'left' : 'right']: -6,
cursor: `${d}-resize`,
zIndex: 10,
}}
/>
))}
{showAlignMenu && (
<div
style={{
position: 'absolute',
top: -40,
left: '50%',
transform: 'translateX(-50%)',
backgroundColor: 'white',
boxShadow: '0 2px 8px rgba(0,0,0,0.15)',
borderRadius: 4,
padding: 4,
zIndex: 20,
display: 'flex',
}}
>
{ALIGN_OPTIONS.map((a) => (
<button
type="button"
key={a}
onClick={() => handleAlign(a)}
style={{
margin: '0 2px',
padding: '10px 8px',
background: align === a ? '#e6f7ff' : 'transparent',
border: '1px solid #d9d9d9',
borderRadius: 2,
cursor: 'pointer',
}}
>
{a}
</button>
))}
</div>
)}
<button
type="button"
onClick={(e) => {
e.stopPropagation()
setShowAlignMenu((v) => !v)
}}
/>
))}
{showAlignMenu && (
<div
style={{
position: 'absolute',
top: -40,
left: '50%',
top: -30,
left: 'calc(50% - 6px)',
transform: 'translateX(-50%)',
backgroundColor: 'white',
boxShadow: '0 2px 8px rgba(0,0,0,0.15)',
border: `1px solid ${BORDER_COLOR}`,
borderRadius: 4,
padding: 4,
zIndex: 20,
display: 'flex',
padding: '8px 8px',
cursor: 'pointer',
fontSize: 12,
zIndex: 10,
}}
>
{ALIGN_OPTIONS.map((align) => (
<button
type="button"
key={align}
onClick={() => handleAlign(align)}
style={{
margin: '0 2px',
padding: '10px 8px',
background: node.attrs.align === align ? '#e6f7ff' : 'transparent',
border: '1px solid #d9d9d9',
borderRadius: 2,
cursor: 'pointer',
}}
>
{align}
</button>
))}
</div>
)}
<button
type="button"
onClick={(e) => {
e.stopPropagation()
setShowAlignMenu((v) => !v)
}}
style={{
position: 'absolute',
top: -30,
left: 'calc(50% - 6px)',
transform: 'translateX(-50%)',
backgroundColor: 'white',
border: `1px solid ${BORDER_COLOR}`,
borderRadius: 4,
padding: '8px 8px',
cursor: 'pointer',
fontSize: 12,
zIndex: 10,
}}
>
Align
</button>
</Fragment>
)}
Align
</button>
</Fragment>
)}
</div>
</NodeViewWrapper>
)
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment