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

KaTeX Integration #179

Closed
wngu6 opened this issue Jan 27, 2019 · 13 comments
Closed

KaTeX Integration #179

wngu6 opened this issue Jan 27, 2019 · 13 comments
Labels
Type: Feature The issue or pullrequest is a new feature

Comments

@wngu6
Copy link

wngu6 commented Jan 27, 2019

It would be great if there was an extension that uses KaTeX, sort of like Dropbox Paper but better.
There should be one for inline mode and another for display mode. When editing maths, especially for display mode, it would be great if it allows multiple lines.

This is my attempt in display math mode.

import { Node } from "tiptap"
import { toggleBlockType, setBlockType, textblockTypeInputRule } from "tiptap-commands"
import katex from "katex"

export default class DisplayMath extends Node {

  get name() {
    return "displaymath"
  }

  get schema() {
    return {
      attrs: {
        content: {
          default: ""
        }
      },
      content: "text*",
      marks: "",
      group: "block",
      defining: true,
      draggable: false,
      parseDOM: [
        {
          tag: "displaymath",
          getAttrs: dom => ({
            content: dom.getAttribute("content")
          })
        }
      ],
      toDOM: node => [
        "displaymath", { content: node.attrs.content }, ["div"], ["textarea", 0]
      ]
    }
  }

  get view() {
    return {
      props: ["node", "updateAttrs", "editable"],
      data: function () {
        return {
          edit: true
        }
      },
      watch: {
        content: function (newContent, oldContent) {
          katex.render(this.content, this.$refs.disp, {
            throwOnError: false
          })
        }
      },
      computed: {
        content: {
          get() {
            return this.node.attrs.content
          },
          set(content) {
            this.updateAttrs({
              content
            })
          }
        }
      },
      mounted() {
        katex.render(this.content, this.$refs.disp, {
          throwOnError: false
        })
      },
      methods: {
        change() {
          this.edit = true;
        },
        update() {
          this.edit = false;
        }
      },
      template: `
      <div>
        <div ref="disp" @click="change"></div>
        <textarea v-if="edit" class="katex-input" v-model="content" @focusout="update"></textarea>
      </div>
      `
    }
  }

  inputRules({ type }) {
    return [
      textblockTypeInputRule(/^\$\$\$$/, type)
    ]
  }

}

I modeled it after Iframe.js.

@philippkuehn philippkuehn added the Type: Feature The issue or pullrequest is a new feature label Jan 29, 2019
@philippkuehn
Copy link
Contributor

Maybe you could see how it's implemented here. Since I don't want to implement it, I will close the ticket.

@ninest
Copy link

ninest commented Aug 26, 2019

@wngu6 Were you able to figure out how to do this?

@BrianHung
Copy link
Contributor

BrianHung commented Nov 23, 2019

@wngu6 @themindstorm

I've implemented a working prototype for inline math. You may have to add additional css to get it working as depicted here.

https://gist.github.com/BrianHung/b72126c98fa08cb1c09170b1394771a0

Edit

I've also implemented a working prototype for mathblocks. You'd have to figure out how to get the arrow_handler to work properly but mostly seems functional.

https://gist.github.com/BrianHung/60efde8536f3fa76334f759c33a741e5

@mvind
Copy link

mvind commented May 30, 2020

@BrianHung can you explain how to use the katex inline extension?
I've tried to use just like an regular extensions, but it does not render and I get the following error:
VM241 app.js:125340 [Vue warn]: Avoid mutating a prop directly since the value will be overwritten whenever the parent component re-renders. Instead, use a data or computed property based on the prop's value. Prop being mutated: "selected"

@BrianHung
Copy link
Contributor

BrianHung commented May 30, 2020

@mvind @ninest I updated the math and mathblock node gists. To use them, just import and use in your editor like any other nodes.

@ramsane
Copy link

ramsane commented Aug 31, 2020

