Where communities thrive


  • Join over 1.5M+ people
  • Join over 100K+ communities
  • Free without limits
  • Create your own community
People
Repo info
Activity
  • Feb 24 03:19
    herbertpimentel commented #926
  • Feb 23 07:32
    marijnh closed #1133
  • Feb 23 03:54
    A1vinSmith commented #396
  • Feb 22 21:33
    yyjhao commented #1133
  • Feb 22 16:39
    marijnh commented #1133
  • Feb 22 16:03
    marijnh commented #1116
  • Feb 22 16:02
    marijnh closed #1116
  • Feb 22 15:54
    marijnh commented #1122
  • Feb 22 15:43
    marijnh commented #1134
  • Feb 22 11:00
    marijnh commented #1136
  • Feb 22 11:00
    marijnh closed #1136
  • Feb 22 08:39
    carlobeltrame opened #1136
  • Feb 20 20:42
    orange030 opened #1135
  • Feb 19 23:19
    kylecho commented #466
  • Feb 18 13:46
    Violeta-Amza opened #1134
  • Feb 17 22:56
    yyjhao opened #1133
  • Feb 17 19:49
    buddh4 commented #1043
  • Feb 17 19:40
    buddh4 commented #1043
  • Feb 17 19:39
    buddh4 commented #1043
  • Feb 17 19:05
    buddh4 commented #565
Zeljko Bulatovic
@zeljko-bulatovic
Also, one more question. Can i somehow change the fonts that are used for writting in the editor?
Zeljko Bulatovic
@zeljko-bulatovic

Hey guys, me again :) I have issue with syncing doc using collaboration module. I am building VueJS app and i am using tiptap library. Within their example, in order to make collaboration working, it should be called this:
socket.on('update', data => this.editor.extensions.options.collaboration.update(data))

But when i update doc from another window, in the first window i am receiving update event with newer version, but nothing happen, and doc remains out of sync. I read the whole discussion here:
https://discuss.prosemirror.net/t/how-to-handle-edge-case-with-collab-module/288/22

But i didn't conclude what am i doing wrong.. Any help?

BrianHung
@BrianHung

Is there a proper way to use prosemirror-commands within an InputRule, or are we supposed to compose transactions from scratch using prosemirror-transforms?

I'm trying to modify the original input rules for lists, so that I can not only toggle lists within paragraphs, but within other lists too.
For example, if we're in a bullet list, and 1. is typed, I would want to convert that first bullet list item into an ordered list.

My current approach is to use the commands given in schema list basic: use the liftListItem followed by a wrapInList.
However, I'm noticing that commands require the current state as input: updating the state results in a mismatched transaction, while not updating it between commands results in overwrites.

 // most of this is skeleton code of wrappingInputRule
      new InputRule(/^([-+*])\s$/, (state, match, start, end) => {
        let tr = state.tr.delete(start, end)
        let $start = tr.doc.resolve(start), range = $start.blockRange();
        let parentType = range.parent.type;
        if (parentType.name.includes("item")) {
          state = state.apply(tr); // mismatched transaction
          if (!sinkListItem(nodeType)(state, newTr => {tr = newTr})) return null
          $start = tr.doc.resolve(start), range = $start.blockRange();
        }
        let wrapping = range && findWrapping(range, nodeType, {})
        if (!wrapping) return null
        tr.wrap(range, wrapping)
        let before = tr.doc.resolve(start - 1).nodeBefore
        if (before && before.type == nodeType && canJoin(tr.doc, start - 1))
          tr.join(start - 1)
        return tr
      }),
BrianHung
@BrianHung
After diving into what causes a mismatched transaction, I realized 1. you can't use state.apply(tr)because there's no dispatch function to update the state in an inputrule 2. all new transforms after the initial one have to work off the previous tr's doc. So I had to hack liftListItem and wrapInList a bit to get a working list conversion inputrule: https://gist.github.com/BrianHung/0159c278885cd975a6a8a690e18df0a4.
The second realization proved a bit difficult, because it was hard to visualize the document during each new transform.
Pieter van de Bruggen
@pvande
I've got a pair of issues with inline nodes that I'd love to get some eyes on — one looks like a missed opportunity for gapcursor, and the other looks like ProseMirror might be mishandling a Chrome bug… Demos here: https://eastern-zircon-algebra.glitch.me/
ithil
@ithil

