소스 검색

Merge pull request #17908 from frappe/mergify/bp/version-14-hotfix/pr-17863

version-14
Suraj Shetty 2 년 전
committed by GitHub
부모
커밋
4c56aaba26
No known key found for this signature in database GPG 키 ID: 4AEE18F83AFDEB23
20개의 변경된 파일735개의 추가작업 그리고 503개의 파일을 삭제
  1. +14
    -13
      cypress/integration/web_form.js
  2. +9
    -4
      frappe/public/js/bootstrap-4-web.bundle.js
  3. +1
    -1
      frappe/public/js/frappe/form/controls/base_control.js
  4. +3
    -3
      frappe/public/js/frappe/form/controls/color.js
  5. +4
    -1
      frappe/public/js/frappe/form/formatters.js
  6. +1
    -1
      frappe/public/js/frappe/ui/dialog.js
  7. +0
    -1
      frappe/public/js/frappe/ui/messages.js
  8. +77
    -41
      frappe/public/js/frappe/web_form/web_form.js
  9. +5
    -1
      frappe/public/js/frappe/web_form/web_form_list.js
  10. +1
    -4
      frappe/public/js/frappe/web_form/webform_script.js
  11. +400
    -267
      frappe/public/scss/website/web_form.scss
  12. +65
    -55
      frappe/website/doctype/web_form/templates/web_form.html
  13. +6
    -6
      frappe/website/doctype/web_form/templates/web_form_skeleton.html
  14. +3
    -1
      frappe/website/doctype/web_form/templates/web_list.html
  15. +1
    -1
      frappe/website/doctype/web_form/test_web_form.py
  16. +54
    -17
      frappe/website/doctype/web_form/web_form.js
  17. +65
    -63
      frappe/website/doctype/web_form/web_form.json
  18. +18
    -16
      frappe/website/doctype/web_form/web_form.py
  19. +5
    -4
      frappe/website/doctype/web_form_field/web_form_field.json
  20. +3
    -3
      frappe/website/doctype/web_form_list_column/web_form_list_column.json

+ 14
- 13
cypress/integration/web_form.js 파일 보기

