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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f33daf604f4135d4096075528761e22049f97d12f4b908a3479f0e52d03ccaf1
4
- data.tar.gz: 00040d5267c53eb0cca689d969c035d114c4ee9633468fb9d65abfce923fb9fa
3
+ metadata.gz: 8e4087c76633f9b2a02fc083fd95c60a4a28d9677dbe44ee11735e4fa0e29810
4
+ data.tar.gz: 2ab23a72ad341b331ef4c8ea1fc1780d46e32d1657194a4a8d1fb7ca0193db37
5
5
  SHA512:
6
- metadata.gz: bc4cd1f571d86a277c605631e52657eeb244530976d5a37293fa68be3cc4630a1aea3b282a7c212ad0d6988915e76fd439373d01ab7e4539f0d5baceb036da9b
7
- data.tar.gz: 17eba6faa168759e865f40f042c346ba38169ca5169589370e64a84e2f76b4ec466c4eb864855041dbe4a1565d90aa7ba732d424cae9332c644d99520f795ccb
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-white dark:bg-opacity-75 bg-black bg-opacity-50 dark:text-black text-white;
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-72 class="#{inline ? 'inline-block' : 'hidden'}" data-satis-date-time-picker-target="calendarView"
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.fal.fa-angle-left.text-gray-500.inline-flex.px-1.py-1
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
- span.ml-1.text-lg.text-gray-600.dark:text-gray-200.font-normal data-satis-date-time-picker-target="year"
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.fal.fa-angle-right.text-gray-500.inline-flex.px-1.py-1
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
- previousYear(event) {
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
- nextYear(event) {
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
- // FIXME: This doesn't work properly yet
270
- // let newValue
271
- // try {
272
- // newValue = new Date(this.inputTarget.value)
273
- // } catch (error) {}
274
- // if (!isNaN(newValue.getTime())) {
275
- // this.selectedValue = [newValue]
276
- // this.refreshCalendar()
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] = new Date(new Date(this.displayValue).setDate(+event.target.innerText))
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.monthDays.forEach((day) => {
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
- let tmpDiv = document.createElement("div")
404
- tmpDiv.innerHTML = this.dayTemplateTarget.innerHTML.replace(/\${day}/g, day)
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
- if (this.isToday(date)) {
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
- this.daysTarget.insertAdjacentHTML("beforeend", tmpDiv.innerHTML)
433
- tmpDiv.remove()
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: 'popper.js.js', preload: false
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
@@ -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
- alias setup configure
88
+ alias_method :setup, :configure
84
89
 
85
90
  def reset_config!
86
91
  @config = Configuration.new
@@ -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
- # form_group(method, options) do
332
- # safe_join [
333
- # (custom_label(method, options[:label], options) unless options[:label] == false),
334
- # tag.div(text_area(method,
335
- # merge_input_options({
336
- # class: 'form-control hidden',
337
- # data: {
338
- # # controller: 'satis-editor',
339
- # 'satis-editor-target' => 'textarea',
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
@@ -1,3 +1,3 @@
1
1
  module Satis
2
- VERSION = "2.1.52"
2
+ VERSION = "2.1.54"
3
3
  end
@@ -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.52
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-01-23 00:00:00.000000000 Z
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