satis 2.1.53 → 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/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
|