Skip to content

Commit fa99b4e

Browse files
authored
Merge from docusealco/wip
2 parents ae89193 + 83c793a commit fa99b4e

24 files changed

Lines changed: 368 additions & 73 deletions

Gemfile.lock

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -77,24 +77,27 @@ GEM
7777
annotaterb (4.14.0)
7878
arabic-letter-connector (0.1.1)
7979
ast (2.4.3)
80-
aws-eventstream (1.3.0)
81-
aws-partitions (1.1027.0)
82-
aws-sdk-core (3.214.0)
80+
aws-eventstream (1.4.0)
81+
aws-partitions (1.1197.0)
82+
aws-sdk-core (3.240.0)
8383
aws-eventstream (~> 1, >= 1.3.0)
8484
aws-partitions (~> 1, >= 1.992.0)
8585
aws-sigv4 (~> 1.9)
86+
base64
87+
bigdecimal
8688
jmespath (~> 1, >= 1.6.1)
87-
aws-sdk-kms (1.96.0)
88-
aws-sdk-core (~> 3, >= 3.210.0)
89+
logger
90+
aws-sdk-kms (1.118.0)
91+
aws-sdk-core (~> 3, >= 3.239.1)
8992
aws-sigv4 (~> 1.5)
90-
aws-sdk-s3 (1.176.1)
91-
aws-sdk-core (~> 3, >= 3.210.0)
93+
aws-sdk-s3 (1.208.0)
94+
aws-sdk-core (~> 3, >= 3.234.0)
9295
aws-sdk-kms (~> 1)
9396
aws-sigv4 (~> 1.5)
9497
aws-sdk-secretsmanager (1.110.0)
9598
aws-sdk-core (~> 3, >= 3.210.0)
9699
aws-sigv4 (~> 1.5)
97-
aws-sigv4 (1.10.1)
100+
aws-sigv4 (1.12.1)
98101
aws-eventstream (~> 1, >= 1.0.2)
99102
azure-storage-blob (2.0.3)
100103
azure-storage-common (~> 2.0)

app/controllers/submissions_controller.rb

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,14 +53,15 @@ def create
5353
else
5454
submissions_attrs = submissions_params[:submission].to_h.values
5555

56-
submissions_attrs, =
57-
Submissions::NormalizeParamUtils.normalize_submissions_params!(submissions_attrs, @template)
56+
submissions_attrs, _, new_fields =
57+
Submissions::NormalizeParamUtils.normalize_submissions_params!(submissions_attrs, @template, add_fields: true)
5858

5959
Submissions.create_from_submitters(template: @template,
6060
user: current_user,
6161
source: :invite,
6262
submitters_order: params[:preserve_order] == '1' ? 'preserved' : 'random',
6363
submissions_attrs:,
64+
new_fields:,
6465
params: params.merge('send_completed_email' => true))
6566
end
6667

app/javascript/application.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ import AutosizeField from './elements/autosize_field'
5252
import GoogleDriveFilePicker from './elements/google_drive_file_picker'
5353
import OpenModal from './elements/open_modal'
5454
import BarChart from './elements/bar_chart'
55+
import FieldCondition from './elements/field_condition'
5556

5657
import * as TurboInstantClick from './lib/turbo_instant_click'
5758

@@ -142,6 +143,7 @@ safeRegisterElement('autosize-field', AutosizeField)
142143
safeRegisterElement('google-drive-file-picker', GoogleDriveFilePicker)
143144
safeRegisterElement('open-modal', OpenModal)
144145
safeRegisterElement('bar-chart', BarChart)
146+
safeRegisterElement('field-condition', FieldCondition)
145147

