Repository URL to install this package:
|
Version:
2.4.0.gt1 ▾
|
import $ from 'jquery';
import django from 'django';
import md5 from 'md5';
import React from 'react';
import ReactDOM from 'react-dom';
import Remarkable from 'remarkable';
import * as lib from './lib.js';
export class CommentForm extends React.Component {
constructor(props) {
super(props);
this.state = {
name: '', email: '', url: '', followup: false, comment: '',
reply_to: this.props.reply_to || 0,
visited: {name: false, email: false, comment: false},
errors: {name: false, email: false, comment: false},
previewing: false,
alert: {message: '', cssc: ''}
};
this.handle_input_change = this.handle_input_change.bind(this);
this.handle_blur = this.handle_blur.bind(this);
this.handle_submit = this.handle_submit.bind(this);
this.handle_preview = this.handle_preview.bind(this);
this.reset_form = this.reset_form.bind(this);
this.fhelp = <span className="form-text small invalid-feedback">
{django.gettext("This field is required.")}
</span>;
}
handle_input_change(event) {
const target = event.target;
const value = target.type === 'checkbox' ? target.checked : target.value;
const iname = target.name;
this.setState({[iname]: value});
}
handle_blur(field) {
function handler(event) {
var visited = this.state.visited;
visited[field] = true;
this.setState({visited: visited});
};
return handler.bind(this);
}
validate() {
var errors = this.state.errors;
errors.name = false;
errors.email = false;
if(!this.state.comment.length)
errors.comment = true;
else errors.comment = false;
if(!this.props.is_authenticated || this.props.request_name) {
if(/^\s*$/.test(this.state.name))
errors.name = true;
else errors.name = false;
}
if(!this.props.is_authenticated || this.props.request_email_address) {
if(/\S+@\S+\.\S+/.test(this.state.email))
errors.email = false;
else errors.email = true;
}
this.setState({errors: errors});
if(this.state.errors.comment ||
this.state.errors.name ||
this.state.errors.email)
return false;
else return true;
}
render_field_comment() {
let div_cssc = "form-group row",
input_cssc = "form-control",
help = "";
if (this.state.reply_to > 0) {
input_cssc += " form-control-sm";
}
if (this.state.errors.comment) {
div_cssc += (this.state.errors.comment ? " has-danger" : "");
input_cssc += " is-invalid";
help = this.fhelp;
}
var placeholder = django.gettext("Your comment");
return (
<>
<textarea required name="comment" id="id_comment"
placeholder={placeholder} maxLength="3000"
className={input_cssc} value={this.state.comment}
onChange={this.handle_input_change}
onBlur={this.handle_blur('comment')} />
{help}
</>
);
}
render_field_name() {
if(this.props.is_authenticated && !this.props.request_name)
return "";
let div_cssc = "form-group row",
label_cssc = "col-form-label col-md-3 text-right",
input_cssc = "form-control",
help = "";
const placeholder = django.gettext('name');
if (this.state.reply_to > 0) {
label_cssc += " form-control-sm";
input_cssc += " form-control-sm";
}
if (this.state.errors.name) {
div_cssc += " has-danger";
input_cssc += " is-invalid";
help = this.fhelp;
}
return (
<div className={div_cssc}>
<label htmlFor="id_name" className={label_cssc}>
{django.gettext("Name")}
</label>
<div className="col-md-7">
<input type="text" name="name" required id="id_name"
value={this.state.name} placeholder={placeholder}
onChange={this.handle_input_change}
onBlur={this.handle_blur('name')}
className={input_cssc} />
{help}
</div>
</div>
);
}
render_field_email() {
if(this.props.is_authenticated && !this.props.request_email_address)
return "";
let div_cssc = "form-group row",
label_cssc = "col-form-label col-md-3 text-right",
input_cssc = "form-control",
help_cssc = "form-text small",
helptext_style = {};
const placeholder = django.gettext('mail address'),
helptext = django.gettext('Required for comment verification.');
if (this.state.reply_to > 0) {
label_cssc += " form-control-sm";
input_cssc += " form-control-sm";
helptext_style = {fontSize: "0.710rem"};
}
if (this.state.errors.email) {
div_cssc += " has-danger";
input_cssc += " is-invalid";
help_cssc += " invalid-feedback";
}
return (
<div className={div_cssc}>
<label htmlFor="id_email" className={label_cssc}>
{django.gettext("Mail")}
</label>
<div className="col-md-7">
<input type="text" name="email" required id="id_email"
value={this.state.email} placeholder={placeholder}
onChange={this.handle_input_change}
onBlur={this.handle_blur('email')}
className={input_cssc} />
<span className={help_cssc}
style={helptext_style}>{helptext}</span>
</div>
</div>
);
}
render_field_url() {
if(this.props.is_authenticated)
return "";
let label_cssc = "col-form-label col-md-3 text-right",
input_cssc = "form-control";
if(this.state.reply_to > 0) {
label_cssc += " form-control-sm";
input_cssc += " form-control-sm";
}
if(this.state.errors.url)
var placeholder = django.gettext("url your name links to (optional)");
return (
<div className="form-group row">
<label htmlFor="id_url" className={label_cssc}>
{django.gettext("Link")}
</label>
<div className="col-md-7">
<input type="text" name="url" id="id_url"
value={this.state.url}
placeholder={placeholder}
onChange={this.handle_input_change}
className={input_cssc} />
</div>
</div>
);
}
render_field_followup() {
let label = django.gettext("Notify me about follow-up comments"),
label_cssc = "custom-control-label";
if(this.state.reply_to > 0)
label_cssc += " small";
return (
<div className="custom-control custom-checkbox">
<input className="custom-control-input" type="checkbox"
checked={this.state.followup}
onChange={this.handle_input_change}
name="followup" id="id_followup" />
<label className={label_cssc} htmlFor="id_followup">
{label}
</label>
</div>
);
}
reset_form() {
this.setState({
name: '', email: '', url: '', followup: false, comment: '',
visited: {name: false, email: false, comment: false},
errors: {name: false, email: false, comment: false}
});
}
handle_submit_response(status) {
let css_class = "";
const msg_202 = django.gettext("Your comment will be reviewed. Thank your for your patience."),
msg_204 = django.gettext("Thank you, a comment confirmation request has been sent by mail."),
msg_403 = django.gettext("Sorry, your comment has been rejected.");
const message = {202: msg_202,
204: msg_204,
403: msg_403},
cssc = "alert alert-";
if(status == 403)
css_class = cssc + "danger";
else css_class = cssc + "info";
this.setState({alert: {message: message[status], cssc: css_class},
previewing: false});
this.reset_form();
this.props.on_comment_created();
}
handle_submit(event) {
event.preventDefault();
if(!this.validate())
return;
const data = {
content_type: this.props.form.content_type,
object_pk: this.props.form.object_pk,
timestamp: this.props.form.timestamp,
security_hash: this.props.form.security_hash,
honeypot: '',
comment: this.state.comment,
name: this.state.name,
email: this.state.email,
url: this.state.url,
followup: this.state.followup,
reply_to: this.state.reply_to
};
$.ajax({
method: 'POST',
url: this.props.send_url,
data: data,
dataType: 'json',
cache: false,
success: function(data, textStatus, xhr) {
if([201, 202, 204].indexOf(xhr.status) > -1) {
this.handle_submit_response(xhr.status);
}
}.bind(this),
error: function(xhr, status, err) {
if(xhr.status == 400) {
let errors = this.state.errors;
xhr.responseJSON.forEach(function(item, idx, array) {
errors[item] = true;
});
this.setState({errors: errors});
} else if (xhr.status == 403) {
this.handle_submit_response(xhr.status);
} else {
console.error(this.props.send_url, status, err.toString());
}
}.bind(this)
});
}
handle_preview(event) {
event.preventDefault();
if(this.validate())
this.setState({previewing: true});
}
rawMarkup() {
var md = new Remarkable();
const rawMarkup = md.render(this.state.comment);
return { __html: rawMarkup };
}
render_preview() {
if(!this.state.previewing)
return "";
let heading_name = "";
// Build Gravatar.
const hash = md5(this.state.email.toLowerCase());
const avatar_url = "https://www.gravatar.com/avatar/"+hash+"?s=48&d=mm";
const avatar_img = <img className="mr-3" src={avatar_url}
height="48" width="48"/>;
if(this.state.url) {
heading_name = (<a href={this.state.url} target="_new">
{this.state.name}</a>);
} else {
if(this.props.is_authenticated)
heading_name = this.props.current_user.split(":")[1];
else heading_name = this.state.name;
}
let label = "";
var header_text = django.gettext("Your comment in preview");
let header = <h5 className="text-center">{header_text}</h5>;
if(this.state.reply_to > 0) {
header = "";
label = <div className="badge badge-info">preview</div>;
}
var nowtext = django.gettext("Now");
return (
<div>
<hr/>
{header}
<div className="media">
{avatar_img}
<div className="media-body">
<div className="comment pb-3">
<h6 className="mb-1 small">
{nowtext} - {heading_name} {label}
</h6>
<div className="preview"
dangerouslySetInnerHTML={this.rawMarkup()} />
</div>
</div>
</div>
</div>
);
}
render_form() {
let comment = this.render_field_comment();
let followup = this.render_field_followup();
let btn_submit_class = "btn";
var btn_label_send = django.gettext("POST");
return (
<form method="POST" onSubmit={this.handle_submit}>
<input type="hidden" name="content_type"
defaultValue={this.props.form.content_type}/>
<input type="hidden" name="object_pk"
defaultValue={this.props.form.object_pk}/>
<input type="hidden" name="timestamp"
defaultValue={this.props.form.timestamp}/>
<input type="hidden" name="security_hash"
defaultValue={this.props.form.security_hash}/>
<input type="hidden" name="reply_to"
defaultValue={this.state.reply_to}/>
<div className="comment-form row">
<div className="col-10 cbox">
<fieldset>
<div style={{display: 'none'}}>
<input type="text" name="honeypot" defaultValue=""/>
</div>
{comment}
</fieldset>
</div>
<div className="col-2 cbtn">
<button type="submit" name="post"
className={btn_submit_class}>{btn_label_send}</button>
</div>
</div>
{followup}
</form>
);
}
render() {
let header = "";
let div_class = "card card-block card-reply";
var label = django.gettext("LEAVE A COMMENT");
if(this.state.reply_to == 0) {
header = <h4 className="card-title text-left">{label}</h4>;
div_class = "card card-block mb-2";
}
let alert_div = "";
if(this.state.alert.message) {
alert_div = (
<div className={this.state.alert.cssc}>
{this.state.alert.message}
</div>
);
}
let form = this.render_form();
return (<div>
<div className={div_class}>
<div className="card-body">
{header}
{alert_div}
{form}
</div>
</div>
</div>);
}
}