From 90e9f7f266ae05944ad050e17635b781cd9464b0 Mon Sep 17 00:00:00 2001 From: Graeme Fulton Date: Sun, 23 Jun 2024 12:39:36 -0400 Subject: [PATCH] #43 --- .../CustomExtensions/Figure2/CustomImage.js | 32 +- .../Editor/CustomExtensions/Figure2/Figure.js | 788 +++++++++--------- .../Figure2/ImageNodeView/ImageNodeView.js | 40 + components/Editor/Menus/Common/WidthRange.js | 32 + components/Editor/Menus/ImageMenu.jsx | 76 +- styles/posts-page.scss | 2 +- 6 files changed, 510 insertions(+), 460 deletions(-) create mode 100644 components/Editor/CustomExtensions/Figure2/ImageNodeView/ImageNodeView.js diff --git a/components/Editor/CustomExtensions/Figure2/CustomImage.js b/components/Editor/CustomExtensions/Figure2/CustomImage.js index a6c99cd8..db38e3ab 100644 --- a/components/Editor/CustomExtensions/Figure2/CustomImage.js +++ b/components/Editor/CustomExtensions/Figure2/CustomImage.js @@ -1,3 +1,5 @@ +import React from 'react'; +import { ReactNodeViewRenderer } from "@tiptap/react"; import { mergeAttributes, Node, @@ -5,6 +7,7 @@ import { } from '@tiptap/core' import { PluginKey , Plugin} from "prosemirror-state"; import {Decoration, DecorationSet} from "prosemirror-view" +import ImageNodeView from './ImageNodeView/ImageNodeView'; export const ImageDecorationKey = new PluginKey('image-decoration'); @@ -31,13 +34,20 @@ export const ImageDecorationKey = new PluginKey('image-decoration'); return this.options.inline ? 'inline' : 'block' }, - draggable: false, + draggable: true, addAttributes() { return { src: { default: null, }, + // blob:{ + // default:null, + // parseHTML: async (element) => { + // const blob = await imgToBlob() + // return blob + // } + // }, alt: { default: null, }, @@ -144,6 +154,13 @@ export const ImageDecorationKey = new PluginKey('image-decoration'); props: { decorations(state) { return this.getState(state) }, }, + // filterTransaction: (transaction, state) => { + // let result = true; // true for keep, false for stop transaction + // if (transaction?.curSelection?.node?.type.name == "image") { + // result = false; + // } + // return result; + // }, }) ]; @@ -189,11 +206,20 @@ export const ImageDecorationKey = new PluginKey('image-decoration'); find: inputRegex, type: this.type, getAttributes: match => { - const [,, alt, src, title] = match + const [alt, src, title] = match return { src, alt, title } }, }), ] }, - }) \ No newline at end of file + // addNodeView() { + // return ReactNodeViewRenderer(React.memo(ImageNodeView)); + // } + }) + + const imgToBlob = async () => { + const response = await fetch(`https://req.prototypr.io/${props.node.attrs.src}`); + const blob = await response.blob(); + return (URL.createObjectURL(blob)); + }; \ No newline at end of file diff --git a/components/Editor/CustomExtensions/Figure2/Figure.js b/components/Editor/CustomExtensions/Figure2/Figure.js index 2caa6020..4f38697b 100644 --- a/components/Editor/CustomExtensions/Figure2/Figure.js +++ b/components/Editor/CustomExtensions/Figure2/Figure.js @@ -1,298 +1,328 @@ import { - Node, - nodeInputRule, - findChildrenInRange, - Tracker, - mergeAttributes, - } from '@tiptap/core'; + Node, + nodeInputRule, + findChildrenInRange, + Tracker, + mergeAttributes, +} from "@tiptap/core"; // import { JSONContent } from '@tiptap/react'; - import { TextSelection } from 'prosemirror-state'; - import { PluginKey , Plugin} from "prosemirror-state"; +import { TextSelection } from "prosemirror-state"; +import { PluginKey, Plugin } from "prosemirror-state"; // import {Decoration, DecorationSet} from "prosemirror-view" - + // export const ImageDecorationKey = new PluginKey('image-decoration'); - - export const inputRegex = /!\[(.+|:?)]\((\S+)(?:(?:\s+)["'](\S+)["'])?\)/; - - const Figure = Node.create({ - name: 'figure', - // defaultOptions: { - // HTMLAttributes: {}, - // }, - group: 'block', - content: 'image?video?figcaption?', - draggable: true, - inline: false, - atom:true, - defining: true, - selectable:true, - addAttributes() { - return { - src: { - default: null, - parseHTML: (element) =>{ - if(element.querySelector('img')?.getAttribute('src')){ - return element.querySelector('img')?.getAttribute('src') - }else if(element.querySelector('video')?.getAttribute('src')){ - return element.querySelector('video')?.getAttribute('src') - } +export const inputRegex = /!\[(.+|:?)]\((\S+)(?:(?:\s+)["'](\S+)["'])?\)/; - return false - }, - }, - alt: { - default: null, - parseHTML: (element) =>{ - if(element.querySelector('img')?.getAttribute('alt')){ - return element.querySelector('img')?.getAttribute('alt') - }else if(element.querySelector('video')?.getAttribute('alt')){ - return element.querySelector('video')?.getAttribute('alt') - } - return false +const Figure = Node.create({ + name: "figure", + // defaultOptions: { + // HTMLAttributes: {}, + // }, + group: "block", + content: "image?video?figcaption?", + draggable: true, + inline: false, + atom: true, + defining: true, + selectable: true, + addAttributes() { + return { + src: { + default: null, + parseHTML: element => { + if (element.querySelector("img")?.getAttribute("src")) { + return element.querySelector("img")?.getAttribute("src"); + } else if (element.querySelector("video")?.getAttribute("src")) { + return element.querySelector("video")?.getAttribute("src"); } + + return false; }, - title: { - default: null, - parseHTML: (element) => - element.querySelector('img')?.getAttribute('title'), + }, + alt: { + default: null, + parseHTML: element => { + if (element.querySelector("img")?.getAttribute("alt")) { + return element.querySelector("img")?.getAttribute("alt"); + } else if (element.querySelector("video")?.getAttribute("alt")) { + return element.querySelector("video")?.getAttribute("alt"); + } + return false; }, - figureType:{ - default:'image', - parseHTML:(element)=>{ - if(element.querySelector('img')){ - return 'image' - }else if(element.querySelector('video')){ - return 'video' - } + }, + title: { + default: null, + parseHTML: element => + element.querySelector("img")?.getAttribute("title"), + }, + figureType: { + default: "image", + parseHTML: element => { + if (element.querySelector("img")) { + return "image"; + } else if (element.querySelector("video")) { + return "video"; } }, + }, - width:{ + width: { default: null, parseHTML: element => { - if(element.nodeName=='FIGURE'){ - - return element.getAttribute("width") + if (element.nodeName == "FIGURE") { + return element.getAttribute("width"); + } + }, + }, + link: { + parseHTML: element => { + if (element.querySelector("a")) { + return element.querySelector("a")?.getAttribute("href"); + } else if (element.parentElement?.nodeName == "A") { + var url = element.parentElement.getAttribute("href"); + return url; + } else { + return null; } }, }, - link: { parseHTML: (element) => { - if(element.querySelector('a')){ - return element.querySelector('a')?.getAttribute('href') - } - else if(element.parentElement?.nodeName=='A') { - var url = element.parentElement.getAttribute("href") - return url - }else{ - return null - } - }} - }; - }, - - parseHTML() { - return [{ tag: 'figure' }]; - }, - - addProseMirrorPlugins() { - const editor = this.editor - return [ - new Plugin({ - props: { - handleDOMEvents:(view,e)=>{ - console.log(e) - }, - handleKeyDown:(view, e)=>{ - - if(e.key=='Backspace'){ - return + }; + }, + + parseHTML() { + return [{ tag: "figure" }]; + }, + + addProseMirrorPlugins() { + const editor = this.editor; + return [ + new Plugin({ + props: { + handleDOMEvents: (view, e) => { + console.log(e); + }, + handleKeyDown: (view, e) => { + if (e.key == "Backspace") { + return; } - - let $pos = view.state.doc.resolve(view.state.selection?.$anchor.pos) - - if($pos?.nodeAfter?.type.name=='figure'){ - //if caret in text caption - if($pos.nodeAfter.firstChild?.type?.name=='text' || $pos.nodeAfter.firstChild==null){ - let returnPos = $pos.pos - for (let d = $pos.depth; d > 0; d--) { - let prevNode = $pos.node(d) - if(prevNode?.type?.name=='figure'){ - returnPos = $pos.before(d) - break; - } - } - - if(e.key=='Enter'){ - editor.chain().focus() - .setNodeSelection(returnPos) - // .insertContentAt(pos+1, '