@@ -45,7 +45,7 @@ context("Web Form", () => {
cy.login();
cy.visit("/app/web-form/note");

cy.findByRole("tab", { name: "Form Settings" }).click();
cy.findByRole("tab", { name: "Settings" }).click();
cy.get('input[data-fieldname="login_required"]').check({ force: true });

cy.save();
@@ -65,7 +65,8 @@ context("Web Form", () => {
cy.login();
cy.visit("/app/web-form/note");

cy.findByRole("tab", { name: "List Settings" }).click();
cy.findByRole("tab", { name: "Settings" }).click();
cy.get(".section-head").contains("List Settings").click();
cy.get('input[data-fieldname="show_list"]').check();

cy.save();
@@ -78,7 +79,7 @@ context("Web Form", () => {
it("Show Custom List Title", () => {
cy.visit("/app/web-form/note");

cy.findByRole("tab", { name: "List Settings" }).click();
cy.findByRole("tab", { name: "Settings" }).click();
cy.fill_field("list_title", "Note List");

cy.save();
@@ -97,7 +98,7 @@ context("Web Form", () => {

cy.visit("/app/web-form/note");

cy.findByRole("tab", { name: "List Settings" }).click();
cy.findByRole("tab", { name: "Settings" }).click();

cy.get('[data-fieldname="list_columns"] .grid-footer button')
.contains("Add Row")
@@ -108,19 +109,19 @@ context("Web Form", () => {
cy.get("@grid-rows").find('.grid-row:first [data-fieldname="fieldname"]').click();
cy.get("@grid-rows")
.find('.grid-row:first select[data-fieldname="fieldname"]')
.select("Title (Data)");
.select("Title");

cy.get("@add-row").click();
cy.get("@grid-rows").find('.grid-row[data-idx="2"] [data-fieldname="fieldname"]').click();
cy.get("@grid-rows")
.find('.grid-row[data-idx="2"] select[data-fieldname="fieldname"]')
.select("Public (Check)");
.select("Public");

cy.get("@add-row").click();
cy.get("@grid-rows").find('.grid-row:last [data-fieldname="fieldname"]').click();
cy.get("@grid-rows")
.find('.grid-row:last select[data-fieldname="fieldname"]')
.select("Content (Text Editor)");
.select("Content");

cy.save();

@@ -171,7 +172,7 @@ context("Web Form", () => {
it("Edit Mode", () => {
cy.visit("/app/web-form/note");

cy.findByRole("tab", { name: "Form Settings" }).click();
cy.findByRole("tab", { name: "Settings" }).click();
cy.get('input[data-fieldname="allow_edit"]').check();

cy.save();
@@ -179,7 +180,7 @@ context("Web Form", () => {
cy.visit("/note/Note 1");
cy.url().should("include", "/note/Note%201");

cy.get(".web-form-actions a").contains("Edit").click();
cy.get(".web-form-actions a").contains("Edit Response").click();
cy.url().should("include", "/note/Note%201/edit");

// Editable Field
@@ -194,7 +195,7 @@ context("Web Form", () => {
it("Allow Multiple Response", () => {
cy.visit("/app/web-form/note");

cy.findByRole("tab", { name: "Form Settings" }).click();
cy.findByRole("tab", { name: "Settings" }).click();
cy.get('input[data-fieldname="allow_multiple"]').check();

cy.save();
@@ -212,7 +213,7 @@ context("Web Form", () => {
it("Allow Delete", () => {
cy.visit("/app/web-form/note");

cy.findByRole("tab", { name: "Form Settings" }).click();
cy.findByRole("tab", { name: "Settings" }).click();
cy.get('input[data-fieldname="allow_delete"]').check();

cy.save();
@@ -235,7 +236,7 @@ context("Web Form", () => {
it("Navigate and Submit a WebForm", () => {
cy.visit("/update-profile");

cy.get(".web-form-actions a").contains("Edit").click();
cy.get(".web-form-actions a").contains("Edit Response").click();

cy.fill_field("middle_name", "_Test User");

@@ -247,7 +248,7 @@ context("Web Form", () => {
cy.call("frappe.tests.ui_test_helpers.update_webform_to_multistep").then(() => {
cy.visit("/update-profile-duplicate");

cy.get(".web-form-actions a").contains("Edit").click();
cy.get(".web-form-actions a").contains("Edit Response").click();

cy.fill_field("middle_name", "_Test User");



+ 9
- 4
frappe/public/js/bootstrap-4-web.bundle.js 파일 보기

@@ -32,10 +32,7 @@ frappe.get_modal = function (title, content) {
${content}
</div>
<div class="modal-footer hidden">
<button type="button" class="btn btn-default btn-sm btn-modal-close" data-dismiss="modal">
<i class="octicon octicon-x visible-xs" style="padding: 1px 0px;"></i>
<span class="hidden-xs">${__("Close")}</span>
</button>
<button type="button" class="btn btn-sm btn-secondary hidden"></button>
<button type="button" class="btn btn-sm btn-primary hidden"></button>
</div>
</div>
@@ -49,11 +46,19 @@ frappe.ui.Dialog = class Dialog extends frappe.ui.Dialog {
return this.$wrapper.find(".modal-footer .btn-primary");
}

get_secondary_btn() {
return this.$wrapper.find(".modal-footer .btn-secondary");
}

set_primary_action(label, click) {
this.$wrapper.find(".modal-footer").removeClass("hidden");
return super.set_primary_action(label, click).removeClass("hidden");
}

set_secondary_action(click) {
return super.set_secondary_action(click).removeClass("hidden");
}

make() {
super.make();
if (this.fields) {


+ 1
- 1
frappe/public/js/frappe/form/controls/base_control.js 파일 보기

@@ -82,7 +82,7 @@ frappe.ui.form.Control = class BaseControl {
is_null(value) &&
!in_list(["HTML", "Image", "Button"], this.df.fieldtype)
)
status = "None";
status = "Read";

return status;
}


+ 3
- 3
frappe/public/js/frappe/form/controls/color.js 파일 보기

@@ -93,11 +93,11 @@ frappe.ui.form.ControlColor = class ControlColor extends frappe.ui.form.ControlD

set_formatted_input(value) {
super.set_formatted_input(value);
this.$input.val(value);
this.selected_color.css({
this.$input?.val(value);
this.selected_color?.css({
"background-color": value || "transparent",
});
this.selected_color.toggleClass("no-value", !value);
this.selected_color?.toggleClass("no-value", !value);
}

get_color() {


+ 4
- 1
frappe/public/js/frappe/form/formatters.js 파일 보기

@@ -294,7 +294,10 @@ frappe.form.formatters = {
let formatted_value = frappe.form.formatters.Text(value);
// to use ql-editor styles
try {
if (!$(formatted_value).find(".ql-editor").length) {
if (
!$(formatted_value).find(".ql-editor").length &&
!$(formatted_value).hasClass("ql-editor")
) {
formatted_value = `<div class="ql-editor read-mode">${formatted_value}</div>`;
}
} catch (e) {


+ 1
- 1
frappe/public/js/frappe/ui/dialog.js 파일 보기

@@ -168,7 +168,7 @@ frappe.ui.Dialog = class Dialog extends frappe.ui.FieldGroup {

set_secondary_action(click) {
this.footer.removeClass("hide");
this.get_secondary_btn().removeClass("hide").off("click").on("click", click);
return this.get_secondary_btn().removeClass("hide").off("click").on("click", click);
}

set_secondary_action_label(label) {


+ 0
- 1
frappe/public/js/frappe/ui/messages.js 파일 보기

@@ -72,7 +72,6 @@ frappe.warn = function (title, message_html, proceed_action, primary_label, is_m

d.$body.append(`<div class="frappe-confirm-message">${message_html}</div>`);
d.standard_actions.find(".btn-primary").removeClass("btn-primary").addClass("btn-danger");
d.standard_actions.find(".btn-primary").removeClass("btn-primary").addClass("btn-danger");

d.show();
return d;


+ 77
- 41
frappe/public/js/frappe/web_form/web_form.js 파일 보기

@@ -24,10 +24,10 @@ export default class WebForm extends frappe.ui.FieldGroup {
super.make();
this.set_page_breaks();
this.set_field_values();
this.setup_listeners();

if (this.is_new || this.is_form_editable) {
if (this.is_new || this.in_edit_mode) {
this.setup_primary_action();
this.setup_discard_action();
}

this.setup_previous_next_button();
@@ -35,6 +35,7 @@ export default class WebForm extends frappe.ui.FieldGroup {

// webform client script
frappe.init_client_script && frappe.init_client_script();
this.setup_listeners();
frappe.web_form.events.trigger("after_load");
this.after_load && this.after_load();
}
@@ -43,34 +44,39 @@ export default class WebForm extends frappe.ui.FieldGroup {
let field = this.fields_dict[fieldname];
field.df.change = () => {
handler(field, field.value);
this.make_form_dirty();
};
}

setup_listeners() {
// Event listener for triggering Save/Next button for Multi Step Forms
// Do not use `on` event here since that can be used by user which will render this function useless
// setTimeout has 200ms delay so that all the base_control triggers for the fields have been run
let me = this;

if (!me.is_multi_step_form) {
return;
}
// setup change event for all fields if not already set through client script
this.fields.forEach((field) => {
if (!field.change) {
field.change = () => {
this.make_form_dirty();
};
}
});
}

for (let field of $(".input-with-feedback")) {
$(field).change((e) => {
setTimeout(() => {
e.stopPropagation();
me.toggle_buttons();
}, 200);
});
}
make_form_dirty() {
frappe.form_dirty = true;
$(".indicator-pill.orange").removeClass("hide");
}

set_page_breaks() {
if (this.page_breaks.length) return;
this.page_breaks = $(".page-break");

if (this.page_breaks.length) {
this.page_breaks.each((i, page_break) => {
if (!$(page_break).find("form").length) {
$(page_break).remove();
}
});
}

this.page_breaks = $(`.page-break`);
this.is_multi_step_form = true;
this.page_breaks = $(".page-break");
this.is_multi_step_form = !!this.page_breaks.length;
}

setup_previous_next_button() {
@@ -80,15 +86,19 @@ export default class WebForm extends frappe.ui.FieldGroup {
return;
}

$(".web-form-footer .web-form-actions .left-area").prepend(`
<button class="btn btn-default btn-previous btn-md mr-2">${__("Previous")}</button>
`);
this.$next_button = $(`<button class="btn btn-default btn-next btn-sm ml-2">
${__("Next")}
</button>`);

this.$previous_button = $(`<button class="btn btn-default btn-previous btn-sm">
${__("Previous")}
</button>`);

$(".web-form-footer .web-form-actions .right-area").prepend(`
<button class="btn btn-default btn-next btn-md">${__("Next")}</button>
`);
this.$next_button.insertAfter(".web-form-footer .right-area .discard-btn");
this.in_view_mode && $(".web-form-footer .right-area").append(this.$next_button);
$(".web-form-footer .left-area").prepend(this.$previous_button);

$(".btn-previous").on("click", function () {
this.$previous_button.on("click", () => {
let is_validated = me.validate_section();

if (!is_validated) return false;
@@ -115,7 +125,7 @@ export default class WebForm extends frappe.ui.FieldGroup {
return false;
});

$(".btn-next").on("click", function () {
this.$next_button.on("click", () => {
let is_validated = me.validate_section();

if (!is_validated) return false;
@@ -155,7 +165,29 @@ export default class WebForm extends frappe.ui.FieldGroup {
}

setup_primary_action() {
$(".web-form-container").on("submit", () => this.save());
$(".web-form").on("submit", () => this.save());
}

setup_discard_action() {
$(".web-form-footer .discard-btn").on("click", () => this.discard_form());
}

discard_form() {
let path = window.location.href;
// remove new or edit after last / from url
path = path.substring(0, path.lastIndexOf("/"));

if (frappe.form_dirty) {
frappe.warn(
__("Discard?"),
__("Are you sure you want to discard the changes?"),
() => (window.location.href = path),
__("Discard")
);
} else {
window.location.href = path;
}
return false;
}

validate_section() {
@@ -223,8 +255,18 @@ export default class WebForm extends frappe.ui.FieldGroup {
}

render_progress_dots() {
if (!this.is_multi_step_form) return;
$(".center-area.paging").empty();

if (this.in_view_mode) {
let paging_text = __("Page {0} of {1}", [
this.current_section + 1,
this.page_breaks.length + 1,
]);
$(".center-area.paging").append(`<div>${paging_text}</div>`);
return;
}

this.$slide_progress = $(`<div class="slides-progress"></div>`).appendTo(
$(".center-area.paging")
);
@@ -246,12 +288,6 @@ export default class WebForm extends frappe.ui.FieldGroup {
}
this.$slide_progress.append($dot);
}

let paging_text = __("Page {0} of {1}", [
this.current_section + 1,
this.page_breaks.length + 1,
]);
$(".center-area.paging").append(`<div>${paging_text}</div>`);
}

toggle_buttons() {
@@ -290,7 +326,7 @@ export default class WebForm extends frappe.ui.FieldGroup {

show_next_and_hide_save_button() {
$(".btn-next").show();
$(".submit-btn").hide();
!this.allow_incomplete && $(".submit-btn").hide();
}

toggle_previous_button() {
@@ -398,16 +434,16 @@ export default class WebForm extends frappe.ui.FieldGroup {

render_success_page(data) {
if (this.allow_edit && data.name) {
$(".success-page").append(`
<a href="/${this.route}/${data.name}/edit" class="edit-button btn btn-light btn-md ml-2">
$(".success-footer").append(`
<a href="/${this.route}/${data.name}/edit" class="edit-button btn btn-default btn-md">
${__("Edit your response", null, "Button in web form")}
</a>
`);
}

if (this.login_required && !this.allow_multiple && !this.show_list && data.name) {
$(".success-page").append(`
<a href="/${this.route}/${data.name}" class="view-button btn btn-light btn-md ml-2">
$(".success-footer").append(`
<a href="/${this.route}/${data.name}" class="view-button btn btn-default btn-md">
${__("View your response", null, "Button in web form")}
</a>
`);


+ 5
- 1
frappe/public/js/frappe/web_form/web_form_list.js 파일 보기

@@ -381,7 +381,11 @@ frappe.ui.WebFormListRow = class WebFormListRow {
formatter(this.doc[field.fieldname], field, { only_value: 1 }, this.doc)
)) ||
"";
let cell = $(`<td>${value}</td>`);
let cell = $(`<td><p class="ellipsis">${value}</p></td>`);
if (field.fieldtype === "Text Editor") {
value = $(value).addClass("ellipsis");
cell = $("<td></td>").append(value);
}
cell.appendTo(this.row);
});



+ 1
- 4
frappe/public/js/frappe/web_form/webform_script.js 파일 보기

@@ -36,9 +36,6 @@ frappe.ready(function () {
function show_form() {
let web_form = new WebForm({
parent: $(".web-form-wrapper"),
is_new: web_form_doc.is_new,
is_form_editable: web_form_doc.is_form_editable,
web_form_name: web_form_doc.name,
});
let doc = reference_doc || {};
setup_fields(web_form_doc, doc);
@@ -58,7 +55,7 @@ frappe.ready(function () {
function setup_fields(web_form_doc, doc_data) {
web_form_doc.web_form_fields.forEach((df) => {
df.is_web_form = true;
df.read_only = !web_form_doc.is_new && !web_form_doc.is_form_editable;
df.read_only = !web_form_doc.is_new && !web_form_doc.in_edit_mode;
if (df.fieldtype === "Table") {
df.get_data = () => {
let data = [];


+ 400
- 267
frappe/public/scss/website/web_form.scss 파일 보기

@@ -1,361 +1,494 @@
@import "../common/form";

[data-doctype="Web Form"] {
.page_content {
max-width: 800px;
margin: auto;

h1 {
font-size: 2.25rem;
margin-top: 0;
margin-bottom: 0;
}

.web-form-banner-image {
margin: -4rem -14rem 5rem;
padding-top: 3rem;
position: relative;

img {
position: absolute;
object-fit: cover;
.page-content-wrapper {
.container {
.page-header {
width: 100%;
height: 250px;
z-index: -1;
}
}

.web-form-header {
border: 1px solid var(--dark-border-color);
border-bottom: none;
border-top-left-radius: var(--border-radius-md);
border-top-right-radius: var(--border-radius-md);
background-color: var(--fg-color);
padding: 2rem 2rem 0;

.breadcrumb-container {
padding: 0px;
margin: 0 0 2rem;

ol.breadcrumb {
padding: 0px;
img {
margin: -1rem 0rem -10.5rem;
object-fit: cover;
width: 100%;
height: 250px;
z-index: -1;
}
}

.web-form-head {
border-bottom: 1px solid var(--dark-border-color);
padding-bottom: 1.25rem;
.page_content {
max-width: 800px;
margin: auto;

.title {
display: flex;
justify-content: space-between;
h1 {
font-size: 2.25rem;
margin-top: 0;
margin-bottom: 0;
padding-bottom: 2px;
}

.web-form-introduction {
color: var(--text-muted);
margin-top: 1.25rem;
.web-form-header {
border: 1px solid var(--dark-border-color);
border-bottom: none;
border-top-left-radius: var(--border-radius-md);
border-top-right-radius: var(--border-radius-md);
background-color: var(--fg-color);
padding: 2rem 2rem 0;

p {
color: var(--text-muted);
.breadcrumb-container {
padding: 0px;
margin: 0 0 2rem;

ol.breadcrumb {
padding: 0px;
}
}
}
}
}

.web-form {
background-color: var(--fg-color);
padding: 1.25rem 2rem 2rem;
border: 1px solid var(--dark-border-color);
border-top: none;
border-bottom-left-radius: var(--border-radius);
border-bottom-right-radius: var(--border-radius);

.web-form-wrapper {
.form-control {
color: var(--text-color);
background-color: var(--control-bg);
}
.web-form-head {
border-bottom: 1px solid var(--dark-border-color);
padding-bottom: 1.25rem;

.form-section {
.section-head {
font-weight: bold;
font-size: var(--text-xl);
padding: var(--padding-md) 0;
}
}
.title {
display: flex;
justify-content: space-between;
flex-wrap: wrap;
gap: 1rem;

.form-column {
padding: 0 var(--padding-sm);
.web-form-title p {
margin-bottom: 0;
}

&:first-child {
padding-left: 0;
}
.indicator-pill {
margin-top: 7px;
}

&:last-child {
padding-right: 0;
}
.web-form-actions {
display: flex;
align-items: center;
justify-content: flex-end;
flex: 1;

.btn {
font-size: var(--text-base);
}
}
}

@include media-breakpoint-down(sm) {
padding: 0;
.web-form-introduction {
color: var(--text-muted);
margin-top: 1.25rem;

p {
color: var(--text-muted);
}
}
}
}

.web-form-skeleton {
.box-group {
display: flex;
gap: 20px;
margin-bottom: 15px;
.web-form {
background-color: var(--fg-color);
padding: 1.25rem 2rem 2rem;
border: 1px solid var(--dark-border-color);
border-top: none;
border-bottom-left-radius: var(--border-radius);
border-bottom-right-radius: var(--border-radius);

.web-form-wrapper {
.form-control {
color: var(--text-color);
background-color: var(--control-bg);
}

.box-container {
width: 100%;
.form-section {
.section-head {
font-weight: bold;
font-size: var(--text-xl);
padding: var(--padding-md) 0;
}
}

.box {
background-color: var(--control-bg);
border-radius: var(--border-radius);
.form-column {
padding: 0 var(--padding-sm);

.frappe-control[data-fieldtype="Rating"] {
.like-disabled-input {
background-color: unset;
padding-left: 0px;

.rating {
cursor: default;
}
}
}

.box-label {
height: 20px;
width: 100px;
margin-bottom: 0.5rem;
&:first-child {
padding-left: 0;
}

.box-area {
height: 34px;
width: 100%;
&:last-child {
padding-right: 0;
}

@include media-breakpoint-down(xs) {
padding: 0;
}
}
}
}
}

.web-form-footer {
margin-top: 1rem;
.web-form-skeleton {
.box-group {
display: flex;
flex-wrap: wrap;

.web-form-actions {
display: flex;
justify-content: space-between;
.box-container {
width: 100%;
padding: 0 var(--padding-sm);
margin-bottom: 15px;

.btn {
font-size: var(--font-size-base);
&:first-child {
padding-left: 0;
}

&:last-child {
padding-right: 0;
}

@include media-breakpoint-down(xs) {
padding: 0;
}

.box {
background-color: var(--control-bg);
border-radius: var(--border-radius);
}

.box-label {
height: 20px;
width: 100px;
margin-bottom: 0.5rem;
}

.box-area {
height: 34px;
width: 100%;
}
}
}
}
}

.center-area {
padding: 0.5rem;
display: flex;
align-items: center;
.web-form-footer {
margin-top: 1rem;

.slides-progress {
.web-form-actions {
display: flex;
margin-right: .5rem;

.slide-step {
@include flex(flex, center, center, null);

height: 18px;
width: 18px;
border-radius: var(--border-radius-full);
border: 1px solid var(--gray-300);
margin: 0 var(--margin-xs);
background-color: var(--card-bg);

.slide-step-indicator {
height: 6px;
width: 6px;
background-color: var(--gray-300);
border-radius: var(--border-radius-full);
}
justify-content: space-between;
flex-wrap: wrap;

.slide-step-complete {
display: none;
.btn {
font-size: var(--text-base);
}

.icon-xs {
height: 10px;
width: 10px;
}
.btn-link {
padding-left: 0px;
color: var(--text-color);

&:hover {
color: var(--text-on-light-blue);
}
}

&.active {
border: 1px solid var(--primary);
.left-area {
display: flex;
flex: 1;

.slide-step-indicator {
display: block;
background-color: var(--primary);
}
@include media-breakpoint-down(sm) {
order: 1
}
}

&.step-success:not(.active) {
background-color: var(--primary);
border: 1px solid var(--primary);
.center-area {
display: flex;
align-items: center;
font-size: var(--text-base);

.slides-progress {
display: flex;

.slide-step {
@include flex(flex, center, center, null);

height: 18px;
width: 18px;
border-radius: var(--border-radius-full);
border: 1px solid var(--gray-300);
margin: 0 var(--margin-xs);
background-color: var(--card-bg);

.slide-step-indicator {
height: 6px;
width: 6px;
background-color: var(--gray-300);
border-radius: var(--border-radius-full);
}

.slide-step-indicator {
display: none;
}
.slide-step-complete {
display: none;

.icon-xs {
height: 10px;
width: 10px;
}
}

&.active {
border: 1px solid var(--primary);

.slide-step-indicator {
display: block;
background-color: var(--primary);
}
}

&.step-success:not(.active) {
background-color: var(--primary);
border: 1px solid var(--primary);

.slide-step-complete {
display: flex;
.slide-step-indicator {
display: none;
}

.icon use {
stroke-width: 2;
stroke: var(--white);
.slide-step-complete {
display: flex;

.icon use {
stroke-width: 2;
stroke: var(--white);
}
}
}

@include media-breakpoint-down(xs) {
width: 16px;
height: 16px;
}
}
}

@include media-breakpoint-down(sm) {
order: 0;
width: 100%;
justify-content: center;
margin-bottom: 1.5rem;
}
}
}
}
}
}
}

.attachments {
margin-top: 2rem;
padding: 2rem;
border-radius: var(--border-radius);
border: 1px solid var(--dark-border-color);

.attachment {
display: flex;
justify-content: space-between;
gap: 6px;
color: var(--text-muted);
font-size: var(--text-md);

&:hover {
text-decoration: none;
.file-name span {
text-decoration: underline;
.right-area {
display: flex;
justify-content: flex-end;
flex: 1;

@include media-breakpoint-down(sm) {
order: 2
}
}
}
}
}
}
}

.success-page {
background-color: var(--fg-color);
padding: 2rem;
border: 1px solid var(--dark-border-color);
border-radius: var(--border-radius);
text-align: center;

svg.icon {
width: 5rem;
height: 5rem;
margin: 1rem;
}
.attachments {
margin-top: 2rem;
padding: 2rem;
border-radius: var(--border-radius);
border: 1px solid var(--dark-border-color);

h2 {
margin-top: 0;
margin-bottom: 0;
}
.attachment {
display: flex;
justify-content: space-between;
gap: 6px;
color: var(--text-muted);
font-size: var(--text-md);

.success-message {
margin-bottom: 1.6rem;
}
}
&:hover {
text-decoration: none;
.file-name span {
text-decoration: underline;
}
}
}
}

.web-list-container {
min-height: 470px;
border: 1px solid var(--dark-border-color);
border-radius: var(--border-radius-md);
padding: 2rem;
.success-page {
background-color: var(--fg-color);
padding: 5rem 2rem;
margin-top: 3rem;
border: 1px solid var(--dark-border-color);
border-radius: var(--border-radius);
text-align: center;

.web-list-header {
display: flex;
justify-content: space-between;
border-bottom: 1px solid var(--dark-border-color);
padding-bottom: 1.25rem;
.success-header {
display: flex;
justify-content: center;
align-items: center;
gap: 0.5rem;
margin-top: 1rem;

.web-list-actions {
align-self: center;
}
}
.success-icon {
width: 3rem;
height: 3rem;
margin: 0;

.web-list-filters {
display: flex;
flex-wrap: wrap;
margin: 1.25rem 0;
gap: 10px;

.form-group.frappe-control {
min-width: 145px;
padding: 0px;
margin: 0px;
align-self: center;

.checkbox {
.input-xs {
height: var(--checkbox-size);
@include media-breakpoint-down(sm) {
width: 2rem;
height: 2rem;
}
}

.help-box {
display: none;
.success-title {
margin-top: 0;
margin-bottom: 0;
}
}

.input-xs {
height: 28px;
line-height: 1.2;
.success-body .success-message {
margin: 1rem 0rem 1.5rem;
}

.success-footer a {
margin: 0rem 0.3rem 1rem;
}
}
}

.web-list-table {
overflow: auto;
.web-list-container {
min-height: 470px;
border: 1px solid var(--dark-border-color);
border-radius: var(--border-radius-md);
padding: 2rem;

.table {
border-bottom: 1px solid var(--border-color);
border-top: 1px solid var(--border-color);
.web-list-header {
display: flex;
justify-content: space-between;
flex-wrap: wrap;
gap: 1rem;
border-bottom: 1px solid var(--dark-border-color);
padding-bottom: 1.25rem;

thead tr {
th {
border: 0;
font-size: 13px;
font-weight: normal;
color: var(--text-muted);
.web-list-actions {
display: flex;
align-items: center;
justify-content: flex-end;
flex: 1;
}
}

input[type="checkbox"] {
margin-bottom: -2px;
.web-list-filters {
display: flex;
flex-wrap: wrap;
margin: 1.25rem 0;
gap: 10px;

.form-group.frappe-control {
min-width: 145px;
padding: 0px;
margin: 0px;
align-self: center;

.checkbox {
.input-xs {
height: var(--checkbox-size);
}

.help-box {
display: none;
}
}

.input-xs {
height: 28px;
line-height: 1.2;
}
}
}

tbody tr {
color: var(--text-color);
cursor: pointer;
.web-list-table {
overflow: auto;

td {
font-size: 13px;
.table {
border-bottom: 1px solid var(--border-color);
border-top: 1px solid var(--border-color);

thead tr {
th {
border: 0;
font-size: 13px;
font-weight: normal;
color: var(--text-muted);

input[type="checkbox"] {
margin-bottom: -2px;
}
}
}

tbody tr {
color: var(--text-color);
cursor: pointer;

td {
font-size: 13px;
border-top: 1px solid var(--border-color);
max-width: 160px;

.ql-editor, p {
width: max-content;
max-width: 150px;
margin-bottom: 0;

&.read-mode {
display: inline-flex;
gap: 5px;
}
}
}
}

input[type="checkbox"] {
margin-top: 2px;
}

.list-col-checkbox {
width: 1rem;
}

.list-col-serial {
width: 1.5rem;
}
}
}

input[type="checkbox"] {
margin-top: 2px;
.no-result {
min-height: 330px;
border-top: 1px solid var(--border-color);
}
}

.list-col-checkbox {
width: 1rem;
.web-list-footer {
text-align: right;
}
}

.list-col-serial {
width: 1.5rem;
.breadcrumb-container.container {
@include media-breakpoint-up(sm) {
padding-left: 0;
}
}

.no-result {
min-height: 330px;
border-top: 1px solid var(--border-color);
@include media-breakpoint-down(lg) {
padding-left: 1.5rem;
padding-right: 1.5rem;
}
}

.web-list-footer {
text-align: right;
}
}

.breadcrumb-container.container {
@include media-breakpoint-up(sm) {
@include media-breakpoint-down(lg) {
padding-left: 0;
padding-right: 0;
}
}
}


+ 65
- 55
frappe/website/doctype/web_form/templates/web_form.html 파일 보기

@@ -2,49 +2,44 @@

{% block breadcrumbs %}{% endblock %}

{% block header %}
{% if banner_image %}
<!-- banner image -->
<img class="web-form-banner-image" src="{{ banner_image }}" alt="Banner Image">
{% endif %}
{% endblock %}

{% macro header_buttons() %}
{% if allow_print and not is_new %}
{% if allow_edit and in_view_mode %}
<!-- edit button -->
<a href="/{{ route }}/{{ doc_name }}/edit" class="edit-button btn btn-default btn-sm">{{ _("Edit Response", null, "Button in web form") }}</a>
{% endif %}

{% if allow_print and in_view_mode %}
{% set print_format_url = "/printview?doctype=" + doc_type + "&name=" + doc_name + "&format=" + print_format %}
<!-- print button -->
<a href="{{ print_format_url }}" target="_blank" class="print-btn btn btn-light btn-sm ml-2">
<a href="{{ print_format_url }}" target="_blank" class="print-btn btn btn-default btn-sm ml-2">
<svg class="icon icon-sm"><use href="#icon-printer"></use></svg>
</a>
{% endif %}

{% if allow_edit and doc_name and not is_form_editable %}
<!-- edit button -->
<a href="/{{ route }}/{{ doc_name }}/edit" class="edit-button btn btn-primary btn-sm ml-2">{{ _("Edit", null, "Button in web form") }}</a>
{% endif %}
{% endmacro %}

{% macro action_buttons() %}
{% if is_new or is_form_editable %}
<div class="left-area">
<!-- clear button -->
<a href="/{{ path }}" class="clear-btn btn btn-light btn-md">
{% if is_form_editable %}
{{ _("Reset Form", null, "Button in web form") }}
{% else %}
{{ _("Clear Form", null, "Button in web form") }}
{% endif %}
</a>
</div>
<div class="center-area paging"></div>
<div class="right-area">
<div class="left-area"></div>
<div class="center-area paging"></div>
<div class="right-area">
{% if not in_view_mode %}
<!-- discard button -->
<button class="discard-btn btn btn-default btn-sm">
{{ _("Discard", null, "Button in web form") }}
</button>
<!-- submit button -->
<button type="submit" class="submit-btn btn btn-primary btn-md ml-2">{{ button_label or _("Submit", null, "Button in web form") }}</button>
</div>
{% endif %}
<button type="submit" class="submit-btn btn btn-primary btn-sm ml-2">{{ button_label or _("Submit", null, "Button in web form") }}</button>
{% endif %}
</div>
{% endmacro %}

{% block page_content %}
<!-- banner image -->
{% if banner_image %}
<div class="web-form-banner-image">
<img src="{{ banner_image }}" alt="Banner Image">
</div>
{% endif %}

<!-- web form container -->
<div class="web-form-container">
<!-- breadcrumb -->
@@ -61,12 +56,20 @@
{% endif %}
<div class="web-form-head">
<div class="title">
<h1>{{ _(title) }}</h1>
<div class="web-form-title ellipsis">
{% if show_list and not is_new %}
<h1 class="ellipsis">{{ _(web_form_title) }}</h1>
<p class="ellipsis">{{ _(title) }}</p>
{% else %}
<h1 class="ellipsis">{{ _(title) }}</h1>
{% endif %}
</div>
<span class="indicator-pill orange hide">Not Saved</span>
<div class="web-form-actions">
{{ header_buttons() }}
</div>
</div>
{% if is_new and introduction_text %}
{% if introduction_text and (is_new or in_edit_mode) %}
<div class="web-form-introduction">{{ introduction_text }}</div>
{% endif %}
</div>
@@ -115,30 +118,37 @@

<!-- success page -->
<div class="success-page hide">
<svg class="icon">
<use href="#icon-solid-success"></use>
</svg>
<h2 class="success-title">{{ _(success_title) or _("Submitted") }}</h2>
<p class="success-message">{{ _(success_message) or _("Thank you for spending your valuable time to fill this form") }}</p>

{% if success_url %}
<div class="success_url_message">
<p>
<span>Click on this </span>
<a href="{{ success_url }}">{{_("URL")}}</a>
<span> if you are not redirected within </span>
<span class="time">5</span>
<span> seconds.</span>
</p>
</div>
{% else %}
{% if show_list %}
<a href="/{{ route }}/list" class="show-list-button btn btn-light btn-md mr-2">{{ _("See previous responses", null, "Button in web form") }}</a>
{% endif %}
{% if not login_required or allow_multiple %}
<a href="/{{ route }}/new" class="new-btn btn btn-light btn-md">{{ _("Submit another response", null, "Button in web form") }}</a>
<div class="success-header">
<svg class="success-icon icon">
<use href="#icon-solid-success"></use>
</svg>
<h2 class="success-title">{{ _(success_title) or _("Submitted") }}</h2>
</div>

<div class="success-body">
<p class="success-message">{{ _(success_message) or _("Thank you for spending your valuable time to fill this form") }}</p>
</div>

<div class="success-footer">
{% if success_url %}
<div class="success_url_message">
<p>
<span>Click on this </span>
<a href="{{ success_url }}">{{_("URL")}}</a>
<span> if you are not redirected within </span>
<span class="time">5</span>
<span> seconds.</span>
</p>
</div>
{% else %}
{% if show_list %}
<a href="/{{ route }}/list" class="show-list-button btn btn-default btn-md">{{ _("See previous responses", null, "Button in web form") }}</a>
{% endif %}
{% if not login_required or allow_multiple %}
<a href="/{{ route }}/new" class="new-btn btn btn-default btn-md">{{ _("Submit another response", null, "Button in web form") }}</a>
{% endif %}
{% endif %}
{% endif %}
</div>
</div>

{% endblock page_content %}


+ 6
- 6
frappe/website/doctype/web_form/templates/web_form_skeleton.html 파일 보기

@@ -1,10 +1,10 @@
<div class="web-form-skeleton">
<div class="box-group">
<div class="box-container">
<div class="box-container col-sm-6">
<div class="box box-label"></div>
<div class="box box-area"></div>
</div>
<div class="box-container">
<div class="box-container col-sm-6">
<div class="box box-label"></div>
<div class="box box-area"></div>
</div>
@@ -16,21 +16,21 @@
</div>
</div>
<div class="box-group">
<div class="box-container">
<div class="box-container col-sm-6">
<div class="box box-label"></div>
<div class="box box-area"></div>
</div>
<div class="box-container">
<div class="box-container col-sm-6">
<div class="box box-label"></div>
<div class="box box-area"></div>
</div>
</div>
<div class="box-group">
<div class="box-container">
<div class="box-container col-sm-6">
<div class="box box-label"></div>
<div class="box box-area"></div>
</div>
<div class="box-container">
<div class="box-container col-sm-6">
<div class="box box-label"></div>
<div class="box box-area"></div>
</div>


+ 3
- 1
frappe/website/doctype/web_form/templates/web_list.html 파일 보기

@@ -7,7 +7,9 @@
<div class="web-list-container">
<!-- list -->
<div class="web-list-header">
<h1>{{ _(list_title or title) }}</h1>
<div class="web-list-title ellipsis">
<h1 class="ellipsis">{{ _(list_title or title) }}</h1>
</div>
<div class="web-list-actions">
{%- if allow_multiple -%}
<a class="btn btn-primary btn-sm button-new" href="/{{ route }}/new">New</a>


+ 1
- 1
frappe/website/doctype/web_form/test_web_form.py 파일 보기

@@ -71,7 +71,7 @@ class TestWebForm(unittest.TestCase):
def test_webform_render(self):
set_request(method="GET", path="manage-events/new")
content = get_response_content("manage-events/new")
self.assertIn("<h1>New Manage Events</h1>", content)
self.assertIn('<h1 class="ellipsis">New Manage Events</h1>', content)
self.assertIn('data-doctype="Web Form"', content)
self.assertIn('data-path="manage-events/new"', content)
self.assertIn('source-type="Generator"', content)

+ 54
- 17
frappe/website/doctype/web_form/web_form.js 파일 보기

@@ -1,4 +1,28 @@
frappe.ui.form.on("Web Form", {
setup: function () {
frappe.meta.docfield_map["Web Form Field"].fieldtype.formatter = (value) => {
const prefix = {
"Page Break": "--red-600",
"Section Break": "--blue-600",
"Column Break": "--yellow-600",
};
if (prefix[value]) {
value = `<span class="bold" style="color: var(${prefix[value]})">${value}</span>`;
}
return value;
};

frappe.meta.docfield_map["Web Form Field"].fieldname.formatter = (value) => {
if (!value) return;
return frappe.unscrub(value);
};

frappe.meta.docfield_map["Web Form List Column"].fieldname.formatter = (value) => {
if (!value) return;
return frappe.unscrub(value);
};
},

refresh: function (frm) {
// show is-standard only if developer mode
frm.get_field("is_standard").toggle(frappe.boot.developer_mode);
@@ -32,6 +56,14 @@ frappe.ui.form.on("Web Form", {
frm.scroll_to_field("web_form_fields");
frappe.throw(__("Atleast one field is required in Web Form Fields Table"));
}

let page_break_count = frm.doc.web_form_fields.filter(
(f) => f.fieldtype == "Page Break"
).length;

if (page_break_count >= 10) {
frappe.throw(__("There can be only 9 Page Break fields in a Web Form"));
}
},

add_publish_button(frm) {
@@ -97,7 +129,7 @@ frappe.ui.form.on("Web Form", {

get_fields_for_doctype(doc.doc_type).then((fields) => {
let as_select_option = (df) => ({
label: df.label + " (" + df.fieldtype + ")",
label: df.label,
value: df.fieldname,
});
update_options(fields.map(as_select_option));
@@ -147,9 +179,19 @@ frappe.ui.form.on("Web Form List Column", {

frappe.ui.form.on("Web Form Field", {
fieldtype: function (frm, doctype, name) {
var doc = frappe.get_doc(doctype, name);
let doc = frappe.get_doc(doctype, name);

if (doc.fieldtype == "Page Break") {
let page_break_count = frm.doc.web_form_fields.filter(
(f) => f.fieldtype == "Page Break"
).length;
page_break_count >= 10 &&
frappe.throw(__("There can be only 9 Page Break fields in a Web Form"));
}

if (["Section Break", "Column Break", "Page Break"].includes(doc.fieldtype)) {
doc.fieldname = "";
doc.label = "";
doc.options = "";
frm.refresh_field("web_form_fields");
}
@@ -188,23 +230,18 @@ function get_fields_for_doctype(doctype) {
function render_list_settings_message(frm) {
// render list setting message
if (frm.fields_dict["list_setting_message"] && !frm.doc.login_required) {
const switch_to_form_settings_tab = `
<span class="bold pointer" title="${__("Switch to Form Settings Tab")}">
${__("Form Settings Tab")}
</span>
const go_to_login_required_field = `
<code class="pointer" title="${__("Go to Login Required field")}">
${__("login_required")}
</code>
`;
let message = __(
"Login is required to see web form list view. Enable {0} to see list settings",
[go_to_login_required_field]
);
$(frm.fields_dict["list_setting_message"].wrapper)
.html(
$(
`<div class="form-message blue">
${__(
"Login is required to see web form list view. Enable <code>login_required</code> from {0} to see list settings",
[switch_to_form_settings_tab]
)}
</div>`
)
)
.find("span")
.html($(`<div class="form-message blue">${message}</div>`))
.find("code")
.click(() => frm.scroll_to_field("login_required"));
} else {
$(frm.fields_dict["list_setting_message"].wrapper).empty();


+ 65
- 63
frappe/website/doctype/web_form/web_form.json 파일 보기

@@ -5,50 +5,50 @@
"document_type": "Document",
"engine": "InnoDB",
"field_order": [
"title_and_route_tab",
"form_tab",
"title",
"route",
"published",
"column_break_4",
"column_break_1",
"doc_type",
"module",
"is_standard",
"introduction",
"section_break_1",
"introduction_text",
"form_settings_tab",
"web_form_fields",
"settings_tab",
"login_required",
"allow_multiple",
"allow_edit",
"allow_delete",
"column_break_18",
"column_break_2",
"apply_document_permissions",
"allow_print",
"print_format",
"allow_comments",
"show_attachments",
"allow_incomplete",
"form_fields",
"web_form_fields",
"section_break_2",
"max_attachment_size",
"list_settings_tab",
"section_break_3",
"list_setting_message",
"show_list",
"list_title",
"list_columns",
"sidebar_settings_tab",
"section_break_4",
"show_sidebar",
"website_sidebar",
"customization_tab",
"button_label",
"banner_image",
"column_break_37",
"column_break_3",
"breadcrumbs",
"section_break_43",
"section_break_5",
"success_title",
"success_url",
"column_break_41",
"column_break_4",
"success_message",
"scripting_style_tab",
"section_break_6",
"client_script",
"custom_css"
],
@@ -81,10 +81,6 @@
"label": "Module",
"options": "Module Def"
},
{
"fieldname": "column_break_4",
"fieldtype": "Column Break"
},
{
"default": "0",
"fieldname": "is_standard",
@@ -158,12 +154,6 @@
"fieldtype": "Check",
"label": "Allow Incomplete Forms"
},
{
"collapsible": 1,
"fieldname": "introduction",
"fieldtype": "Section Break",
"label": "Introduction"
},
{
"fieldname": "introduction_text",
"fieldtype": "Text Editor",
@@ -250,21 +240,6 @@
"label": "List Columns",
"options": "Web Form List Column"
},
{
"fieldname": "title_and_route_tab",
"fieldtype": "Tab Break",
"label": "Title & Route"
},
{
"collapsible": 1,
"fieldname": "form_fields",
"fieldtype": "Section Break",
"label": "Form Fields"
},
{
"fieldname": "column_break_18",
"fieldtype": "Column Break"
},
{
"fieldname": "website_sidebar",
"fieldtype": "Link",
@@ -277,62 +252,89 @@
"label": "List Setting Message"
},
{
"fieldname": "form_settings_tab",
"fieldname": "customization_tab",
"fieldtype": "Tab Break",
"label": "Form Settings"
"label": "Customization"
},
{
"collapsible": 1,
"collapsible_depends_on": "show_list",
"fieldname": "list_settings_tab",
"fieldtype": "Tab Break",
"label": "List Settings"
"fieldname": "success_title",
"fieldtype": "Data",
"label": "Success Title"
},
{
"collapsible": 1,
"fieldname": "sidebar_settings_tab",
"fieldtype": "Tab Break",
"label": "Sidebar Settings"
"fieldname": "banner_image",
"fieldtype": "Attach Image",
"label": "Banner Image"
},
{
"fieldname": "scripting_style_tab",
"fieldname": "form_tab",
"fieldtype": "Tab Break",
"label": "Scripting / Style"
"label": "Form"
},
{
"fieldname": "customization_tab",
"fieldname": "column_break_1",
"fieldtype": "Column Break"
},
{
"fieldname": "section_break_1",
"fieldtype": "Section Break"
},
{
"fieldname": "settings_tab",
"fieldtype": "Tab Break",
"label": "Customization"
"label": "Settings"
},
{
"fieldname": "success_title",
"fieldtype": "Data",
"label": "Success Title"
"fieldname": "column_break_2",
"fieldtype": "Column Break"
},
{
"fieldname": "banner_image",
"fieldtype": "Attach Image",
"label": "Banner Image"
"collapsible": 1,
"fieldname": "section_break_2",
"fieldtype": "Section Break"
},
{
"fieldname": "column_break_41",
"collapsible": 1,
"collapsible_depends_on": "show_list",
"fieldname": "section_break_3",
"fieldtype": "Section Break",
"label": "List Settings"
},
{
"collapsible": 1,
"collapsible_depends_on": "show_sidebar",
"fieldname": "section_break_4",
"fieldtype": "Section Break",
"label": "Sidebar Settings"
},
{
"fieldname": "column_break_3",
"fieldtype": "Column Break"
},
{
"fieldname": "section_break_43",
"collapsible": 1,
"collapsible_depends_on": "eval: doc.success_title || doc.success_message || doc.success_url",
"fieldname": "section_break_5",
"fieldtype": "Section Break",
"label": "After Submission"
},
{
"fieldname": "column_break_37",
"fieldname": "column_break_4",
"fieldtype": "Column Break"
},
{
"collapsible": 1,
"collapsible_depends_on": "eval: doc.client_script || doc.custom_css",
"fieldname": "section_break_6",
"fieldtype": "Section Break",
"label": "Scripting / Style"
}
],
"has_web_view": 1,
"icon": "icon-edit",
"is_published_field": "published",
"links": [],
"modified": "2022-08-11 16:27:25.914627",
"modified": "2022-08-17 18:58:49.451658",
"modified_by": "Administrator",
"module": "Website",
"name": "Web Form",


+ 18
- 16
frappe/website/doctype/web_form/web_form.py 파일 보기

@@ -124,7 +124,8 @@ def get_context(context):

def get_context(self, context):
"""Build context to render the `web_form.html` template"""
context.is_form_editable = False
context.in_edit_mode = False
context.in_view_mode = False
self.set_web_form_module()

if frappe.form_dict.is_list:
@@ -156,10 +157,14 @@ def get_context(context):
frappe.redirect(f"/{self.route}/new")

if frappe.form_dict.is_edit and not self.allow_edit:
context.in_view_mode = True
frappe.redirect(f"/{self.route}/{frappe.form_dict.name}")

if frappe.form_dict.is_edit:
context.is_form_editable = True
context.in_edit_mode = True

if frappe.form_dict.is_read:
context.in_view_mode = True

if (
not frappe.form_dict.is_edit
@@ -167,7 +172,7 @@ def get_context(context):
and self.allow_edit
and frappe.form_dict.name
):
context.is_form_editable = True
context.in_edit_mode = True
frappe.redirect(f"/{frappe.local.path}/edit")

if (
@@ -179,6 +184,7 @@ def get_context(context):
):
name = frappe.db.get_value(self.doc_type, {"owner": frappe.session.user}, "name")
if name:
context.in_view_mode = True
frappe.redirect(f"/{self.route}/{name}")

# Show new form when
@@ -203,7 +209,9 @@ def get_context(context):

# load web form doc
context.web_form_doc = self.as_dict(no_nulls=True)
context.web_form_doc.update(dict_with_keys(context, ["is_list", "is_new", "is_form_editable"]))
context.web_form_doc.update(
dict_with_keys(context, ["is_list", "is_new", "in_edit_mode", "in_view_mode"])
)

if self.show_sidebar and self.website_sidebar:
context.sidebar_items = get_sidebar_items(self.website_sidebar)
@@ -278,17 +286,11 @@ def get_context(context):
if frappe.form_dict.name:
context.doc_name = frappe.form_dict.name
context.reference_doc = frappe.get_doc(self.doc_type, context.doc_name)
context.title = strip_html(
context.reference_doc.get(context.reference_doc.meta.get_title_field())
context.web_form_title = context.title
context.title = (
strip_html(context.reference_doc.get(context.reference_doc.meta.get_title_field()))
or context.doc_name
)
if context.is_form_editable and context.parents:
context.parents.append(
{
"label": _(context.title),
"route": f"{self.route}/{context.doc_name}",
}
)
context.title = _("Editing {0}").format(context.title)
context.reference_doc.add_seen()
context.reference_doctype = context.reference_doc.doctype
context.reference_name = context.reference_doc.name
@@ -309,7 +311,7 @@ def get_context(context):
context.reference_doc.doctype, context.reference_doc.name
)

context.reference_doc = json.loads(context.reference_doc.as_json())
context.reference_doc = context.reference_doc.as_dict(no_nulls=True)

def add_custom_context_and_script(self, context):
"""Update context from module if standard and append script"""
@@ -481,7 +483,7 @@ def accept(web_form, data, docname=None):
for field in web_form.web_form_fields:
fieldname = field.fieldname
df = meta.get_field(fieldname)
value = data.get(fieldname, None)
value = data.get(fieldname, "")

if df and df.fieldtype in ("Attach", "Attach Image"):
if value and "data:" and "base64" in value:


+ 5
- 4
frappe/website/doctype/web_form_field/web_form_field.json 파일 보기

@@ -32,20 +32,20 @@
"fieldname": "fieldname",
"fieldtype": "Select",
"in_list_view": 1,
"label": "Fieldname"
"label": "Field"
},
{
"fieldname": "fieldtype",
"fieldtype": "Select",
"in_list_view": 1,
"label": "Fieldtype",
"options": "Attach\nAttach Image\nCheck\nCurrency\nData\nDate\nDatetime\nDuration\nFloat\nHTML\nInt\nLink\nPassword\nRating\nSelect\nSignature\nSmall Text\nText\nText Editor\nTable\nTime\nSection Break\nColumn Break\nPage Break"
"options": "Attach\nAttach Image\nCheck\nCurrency\nColor\nData\nDate\nDatetime\nDuration\nFloat\nHTML\nInt\nLink\nPassword\nRating\nSelect\nSignature\nSmall Text\nText\nText Editor\nTable\nTime\nSection Break\nColumn Break\nPage Break"
},
{
"fieldname": "label",
"fieldtype": "Data",
"in_list_view": 1,
"label": "Label"
"label": "Custom Label"
},
{
"default": "0",
@@ -58,6 +58,7 @@
"default": "0",
"fieldname": "reqd",
"fieldtype": "Check",
"in_list_view": 1,
"label": "Mandatory"
},
{
@@ -146,7 +147,7 @@
],
"istable": 1,
"links": [],
"modified": "2022-08-10 12:59:51.170546",
"modified": "2022-08-22 17:22:39.026893",
"modified_by": "Administrator",
"module": "Website",
"name": "Web Form Field",


+ 3
- 3
frappe/website/doctype/web_form_list_column/web_form_list_column.json 파일 보기

@@ -15,14 +15,14 @@
"fieldname": "fieldname",
"fieldtype": "Select",
"in_list_view": 1,
"label": "Fieldname",
"label": "Field",
"reqd": 1
},
{
"fieldname": "label",
"fieldtype": "Data",
"in_list_view": 1,
"label": "Label"
"label": "Custom Label"
},
{
"fieldname": "fieldtype",
@@ -35,7 +35,7 @@
"index_web_pages_for_search": 1,
"istable": 1,
"links": [],
"modified": "2022-06-21 17:22:14.978947",
"modified": "2022-08-17 19:09:01.417841",
"modified_by": "Administrator",
"module": "Website",
"name": "Web Form List Column",


불러오는 중...
취소
저장