[print-format] add print heading + fix tables

This commit is contained in:
Rushabh Mehta 2015-02-03 17:54:36 +05:30
parent 4c8558665d
commit c19cb66542
11 changed files with 149 additions and 57 deletions

View file

@ -364,6 +364,29 @@ class BaseDocument(object):
return format_value(self.get(fieldname), self.meta.get_field(fieldname),
doc=doc or self, currency=currency)
def get_print_template(self, fieldname, parent_doc=None):
"""Returns print template for given fieldname if specified in controller
or parent controller.
Templates must be specified as:
class MyDocType(Document):
def __setup__(self):
self.print_templates = {
"[fieldname]": "templates/includes/template_name.html",
"[table fieldname].[fieldname]": "templates/includes/template_name.html"
}
:param fieldname: Field for which template is queried.
:param parent_doc: Parent Document, if child doc."""
src = self
if parent_doc:
src = parent_doc
fieldname = self.parentfield + "." + fieldname
if hasattr(src, "print_templates"):
return src.print_templates.get(fieldname)
def _filter(data, filters, limit=None):
"""pass filters as:
{"key": "val", "key": ["!=", "val"],

View file

@ -213,7 +213,7 @@ class Meta(Document):
def is_print_hide(self, fieldname):
df = self.get_field(fieldname)
return df.get("__print_hide") or df.print_hide
return df and (df.get("__print_hide") or df.print_hide)
doctype_table_fields = [
frappe._dict({"fieldname": "fields", "options": "DocField"}),

View file

@ -3,13 +3,16 @@
margin: 0px;
margin-bottom: 15px;
}
.print-format-builder-add-section {
.print-format-builder-add-section, .print-format-builder-header {
border: 1px dashed #d1d8dd;
text-align: center;
padding: 15px;
cursor: pointer;
}
.print-format-builder-header {
margin-bottom: 15px;
}
.print-format-builder-column {
padding: 15px;
margin: 0px -15px 0 -16px;

View file

@ -166,12 +166,19 @@ frappe.PrintFormatBuilder = Class.extend({
.appendTo(this.page.main);
this.setup_sortable();
this.setup_add_section();
this.setup_edit_heading();
},
prepare_data: function() {
this.data = JSON.parse(this.print_format.format_data || "[]");
if(!this.data.length) {
// new layout
this.data = this.meta.fields;
} else {
// extract print_heading_template if found
if(this.data[0].fieldname==="print_heading_template") {
this.print_heading_template = this.data[0].options;
this.data = this.data.splice(1);
}
}
this.layout_data = [];
var section = null, column = null, me = this;
@ -242,7 +249,7 @@ frappe.PrintFormatBuilder = Class.extend({
!_f.print_hide && f.label) {
// column names set as fieldname|width
f.visible_columns.push({fieldname: _f.fieldname, width: _f.width});
f.visible_columns.push({fieldname: _f.fieldname, print_width: (_f.width || "")});
}
});
}
@ -412,6 +419,14 @@ frappe.PrintFormatBuilder = Class.extend({
me.setup_sortable_for_column($section.find(".print-format-builder-column").get(0));
});
},
setup_edit_heading: function() {
var me = this;
this.page.main.find(".edit-heading").on("click", function() {
var $heading = $(this).parents(".print-format-builder-header:first")
.find(".print-format-builder-print-heading");
var d = me.get_edit_html_dialog(__("Edit Heading"), __("Heading"), $heading);
})
},
setup_column_selector: function() {
var me = this;
this.page.main.on("click", ".select-columns", function() {
@ -424,7 +439,7 @@ frappe.PrintFormatBuilder = Class.extend({
$.each(columns, function(i, v) {
var parts = v.split("|");
widths[parts[0]] = parts[1];
widths[parts[0]] = parts[1] || "";
});
var d = new frappe.ui.Dialog({
@ -473,7 +488,7 @@ frappe.PrintFormatBuilder = Class.extend({
});
},
get_visible_columns_string: function(f) {
return $.map(f.visible_columns, function(v) { return v.fieldname + "|" + v.width }).join(",")
return $.map(f.visible_columns, function(v) { return v.fieldname + "|" + (v.print_width || "") }).join(",")
},
get_no_content: function() {
return '<div class="text-extra-muted" data-no-content>'+__("Edit to add content")+'</div>'
@ -481,38 +496,48 @@ frappe.PrintFormatBuilder = Class.extend({
setup_edit_custom_html: function() {
var me = this;
this.page.main.on("click", ".edit-html", function() {
var parent = $(this).parents(".print-format-builder-field:first"),
$content = parent.find(".html-content");
var d = new frappe.ui.Dialog({
title: __("Edit Custom HTML"),
me.get_edit_html_dialog(__("Edit Custom HTML"), __("Custom HTML"),
$(this).parents(".print-format-builder-field:first").find(".html-content"));
});
},
get_edit_html_dialog: function(title, label, $content) {
var d = new frappe.ui.Dialog({
title: title,
fields: [
{
fieldname: "content",
fieldtype: "Text Editor",
label: "Custom HTML"
label: label
}
]
});
var content = $content.html();
if(content.indexOf("data-no-content")!==-1) content = "";
// set existing content in input
content = $content.html();
if(content.indexOf("data-no-content")!==-1) content = "";
d.set_input("content", content);
d.set_input("content", content);
d.set_primary_action(__("Update"), function() {
$content.html(d.get_value("content"));
d.hide();
});
d.show();
return false;
d.set_primary_action(__("Update"), function() {
$content.html(d.get_value("content"));
d.hide();
});
d.show();
return d;
},
save_print_format: function() {
var data = [],
me = this;
// add print heading as the first field
// this will be removed and set as a doc property
// before rendering
data.push({"fieldname": "print_heading_template",
fieldtype:"HTML",
options: this.page.main.find(".print-format-builder-print-heading").html()});
// add pages
this.page.main.find(".print-format-builder-section").each(function() {
data.push({"fieldtype": "Section Break"});
$(this).find(".print-format-builder-column").each(function() {
@ -530,7 +555,7 @@ frappe.PrintFormatBuilder = Class.extend({
$.each(columns, function(i, c) {
var parts = c.split("|");
df.visible_columns.push({fieldname:parts[0],
width:parts[1]});
print_width:parts[1]});
});
}
if(fieldtype==="Custom HTML") {

View file

@ -21,7 +21,7 @@
</div>
<div class="col-sm-6 text-right">
<input class="form-control column-width input-sm text-right"
value="{%= widths[f.fieldname] || "" %}"
value="{%= (widths[f.fieldname] || "") %}"
data-fieldname="{%= f.fieldname %}"
style="width: 100px; display: inline"
{%= selected ? "" : "disabled" %}>

View file

@ -2,13 +2,23 @@
<div class="text-muted text-center">
{%= __("Drag elements from the sidebar to add. Drag them back to trash.") %}<br><br>
</div>
<div class="print-format-builder-header">
<div class="text-right">
<a class="edit-heading btn btn-default btn-xs">
{%= __("Edit Heading") %}</a>
</div>
<div class="print-format-builder-print-heading">
{%= me.print_heading_template || __("<span class=text-muted data-no-content=1>"
+ __("Edit to set heading") + "</span>") %}
</div>
</div>
<div class="print-format-builder-layout">
{% for(var i=0; i < data.length; i++) { %}
{%= frappe.render_template("print_format_builder_section",
{section: data[i], me:me}) %}
{% } %}
</div>
<div class="print-format-builder-add-section text-muted">
<div class="print-format-builder-add-section text-muted text-center">
<span class="octicon octicon-plus"></span>
<a class="grey">Add a new section</a>
</div>

View file

@ -9,7 +9,7 @@ frappe.route_titles = {};
frappe.route_history = [];
frappe.view_factory = {};
frappe.view_factories = [];
frappe.route_options = {};
frappe.route_options = null;
frappe.route = function() {
if(frappe.re_route[window.location.hash]) {

View file

@ -375,11 +375,8 @@ bsEditorToolbar = Class.extend({
// edit html
this.toolbar.find(".btn-html").on("click", function() {
if(!window.bs_html_editor)
window.bs_html_editor = new bsHTMLEditor();
window.bs_html_editor.show(me.editor);
})
new bsHTMLEditor().show(me.editor);
});
},
update: function () {
@ -457,10 +454,9 @@ bsHTMLEditor = Class.extend({
var me = this;
this.modal = bs_get_modal("<i class='icon-code'></i> Edit HTML", '<textarea class="form-control" \
style="height: 400px; width: 100%; font-family: Monaco, \'Courier New\', monospace; font-size: 11px">\
</textarea><br>\
<button class="btn btn-primary" style="margin-top: 7px;">' + __("Save") + '</button>');
this.modal.addClass("frappe-ignore-click");
this.modal.find(".btn-primary").on("click", function() {
</textarea>');
this.modal.addClass("frappe-ignore-click");
this.modal.find(".btn-primary").removeClass("hide").html(__("Update")).on("click", function() {
me._html = me.modal.find("textarea").val();
$.each(me.editor.dataurls, function(key, val) {
@ -476,7 +472,7 @@ bsHTMLEditor = Class.extend({
show: function(editor) {
var me = this;
this.editor = editor;
this.modal.modal("show")
this.modal.modal("show");
var html = me.editor.html();
// pack dataurls so that html display is faster
this.editor.dataurls = {}

View file

@ -142,8 +142,22 @@ def get_print_format(doctype, print_format):
frappe.TemplateNotFoundError)
def make_layout(doc, meta, format_data=None):
"""Builds a hierarchical layout object from the fields list to be rendered
by `standard.html`
:param doc: Document to be rendered.
:param meta: Document meta object (doctype).
:param format_data: Fields sequence and properties defined by Print Format Builder."""
layout, page = [], []
layout.append(page)
if format_data:
# extract print_heading_template from the first field
# and remove the field
if format_data[0].get("fieldname") == "print_heading_template":
doc.print_heading_template = format_data[0].get("options")
format_data = format_data[1:]
for df in format_data or meta.fields:
if format_data:
# embellish df with original properties
@ -234,11 +248,19 @@ def get_print_style(style=None):
return css
def get_visible_columns(data, table_meta):
def get_visible_columns(data, table_meta, df):
"""Returns list of visible columns based on print_hide and if all columns have value."""
columns = []
for tdf in table_meta.fields:
if is_visible(tdf) and column_has_value(data, tdf.fieldname):
columns.append(tdf)
if df.get("visible_columns"):
# columns specified by column builder
for col_df in df.get("visible_columns"):
newdf = table_meta.get_field(col_df.get("fieldname")).as_dict().copy()
newdf.update(col_df)
columns.append(newdf)
else:
for col_df in table_meta.fields:
if is_visible(col_df) and column_has_value(data, col_df.get("fieldname")):
columns.append(col_df)
return columns

View file

@ -13,13 +13,13 @@
{%- macro render_table(df, doc) -%}
{%- set table_meta = frappe.get_meta(df.options) -%}
{%- set data = doc.get(df.fieldname)[df.start:df.end] -%}
{%- if doc.table_print_templates and
doc.table_print_templates.get(df.fieldname) -%}
{% include doc.table_print_templates[df.fieldname] %}
{%- if doc.print_templates and
doc.print_templates.get(df.fieldname) -%}
{% include doc.print_templates[df.fieldname] %}
{%- else -%}
{%- if data -%}
{%- set visible_columns = get_visible_columns(doc.get(df.fieldname),
table_meta) -%}
table_meta, df) -%}
<div>
<table class="table table-bordered table-condensed">
<thead>
@ -36,7 +36,8 @@
<tr>
<td>{{ d.idx }}</td>
{% for tdf in visible_columns %}
<td class="{{ get_align_class(tdf.fieldtype) }}">{{ print_value(tdf, d, doc) }}</td>
<td class="{{ get_align_class(tdf.fieldtype) }}">
{{ print_value(tdf, d, doc) }}</td>
{% endfor %}
</tr>
{% endfor %}
@ -76,10 +77,14 @@
{%- endmacro -%}
{%- macro print_value(df, doc, parent_doc=None) -%}
{% if df.fieldtype=="Check" %}
{% if doc.get_print_template(df.fieldname, parent_doc) %}
{% include doc.get_print_template(df.fieldname, parent_doc) %}
{% elif df.fieldtype=="Check" %}
<i class="{{ 'icon-check' if doc[df.fieldname] else 'icon-check-empty' }}"></i>
{% elif df.fieldtype=="Image" %}
<img src="{{ doc[doc.meta.get_field(df.fieldname).options] }}" class="img-responsive">
{% elif df.fieldtype=="HTML" %}
{{ frappe.render_template(df.options, {"doc":doc}) }}
{% else %}
{{ doc.get_formatted(df.fieldname, parent_doc or doc) }}
{% endif %}
@ -101,19 +106,26 @@
{% if letter_head and not no_letterhead %}
<div class="letter-head">{{ letter_head }}</div>
{% endif %}
<div class="print-heading">
<h3>{{ doc.select_print_heading or (doc.print_heading if doc.print_heading != None
else _(doc.doctype)) }}</h3>
<h4 class="text-muted">{{ doc.sub_heading if doc.sub_heading != None
else ("#" + doc[doc.meta.title_field or "name"]) }}</h4>
</div>
{% if doc.print_heading_template %}
{{ frappe.render_template(doc.print_heading_template, {"doc":doc}) }}
{% else %}
<div class="print-heading">
<h2>{{ doc.select_print_heading or (doc.print_heading if doc.print_heading != None
else _(doc.doctype)) }}
<small>{{ doc.sub_heading if doc.sub_heading != None
else doc.name }}</small>
</h2>
</div>
{% endif %}
{%- if doc.meta.is_submittable and doc.docstatus==0-%}
<div class="text-center">
<h4 style="margin: 0px;">{{ _("DRAFT") }}</h4></div>
<h4 style="margin: 0px;">{{ _("DRAFT") }}</h4>
</div>
{%- endif -%}
{%- if doc.meta.is_submittable and doc.docstatus==2-%}
<div class="text-center">
<h4 style="margin: 0px;">{{ _("CANCELLED") }}</h4></div>
<h4 style="margin: 0px;">{{ _("CANCELLED") }}</h4>
</div>
{%- endif -%}
{% if max_pages > 1 %}
<p class="text-right">{{ _("Page #{0} of {1}").format(page_num, max_pages) }}</p>

View file

@ -67,7 +67,8 @@ def get_allowed_functions_for_jenv():
"date_format": frappe.db.get_default("date_format") or "yyyy-mm-dd",
"get_fullname": frappe.utils.get_fullname,
"get_gravatar": frappe.utils.get_gravatar,
"full_name": hasattr(frappe.local, "session") and frappe.local.session.data.full_name or "Guest"
"full_name": hasattr(frappe.local, "session") and frappe.local.session.data.full_name or "Guest",
"render_template": frappe.render_template
},
"autodoc": {
"get_version": get_version,