Click To Edit

:information_source: Summary Clicking in the textarea in the composer will select the corresponding line in the preview pane, and vice versa.
:hammer_and_wrench: Repository Link https://github.com/thijsbrilleman/discourse-click-to-edit
:open_book: Install Guide How to install plugins in Discourse

click-to-edit - 1080WebShareName-2

Features

Clicking in the textarea in the composer will select the corresponding line in the preview pane, and vice versa.

25 Likes

Very nice addition to the core editing of Discourse. Thank you for creating it.

5 Likes

Seems like something that should be pr welcome, though I have no say in that.

6 Likes

Hello :wave: Thanks, this is really cool :tada: I am just thinking that it would be awesome to make it as a theme component. :slightly_smiling_face:

7 Likes

It doesn’t work too well on iPad, because it is choosing whole text when writing. It looks very odd.

3 Likes

Thanks, and I agree. Will look into it as soon as I have time. You’d always be welcome to file a pull request.

This currently is intended behavior, but I am of course open to better ideas. What sort of visual queue would you recommend?

2 Likes

It would show as pasted text when something is really selected. Then there would be action and response.

Curious, why is this a plugin vs theme component? All this tokens can be generated client side no?

Nice job btw, love that you are leaning on line numbers injected by the markdown engine.

4 Likes

Thank you Sam.

As you might have noticed, the data-ln attributes are present in the cooked html generated and stored on the server as well.

I implemented this behavior, so that later on I could extend the plugin to allow reliable insertion/editing of fragments from the topic view page, equivalent to the edit-button shown below (but a bit more robust):

The image is a screenshot of a web browser showing a quote soaking window with options to edit, copy, and quote.  (Captioned by AI)

It’s been a year since I wrote it, but if I remember correctly, to that end in plugin.rb the line

register_asset "vendor/javascripts/markdown-it-line-numbers.js", :vendored_pretty_text

is required to make sure the MarkdownIt extension also runs server-side when cooking the html.

I have not found the time required to implement the extended edit feature though, so if that requirement is dropped it could be converted to a component I guess.

5 Likes

@sam I’m looking into converting it into a theme component, but I’m unable to figure out how to get this code executed in the context of a markdownit plugin:

// javascripts/lib/discourse-markdown/initialize_markdownit_plugin.js:

export function setup(helper) {
    helper.registerPlugin(markdownitLineNumbers); // markdownitLineNumbers already available
}

I have the suspicion that the line in the plugin I wrote earlier sprinkles some client-side magic as well:

# plugin.rb

register_asset "vendor/javascripts/markdown-it-line-numbers.js", :vendored_pretty_text`

Do you have any clue?

Not sure, will ping the team.

2 Likes

I believe this is because it is currently restricted to plugins scope only. It would work without that check. (This code has been introduced in this commit)

I wanted to integrate line-number for another component, but I did not want to make a plugin, so I gave up on it. It would be super cool if markdown features could be supported in theme components!

On a side note, a great feature that you proposed here – very nice. :+1: :rocket:

4 Likes

Ah yes, this clears it up.

Looking at this code, it might be possible to manually inject the markdown plugin from the theme component at run-time, but this would be pretty hacky. I’ll await the verdict from the core team before trying to implement it.

4 Likes

Our markdown pipeline runs both on the client (for preview), and on the server (to pre-render the HTML for posts). So that’s why it’s designed for plugins only - they’re the only ones which can inject code on the server-side.

Now… this case is quite unusual, since the extension is only needed in the composer, and not on the server. So doing it from a theme component should be feasible.

Did you have a particular strategy in mind for this?

5 Likes

This seems like something that would have wide appeal. It can be hard to find your place in a long post. Might it be pr-welcome ?

5 Likes

Override this function in the original codebase:

// discourse/app/assets/javascripts/discourse/app/components/d-editor.js
async cachedCookAsync(text, options) {
  this._cachedCookFunction ||= await generateCookFunction(options || {});
  return await this._cachedCookFunction(text);
}

with a theme component initializer:

export default {
  name: "d-editor-cached-cook-async-override",
  initialize() {
    const dEditor = require("discourse/components/d-editor").default;
    dEditor.reopen({
      cachedCookAsync(text, options) {
        // duplicate code here to return an altered cook function
      },
    });
  },
};

It would mean quite a bit of code duplication, if it’d work at all. Dirty, dirty.

4 Likes

Hmm yeah, agreed - definitely not ideal. Duplicating the code might not even be possible, because the markdown-it modules are loaded asynchronously, and aren’t part of the amd module system which themes/plugins have direct access to. :thinking:

Building a system to allow themes to contribute client-side-only md transformations could be cool, although the use-cases are fairly limited. In 99% of cases, people want md transforms to apply server-side as well.

So I think, for now, sticking with a plugin is probably the best approach.

5 Likes

I wonder if this kind of decoration should be applied regardless though?

Eg:

<p data-source-line="0">.....</p>

The extra data attribute will assist a lot of internal implementations we have, like, for example, not showing autocomplete when you are inside a code block. Also quoting and quick edit become much easier.

The trivial implementation carries almost no extra weight, but allows us to delete a pile of source code.

7 Likes

We had this in the past (behind a flag), but it was removed in this commit. I found this screenshot from some internal discussions about that feature:

i.e. the perf issue was with the scroll syncing code, not the injection of the line-numbers :ok_hand:

So yeah, I have no objection to adding the data-source-line injection into core, as long as it’s only added in preview. Is it something you’d be interested in making a PR for @pipkin?

4 Likes

Gladly! Happy to be able to give something back to you guys.

6 Likes