I'm trying to implement a function to make ParseMirror select the next double quote in the document to the right of the cursor. So far I have the following:

    moveToQuote() {
      var {size} = this.editor.view.state.doc.content
      var from = this.editor.selection.from
      var to = this.editor.selection.to
      var before = this.editor.state.doc.textBetween(0, from, '\n', ' ')
      var after = this.editor.state.doc.textBetween(to, size, '\n', ' ')
      var myIndex = after.indexOf('"')
      this.editor.setSelection(to+myIndex, to+myIndex+1)
    }

And this works well if the double quote is on the same line as the cursor. However, if there is one or more new line between the cursor and the match then the index will be off by one or more characters.
Basically, there seem to be hidden elements that influence the position but don't get returned with .textBetween() (and they don't seem to be non-text leaf nodes either, because those should be converted into whitespaces in this example).
So my question is basically: is there anyway to do an .indexOf() in ParseMirror to get the correct pos to use in .setSelection()?

Marijn Haverbeke
@marijnh
Run over the tree with nodesBetween and it'll pass you the offset of the node you're looking at. You can then scan text nodes' content and add the offset of any matches to the node's offset.
Pieter van de Bruggen
@pvande

I've got a pair of issues with inline nodes that I'd love to get some eyes on — one looks like a missed opportunity for gapcursor, and the other looks like ProseMirror might be mishandling a Chrome bug… Demos here: https://eastern-zircon-algebra.glitch.me/

@marijnh Any chance you could help me understand what's going on here?

ithil
@ithil

Run over the tree with nodesBetween and it'll pass you the offset of the node you're looking at. You can then scan text nodes' content and add the offset of any matches to the node's offset.

Nice, thank you! :) For anyone interested this is what I ended up doing:

moveToQuote() {
      var $editor = this.editor
      var {size} = $editor.view.state.doc.content
      var from = $editor.selection.from
      var to = $editor.selection.to
      var $succeeded = false
      $editor.state.doc.nodesBetween(to, size, (node, pos, parent, index) => {
        if (!$succeeded) {
          var text = node.text
          if (text) {
            var myIndex = text.indexOf('"', to-pos)
          }
          if (myIndex > -1) {
            $editor.setSelection(pos+myIndex, pos+myIndex+1)
            $succeeded = true
            return false
          }
        }
      })
    },

Because nodesBetween fires for every note in the range I needed to add the control variable $succeeded so it doesn't move the cursor again once it has found a match.

Marijn Haverbeke
@marijnh
@pvande For things like that, focused issues on the bug tracker are probably a better way to communicate. On first glance, gap cursors work on the block level, and I don't really see how they would make sense between inline nodes.
Pieter van de Bruggen
@pvande
@marijnh Sure thing; I just wanted to get a sense of whether I was doing something stupid in my examples, or whether this was worth bringing up on the bug tracker. I'm happy to migrate the discussion.
Andrew Milich
@amilich
any simple way to convert my entire document to just plain text?
Marijn Haverbeke
@marijnh
@amilich There's no obvious way to do that, since many constructs don't have a clear plain-text representation. You can just get the text out with textBetween, but that'll obviously drop markup. Or use the markdown serializer from the prosemirror-markdown module (assuming you are also using that schema)
Anton Kireev
@AGKireev
Hi everyone. @marijnh Marijn, if I may, I would like to ask people here: if someone is interested in paid work on tasks related to the ProseMirror editor, please PM me.
ken-yxy
@ken-yxy

@BrianHung how to address "all new transforms after the initial one have to work off the previous tr's doc"?
I have similar issue where I tried to upload an image with URL.createObjectURL(f) as placeholder, then I replace
it with the uploaded image url:

