add LTR script support
This commit is contained in:
+10
-1
@@ -1,3 +1,11 @@
|
|||||||
|
FROM ruby:3.2.2-alpine3.18 as fonts
|
||||||
|
|
||||||
|
WORKDIR /fonts
|
||||||
|
|
||||||
|
RUN apk --no-cache add fontforge wget ttf-liberation && cp /usr/share/fonts/liberation/LiberationSans-Regular.ttf /usr/share/fonts/liberation/LiberationSans-Bold.ttf . && wget https://cdn.jsdelivr.net/gh/notofonts/notofonts.github.io/fonts/NotoSansArabic/hinted/ttf/NotoSansArabic-Regular.ttf && wget https://github.com/impallari/DancingScript/raw/master/fonts/DancingScript-Regular.otf && wget https://github.com/impallari/DancingScript/blob/master/OFL.txt
|
||||||
|
|
||||||
|
RUN fontforge -lang=py -c 'font1 = fontforge.open("LiberationSans-Regular.ttf"); font2 = fontforge.open("NotoSansArabic-Regular.ttf"); font1.mergeFonts(font2); font1.generate("LiberationSans-Regular.ttf")'
|
||||||
|
|
||||||
FROM ruby:3.2.2-alpine3.18 as webpack
|
FROM ruby:3.2.2-alpine3.18 as webpack
|
||||||
|
|
||||||
ENV RAILS_ENV=production
|
ENV RAILS_ENV=production
|
||||||
@@ -31,7 +39,7 @@ ENV BUNDLE_WITHOUT="development:test"
|
|||||||
|
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
RUN apk add --no-cache build-base sqlite-dev libpq-dev mariadb-dev vips-dev vips-poppler poppler-utils vips-heif libc6-compat ttf-freefont ttf-liberation && mkdir /fonts && cp /usr/share/fonts/liberation/LiberationSans-Regular.ttf /usr/share/fonts/liberation/LiberationSans-Bold.ttf /fonts && apk del ttf-liberation && wget -O /fonts/DancingScript.otf "https://github.com/impallari/DancingScript/raw/master/fonts/DancingScript-Regular.otf" && wget -O /fonts/DancingScript-License.txt https://github.com/impallari/DancingScript/blob/master/OFL.txt
|
RUN apk add --no-cache build-base sqlite-dev libpq-dev mariadb-dev vips-dev vips-poppler poppler-utils vips-heif libc6-compat ttf-freefont && mkdir /fonts
|
||||||
|
|
||||||
COPY ./Gemfile ./Gemfile.lock ./
|
COPY ./Gemfile ./Gemfile.lock ./
|
||||||
|
|
||||||
@@ -47,6 +55,7 @@ COPY ./public ./public
|
|||||||
COPY ./tmp ./tmp
|
COPY ./tmp ./tmp
|
||||||
COPY LICENSE README.md Rakefile config.ru ./
|
COPY LICENSE README.md Rakefile config.ru ./
|
||||||
|
|
||||||
|
COPY --from=fonts /fonts/LiberationSans-Regular.ttf /fonts/LiberationSans-Bold.ttf /fonts/DancingScript-Regular.otf /fonts/OFL.txt /fonts
|
||||||
COPY --from=webpack /app/public/packs ./public/packs
|
COPY --from=webpack /app/public/packs ./public/packs
|
||||||
|
|
||||||
RUN ln -s /fonts /app/public/fonts
|
RUN ln -s /fonts /app/public/fonts
|
||||||
|
|||||||
@@ -32,6 +32,8 @@ export default class extends HTMLElement {
|
|||||||
render = (item) => {
|
render = (item) => {
|
||||||
const div = document.createElement('div')
|
const div = document.createElement('div')
|
||||||
|
|
||||||
|
div.setAttribute('dir', 'auto')
|
||||||
|
|
||||||
div.textContent = item.name
|
div.textContent = item.name
|
||||||
|
|
||||||
return div
|
return div
|
||||||
|
|||||||
@@ -56,6 +56,8 @@ export default class extends HTMLElement {
|
|||||||
render = (item) => {
|
render = (item) => {
|
||||||
const div = document.createElement('div')
|
const div = document.createElement('div')
|
||||||
|
|
||||||
|
div.setAttribute('dir', 'auto')
|
||||||
|
|
||||||
div.textContent = item[this.dataset.field]
|
div.textContent = item[this.dataset.field]
|
||||||
|
|
||||||
return div
|
return div
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div
|
<div
|
||||||
class="flex absolute lg:text-base"
|
class="flex absolute lg:text-base"
|
||||||
|
dir="auto"
|
||||||
:style="computedStyle"
|
:style="computedStyle"
|
||||||
:class="{ 'text-[1.5vw] lg:text-base': !textOverflowChars, 'text-[1.0vw] lg:text-xs': textOverflowChars, 'cursor-default': !submittable, 'bg-red-100 border cursor-pointer ': submittable, 'border-red-100': !isActive && submittable, 'bg-opacity-80': !isActive && !isValueSet && submittable, 'border-red-500 border-dashed border-2 z-10': isActive && submittable, 'bg-opacity-40': (isActive || isValueSet) && submittable }"
|
:class="{ 'text-[1.5vw] lg:text-base': !textOverflowChars, 'text-[1.0vw] lg:text-xs': textOverflowChars, 'cursor-default': !submittable, 'bg-red-100 border cursor-pointer ': submittable, 'border-red-100': !isActive && submittable, 'bg-opacity-80': !isActive && !isValueSet && submittable, 'border-red-500 border-dashed border-2 z-10': isActive && submittable, 'bg-opacity-40': (isActive || isValueSet) && submittable }"
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div dir="auto">
|
||||||
<div class="flex justify-between items-center w-full mb-2">
|
<div class="flex justify-between items-center w-full mb-2">
|
||||||
<label
|
<label
|
||||||
:for="field.uuid"
|
:for="field.uuid"
|
||||||
|
|||||||
@@ -79,6 +79,7 @@
|
|||||||
<label
|
<label
|
||||||
v-if="currentField.name"
|
v-if="currentField.name"
|
||||||
:for="currentField.uuid"
|
:for="currentField.uuid"
|
||||||
|
dir="auto"
|
||||||
class="label text-2xl mb-2"
|
class="label text-2xl mb-2"
|
||||||
>{{ currentField.name }}
|
>{{ currentField.name }}
|
||||||
<template v-if="!currentField.required">({{ t('optional') }})</template>
|
<template v-if="!currentField.required">({{ t('optional') }})</template>
|
||||||
@@ -90,6 +91,7 @@
|
|||||||
<AppearsOn :field="currentField" />
|
<AppearsOn :field="currentField" />
|
||||||
<select
|
<select
|
||||||
:id="currentField.uuid"
|
:id="currentField.uuid"
|
||||||
|
dir="auto"
|
||||||
:required="currentField.required"
|
:required="currentField.required"
|
||||||
class="select base-input !text-2xl w-full text-center font-normal"
|
class="select base-input !text-2xl w-full text-center font-normal"
|
||||||
:name="`values[${currentField.uuid}]`"
|
:name="`values[${currentField.uuid}]`"
|
||||||
@@ -116,6 +118,7 @@
|
|||||||
<label
|
<label
|
||||||
v-if="currentField.name"
|
v-if="currentField.name"
|
||||||
:for="currentField.uuid"
|
:for="currentField.uuid"
|
||||||
|
dir="auto"
|
||||||
class="label text-2xl mb-2"
|
class="label text-2xl mb-2"
|
||||||
>{{ currentField.name }}
|
>{{ currentField.name }}
|
||||||
<template v-if="!currentField.required">({{ t('optional') }})</template>
|
<template v-if="!currentField.required">({{ t('optional') }})</template>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div dir="auto">
|
||||||
<div class="flex justify-between items-center w-full mb-2">
|
<div class="flex justify-between items-center w-full mb-2">
|
||||||
<label
|
<label
|
||||||
class="label text-2xl"
|
class="label text-2xl"
|
||||||
@@ -24,7 +24,7 @@
|
|||||||
</span>
|
</span>
|
||||||
<span
|
<span
|
||||||
v-else
|
v-else
|
||||||
class="tooltip"
|
class="tooltip ml-2"
|
||||||
:data-tip="t('draw_initials')"
|
:data-tip="t('draw_initials')"
|
||||||
>
|
>
|
||||||
<a
|
<a
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
<label
|
<label
|
||||||
v-if="field.name"
|
v-if="field.name"
|
||||||
:for="field.uuid"
|
:for="field.uuid"
|
||||||
|
dir="auto"
|
||||||
class="label text-2xl mb-2"
|
class="label text-2xl mb-2"
|
||||||
>{{ field.name }}</label>
|
>{{ field.name }}</label>
|
||||||
<div class="flex w-full">
|
<div class="flex w-full">
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div dir="auto">
|
||||||
<div class="flex justify-between items-center w-full mb-2">
|
<div class="flex justify-between items-center w-full mb-2">
|
||||||
<label
|
<label
|
||||||
class="label text-2xl"
|
class="label text-2xl"
|
||||||
@@ -24,7 +24,7 @@
|
|||||||
</span>
|
</span>
|
||||||
<span
|
<span
|
||||||
v-else-if="withTypedSignature"
|
v-else-if="withTypedSignature"
|
||||||
class="tooltip"
|
class="tooltip ml-2"
|
||||||
:data-tip="t('type_text')"
|
:data-tip="t('type_text')"
|
||||||
>
|
>
|
||||||
<a
|
<a
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
<label
|
<label
|
||||||
v-if="field.name"
|
v-if="field.name"
|
||||||
:for="field.uuid"
|
:for="field.uuid"
|
||||||
|
dir="auto"
|
||||||
class="label text-2xl mb-2"
|
class="label text-2xl mb-2"
|
||||||
>{{ field.name }}
|
>{{ field.name }}
|
||||||
<template v-if="!field.required">({{ t('optional') }})</template>
|
<template v-if="!field.required">({{ t('optional') }})</template>
|
||||||
@@ -17,6 +18,7 @@
|
|||||||
:id="field.uuid"
|
:id="field.uuid"
|
||||||
v-model="text"
|
v-model="text"
|
||||||
:maxlength="cellsMaxLegth"
|
:maxlength="cellsMaxLegth"
|
||||||
|
dir="auto"
|
||||||
class="base-input !text-2xl w-full !pr-11 -mr-10"
|
class="base-input !text-2xl w-full !pr-11 -mr-10"
|
||||||
:required="field.required"
|
:required="field.required"
|
||||||
:pattern="field.validation?.pattern"
|
:pattern="field.validation?.pattern"
|
||||||
|
|||||||
@@ -61,6 +61,7 @@
|
|||||||
v-if="field.type !== 'checkbox' || field.name"
|
v-if="field.type !== 'checkbox' || field.name"
|
||||||
ref="name"
|
ref="name"
|
||||||
:contenteditable="editable && !defaultField"
|
:contenteditable="editable && !defaultField"
|
||||||
|
dir="auto"
|
||||||
class="pr-1 cursor-text outline-none block"
|
class="pr-1 cursor-text outline-none block"
|
||||||
style="min-width: 2px"
|
style="min-width: 2px"
|
||||||
@keydown.enter.prevent="onNameEnter"
|
@keydown.enter.prevent="onNameEnter"
|
||||||
@@ -83,7 +84,7 @@
|
|||||||
class="label text-xs"
|
class="label text-xs"
|
||||||
@click.prevent="field.required = !field.required"
|
@click.prevent="field.required = !field.required"
|
||||||
@mousedown.prevent
|
@mousedown.prevent
|
||||||
>Required</label>
|
>{{ t('required') }}</label>
|
||||||
</div>
|
</div>
|
||||||
<button
|
<button
|
||||||
v-else-if="editable"
|
v-else-if="editable"
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
ref="contenteditable"
|
ref="contenteditable"
|
||||||
|
dir="auto"
|
||||||
:contenteditable="editable"
|
:contenteditable="editable"
|
||||||
style="min-width: 2px"
|
style="min-width: 2px"
|
||||||
:class="iconInline ? 'inline' : 'block'"
|
:class="iconInline ? 'inline' : 'block'"
|
||||||
|
|||||||
@@ -102,6 +102,7 @@
|
|||||||
v-model="field.default_value"
|
v-model="field.default_value"
|
||||||
type="text"
|
type="text"
|
||||||
:placeholder="t('default_value')"
|
:placeholder="t('default_value')"
|
||||||
|
dir="auto"
|
||||||
class="input input-bordered input-xs w-full max-w-xs h-7 !outline-0"
|
class="input input-bordered input-xs w-full max-w-xs h-7 !outline-0"
|
||||||
@blur="save"
|
@blur="save"
|
||||||
>
|
>
|
||||||
@@ -249,6 +250,7 @@
|
|||||||
v-model="option.value"
|
v-model="option.value"
|
||||||
class="w-full input input-primary input-xs text-sm bg-transparent !pr-7 -mr-6"
|
class="w-full input input-primary input-xs text-sm bg-transparent !pr-7 -mr-6"
|
||||||
type="text"
|
type="text"
|
||||||
|
dir="auto"
|
||||||
required
|
required
|
||||||
:placeholder="`${t('option')} ${index + 1}`"
|
:placeholder="`${t('option')} ${index + 1}`"
|
||||||
@blur="save"
|
@blur="save"
|
||||||
@@ -271,6 +273,7 @@
|
|||||||
:placeholder="`${t('option')} ${index + 1}`"
|
:placeholder="`${t('option')} ${index + 1}`"
|
||||||
type="text"
|
type="text"
|
||||||
required
|
required
|
||||||
|
dir="auto"
|
||||||
@focus="maybeFocusOnOptionArea(option)"
|
@focus="maybeFocusOnOptionArea(option)"
|
||||||
@blur="save"
|
@blur="save"
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
<%= f.fields_for current_account do |ff| %>
|
<%= f.fields_for current_account do |ff| %>
|
||||||
<div class="form-control">
|
<div class="form-control">
|
||||||
<%= ff.label :name, 'Company Name', class: 'label' %>
|
<%= ff.label :name, 'Company Name', class: 'label' %>
|
||||||
<%= ff.text_field :name, required: true, class: 'base-input' %>
|
<%= ff.text_field :name, required: true, class: 'base-input', dir: 'auto' %>
|
||||||
</div>
|
</div>
|
||||||
<div class="grid md:grid-cols-2 gap-4">
|
<div class="grid md:grid-cols-2 gap-4">
|
||||||
<div class="form-control">
|
<div class="form-control">
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
<style>
|
<style>
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body dir="auto">
|
||||||
<%= yield %>
|
<%= yield %>
|
||||||
<%= render partial: 'shared/mailer_attribution' %>
|
<%= render partial: 'shared/mailer_attribution' %>
|
||||||
</body>
|
</body>
|
||||||
|
|||||||
@@ -11,12 +11,12 @@
|
|||||||
<%= f.fields_for :value, Struct.new(:subject, :body).new(*f.object.value.values_at('subject', 'body')) do |ff| %>
|
<%= f.fields_for :value, Struct.new(:subject, :body).new(*f.object.value.values_at('subject', 'body')) do |ff| %>
|
||||||
<div class="form-control">
|
<div class="form-control">
|
||||||
<%= ff.label :subject, class: 'label' %>
|
<%= ff.label :subject, class: 'label' %>
|
||||||
<%= ff.text_field :subject, required: true, class: 'base-input' %>
|
<%= ff.text_field :subject, required: true, class: 'base-input', dir: 'auto' %>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-control">
|
<div class="form-control">
|
||||||
<%= ff.label :body, class: 'label' %>
|
<%= ff.label :body, class: 'label' %>
|
||||||
<autoresize-textarea>
|
<autoresize-textarea>
|
||||||
<%= ff.text_area :body, required: true, class: 'base-input w-full py-2' %>
|
<%= ff.text_area :body, required: true, class: 'base-input w-full py-2', dir: 'auto' %>
|
||||||
</autoresize-textarea>
|
</autoresize-textarea>
|
||||||
</div>
|
</div>
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
<%= f.fields_for :value, Struct.new(:title, :url).new(*(f.object.value || {}).values_at('title', 'url')) do |ff| %>
|
<%= f.fields_for :value, Struct.new(:title, :url).new(*(f.object.value || {}).values_at('title', 'url')) do |ff| %>
|
||||||
<div class="form-control">
|
<div class="form-control">
|
||||||
<%= ff.label :title, 'Button title', class: 'label' %>
|
<%= ff.label :title, 'Button title', class: 'label' %>
|
||||||
<%= ff.text_field :title, class: 'base-input' %>
|
<%= ff.text_field :title, class: 'base-input', dir: 'auto' %>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-control">
|
<div class="form-control">
|
||||||
<%= ff.label :url, 'Button URL', class: 'label' %>
|
<%= ff.label :url, 'Button URL', class: 'label' %>
|
||||||
|
|||||||
@@ -11,12 +11,12 @@
|
|||||||
<%= f.fields_for :value, Struct.new(:subject, :body).new(*f.object.value.values_at('subject', 'body')) do |ff| %>
|
<%= f.fields_for :value, Struct.new(:subject, :body).new(*f.object.value.values_at('subject', 'body')) do |ff| %>
|
||||||
<div class="form-control">
|
<div class="form-control">
|
||||||
<%= ff.label :subject, class: 'label' %>
|
<%= ff.label :subject, class: 'label' %>
|
||||||
<%= ff.text_field :subject, required: true, class: 'base-input' %>
|
<%= ff.text_field :subject, required: true, class: 'base-input', dir: 'auto' %>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-control">
|
<div class="form-control">
|
||||||
<%= ff.label :body, class: 'label' %>
|
<%= ff.label :body, class: 'label' %>
|
||||||
<autoresize-textarea>
|
<autoresize-textarea>
|
||||||
<%= ff.text_area :body, required: true, class: 'base-input w-full py-2' %>
|
<%= ff.text_area :body, required: true, class: 'base-input w-full py-2', dir: 'auto' %>
|
||||||
</autoresize-textarea>
|
</autoresize-textarea>
|
||||||
</div>
|
</div>
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|||||||
@@ -11,12 +11,12 @@
|
|||||||
<%= f.fields_for :value, Struct.new(:subject, :body).new(*f.object.value.values_at('subject', 'body')) do |ff| %>
|
<%= f.fields_for :value, Struct.new(:subject, :body).new(*f.object.value.values_at('subject', 'body')) do |ff| %>
|
||||||
<div class="form-control">
|
<div class="form-control">
|
||||||
<%= ff.label :subject, class: 'label' %>
|
<%= ff.label :subject, class: 'label' %>
|
||||||
<%= ff.text_field :subject, required: true, class: 'base-input' %>
|
<%= ff.text_field :subject, required: true, class: 'base-input', dir: 'auto' %>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-control">
|
<div class="form-control">
|
||||||
<%= ff.label :body, class: 'label' %>
|
<%= ff.label :body, class: 'label' %>
|
||||||
<autoresize-textarea>
|
<autoresize-textarea>
|
||||||
<%= ff.text_area :body, required: true, class: 'base-input w-full py-2' %>
|
<%= ff.text_area :body, required: true, class: 'base-input w-full py-2', dir: 'auto' %>
|
||||||
</autoresize-textarea>
|
</autoresize-textarea>
|
||||||
</div>
|
</div>
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|||||||
@@ -6,11 +6,11 @@
|
|||||||
<div class="grid md:grid-cols-2 gap-4">
|
<div class="grid md:grid-cols-2 gap-4">
|
||||||
<div class="form-control">
|
<div class="form-control">
|
||||||
<%= f.label :first_name, class: 'label' %>
|
<%= f.label :first_name, class: 'label' %>
|
||||||
<%= f.text_field :first_name, required: true, class: 'base-input' %>
|
<%= f.text_field :first_name, required: true, class: 'base-input', dir: 'auto' %>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-control">
|
<div class="form-control">
|
||||||
<%= f.label :last_name, class: 'label' %>
|
<%= f.label :last_name, class: 'label' %>
|
||||||
<%= f.text_field :last_name, required: true, class: 'base-input' %>
|
<%= f.text_field :last_name, required: true, class: 'base-input', dir: 'auto' %>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-control">
|
<div class="form-control">
|
||||||
|
|||||||
@@ -18,7 +18,7 @@
|
|||||||
<% end %>
|
<% end %>
|
||||||
<input type="hidden" name="submission[1][submitters][][uuid]" value="<%= item['uuid'] %>">
|
<input type="hidden" name="submission[1][submitters][][uuid]" value="<%= item['uuid'] %>">
|
||||||
<submitters-autocomplete data-field="name">
|
<submitters-autocomplete data-field="name">
|
||||||
<%= tag.input type: 'text', name: 'submission[1][submitters][][name]', autocomplete: 'off', class: 'input input-sm input-bordered w-full', placeholder: 'Name', required: index.zero?, value: params[:selfsign] && index.zero? ? current_user.full_name : '' %>
|
<%= tag.input type: 'text', name: 'submission[1][submitters][][name]', autocomplete: 'off', class: 'input input-sm input-bordered w-full', placeholder: 'Name', required: index.zero?, value: params[:selfsign] && index.zero? ? current_user.full_name : '', dir: 'auto' %>
|
||||||
</submitters-autocomplete>
|
</submitters-autocomplete>
|
||||||
<div class="grid <%= 'md:grid-cols-2 gap-1' if template.submitters.size == 1 %>">
|
<div class="grid <%= 'md:grid-cols-2 gap-1' if template.submitters.size == 1 %>">
|
||||||
<submitters-autocomplete data-field="email">
|
<submitters-autocomplete data-field="email">
|
||||||
|
|||||||
@@ -23,14 +23,14 @@
|
|||||||
</submitters-autocomplete>
|
</submitters-autocomplete>
|
||||||
<% if template.submitters.size > 1 %>
|
<% if template.submitters.size > 1 %>
|
||||||
<submitters-autocomplete data-field="name">
|
<submitters-autocomplete data-field="name">
|
||||||
<input type="text" name="submission[1][submitters][][name]" autocomplete="off" class="input input-sm input-bordered mt-1.5 w-full" placeholder="Name (optional)" value="<%= params[:selfsign] && index.zero? ? current_user.full_name : '' %>">
|
<input type="text" name="submission[1][submitters][][name]" autocomplete="off" class="input input-sm input-bordered mt-1.5 w-full" placeholder="Name (optional)" value="<%= params[:selfsign] && index.zero? ? current_user.full_name : '' %>" dir="auto">
|
||||||
</submitters-autocomplete>
|
</submitters-autocomplete>
|
||||||
<% end %>
|
<% end %>
|
||||||
</div>
|
</div>
|
||||||
<% if template.submitters.size == 1 %>
|
<% if template.submitters.size == 1 %>
|
||||||
<div class="form-control flex">
|
<div class="form-control flex">
|
||||||
<submitters-autocomplete data-field="name">
|
<submitters-autocomplete data-field="name">
|
||||||
<input type="text" name="submission[1][submitters][][name]" autocomplete="off" class="input input-sm input-bordered w-full" placeholder="Name (optional)" value="<%= params[:selfsign] && index.zero? ? current_user.full_name : '' %>">
|
<input type="text" name="submission[1][submitters][][name]" autocomplete="off" class="input input-sm input-bordered w-full" placeholder="Name (optional)" value="<%= params[:selfsign] && index.zero? ? current_user.full_name : '' %>" dir="auto">
|
||||||
</submitters-autocomplete>
|
</submitters-autocomplete>
|
||||||
</div>
|
</div>
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|||||||
@@ -33,12 +33,12 @@
|
|||||||
<div class="form-control space-y-2">
|
<div class="form-control space-y-2">
|
||||||
<div class="form-control">
|
<div class="form-control">
|
||||||
<%= f.label :subject, class: 'label' %>
|
<%= f.label :subject, class: 'label' %>
|
||||||
<%= f.text_field :subject, value: config.value['subject'], required: true, class: '!text-sm base-input w-full' %>
|
<%= f.text_field :subject, value: config.value['subject'], required: true, class: '!text-sm base-input w-full', dir: 'auto' %>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-control">
|
<div class="form-control">
|
||||||
<%= f.label :message, 'Body', class: 'label' %>
|
<%= f.label :message, 'Body', class: 'label' %>
|
||||||
<autoresize-textarea>
|
<autoresize-textarea>
|
||||||
<%= f.text_area :body, value: config.value['body'], required: true, class: 'base-textarea w-full', rows: 10 %>
|
<%= f.text_area :body, value: config.value['body'], required: true, class: 'base-textarea w-full', rows: 10, dir: 'auto' %>
|
||||||
</autoresize-textarea>
|
</autoresize-textarea>
|
||||||
</div>
|
</div>
|
||||||
<%= render 'message_fields' %>
|
<%= render 'message_fields' %>
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
<field-value class="flex absolute text-[1.5vw] lg:text-base" style="width: <%= area['w'] * 100 %>%; height: <%= area['h'] * 100 %>%; left: <%= area['x'] * 100 %>%; top: <%= area['y'] * 100 %>%">
|
<field-value dir="auto" class="flex absolute text-[1.5vw] lg:text-base" style="width: <%= area['w'] * 100 %>%; height: <%= area['h'] * 100 %>%; left: <%= area['x'] * 100 %>%; top: <%= area['y'] * 100 %>%">
|
||||||
<% if field['type'].in?(['signature', 'image', 'initials', 'stamp']) %>
|
<% if field['type'].in?(['signature', 'image', 'initials', 'stamp']) %>
|
||||||
<img class="object-contain mx-auto" src="<%= attachments_index[value].url %>" loading="lazy">
|
<img class="object-contain mx-auto" src="<%= attachments_index[value].url %>" loading="lazy">
|
||||||
<% elsif field['type'].in?(['file', 'payment']) %>
|
<% elsif field['type'].in?(['file', 'payment']) %>
|
||||||
|
|||||||
@@ -35,7 +35,7 @@
|
|||||||
<% document = @submission.template_schema_documents.find { |a| item['attachment_uuid'] == a.uuid } %>
|
<% document = @submission.template_schema_documents.find { |a| item['attachment_uuid'] == a.uuid } %>
|
||||||
<a href="#<%= "page-#{document.uuid}-0" %>" onclick="[event.preventDefault(), window[event.target.closest('a').href.split('#')[1]].scrollIntoView({ behavior: 'smooth', block: 'start' })]" class="block cursor-pointer">
|
<a href="#<%= "page-#{document.uuid}-0" %>" onclick="[event.preventDefault(), window[event.target.closest('a').href.split('#')[1]].scrollIntoView({ behavior: 'smooth', block: 'start' })]" class="block cursor-pointer">
|
||||||
<img src="<%= document.preview_images.first.url %>" width="<%= document.preview_images.first.metadata['width'] %>" height="<%= document.preview_images.first.metadata['height'] %>" class="rounded border" loading="lazy">
|
<img src="<%= document.preview_images.first.url %>" width="<%= document.preview_images.first.metadata['width'] %>" height="<%= document.preview_images.first.metadata['height'] %>" class="rounded border" loading="lazy">
|
||||||
<div class="pb-2 pt-1.5 text-center">
|
<div class="pb-2 pt-1.5 text-center" dir="auto">
|
||||||
<%= item['name'].presence || document.filename.base %>
|
<%= item['name'].presence || document.filename.base %>
|
||||||
</div>
|
</div>
|
||||||
</a>
|
</a>
|
||||||
@@ -81,7 +81,7 @@
|
|||||||
<div class="border border-base-300 rounded-md px-2 py-1 mb-1">
|
<div class="border border-base-300 rounded-md px-2 py-1 mb-1">
|
||||||
<div class="flex items-center space-x-1">
|
<div class="flex items-center space-x-1">
|
||||||
<span class="mx-1 w-3 h-3 rounded-full <%= colors[index] %>"></span>
|
<span class="mx-1 w-3 h-3 rounded-full <%= colors[index] %>"></span>
|
||||||
<span class="text-lg">
|
<span class="text-lg" dir="auto">
|
||||||
<%= (@submission.template_submitters || @submission.template.submitters).find { |e| e['uuid'] == submitter&.uuid }&.dig('name') || "#{(index + 1).ordinalize} Submitter" %>
|
<%= (@submission.template_submitters || @submission.template.submitters).find { |e| e['uuid'] == submitter&.uuid }&.dig('name') || "#{(index + 1).ordinalize} Submitter" %>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
@@ -138,10 +138,10 @@
|
|||||||
<% value = values[field['uuid']] %>
|
<% value = values[field['uuid']] %>
|
||||||
<% next if value.blank? %>
|
<% next if value.blank? %>
|
||||||
<div class="pt-2.5 border-b border-base-300">
|
<div class="pt-2.5 border-b border-base-300">
|
||||||
<div class="text-xs font-medium uppercase mb-0.5">
|
<div class="text-xs font-medium uppercase mb-0.5" dir="auto">
|
||||||
<%= field['name'].presence || "#{field['type'].titleize} Field #{submitter_field_counters[field['type']]}" %>
|
<%= field['name'].presence || "#{field['type'].titleize} Field #{submitter_field_counters[field['type']]}" %>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div dir="auto">
|
||||||
<% if field['type'].in?(%w[signature initials]) %>
|
<% if field['type'].in?(%w[signature initials]) %>
|
||||||
<div class="w-full bg-base-300 py-1">
|
<div class="w-full bg-base-300 py-1">
|
||||||
<img class="object-contain mx-auto" height="<%= attachments_index[value].metadata['height'] %>" width="<%= attachments_index[value].metadata['width'] %>" src="<%= attachments_index[value].url %>" loading="lazy">
|
<img class="object-contain mx-auto" height="<%= attachments_index[value].metadata['height'] %>" width="<%= attachments_index[value].metadata['width'] %>" src="<%= attachments_index[value].url %>" loading="lazy">
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<%= render 'shared/turbo_modal', title: 'Rename Folder' do %>
|
<%= render 'shared/turbo_modal', title: 'Rename Folder' do %>
|
||||||
<%= form_for @template_folder, url: folder_path(@template_folder), data: { turbo_frame: :_top }, html: { autocomplete: :off } do |f| %>
|
<%= form_for @template_folder, url: folder_path(@template_folder), data: { turbo_frame: :_top }, html: { autocomplete: :off } do |f| %>
|
||||||
<div class="form-control my-6">
|
<div class="form-control my-6">
|
||||||
<%= f.text_field :name, required: true, placeholder: 'Folder Name...', class: 'base-input w-full', autofocus: true %>
|
<%= f.text_field :name, required: true, placeholder: 'Folder Name...', class: 'base-input w-full', autofocus: true, dir: 'auto' %>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-control">
|
<div class="form-control">
|
||||||
<%= f.button button_title(title: 'Rename', disabled_with: 'Saving'), class: 'base-button' %>
|
<%= f.button button_title(title: 'Rename', disabled_with: 'Saving'), class: 'base-button' %>
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
<%= hidden_field_tag :base_template_id, @base_template.id %>
|
<%= hidden_field_tag :base_template_id, @base_template.id %>
|
||||||
<% end %>
|
<% end %>
|
||||||
<div class="form-control mt-6">
|
<div class="form-control mt-6">
|
||||||
<%= f.text_field :name, required: true, placeholder: 'Document Name', class: 'base-input' %>
|
<%= f.text_field :name, required: true, placeholder: 'Document Name', class: 'base-input', dir: 'auto' %>
|
||||||
</div>
|
</div>
|
||||||
<div class="mt-3 mb-4 flex items-center justify-between">
|
<div class="mt-3 mb-4 flex items-center justify-between">
|
||||||
<a href="#" onclick="[event.preventDefault(), window.folder_name.focus()]">
|
<a href="#" onclick="[event.preventDefault(), window.folder_name.focus()]">
|
||||||
|
|||||||
@@ -2,11 +2,11 @@
|
|||||||
<div class="space-y-2">
|
<div class="space-y-2">
|
||||||
<div class="form-control">
|
<div class="form-control">
|
||||||
<%= f.label :first_name, class: 'label' %>
|
<%= f.label :first_name, class: 'label' %>
|
||||||
<%= f.text_field :first_name, required: true, class: 'base-input' %>
|
<%= f.text_field :first_name, required: true, class: 'base-input', dir: 'auto' %>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-control">
|
<div class="form-control">
|
||||||
<%= f.label :last_name, class: 'label' %>
|
<%= f.label :last_name, class: 'label' %>
|
||||||
<%= f.text_field :last_name, required: true, class: 'base-input' %>
|
<%= f.text_field :last_name, required: true, class: 'base-input', dir: 'auto' %>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-control">
|
<div class="form-control">
|
||||||
<%= f.label :email, class: 'label' %>
|
<%= f.label :email, class: 'label' %>
|
||||||
|
|||||||
@@ -27,6 +27,8 @@ module Submissions
|
|||||||
'GBP' => '£'
|
'GBP' => '£'
|
||||||
}.freeze
|
}.freeze
|
||||||
|
|
||||||
|
RTL_REGEXP = Submissions::GenerateResultAttachments::RTL_REGEXP
|
||||||
|
|
||||||
module_function
|
module_function
|
||||||
|
|
||||||
# rubocop:disable Metrics
|
# rubocop:disable Metrics
|
||||||
@@ -147,7 +149,7 @@ module Submissions
|
|||||||
[
|
[
|
||||||
submission.template_submitters.size > 1 && { text: "#{item['name']}\n" },
|
submission.template_submitters.size > 1 && { text: "#{item['name']}\n" },
|
||||||
submitter.email && { text: "#{submitter.email}\n", font: [FONT_BOLD_NAME, { variant: :bold }] },
|
submitter.email && { text: "#{submitter.email}\n", font: [FONT_BOLD_NAME, { variant: :bold }] },
|
||||||
submitter.name && { text: "#{submitter.name}\n" },
|
submitter.name && { text: "#{maybe_rtl_reverse(submitter.name)}\n" },
|
||||||
submitter.phone && { text: "#{submitter.phone}\n" }
|
submitter.phone && { text: "#{submitter.phone}\n" }
|
||||||
].compact_blank, line_spacing: 1.8, padding: [0, 20, 0, 0]
|
].compact_blank, line_spacing: 1.8, padding: [0, 20, 0, 0]
|
||||||
)
|
)
|
||||||
@@ -185,11 +187,13 @@ module Submissions
|
|||||||
composer.formatted_text_box(
|
composer.formatted_text_box(
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
text: field['name'].to_s.upcase.presence ||
|
text: maybe_rtl_reverse(field['name'].to_s).upcase.presence ||
|
||||||
"#{field['type']} Field #{submitter_field_counters[field['type']]}\n".upcase,
|
"#{field['type']} Field #{submitter_field_counters[field['type']]}\n".upcase,
|
||||||
font_size: 6
|
font_size: 6
|
||||||
}
|
}
|
||||||
].compact_blank, line_spacing: 1.8, padding: [0, 0, 5, 0]
|
].compact_blank,
|
||||||
|
align: field['name'].to_s.match?(RTL_REGEXP) ? :right : :left,
|
||||||
|
line_spacing: 1.8, padding: [0, 0, 5, 0]
|
||||||
),
|
),
|
||||||
if field['type'].in?(%w[image signature initials stamp])
|
if field['type'].in?(%w[image signature initials stamp])
|
||||||
attachment = submitter.attachments.find { |a| a.uuid == value }
|
attachment = submitter.attachments.find { |a| a.uuid == value }
|
||||||
@@ -233,7 +237,9 @@ module Submissions
|
|||||||
|
|
||||||
value = value.join(', ') if value.is_a?(Array)
|
value = value.join(', ') if value.is_a?(Array)
|
||||||
|
|
||||||
composer.formatted_text_box([{ text: value.to_s.presence || 'n/a' }], padding: [0, 0, 10, 0])
|
composer.formatted_text_box([{ text: maybe_rtl_reverse(value.to_s.presence || 'n/a') }],
|
||||||
|
align: value.to_s.match?(RTL_REGEXP) ? :right : :left,
|
||||||
|
padding: [0, 0, 10, 0])
|
||||||
end
|
end
|
||||||
]
|
]
|
||||||
end
|
end
|
||||||
@@ -292,6 +298,14 @@ module Submissions
|
|||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def maybe_rtl_reverse(text)
|
||||||
|
if text.match?(RTL_REGEXP)
|
||||||
|
text.reverse
|
||||||
|
else
|
||||||
|
text
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def add_logo(column, _submission = nil)
|
def add_logo(column, _submission = nil)
|
||||||
column.image(PdfIcons.logo_io, width: 40, height: 40, position: :float)
|
column.image(PdfIcons.logo_io, width: 40, height: 40, position: :float)
|
||||||
|
|
||||||
|
|||||||
@@ -13,6 +13,8 @@ module Submissions
|
|||||||
SIGN_REASON = 'Signed by %<name>s with DocuSeal.co'
|
SIGN_REASON = 'Signed by %<name>s with DocuSeal.co'
|
||||||
SIGN_SIGNLE_REASON = 'Digitally signed with DocuSeal.co'
|
SIGN_SIGNLE_REASON = 'Digitally signed with DocuSeal.co'
|
||||||
|
|
||||||
|
RTL_REGEXP = /\A[\p{Hebrew}\p{Arabic}\s;.,-]+\z/
|
||||||
|
|
||||||
TEXT_LEFT_MARGIN = 1
|
TEXT_LEFT_MARGIN = 1
|
||||||
TEXT_TOP_MARGIN = 1
|
TEXT_TOP_MARGIN = 1
|
||||||
|
|
||||||
@@ -56,10 +58,12 @@ module Submissions
|
|||||||
height = page.box.height
|
height = page.box.height
|
||||||
font_size = ((page.box.width / A4_SIZE[0].to_f) * FONT_SIZE).to_i
|
font_size = ((page.box.width / A4_SIZE[0].to_f) * FONT_SIZE).to_i
|
||||||
|
|
||||||
layouter = HexaPDF::Layout::TextLayouter.new(valign: :center, font: pdf.fonts.add(FONT_NAME), font_size:)
|
|
||||||
|
|
||||||
value = submitter.values[field['uuid']]
|
value = submitter.values[field['uuid']]
|
||||||
|
|
||||||
|
layouter = HexaPDF::Layout::TextLayouter.new(valign: :center,
|
||||||
|
align: value.to_s.match?(RTL_REGEXP) ? :right : :left,
|
||||||
|
font: pdf.fonts.add(FONT_NAME), font_size:)
|
||||||
|
|
||||||
next if Array.wrap(value).compact_blank.blank?
|
next if Array.wrap(value).compact_blank.blank?
|
||||||
|
|
||||||
canvas = page.canvas(type: :overlay)
|
canvas = page.canvas(type: :overlay)
|
||||||
@@ -155,7 +159,7 @@ module Submissions
|
|||||||
when 'cells'
|
when 'cells'
|
||||||
cell_width = area['cell_w'] * width
|
cell_width = area['cell_w'] * width
|
||||||
|
|
||||||
value.chars.each_with_index do |char, index|
|
maybe_rtl_reverse(value).chars.each_with_index do |char, index|
|
||||||
text = HexaPDF::Layout::TextFragment.create(char, font: pdf.fonts.add(FONT_NAME),
|
text = HexaPDF::Layout::TextFragment.create(char, font: pdf.fonts.add(FONT_NAME),
|
||||||
font_size:)
|
font_size:)
|
||||||
|
|
||||||
@@ -168,14 +172,16 @@ module Submissions
|
|||||||
value = TimeUtils.format_date_string(value, field.dig('preferences', 'format'), account.locale)
|
value = TimeUtils.format_date_string(value, field.dig('preferences', 'format'), account.locale)
|
||||||
end
|
end
|
||||||
|
|
||||||
text = HexaPDF::Layout::TextFragment.create(Array.wrap(value).join(', '), font: pdf.fonts.add(FONT_NAME),
|
value = maybe_rtl_reverse(Array.wrap(value).join(', '))
|
||||||
font_size:)
|
|
||||||
|
text = HexaPDF::Layout::TextFragment.create(value, font: pdf.fonts.add(FONT_NAME),
|
||||||
|
font_size:)
|
||||||
|
|
||||||
lines = layouter.fit([text], area['w'] * width, height).lines
|
lines = layouter.fit([text], area['w'] * width, height).lines
|
||||||
box_height = lines.sum(&:height)
|
box_height = lines.sum(&:height)
|
||||||
|
|
||||||
if box_height > (area['h'] * height) + 1
|
if box_height > (area['h'] * height) + 1
|
||||||
text = HexaPDF::Layout::TextFragment.create(Array.wrap(value).join(', '),
|
text = HexaPDF::Layout::TextFragment.create(value,
|
||||||
font: pdf.fonts.add(FONT_NAME),
|
font: pdf.fonts.add(FONT_NAME),
|
||||||
font_size: (font_size / 1.4).to_i)
|
font_size: (font_size / 1.4).to_i)
|
||||||
|
|
||||||
@@ -312,6 +318,14 @@ module Submissions
|
|||||||
pdf
|
pdf
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def maybe_rtl_reverse(text)
|
||||||
|
if text.match?(RTL_REGEXP)
|
||||||
|
text.reverse
|
||||||
|
else
|
||||||
|
text
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def sign_reason(name)
|
def sign_reason(name)
|
||||||
format(SIGN_REASON, name:)
|
format(SIGN_REASON, name:)
|
||||||
end
|
end
|
||||||
|
|||||||
Reference in New Issue
Block a user