satis 2.1.52 → 2.1.54
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/app/components/satis/attachments/component.css +2 -1
- data/app/components/satis/date_time_picker/component.html.slim +7 -9
- data/app/components/satis/date_time_picker/component_controller.js +192 -55
- data/app/components/satis/signature/component.html.slim +8 -0
- data/app/components/satis/signature/component.rb +14 -0
- data/app/components/satis/signature/component_controller.js +74 -0
- data/app/javascript/satis/controllers/index.js +3 -0
- data/config/importmap.rb +6 -1
- data/lib/satis/configuration.rb +7 -2
- data/lib/satis/forms/builder.rb +9 -25
- data/lib/satis/version.rb +1 -1
- data/vendor/javascript/dayjs--plugin--customParseFormat.js +4 -0
- data/vendor/javascript/dayjs--plugin--localizedFormat.js +4 -0
- data/vendor/javascript/dayjs--plugin--utc.js +4 -0
- data/vendor/javascript/dayjs.js +4 -0
- data/vendor/javascript/signature_pad.js +12 -0
- metadata +10 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8e4087c76633f9b2a02fc083fd95c60a4a28d9677dbe44ee11735e4fa0e29810
|
4
|
+
data.tar.gz: 2ab23a72ad341b331ef4c8ea1fc1780d46e32d1657194a4a8d1fb7ca0193db37
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 609e9ac871cbfb81c23b4bad5a60822671d1b4e26132fe2ac219ac6185ef459e7a69a5ca8f28ece3eb911588e505d93fd0206bbf0f07f338d20a0783f2f6a54e
|
7
|
+
data.tar.gz: b572b8fcfb7ee048e40b729b3f56fa5f3b61cd97515b9ddce60c35c1a5a77f01544ca4b53f5f0fdc2a5fb335b3fc2969b02d71997f2d325b080aed3da7ca11b6
|
@@ -136,5 +136,6 @@
|
|
136
136
|
@apply hover:border-white;
|
137
137
|
}
|
138
138
|
.attachments__group .attachment-upload.upload-btn.attachments__attachment.dragging {
|
139
|
-
@apply dark:bg-
|
139
|
+
@apply dark:bg-gray-700 dark:bg-opacity-75 bg-gray-200 bg-opacity-50 dark:text-black text-white;
|
140
|
+
transition: all 0.3s ease;
|
140
141
|
}
|
@@ -6,22 +6,20 @@ div.satis-date-time-picker data-controller="satis-date-time-picker" data-satis-d
|
|
6
6
|
button.cursor-pointer.w-6.h-full.flex.items-center.text-gray-400.outline-none.focus:outline-none data-satis-date-time-picker-target="clearButton" data-action="click->satis-date-time-picker#clear"
|
7
7
|
i.fas.fa-xmark
|
8
8
|
|
9
|
-
.container.z-10.shadow.bg-white.border.border-gray-300.dark:bg-gray-800.dark:border-gray-700.rounded.p-4.w-
|
9
|
+
.container.z-10.shadow.bg-white.border.border-gray-300.dark:bg-gray-800.dark:border-gray-700.rounded.p-4.w-96 class="#{inline ? 'inline-block' : 'hidden'}" data-satis-date-time-picker-target="calendarView"
|
10
10
|
.flex.justify-between.items-center.mb-2
|
11
11
|
div
|
12
|
-
button type="button" class="transition ease-in-out duration-100 inline-flex cursor-pointer hover:bg-gray-200 rounded-full" data-action="satis-date-time-picker#previousYear"
|
13
|
-
i.fal.fa-angle-double-left.text-gray-500.inline-flex.py-1
|
14
12
|
button type="button" class="transition ease-in-out duration-100 inline-flex cursor-pointer hover:bg-gray-200 rounded-full" data-action="satis-date-time-picker#previousMonth"
|
15
|
-
i.
|
13
|
+
i.text-gray-500.inline-flex.px-1.py-1 class=Satis.config.icons[:previous_month]
|
16
14
|
div.text-center
|
17
15
|
span.text-lg.font-bold.text-gray-800.dark:text-gray-200 data-satis-date-time-picker-target="month"
|
18
|
-
|
16
|
+
select.appearance-none.border-none.bg-transparent.text-lg.font-normal.ml-1.text-gray-600.dark:text-gray-200.w-32.focus:outline-none.focus:ring-0 style="max-height: 50px; overflow-y:auto;" data-satis-date-time-picker-target="select" data-action="change->satis-date-time-picker#selectYear"
|
17
|
+
- current_year = Time.current.year
|
18
|
+
- (current_year - 100..current_year + 100).each do |year|
|
19
|
+
option value=year data-satis-date-time-picker-target="year" = year
|
19
20
|
div
|
20
21
|
button type="button" class="transition ease-in-out duration-100 inline-flex cursor-pointer hover:bg-gray-200 rounded-full" data-action="satis-date-time-picker#nextMonth"
|
21
|
-
i.
|
22
|
-
button type="button" class="transition ease-in-out duration-100 inline-flex cursor-pointer hover:bg-gray-200 rounded-full" data-action="satis-date-time-picker#nextYear"
|
23
|
-
i.fal.fa-angle-double-right.text-gray-500.inline-flex.py-1
|
24
|
-
|
22
|
+
i.text-gray-500.inline-flex.px-1.py-1 class=Satis.config.icons[:next_month]
|
25
23
|
|
26
24
|
.grid.grid-cols-7 data-satis-date-time-picker-target="weekDays"
|
27
25
|
template data-satis-date-time-picker-target="weekDayTemplate"
|
@@ -1,7 +1,15 @@
|
|
1
1
|
import ApplicationController from "satis/controllers/application_controller"
|
2
2
|
import { createPopper } from "@popperjs/core"
|
3
|
+
import dayjs from "dayjs"
|
4
|
+
import customParseFormat from "dayjs/plugin/customParseFormat"
|
5
|
+
import localizedFormat from "dayjs/plugin/localizedFormat"
|
6
|
+
import utc from "dayjs/plugin/utc"
|
3
7
|
import { debounce } from "satis/utils"
|
4
8
|
|
9
|
+
dayjs.extend(customParseFormat)
|
10
|
+
dayjs.extend(localizedFormat)
|
11
|
+
dayjs.extend(utc)
|
12
|
+
|
5
13
|
export default class DateTimePickerComponentController extends ApplicationController {
|
6
14
|
static targets = [
|
7
15
|
"input",
|
@@ -156,22 +164,18 @@ export default class DateTimePickerComponentController extends ApplicationContro
|
|
156
164
|
|
157
165
|
previousMonth(event) {
|
158
166
|
this.displayValue = new Date(new Date(this.displayValue).setMonth(this.displayValue.getMonth() - 1))
|
167
|
+
|
168
|
+
this.updateYear()
|
169
|
+
|
159
170
|
this.refreshCalendar(false)
|
160
171
|
}
|
161
172
|
|
162
173
|
nextMonth(event) {
|
163
174
|
this.displayValue = new Date(new Date(this.displayValue).setMonth(this.displayValue.getMonth() + 1))
|
164
|
-
this.refreshCalendar(false)
|
165
|
-
}
|
166
175
|
|
167
|
-
|
168
|
-
this.displayValue = new Date(new Date(this.displayValue).setFullYear(this.displayValue.getFullYear() - 1));
|
169
|
-
this.refreshCalendar(false);
|
170
|
-
}
|
176
|
+
this.updateYear()
|
171
177
|
|
172
|
-
|
173
|
-
this.displayValue = new Date(new Date(this.displayValue).setFullYear(this.displayValue.getFullYear() + 1));
|
174
|
-
this.refreshCalendar(false);
|
178
|
+
this.refreshCalendar(false)
|
175
179
|
}
|
176
180
|
|
177
181
|
clickedOutside(event) {
|
@@ -266,21 +270,75 @@ export default class DateTimePickerComponentController extends ApplicationContro
|
|
266
270
|
}
|
267
271
|
|
268
272
|
dateTimeEntered(event) {
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
273
|
+
const inputValue = this.inputTarget.value;
|
274
|
+
|
275
|
+
if (inputValue.length < 10) return;
|
276
|
+
|
277
|
+
const locale = this.localeValue || navigator.language;
|
278
|
+
const defaultFormat = this.formatValue || "YYYY-MM-DD HH:mm:ss";
|
279
|
+
dayjs.locale(locale);
|
280
|
+
|
281
|
+
const formats = [
|
282
|
+
defaultFormat,
|
283
|
+
'YYYY-MM-DD',
|
284
|
+
'YYYY/MM/DD',
|
285
|
+
'DD/MM/YYYY',
|
286
|
+
'DD.MM.YYYY',
|
287
|
+
"DD-MM-YYYY",
|
288
|
+
"DD-MM-YYYY HH:mm",
|
289
|
+
"dddd, MMMM DD, YYYY h:mma",
|
290
|
+
"dddd, MMMM DD, YYYY h:mm A"
|
291
|
+
];
|
292
|
+
|
293
|
+
let parsedDate = null;
|
294
|
+
|
295
|
+
for (const format of formats) {
|
296
|
+
parsedDate = dayjs(inputValue, format, locale, true);
|
297
|
+
if (parsedDate.isValid()) {
|
298
|
+
break;
|
299
|
+
}
|
300
|
+
}
|
301
|
+
|
302
|
+
if (parsedDate && parsedDate.isValid()) {
|
303
|
+
this.selectedValue = [parsedDate.toDate()];
|
304
|
+
this.refreshCalendar(true);
|
305
|
+
this.refreshInputs();
|
306
|
+
} else {
|
307
|
+
console.warn("Invalid date/time entered");
|
308
|
+
const currentDate = dayjs().toDate();
|
309
|
+
this.selectedValue = [currentDate];
|
310
|
+
this.refreshCalendar(true);
|
311
|
+
this.refreshInputs();
|
312
|
+
}
|
313
|
+
|
278
314
|
}
|
279
315
|
|
316
|
+
|
280
317
|
selectDay(event) {
|
281
318
|
let oldCurrentValue = this.selectedValue[0]
|
319
|
+
let dayType = event.target.dataset.type
|
320
|
+
let selectedDate = new Date(this.displayValue)
|
321
|
+
|
322
|
+
if (dayType === "prev") {
|
323
|
+
if (this.rangeValue) {
|
324
|
+
return false
|
325
|
+
}
|
326
|
+
selectedDate.setMonth(this.displayValue.getMonth() - 1)
|
327
|
+
this.displayValue = selectedDate
|
328
|
+
} else if (dayType === "next") {
|
329
|
+
if (this.rangeValue) {
|
330
|
+
return false
|
331
|
+
}
|
332
|
+
selectedDate.setMonth(this.displayValue.getMonth() + 1)
|
333
|
+
this.displayValue = selectedDate
|
334
|
+
}
|
335
|
+
|
336
|
+
this.updateYear()
|
337
|
+
|
338
|
+
selectedDate.setDate(+event.target.innerText)
|
339
|
+
|
282
340
|
if (!this.rangeValue && !this.multipleValue) {
|
283
|
-
this.selectedValue[0] =
|
341
|
+
this.selectedValue[0] = selectedDate
|
284
342
|
if (this.timePickerValue && oldCurrentValue) {
|
285
343
|
this.selectedValue[0].setHours(oldCurrentValue.getHours())
|
286
344
|
this.selectedValue[0].setMinutes(oldCurrentValue.getMinutes())
|
@@ -304,6 +362,7 @@ export default class DateTimePickerComponentController extends ApplicationContro
|
|
304
362
|
this.currentSelectNr += 1
|
305
363
|
}
|
306
364
|
|
365
|
+
this.refreshInputs()
|
307
366
|
this.refreshCalendar()
|
308
367
|
|
309
368
|
if (!this.rangeValue || this.selectedValue.length == 2) {
|
@@ -392,46 +451,19 @@ export default class DateTimePickerComponentController extends ApplicationContro
|
|
392
451
|
this.minutesTarget.value = "00" // FIXME: Should be 0:00 in locale
|
393
452
|
}
|
394
453
|
}
|
395
|
-
this.daysTarget.innerHTML = ""
|
396
454
|
|
397
|
-
this.
|
398
|
-
if (day == " ") {
|
399
|
-
this.daysTarget.insertAdjacentHTML("beforeend", this.emtpyTemplateTarget.innerHTML)
|
400
|
-
} else {
|
401
|
-
let date = new Date(new Date(this.displayValue).setDate(day))
|
455
|
+
let days = this.generateDays()
|
402
456
|
|
403
|
-
|
404
|
-
|
457
|
+
this.daysTarget.innerHTML = ""
|
458
|
+
days.forEach((day) => {
|
459
|
+
let tmpDiv = document.createElement("div")
|
460
|
+
tmpDiv.innerHTML = this.dayTemplateTarget.innerHTML.replace(/\${day}/g, day.date.getDate())
|
461
|
+
let div = tmpDiv.querySelector(".text-center")
|
405
462
|
|
406
|
-
|
407
|
-
let div = tmpDiv.querySelector(".text-center")
|
408
|
-
div.classList.add("border-red-500", "border")
|
409
|
-
}
|
410
|
-
let div = tmpDiv.querySelector(".text-center")
|
411
|
-
|
412
|
-
if (this.isSelected(date)) {
|
413
|
-
if (this.rangeValue && this.selectedValue.length == 2) {
|
414
|
-
if (this.isDate(this.selectedValue[0], date)) {
|
415
|
-
div.classList.add("bg-primary-500", "text-white", "dark:text-gray-200")
|
416
|
-
div.classList.remove("rounded-r-full")
|
417
|
-
} else if (this.isDate(this.selectedValue[1], date)) {
|
418
|
-
div.classList.add("bg-primary-500", "text-white", "dark:text-gray-200")
|
419
|
-
div.classList.remove("rounded-l-full")
|
420
|
-
} else if (this.isSelected(date)) {
|
421
|
-
div.classList.remove("rounded-r-full")
|
422
|
-
div.classList.remove("rounded-l-full")
|
423
|
-
div.classList.add("bg-primary-200", "text-white", "dark:text-gray-200")
|
424
|
-
}
|
425
|
-
} else {
|
426
|
-
div.classList.add("bg-primary-500", "text-white", "dark:text-gray-200")
|
427
|
-
}
|
428
|
-
} else {
|
429
|
-
div.classList.add("text-gray-700", "dark:text-gray-300")
|
430
|
-
}
|
463
|
+
this.applyDayStyles(div, day)
|
431
464
|
|
432
|
-
|
433
|
-
|
434
|
-
}
|
465
|
+
this.daysTarget.insertAdjacentHTML("beforeend", tmpDiv.innerHTML)
|
466
|
+
tmpDiv.remove()
|
435
467
|
})
|
436
468
|
|
437
469
|
if (refreshInputs != false) {
|
@@ -443,6 +475,90 @@ export default class DateTimePickerComponentController extends ApplicationContro
|
|
443
475
|
}
|
444
476
|
}
|
445
477
|
|
478
|
+
generateDays() {
|
479
|
+
let days = []
|
480
|
+
const firstDayOfMonth = new Date(this.displayValue.getFullYear(), this.displayValue.getMonth(), 1)
|
481
|
+
const lastDayOfMonth = new Date(this.displayValue.getFullYear(), this.displayValue.getMonth() + 1, 0)
|
482
|
+
const startDayOfWeek = (firstDayOfMonth.getDay() - this.weekStartValue + 7) % 7
|
483
|
+
const endDayOfWeek = (6 - lastDayOfMonth.getDay() + this.weekStartValue + 7) % 7
|
484
|
+
const previousMonthLastDate = new Date(this.displayValue.getFullYear(), this.displayValue.getMonth(), 0).getDate()
|
485
|
+
|
486
|
+
// Previous month's days
|
487
|
+
for (let i = startDayOfWeek; i > 0; i--) {
|
488
|
+
const day = previousMonthLastDate - i + 1
|
489
|
+
days.push({
|
490
|
+
date: new Date(this.displayValue.getFullYear(), this.displayValue.getMonth() - 1, day),
|
491
|
+
type: "prev",
|
492
|
+
})
|
493
|
+
}
|
494
|
+
|
495
|
+
// Current month's days
|
496
|
+
for (let i = 1; i <= lastDayOfMonth.getDate(); i++) {
|
497
|
+
days.push({
|
498
|
+
date: new Date(this.displayValue.getFullYear(), this.displayValue.getMonth(), i),
|
499
|
+
type: "current",
|
500
|
+
})
|
501
|
+
}
|
502
|
+
|
503
|
+
// Next month's days
|
504
|
+
for (let i = 1; i <= endDayOfWeek; i++) {
|
505
|
+
days.push({
|
506
|
+
date: new Date(this.displayValue.getFullYear(), this.displayValue.getMonth() + 1, i),
|
507
|
+
type: "next",
|
508
|
+
})
|
509
|
+
}
|
510
|
+
|
511
|
+
return days
|
512
|
+
}
|
513
|
+
|
514
|
+
applyDayStyles(div, day) {
|
515
|
+
if (day.type === "prev" || day.type === "next") {
|
516
|
+
div.classList.add("text-gray-400", "hover:bg-gray-200", "cursor-pointer")
|
517
|
+
div.dataset.type = day.type
|
518
|
+
|
519
|
+
this.addDayClickListener(div, day)
|
520
|
+
} else {
|
521
|
+
div.classList.add("text-gray-700", "dark:text-gray-300")
|
522
|
+
|
523
|
+
if (this.isToday(day.date)) {
|
524
|
+
div.classList.add("border-red-500", "border")
|
525
|
+
}
|
526
|
+
|
527
|
+
if (this.isSelected(day.date)) {
|
528
|
+
if (this.rangeValue && this.selectedValue.length == 2) {
|
529
|
+
if (this.isDate(this.selectedValue[0], day.date)) {
|
530
|
+
div.classList.add("bg-primary-500", "text-white", "dark:text-gray-200")
|
531
|
+
div.classList.remove("rounded-r-full")
|
532
|
+
} else if (this.isDate(this.selectedValue[1], day.date)) {
|
533
|
+
div.classList.add("bg-primary-500", "text-white", "dark:text-gray-200")
|
534
|
+
div.classList.remove("rounded-l-full")
|
535
|
+
} else if (this.isSelected(day.date)) {
|
536
|
+
div.classList.remove("rounded-r-full")
|
537
|
+
div.classList.remove("rounded-l-full")
|
538
|
+
div.classList.add("bg-primary-200", "text-white", "dark:text-gray-200")
|
539
|
+
}
|
540
|
+
} else {
|
541
|
+
div.classList.add("bg-primary-500", "text-white", "dark:text-gray-200")
|
542
|
+
}
|
543
|
+
} else {
|
544
|
+
div.classList.add("text-gray-700", "dark:text-gray-300")
|
545
|
+
}
|
546
|
+
}
|
547
|
+
}
|
548
|
+
|
549
|
+
addDayClickListener(div, day) {
|
550
|
+
if (day.type === "prev" || day.type === "next") {
|
551
|
+
div.addEventListener("click", () => {
|
552
|
+
this.displayValue = new Date(day.date.getFullYear(), day.date.getMonth(), 1)
|
553
|
+
this.selectedValue[0] = new Date(day.date)
|
554
|
+
this.refreshCalendar(true)
|
555
|
+
|
556
|
+
if (!this.inlineValue) {
|
557
|
+
this.hideCalendar()
|
558
|
+
}
|
559
|
+
})
|
560
|
+
}
|
561
|
+
}
|
446
562
|
// Format the given Date into an ISO8601 string whilst preserving the given timezone
|
447
563
|
iso8601(date) {
|
448
564
|
let tzo = -date.getTimezoneOffset(),
|
@@ -550,4 +666,25 @@ export default class DateTimePickerComponentController extends ApplicationContro
|
|
550
666
|
|
551
667
|
return results
|
552
668
|
}
|
669
|
+
|
670
|
+
selectYear(event) {
|
671
|
+
let selectedYear = Number(event.target.value)
|
672
|
+
this.displayValue.setFullYear(selectedYear)
|
673
|
+
this.refreshCalendar(false)
|
674
|
+
|
675
|
+
if (!this.rangeValue && !this.multipleValue) {
|
676
|
+
this.selectedValue[0] = new Date(this.displayValue)
|
677
|
+
} else if(this.rangeValue && this.selectedValue.length == 2){
|
678
|
+
return false
|
679
|
+
}
|
680
|
+
|
681
|
+
this.refreshInputs()
|
682
|
+
event.cancelBubble = true
|
683
|
+
}
|
684
|
+
|
685
|
+
updateYear() {
|
686
|
+
const yearSelect = document.querySelector('[data-satis-date-time-picker-target="select"]')
|
687
|
+
const newYear = this.displayValue.getFullYear()
|
688
|
+
yearSelect.value = newYear
|
689
|
+
}
|
553
690
|
}
|
@@ -0,0 +1,8 @@
|
|
1
|
+
div data-controller="satis-signature" data-satis-signature-url-value=(form.object.send(attribute).attached? ? helpers.main_app.url_for(form.object.send(attribute)) : nil)
|
2
|
+
canvas.border-solid.border.rounded-md data-satis-signature-target="canvas" data-satis-signature-action="change->satis-signature#update" width="600" height="200"
|
3
|
+
.button
|
4
|
+
i.fal.fa-trash data-action='click->satis-signature#clear' class='cursor-pointer'
|
5
|
+
|<
|
6
|
+
.button
|
7
|
+
i.fal.fa-undo data-action='click->satis-signature#undo' class='cursor-pointer'
|
8
|
+
= form.file_field :signature, data: { "satis-signature-target" => 'file' }, class: 'hidden'
|
@@ -0,0 +1,14 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Satis
|
4
|
+
module Signature
|
5
|
+
class Component < ViewComponent::Base
|
6
|
+
attr_reader :url, :form, :attribute, :title, :options
|
7
|
+
|
8
|
+
def initialize(form:, attribute:, **options, &block)
|
9
|
+
@form = form
|
10
|
+
@attribute = attribute
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
import ApplicationController from "satis/controllers/application_controller"
|
2
|
+
|
3
|
+
import SignaturePad from "signature_pad"
|
4
|
+
|
5
|
+
export default class SignatureComponentController extends ApplicationController {
|
6
|
+
static targets = ["canvas", "file"]
|
7
|
+
static values = { url: String }
|
8
|
+
|
9
|
+
async connect() {
|
10
|
+
this.signaturePad = new SignaturePad(this.canvasTarget)
|
11
|
+
if (this.hasUrlValue) {
|
12
|
+
let blob = await fetch(this.urlValue)
|
13
|
+
.then(r => r.blob())
|
14
|
+
|
15
|
+
|
16
|
+
let dataUrl = await new Promise(resolve => {
|
17
|
+
let reader = new FileReader()
|
18
|
+
reader.onload = () => resolve(reader.result)
|
19
|
+
reader.readAsDataURL(blob)
|
20
|
+
})
|
21
|
+
const dpi = window.devicePixelRatio
|
22
|
+
window.devicePixelRatio = 1
|
23
|
+
this.signaturePad.fromDataURL(dataUrl)
|
24
|
+
const file = this.dataURLtoFile(dataUrl, "signature.svg")
|
25
|
+
window.devicePixelRatio = dpi
|
26
|
+
this.signaturePad.addEventListener("beginStroke", this.clear.bind(this), { once: true })
|
27
|
+
this.persistFile(file)
|
28
|
+
}
|
29
|
+
this.signaturePad.addEventListener("endStroke", this.persist.bind(this))
|
30
|
+
}
|
31
|
+
|
32
|
+
clear(event) {
|
33
|
+
this.signaturePad.clear()
|
34
|
+
this.fileTarget.files = new DataTransfer().files
|
35
|
+
}
|
36
|
+
|
37
|
+
undo(event) {
|
38
|
+
event.preventDefault()
|
39
|
+
const data = this.signaturePad.toData()
|
40
|
+
if (data) {
|
41
|
+
data.pop()
|
42
|
+
this.signaturePad.fromData(data)
|
43
|
+
}
|
44
|
+
}
|
45
|
+
|
46
|
+
persist(event) {
|
47
|
+
const dpi = window.devicePixelRatio
|
48
|
+
const dataUrl = this.signaturePad.toSVG()
|
49
|
+
window.devicePixelRatio = 1
|
50
|
+
const file = new File([this.signaturePad?.toSVG()], "signature.svg", { type: "image/svg+xml" })
|
51
|
+
window.devicePixelRatio = dpi
|
52
|
+
this.persistFile(file)
|
53
|
+
}
|
54
|
+
|
55
|
+
persistFile(file) {
|
56
|
+
const dt = new DataTransfer()
|
57
|
+
dt.items.add(file)
|
58
|
+
this.fileTarget.files = dt.files
|
59
|
+
}
|
60
|
+
|
61
|
+
// HELPER
|
62
|
+
|
63
|
+
dataURLtoFile(dataurl, filename) {
|
64
|
+
var arr = dataurl.split(","),
|
65
|
+
mime = arr[0].match(/:(.*?);/)[1],
|
66
|
+
bstr = atob(arr[arr.length - 1]),
|
67
|
+
n = bstr.length,
|
68
|
+
u8arr = new Uint8Array(n);
|
69
|
+
while (n--) {
|
70
|
+
u8arr[n] = bstr.charCodeAt(n);
|
71
|
+
}
|
72
|
+
return new File([u8arr], filename, { type: mime });
|
73
|
+
}
|
74
|
+
}
|
@@ -48,6 +48,9 @@ application.register("satis-dialog", DialogComponentController);
|
|
48
48
|
import ColorPickerComponentController from "satis/components/color_picker/component_controller";
|
49
49
|
application.register("satis-color-picker", ColorPickerComponentController);
|
50
50
|
|
51
|
+
import SignatureComponentController from "satis/components/signature/component_controller";
|
52
|
+
application.register("satis-signature", SignatureComponentController);
|
53
|
+
|
51
54
|
// Controllers
|
52
55
|
|
53
56
|
import LinkController from "satis/controllers/link_controller";
|
data/config/importmap.rb
CHANGED
@@ -13,7 +13,7 @@ pin_all_from Satis::Engine.root.join("app/javascript/satis/elements"), under: "s
|
|
13
13
|
pin_all_from Satis::Engine.root.join("app/components/satis"), under: "satis/components", to: "satis"
|
14
14
|
|
15
15
|
pin "tippy.js", preload: false # @6.3.7
|
16
|
-
pin "@popperjs/core", to:
|
16
|
+
pin "@popperjs/core", to: "popper.js.js", preload: false
|
17
17
|
pin "leaflet", to: "leaflet.js", preload: false
|
18
18
|
pin "sortablejs", to: "sortablejs.js", preload: false # @1.15.2
|
19
19
|
pin "@rails/actiontext", to: "@rails--actiontext.js" # @7.1.3
|
@@ -48,3 +48,8 @@ pin "@lezer/markdown", to: "@lezer--markdown.js" # @1.2.0
|
|
48
48
|
pin "intl-tel-input", to: "intl-tel-input.js" # @19.5.6
|
49
49
|
pin "intl-tel-input-utils", to: "intl-tel-input-utils.js" # @19.5.6
|
50
50
|
pin "pickr", to: "pickr.es5.min.js" # @0.1.4
|
51
|
+
pin "dayjs" # @1.11.13
|
52
|
+
pin "dayjs/plugin/customParseFormat", to: "dayjs--plugin--customParseFormat.js" # @1.11.13
|
53
|
+
pin "dayjs/plugin/localizedFormat", to: "dayjs--plugin--localizedFormat.js" # @1.11.13
|
54
|
+
pin "dayjs/plugin/utc", to: "dayjs--plugin--utc.js" # @1.11.13
|
55
|
+
pin "signature_pad" # @5.0.4
|
data/lib/satis/configuration.rb
CHANGED
@@ -15,7 +15,7 @@ module Satis
|
|
15
15
|
|
16
16
|
def set_defaults!
|
17
17
|
self.class.schema.each do |name, default|
|
18
|
-
instance_variable_set("@#{name}", default)
|
18
|
+
instance_variable_set(:"@#{name}", default)
|
19
19
|
end
|
20
20
|
end
|
21
21
|
|
@@ -33,6 +33,11 @@ module Satis
|
|
33
33
|
option :confirm_before_leave, default: false
|
34
34
|
option :current_user, default: lambda {}
|
35
35
|
|
36
|
+
option :icons, default: {
|
37
|
+
previous_month: "fa-solid fa-angle-left",
|
38
|
+
next_month: "fa-solid fa-angle-right"
|
39
|
+
}
|
40
|
+
|
36
41
|
option(:default_help_text, default: lambda do |template, object, key, additional_scope|
|
37
42
|
scope = help_scope(template, object, additional_scope)
|
38
43
|
|
@@ -80,7 +85,7 @@ module Satis
|
|
80
85
|
def configure
|
81
86
|
yield(config)
|
82
87
|
end
|
83
|
-
|
88
|
+
alias_method :setup, :configure
|
84
89
|
|
85
90
|
def reset_config!
|
86
91
|
@config = Configuration.new
|
data/lib/satis/forms/builder.rb
CHANGED
@@ -328,31 +328,15 @@ module Satis
|
|
328
328
|
@template.render(Satis::Editor::Component.new(form: self, attribute: method, **options, &block))
|
329
329
|
]
|
330
330
|
end
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
# 'satis-editor-read-only-value' => options.delete(:read_only) || false,
|
341
|
-
# 'satis-editor-mode-value' => options.delete(:mode) || 'text/html',
|
342
|
-
# 'satis-editor-height-value' => options.delete(:height) || '200px',
|
343
|
-
# 'satis-editor-color-scheme-value' => options.delete(:color_scheme),
|
344
|
-
# 'satis-editor-color-scheme-dark-value' => options.delete(:color_scheme_dark) || 'lucario'
|
345
|
-
# }
|
346
|
-
#
|
347
|
-
# }, options[:input_html])), class: "editor #{
|
348
|
-
# if has_error?(method)
|
349
|
-
# 'is-invalid'
|
350
|
-
# end}", data: {
|
351
|
-
# controller: 'satis-editor'
|
352
|
-
# }),
|
353
|
-
# hint_text(options[:hint] || '⌘-F/⌃-f: search; ⌥-g: goto line, ⌃-space: autocomplete')
|
354
|
-
# ]
|
355
|
-
# end
|
331
|
+
end
|
332
|
+
|
333
|
+
def signature(method, options = {}, &block)
|
334
|
+
form_group(method, options) do
|
335
|
+
safe_join [
|
336
|
+
(custom_label(method, options[:label], options) unless options[:label] == false),
|
337
|
+
@template.render(Satis::Signature::Component.new(form: self, attribute: method, **options, &block))
|
338
|
+
]
|
339
|
+
end
|
356
340
|
end
|
357
341
|
|
358
342
|
def boolean_input(method, options = {})
|
data/lib/satis/version.rb
CHANGED
@@ -0,0 +1,4 @@
|
|
1
|
+
// dayjs/plugin/customParseFormat@1.11.13 downloaded from https://ga.jspm.io/npm:dayjs@1.11.13/plugin/customParseFormat.js
|
2
|
+
|
3
|
+
var e=typeof globalThis!=="undefined"?globalThis:typeof self!=="undefined"?self:global;var t={};!function(e,n){t=n()}(0,(function(){var t={LTS:"h:mm:ss A",LT:"h:mm A",L:"MM/DD/YYYY",LL:"MMMM D, YYYY",LLL:"MMMM D, YYYY h:mm A",LLLL:"dddd, MMMM D, YYYY h:mm A"},n=/(\[[^[]*\])|([-_:/.,()\s]+)|(A|a|Q|YYYY|YY?|ww?|MM?M?M?|Do|DD?|hh?|HH?|mm?|ss?|S{1,3}|z|ZZ?)/g,r=/\d/,i=/\d\d/,o=/\d\d?/,s=/\d*[^-_:/,()\s\d]+/,h={},a=function(e){return(e=+e)+(e>68?1900:2e3)};var f=function(t){return function(n){(this||e)[t]=+n}},c=[/[+-]\d\d:?(\d\d)?|Z/,function(t){((this||e).zone||((this||e).zone={})).offset=function(e){if(!e)return 0;if("Z"===e)return 0;var t=e.match(/([+-]|\d\d)/g),n=60*t[1]+(+t[2]||0);return 0===n?0:"+"===t[0]?-n:n}(t)}],u=function(e){var t=h[e];return t&&(t.indexOf?t:t.s.concat(t.f))},d=function(e,t){var n,r=h.meridiem;if(r){for(var i=1;i<=24;i+=1)if(e.indexOf(r(i,0,t))>-1){n=i>12;break}}else n=e===(t?"pm":"PM");return n},m={A:[s,function(t){(this||e).afternoon=d(t,!1)}],a:[s,function(t){(this||e).afternoon=d(t,!0)}],Q:[r,function(t){(this||e).month=3*(t-1)+1}],S:[r,function(t){(this||e).milliseconds=100*+t}],SS:[i,function(t){(this||e).milliseconds=10*+t}],SSS:[/\d{3}/,function(t){(this||e).milliseconds=+t}],s:[o,f("seconds")],ss:[o,f("seconds")],m:[o,f("minutes")],mm:[o,f("minutes")],H:[o,f("hours")],h:[o,f("hours")],HH:[o,f("hours")],hh:[o,f("hours")],D:[o,f("day")],DD:[i,f("day")],Do:[s,function(t){var n=h.ordinal,r=t.match(/\d+/);if((this||e).day=r[0],n)for(var i=1;i<=31;i+=1)n(i).replace(/\[|\]/g,"")===t&&((this||e).day=i)}],w:[o,f("week")],ww:[i,f("week")],M:[o,f("month")],MM:[i,f("month")],MMM:[s,function(t){var n=u("months"),r=(u("monthsShort")||n.map((function(e){return e.slice(0,3)}))).indexOf(t)+1;if(r<1)throw new Error;(this||e).month=r%12||r}],MMMM:[s,function(t){var n=u("months").indexOf(t)+1;if(n<1)throw new Error;(this||e).month=n%12||n}],Y:[/[+-]?\d+/,f("year")],YY:[i,function(t){(this||e).year=a(t)}],YYYY:[/\d{4}/,f("year")],Z:c,ZZ:c};function l(e){var r,i;r=e,i=h&&h.formats;for(var o=(e=r.replace(/(\[[^\]]+])|(LTS?|l{1,4}|L{1,4})/g,(function(e,n,r){var o=r&&r.toUpperCase();return n||i[r]||t[r]||i[o].replace(/(\[[^\]]+])|(MMMM|MM|DD|dddd)/g,(function(e,t,n){return t||n.slice(1)}))}))).match(n),s=o.length,c=0;c<s;c+=1){var M=o[c],Y=m[M],v=Y&&Y[0],D=Y&&Y[1];o[c]=D?{regex:v,parser:D}:M.replace(/^\[|\]$/g,"")}return function(e){for(var t={},n=0,r=0;n<s;n+=1){var i=o[n];if("string"==typeof i)r+=i.length;else{var h=i.regex,c=i.parser,m=e.slice(r),M=h.exec(m)[0];c.call(t,M),e=e.replace(M,"")}}return function(e){var t=e.afternoon;if(void 0!==t){var n=e.hours;t?n<12&&(e.hours+=12):12===n&&(e.hours=0),delete e.afternoon}}(t),t}}return function(t,n,r){r.p.customParseFormat=!0,t&&t.parseTwoDigitYear&&(a=t.parseTwoDigitYear);var i=n.prototype,o=i.parse;i.parse=function(t){var n=t.date,i=t.utc,s=t.args;(this||e).$u=i;var c=s[1];if("string"==typeof c){var m=!0===s[2],M=!0===s[3],Y=m||M,v=s[2];M&&(v=s[2]),h=this.$locale(),!m&&v&&(h=r.Ls[v]),(this||e).$d=function(e,t,n,r){try{if(["x","X"].indexOf(t)>-1)return new Date(("X"===t?1e3:1)*e);var i=l(t)(e),o=i.year,s=i.month,h=i.day,c=i.hours,m=i.minutes,M=i.seconds,Y=i.milliseconds,v=i.zone,D=i.week,p=new Date,w=h||(o||s?1:p.getDate()),g=o||p.getFullYear(),L=0;o&&!s||(L=s>0?s-1:p.getMonth());var y,$=c||0,x=m||0,S=M||0,T=Y||0;return v?new Date(Date.UTC(g,L,w,$,x,S,T+60*v.offset*1e3)):n?new Date(Date.UTC(g,L,w,$,x,S,T)):(y=new Date(g,L,w,$,x,S,T),D&&(y=r(y).week(D).toDate()),y)}catch(e){return new Date("")}}(n,c,i,r),this.init(),v&&!0!==v&&((this||e).$L=this.locale(v).$L),Y&&n!=this.format(c)&&((this||e).$d=new Date("")),h={}}else if(c instanceof Array)for(var D=c.length,p=1;p<=D;p+=1){s[1]=c[p-1];var w=r.apply(this||e,s);if(w.isValid()){(this||e).$d=w.$d,(this||e).$L=w.$L,this.init();break}p===D&&((this||e).$d=new Date(""))}else o.call(this||e,t)}}}));var n=t;export{n as default};
|
4
|
+
|
@@ -0,0 +1,4 @@
|
|
1
|
+
// dayjs/plugin/localizedFormat@1.11.13 downloaded from https://ga.jspm.io/npm:dayjs@1.11.13/plugin/localizedFormat.js
|
2
|
+
|
3
|
+
var r=typeof globalThis!=="undefined"?globalThis:typeof self!=="undefined"?self:global;var e={};!function(r,t){e=t()}(0,(function(){var e={LTS:"h:mm:ss A",LT:"h:mm A",L:"MM/DD/YYYY",LL:"MMMM D, YYYY",LLL:"MMMM D, YYYY h:mm A",LLLL:"dddd, MMMM D, YYYY h:mm A"};return function(t,n,o){var M=n.prototype,a=M.format;o.en.formats=e,M.format=function(t){void 0===t&&(t="YYYY-MM-DDTHH:mm:ssZ");var n=this.$locale().formats,o=function(r,t){return r.replace(/(\[[^\]]+])|(LTS?|l{1,4}|L{1,4})/g,(function(r,n,o){var M=o&&o.toUpperCase();return n||t[o]||e[o]||t[M].replace(/(\[[^\]]+])|(MMMM|MM|DD|dddd)/g,(function(r,e,t){return e||t.slice(1)}))}))}(t,void 0===n?{}:n);return a.call(this||r,o)}}}));var t=e;export{t as default};
|
4
|
+
|
@@ -0,0 +1,4 @@
|
|
1
|
+
// dayjs/plugin/utc@1.11.13 downloaded from https://ga.jspm.io/npm:dayjs@1.11.13/plugin/utc.js
|
2
|
+
|
3
|
+
var t=typeof globalThis!=="undefined"?globalThis:typeof self!=="undefined"?self:global;var i={};!function(t,s){i=s()}(0,(function(){var i="minute",s=/[+-]\d\d(?::?\d\d)?/g,e=/([+-]|\d\d)/g;return function(f,n,r){var u=n.prototype;r.utc=function(t){var i={date:t,utc:!0,args:arguments};return new n(i)},u.utc=function(s){var e=r(this.toDate(),{locale:(this||t).$L,utc:!0});return s?e.add(this.utcOffset(),i):e},u.local=function(){return r(this.toDate(),{locale:(this||t).$L,utc:!1})};var a=u.parse;u.parse=function(i){i.utc&&((this||t).$u=!0),this.$utils().u(i.$offset)||((this||t).$offset=i.$offset),a.call(this||t,i)};var o=u.init;u.init=function(){if((this||t).$u){var i=(this||t).$d;(this||t).$y=i.getUTCFullYear(),(this||t).$M=i.getUTCMonth(),(this||t).$D=i.getUTCDate(),(this||t).$W=i.getUTCDay(),(this||t).$H=i.getUTCHours(),(this||t).$m=i.getUTCMinutes(),(this||t).$s=i.getUTCSeconds(),(this||t).$ms=i.getUTCMilliseconds()}else o.call(this||t)};var h=u.utcOffset;u.utcOffset=function(f,n){var r=this.$utils().u;if(r(f))return(this||t).$u?0:r((this||t).$offset)?h.call(this||t):(this||t).$offset;if("string"==typeof f&&(f=function(t){void 0===t&&(t="");var i=t.match(s);if(!i)return null;var f=(""+i[0]).match(e)||["-",0,0],n=f[0],r=60*+f[1]+ +f[2];return 0===r?0:"+"===n?r:-r}(f),null===f))return this||t;var u=Math.abs(f)<=16?60*f:f,a=this||t;if(n)return a.$offset=u,a.$u=0===f,a;if(0!==f){var o=(this||t).$u?this.toDate().getTimezoneOffset():-1*this.utcOffset();(a=this.local().add(u+o,i)).$offset=u,a.$x.$localOffset=o}else a=this.utc();return a};var l=u.format;u.format=function(i){var s=i||((this||t).$u?"YYYY-MM-DDTHH:mm:ss[Z]":"");return l.call(this||t,s)},u.valueOf=function(){var i=this.$utils().u((this||t).$offset)?0:(this||t).$offset+((this||t).$x.$localOffset||(this||t).$d.getTimezoneOffset());return(this||t).$d.valueOf()-6e4*i},u.isUTC=function(){return!!(this||t).$u},u.toISOString=function(){return this.toDate().toISOString()},u.toString=function(){return this.toDate().toUTCString()};var c=u.toDate;u.toDate=function(i){return"s"===i&&(this||t).$offset?r(this.format("YYYY-MM-DD HH:mm:ss:SSS")).toDate():c.call(this||t)};var $=u.diff;u.diff=function(i,s,e){if(i&&(this||t).$u===i.$u)return $.call(this||t,i,s,e);var f=this.local(),n=r(i).local();return $.call(f,n,s,e)}}}));var s=i;export{s as default};
|
4
|
+
|
@@ -0,0 +1,4 @@
|
|
1
|
+
// dayjs@1.11.13 downloaded from https://ga.jspm.io/npm:dayjs@1.11.13/dayjs.min.js
|
2
|
+
|
3
|
+
var e=typeof globalThis!=="undefined"?globalThis:typeof self!=="undefined"?self:global;var n={};!function(e,r){n=r()}(0,(function(){var n=1e3,r=6e4,s=36e5,i="millisecond",u="second",a="minute",o="hour",c="day",f="week",v="month",g="quarter",p="year",w="date",b="Invalid Date",_=/^(\d{4})[-/]?(\d{1,2})?[-/]?(\d{0,2})[Tt\s]*(\d{1,2})?:?(\d{1,2})?:?(\d{1,2})?[.:]?(\d+)?$/,k=/\[([^\]]+)]|Y{1,4}|M{1,4}|D{1,2}|d{1,4}|H{1,2}|h{1,2}|a|A|m{1,2}|s{1,2}|Z{1,2}|SSS/g,T={name:"en",weekdays:"Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"),months:"January_February_March_April_May_June_July_August_September_October_November_December".split("_"),ordinal:function(e){var n=["th","st","nd","rd"],r=e%100;return"["+e+(n[(r-20)%10]||n[r]||n[0])+"]"}},m=function(e,n,r){var s=String(e);return!s||s.length>=n?e:""+Array(n+1-s.length).join(r)+e},Y={s:m,z:function(e){var n=-e.utcOffset(),r=Math.abs(n),s=Math.floor(r/60),i=r%60;return(n<=0?"+":"-")+m(s,2,"0")+":"+m(i,2,"0")},m:function t(e,n){if(e.date()<n.date())return-t(n,e);var r=12*(n.year()-e.year())+(n.month()-e.month()),s=e.clone().add(r,v),i=n-s<0,u=e.clone().add(r+(i?-1:1),v);return+(-(r+(n-s)/(i?s-u:u-s))||0)},a:function(e){return e<0?Math.ceil(e)||0:Math.floor(e)},p:function(e){return{M:v,y:p,w:f,d:c,D:w,h:o,m:a,s:u,ms:i,Q:g}[e]||String(e||"").toLowerCase().replace(/s$/,"")},u:function(e){return void 0===e}},H="en",x={};x[H]=T;var L="$isDayjsObject",S=function(e){return e instanceof A||!(!e||!e[L])},W=function t(e,n,r){var s;if(!e)return H;if("string"==typeof e){var i=e.toLowerCase();x[i]&&(s=i),n&&(x[i]=n,s=i);var u=e.split("-");if(!s&&u.length>1)return t(u[0])}else{var a=e.name;x[a]=e,s=a}return!r&&s&&(H=s),s||!r&&H},O=function(e,n){if(S(e))return e.clone();var r="object"==typeof n?n:{};return r.date=e,r.args=arguments,new A(r)},C=Y;C.l=W,C.i=S,C.w=function(e,n){return O(e,{locale:n.$L,utc:n.$u,x:n.$x,$offset:n.$offset})};var A=function(){function M(n){(this||e).$L=W(n.locale,null,!0),this.parse(n),(this||e).$x=(this||e).$x||n.x||{},(this||e)[L]=!0}var T=M.prototype;return T.parse=function(n){(this||e).$d=function(e){var n=e.date,r=e.utc;if(null===n)return new Date(NaN);if(C.u(n))return new Date;if(n instanceof Date)return new Date(n);if("string"==typeof n&&!/Z$/i.test(n)){var s=n.match(_);if(s){var i=s[2]-1||0,u=(s[7]||"0").substring(0,3);return r?new Date(Date.UTC(s[1],i,s[3]||1,s[4]||0,s[5]||0,s[6]||0,u)):new Date(s[1],i,s[3]||1,s[4]||0,s[5]||0,s[6]||0,u)}}return new Date(n)}(n),this.init()},T.init=function(){var n=(this||e).$d;(this||e).$y=n.getFullYear(),(this||e).$M=n.getMonth(),(this||e).$D=n.getDate(),(this||e).$W=n.getDay(),(this||e).$H=n.getHours(),(this||e).$m=n.getMinutes(),(this||e).$s=n.getSeconds(),(this||e).$ms=n.getMilliseconds()},T.$utils=function(){return C},T.isValid=function(){return!((this||e).$d.toString()===b)},T.isSame=function(e,n){var r=O(e);return this.startOf(n)<=r&&r<=this.endOf(n)},T.isAfter=function(e,n){return O(e)<this.startOf(n)},T.isBefore=function(e,n){return this.endOf(n)<O(e)},T.$g=function(n,r,s){return C.u(n)?(this||e)[r]:this.set(s,n)},T.unix=function(){return Math.floor(this.valueOf()/1e3)},T.valueOf=function(){return(this||e).$d.getTime()},T.startOf=function(n,r){var s=this||e,i=!!C.u(r)||r,g=C.p(n),l=function(e,n){var r=C.w(s.$u?Date.UTC(s.$y,n,e):new Date(s.$y,n,e),s);return i?r:r.endOf(c)},$=function(e,n){return C.w(s.toDate()[e].apply(s.toDate("s"),(i?[0,0,0,0]:[23,59,59,999]).slice(n)),s)},b=(this||e).$W,_=(this||e).$M,k=(this||e).$D,T="set"+((this||e).$u?"UTC":"");switch(g){case p:return i?l(1,0):l(31,11);case v:return i?l(1,_):l(0,_+1);case f:var Y=this.$locale().weekStart||0,H=(b<Y?b+7:b)-Y;return l(i?k-H:k+(6-H),_);case c:case w:return $(T+"Hours",0);case o:return $(T+"Minutes",1);case a:return $(T+"Seconds",2);case u:return $(T+"Milliseconds",3);default:return this.clone()}},T.endOf=function(e){return this.startOf(e,!1)},T.$set=function(n,r){var s,f=C.p(n),g="set"+((this||e).$u?"UTC":""),b=(s={},s[c]=g+"Date",s[w]=g+"Date",s[v]=g+"Month",s[p]=g+"FullYear",s[o]=g+"Hours",s[a]=g+"Minutes",s[u]=g+"Seconds",s[i]=g+"Milliseconds",s)[f],_=f===c?(this||e).$D+(r-(this||e).$W):r;if(f===v||f===p){var k=this.clone().set(w,1);k.$d[b](_),k.init(),(this||e).$d=k.set(w,Math.min((this||e).$D,k.daysInMonth())).$d}else b&&(this||e).$d[b](_);return this.init(),this||e},T.set=function(e,n){return this.clone().$set(e,n)},T.get=function(e){return this[C.p(e)]()},T.add=function(i,g){var w,b=this||e;i=Number(i);var _=C.p(g),y=function(e){var n=O(b);return C.w(n.date(n.date()+Math.round(e*i)),b)};if(_===v)return this.set(v,(this||e).$M+i);if(_===p)return this.set(p,(this||e).$y+i);if(_===c)return y(1);if(_===f)return y(7);var k=(w={},w[a]=r,w[o]=s,w[u]=n,w)[_]||1,T=(this||e).$d.getTime()+i*k;return C.w(T,this||e)},T.subtract=function(e,n){return this.add(-1*e,n)},T.format=function(n){var r=this||e,s=this.$locale();if(!this.isValid())return s.invalidDate||b;var i=n||"YYYY-MM-DDTHH:mm:ssZ",u=C.z(this||e),a=(this||e).$H,o=(this||e).$m,c=(this||e).$M,f=s.weekdays,v=s.months,g=s.meridiem,h=function(e,n,s,u){return e&&(e[n]||e(r,i))||s[n].slice(0,u)},d=function(e){return C.s(a%12||12,e,"0")},p=g||function(e,n,r){var s=e<12?"AM":"PM";return r?s.toLowerCase():s};return i.replace(k,(function(e,n){return n||function(e){switch(e){case"YY":return String(r.$y).slice(-2);case"YYYY":return C.s(r.$y,4,"0");case"M":return c+1;case"MM":return C.s(c+1,2,"0");case"MMM":return h(s.monthsShort,c,v,3);case"MMMM":return h(v,c);case"D":return r.$D;case"DD":return C.s(r.$D,2,"0");case"d":return String(r.$W);case"dd":return h(s.weekdaysMin,r.$W,f,2);case"ddd":return h(s.weekdaysShort,r.$W,f,3);case"dddd":return f[r.$W];case"H":return String(a);case"HH":return C.s(a,2,"0");case"h":return d(1);case"hh":return d(2);case"a":return p(a,o,!0);case"A":return p(a,o,!1);case"m":return String(o);case"mm":return C.s(o,2,"0");case"s":return String(r.$s);case"ss":return C.s(r.$s,2,"0");case"SSS":return C.s(r.$ms,3,"0");case"Z":return u}return null}(e)||u.replace(":","")}))},T.utcOffset=function(){return 15*-Math.round((this||e).$d.getTimezoneOffset()/15)},T.diff=function(i,w,b){var _,k=this||e,T=C.p(w),Y=O(i),H=(Y.utcOffset()-this.utcOffset())*r,x=(this||e)-Y,D=function(){return C.m(k,Y)};switch(T){case p:_=D()/12;break;case v:_=D();break;case g:_=D()/3;break;case f:_=(x-H)/6048e5;break;case c:_=(x-H)/864e5;break;case o:_=x/s;break;case a:_=x/r;break;case u:_=x/n;break;default:_=x}return b?_:C.a(_)},T.daysInMonth=function(){return this.endOf(v).$D},T.$locale=function(){return x[(this||e).$L]},T.locale=function(n,r){if(!n)return(this||e).$L;var s=this.clone(),i=W(n,r,!0);return i&&(s.$L=i),s},T.clone=function(){return C.w((this||e).$d,this||e)},T.toDate=function(){return new Date(this.valueOf())},T.toJSON=function(){return this.isValid()?this.toISOString():null},T.toISOString=function(){return(this||e).$d.toISOString()},T.toString=function(){return(this||e).$d.toUTCString()},M}(),I=A.prototype;return O.prototype=I,[["$ms",i],["$s",u],["$m",a],["$H",o],["$W",c],["$M",v],["$y",p],["$D",w]].forEach((function(e){I[e[1]]=function(n){return this.$g(n,e[0],e[1])}})),O.extend=function(e,n){return e.$i||(e(n,A,O),e.$i=!0),O},O.locale=W,O.isDayjs=S,O.unix=function(e){return O(1e3*e)},O.en=x[H],O.Ls=x,O.p={},O}));var r=n;export{r as default};
|
4
|
+
|
@@ -0,0 +1,12 @@
|
|
1
|
+
/**
|
2
|
+
* Bundled by jsDelivr using Rollup v2.79.1 and Terser v5.19.2.
|
3
|
+
* Original file: /npm/signature_pad@5.0.4/dist/signature_pad.js
|
4
|
+
*
|
5
|
+
* Do NOT use SRI with dynamically generated files! More information: https://www.jsdelivr.com/using-sri-with-dynamic-files
|
6
|
+
*/
|
7
|
+
/*!
|
8
|
+
* Signature Pad v5.0.4 | https://github.com/szimek/signature_pad
|
9
|
+
* (c) 2024 Szymon Nowak | Released under the MIT license
|
10
|
+
*/
|
11
|
+
class t { constructor(t, e, i, n) { if (isNaN(t) || isNaN(e)) throw new Error(`Point is invalid: (${t}, ${e})`); this.x = +t, this.y = +e, this.pressure = i || 0, this.time = n || Date.now() } distanceTo(t) { return Math.sqrt(Math.pow(this.x - t.x, 2) + Math.pow(this.y - t.y, 2)) } equals(t) { return this.x === t.x && this.y === t.y && this.pressure === t.pressure && this.time === t.time } velocityFrom(t) { return this.time !== t.time ? this.distanceTo(t) / (this.time - t.time) : 0 } } class e { static fromPoints(t, i) { const n = this.calculateControlPoints(t[0], t[1], t[2]).c2, s = this.calculateControlPoints(t[1], t[2], t[3]).c1; return new e(t[1], n, s, t[2], i.start, i.end) } static calculateControlPoints(e, i, n) { const s = e.x - i.x, o = e.y - i.y, r = i.x - n.x, h = i.y - n.y, a = (e.x + i.x) / 2, c = (e.y + i.y) / 2, d = (i.x + n.x) / 2, l = (i.y + n.y) / 2, u = Math.sqrt(s * s + o * o), v = Math.sqrt(r * r + h * h), _ = u + v == 0 ? 0 : v / (u + v), p = d + (a - d) * _, m = l + (c - l) * _, g = i.x - p, w = i.y - m; return { c1: new t(a + g, c + w), c2: new t(d + g, l + w) } } constructor(t, e, i, n, s, o) { this.startPoint = t, this.control2 = e, this.control1 = i, this.endPoint = n, this.startWidth = s, this.endWidth = o } length() { let t, e, i = 0; for (let n = 0; n <= 10; n += 1) { const s = n / 10, o = this.point(s, this.startPoint.x, this.control1.x, this.control2.x, this.endPoint.x), r = this.point(s, this.startPoint.y, this.control1.y, this.control2.y, this.endPoint.y); if (n > 0) { const n = o - t, s = r - e; i += Math.sqrt(n * n + s * s) } t = o, e = r } return i } point(t, e, i, n, s) { return e * (1 - t) * (1 - t) * (1 - t) + 3 * i * (1 - t) * (1 - t) * t + 3 * n * (1 - t) * t * t + s * t * t * t } } class i { constructor() { try { this._et = new EventTarget } catch (t) { this._et = document } } addEventListener(t, e, i) { this._et.addEventListener(t, e, i) } dispatchEvent(t) { return this._et.dispatchEvent(t) } removeEventListener(t, e, i) { this._et.removeEventListener(t, e, i) } } class n extends i { constructor(t, e = {}) { var i, s, o; super(), this.canvas = t, this._drawingStroke = !1, this._isEmpty = !0, this._lastPoints = [], this._data = [], this._lastVelocity = 0, this._lastWidth = 0, this._handleMouseDown = t => { this._isLeftButtonPressed(t, !0) && !this._drawingStroke && this._strokeBegin(this._pointerEventToSignatureEvent(t)) }, this._handleMouseMove = t => { this._isLeftButtonPressed(t, !0) && this._drawingStroke ? this._strokeMoveUpdate(this._pointerEventToSignatureEvent(t)) : this._strokeEnd(this._pointerEventToSignatureEvent(t), !1) }, this._handleMouseUp = t => { this._isLeftButtonPressed(t) || this._strokeEnd(this._pointerEventToSignatureEvent(t)) }, this._handleTouchStart = t => { 1 !== t.targetTouches.length || this._drawingStroke || (t.cancelable && t.preventDefault(), this._strokeBegin(this._touchEventToSignatureEvent(t))) }, this._handleTouchMove = t => { 1 === t.targetTouches.length && (t.cancelable && t.preventDefault(), this._drawingStroke ? this._strokeMoveUpdate(this._touchEventToSignatureEvent(t)) : this._strokeEnd(this._touchEventToSignatureEvent(t), !1)) }, this._handleTouchEnd = t => { 0 === t.targetTouches.length && (t.cancelable && t.preventDefault(), this.canvas.removeEventListener("touchmove", this._handleTouchMove), this._strokeEnd(this._touchEventToSignatureEvent(t))) }, this._handlePointerDown = t => { t.isPrimary && this._isLeftButtonPressed(t) && !this._drawingStroke && (t.preventDefault(), this._strokeBegin(this._pointerEventToSignatureEvent(t))) }, this._handlePointerMove = t => { t.isPrimary && (this._isLeftButtonPressed(t, !0) && this._drawingStroke ? (t.preventDefault(), this._strokeMoveUpdate(this._pointerEventToSignatureEvent(t))) : this._strokeEnd(this._pointerEventToSignatureEvent(t), !1)) }, this._handlePointerUp = t => { t.isPrimary && !this._isLeftButtonPressed(t) && (t.preventDefault(), this._strokeEnd(this._pointerEventToSignatureEvent(t))) }, this.velocityFilterWeight = e.velocityFilterWeight || .7, this.minWidth = e.minWidth || .5, this.maxWidth = e.maxWidth || 2.5, this.throttle = null !== (i = e.throttle) && void 0 !== i ? i : 16, this.minDistance = null !== (s = e.minDistance) && void 0 !== s ? s : 5, this.dotSize = e.dotSize || 0, this.penColor = e.penColor || "black", this.backgroundColor = e.backgroundColor || "rgba(0,0,0,0)", this.compositeOperation = e.compositeOperation || "source-over", this.canvasContextOptions = null !== (o = e.canvasContextOptions) && void 0 !== o ? o : {}, this._strokeMoveUpdate = this.throttle ? function (t, e = 250) { let i, n, s, o = 0, r = null; const h = () => { o = Date.now(), r = null, i = t.apply(n, s), r || (n = null, s = []) }; return function (...a) { const c = Date.now(), d = e - (c - o); return n = this, s = a, d <= 0 || d > e ? (r && (clearTimeout(r), r = null), o = c, i = t.apply(n, s), r || (n = null, s = [])) : r || (r = window.setTimeout(h, d)), i } }(n.prototype._strokeUpdate, this.throttle) : n.prototype._strokeUpdate, this._ctx = t.getContext("2d", this.canvasContextOptions), this.clear(), this.on() } clear() { const { _ctx: t, canvas: e } = this; t.fillStyle = this.backgroundColor, t.clearRect(0, 0, e.width, e.height), t.fillRect(0, 0, e.width, e.height), this._data = [], this._reset(this._getPointGroupOptions()), this._isEmpty = !0 } fromDataURL(t, e = {}) { return new Promise(((i, n) => { const s = new Image, o = e.ratio || window.devicePixelRatio || 1, r = e.width || this.canvas.width / o, h = e.height || this.canvas.height / o, a = e.xOffset || 0, c = e.yOffset || 0; this._reset(this._getPointGroupOptions()), s.onload = () => { this._ctx.drawImage(s, a, c, r, h), i() }, s.onerror = t => { n(t) }, s.crossOrigin = "anonymous", s.src = t, this._isEmpty = !1 })) } toDataURL(t = "image/png", e) { return "image/svg+xml" === t ? ("object" != typeof e && (e = void 0), `data:image/svg+xml;base64,${btoa(this.toSVG(e))}`) : ("number" != typeof e && (e = void 0), this.canvas.toDataURL(t, e)) } on() { this.canvas.style.touchAction = "none", this.canvas.style.msTouchAction = "none", this.canvas.style.userSelect = "none"; const t = /Macintosh/.test(navigator.userAgent) && "ontouchstart" in document; window.PointerEvent && !t ? this._handlePointerEvents() : (this._handleMouseEvents(), "ontouchstart" in window && this._handleTouchEvents()) } off() { this.canvas.style.touchAction = "auto", this.canvas.style.msTouchAction = "auto", this.canvas.style.userSelect = "auto", this.canvas.removeEventListener("pointerdown", this._handlePointerDown), this.canvas.removeEventListener("mousedown", this._handleMouseDown), this.canvas.removeEventListener("touchstart", this._handleTouchStart), this._removeMoveUpEventListeners() } _getListenerFunctions() { var t; const e = window.document === this.canvas.ownerDocument ? window : null !== (t = this.canvas.ownerDocument.defaultView) && void 0 !== t ? t : this.canvas.ownerDocument; return { addEventListener: e.addEventListener.bind(e), removeEventListener: e.removeEventListener.bind(e) } } _removeMoveUpEventListeners() { const { removeEventListener: t } = this._getListenerFunctions(); t("pointermove", this._handlePointerMove), t("pointerup", this._handlePointerUp), t("mousemove", this._handleMouseMove), t("mouseup", this._handleMouseUp), t("touchmove", this._handleTouchMove), t("touchend", this._handleTouchEnd) } isEmpty() { return this._isEmpty } fromData(t, { clear: e = !0 } = {}) { e && this.clear(), this._fromData(t, this._drawCurve.bind(this), this._drawDot.bind(this)), this._data = this._data.concat(t) } toData() { return this._data } _isLeftButtonPressed(t, e) { return e ? 1 === t.buttons : 1 == (1 & t.buttons) } _pointerEventToSignatureEvent(t) { return { event: t, type: t.type, x: t.clientX, y: t.clientY, pressure: "pressure" in t ? t.pressure : 0 } } _touchEventToSignatureEvent(t) { const e = t.changedTouches[0]; return { event: t, type: t.type, x: e.clientX, y: e.clientY, pressure: e.force } } _getPointGroupOptions(t) { return { penColor: t && "penColor" in t ? t.penColor : this.penColor, dotSize: t && "dotSize" in t ? t.dotSize : this.dotSize, minWidth: t && "minWidth" in t ? t.minWidth : this.minWidth, maxWidth: t && "maxWidth" in t ? t.maxWidth : this.maxWidth, velocityFilterWeight: t && "velocityFilterWeight" in t ? t.velocityFilterWeight : this.velocityFilterWeight, compositeOperation: t && "compositeOperation" in t ? t.compositeOperation : this.compositeOperation } } _strokeBegin(t) { if (!this.dispatchEvent(new CustomEvent("beginStroke", { detail: t, cancelable: !0 }))) return; const { addEventListener: e } = this._getListenerFunctions(); switch (t.event.type) { case "mousedown": e("mousemove", this._handleMouseMove), e("mouseup", this._handleMouseUp); break; case "touchstart": e("touchmove", this._handleTouchMove), e("touchend", this._handleTouchEnd); break; case "pointerdown": e("pointermove", this._handlePointerMove), e("pointerup", this._handlePointerUp) }this._drawingStroke = !0; const i = this._getPointGroupOptions(), n = Object.assign(Object.assign({}, i), { points: [] }); this._data.push(n), this._reset(i), this._strokeUpdate(t) } _strokeUpdate(t) { if (!this._drawingStroke) return; if (0 === this._data.length) return void this._strokeBegin(t); this.dispatchEvent(new CustomEvent("beforeUpdateStroke", { detail: t })); const e = this._createPoint(t.x, t.y, t.pressure), i = this._data[this._data.length - 1], n = i.points, s = n.length > 0 && n[n.length - 1], o = !!s && e.distanceTo(s) <= this.minDistance, r = this._getPointGroupOptions(i); if (!s || !s || !o) { const t = this._addPoint(e, r); s ? t && this._drawCurve(t, r) : this._drawDot(e, r), n.push({ time: e.time, x: e.x, y: e.y, pressure: e.pressure }) } this.dispatchEvent(new CustomEvent("afterUpdateStroke", { detail: t })) } _strokeEnd(t, e = !0) { this._removeMoveUpEventListeners(), this._drawingStroke && (e && this._strokeUpdate(t), this._drawingStroke = !1, this.dispatchEvent(new CustomEvent("endStroke", { detail: t }))) } _handlePointerEvents() { this._drawingStroke = !1, this.canvas.addEventListener("pointerdown", this._handlePointerDown) } _handleMouseEvents() { this._drawingStroke = !1, this.canvas.addEventListener("mousedown", this._handleMouseDown) } _handleTouchEvents() { this.canvas.addEventListener("touchstart", this._handleTouchStart) } _reset(t) { this._lastPoints = [], this._lastVelocity = 0, this._lastWidth = (t.minWidth + t.maxWidth) / 2, this._ctx.fillStyle = t.penColor, this._ctx.globalCompositeOperation = t.compositeOperation } _createPoint(e, i, n) { const s = this.canvas.getBoundingClientRect(); return new t(e - s.left, i - s.top, n, (new Date).getTime()) } _addPoint(t, i) { const { _lastPoints: n } = this; if (n.push(t), n.length > 2) { 3 === n.length && n.unshift(n[0]); const t = this._calculateCurveWidths(n[1], n[2], i), s = e.fromPoints(n, t); return n.shift(), s } return null } _calculateCurveWidths(t, e, i) { const n = i.velocityFilterWeight * e.velocityFrom(t) + (1 - i.velocityFilterWeight) * this._lastVelocity, s = this._strokeWidth(n, i), o = { end: s, start: this._lastWidth }; return this._lastVelocity = n, this._lastWidth = s, o } _strokeWidth(t, e) { return Math.max(e.maxWidth / (t + 1), e.minWidth) } _drawCurveSegment(t, e, i) { const n = this._ctx; n.moveTo(t, e), n.arc(t, e, i, 0, 2 * Math.PI, !1), this._isEmpty = !1 } _drawCurve(t, e) { const i = this._ctx, n = t.endWidth - t.startWidth, s = 2 * Math.ceil(t.length()); i.beginPath(), i.fillStyle = e.penColor; for (let i = 0; i < s; i += 1) { const o = i / s, r = o * o, h = r * o, a = 1 - o, c = a * a, d = c * a; let l = d * t.startPoint.x; l += 3 * c * o * t.control1.x, l += 3 * a * r * t.control2.x, l += h * t.endPoint.x; let u = d * t.startPoint.y; u += 3 * c * o * t.control1.y, u += 3 * a * r * t.control2.y, u += h * t.endPoint.y; const v = Math.min(t.startWidth + h * n, e.maxWidth); this._drawCurveSegment(l, u, v) } i.closePath(), i.fill() } _drawDot(t, e) { const i = this._ctx, n = e.dotSize > 0 ? e.dotSize : (e.minWidth + e.maxWidth) / 2; i.beginPath(), this._drawCurveSegment(t.x, t.y, n), i.closePath(), i.fillStyle = e.penColor, i.fill() } _fromData(e, i, n) { for (const s of e) { const { points: e } = s, o = this._getPointGroupOptions(s); if (e.length > 1) for (let n = 0; n < e.length; n += 1) { const s = e[n], r = new t(s.x, s.y, s.pressure, s.time); 0 === n && this._reset(o); const h = this._addPoint(r, o); h && i(h, o) } else this._reset(o), n(e[0], o) } } toSVG({ includeBackgroundColor: t = !1 } = {}) { const e = this._data, i = Math.max(window.devicePixelRatio || 1, 1), n = this.canvas.width / i, s = this.canvas.height / i, o = document.createElementNS("http://www.w3.org/2000/svg", "svg"); if (o.setAttribute("xmlns", "http://www.w3.org/2000/svg"), o.setAttribute("xmlns:xlink", "http://www.w3.org/1999/xlink"), o.setAttribute("viewBox", `0 0 ${n} ${s}`), o.setAttribute("width", n.toString()), o.setAttribute("height", s.toString()), t && this.backgroundColor) { const t = document.createElement("rect"); t.setAttribute("width", "100%"), t.setAttribute("height", "100%"), t.setAttribute("fill", this.backgroundColor), o.appendChild(t) } return this._fromData(e, ((t, { penColor: e }) => { const i = document.createElement("path"); if (!(isNaN(t.control1.x) || isNaN(t.control1.y) || isNaN(t.control2.x) || isNaN(t.control2.y))) { const n = `M ${t.startPoint.x.toFixed(3)},${t.startPoint.y.toFixed(3)} C ${t.control1.x.toFixed(3)},${t.control1.y.toFixed(3)} ${t.control2.x.toFixed(3)},${t.control2.y.toFixed(3)} ${t.endPoint.x.toFixed(3)},${t.endPoint.y.toFixed(3)}`; i.setAttribute("d", n), i.setAttribute("stroke-width", (2.25 * t.endWidth).toFixed(3)), i.setAttribute("stroke", e), i.setAttribute("fill", "none"), i.setAttribute("stroke-linecap", "round"), o.appendChild(i) } }), ((t, { penColor: e, dotSize: i, minWidth: n, maxWidth: s }) => { const r = document.createElement("circle"), h = i > 0 ? i : (n + s) / 2; r.setAttribute("r", h.toString()), r.setAttribute("cx", t.x.toString()), r.setAttribute("cy", t.y.toString()), r.setAttribute("fill", e), o.appendChild(r) })), o.outerHTML } } export { n as default };
|
12
|
+
//# sourceMappingURL=/sm/fcb20b2f86ed10615b8b8c6a0c684f42d4284af51d740bacacf53d4ccdbe767b.map
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: satis
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.1.
|
4
|
+
version: 2.1.54
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Tom de Grunt
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2025-
|
11
|
+
date: 2025-02-04 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: browser
|
@@ -847,6 +847,9 @@ files:
|
|
847
847
|
- app/components/satis/sidebar_menu_item/component_controller.js
|
848
848
|
- app/components/satis/sidebar_menu_item/mobile/component.html.slim
|
849
849
|
- app/components/satis/sidebar_menu_item/mobile/component.rb
|
850
|
+
- app/components/satis/signature/component.html.slim
|
851
|
+
- app/components/satis/signature/component.rb
|
852
|
+
- app/components/satis/signature/component_controller.js
|
850
853
|
- app/components/satis/switch/component.html.slim
|
851
854
|
- app/components/satis/switch/component.rb
|
852
855
|
- app/components/satis/switch/component_controller.js
|
@@ -959,11 +962,16 @@ files:
|
|
959
962
|
- vendor/javascript/codemirror.js
|
960
963
|
- vendor/javascript/crelt.js
|
961
964
|
- vendor/javascript/data.min.js
|
965
|
+
- vendor/javascript/dayjs--plugin--customParseFormat.js
|
966
|
+
- vendor/javascript/dayjs--plugin--localizedFormat.js
|
967
|
+
- vendor/javascript/dayjs--plugin--utc.js
|
968
|
+
- vendor/javascript/dayjs.js
|
962
969
|
- vendor/javascript/intl-tel-input-utils.js
|
963
970
|
- vendor/javascript/intl-tel-input.js
|
964
971
|
- vendor/javascript/leaflet.js
|
965
972
|
- vendor/javascript/pickr.es5.min.js
|
966
973
|
- vendor/javascript/popper.js.js
|
974
|
+
- vendor/javascript/signature_pad.js
|
967
975
|
- vendor/javascript/sortablejs.js
|
968
976
|
- vendor/javascript/style-mod.js
|
969
977
|
- vendor/javascript/tippy.js.js
|