', { - // updateSelection: false, - // parseOptions: { - // preserveWhitespace: 'full', - // } - // }) - .run() - } - }else{ - const { $from } = this.editor.state.selection; - const selectedNode = $from.nodeAfter; - - let ev = e; // Event object 'ev' - var key = ev.which || ev.keyCode; // Detecting keyCode - // Detecting Ctrl - var ctrl = ev.ctrlKey ? ev.ctrlKey :ev.metaKey?ev.metaKey: ((key === 17 ) - ? true : false); - // If key pressed is V and if ctrl is true. - if ((key == 86 && ctrl) || (ctrl)) { - } - else if ((key == 67 && ctrl) || (ctrl)) { - // If key pressed is C and if ctrl is true. - console.log("Ctrl+C is pressed."); - } - else if (e.key!=='Enter' && selectedNode.type.name === 'figure' && !selectedNode.maybeChild(1)) { - return ( - this.editor.chain() - // Go through the image. - .insertContentAt($pos.pos+2,'
') - // .setTextSelection($pos.pos + 1) - .scrollIntoView() - .run() - ); - }else if (e.key!=='Enter' && selectedNode.type.name === 'figure' && selectedNode.maybeChild(1)) { - - this.editor.chain() - // Go through the image. - // .insertContentAt($pos.pos+1,'
') - .setTextSelection($pos.pos + 3) - .scrollIntoView() - .run() - } - } + + let $pos = view.state.doc.resolve( + view.state.selection?.$anchor.pos + ); + + if ($pos?.nodeAfter?.type.name == "figure") { + //if caret in text caption + if ( + $pos.nodeAfter.firstChild?.type?.name == "text" || + $pos.nodeAfter.firstChild == null + ) { + let returnPos = $pos.pos; + for (let d = $pos.depth; d > 0; d--) { + let prevNode = $pos.node(d); + if (prevNode?.type?.name == "figure") { + returnPos = $pos.before(d); + break; + } } - - }, - }, - filterTransaction: (transaction, state) => { - // console.log(transaction) - let result = true; // true for keep, false for stop transaction - if(transaction?.curSelection?.node?.type.name=='image'){ - result = false + + if (e.key == "Enter") { + editor + .chain() + .focus() + .setNodeSelection(returnPos) + // .insertContentAt(pos+1, '

