Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Editor] - Code block eats up lines if it's added in the beginning of article content #374

Closed
devformatters opened this issue Jul 5, 2021 · 4 comments · Fixed by #382 · May be fixed by #369
Closed

[Editor] - Code block eats up lines if it's added in the beginning of article content #374

devformatters opened this issue Jul 5, 2021 · 4 comments · Fixed by #382 · May be fixed by #369
Assignees
Projects

Comments

@devformatters
Copy link
Contributor

@devformatters devformatters self-assigned this Jul 22, 2021
@devformatters devformatters removed their assignment Aug 17, 2021
@devformatters devformatters changed the title Code block apply all content automatically if it's in the first line Code block eat up lines if it's added in the beginning of article content Sep 24, 2021
@devformatters devformatters changed the title Code block eat up lines if it's added in the beginning of article content Code block eats up lines if it's added in the beginning of article content Sep 24, 2021
@devformatters devformatters changed the title Code block eats up lines if it's added in the beginning of article content [Editor] - Code block eats up lines if it's added in the beginning of article content Sep 24, 2021
@tx0c
Copy link
Contributor

tx0c commented Sep 28, 2021

Should be an initialization problem in the Editor,

  1. On reloading the page, the graphql reading the draft is still showing 2nd paragraph out of the pre block,
    image
