Django markdown show_preview feature throws an error - django

I am new using markdown. I tried to use the show_preview = False to implement preview using jQuery instead.
class PostForm(forms.ModelForm):
content = forms.CharField(widget=PagedownWidget(show_preview=False))
publish = forms.DateField(widget = forms.SelectDateWidget)
class Meta:
model = Post
fields = [
"title",
"content",
"image",
"draft",
"publish",
]
unfortunately, it throws an error:
line 9, in PostForm
content = forms.CharField(widget=PagedownWidget(show_preview=False))
TypeError: __init__() got an unexpected keyword argument 'show_preview'
I did look into the markdown files and could not find show_preview using except here:
4 <textarea {{ attrs|safe }}>{{ body }}</textarea>
5 </div>
6 {% if show_preview %}
7 <p class="wmd-preview-title">
8 <small>HTML Preview:</small>
I am running:
Django==2.2.6
django-markdown-deux==1.0.5
django-pagedown==2.0.3

Are you following a guide?
Django-pagedown widget used to take a number of arguments (including show_preview). Use version 1.0.6 if you want to do that. v1.0.6 is still compatible with django2.2.x.
Since v2.0.0 it is better to subclass the widget and point it to the template / css to define the preview box, see the docs for that:
Github (see the readme)
Example app with form
You can stop the preview showing by overwriting the CSS. eg, add the following to your .css file in the static folder (and ensure it is being imported into your template). Or just stick it in a style tag at the top of your template.
.wmd-preview{
display: none;
}

Related

Stylized HTML fields in Django admin

I Have TextField to store HTML text. I want to colorize HTML tags. I use TinyMCE but didn't need an HTML editor like WordPress just simple to colorize like IDE, Search a lot but didn't find anything useful, So if you can help I appreciate it.
My field:
I want output like this but changeable:
Using a code editor in Django admin Textarea
The following is implemented with CodeMirror but you can use any other library (Monaco, etc).
Final result:
For all the libraries, we need to add some library specific javascript and stylesheet plus some custom code for integration.
Django has pretty flexible templating to enable this. We can override the entire template or specific blocks. Detailed documentation can be fond here.
To integration CodeMirror, we can override the admin/base.html 's extrahead block. We will include the required js/css, one extra css for theming and some js to find and apply CodeMirror.
Here, I have create a admin/base.html inside my project's configured template directory. This will apply to all the apps and models. There are ways to target an app or model individually - check the office docs.
This works for JSONField data. You will have to tweak a bit to format
html or any other language.
Inspect the page and find id of the textarea you want to target
<!-- tested with Django 3.2.9 -->
{% extends "admin/base.html" %}
{% block extrahead %}
{{ block.super }}
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.0/codemirror.min.js" crossorigin="anonymous"
referrerpolicy="no-referrer"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.0/codemirror.min.css"
crossorigin="anonymous" referrerpolicy="no-referrer" />
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.0/theme/oceanic-next.min.css"
crossorigin="anonymous" referrerpolicy="no-referrer" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.0/mode/javascript/javascript.min.js"
crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script type="text/javascript">
window.addEventListener('load', (event) => {
const target = document.getElementById("id_data");
target.value = JSON.stringify(JSON.parse(target.value), null, ' ');
const config = {
mode: 'javascript',
theme: 'oceanic-next',
lineNumbers: true,
lineWrapping: true
}
const jsonCodeMirror = CodeMirror.fromTextArea(target, config);
jsonCodeMirror.setSize("100%", 600);
});
</script>
{% endblock %}
Multiple textarea inputs can be targeted as well with get element with classname and then looping over the result set and applying the same logic.
For html formatting,
you can use this https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.0/mode/htmlmixed/htmlmixed.min.js instead of javascript. Delete the json stringify statement. Change mode to htmlmixed.
Don't need to override any template
solved by integrating django-ace field and in this we have support for CSS, python, HTML etc also.
Simply use this in django forms and provide the form in django model admin class
admin file
from appname import forms
#admin.register(models.Table)
class TableModelAdmin(admin.ModelAdmin):
form = forms.TableModelForm
form file
from django import forms
from django_ace import AceWidget
class TableModelForm(forms.ModelForm):
class Meta:
model = models.Table
fields = '__all__'
widgets = {
'columns': AceWidget(
mode='json',
theme='None',
width='1200px',
height='500px',
fontsize='18px',
showprintmargin=False,
),
}