146148
safeRegisterElement('template-builder', class extends HTMLElement {
147149
connectedCallback () {
Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
export default class extends HTMLElement {
2+
connectedCallback () {
3+
this.targetId = this.dataset.targetId
4+
this.fieldId = this.dataset.fieldId
5+
this.action = (this.dataset.action || '').trim()
6+
this.expectedValue = this.dataset.value
7+
8+
this.targetEl = document.getElementById(this.targetId)
9+
this.sourceEl = document.getElementById(this.fieldId)
10+
11+
this.bindListeners()
12+
13+
this.evaluateAndApply()
14+
}
15+
16+
disconnectedCallback () {
17+
this.unbindListeners()
18+
}
19+
20+
bindListeners () {
21+
this.eventsFor(this.sourceEl).forEach((ev) => {
22+
this.sourceEl.addEventListener(ev, this.evaluateAndApply)
23+
})
24+
}
25+
26+
unbindListeners () {
27+
this.eventsFor(this.sourceEl).forEach((ev) => {
28+
this.sourceEl.removeEventListener(ev, this.evaluateAndApply)
29+
})
30+
}
31+
32+
eventsFor (el) {
33+
if (!el) return []
34+
35+
const tag = el.tagName.toLowerCase()
36+
37+
if (tag === 'textarea') return ['input']
38+
if (tag === 'input') return ['input', 'change']
39+
40+
return ['change']
41+
}
42+
43+
evaluateAndApply = () => {
44+
const fieldConditions = document.querySelectorAll(`field-condition[data-target-id="${this.targetId}"]`)
45+
46+
const result = [...fieldConditions].reduce((acc, cond) => {
47+
if (cond.dataset.operation === 'or') {
48+
acc.push(acc.pop() || cond.checkCondition())
49+
} else {
50+
acc.push(cond.checkCondition())
51+
}
52+
53+
return acc
54+
}, [])
55+
56+
this.apply(!result.includes(false))
57+
}
58+
59+
checkCondition () {
60+
const action = this.action
61+
const actual = this.getSourceValue()
62+
const expected = this.expectedValue
63+
64+
if (action === 'empty' || action === 'unchecked') return this.isEmpty(actual)
65+
if (action === 'not_empty' || action === 'checked') return !this.isEmpty(actual)
66+
67+
if (action === 'equal') {
68+
const list = Array.isArray(actual) ? actual : [actual]
69+
return list.filter((v) => v !== null && v !== undefined).map(String).includes(String(expected))
70+
}
71+
72+
if (action === 'contains') return this.contains(actual, expected)
73+
74+
if (action === 'not_equal') {
75+
const list = Array.isArray(actual) ? actual : [actual]
76+
return !list.filter((v) => v !== null && v !== undefined).map(String).includes(String(expected))
77+
}
78+
79+
if (action === 'does_not_contain') return !this.contains(actual, expected)
80+
81+
return true
82+
}
83+
84+
getSourceValue () {
85+
const el = this.sourceEl
86+
87+
if (!el) return
88+
89+
const tag = el.tagName.toLowerCase()
90+
const type = (el.getAttribute('type') || '').toLowerCase()
91+
92+
if (tag === 'select') return el.value
93+
if (tag === 'textarea') return el.value
94+
if (tag === 'input' && type === 'checkbox') return el.checked ? (el.value || '1') : null
95+
if (tag === 'input') return el.value
96+
97+
return el.value ?? null
98+
}
99+
100+
isEmpty (obj) {
101+
if (obj == null) return true
102+
103+
if (Array.isArray(obj)) {
104+
return obj.length === 0
105+
}
106+
107+
if (typeof obj === 'string') {
108+
return obj.trim().length === 0
109+
}
110+
111+
if (typeof obj === 'object') {
112+
return Object.keys(obj).length === 0
113+
}
114+
115+
if (obj === false) {
116+
return true
117+
}
118+
119+
return false
120+
}
121+
122+
contains (actual, expected) {
123+
if (expected === null || expected === undefined) return false
124+
125+
const exp = String(expected)
126+
127+
if (Array.isArray(actual)) return actual.filter((v) => v !== null && v !== undefined).map(String).includes(exp)
128+
129+
if (typeof actual === 'string') return actual.includes(exp)
130+
131+
return actual !== null && actual !== undefined && String(actual) === exp
132+
}
133+
134+
apply (passed) {
135+
const controls = this.targetEl.matches('input, select, textarea, button')
136+
? [this.targetEl]
137+
: Array.from(this.targetEl.querySelectorAll('input, select, textarea, button'))
138+
139+
if (passed) {
140+
this.targetEl.style.display = ''
141+
this.targetEl.labels.forEach((label) => { label.style.display = '' })
142+
143+
controls.forEach((c) => (c.disabled = false))
144+
} else {
145+
this.targetEl.style.display = 'none'
146+
this.targetEl.labels.forEach((label) => { label.style.display = 'none' })
147+
148+
controls.forEach((c) => (c.disabled = true))
149+
}
150+
}
151+
}

app/javascript/form.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ safeRegisterElement('submission-form', class extends HTMLElement {
3737
withSignatureId: this.dataset.withSignatureId === 'true',
3838
requireSigningReason: this.dataset.requireSigningReason === 'true',
3939
withConfetti: this.dataset.withConfetti !== 'false',
40+
withFieldLabels: this.dataset.withFieldLabels !== 'false',
4041
withDisclosure: this.dataset.withDisclosure === 'true',
4142
reuseSignature: this.dataset.reuseSignature !== 'false',
4243
withTypedSignature: this.dataset.withTypedSignature !== 'false',

app/javascript/submission_form/area.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -560,7 +560,7 @@ export default {
560560
return style
561561
},
562562
isNarrow () {
563-
return this.area.h > 0 && (this.area.w / this.area.h) > 6
563+
return this.area.h > 0 && ((this.area.w * this.pageWidth) / (this.area.h * this.pageHeight)) > 4.5
564564
}
565565
},
566566
watch: {

app/javascript/submission_form/form.vue

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
:scroll-el="scrollEl"
99
:with-signature-id="withSignatureId"
1010
:attachments-index="attachmentsIndex"
11-
:with-label="!isAnonymousChecboxes && showFieldNames"
11+
:with-label="withFieldLabels && !isAnonymousChecboxes && showFieldNames"
1212
:current-step="currentStepFields"
1313
:scroll-padding="scrollPadding"
1414
@focus-step="[saveStep(), currentField.type !== 'checkbox' ? isFormVisible = true : '', goToStep($event, false, true)]"
@@ -737,6 +737,11 @@ export default {
737737
required: false,
738738
default: true
739739
},
740+
withFieldLabels: {
741+
type: Boolean,
742+
required: false,
743+
default: true
744+
},
740745
withConfetti: {
741746
type: Boolean,
742747
required: false,

app/javascript/submission_form/phone_step.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@
100100
<input
101101
:id="field.uuid"
102102
ref="phone"
103-
:value="phoneValue"
103+
:value="defaultValue && detectedPhoneValueDialCode ? phoneValue.split('+' + detectedPhoneValueDialCode).slice(-1).join('') : phoneValue"
104104
:readonly="!!defaultValue"
105105
class="base-input !text-2xl !rounded-l-none !border-l-0 !outline-none w-full"
106106
autocomplete="tel"

0 commit comments

Comments
 (0)