const attrs = { src: URL.createObjectURL(imageFile), className: "uploading_" + new Date().getTime() }
// placeholder before actually uploaded
dispatch(state.tr.replaceSelectionWith(nodeType.createAndFill(attrs)))
view.focus()
// simulate uploading
setTimeout(() => {
    const node = $("." + attrs.className)
    const pos = view.posAtDOM(node)
    // replace with the uploaded image url
    dispatch(state.tr.replaceWith(pos, pos, nodeType.create({ src: "https://avatars-03.gitter.im/group/iv/6/57542d82c43b8c601977d702?s=48" })))
}, 2000)

the second dispatch will throw Uncaught RangeError: Applying a mismatched transaction error. but if I comment out the first dispatch, then the second dispatch will work perfectly.

Marijn Haverbeke
@marijnh
You'll have to get the new state, after the initial transaction, and start the second transaction from that.
ken-yxy
@ken-yxy

Thank Marijn very much! I got the idea.
then I look for the way to get the new state after the initial transaction, I saw let newState = state.apply(tr), then I tried to change the code a little as:

let newState = state.apply(state.tr)
dispatch(newState.tr.replaceWith(pos, pos, nodeType.create({ src: "https://avatars-03.gitter.im/group/iv/6/57542d82c43b8c601977d702?s=48" })))

can you guide me further on this?

Marijn Haverbeke
@marijnh
The easiest way is to keep a reference to the view and access view.state.
ken-yxy
@ken-yxy
Thank you, Marijn! it works perfect now.
Andrew Milich
@amilich
Hello! I've got a few draggable nodes, and the built-in behavior works great. Any suggestions on how to add a drag handle to nodes that are draggable? I could add one to a node's toDom but I fee like there should be a better way
Andrew Milich
@amilich
Trying adding a plugin - any way to get the node under the mouse?
Eric Reyes
@Juxsta
Hi all. Would anyone be able to tell me if it’s possible to implement a google-docs like collaboration experience with prose mirror? I saw the collab example however, I’m not sure if its possible to let others know who is typing and where their cursors are
Attila Gazso
@agazso
@Juxsta you can make a plugin that implements appendTransaction, newState.selection returns the cursor (or selection) position
Anton Kireev
@AGKireev
list.png
Anton Kireev
@AGKireev
Hello everyone. I'm working with a todo-lists in ProseMirror, and trying to solve the following quest: how not focus the Editor after applying a transaction (changing the attribute of a list item to "done"). On a mobile when I hit the checkbox the keyboard is shown on screen every time ('cause the Editor gets the focus). Appreciate any hint how to solve it.
Marijn Haverbeke
@marijnh
If you handle and preventDefault the mousedown event, the editor shouldn't be receiving focus
Zeljko Bulatovic
@zeljko-bulatovic
Hi all... i started experiencing RangeError: Position X out of range on ClientA since he has wifi issues, and in the meantime ClientB edits the doc.. Then when ClientA sends the data, his version is for example 410, and on the server it is stored version 400... Then this part of code throws exception

`
let doc = schema.nodeFromJSON(storedData.doc);
let newSteps = steps.map(step => {
const newStep = Step.fromJSON(schema, step);
newStep.clientID = clientID;

// apply step to document
let result = newStep.apply(doc);
doc = result.doc;
return newStep;
});
`

