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

Task List Classes #1430

Closed
oasiz opened this issue Feb 28, 2019 · 10 comments
Closed

Task List Classes #1430

oasiz opened this issue Feb 28, 2019 · 10 comments
Labels
category: lists good first issue Something easy to get started with proposal

Comments

@oasiz
Copy link

oasiz commented Feb 28, 2019

Describe the feature
Hi folks! This Markdown:

- [ ] foo
- [x] bar

.. generates the following HTML:

<ul>
    <li><input type="checkbox" disabled=""> foo</li>
    <li><input type="checkbox" disabled="" checked=""> bar</li>
</ul>

Is it possible to add classes (as GitHub does) to make these style-able?

GitHub renders as such:

<ul class="contains-task-list">
    <li class="task-list-item"><input type="checkbox" id="" disabled="" class="task-list-item-checkbox"> foo</li>
    <li class="task-list-item"><input type="checkbox" id="" disabled="" class="task-list-item-checkbox" checked=""> bar</li>
</ul> 

Why is this feature necessary?
I want to add "list-style: none;" to the UL class, as it currently doesn't look good:

tasklist

Apologies if I've missed a way to do this, I've looked through the docs but couldn't see a way.

Thanks for reading! :-)

@UziTech
Copy link
Member

UziTech commented Feb 28, 2019

You should be able to do this be extending the renderer

something like:

// Create reference instance
const marked= require('marked');

// Get reference
const renderer = new marked.Renderer();
const renderListitem = renderer.prototype.listitem;

// Override function
renderer.listitem = function (text) {
	let html = renderListitem(text);
	
	if (html.includes("<input")) {
		html = html.replace("<li>", "<li class='task-list-item'>");
	}

	return html;
};

// Run marked
console.log(marked('* [ ] test', { renderer: renderer }));

// <ul><li class='task-list-item'><input disabled="" type="checkbox"> test</li></ul>

@UziTech
Copy link
Member

UziTech commented Feb 28, 2019

It could be easier if the renderer was passed a task boolean.

That would be a great PR if you want to work on it. 😁

@UziTech UziTech added good first issue Something easy to get started with proposal category: lists labels Feb 28, 2019
@oasiz
Copy link
Author

oasiz commented Feb 28, 2019

You should be able to do this be extending the renderer

something like:

// Create reference instance
const marked= require('marked');

// Get reference
const renderer = new marked.Renderer();
const renderListitem = renderer.prototype.listitem;

// Override function
renderer.listitem = function (text) {
	let html = renderListitem(text);
	
	if (html.includes("<input")) {
		html = html.replace("<li>", "<li class='task-list-item'>");
	}

	return html;
};

// Run marked
console.log(marked('* [ ] test', { renderer: renderer }));

// <ul><li class='task-list-item'><input disabled="" type="checkbox"> test</li></ul>

Hi, thanks for the reply!

The render.prototype.listitem was throwing errors for me (Chrome) so I swapped it for the following code and it's working great:

const renderListitem = renderer.listitem.bind(renderer);

// Override function
renderer.listitem = function (text) {
	let html = renderListitem(text);
	
	if (html.includes("<input") && ! html.includes("task-list-item-checkbox")) {
		html = html.replace("<input ", "<input class='task-list-item-checkbox' ");
		html = html.replace("<li>", "<li class='task-list-item'>");
	}

	return html;
};

Note: I added the task-list-item-checkbox class and check for it's existence as otherwise it failed when using nested lists. No idea if this is the most efficient way of doing this but it appears to work fine.

Here's the CSS I used if anyone finds it useful:

/* task list */
.task-list-item {
	list-style: none;
}
.task-list-item-checkbox {
    margin: 0 .2em .25em -1.6em;
    vertical-align: middle;
}

Thanks for your help, much appreciated!

@x13machine
Copy link
Contributor

@UziTech

It could be easier if the renderer was passed a task boolean.

What do you mean by that? Do you mean passing override functions through new marked.Renderer()? Though that wouldn't be a boolean. 😕

@UziTech
Copy link
Member

UziTech commented Mar 8, 2019

No I mean changing marked to pass in a boolean to renderer.listitem that tells it whether it is a task item

Then you would be able to do:

const renderListitem = renderer.listitem.bind(renderer);

// Override function
renderer.listitem = function (text, task) {
	let html = renderListitem(text, task);
	
	if (task) {
		html = html.replace("<input ", "<input class='task-list-item-checkbox' ");
		html = html.replace("<li>", "<li class='task-list-item'>");
	}

	return html;
};

This would require a small change to marked.

@UziTech
Copy link
Member

UziTech commented Mar 11, 2019

task and checked will be sent to renderer.listitem in v0.6.2

thanks @x13machine 🎉

@UziTech UziTech closed this as completed Mar 11, 2019
@Jakobud
Copy link

Jakobud commented May 6, 2019

I can't seem to get this to work. I tried this:

var renderer = new marked.Renderer();
var renderListitem = renderer.listitem.bind(renderer);

// Override function
renderer.listitem = function (text, task) {
        console.log(text, task)
	var html = renderListitem(text, task);
	
	if (task) {
		html = html.replace("<input ", "<input class='task-list-item-checkbox' ");
		html = html.replace("<li>", "<li class='task-list-item'>");
	}

	return html;
};

I don't get anything printing out in the console. What am I missing here?

Also, side note, it seems like this functionality should be out of the box for GFM. GFM should be rendering out the same html you would see on GitHub. In this case, it should be adding the class contains-task-list to the checkbox list.

@UziTech
Copy link
Member

UziTech commented May 6, 2019

@Jakobud make sure you are adding the renderer as an option.

The following script worked for me:

var marked = require('marked');

var renderer = new marked.Renderer();
var renderListitem = renderer.listitem.bind(renderer);

// Override function
renderer.listitem = function(text, task) {
  console.log(text, task);
  var html = renderListitem(text, task);

  if (task) {
    html = html.replace('<input ', "<input class='task-list-item-checkbox' ");
    html = html.replace('<li>', "<li class='task-list-item'>");
  }

  return html;
};

marked('- hi', { renderer: renderer });
// logs "hi false"

GFM should be rendering out the same html you would see on GitHub

gfm: true renders html according to the GFM spec. No where in the spec does it say that the class contains-task-list should be added to a task list.

@Jakobud
Copy link

Jakobud commented May 6, 2019

Ah good call thanks for the help!

Interesting on the GFM spec. Thanks I had not seen that link. I wonder why their markdown renders different on github.com than in their spec. Thanks again!

@doraven
Copy link

doraven commented Jun 7, 2019

Additional:
@UziTech 's solution is not right with marked/0.6.2 .

Here is my version of solving this problem inproved from his idea

let markedRender = new marked.Renderer()

// renderlistitem is not working well in marked, let's correct it using function below
let renderListitem = markedRender.listitem.bind(markedRender)
markedRender.listitem = function(text, task) {
    var html = renderListitem(text, task)
    if (task) {
        html = html.replace('<input ', "<input class='task-list-item-checkbox' ")
         html = html.replace('<li>', "<li class='task-list-item'>")
         html = html.replace('<p>', '')
         html = html.replace('</p>', '')
    }
    return html
  }

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
category: lists good first issue Something easy to get started with proposal
Projects
None yet
Development

No branches or pull requests

5 participants