Add webform css and add event loop on homepage

This commit is contained in:
Raghavendra Kamath
2018-02-20 17:31:35 +05:30
parent 091765d8ed
commit b9b0395927
18 changed files with 4617 additions and 61 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -1,4 +1,5 @@
@import "reset.css";
/*@import (css) "bootstrap-temp.css";*/
.indicator,
.indicator-right {
background: none;
@@ -360,7 +361,6 @@ hr {
font-size: 0.75rem;
}
.footer-end a {
text-decoration: underline;
color: #8D99A6;
}
.footer-end a:hover {
@@ -371,6 +371,47 @@ hr {
margin-right: .5em;
}
/* loaned from bootstrap*/
caption {
padding-top: 8px;
padding-bottom: 8px;
color: #8d99a6;
text-align: left;
}
th {
text-align: left;
}
.note-popover .popover-content > .btn-group,
.panel-heading.note-toolbar > .btn-group {
margin-top: 5px;
margin-right: 5px;
margin-left: 0;
}
.btn-group,
.btn-group-vertical {
position: relative;
display: inline-block;
vertical-align: middle;
}
.note-popover .popover-content,
.panel-heading.note-toolbar {
padding: 0 0 5px 5px;
margin: 0;
}
.panel-default > .panel-heading {
color: #333;
background-color: #F7FAFC;
border-color: #d1d8dd;
}
.panel-heading,
.panel-body {
padding-left: 1rem;
}
.panel-heading {
padding: .5rem 1rem;
border-bottom: 1px solid transparent;
border-top-left-radius: .25em;
border-top-right-radius: .25em;
}
.modal-open .modal {
overflow-x: hidden;
overflow-y: auto;
@@ -467,27 +508,6 @@ hr {
border: 1px solid transparent;
border-radius: .25em;
}
.table-bordered {
border: 1px solid #d1d8dd;
}
.table-bordered > thead > tr > th,
.table-bordered > tbody > tr > th,
.table-bordered > tfoot > tr > th,
.table-bordered > thead > tr > td,
.table-bordered > tbody > tr > td,
.table-bordered > tfoot > tr > td {
border: 1px solid #d1d8dd;
}
.table > thead > tr > th,
.table > tbody > tr > th,
.table > tfoot > tr > th,
.table > thead > tr > td,
.table > tbody > tr > td,
.table > tfoot > tr > td {
padding: .5em;
vertical-align: top;
border-top: 1px solid #EBEFF2;
}
.btn-block {
display: block;
width: 100%;
@@ -682,6 +702,12 @@ img.blog-cover-image,
.media-heading {
margin-top: 0;
}
.with-border {
border: 1px solid #d1d8dd;
border-radius: 0.25em;
padding: 1rem;
margin-bottom: 2rem;
}
/* individual elements */
.domain-links {
font-size: 1.5rem;

View File

@@ -1,4 +1,5 @@
@import (css) "reset.css";
/*@import (css) "bootstrap-temp.css";*/
@import "variables.less";
@import "indicator.less";
@@ -231,9 +232,12 @@ a {
}
.list-circle {
list-style: circle;
}
.bulleted-list {
margin: 0;
list-style: circle;
padding-left: 1em;
li {
@@ -337,7 +341,6 @@ hr {
}
.footer-end a{
text-decoration: underline;
color: @text-muted;
&:hover{
color: #fff;
@@ -351,6 +354,44 @@ hr {
/* loaned from bootstrap*/
caption {
padding-top: 8px;
padding-bottom: 8px;
color: #8d99a6;
text-align: left;
}
th {
text-align: left;
}
.note-popover .popover-content > .btn-group, .panel-heading.note-toolbar > .btn-group {
margin-top: 5px;
margin-right: 5px;
margin-left: 0;
}
.btn-group, .btn-group-vertical {
position: relative;
display: inline-block;
vertical-align: middle;
}
.note-popover .popover-content, .panel-heading.note-toolbar {
padding: 0 0 5px 5px;
margin: 0;
}
.panel-default > .panel-heading {
color: #333;
background-color:@panel-bg;
border-color: @border-color;
}
.panel-heading, .panel-body {
padding-left: 1rem;
}
.panel-heading {
padding: .5rem 1rem;
border-bottom: 1px solid transparent;
border-top-left-radius: .25em;
border-top-right-radius: .25em;
}
.modal-open .modal {
overflow-x: hidden;
overflow-y: auto;
@@ -453,20 +494,6 @@ hr {
border-radius: .25em;
}
.table-bordered {
border: @border;
}
.table-bordered > thead > tr > th, .table-bordered > tbody > tr > th, .table-bordered > tfoot > tr > th, .table-bordered > thead > tr > td, .table-bordered > tbody > tr > td, .table-bordered > tfoot > tr > td {
border: @border;
}
.table > thead > tr > th, .table > tbody > tr > th, .table > tfoot > tr > th, .table > thead > tr > td, .table > tbody > tr > td, .table > tfoot > tr > td {
padding: .5em;
vertical-align: top;
border-top: 1px solid @light-border-color;
}
.btn-block {
display: block;
width: 100%;
@@ -676,7 +703,7 @@ img.blog-cover-image, .blog-text img, .screenshot {
.media {
display: flex;
padding: 1.5rem;
background: #fafbfc;
background: @light-bg;
margin-bottom: 1.5rem;
border-radius: .25em;
border: 1px solid lightgray;
@@ -689,7 +716,15 @@ img.blog-cover-image, .blog-text img, .screenshot {
.media-heading {
margin-top: 0;
}
.media-object {
.with-border {
border: @border;
border-radius: 0.25em;
padding: 1rem;
margin-bottom: 2rem;
&:hover{
border-color: @text-light:;
background-color: @light-bg;
}
}
/* individual elements */

View File

@@ -17,11 +17,13 @@
{%- block head -%}
{% block meta_block %}{% endblock %}
<link href="/assets/foundation/css/erpnext-org-theme.css" rel="stylesheet">
{% if path != '' %}
<link type="text/css" rel="stylesheet" href="/assets/frappe/css/hljs.css">
<link type="text/css" rel="stylesheet" href="/assets/frappe/css/font-awesome.css">
<link type="text/css" rel="stylesheet" href="/assets/frappe/css/octicons/octicons.css">
{% endif %}
{%- endblock -%}
{# loading required JS for login #}
{%- block style %}{%- endblock -%}
<script>
window.frappe = {};
frappe.ready_events = [];
@@ -30,7 +32,6 @@
}
window.dev_server = {{ dev_server }};
</script>
{# loading required JS for login #}
</head>
<body data-path="{{ path }}">
<div class="wrapper">

View File

@@ -0,0 +1,52 @@
.introduction {
border-bottom: 1px solid #e1e9f0;
padding: 15px;
padding-top: 0px;
margin-left: -15px;
margin-right: -15px;
margin-bottom: 15px;
}
.form-group label {
font-weight: normal;
}
input[type='checkbox'] {
margin-top: 3px;
}
.checkbox label {
font-size: 12px;
}
.web-form-page, .web-form-page .section {
padding: 20px 0px;
}
.web-form-grid-row input, .web-form-grid-row select {
border: 0px;
padding: 0px;
}
.web-form-grid-row input:focus, .web-form-grid-row select:focus {
box-shadow: none;
}
.web-form-grid-row .form-group {
margin: 0px;
}
.slide-progress {
/*border-top: 1px solid #d1d8dd;*/
margin-top: -10px;
}
.slide-progress .fa-fw {
vertical-align: middle;
margin-right: 9px;
padding-left: 2px;
cursor: pointer;
}
.slide-progress .icon-circle-blank {
font-size: 12px;
}
.slide-progress .icon-circle {
font-size: 14px;
}

View File

@@ -0,0 +1,383 @@
{% extends "foundation/templates/web.html" %}
{% block title %}{{ _(title) }}{% endblock %}
{% block header %}
<h1>{{ _(title) }}</h1>
{% endblock %}
{% block breadcrumbs %}
{% if has_header and login_required %}
{% include "templates/includes/breadcrumbs.html" %}
{% endif %}
{% endblock %}
{% block header_actions %}
{% if not read_only and has_header %}
<div style="padding-bottom: 15px;">
{% if login_required -%}
<a href="{{ cancel_url or pathname }}" class="btn btn-default btn-sm">
{{ _("Cancel") }}</a>
{%- endif %}
{% if not is_list %}
<button type="submit" class="btn btn-primary btn-sm btn-form-submit">
{{ _("Save") }}</button>
{% endif %}
</div>
{% endif %}
{% if is_list %}
<div style="padding-bottom: 15px;">
<a href="/{{ pathname }}{{ delimeter }}new=1{{ params_from_form_dict}}" class="btn btn-primary btn-new btn-sm">
{{ _("New") }}
</a>
</div>
{% endif %}
{%- if allow_print and not is_list and not _login_required -%}
<div class='text-right'>
<a class='text-muted small' href='/printview?doctype={{ doc.doctype}}&name={{ doc.name }}
{%- if print_format -%}&format={{ print_format }}{%- endif -%}' target="_blank" rel="noopener noreferrer">
<i class='fa fa-print'></i> {{ _("Print") }}</a>
</div>
{%- endif -%}
{% endblock %}
{% block page_content %}
<div class="introduction">
{% if introduction_text %} hello
<p class="text-muted">{{ _(introduction_text) }}</p>
{% endif %}
</div>
<div class="form-message hide"></div>
{% if _login_required %}
<div class="login-required">
<div class="text-muted">
{{ _("Please sign-up or login to begin") }}
</div>
<p>
<a href="/login?redirect-to=/{{ pathname }}" class="btn btn-primary">
{{ _("Login") }}
</a>
</p>
</div>
{% elif is_list %}
{% include "templates/includes/list/list.html" %}
<script>{% include "templates/includes/list/list.js" %}</script>
{% else %}
<br>
{%- macro properties(field) %}
name="{{ field.fieldname }}" data-fieldname="{{ field.fieldname }}"
{% if field.placeholder -%} placeholder="{{ _(field.placeholder) }}" {%- endif %}
data-label="{{ _(field.label) }}" data-fieldtype="{{ field.fieldtype }}"
data-doctype="{{ field.parent }}" data-default="{{ field.default or "" }}"
{{ field.reqd and "data-reqd=1" or "" }}
{{ (read_only or field.read_only) and "disabled" or "" }}
{% endmacro -%}
{%- macro value(field, _doc) -%}
{%- if _doc -%}
{%- set _value = _doc.get(field.fieldname) or frappe.form_dict.get(field.fieldname) -%}
{%- else -%}
{%- set _value = frappe.form_dict.get(field.fieldname) or field.default -%}
{%- endif -%}
{{ "" if _value==None else _value }}
{%- endmacro -%}
{%- macro help(field) -%}
{% if field.description -%}
<span class="help-block small text-muted">{{ _(field.description) }}</span>
{%- endif -%}
{%- endmacro %}
{% macro label(field) %}
<label for="{{ field.fieldname }}" class="control-label text-muted small">
{{ _(field.label) }}</label>
{% endmacro %}
{% macro render_field(field, _doc=None, with_label=True) %}
{% if field.hidden %}
<input type="hidden" data-doctype="{{ field.parent }}"
name="{{ field.fieldname }}" value="{{ value(field, _doc) }}">
{% elif field.fieldtype == "HTML" %}
<div class="form-group" data-label="{{ field.label }}">
{% if field.options %}{{ field.options }}{% endif %}
</div>
{% elif field.fieldtype in ("Data", "Date", "Datetime", "Int", "Float") %}
<div class="form-group{% if field.reqd %} has-error{% endif %}">
{% if with_label %}{{ label(field) }}{% endif %}
<input type={{ "number" if field.fieldtype in ("Int", "Float") else "text" }}
class="form-control" {{ properties(field) }}
value="{{ value(field, _doc) }}"
{%- if field.fieldtype=="Int" %} pattern="[0-9]*"{% endif %}
{%- if field.max_length %} maxlength={{ field.max_length }}{% endif %}>
{{ help(field) }}
</div>
{% elif field.fieldtype=="Link" %}
<div class="form-group{% if field.reqd %} has-error{% endif %}">
{% if with_label %}{{ label(field) }}{% endif %}
<select class="form-control" {{ properties(field) }}>
{% for option in ([{"name":""}] + frappe.get_all(field.options)) -%}
<option value="{{ option.name }}"
{{ 'selected="selected"' if value(field, _doc)==option.name else '' }}>
{{ option.name }}</option>
{%- endfor %}
</select>
{{ help(field) }}
</div>
{% elif field.fieldtype=="Select" %}
<div class="form-group{% if field.reqd %} has-error{% endif %}">
{% if with_label %}{{ label(field) }}{% endif %}
<select class="form-control" {{ properties(field) }}>
{% for option in field.options.split("\n") -%}
<option value="{{ option }}"
{{ 'selected="selected"' if value(field, _doc)==option else '' }}>
{{ _(option) }}</option>
{%- endfor %}
</select>
{{ help(field) }}
</div>
{% elif field.fieldtype in ("Text", "Small Text") %}
<div class="form-group{% if field.reqd %} has-error{% endif %}">
{% if with_label %}{{ label(field) }}{% endif %}
{{ help(field) }}
<textarea class="form-control" style="height: {% if field.fieldtype=="Small Text" %}150px{% else %}300px;{% endif %}"
{{ properties(field) }}>{{ value(field, _doc) }}</textarea>
</div>
{% elif field.fieldtype == "Text Editor" %}
<div class="form-group{% if field.reqd %} has-error{% endif %}">
{% if with_label %}{{ label(field) }}{% endif %}
{{ help(field) }}
<div {{ properties(field) }}>{{ value(field, _doc) }}</div>
</div>
{% elif field.fieldtype=="Attach" %}
<div class="form-group">
{% if with_label %}{{ label(field) }}{% endif %}
{% if value(field, _doc) -%}
<p class="small">
<a href="{{ doc.get(field.fieldname) }}" target="blank">
{{ _doc.get(field.fieldname) }}
</a>
<br><button class="btn btn-small btn-default btn-xs
change-attach" style="margin-top: 5px;">{{ _("Change") }}</button>
</p>
{%- endif %}
<p class="{{ value(field, _doc) and 'hide' or '' }} attach-input-wrap">
<input type="file" style="margin-top: 7px;"
{{ properties(field) }}
{%- if value(field, _doc) -%} data-value="{{ value(field, _doc) }}"{%- endif -%}>
<p class='text-muted small' style='margin-bottom: 20px;'>
{{ _("Max attachment size is {0}MB").format(max_attachment_size) }}
</p>
</p>
{{ help(field) }}
</div>
{% elif field.fieldtype=="Check" %}
<div class="form-group">
<div class="checkbox">
{% if with_label %}
<label class='text-muted'>
<input type="checkbox" id="{{ field.fieldname }}"
{{ properties(field) }}
name="{{ field.fieldname }}" data-doctype="{{ field.parent }}"
{{ _doc and _doc.get(field.fieldname) and 'checked' or '' }}>
{{ _(field.label) }}
</label>
{% endif %}
{{ help(field) }}
</div>
</div>
{% endif %}
{% endmacro %}
{% macro render_row(field, d=None, hidden=False) %}
<tr class="web-form-grid-row {% if hidden %}hidden{% endif %}"
{% if d != None %}data-name="{{ d.name or "" }}" data-child-row=1{% endif %}>
{% for df in frappe.get_meta(field.options).fields %}
{% if df.in_list_view %}
<{{ 'th' if d==None else 'td' }} style="width: {{ (df.columns or 2) * 8.3333 }}%;">
{% if d!=None %}
{{ render_field(df, d, False) }}
{% else %}
<span class='text-muted small'>{{ _(df.label) }}</span>
{% endif %}
</{{ 'th' if d.name==None else 'td' }}>
{% endif %}
{% endfor %}
<td style="width: 8.3333%">
{% if d!=None %}
<button class='btn btn-default btn-sm btn-remove'><i class='fa fa-remove'></i></button>
{% endif %}
</td>
</tr>
{% endmacro %}
{% macro render_table(field) %}
{{ label(field) }}
<div class='web-form-grid'
data-fieldname='{{ field.fieldname }}' data-doctype='{{ field.options }}'>
<table class='table table-bordered'>
<thead>
{{ render_row(field) }}
</thead>
<tbody>
{{ render_row(field, {}, True) }}
{% if doc and doc.get(field.fieldname) %}
{% for d in doc.get(field.fieldname) %}
{{ render_row(field, d) }}
{% endfor %}
{% endif %}
</tbody>
</table>
</div>
<p><button class='btn btn-default btn-sm btn-add-row'
data-fieldname='{{ field.fieldname }}'>{{ _("Add Row") }}</button></p>
{% endmacro %}
<!-- pagination -->
{% if not frappe.form_dict.new and layout|len > 1 %}
<div class="text-center slide-progress text-extra-muted">
{% for page in layout %}
<i data-idx="{{ loop.index }}" data-toggle="tooltip" data-placement="top"
title="{{ _(page.label) or _("Page {0}").format(loop.index) }}" class="fa-fw
{% if loop.index==1 %}fa fa-circle{% else %}fa fa-circle-o{% endif %}"></i>
{% endfor %}
</div>
{% endif %}
<form role="form"
data-web-form="{{ name }}" data-owner="{{ doc.owner }}">
{% if frappe.form_dict.name and web_page_link_text %}
<div class="row">
<div class="col-sm-9">
<p class="text-muted">
<a class="btn btn-default btn-sm" href="{{ doc.route }}" target="_blank" rel="noopener noreferrer">
{{ web_page_link_text }}</a>
</p>
</div>
</div>
{% endif %}
{% for page in layout %}
{% set last_page = True if loop.index == layout|len else False %}
<div class="web-form-page{% if loop.index > 1 %} hidden{% endif %}"
data-idx="{{ loop.index }}"
data-label="{{ page.label or _("Page {0}").format(loop.index) }}">
{% if page.label %}
<h2 class='text-center'>{{ _(page.label) }}</h2>
{% endif %}
{% if page.description %}
<p class='text-center text-muted small'>{{ _(page.description) }}</p>
<br>
{% endif %}
{% for section in page.sections %}
<div class="section">
{% if section.label %}
<h5 class='uppercase'>{{ _(section.label) }}</h5>
<span class="help-block small text-muted">{{ _(section.description) }}</span>
{% endif %}
<div class="row">
{% for column in section.columns %}
<div class="col-sm-{{ (12 / (section.columns|len))|int }}">
{% for field in column %}
{% if field.fieldtype=='Table' %}
{{ render_table(field) }}
{% else %}
{{ render_field(field, doc) }}
{% endif %}
{% endfor %}
</div>
{% endfor %}
</div>
</div>
{% endfor %}
{% if last_page and accept_payment %}
<div class="well payment-details">
{% if not doc.paid %}
{% if payment_button_help %}
<div class='text-muted' style='padding-bottom: 15px;'>
{{ payment_button_help }}</div>
{% endif %}
<a class="btn btn-primary btn-payment">
{{ payment_button_label or "Pay"}}</a>
{% else %}
<div>{{ _("Payment Complete") }}</div>
{% endif %}
</div>
{% endif %}
<!-- page footer buttons -->
<div>
{% if layout|len > 1 %}
<p class='text-muted small text-center'>
{{ _("Page {0} of {1}").format(loop.index, layout|len) }}</p>
{% endif %}
<br>
<p class='text-right'>
{%- if loop.index > 1 -%}
<button class='btn btn-sm btn-default btn-change-section'
data-idx="{{ loop.index - 1 }}">
{{ _("Previous") }}</button>
{%- endif -%}
<!-- save/next button -->
{% if (loop.index == layout|len or frappe.form_dict.new) %}
{% if not read_only %}
<button type="submit" class="btn btn-primary btn-sm btn-form-submit">
{{ _("Save") }}</button>
{% endif %}
{% elif layout|len > 1 %}
<button class="btn btn-primary btn-sm btn-change-section"
data-idx="{{ loop.index + 1 }}">
{{ _("Next") }}</button>
{% endif %}
</p>
</div>
</div>
{% endfor %}
</form>
{% if allow_comments and not frappe.form_dict.new -%}
<div class="comments">
<br><br>
<h3>{{ _("Comments") }}</h3>
{% include 'templates/includes/comments/comments.html' %}
</div>
{%- endif %}
{% endif %}
<div class="padding"></div>
{% endblock %}
{% block script %}
<script>
window.web_form_settings = {
allow_incomplete: {{ allow_incomplete or 0 }},
success_link: '<p>{{ success_message or _("Your information has been submitted") }}</p><p><a href="{{ success_url or "/" }}" class="btn btn-sm btn-default">{{ _("Continue") }}</a></p>',
datepicker_format: "{{ frappe.date_format }}",
web_form_doctype: "{{ doc_type }}",
web_form_name: "{{ name }}",
is_new: {{ 1 if frappe.form_dict.new else 0 }},
is_read_only: {{ 1 if read_only else 0 }},
doc_name: "{{ frappe.form_dict.name or "" }}",
login_required: {{ 1 if login_required else 0 }},
max_attachment_size:{{ max_attachment_size }},
moment_date_format: "{{ frappe.date_format.upper() }}"
}
{% if row_template %}web_form_settings.web_form_row_template = "{{ row_template }}";{% endif %}
</script>
<script type="text/javascript" src="/assets/js/web_form.min.js"></script>
<script>
{% if script is defined %}
{{ script }}
{% endif %}
</script>
{% endblock %}
{% block style %}
<link type="text/css" rel="stylesheet" href="/assets/css/web_form.css">
<link href="/assets/foundation/css/bootstrap-for-webform.css" rel="stylesheet">
<style>
{% if style is defined %}{{ style }}{% endif %}
</style>
{% endblock %}

View File

@@ -0,0 +1,4 @@
<div>
<a href={{ route }}>{{ title }}</a>
</div>
<!-- this is a sample default list template -->

View File

@@ -0,0 +1,48 @@
[{
"allow_comments": 0,
"allow_edit": 1,
"allow_multiple": 1,
"doc_type": "Event",
"docstatus": 0,
"doctype": "Web Form",
"introduction_text": "Add events",
"login_required": 1,
"name": "manage-events",
"owner": "Administrator",
"page_name": "manage-events",
"published": 1,
"success_url": "/manage-events",
"title": "Manage Events",
"web_form_fields": [
{
"doctype": "Web Form Field",
"fieldname": "subject",
"fieldtype": "Data",
"hidden": 0,
"idx": 1,
"label": "Title",
"read_only": 0,
"reqd": 1
},
{
"doctype": "Web Form Field",
"fieldname": "starts_on",
"fieldtype": "Date",
"hidden": 0,
"idx": 2,
"label": "Event Date",
"read_only": 0,
"reqd": 1
},
{
"doctype": "Web Form Field",
"fieldname": "description",
"fieldtype": "Text",
"hidden": 0,
"idx": 3,
"label": "Description",
"read_only": 0,
"reqd": 0
}
]
}]

View File

@@ -0,0 +1,68 @@
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
# See license.txt
from __future__ import unicode_literals
import frappe
import unittest, json
from frappe.website.render import build_page
from frappe.website.doctype.web_form.web_form import accept
test_records = frappe.get_test_records('Web Form')
class TestWebForm(unittest.TestCase):
def setUp(self):
frappe.conf.disable_website_cache = True
frappe.local.path = None
def tearDown(self):
frappe.conf.disable_website_cache = False
frappe.local.path = None
def test_basic(self):
frappe.set_user("Guest")
html = build_page("manage-events")
self.assertTrue('<div class="login-required">' in html)
def test_logged_in(self):
frappe.set_user("Administrator")
html = build_page("manage-events")
self.assertFalse('<div class="login-required">' in html)
self.assertTrue('"/manage-events?new=1"' in html)
def test_new(self):
frappe.set_user("Administrator")
frappe.local.form_dict.new = 1
html = build_page("manage-events")
self.assertTrue('name="subject"' in html)
def test_accept(self):
frappe.set_user("Administrator")
accept(web_form='manage-events', data=json.dumps({
'doctype': 'Event',
'subject': '_Test Event Web Form',
'description': '_Test Event Description',
'starts_on': '2014-09-09'
}))
self.event_name = frappe.db.get_value("Event",
{"subject": "_Test Event Web Form"})
self.assertTrue(self.event_name)
def test_edit(self):
self.test_accept()
doc={
'doctype': 'Event',
'subject': '_Test Event Web Form',
'description': '_Test Event Description 1',
'starts_on': '2014-09-09',
'name': self.event_name
}
self.assertNotEquals(frappe.db.get_value("Event",
self.event_name, "description"), doc.get('description'))
accept(web_form='manage-events', data=json.dumps(doc))
self.assertEquals(frappe.db.get_value("Event",
self.event_name, "description"), doc.get('description'))

View File

@@ -0,0 +1,80 @@
frappe.web_form = {
set_fieldname_select: function(frm) {
var me = this,
doc = frm.doc;
if (doc.doc_type) {
frappe.model.with_doctype(doc.doc_type, function() {
var fields = $.map(frappe.get_doc("DocType", frm.doc.doc_type).fields, function(d) {
if (frappe.model.no_value_type.indexOf(d.fieldtype) === -1 ||
d.fieldtype === 'Table') {
return { label: d.label + ' (' + d.fieldtype + ')', value: d.fieldname }
} else {
return null;
}
})
var currency_fields = $.map(frappe.get_doc("DocType", frm.doc.doc_type).fields, function(d) {
if (d.fieldtype === 'Currency' || d.fieldtype === 'Float') {
return { label: d.label, value: d.fieldname }
} else {
return null;
}
})
frappe.meta.get_docfield("Web Form Field", "fieldname", frm.doc.name).options = [""].concat(fields);
frappe.meta.get_docfield("Web Form", "amount_field", frm.doc.name).options = [""].concat(currency_fields);
frm.refresh_field("amount_field");
});
}
}
}
frappe.ui.form.on("Web Form", {
refresh: function(frm) {
// show is-standard only if developer mode
frm.get_field("is_standard").toggle(frappe.boot.developer_mode);
frappe.web_form.set_fieldname_select(frm);
if (frm.doc.is_standard && !frappe.boot.developer_mode) {
frm.set_read_only();
frm.disable_save();
}
},
title: function(frm) {
if (frm.doc.__islocal) {
var page_name = frm.doc.title.toLowerCase().replace(/ /g, "-");
frm.set_value("route", page_name);
frm.set_value("success_url", "/" + page_name);
}
},
doc_type: function(frm) {
frappe.web_form.set_fieldname_select(frm);
}
});
frappe.ui.form.on("Web Form Field", {
fieldtype: function(frm, doctype, name) {
var doc = frappe.get_doc(doctype, name);
if (['Section Break', 'Column Break', 'Page Break'].includes(doc.fieldtype)) {
doc.fieldname = '';
frm.refresh_field("web_form_fields");
}
},
fieldname: function(frm, doctype, name) {
var doc = frappe.get_doc(doctype, name);
var df = $.map(frappe.get_doc("DocType", frm.doc.doc_type).fields, function(d) {
return doc.fieldname == d.fieldname ? d : null;
})[0];
doc.label = df.label;
doc.reqd = df.reqd;
doc.options = df.options;
doc.fieldtype = frappe.meta.get_docfield("Web Form Field", "fieldtype")
.options.split("\n").indexOf(df.fieldtype) === -1 ? "Data" : df.fieldtype;
doc.description = df.description;
doc["default"] = df["default"];
}
});

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,485 @@
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and contributors
# For license information, please see license.txt
from __future__ import unicode_literals
import frappe, json, os
from frappe.website.website_generator import WebsiteGenerator
from frappe import _, scrub
from frappe.utils import cstr
from frappe.utils.file_manager import save_file, remove_file_by_url
from frappe.website.utils import get_comment_list
from frappe.custom.doctype.customize_form.customize_form import docfield_properties
from frappe.utils.file_manager import get_max_file_size
from frappe.modules.utils import export_module_json, get_doc_module
from six.moves.urllib.parse import urlencode
from frappe.integrations.utils import get_payment_gateway_controller
from six import iteritems
class WebForm(WebsiteGenerator):
website = frappe._dict(
no_cache = 1
)
def onload(self):
super(WebForm, self).onload()
if self.is_standard and not frappe.conf.developer_mode:
self.use_meta_fields()
def validate(self):
super(WebForm, self).validate()
if not self.module:
self.module = frappe.db.get_value('DocType', self.doc_type, 'module')
if (not (frappe.flags.in_install or frappe.flags.in_patch or frappe.flags.in_test or frappe.flags.in_fixtures)
and self.is_standard and not frappe.conf.developer_mode):
frappe.throw(_("You need to be in developer mode to edit a Standard Web Form"))
if not frappe.flags.in_import:
self.validate_fields()
if self.accept_payment:
self.validate_payment_amount()
def validate_fields(self):
'''Validate all fields are present'''
from frappe.model import no_value_fields
missing = []
meta = frappe.get_meta(self.doc_type)
for df in self.web_form_fields:
if df.fieldname and (df.fieldtype not in no_value_fields and not meta.has_field(df.fieldname)):
missing.append(df.fieldname)
if missing:
frappe.throw(_('Following fields are missing:') + '<br>' + '<br>'.join(missing))
def validate_payment_amount(self):
if self.amount_based_on_field and not self.amount_field:
frappe.throw(_("Please select a Amount Field."))
elif not self.amount_based_on_field and not self.amount > 0:
frappe.throw(_("Amount must be greater than 0."))
def reset_field_parent(self):
'''Convert link fields to select with names as options'''
for df in self.web_form_fields:
df.parent = self.doc_type
def use_meta_fields(self):
'''Override default properties for standard web forms'''
meta = frappe.get_meta(self.doc_type)
for df in self.web_form_fields:
meta_df = meta.get_field(df.fieldname)
if not meta_df:
continue
for prop in docfield_properties:
if df.fieldtype==meta_df.fieldtype and prop not in ("idx",
"reqd", "default", "description", "default", "options",
"hidden", "read_only", "label"):
df.set(prop, meta_df.get(prop))
# TODO translate options of Select fields like Country
# export
def on_update(self):
"""
Writes the .txt for this page and if write_content is checked,
it will write out a .html file
"""
path = export_module_json(self, self.is_standard, self.module)
if path:
# js
if not os.path.exists(path + '.js'):
with open(path + '.js', 'w') as f:
f.write("""frappe.ready(function() {
// bind events here
})""")
# py
if not os.path.exists(path + '.py'):
with open(path + '.py', 'w') as f:
f.write("""from __future__ import unicode_literals
import frappe
def get_context(context):
# do your magic here
pass
""")
def get_context(self, context):
'''Build context to render the `web_form.html` template'''
self.set_web_form_module()
context._login_required = False
if self.login_required and frappe.session.user == "Guest":
context._login_required = True
doc, delimeter = make_route_string(frappe.form_dict)
context.doc = doc
context.delimeter = delimeter
# check permissions
if frappe.session.user == "Guest" and frappe.form_dict.name:
frappe.throw(_("You need to be logged in to access this {0}.").format(self.doc_type), frappe.PermissionError)
if frappe.form_dict.name and not has_web_form_permission(self.doc_type, frappe.form_dict.name):
frappe.throw(_("You don't have the permissions to access this document"), frappe.PermissionError)
self.reset_field_parent()
if self.is_standard:
self.use_meta_fields()
if not context._login_required:
if self.allow_edit:
if self.allow_multiple:
if not frappe.form_dict.name and not frappe.form_dict.new:
self.build_as_list(context)
else:
if frappe.session.user != 'Guest' and not frappe.form_dict.name:
frappe.form_dict.name = frappe.db.get_value(self.doc_type, {"owner": frappe.session.user}, "name")
if not frappe.form_dict.name:
# only a single doc allowed and no existing doc, hence new
frappe.form_dict.new = 1
# always render new form if login is not required or doesn't allow editing existing ones
if not self.login_required or not self.allow_edit:
frappe.form_dict.new = 1
self.load_document(context)
context.parents = self.get_parents(context)
if self.breadcrumbs:
context.parents = frappe.safe_eval(self.breadcrumbs, { "_": _ })
context.has_header = ((frappe.form_dict.name or frappe.form_dict.new)
and (frappe.session.user!="Guest" or not self.login_required))
if context.success_message:
context.success_message = frappe.db.escape(context.success_message.replace("\n",
"<br>"))
self.add_custom_context_and_script(context)
if not context.max_attachment_size:
context.max_attachment_size = get_max_file_size() / 1024 / 1024
def load_document(self, context):
'''Load document `doc` and `layout` properties for template'''
if frappe.form_dict.name or frappe.form_dict.new:
context.layout = self.get_layout()
context.parents = [{"route": self.route, "label": _(self.title) }]
if frappe.form_dict.name:
context.doc = frappe.get_doc(self.doc_type, frappe.form_dict.name)
context.title = context.doc.get(context.doc.meta.get_title_field())
context.doc.add_seen()
context.reference_doctype = context.doc.doctype
context.reference_name = context.doc.name
if self.allow_comments:
context.comment_list = get_comment_list(context.doc.doctype,
context.doc.name)
def build_as_list(self, context):
'''Web form is a list, show render as list.html'''
from frappe.www.list import get_context as get_list_context
# set some flags to make list.py/list.html happy
frappe.form_dict.web_form_name = self.name
frappe.form_dict.doctype = self.doc_type
frappe.flags.web_form = self
self.update_params_from_form_dict(context)
self.update_list_context(context)
get_list_context(context)
context.is_list = True
def update_params_from_form_dict(self, context):
'''Copy params from list view to new view'''
context.params_from_form_dict = ''
params = {}
for key, value in iteritems(frappe.form_dict):
if frappe.get_meta(self.doc_type).get_field(key):
params[key] = value
if params:
context.params_from_form_dict = '&' + urlencode(params)
def update_list_context(self, context):
'''update list context for stanard modules'''
if hasattr(self, 'web_form_module') and hasattr(self.web_form_module, 'get_list_context'):
self.web_form_module.get_list_context(context)
def get_payment_gateway_url(self, doc):
if self.accept_payment:
controller = get_payment_gateway_controller(self.payment_gateway)
title = "Payment for {0} {1}".format(doc.doctype, doc.name)
amount = self.amount
if self.amount_based_on_field:
amount = doc.get(self.amount_field)
payment_details = {
"amount": amount,
"title": title,
"description": title,
"reference_doctype": doc.doctype,
"reference_docname": doc.name,
"payer_email": frappe.session.user,
"payer_name": frappe.utils.get_fullname(frappe.session.user),
"order_id": doc.name,
"currency": self.currency,
"redirect_to": frappe.utils.get_url(self.route)
}
# Redirect the user to this url
return controller.get_payment_url(**payment_details)
def add_custom_context_and_script(self, context):
'''Update context from module if standard and append script'''
if self.web_form_module:
new_context = self.web_form_module.get_context(context)
if new_context:
context.update(new_context)
js_path = os.path.join(os.path.dirname(self.web_form_module.__file__), scrub(self.name) + '.js')
if os.path.exists(js_path):
context.script = frappe.render_template(open(js_path, 'r').read().decode('utf-8'), context)
css_path = os.path.join(os.path.dirname(self.web_form_module.__file__), scrub(self.name) + '.css')
if os.path.exists(css_path):
context.style = open(css_path, 'r').read()
def get_layout(self):
layout = []
def add_page(df=None):
new_page = {'sections': []}
layout.append(new_page)
if df and df.fieldtype=='Page Break':
new_page.update(df.as_dict())
return new_page
def add_section(df=None):
new_section = {'columns': []}
layout[-1]['sections'].append(new_section)
if df and df.fieldtype=='Section Break':
new_section.update(df.as_dict())
return new_section
def add_column(df=None):
new_col = []
layout[-1]['sections'][-1]['columns'].append(new_col)
return new_col
page, section, column = None, None, None
for df in self.web_form_fields:
# breaks
if df.fieldtype=='Page Break':
page = add_page(df)
section, column = None, None
if df.fieldtype=='Section Break':
section = add_section(df)
column = None
if df.fieldtype=='Column Break':
column = add_column(df)
# input
if df.fieldtype not in ('Section Break', 'Column Break', 'Page Break'):
if not page:
page = add_page()
section, column = None, None
if not section:
section = add_section()
column = None
if column==None:
column = add_column()
column.append(df)
return layout
def get_parents(self, context):
parents = None
if context.is_list and not context.parents:
parents = [{"title": _("My Account"), "name": "me"}]
elif context.parents:
parents = context.parents
return parents
def set_web_form_module(self):
'''Get custom web form module if exists'''
if self.is_standard:
self.web_form_module = get_doc_module(self.module, self.doctype, self.name)
else:
self.web_form_module = None
def validate_mandatory(self, doc):
'''Validate mandatory web form fields'''
missing = []
for f in self.web_form_fields:
if f.reqd and doc.get(f.fieldname) in (None, [], ''):
missing.append(f)
if missing:
frappe.throw(_('Mandatory Information missing:') + '<br><br>'
+ '<br>'.join(['{0} ({1})'.format(d.label, d.fieldtype) for d in missing]))
@frappe.whitelist(allow_guest=True)
def accept(web_form, data, for_payment=False):
'''Save the web form'''
data = frappe._dict(json.loads(data))
files = []
files_to_delete = []
web_form = frappe.get_doc("Web Form", web_form)
if data.doctype != web_form.doc_type:
frappe.throw(_("Invalid Request"))
elif data.name and not web_form.allow_edit:
frappe.throw(_("You are not allowed to update this Web Form Document"))
frappe.flags.in_web_form = True
if data.name:
# update
doc = frappe.get_doc(data.doctype, data.name)
else:
# insert
doc = frappe.new_doc(data.doctype)
# set values
for fieldname, value in iteritems(data):
if value and isinstance(value, dict):
try:
if "__file_attachment" in value:
files.append((fieldname, value))
continue
if '__no_attachment' in value:
files_to_delete.append(doc.get(fieldname))
value = ''
except ValueError:
pass
doc.set(fieldname, value)
if for_payment:
web_form.validate_mandatory(doc)
doc.run_method('validate_payment')
if doc.name:
if has_web_form_permission(doc.doctype, doc.name, "write"):
doc.save(ignore_permissions=True)
else:
# only if permissions are present
doc.save()
else:
# insert
if web_form.login_required and frappe.session.user=="Guest":
frappe.throw(_("You must login to submit this form"))
doc.insert(ignore_permissions = True)
# add files
if files:
for f in files:
fieldname, filedata = f
# remove earlier attached file (if exists)
if doc.get(fieldname):
remove_file_by_url(doc.get(fieldname), doc.doctype, doc.name)
# save new file
filedoc = save_file(filedata["filename"], filedata["dataurl"],
doc.doctype, doc.name, decode=True)
# update values
doc.set(fieldname, filedoc.file_url)
doc.save()
if files_to_delete:
for f in files_to_delete:
if f:
remove_file_by_url(f, doc.doctype, doc.name)
frappe.flags.web_form_doc = doc
if for_payment:
return web_form.get_payment_gateway_url(doc)
else:
return doc.name
@frappe.whitelist()
def delete(web_form, name):
web_form = frappe.get_doc("Web Form", web_form)
owner = frappe.db.get_value(web_form.doc_type, name, "owner")
if frappe.session.user == owner and web_form.allow_delete:
frappe.delete_doc(web_form.doc_type, name, ignore_permissions=True)
else:
raise frappe.PermissionError("Not Allowed")
def has_web_form_permission(doctype, name, ptype='read'):
if frappe.session.user=="Guest":
return False
# owner matches
elif frappe.db.get_value(doctype, name, "owner")==frappe.session.user:
return True
elif frappe.has_website_permission(name, ptype=ptype, doctype=doctype):
return True
elif check_webform_perm(doctype, name):
return True
else:
return False
def check_webform_perm(doctype, name):
doc = frappe.get_doc(doctype, name)
if hasattr(doc, "has_webform_permission"):
if doc.has_webform_permission():
return True
def get_web_form_list(doctype, txt, filters, limit_start, limit_page_length=20, order_by=None):
from frappe.www.list import get_list
if not filters:
filters = {}
filters["owner"] = frappe.session.user
return get_list(doctype, txt, filters, limit_start, limit_page_length, order_by=order_by,
ignore_permissions=True)
def make_route_string(parameters):
route_string = ""
delimeter = '?'
if isinstance(parameters, dict):
for key in parameters:
if key != "web_form_name":
route_string += route_string + delimeter + key + "=" + cstr(parameters[key])
delimeter = '&'
return (route_string, delimeter)

View File

@@ -0,0 +1,432 @@
{
"allow_copy": 0,
"allow_import": 0,
"allow_rename": 0,
"beta": 0,
"creation": "2014-09-01 14:14:14.292173",
"custom": 0,
"docstatus": 0,
"doctype": "DocType",
"document_type": "",
"editable_grid": 1,
"fields": [
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "fieldname",
"fieldtype": "Select",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "Fieldname",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "fieldtype",
"fieldtype": "Select",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "Fieldtype",
"length": 0,
"no_copy": 0,
"options": "Attach\nCheck\nData\nDate\nDatetime\nFloat\nHTML\nInt\nLink\nSelect\nSmall Text\nText\nText Editor\nTable\nSection Break\nColumn Break\nPage Break",
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "label",
"fieldtype": "Data",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "Label",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "reqd",
"fieldtype": "Check",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Mandatory",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "read_only",
"fieldtype": "Check",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Read Only",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "hidden",
"fieldtype": "Check",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Hidden",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "column_break_4",
"fieldtype": "Column Break",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"length": 0,
"no_copy": 0,
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "options",
"fieldtype": "Text",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "Options",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "max_length",
"fieldtype": "Int",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Max Length",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"depends_on": "eval:doc.fieldtype=='Int'",
"fieldname": "max_value",
"fieldtype": "Int",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Max Value",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "section_break_6",
"fieldtype": "Section Break",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"length": 0,
"no_copy": 0,
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "description",
"fieldtype": "Text",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Description",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "column_break_8",
"fieldtype": "Column Break",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"length": 0,
"no_copy": 0,
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "default",
"fieldtype": "Data",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Default",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
}
],
"hide_heading": 0,
"hide_toolbar": 0,
"idx": 0,
"image_view": 0,
"in_create": 0,
"in_dialog": 0,
"is_submittable": 0,
"issingle": 0,
"istable": 1,
"max_attachments": 0,
"modified": "2017-02-27 15:55:00.850515",
"modified_by": "Administrator",
"module": "Website",
"name": "Web Form Field",
"name_case": "",
"owner": "Administrator",
"permissions": [],
"quick_entry": 0,
"read_only": 0,
"read_only_onload": 0,
"show_name_in_global_search": 0,
"sort_field": "modified",
"sort_order": "DESC",
"track_changes": 0,
"track_seen": 0
}

View File

@@ -0,0 +1,9 @@
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and contributors
# For license information, please see license.txt
from __future__ import unicode_literals
import frappe
from frappe.model.document import Document
class WebFormField(Document):
pass

View File

@@ -55,30 +55,26 @@
<div class="centered">
<h1 class="title">ERPNext Foundation</h1>
<p class="intro-copy">ERPNext Foundation is a community of ERPNext Users, Developers and Service Providers. The goal of the ERPNext Foundation is to provide a platform for the ERPNext Community to come together, join hands and build assets to help build and enhance ERPNext around the world.</p>
<a href="" class="button button-secondary">Become a Member</a>
<a href="/members/details" class="button button-secondary">Become a Member</a>
</div>
</div>
</section>
<section class="feature">
<div class="container">
<div class="three-column left-aligned">
<div class="first-column">
<div class="columns">
<h1 class="subtitle">Events & Meetups</h1>
<ul class="bulleted-list">
<ul class="bulleted-list list-circle">
{% for e in events %}
<li>
<a href="" class="secondary-link">2nd Indonesian Meetup</a>
</li>
<li>
<a href="" class="secondary-link">2nd Indonesian Meetup</a>
</li>
<li>
<a href="/members" class="secondary-link">2nd Indonesian Meetup</a>
<a href="{{ e.route }}" class="secondary-link">{{ frappe.format_date(e.event_date, "medium") }} - {{ e.event_title }}</a>
</li>
{% endfor %}
</ul>
</div>
<div class="second-column">
<div class="columns">
<h1 class="subtitle">Help Us Improve</h1>
<ul class="bulleted-list">
<ul class="bulleted-list list-circle">
<li>
<a href="https://github.com/frappe/erpnext/tree/develop/erpnext/docs" class="secondary-link">Write Documentation</a>
</li>
@@ -90,14 +86,14 @@
</li>
</ul>
</div>
<div class="third-column">
<div class="columns">
<h1 class="subtitle">Need Help?</h1>
<ul class="bulleted-list">
<ul class="bulleted-list list-circle">
<li>
<a href="" class="secondary-link">User Manual</a>
<a href="/docs/user/manual" class="secondary-link">User Manual</a>
</li>
<li>
<a href="" class="secondary-link">Ask in our forum</a>
<a href="https://discuss.erpnext.com/" class="secondary-link">Ask in our forum</a>
</li>
<li>
<a href="" class="secondary-link">Get Paid Support</a>

10
foundation/www/index.py Normal file
View File

@@ -0,0 +1,10 @@
# See license.txt
from __future__ import unicode_literals
import frappe
def get_context(context):
out = {
"events": frappe.get_all("Portal Event", fields=["event_title", "event_date", "details", "route"], filters=[["published", "=", 1]])
}
return out