Django-CMS apphooked templates showing same placeholder content

I've got a django-cms site on which I have created a page at /managers-home/ with an app hook so that I can use myapp from that page.
myapp renders various templates at various URLs beneath /managers-home/ and I would like each of these templates to have a section editable via the django-cms content plugin. Therefore I have added {% staticplaceholder "content" site %} to these templates, because, as I understand it, you can't use a standard {% placeholder "" %} from within a hooked application.
I made a start with this and added some text to the placeholder on /managers-home/page-1/ which uses page-1.html and then when I got to the placeholder on /managers-home/page-2 I could already see the content from page-1 despite now using page-2.html so the placeholder on these two individual templates is being shared.
How can I correctly add django-cms placeholders throughout my application templates?
Turns out my problem was that a static_placeholder is exactly that, just a placeholder identified by the name given and anywhere you reference that name you get the same content.
So in order to allow each of my templates to display custom text, I've created a static_placeholder for each template.
# page-1.html
{% static_placeholder "page-1" site or %}
Default text goes here
{% endstatic_placeholder %}
# settings.py
CMS_PLACEHOLDER_CONF = {
'page-1': {
'plugins': ['TextPlugin', 'UploadedPicturePlugin'],
'text_only_plugins': ['LinkPlugin'],
'extra_context': {"width": 640},
'name': gettext("Content"),
}
}

Condition that checks placeholder content existence

How can I check placeholder content existence and make next trick? :
{% if placeholder 'Head_text' %} <--check here
<div class="in">
...
...
<h2 class="title">{% placeholder 'Head_text' %}</h2>
...
...
</div>
{% endif %}
I want to know, does placeholder have some content before rendering some special HTML-structure for it.
Thanks.
I was looking for a solution for this and I found a few alternatives instead of checking if the placeholder exists. Basically the idea is to use a different plugin instead that adds the extra html. There are a few packages you can install with pip. Now, after trying them I just did it myself and it was much more easier than using the packages.
cmsplugin-text-wrapper: It integrates to the existent django-cms default text plugin keeping the editor but adds a selector on top so you can select a wrapper. The wrapper contains the extra html you would like to add. It also has a nice CSS system to add classes. On the downside, I didn't want to make the editors life more difficult with the extra template selector.
cmsplugin-text-ng: This basically adds a new plugin. When you add the plugin to your placeholder, it display a selector with the available templates (that contains your extra HTML). What I really like is that you can add extra fields that you can use in your customized HTML. For example, you could add a title so the plugin displays an extra textfield for it. On the downside, the templates are store in the database through the admin!. That is an extra hit to the database and I really don't want to sacrifice it for something too simple.
Do your own plugin using the existent Text Model. Four very simple steps:
3.1 Basically add this to your cms_plugins.py:
from cms.plugin_pool import plugin_pool
from cms.plugins.text.models import Text
from cms.plugins.text.cms_plugins import TextPlugin
class WidgetPlugin(TextPlugin):
model = Text
name = _("Widget")
render_template = "widget.html"
def render(self, context, instance, placeholder):
context['instance'] = instance
return context
plugin_pool.register_plugin(WidgetPlugin)
3.2 Create your widget.html template in your templates folder:
<div class="in">
...
...
{{ instance.body|safe }}
...
...
</div>
3.3 Place your placeholder wherever you want:
{% placeholder 'Head_text' %}
3.4 Make the user use the new plugin adding the Head_text configuration plugin in the settings.py:
CMS_PLACEHOLDER_CONF = {
#...
'Head_text': {
'plugins': {'WidgetPlugin'}
},
}
I've had this problem before, and when I researched it (this might have changed since) there is no built in way to do this, so you have to write your own template tag to load the placeholder into a variable.
Here are some discussions on the django-cms mailing list:
https://groups.google.com/forum/?fromgroups=#!topic/django-cms/QeTlmxQnn3E
https://groups.google.com/forum/#!topic/django-cms/2mWvEpTH0ns/discussion