@BrianHung Thanks for the gist. But when I try to render by typing $a$, when I type the last $, it is giving the error.

Cannot set property 'textContent' of undefined

This is what I've done.
image
I kept all the files in the same directory. And then, importing it. import Math from '@/utils/editor/Math.js' and then adding new Math() to the extensions array when initializing the editor.

I think that's enough.

Is there anything else that I've missed ?

Update:
After some debugging, I found the root cause, but I don't know the solution. katex was not able to render it properly.
image

this.$refs.render came undefined. Because this.$refs is giving empty object instead of reference to the span. Is there any additional step that I have to do ?

Is there any code sandbox where it is implemented, I can compare these two and that might fix the error.

@hanspagel hanspagel mentioned this issue Sep 1, 2020
6 tasks
@ramsane
Copy link

ramsane commented Sep 1, 2020

I got the solution. We need to add this to the nuxt confit( if you are using nuxt) so that it renders at pre compilation stage. Same is requred for youtube embeds too.

  build: {
    extend(config) {
      config.resolve.alias.vue = 'vue/dist/vue.common'
    },
  },

One request
image

It won't render when the parent element is active. It should render immediately when the cursor leaves the math node. And get back to edit mode when the cursor moves between $ symbol.

I've tried but couldn't figure it out. All I know is to change the logic here to make it false when the cursor leaves the node.
image

Can someone help me with this logic. With this, I think inline math functionality would be usable.

@BrianHung
Copy link
Contributor

Detecting whether a cursor leaves or enter an inline node is harder than detecting whether it leaves a block-level node like a paragraph. See https://discuss.prosemirror.net/t/prosemirror-math-at-desmos/707/8. I would recommend getting comfortable with ProseMirror's plugin system first: https://prosemirror.net/docs/ref/#state.Plugin_System.

@ramsane
Copy link

ramsane commented Sep 2, 2020

pheww.... I figured it out. finally.

parentHasSelection() {
  .....
  // decides whether the anchor is between the Math node or not
  const hasAnchor = this.getPos() < anchor && anchor < this.getPos() + this.node.nodeSize
  ...
  ...
  // some other cases where it is necessary like when the editor is out of focus OR displaying in non-editable mode.
  // I removed the selection as it doesn't change anything when I paste the math. It is adding extra $ at both ends. Don't know 
  // why.
  return hasAnchor && this.view.focused && this.view.editable

@BrianHung if possible, could you please update the gist with this logic with some changes if required. And if you have time, please add comments so that we understand what is going on. It saves lot of time.

@ramsane
Copy link

ramsane commented Sep 3, 2020

And, for mathblock.js too, we need to change few things Otherwise it won't work properly.

...
      computed: {
        visibleClass() {
          return this.hasProseMirrorSelection() ? "active" : "hidden"
        },
      },
...

And this

 hasProseMirrorSelection() {
          let anchor = this.view.state.selection.anchor
          const hasAnchor = this.getPos() <= anchor && anchor < this.node.nodeSize + this.getPos()
          return hasAnchor && this.view.focused && this.view.editable
  },

Hope these are updated in the gist so that others won't face this issue.

@Zogsha
Copy link

Zogsha commented Jan 26, 2021

@ramsane @BrianHung hello. I'm no expert but I managed to use different extension except this one. Could you provide a sandbox or a working exemple ? I can't figure why it doesnt work for me. I'd love to be able to add maths to a project.

@AdminScientificHub
Copy link

Hi, did anyone know an alternative when you work in React ? Didn't find any so far 😔

@MuhamadSelim
Copy link

Hi, did anyone know an alternative when you work in React ? Didn't find any so far 😔

@AdminScientificHub
Check this
https://github.com/fantasticit/think/blob/main/packages/client/src/tiptap/core/wrappers/katex/index.tsx

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Type: Feature The issue or pullrequest is a new feature
Projects
None yet
Development

No branches or pull requests

9 participants