fetch("https://server-develop.matters.news/graphql", {
  "headers": {
    "accept": "*/*",
    "accept-language": "en-US,en;q=0.9",
    "content-type": "application/json",
    // ...
  },
  "referrer": "https://web-develop.matters.news/",
  "referrerPolicy": "strict-origin-when-cross-origin",
  body: JSON.stringify({
  operationName: 'DraftDetailQuery',
  variables: { id: 'RHJhZnQ6OTMyMw' },
  extensions: {
    persistedQuery: {
      version: 1,
      sha256Hash: 'b7318ad6e8c00295c68f8a947c08a6384fb8ff0a8bebfe6ae8e00b12fbe800b5'
    }
  },
  query: `
query DraftDetailQuery($id: ID!) {
  viewer {
    id
    ownCircles {
      ...DigestRichCirclePublic
      __typename
    }
    __typename
  }
  node(input: {id: $id}) {
    id
    ... on Draft {
      ...EditorDraft
      ...PublishStateDraft
      ...EditMetaDraft
      __typename
    }
    __typename
  }
}

fragment EditorDraft on Draft {
  id
  title
  publishState
  content
  summary
  summaryCustomized
  __typename
}

fragment PublishStateDraft on Draft {
  id
  publishState
  article {
    id
    title
    slug
    mediaHash
    author {
      id
      userName
      __typename
    }
    __typename
  }
  __typename
}

fragment EditMetaDraft on Draft {
  id
  publishState
  cover
  assets {
    ...Asset
    __typename
  }
  tags
  collection(input: {first: null}) {
    edges {
      node {
        ...ArticleDigestDropdownArticle
        __typename
      }
      __typename
    }
    __typename
  }
  access {
    type
    circle {
      ...DigestRichCirclePublic
      __typename
    }
    __typename
  }
  license
  __typename
}

fragment ArticleDigestDropdownArticle on Article {
  id
  title
  articleState: state
  slug
  mediaHash
  author {
    id
    userName
    ...UserDigestMiniUser
    __typename
  }
  ...ArticleDigestTitleArticle
  __typename
}

fragment UserDigestMiniUser on User {
  id
  userName
  displayName
  status {
    state
    __typename
  }
  ...AvatarUser
  __typename
}

fragment AvatarUser on User {
  avatar
  liker {
    civicLiker
    __typename
  }
  info {
    badges {
      type
      __typename
    }
    __typename
  }
  __typename
}

fragment ArticleDigestTitleArticle on Article {
  id
  title
  articleState: state
  slug
  mediaHash
  author {
    id
    userName
    __typename
  }
  __typename
}

fragment Asset on Asset {
  id
  type
  path
  __typename
}

fragment DigestRichCirclePublic on Circle {
  id
  name
  displayName
  description
  owner {
    ...UserDigestMiniUser
    __typename
  }
  ...AvatarCircle
  ...FooterCirclePublic
  __typename
}

fragment AvatarCircle on Circle {
  avatar
  __typename
}

fragment FooterCirclePublic on Circle {
  id
  ...CountsCircle
  ...PriceCirclePublic
  __typename
}

fragment CountsCircle on Circle {
  id
  members(input: {first: 0}) {
    totalCount
    __typename
  }
  works(input: {first: 0}) {
    totalCount
    __typename
  }
  __typename
}

fragment PriceCirclePublic on Circle {
  id
  name
  prices {
    amount
    currency
    __typename
  }
  __typename
}`
  }),
  // "body": "{\"operationName\":\"DraftDetailQuery\",\"variables\":{\"id\":\"RHJhZnQ6OTMyMw\"},\"extensions\":{\"persistedQuery\":{\"version\":1,\"sha256Hash\":\"b7318ad6e8c00295c68f8a947c08a6384fb8ff0a8bebfe6ae8e00b12fbe800b5\"}},\"query\":\"query DraftDetailQuery($id: ID!) {\\n  viewer {\\n    id\\n    ownCircles {\\n      ...DigestRichCirclePublic\\n      __typename\\n    }\\n    __typename\\n  }\\n  node(input: {id: $id}) {\\n    id\\n    ... on Draft {\\n      ...EditorDraft\\n      ...PublishStateDraft\\n      ...EditMetaDraft\\n      __typename\\n    }\\n    __typename\\n  }\\n}\\n\\nfragment EditorDraft on Draft {\\n  id\\n  title\\n  publishState\\n  content\\n  summary\\n  summaryCustomized\\n  __typename\\n}\\n\\nfragment PublishStateDraft on Draft {\\n  id\\n  publishState\\n  article {\\n    id\\n    title\\n    slug\\n    mediaHash\\n    author {\\n      id\\n      userName\\n      __typename\\n    }\\n    __typename\\n  }\\n  __typename\\n}\\n\\nfragment EditMetaDraft on Draft {\\n  id\\n  publishState\\n  cover\\n  assets {\\n    ...Asset\\n    __typename\\n  }\\n  tags\\n  collection(input: {first: null}) {\\n    edges {\\n      node {\\n        ...ArticleDigestDropdownArticle\\n        __typename\\n      }\\n      __typename\\n    }\\n    __typename\\n  }\\n  access {\\n    type\\n    circle {\\n      ...DigestRichCirclePublic\\n      __typename\\n    }\\n    __typename\\n  }\\n  license\\n  __typename\\n}\\n\\nfragment ArticleDigestDropdownArticle on Article {\\n  id\\n  title\\n  articleState: state\\n  slug\\n  mediaHash\\n  author {\\n    id\\n    userName\\n    ...UserDigestMiniUser\\n    __typename\\n  }\\n  ...ArticleDigestTitleArticle\\n  __typename\\n}\\n\\nfragment UserDigestMiniUser on User {\\n  id\\n  userName\\n  displayName\\n  status {\\n    state\\n    __typename\\n  }\\n  ...AvatarUser\\n  __typename\\n}\\n\\nfragment AvatarUser on User {\\n  avatar\\n  liker {\\n    civicLiker\\n    __typename\\n  }\\n  info {\\n    badges {\\n      type\\n      __typename\\n    }\\n    __typename\\n  }\\n  __typename\\n}\\n\\nfragment ArticleDigestTitleArticle on Article {\\n  id\\n  title\\n  articleState: state\\n  slug\\n  mediaHash\\n  author {\\n    id\\n    userName\\n    __typename\\n  }\\n  __typename\\n}\\n\\nfragment Asset on Asset {\\n  id\\n  type\\n  path\\n  __typename\\n}\\n\\nfragment DigestRichCirclePublic on Circle {\\n  id\\n  name\\n  displayName\\n  description\\n  owner {\\n    ...UserDigestMiniUser\\n    __typename\\n  }\\n  ...AvatarCircle\\n  ...FooterCirclePublic\\n  __typename\\n}\\n\\nfragment AvatarCircle on Circle {\\n  avatar\\n  __typename\\n}\\n\\nfragment FooterCirclePublic on Circle {\\n  id\\n  ...CountsCircle\\n  ...PriceCirclePublic\\n  __typename\\n}\\n\\nfragment CountsCircle on Circle {\\n  id\\n  members(input: {first: 0}) {\\n    totalCount\\n    __typename\\n  }\\n  works(input: {first: 0}) {\\n    totalCount\\n    __typename\\n  }\\n  __typename\\n}\\n\\nfragment PriceCirclePublic on Circle {\\n  id\\n  name\\n  prices {\\n    amount\\n    currency\\n    __typename\\n  }\\n  __typename\\n}\\n\"}",
  "method": "POST",
  "mode": "cors",
  "credentials": "include"
});
  1. After Editor initialization, it is showing the 2nd paragraph inside the pre block
    image

  2. At the moment if click the Editor to start, have the mouse editing cursor, then it automatically calls putDraft to save, with the 2nd paragraph inside the pre block
    image

BTW, if use all English in 1st & 2nd paragraph it seems not reproducing;

@tx0c
Copy link
Contributor

tx0c commented Sep 28, 2021

