satis 2.1.53 → 2.1.54
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/app/components/satis/date_time_picker/component.html.slim +5 -7
- data/app/components/satis/date_time_picker/component_controller.js +29 -9
- 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 +1 -0
- data/lib/satis/configuration.rb +1 -3
- data/lib/satis/forms/builder.rb +9 -25
- data/lib/satis/version.rb +1 -1
- data/vendor/javascript/signature_pad.js +12 -0
- metadata +6 -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
|
@@ -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.text-gray-500.inline-flex.py-1 class=Satis.config.icons[:previous_year]
|
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
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
22
|
i.text-gray-500.inline-flex.px-1.py-1 class=Satis.config.icons[:next_month]
|
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.text-gray-500.inline-flex.py-1 class=Satis.config.icons[:next_year]
|
24
|
-
|
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"
|
@@ -164,21 +164,17 @@ export default class DateTimePickerComponentController extends ApplicationContro
|
|
164
164
|
|
165
165
|
previousMonth(event) {
|
166
166
|
this.displayValue = new Date(new Date(this.displayValue).setMonth(this.displayValue.getMonth() - 1))
|
167
|
+
|
168
|
+
this.updateYear()
|
169
|
+
|
167
170
|
this.refreshCalendar(false)
|
168
171
|
}
|
169
172
|
|
170
173
|
nextMonth(event) {
|
171
174
|
this.displayValue = new Date(new Date(this.displayValue).setMonth(this.displayValue.getMonth() + 1))
|
172
|
-
this.refreshCalendar(false)
|
173
|
-
}
|
174
175
|
|
175
|
-
|
176
|
-
this.displayValue = new Date(new Date(this.displayValue).setFullYear(this.displayValue.getFullYear() - 1))
|
177
|
-
this.refreshCalendar(false)
|
178
|
-
}
|
176
|
+
this.updateYear()
|
179
177
|
|
180
|
-
nextYear(event) {
|
181
|
-
this.displayValue = new Date(new Date(this.displayValue).setFullYear(this.displayValue.getFullYear() + 1))
|
182
178
|
this.refreshCalendar(false)
|
183
179
|
}
|
184
180
|
|
@@ -328,13 +324,17 @@ export default class DateTimePickerComponentController extends ApplicationContro
|
|
328
324
|
return false
|
329
325
|
}
|
330
326
|
selectedDate.setMonth(this.displayValue.getMonth() - 1)
|
327
|
+
this.displayValue = selectedDate
|
331
328
|
} else if (dayType === "next") {
|
332
329
|
if (this.rangeValue) {
|
333
330
|
return false
|
334
331
|
}
|
335
332
|
selectedDate.setMonth(this.displayValue.getMonth() + 1)
|
333
|
+
this.displayValue = selectedDate
|
336
334
|
}
|
337
335
|
|
336
|
+
this.updateYear()
|
337
|
+
|
338
338
|
selectedDate.setDate(+event.target.innerText)
|
339
339
|
|
340
340
|
if (!this.rangeValue && !this.multipleValue) {
|
@@ -559,7 +559,6 @@ export default class DateTimePickerComponentController extends ApplicationContro
|
|
559
559
|
})
|
560
560
|
}
|
561
561
|
}
|
562
|
-
|
563
562
|
// Format the given Date into an ISO8601 string whilst preserving the given timezone
|
564
563
|
iso8601(date) {
|
565
564
|
let tzo = -date.getTimezoneOffset(),
|
@@ -667,4 +666,25 @@ export default class DateTimePickerComponentController extends ApplicationContro
|
|
667
666
|
|
668
667
|
return results
|
669
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
|
+
}
|
670
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
@@ -52,3 +52,4 @@ pin "dayjs" # @1.11.13
|
|
52
52
|
pin "dayjs/plugin/customParseFormat", to: "dayjs--plugin--customParseFormat.js" # @1.11.13
|
53
53
|
pin "dayjs/plugin/localizedFormat", to: "dayjs--plugin--localizedFormat.js" # @1.11.13
|
54
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
@@ -34,10 +34,8 @@ module Satis
|
|
34
34
|
option :current_user, default: lambda {}
|
35
35
|
|
36
36
|
option :icons, default: {
|
37
|
-
previous_year: "fa-solid fa-angle-double-left",
|
38
37
|
previous_month: "fa-solid fa-angle-left",
|
39
|
-
next_month: "fa-solid fa-angle-right"
|
40
|
-
next_year: "fa-solid fa-angle-double-right"
|
38
|
+
next_month: "fa-solid fa-angle-right"
|
41
39
|
}
|
42
40
|
|
43
41
|
option(:default_help_text, default: lambda do |template, object, key, additional_scope|
|
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,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
|
@@ -968,6 +971,7 @@ files:
|
|
968
971
|
- vendor/javascript/leaflet.js
|
969
972
|
- vendor/javascript/pickr.es5.min.js
|
970
973
|
- vendor/javascript/popper.js.js
|
974
|
+
- vendor/javascript/signature_pad.js
|
971
975
|
- vendor/javascript/sortablejs.js
|
972
976
|
- vendor/javascript/style-mod.js
|
973
977
|
- vendor/javascript/tippy.js.js
|