', { + // updateSelection: false, + // parseOptions: { + // preserveWhitespace: 'full', + // } + // }) + .run(); } - if(transaction?.curSelection?.node?.type.name=='video'){ - result = false + } else { + const { $from } = this.editor.state.selection; + const selectedNode = $from.nodeAfter; + + let ev = e; // Event object 'ev' + var key = ev.which || ev.keyCode; // Detecting keyCode + // Detecting Ctrl + var ctrl = ev.ctrlKey + ? ev.ctrlKey + : ev.metaKey + ? ev.metaKey + : key === 17 + ? true + : false; + // If key pressed is V and if ctrl is true. + if ((key == 86 && ctrl) || ctrl) { + } else if ((key == 67 && ctrl) || ctrl) { + // If key pressed is C and if ctrl is true. + console.log("Ctrl+C is pressed."); + } else if ( + e.key !== "Enter" && + selectedNode.type.name === "figure" && + !selectedNode.maybeChild(1) + ) { + return ( + this.editor + .chain() + // Go through the image. + .insertContentAt($pos.pos + 2, "
") + // .setTextSelection($pos.pos + 1) + .scrollIntoView() + .run() + ); + } else if ( + e.key !== "Enter" && + selectedNode.type.name === "figure" && + selectedNode.maybeChild(1) + ) { + this.editor + .chain() + // Go through the image. + // .insertContentAt($pos.pos+1,'
') + .setTextSelection($pos.pos + 3) + .scrollIntoView() + .run(); } - if(transaction?.curSelection?.$anchor?.parent?.type.name=='figcaption'){ - if(transaction?.curSelection?.$anchor?.parentOffset==0){ - if(transaction?.curSelection?.$anchor?.parent.textContent?.length>0){ - result = false - var path = transaction?.curSelection?.$anchor?.path - for (var i = path.length - 1; i >= 0; i--) { - if(path[i]?.type?.name=='figure'){ - let fignode = path[i] - if(fignode.childCount==1){ - result = true - }else if (fignode.childCount==2){ - result = true - } - } - } - } + } + } + }, + }, + filterTransaction: (transaction, state) => { + // console.log(transaction) + let result = true; // true for keep, false for stop transaction + if (transaction?.curSelection?.node?.type.name == "image") { + result = false; + } + if (transaction?.curSelection?.node?.type.name == "video") { + result = false; + } + if ( + transaction?.curSelection?.$anchor?.parent?.type.name == + "figcaption" + ) { + if (transaction?.curSelection?.$anchor?.parentOffset == 0) { + if ( + transaction?.curSelection?.$anchor?.parent.textContent?.length > + 0 + ) { + result = false; + var path = transaction?.curSelection?.$anchor?.path; + for (var i = path.length - 1; i >= 0; i--) { + if (path[i]?.type?.name == "figure") { + let fignode = path[i]; + if (fignode.childCount == 1) { + result = true; + } else if (fignode.childCount == 2) { + result = true; } + } } - // if(transaction?.curSelection?.$anchor?.parent?.type.name=='figcaption'){ - // //check the key pressed - - // if(transaction?.curSelection?.$anchor?.parentOffset==0){ - // if(transaction?.curSelection?.$anchor?.parent.textContent?.length>0){ - // if(transaction?.curSelection?.$anchor?.path?.length){ - // console.log('tr',transaction) - // var path = transaction?.curSelection?.$anchor?.path - // console.log(path) - // for (var i = path.length - 1; i >= 0; i--) { - // if(path[i]?.type?.name=='figure'){ - // let fignode = path[i] - // console.log('insidecount',fignode.childCount) - // childcount=fignode.childCount - // if(fignode.childCount==1){ - // result = false - // } - // } - // } - // } - // } - // } - // console.log('fig',transaction) - // } - return result - }, - // appendTransaction:(transactions, oldState, newState)=>{ - // const tr = newState.tr; - // let modified = false; - - // if (!transactions[0].docChanged) { - // return tr; - // } - - // let oldFigureHadImage = false - // if(oldState?.selection?.$anchor?.path?.length){ - // var path = oldState?.selection?.$anchor?.path - // for (var i = path.length - 1; i >= 0; i--) { - // if(path[i]?.type?.name=='figure'){ - // let fignode = path[i] - // if(fignode.childCount==2){ - // oldFigureHadImage=true - // } - // } - // } - // } - - // let newStateHasImage = false - // if(newState?.selection?.$anchor?.path?.length){ - // var path = newState?.selection?.$anchor?.path - // for (var i = path.length - 1; i >= 0; i--) { - // if(path[i]?.type?.name=='figure'){ - // let fignode = path[i] - // if(fignode.childCount==1){ - // newStateHasImage=false - // } - // } - // } - // } - // if(oldFigureHadImage==true && newStateHasImage == false){ - // console.log('hey stop!') - // return false - // } - - - // } - }), - ] - }, - - - - renderHTML({ HTMLAttributes, node }) { - return ['figure', { style:`width:${node?.attrs?.width}`,class: 'figure', ['data-link']:node?.attrs?.link?node?.attrs?.link:'' }, 0]; - }, - - addCommands() { - return { - setFigure: ({ caption, ...attrs }) => ({ chain }) => { - if(attrs.figureType=='image'){ - const content= [{ type: 'image', attrs }]; - + } + } + } + // if(transaction?.curSelection?.$anchor?.parent?.type.name=='figcaption'){ + // //check the key pressed + + // if(transaction?.curSelection?.$anchor?.parentOffset==0){ + // if(transaction?.curSelection?.$anchor?.parent.textContent?.length>0){ + // if(transaction?.curSelection?.$anchor?.path?.length){ + // console.log('tr',transaction) + // var path = transaction?.curSelection?.$anchor?.path + // console.log(path) + // for (var i = path.length - 1; i >= 0; i--) { + // if(path[i]?.type?.name=='figure'){ + // let fignode = path[i] + // console.log('insidecount',fignode.childCount) + // childcount=fignode.childCount + // if(fignode.childCount==1){ + // result = false + // } + // } + // } + // } + // } + // } + // console.log('fig',transaction) + // } + return result; + }, + // appendTransaction:(transactions, oldState, newState)=>{ + // const tr = newState.tr; + // let modified = false; + + // if (!transactions[0].docChanged) { + // return tr; + // } + + // let oldFigureHadImage = false + // if(oldState?.selection?.$anchor?.path?.length){ + // var path = oldState?.selection?.$anchor?.path + // for (var i = path.length - 1; i >= 0; i--) { + // if(path[i]?.type?.name=='figure'){ + // let fignode = path[i] + // if(fignode.childCount==2){ + // oldFigureHadImage=true + // } + // } + // } + // } + + // let newStateHasImage = false + // if(newState?.selection?.$anchor?.path?.length){ + // var path = newState?.selection?.$anchor?.path + // for (var i = path.length - 1; i >= 0; i--) { + // if(path[i]?.type?.name=='figure'){ + // let fignode = path[i] + // if(fignode.childCount==1){ + // newStateHasImage=false + // } + // } + // } + // } + // if(oldFigureHadImage==true && newStateHasImage == false){ + // console.log('hey stop!') + // return false + // } + + // } + }), + ]; + }, + + renderHTML({ HTMLAttributes, node }) { + return [ + "figure", + { + style: `width:${node?.attrs?.width}`, + width: node?.attrs?.width, + class: "figure", + ["data-link"]: node?.attrs?.link ? node?.attrs?.link : "", + }, + 0, + ]; + }, + + addCommands() { + return { + setFigure: + ({ caption, ...attrs }) => + ({ chain }) => { + if (attrs.figureType == "image") { + const content = [{ type: "image", attrs }]; + // if (caption) { // content.push({ type: 'figcaption', text: caption }); // } - content.push({ type: 'figcaption', text: '' }) - + content.push({ type: "figcaption", text: "" }); + return ( chain() // Delete current empty node. .command(({ commands, state }) => { return !state.selection.$from.parent.textContent - ? commands.keyboardShortcut('Backspace') + ? commands.keyboardShortcut("Backspace") : true; }) .insertContent({ @@ -300,30 +330,30 @@ import { attrs, content, }) - + // set cursor at end of caption field .command(({ tr, commands }) => { const { doc, selection } = tr; const position = doc.resolve(selection.to - 2).end(); - + return commands.setTextSelection(position); }) .run() ); - }else if(attrs.figureType=='video'){ - const content= [{ type: 'video', attrs }]; - + } else if (attrs.figureType == "video") { + const content = [{ type: "video", attrs }]; + // if (caption) { // content.push({ type: 'figcaption', text: caption }); // } - content.push({ type: 'figcaption', text: '' }) - + content.push({ type: "figcaption", text: "" }); + return ( chain() // Delete current empty node. .command(({ commands, state }) => { return !state.selection.$from.parent.textContent - ? commands.keyboardShortcut('Backspace') + ? commands.keyboardShortcut("Backspace") : true; }) .insertContent({ @@ -331,46 +361,48 @@ import { attrs, content, }) - + // set cursor at end of caption field .command(({ tr, commands }) => { const { doc, selection } = tr; const position = doc.resolve(selection.to - 2).end(); - + return commands.setTextSelection(position); }) .run() ); } - }, - - imageToFigure: () => ({ tr, commands }) => { + }, + + imageToFigure: + () => + ({ tr, commands }) => { const { doc, selection } = tr; const { from, to } = selection; const images = findChildrenInRange( doc, { from, to }, - (node) => node.type.name === 'image', + node => node.type.name === "image" ); - + if (!images.length) { return false; } - + const tracker = new Tracker(tr); - + return commands.forEach(images, ({ node, pos }) => { const mapResult = tracker.map(pos); - + if (mapResult.deleted) { return false; } - + const range = { from: mapResult.position, to: mapResult.position + node.nodeSize, }; - + return commands.insertContentAt(range, { type: this.name, attrs: { @@ -379,46 +411,50 @@ import { }); }); }, - - figureToImage: () => ({ tr, commands }) => { + + figureToImage: + () => + ({ tr, commands }) => { const { doc, selection } = tr; const { from, to } = selection; const figures = findChildrenInRange( doc, { from, to }, - (node) => node.type.name === this.name, + node => node.type.name === this.name ); - + if (!figures.length) { return false; } - + const tracker = new Tracker(tr); - + return commands.forEach(figures, ({ node, pos }) => { const mapResult = tracker.map(pos); - + if (mapResult.deleted) { return false; } - + const range = { from: mapResult.position, to: mapResult.position + node.nodeSize, }; - + return commands.insertContentAt(range, { - type: 'image', + type: "image", attrs: { src: node.attrs.src, }, }); }); }, - - moveCursorToCaption: () => ({ state, chain }) => { + + moveCursorToCaption: + () => + ({ state, chain }) => { const { anchor } = state.selection; - + return ( chain() // Go through the image. @@ -427,96 +463,70 @@ import { .run() ); }, - }; - }, - - addInputRules() { - return [ - nodeInputRule({find:inputRegex, type:this.type}, (match) => { - const [, alt, src, title] = match; - - return { src, alt, title }; - }), - ]; - }, - - addKeyboardShortcuts() { - const replaceFigureWithParagraph = () => { - const { $from, from, anchor } = this.editor.state.selection; - const selectedNode = $from.parent; - - if (selectedNode.type.name === 'figure') { - const { tr } = this.editor.state; - - tr.replaceRangeWith( - from - 1, - from + selectedNode.nodeSize - 1, - this.editor.state.schema.nodes.paragraph.create(), - ) - .setSelection(TextSelection.create(tr.doc, anchor)) - .scrollIntoView(); - this.editor.view.dispatch(tr); - - return true; - } - // else if (selectedNode.type.name === 'figcaption'){ - // let $pos = this.editor.view.state.doc.resolve(from-1) - // console.log($pos) - // if($pos?.parent?.type?.name=='figure'){ - // // alert('stop it') - // const { tr } = this.editor.state; - // tr.replaceRangeWith( - // from - 1, - // from + selectedNode.nodeSize - 1, - // this.editor.state.schema.nodes.paragraph.create(), - // ) - // // return false - // } + }; + }, - // } - }; - - const moveCursorToCaption = () => { - const { $from } = this.editor.state.selection; - const selectedNode = $from.parent; - - if (selectedNode.type.name === 'figure' && selectedNode.maybeChild(1)) { - return this.editor.commands.moveCursorToCaption(); - } - }; - - return { - Enter: moveCursorToCaption, - Backspace: replaceFigureWithParagraph, - Delete: replaceFigureWithParagraph, - }; - }, - }); - - export default Figure; - - function appendImgNode(src, wrapper) { - const image = document.createElement('img'); - image.setAttribute('src', sanitizeImg(src)); - wrapper.appendChild(image); - return image; - } - - function sanitizeImg(url) { - return sanitize(url, ['http', 'https', 'data']) ? url : '//:0'; - } - - function sanitize(url, protocols) { - const anchor = document.createElement('a'); - anchor.href = url; - const protocol = anchor.href.slice(0, anchor.href.indexOf(':')); - return protocols.indexOf(protocol) > -1; - } - - const keydownlistener = (e) =>{ - console.log(e) - alert('papa') - - } - - \ No newline at end of file + addInputRules() { + return [ + nodeInputRule({ find: inputRegex, type: this.type }, match => { + const [, alt, src, title] = match; + + return { src, alt, title }; + }), + ]; + }, + + addKeyboardShortcuts() { + const replaceFigureWithParagraph = () => { + const { $from, from, anchor } = this.editor.state.selection; + const selectedNode = $from.parent; + + if (selectedNode.type.name === "figure") { + const { tr } = this.editor.state; + + tr.replaceRangeWith( + from - 1, + from + selectedNode.nodeSize - 1, + this.editor.state.schema.nodes.paragraph.create() + ) + .setSelection(TextSelection.create(tr.doc, anchor)) + .scrollIntoView(); + this.editor.view.dispatch(tr); + + return true; + } + // else if (selectedNode.type.name === 'figcaption'){ + // let $pos = this.editor.view.state.doc.resolve(from-1) + // console.log($pos) + // if($pos?.parent?.type?.name=='figure'){ + // // alert('stop it') + // const { tr } = this.editor.state; + // tr.replaceRangeWith( + // from - 1, + // from + selectedNode.nodeSize - 1, + // this.editor.state.schema.nodes.paragraph.create(), + // ) + // // return false + // } + + // } + }; + + const moveCursorToCaption = () => { + const { $from } = this.editor.state.selection; + const selectedNode = $from.parent; + + if (selectedNode.type.name === "figure" && selectedNode.maybeChild(1)) { + return this.editor.commands.moveCursorToCaption(); + } + }; + + return { + Enter: moveCursorToCaption, + Backspace: replaceFigureWithParagraph, + Delete: replaceFigureWithParagraph, + }; + }, +}); + +export default Figure; diff --git a/components/Editor/CustomExtensions/Figure2/ImageNodeView/ImageNodeView.js b/components/Editor/CustomExtensions/Figure2/ImageNodeView/ImageNodeView.js new file mode 100644 index 00000000..b8c4eff9 --- /dev/null +++ b/components/Editor/CustomExtensions/Figure2/ImageNodeView/ImageNodeView.js @@ -0,0 +1,40 @@ +import { NodeViewWrapper } from "@tiptap/react"; +import { useEffect, useState } from "react"; + +const ImageNodeView = props => { + const [blob, setBlob] = useState(null); +console.log(blob) + useEffect(() => { + if (props.node.attrs.src && !blob) { + fetch(`https://req.prototypr.io/${props.node.attrs.src}`) + .then(response => response.blob()) + .then(blob => { + setBlob(URL.createObjectURL(blob)); + }); + } + }, [props.node.attrs.src]); + + return ( + { + // event.preventDefault(); + // event.stopPropagation(); + // }} + // value="Don't drag me :(" + onClick={() => { + console.log("click"); + let pos = props.getPos(); + console.log(pos); + //set editor selection to pos + props.editor.commands.setNodeSelection(pos - 1); + }} + contentEditable={false} + > + {props.node.attrs.alt} + + ); +}; + +export default ImageNodeView; diff --git a/components/Editor/Menus/Common/WidthRange.js b/components/Editor/Menus/Common/WidthRange.js index ee695f39..26da138f 100644 --- a/components/Editor/Menus/Common/WidthRange.js +++ b/components/Editor/Menus/Common/WidthRange.js @@ -22,9 +22,27 @@ const WidthSlider = ({ editor, showing, figureType }) => { if (figureType === "video") { //the video rerenders on change quite badly,causing the tooltip to disappear //so only update video width on mouseup + editor.commands.updateAttributes("figure", { width: value + "%" }); } else { //if not video, update width as the slider moves + + // let height = null + // //get child of figure + // const image_node = editor.state.selection?.$anchor?.nodeAfter?.content?.content?.length?editor.state.selection?.$anchor?.nodeAfter?.content?.content[0]:null + // console.log(image_node) + // if(image_node?.type?.name=='image'){ + // //get current selection position + // const parentPos = editor.state.selection.$anchor.pos +1 + // var domNode = editor.view.nodeDOM(parentPos) + // console.log(domNode) + // //get intrinsic height of image + // let styles = window.getComputedStyle(domNode) + // let minHeight = styles.height + // //depending on the old percentage (value), the new percentage, and the current compouted height, calculate the new height in % + // height = minHeight + // } + setValue(value); editor.commands.updateAttributes("figure", { width: value + "%" }); } @@ -68,3 +86,17 @@ const WidthSlider = ({ editor, showing, figureType }) => { ); }; export default WidthSlider; + + +export const getImageHeight = ({src})=>{ + return new Promise((resolve, reject) => { + let img = new Image(); + img.src = `${src}`; + img.onload = function() { + resolve(this.height); + } + img.onerror = function() { + reject(new Error('Failed to load image')); + } + }); +} \ No newline at end of file diff --git a/components/Editor/Menus/ImageMenu.jsx b/components/Editor/Menus/ImageMenu.jsx index a64744ad..dcaaf2cc 100644 --- a/components/Editor/Menus/ImageMenu.jsx +++ b/components/Editor/Menus/ImageMenu.jsx @@ -1,54 +1,11 @@ import { BubbleMenu } from "@tiptap/react"; -// import LinkInput from "./MenuButtons/LinkDropdown/LinkButtonRadix"; -// import FontFormatButton from "./MenuButtons/FontFormatDropdown/FontFormatButton"; -// import MergeTagsButton from "./MenuButtons/MergeTags/MergeTagsButton"; import { TextSelection } from "prosemirror-state"; -import { styled } from "@stitches/react"; -import { blackA, slate } from "@radix-ui/colors"; import ImagePopoverButton from "./MenuButtons/ImagePopoverButton/ImagePopoverButton"; -import { posToDOMRect } from "@tiptap/core"; import { useState } from "react"; -import { roundArrow } from "tippy.js"; import "tippy.js/dist/svg-arrow.css"; import "tippy.js/animations/scale-subtle.css"; -const switchBlockQuote = editor => { - // editor.chain().focus().updateAttributes('blockquote',{ class: 'wp-block-quote' }).run(); - - if ( - editor.isActive("blockquote") && - !editor.isActive({ class: "wp-block-quote" }) - ) { - editor - .chain() - .focus() - .updateAttributes("blockquote", { class: "wp-block-quote" }) - .run(); - } else { - editor.chain().focus().toggleBlockquote().run(); - } -}; - -const IconButton = styled("button", { - // all: 'unset', - fontFamily: "inherit", - borderRadius: "6px", - height: 28, - width: 35, - display: "inline-flex", - marginRight: 1, - marginLeft: 1, - alignItems: "center", - justifyContent: "center", - // color: slate.slate6, - // backgroundColor: 'transparent', - boxShadow: `0 2px 10px ${blackA.blackA7}`, - // '&:hover': { backgroundColor: slate.slate11 }, - "&:focus": { boxShadow: `0 0 0 2px black` }, - // '&:active':{background:'white'} -}); - const ImageMenu = ({ editor, isSelecting }) => { if (!editor) { return null; @@ -75,7 +32,7 @@ const ImageMenu = ({ editor, isSelecting }) => { duration: 100, zIndex: "38", animation: "scale-subtle", - placement: "top-start", + placement: "left-start", //use the referenceClientRect to position the bubble menu at start of image (because of slider) // getReferenceClientRect: () => { // const { state, view } = editor; @@ -116,14 +73,14 @@ const ImageMenu = ({ editor, isSelecting }) => { const selection = editor.state.selection; const isTextSelection = selection instanceof TextSelection; - if (!editor.isActive("figure", { figureType: "image" })) { - return false; - } + // if (!editor.isActive("figure", { figureType: "image" })) { + // return false; + // } - if (isTextSelection) { - setShowing(false); - return false; - } + // if (isTextSelection) { + // setShowing(false); + // return false; + // } //update image src const figure_node = selection?.$anchor?.nodeAfter @@ -140,32 +97,17 @@ const ImageMenu = ({ editor, isSelecting }) => { element={document.getElementById("editor-container")} editor={editor} > - {/* bold */}
- {/* */} - {/*
*/} - uploadRef.current.closePopup()} editor={editor} - // node={props.node} - // updateAttributes={props.updateAttributes} /> - {/* editor.chain().focus().toggleBold().run()} - className={` - hover:bg-gray-800 mr-1 - ${editor.isActive("bold")?'bg-gray-800':'bg-gray-900'} - ${editor.isActive("bold")?'text-blue-400':'text-gray-200'}`} - > - - */}
diff --git a/styles/posts-page.scss b/styles/posts-page.scss index a1aa419f..2a4b48a2 100644 --- a/styles/posts-page.scss +++ b/styles/posts-page.scss @@ -694,7 +694,7 @@ figure, pre{ -moz-user-select: none; -webkit-user-select: none; user-select: none; - + width:100%; } a{