Why does a DOJO tools text area control break my forms

Hi I'm using django comments in one of my apps. I customized the comments framework to fit my needs. Everything works properly until I use dojo to make the textarea for the comments expandable http://dojotoolkit.org/reference-guide/1.7/dijit/form/Textarea.html#dijit-form-textarea. After adding the script the form throws an error after submitting: this field is required. So it seems django doesn't recognize the textarea as part of the form anymore.
in my template I use the standart comment tags:
{% render_comment_form for event %}
{% render_comment_list for event %}
When I'm adding the dojo script, the textarea gets expandable, but the form doesn't pass it's value anymore.
dojo.require("dijit.form.Textarea");
dojo.ready(function(){
var textarea = new dijit.form.Textarea({
name: "id_comment",
style: "width:200px;"
}, "id_comment");
});
dojo adds a bunch of classes to the textarea so that it looks like following. But it still got it's id and it's still a textarea isn't it?
<textarea autocomplete="off" data-dojo-attach-point="focusNode,containerNode,textbox" name="id_comment" class="dijitTextBox dijitTextArea dijitExpandingTextArea" style="overflow-y: hidden; overflow-x: auto; -moz-box-sizing: border-box; width: 200px; height: 36px;" tabindex="0" id="id_comment" widgetid="id_comment" value="" rows="1"></textarea>
After reading the answers for this question: Searching for the Ultimate Resizing Textarea. I thought this might the best way to go but unfortunatly it's not.
I'm wondering if it's just me. Is there a way to get this right or should I use a different method to make the field expandable.
Edit
with dojo the post looks like that:
content_type cylebrations.image
csrfmiddlewaretoken 24827190efbb5b7793aeadaf8276beed
honeypot
id_comment ssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssss
object_pk 4
post Post
security_hash 8a091cfbf1e309627369069d4f71c21b33843a85
timestamp 1335209980
without dojo:
comment eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee
content_type cylebrations.image
csrfmiddlewaretoken 24827190efbb5b7793aeadaf8276beed
honeypot
object_pk 4
post Post
security_hash e02d8261f528cfc0f22ee30ced820cfbb80715bc
timestamp 1335210114
Dojo overwrites the name of the textarea. I called it id_comment, instead of just comment. After changing that the post looks just fine and everything works like it should:
dojo.require("dijit.form.Textarea");
dojo.ready(function(){
var textarea = new dijit.form.Textarea({
name: "comment",
style: "width:200px;"
}, "id_comment");
});

Django: How to position a page when using Django templates and links

I have this in my template:
<div id="comment-{{ post_comment.id }}">
<a title="Comment was useful" href="/useful-comment/{{ blog_post.id }}/{{ post_comment.id }}/">
When the user clicks on this link, the method useful_comment(blog_post_id, post_comment_id) is called and at when it returns it loads the same template again. I then want to scroll the page down to #comment-{{ post_comment.id }}, but how do I do that if I load my template like so:
arguments = dict(user = request.user, blog_post = blog_post)
t = loader.get_template('blog-post-template.html')
c = RequestContext(request, args)
return HttpResponse(t.render(c))
This is related to Django: How do I position a page when using Django templates, but in that question they are using forms and only scrolling down to a static section of the page.
You should add an #anchor to your link's href. In your case there will be different anchors (<a name="comment_123"></a>, for example) for all your comments, so be sure link points to correct anchor.
This is nothing to do with Django, just old good HTML.