Sometimes result.doc is null
Sebastian Podgajny
@SebastianPodgajny
Hi, is it expected that Fragment doesn't have 'textBetween' method documented?
Zeljko Bulatovic
@zeljko-bulatovic
Also, any server side examples regarding collaboration? Is using Firestore good option when comes to collaboration? I started occurring issues with websockets, poor network connection and synchronization between..
Marijn Haverbeke
@marijnh
@zeljko-bulatovic The collaborative demo on the website might be useful example https://github.com/ProseMirror/website/tree/master/src/collab . I know some people are using Firebase to store steps and it seems to work well for them, but I don't know these products well enough to comment on that myself.
@SebastianPodgajny I think the reasoning was that client code will typically have a node when it needs textBetween. Are you running into a situation where you only have the fragment?
Sebastian Podgajny
@SebastianPodgajny
@marijnh I would like to use default implementation of clipboardTextSerializer but with single \n as block separator
https://github.com/ProseMirror/prosemirror-view/blob/d01c420d9c087f7ba56fc4db2081823ff491dc9d/src/clipboard.js#L30-L31
Marijn Haverbeke
@marijnh
All right, I'll document it and make it public in the next release. Feel free to rely on it. (TS types are likely to lag behind until you create a PR there.)
Zeljko Bulatovic
@zeljko-bulatovic
Thank you very much, i will check!
Sebastian Podgajny
@SebastianPodgajny
Awesome, thanks!
Zeljko Bulatovic
@zeljko-bulatovic

Hi @marijnh , i checked the collab demo from the ProseMirror docs, and i got similar situation like i had right now.. The use case is that two clients are working on the same doc, and then server is down during deploy, or clients got network issues, but they are not aware of it and they continue to type, but as soon as server is up or they come online, multiple new steps are sent, i am getting the following error (this is error from ProseMirror collab server)

Error: Invalid version 91
at Instance.checkVersion (/website/src/collab/server/instance.js:73:17)
at Instance.getEvents (/website/src/collab/server/instance.js:83:10)
at handle (/website/src/collab/server/server.js:140:19)
at finish (/website/src/collab/server/server.js:53:34)
at Object.router.add.args [as handler] (/website/src/collab/server/server.js:67:7)
at routes.some.route (/website/src/collab/server/route.js:47:13)
at Array.some (<anonymous>)
at Router.resolve (/website/src/collab/server/route.js:42:24)
at exports.handleCollabRequest (/website/src/collab/server/server.js:10:17)
at maybeCollab (/website/src/devserver.js:59:9)

Any suggestion how to handle multiple steps with higher version (db has version 10, and client is sending version 15 for example)
Marijn Haverbeke
@marijnh
Clients only roll forward their version when the server has confirmed that it's received the changes, so the scenario you describe shouldn't happen unless the server lost data on restart.
Zeljko Bulatovic
@zeljko-bulatovic
Bigger issue is because some clients has poor wifi connection, and while websockets reconnect and everything is synced, their local version is higher than server version and then i am receiving this error when they send all steps at once
Marijn Haverbeke
@marijnh
No, something else is going wrong, because, as I said, a proper client implementation does not increase its version until it receives the steps it submitted back from the server, to avoid exactly this problem.
Cris Ward
@crisward
Hey all, I'm trying to make the html in my prosemirror editable using codemirror. I have this working, but because I update the whole state on every key press I loose the prosemirror undo stack. I realise I probably need to do a state transform but have no idea where to start with this (eg identify the correct node, change etc). Is there anything in code/prosemirror I can use to map a change in one into a transform into the other?
Cris Ward
@crisward
Ended up doing this, which gives me my undos. Probably not ideal as I'm still replacing the whole doc, but seems performant enough for now.
function updateHTML(view,html){
    let domNode = document.createElement("div");
    domNode.innerHTML = html;
    let tr = view.state.tr;
    let node = DOMParser.fromSchema(schema).parse(domNode);
    tr.setSelection(new AllSelection(view.state.doc));
    tr.replaceSelectionWith(node);
    view.dispatch(tr);
}
Marijn Haverbeke
@marijnh
The example of CodeMirror integration on the website converts code changes to precise ProseMirror transactions. Does that help?
Cris Ward
@crisward
@marijnh thanks for link. I'll take another look. I didn't realise it update the prosemirror state.
Cris Ward
@crisward
It looks like the example updates plain text into a single node. So not exactly what I'm after. But thanks for the feedback. Prosemirror is an excellent library BTW, having fought with contenteditable in the past and working with other less stable abstractions over that it's a pleasure to use. Many thanks for all the work you've put into it.
Zeljko Bulatovic
@zeljko-bulatovic
Hmm, i will take a look, thank you!