reproduced in the local demo, with same content <pre class="ql-syntax">first line\n第一段第一段第一段第一段第一段第一段第一段第一段第一段第一段\n</pre><p>2nd 第二段第二段第二段第二段第二段第二段第二段第二段第二段第二段second-line2</p><p>第三段第三段第三段第三段第三段第三段第三段第三段第三段第三段</p>, reproduced in the MattersArticleEditor but not ReactQuill

image

tx0c referenced this issue in thematters/matters-server Sep 30, 2021
part of reason for thematters/matters-web#2114 is server not saving exactly same pre code-block, as

    <pre class="ql-syntax" spellcheck="false">Pre1\n</pre><p>next paragraph...

server side is always dropping the `spellcheck="false"`, then next time when editor is loading
the pre code-block incomplete, it triggers `clipboard.convert` to parse again, and in MattersArticleEditor
the `mentionContainer` reference is causing ReactQuill to re-initialize twice every time, caused
converting between `HTML <=> Delta` happening 6 or even more times, and eventually caused wrong parsing
@tx0c
Copy link
Contributor

tx0c commented Oct 1, 2021

the minimum reproducible content is like this:

'<pre>Pre1\n</pre><p>Para2</p><p>Para3</p><p>Para4<p><p>Para5<p><p>Para6<p>'

turning into
image

in other words: all paragraphs except the last one are eaten up into the pre block

the root cause is at https://github.com/quilljs/quill/blame/1.3.7/modules/clipboard.js#L80-L85 because quill editor initialization code is calling same clipboard.convert which detects if current savedRange is a pre code-block, then read from its .innerText only dropping all .innerHTML and early return


thematters/matters-server#2285 only fixed part of the problem: if re-initialize the editor with the complete attributes, the preferred HTML from editor.getHTML()

'<pre class="ql-syntax" spellcheck="false">Pre1\n</pre><p>para2</p><p>para3</p>...'

then for some reason, the getFormat in https://github.com/quilljs/quill/blame/1.3.7/modules/clipboard.js#L80-L85 got an empty {} formats and does not early return;

tx0c referenced this issue in thematters/matters-server Oct 1, 2021
part of reason for thematters/matters-web#2114 is server not saving exactly same pre code-block, as

    <pre class="ql-syntax" spellcheck="false">Pre1\n</pre><p>next paragraph...

server side is always dropping the `spellcheck="false"`, then next time when editor is loading
the pre code-block incomplete, it triggers `clipboard.convert` to parse again, and in MattersArticleEditor
the `mentionContainer` reference is causing ReactQuill to re-initialize twice every time, caused
converting between `HTML <=> Delta` happening 6 or even more times, and eventually caused wrong parsing
@tx0c
Copy link
Contributor

tx0c commented Oct 4, 2021

a minimum reproducing with just the Quilt editor's default QuickStart code https://quilljs.com/docs/quickstart/

the root cause why it reproduced in MattersEditor not ReactQuill is MattersEditor always calling initializing twice (because of mention reference change after DOM mount); calling quill.setContents twice caused Quill is treating 2nd time as pasting into a pre code-block, and treating all content from .innerText only, and losing all html format

> quill.setContents( { ops:[] } )             // set with an empty Delta
Delta {ops: Array(1)}
> quill.setContents(quill.clipboard.convert('<pre>pre1</pre><p>p2</p><p>p3</p><p>p4 <b>bold</b> <a href="/link/to">link</a></p>')); quill.root.innerHTML
'<pre class="ql-syntax" spellcheck="false">pre1\n</pre><p>p2</p><p>p3</p><p>p4 <strong>bold</strong> <a href="/link/to" rel="noopener noreferrer" target="_blank">link</a></p>'
> quill.setContents(quill.clipboard.convert('<pre>pre1</pre><p>p2</p><p>p3</p><p>p4 <b>bold</b> <a href="/link/to">link</a></p>')); quill.root.innerHTML
'<pre class="ql-syntax" spellcheck="false">pre1\n\np2\n\np3\n\n</pre><p>p4 bold link</p>'

image

@guoliu guoliu transferred this issue from thematters/matters-web Oct 7, 2021
@guoliu guoliu linked a pull request Oct 7, 2021 that will close this issue
tx0c added a commit that referenced this issue Oct 12, 2021
should the ultimate fix #374 Code block eats up lines if it's added in the beginning of article content 5 pt bug

have tried many ways to remove this empty line after end of initialization, but does not work or have other complications
would be better to leave it, user can always delete this empty line before publishing

current sympton of #374 is losing all rich text formatting, all paragraphs (except the last one) are losing format;

bottom line is not to lose all rich text formatting
@devformatters devformatters moved this from In progress to Review in progress in 🚀 Dev Oct 13, 2021
@tx0c tx0c closed this as completed in 36b36ee Oct 13, 2021
🚀 Dev automation moved this from Review in progress to Done Oct 13, 2021
@tx0c tx0c mentioned this issue Oct 13, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
No open projects
3 participants