glib-web 4.3.0 → 4.4.0
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/controllers/glib/glib_direct_uploads_controller.rb +1 -1
- data/app/controllers/glib/home_controller.rb +5 -0
- data/app/helpers/glib/json_ui/abstract_builder.rb +1 -1
- data/app/helpers/glib/json_ui/action_builder/browsers.rb +12 -0
- data/app/helpers/glib/json_ui/action_builder/fields.rb +6 -0
- data/app/helpers/glib/json_ui/action_builder/logics.rb +9 -0
- data/app/helpers/glib/json_ui/action_builder/storage_items.rb +23 -0
- data/app/helpers/glib/json_ui/action_builder.rb +0 -18
- data/app/helpers/glib/json_ui/menu_builder.rb +1 -1
- data/app/helpers/glib/json_ui/view_builder/charts.rb +3 -2
- data/app/helpers/glib/json_ui/view_builder/fields.rb +20 -22
- data/app/helpers/glib/json_ui/view_builder/panels.rb +23 -11
- data/app/helpers/glib/json_ui/view_builder.rb +20 -8
- data/app/models/glib/dummy_job_application.rb +3 -2
- data/app/views/json_ui/garage/_nav_menu.json.jbuilder +1 -1
- data/app/views/json_ui/garage/forms/file_upload.json.jbuilder +2 -2
- data/app/views/json_ui/garage/forms/show_hide.json.jbuilder +16 -5
- data/app/views/json_ui/garage/forms/submit_on_change.json.jbuilder +1 -1
- data/app/views/json_ui/garage/forms/text_validation.json.jbuilder +13 -8
- data/app/views/json_ui/garage/test_page/_header.json.jbuilder +14 -0
- data/app/views/json_ui/garage/test_page/auto_validate.json.jbuilder +77 -0
- data/app/views/json_ui/garage/test_page/dialog.json.jbuilder +38 -0
- data/app/views/json_ui/garage/test_page/dialog_open.json.jbuilder +14 -0
- data/app/views/json_ui/garage/test_page/form.json.jbuilder +111 -0
- data/app/views/json_ui/garage/test_page/form_dynamic.json.jbuilder +63 -0
- data/app/views/json_ui/garage/test_page/multiupload.json.jbuilder +65 -0
- data/lib/glib/mailer_tester.rb +1 -1
- metadata +10 -2
- data/app/views/json_ui/garage/test_page/index.json.jbuilder +0 -120
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 73e075cfe5041ccb4a1f0f6836a9fb5fe294fff00698ad0974a1ef70e34d8bb8
|
|
4
|
+
data.tar.gz: 5ebb6ca2859d77329531ebec64019f655da409adc0a617c6567be6ef3acf9c88
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 6dc692a9e877c4686fb64600813c1b14e6c9926a69a2d9ffaf0c65cb7ac7a48976ad727eea965c024694e79f5b2af9ae945bb013e02f68d0d434fe57f1bb2640
|
|
7
|
+
data.tar.gz: 6e8a5f227bc198f957372c7de511f8e5b65d197419f3bc6a2e461cf894f6c26e3dbfab25859b0b76b22775186f8ed2106d58d309bfc1118ee68c9f33186389e0
|
|
@@ -287,7 +287,7 @@ module Glib
|
|
|
287
287
|
optional = options[:optional] || []
|
|
288
288
|
|
|
289
289
|
required.each do |req|
|
|
290
|
-
raise ArgumentError, "Hash property: '#{req}' is
|
|
290
|
+
raise ArgumentError, "Hash property: '#{req}' is required" if value[req.to_s].blank?
|
|
291
291
|
end
|
|
292
292
|
|
|
293
293
|
if optional.present?
|
|
@@ -7,6 +7,8 @@ class Glib::JsonUi::ActionBuilder
|
|
|
7
7
|
hash :data
|
|
8
8
|
hash :variables
|
|
9
9
|
action :onSet
|
|
10
|
+
bool :cacheData
|
|
11
|
+
bool :debug
|
|
10
12
|
|
|
11
13
|
def dataBuilder(block)
|
|
12
14
|
json.data do
|
|
@@ -15,6 +17,13 @@ class Glib::JsonUi::ActionBuilder
|
|
|
15
17
|
end
|
|
16
18
|
end
|
|
17
19
|
|
|
20
|
+
class Run < Action
|
|
21
|
+
hash :condition
|
|
22
|
+
hash :variables
|
|
23
|
+
action :onTrue
|
|
24
|
+
action :onFalse
|
|
25
|
+
end
|
|
26
|
+
|
|
18
27
|
# Under consideration, likely not a good idea.
|
|
19
28
|
# class Append < Action
|
|
20
29
|
# string :targetId
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
class Glib::JsonUi::ActionBuilder
|
|
2
|
+
# FUTURE
|
|
3
|
+
module StorageItems
|
|
4
|
+
class Set < Action
|
|
5
|
+
string :key
|
|
6
|
+
string :value
|
|
7
|
+
action :onSet
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
class Get < Action
|
|
11
|
+
string :key
|
|
12
|
+
action :onGet
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
class Remove < Action
|
|
16
|
+
action :onRemove
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
class Clear < Action
|
|
20
|
+
action :onClear
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
@@ -157,24 +157,6 @@ module Glib
|
|
|
157
157
|
# class Clear < Action
|
|
158
158
|
# end
|
|
159
159
|
end
|
|
160
|
-
|
|
161
|
-
# FUTURE
|
|
162
|
-
|
|
163
|
-
module Data
|
|
164
|
-
class Save < Action
|
|
165
|
-
string :key
|
|
166
|
-
string :value
|
|
167
|
-
action :onSave
|
|
168
|
-
end
|
|
169
|
-
|
|
170
|
-
class Remove < Action
|
|
171
|
-
end
|
|
172
|
-
|
|
173
|
-
class Clear < Action
|
|
174
|
-
end
|
|
175
|
-
end
|
|
176
|
-
|
|
177
|
-
###
|
|
178
160
|
end
|
|
179
161
|
end
|
|
180
162
|
end
|
|
@@ -43,8 +43,9 @@ class Glib::JsonUi::ViewBuilder
|
|
|
43
43
|
string :suffix
|
|
44
44
|
int :min
|
|
45
45
|
int :max
|
|
46
|
-
|
|
47
|
-
hash :
|
|
46
|
+
# https://www.chartjs.org/docs/latest/configuration/legend.html
|
|
47
|
+
hash :legend, optional: [:position, :align, :display, :maxHeight, :maxWidth, :fullSize, :reverse, :labels, :rtl, :title]
|
|
48
|
+
hash :plugins, optional: [:datalabels, :centerLabel, :customTooltip]
|
|
48
49
|
end
|
|
49
50
|
end
|
|
50
51
|
|
|
@@ -6,7 +6,6 @@ class Glib::JsonUi::ViewBuilder
|
|
|
6
6
|
|
|
7
7
|
bool :readOnly
|
|
8
8
|
bool :disabled
|
|
9
|
-
hash :validation
|
|
10
9
|
bool :disableDirtyCheck
|
|
11
10
|
action :onChange
|
|
12
11
|
action :onChangeAndLoad
|
|
@@ -17,6 +16,16 @@ class Glib::JsonUi::ViewBuilder
|
|
|
17
16
|
{ only_path: true }
|
|
18
17
|
end
|
|
19
18
|
|
|
19
|
+
def validation(validation)
|
|
20
|
+
return if validation.blank?
|
|
21
|
+
|
|
22
|
+
if validation[:format].present?
|
|
23
|
+
context.cast_to_js_regex(validation[:format])
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
json.validation validation
|
|
27
|
+
end
|
|
28
|
+
|
|
20
29
|
def label(label)
|
|
21
30
|
@label = label
|
|
22
31
|
end
|
|
@@ -127,7 +136,7 @@ class Glib::JsonUi::ViewBuilder
|
|
|
127
136
|
end
|
|
128
137
|
|
|
129
138
|
class Timer < Text
|
|
130
|
-
hash :actionCable
|
|
139
|
+
# hash :actionCable
|
|
131
140
|
int :min
|
|
132
141
|
int :max
|
|
133
142
|
bool :forward
|
|
@@ -168,7 +177,7 @@ class Glib::JsonUi::ViewBuilder
|
|
|
168
177
|
|
|
169
178
|
class RichText < Text
|
|
170
179
|
array :images
|
|
171
|
-
hash :imageUploader
|
|
180
|
+
hash :imageUploader, required: [:name], optional: [:accepts, :directUploadUrl]
|
|
172
181
|
# `html` or `markdown`
|
|
173
182
|
string :produce
|
|
174
183
|
string :accept
|
|
@@ -180,7 +189,7 @@ class Glib::JsonUi::ViewBuilder
|
|
|
180
189
|
# bool :readOnly
|
|
181
190
|
bool :multiple, cache: true
|
|
182
191
|
# bool :manualEntry
|
|
183
|
-
hash :append
|
|
192
|
+
hash :append, optional: [:icon]
|
|
184
193
|
|
|
185
194
|
panels_builder :accessory, :header, :footer
|
|
186
195
|
end
|
|
@@ -269,16 +278,14 @@ class Glib::JsonUi::ViewBuilder
|
|
|
269
278
|
# file_rules = { fileType: 'image/*', maxFileSize: 5000 }
|
|
270
279
|
# file_rules = { fileType: 'video/*', maxFileSize: 50000 }
|
|
271
280
|
# file_rules = { fileType: 'application/pdf', maxFileSize: 5000 }
|
|
272
|
-
hash :accepts
|
|
273
281
|
|
|
274
|
-
|
|
282
|
+
include Glib::JsonUi::Upload
|
|
283
|
+
|
|
275
284
|
string :fileUrl
|
|
276
285
|
string :fileTitle
|
|
277
286
|
string :uploadText
|
|
278
|
-
hash :placeholderView
|
|
279
|
-
hash :infoSpec
|
|
280
|
-
string :storagePrefix
|
|
281
|
-
hash :metadata
|
|
287
|
+
hash :placeholderView # deprecated
|
|
288
|
+
hash :infoSpec # deprecated
|
|
282
289
|
|
|
283
290
|
def buttonLabels(obj)
|
|
284
291
|
@buttonLabels = ActiveSupport::HashWithIndifferentAccess.new(obj)
|
|
@@ -314,23 +321,14 @@ class Glib::JsonUi::ViewBuilder
|
|
|
314
321
|
|
|
315
322
|
class MultiUpload < AbstractField
|
|
316
323
|
include Glib::JsonUi::Default
|
|
324
|
+
include Glib::JsonUi::Upload
|
|
317
325
|
|
|
318
|
-
# hash :accepts
|
|
319
326
|
array :files
|
|
320
|
-
string :directUploadUrl
|
|
321
327
|
string :uploadTitle
|
|
322
328
|
action :onFinishUpload
|
|
323
|
-
string :strategy # can be "delegate" or "dropUpload"
|
|
324
329
|
string :url # http post end point if you don't want to use onFinishUpload
|
|
325
|
-
|
|
326
|
-
string :storagePrefix
|
|
327
|
-
hash :metadata
|
|
328
|
-
string :tagging
|
|
329
|
-
hash :tags
|
|
330
|
-
|
|
331
330
|
required :accepts, :directUploadUrl
|
|
332
331
|
|
|
333
|
-
|
|
334
332
|
def accepts(value)
|
|
335
333
|
@accepts = value
|
|
336
334
|
end
|
|
@@ -378,7 +376,6 @@ class Glib::JsonUi::ViewBuilder
|
|
|
378
376
|
|
|
379
377
|
class Sign < AbstractField
|
|
380
378
|
string :directUploadUrl
|
|
381
|
-
|
|
382
379
|
required :directUploadUrl
|
|
383
380
|
|
|
384
381
|
# Override
|
|
@@ -422,7 +419,8 @@ class Glib::JsonUi::ViewBuilder
|
|
|
422
419
|
hash :latitudeField
|
|
423
420
|
hash :longitudeField
|
|
424
421
|
hash :zoomField
|
|
425
|
-
|
|
422
|
+
# https://developers.google.com/maps/documentation/javascript/reference/places-widget#AutocompleteOptions
|
|
423
|
+
hash :autocompleteOptions, optional: [:bounds, :componentRestrictions, :fields, :strictBounds, :types]
|
|
426
424
|
end
|
|
427
425
|
|
|
428
426
|
class StripeToken < AbstractField
|
|
@@ -125,6 +125,10 @@ class Glib::JsonUi::ViewBuilder
|
|
|
125
125
|
self.class.field_validation(@model, prop)
|
|
126
126
|
end
|
|
127
127
|
|
|
128
|
+
def cast_to_js_regex(format_validation)
|
|
129
|
+
self.class.cast_to_js_regex(format_validation)
|
|
130
|
+
end
|
|
131
|
+
|
|
128
132
|
def self.lookup_error_message(model_name, attribute_name, key)
|
|
129
133
|
message = I18n.t("activerecord.errors.models.#{model_name}.attributes.#{attribute_name}.#{key}", default: nil) if model_name.present? && attribute_name.present?
|
|
130
134
|
message ||= I18n.t("activerecord.errors.models.#{model_name}.#{key}", default: nil) if model_name.present?
|
|
@@ -134,6 +138,18 @@ class Glib::JsonUi::ViewBuilder
|
|
|
134
138
|
message
|
|
135
139
|
end
|
|
136
140
|
|
|
141
|
+
def self.cast_to_js_regex(format_validation)
|
|
142
|
+
if format_validation[:with].instance_of?(Regexp)
|
|
143
|
+
format_validation[:with] = JsRegex.new(format_validation[:with]).source
|
|
144
|
+
end
|
|
145
|
+
if format_validation[:without].instance_of?(Regexp)
|
|
146
|
+
format_validation[:without] = JsRegex.new(format_validation[:without]).source
|
|
147
|
+
end
|
|
148
|
+
if format_validation[:regex].instance_of?(Regexp)
|
|
149
|
+
format_validation[:regex] = JsRegex.new(format_validation[:regex]).source
|
|
150
|
+
end
|
|
151
|
+
end
|
|
152
|
+
|
|
137
153
|
def self.field_validation(model, prop)
|
|
138
154
|
validations = {}
|
|
139
155
|
ignored = ['confirmation', 'comparison', 'uniqueness', 'validates_associated', 'validates_each', 'validates_with']
|
|
@@ -157,12 +173,7 @@ class Glib::JsonUi::ViewBuilder
|
|
|
157
173
|
'less_than_or_equal_to', 'other_than', 'in', 'odd', 'even'
|
|
158
174
|
].inject({}) { |prev, curr| prev.merge(curr => lookup_error_message(model.to_s.underscore, prop, curr)) }
|
|
159
175
|
when :format
|
|
160
|
-
|
|
161
|
-
validations[validator.kind][:with] = JsRegex.new(validations[validator.kind][:with]).source
|
|
162
|
-
end
|
|
163
|
-
if validations[validator.kind][:without].instance_of?(Regexp)
|
|
164
|
-
validations[validator.kind][:without] = JsRegex.new(validations[validator.kind][:without]).source
|
|
165
|
-
end
|
|
176
|
+
cast_to_js_regex(validations[validator.kind])
|
|
166
177
|
validations[validator.kind][:message] ||= lookup_error_message(model.to_s.underscore, prop, 'invalid')
|
|
167
178
|
when :inclusion
|
|
168
179
|
validations[validator.kind][:message] ||= lookup_error_message(model.to_s.underscore, prop, 'inclusion')
|
|
@@ -250,10 +261,11 @@ class Glib::JsonUi::ViewBuilder
|
|
|
250
261
|
string :fieldSubsubtitleName
|
|
251
262
|
|
|
252
263
|
# This can be used to implement "check all" and "uncheck all".
|
|
264
|
+
# deprecated?
|
|
253
265
|
hash :fieldCheckValueIf
|
|
254
266
|
|
|
255
267
|
hash :phoenixSocket
|
|
256
|
-
hash :actionCable
|
|
268
|
+
# hash :actionCable
|
|
257
269
|
|
|
258
270
|
hash :nextPage
|
|
259
271
|
hash :prevPage
|
|
@@ -289,8 +301,8 @@ class Glib::JsonUi::ViewBuilder
|
|
|
289
301
|
|
|
290
302
|
class Table < View
|
|
291
303
|
hash :nextPage
|
|
292
|
-
hash :export
|
|
293
|
-
hash :import
|
|
304
|
+
hash :export, required: [:label, :fileName]
|
|
305
|
+
hash :import, required: [:submitUrl, :paramName]
|
|
294
306
|
action :onScrollToTop
|
|
295
307
|
action :onScrollToBottom
|
|
296
308
|
|
|
@@ -371,11 +383,11 @@ class Glib::JsonUi::ViewBuilder
|
|
|
371
383
|
string :distribution
|
|
372
384
|
string :align
|
|
373
385
|
action :onClick
|
|
374
|
-
hash :dragSupport
|
|
386
|
+
hash :dragSupport, optional: [:onDrop, :paramNameForFormData, :paramNameForNewIndex]
|
|
375
387
|
end
|
|
376
388
|
|
|
377
389
|
class Flow < View
|
|
378
|
-
hash :innerPadding
|
|
390
|
+
hash :innerPadding, optional: [:top, :right, :bottom, :left, :x, :y]
|
|
379
391
|
views :childViews
|
|
380
392
|
|
|
381
393
|
required :innerPadding
|
|
@@ -1,5 +1,20 @@
|
|
|
1
1
|
module Glib
|
|
2
2
|
module JsonUi
|
|
3
|
+
|
|
4
|
+
module Upload
|
|
5
|
+
extend ActiveSupport::Concern
|
|
6
|
+
|
|
7
|
+
included do
|
|
8
|
+
string :directUploadUrl
|
|
9
|
+
hash :accepts, optional: [:fileType, :maxFileSize, :maxFileLength, :maxFileSizeErrorText, :maxFileLengthErrorText]
|
|
10
|
+
string :strategy # can be "delegate" or "dropUpload"
|
|
11
|
+
string :storagePrefix
|
|
12
|
+
hash :metadata
|
|
13
|
+
string :tagging
|
|
14
|
+
hash :tags
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
3
18
|
class ViewBuilder < AbstractBuilder
|
|
4
19
|
def initialize(json, page, multiple)
|
|
5
20
|
super(json, page)
|
|
@@ -38,7 +53,7 @@ module Glib
|
|
|
38
53
|
length :width
|
|
39
54
|
length :height
|
|
40
55
|
color :backgroundColor
|
|
41
|
-
hash :padding
|
|
56
|
+
hash :padding, optional: [:top, :right, :bottom, :left, :x, :y, :all]
|
|
42
57
|
singleton_array :styleClass, :styleClasses
|
|
43
58
|
|
|
44
59
|
hash :showIf
|
|
@@ -49,7 +64,7 @@ module Glib
|
|
|
49
64
|
bool :displayed
|
|
50
65
|
bool :submitWhenNotDisplayed
|
|
51
66
|
|
|
52
|
-
hash :analytics
|
|
67
|
+
hash :analytics, optional: [:featured, :disabled]
|
|
53
68
|
hash :dragData
|
|
54
69
|
|
|
55
70
|
def self.component_name
|
|
@@ -139,7 +154,7 @@ module Glib
|
|
|
139
154
|
end
|
|
140
155
|
|
|
141
156
|
class Label < AbstractText
|
|
142
|
-
hash :actionCable
|
|
157
|
+
# hash :actionCable
|
|
143
158
|
# string :format
|
|
144
159
|
action :onClick
|
|
145
160
|
end
|
|
@@ -315,16 +330,13 @@ module Glib
|
|
|
315
330
|
end
|
|
316
331
|
|
|
317
332
|
class TreeView < View
|
|
333
|
+
include Glib::JsonUi::Upload
|
|
334
|
+
|
|
318
335
|
string :inputName
|
|
319
336
|
string :url
|
|
320
|
-
string :directUploadUrl
|
|
321
|
-
hash :accepts
|
|
322
337
|
string :selected
|
|
323
338
|
array :items
|
|
324
339
|
hash :dropData
|
|
325
|
-
string :strategy
|
|
326
|
-
string :storagePrefix
|
|
327
|
-
hash :metadata
|
|
328
340
|
end
|
|
329
341
|
end
|
|
330
342
|
end
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
module Glib
|
|
2
2
|
class DummyJobApplication
|
|
3
|
+
include ActiveModel::Model
|
|
3
4
|
include ActiveModel::Validations
|
|
4
5
|
include ActiveModel::AttributeMethods
|
|
5
6
|
|
|
6
|
-
attr_accessor :name, :age, :position, :words, :accept
|
|
7
|
+
attr_accessor :name, :age, :position, :words, :accept, :pet_you_have
|
|
7
8
|
|
|
8
9
|
validates :name, :position, presence: true
|
|
9
10
|
validates :accept, acceptance: {}, allow_nil: false
|
|
@@ -11,6 +12,6 @@ module Glib
|
|
|
11
12
|
validates :age, numericality: { only_integer: true, less_than_or_equal_to: 30, greater_than_or_equal_to: 18 }, allow_blank: true
|
|
12
13
|
validates :name, format: { with: /Doe\z/, message: 'This job is for person end with Doe' }
|
|
13
14
|
validates :position, inclusion: { in: ['programmer', 'devops', 'designer'] }, allow_blank: true
|
|
14
|
-
|
|
15
|
+
validates :pet_you_have, exclusion: { in: ['crocodile', 'shark' ], message: 'We dont accept that kind of animal!' }, allow_blank: true
|
|
15
16
|
end
|
|
16
17
|
end
|
|
@@ -52,7 +52,7 @@ if local_assigns[:top_nav] || json_ui_app_is_web?
|
|
|
52
52
|
end
|
|
53
53
|
|
|
54
54
|
menu.button text: 'Test Page', onClick: ->(action) do
|
|
55
|
-
action.windows_open url: json_ui_garage_url(path: 'test_page/
|
|
55
|
+
action.windows_open url: json_ui_garage_url(path: 'test_page/form')
|
|
56
56
|
end
|
|
57
57
|
|
|
58
58
|
menu.divider
|
|
@@ -17,7 +17,7 @@ page.form options.merge(childViews: ->(form) do
|
|
|
17
17
|
fileTitle: '1 month ago',
|
|
18
18
|
placeholderView: { type: 'image', width: 100, height: 75, url: 'https://www.atms.com.au/wp-content/uploads/2019/10/placeholder-1-1024x683.png?x93630' }
|
|
19
19
|
|
|
20
|
-
rules = { fileType: 'image', maxFileSize: 1,
|
|
20
|
+
rules = { fileType: 'image', maxFileSize: 1, maxFileSizeErrorText: 'Too big!' }
|
|
21
21
|
form.fields_file name: 'user[photo][]', width: 'matchParent', label: 'Avatar', accepts: rules, directUploadUrl: glib_direct_uploads_url,
|
|
22
22
|
placeholderView: { type: 'avatar', width: 100, height: 100, url: 'data:image/jpeg;base64,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' }
|
|
23
23
|
|
|
@@ -32,7 +32,7 @@ page.form options.merge(childViews: ->(form) do
|
|
|
32
32
|
form.fields_file name: 'user[zip][]', width: 'matchParent', label: 'ZIP Document', accepts: rules, directUploadUrl: glib_direct_uploads_url
|
|
33
33
|
|
|
34
34
|
# TODO
|
|
35
|
-
# rules = { fileType: 'image/*', maxFileSize: 1,
|
|
35
|
+
# rules = { fileType: 'image/*', maxFileSize: 1, maxFileSizeErrorText: 'Too big!' }
|
|
36
36
|
# form.fields_multiImage name: 'user[photos][]', width: 'matchParent', label: 'Avatar', accepts: rules, directUploadUrl: glib_direct_uploads_url,
|
|
37
37
|
# placeholderView: { type: 'avatar', width: 100, height: 100, url: 'data:image/jpeg;base64,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' }
|
|
38
38
|
|
|
@@ -349,12 +349,14 @@ page.form \
|
|
|
349
349
|
form.spacer height: 20
|
|
350
350
|
options = [
|
|
351
351
|
{ text: 'Option 1', value: 'option1' },
|
|
352
|
-
{ text: 'Option 2', value: 'option2' }
|
|
352
|
+
{ text: 'Option 2', value: 'option2' },
|
|
353
|
+
{ text: 'Option 3', value: 'option3' }
|
|
353
354
|
]
|
|
354
355
|
form.fields_select name: 'user[loadif7]', width: 'matchParent', label: 'Select "show"', options: options, value: '', onChangeAndLoad: ->(action) do
|
|
355
356
|
action.runMultiple childActions: ->(saction) do
|
|
356
357
|
saction.logics_set targetId: 'panel7a', conditionalData: { displayed: { "==": [{ "var": 'user[loadif7]' }, 'option1'] } }
|
|
357
358
|
saction.logics_set targetId: 'panel7b', conditionalData: { displayed: { "==": [{ "var": 'user[loadif7]' }, 'option2'] } }
|
|
359
|
+
saction.logics_set targetId: 'panel7c', conditionalData: { displayed: { "==": [{ "var": 'user[loadif7]' }, 'option3'] } }
|
|
358
360
|
end
|
|
359
361
|
end
|
|
360
362
|
|
|
@@ -363,8 +365,8 @@ page.form \
|
|
|
363
365
|
styleClass: 'border-2',
|
|
364
366
|
width: 'matchParent',
|
|
365
367
|
padding: { top: 8, right: 8, bottom: 8, left: 8 },
|
|
366
|
-
childViews: ->(
|
|
367
|
-
|
|
368
|
+
childViews: ->(vertical) do
|
|
369
|
+
vertical.fields_text name: 'user[0][loadif_target9]', width: 'matchParent', value: 'Value 7a'
|
|
368
370
|
end
|
|
369
371
|
|
|
370
372
|
form.panels_vertical \
|
|
@@ -372,8 +374,17 @@ page.form \
|
|
|
372
374
|
styleClass: 'border-2',
|
|
373
375
|
width: 'matchParent',
|
|
374
376
|
padding: { top: 8, right: 8, bottom: 8, left: 8 },
|
|
375
|
-
childViews: ->(
|
|
376
|
-
|
|
377
|
+
childViews: ->(vertical) do
|
|
378
|
+
vertical.fields_text name: 'user[1][loadif_target9]', width: 'matchParent', value: 'Value 7b'
|
|
379
|
+
end
|
|
380
|
+
|
|
381
|
+
form.panels_vertical \
|
|
382
|
+
id: 'panel7c',
|
|
383
|
+
styleClass: 'border-2',
|
|
384
|
+
width: 'matchParent',
|
|
385
|
+
padding: { top: 8, right: 8, bottom: 8, left: 8 },
|
|
386
|
+
childViews: ->(vertical) do
|
|
387
|
+
vertical.fields_text id: 'target_panel_3', name: 'user[2][loadif_target9]', width: 'matchParent', value: 'Value 7c'
|
|
377
388
|
end
|
|
378
389
|
|
|
379
390
|
form.spacer height: 20
|
|
@@ -107,7 +107,7 @@ page.scroll childViews: ->(scroll) do
|
|
|
107
107
|
end
|
|
108
108
|
|
|
109
109
|
form.spacer height: 20
|
|
110
|
-
rules = { fileType: 'image', maxFileSize: 5000,
|
|
110
|
+
rules = { fileType: 'image', maxFileSize: 5000, maxFileSizeErrorText: 'Too big!' }
|
|
111
111
|
form.fields_file \
|
|
112
112
|
name: 'user[photo][]',
|
|
113
113
|
width: 'matchParent',
|
|
@@ -15,29 +15,32 @@ page.form \
|
|
|
15
15
|
name: 'user[name]',
|
|
16
16
|
width: 'matchParent',
|
|
17
17
|
label: 'Name'
|
|
18
|
-
|
|
18
|
+
form.spacer height: 8
|
|
19
19
|
|
|
20
20
|
form.fields_email \
|
|
21
21
|
name: 'user[email]',
|
|
22
22
|
width: 'matchParent',
|
|
23
23
|
label: 'Email'
|
|
24
|
+
form.spacer height: 8
|
|
24
25
|
|
|
25
26
|
form.fields_url \
|
|
26
27
|
name: 'user[url]',
|
|
27
28
|
width: 'matchParent',
|
|
28
29
|
label: 'URL'
|
|
30
|
+
form.spacer height: 8
|
|
29
31
|
|
|
30
32
|
form.fields_number \
|
|
31
33
|
prop: :age,
|
|
32
34
|
name: 'user[age]',
|
|
33
35
|
width: 'matchParent',
|
|
34
36
|
label: 'Age'
|
|
35
|
-
|
|
37
|
+
form.spacer height: 8
|
|
36
38
|
|
|
37
39
|
form.fields_phone \
|
|
38
40
|
name: 'user[phone1]',
|
|
39
41
|
width: 'matchParent',
|
|
40
42
|
label: 'Phone field'
|
|
43
|
+
form.spacer height: 8
|
|
41
44
|
|
|
42
45
|
form.fields_phone \
|
|
43
46
|
name: 'user[phone2]',
|
|
@@ -45,6 +48,7 @@ page.form \
|
|
|
45
48
|
label: 'Phone field with Australia as the default country',
|
|
46
49
|
disableAutoDetect: true, # Disable country auto detect by user IP
|
|
47
50
|
defaultCountry: 'AU' # ISO Country code, see: https://en.wikipedia.org/wiki/List_of_ISO_3166_country_codes
|
|
51
|
+
form.spacer height: 8
|
|
48
52
|
|
|
49
53
|
form.fields_password \
|
|
50
54
|
name: 'user[password]',
|
|
@@ -52,6 +56,7 @@ page.form \
|
|
|
52
56
|
label: 'Password',
|
|
53
57
|
hint: 'Should contain at least 6 characters',
|
|
54
58
|
leftIcon: 'lock'
|
|
59
|
+
form.spacer height: 8
|
|
55
60
|
|
|
56
61
|
form.fields_textarea \
|
|
57
62
|
prop: :words,
|
|
@@ -59,6 +64,7 @@ page.form \
|
|
|
59
64
|
width: 'matchParent',
|
|
60
65
|
label: 'Textarea with maxLength',
|
|
61
66
|
maxLength: 1000
|
|
67
|
+
form.spacer height: 8
|
|
62
68
|
|
|
63
69
|
|
|
64
70
|
options = ['programmer', 'devops', 'designer', 'ceo', 'office_boy'].map { |v| { text: v.humanize, value: v } }
|
|
@@ -68,11 +74,10 @@ page.form \
|
|
|
68
74
|
width: 'matchParent',
|
|
69
75
|
label: 'Position',
|
|
70
76
|
options: options
|
|
77
|
+
form.spacer height: 8
|
|
71
78
|
|
|
72
79
|
|
|
73
|
-
form.spacer height: 10
|
|
74
80
|
form.h4 text: 'Gender'
|
|
75
|
-
form.spacer height: 4
|
|
76
81
|
form.fields_radioGroup \
|
|
77
82
|
name: 'user[gender]',
|
|
78
83
|
validation: { required: { message: 'Required' } },
|
|
@@ -82,9 +87,9 @@ page.form \
|
|
|
82
87
|
group.fields_radio value: 'F', label: 'Female'
|
|
83
88
|
end
|
|
84
89
|
|
|
85
|
-
form.spacer height:
|
|
90
|
+
form.spacer height: 8
|
|
91
|
+
|
|
86
92
|
form.h4 text: 'Skills'
|
|
87
|
-
form.spacer height: 4
|
|
88
93
|
form.fields_checkGroup \
|
|
89
94
|
name: 'user[skills][]',
|
|
90
95
|
uncheckValue: 1,
|
|
@@ -95,10 +100,10 @@ page.form \
|
|
|
95
100
|
group.fields_check checkValue: 4, label: 'Mobile Development'
|
|
96
101
|
end
|
|
97
102
|
|
|
98
|
-
form.spacer height:
|
|
103
|
+
form.spacer height: 8
|
|
99
104
|
form.fields_check prop: :accept, label: 'Accept terms & condition', name: 'user[accept]'
|
|
100
105
|
|
|
101
|
-
form.spacer height:
|
|
106
|
+
form.spacer height: 8
|
|
102
107
|
form.fields_submit text: 'Submit'
|
|
103
108
|
form.fields_submit text: 'Submit (disable if form invalid)', disableIfFormInvalid: true
|
|
104
109
|
end
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
navs = ['form', 'dialog', 'form_dynamic', 'auto_validate', 'multiupload']
|
|
2
|
+
|
|
3
|
+
view.panels_flow innerPadding: { bottom: 0 }, styleClass: 'align-right', width: 'matchParent', childViews: ->(res) do
|
|
4
|
+
navs.each_with_index do |nav, index|
|
|
5
|
+
if index < navs.size && index != 0
|
|
6
|
+
res.spacer width: 4
|
|
7
|
+
res.label text: '|'
|
|
8
|
+
res.spacer width: 4
|
|
9
|
+
end
|
|
10
|
+
res.label text: nav, onClick: ->(action) do
|
|
11
|
+
action.windows_open url: json_ui_garage_url(path: "test_page/#{nav}")
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
json.title 'Test Page (Form)'
|
|
2
|
+
|
|
3
|
+
page = json_ui_page json
|
|
4
|
+
|
|
5
|
+
page.body childViews: ->(body) do
|
|
6
|
+
render 'json_ui/garage/test_page/header', view: body
|
|
7
|
+
|
|
8
|
+
model = Glib::DummyJobApplication.new(
|
|
9
|
+
name: 'John Deo',
|
|
10
|
+
accept: '0',
|
|
11
|
+
words: '',
|
|
12
|
+
age: 17,
|
|
13
|
+
position: 'ceo',
|
|
14
|
+
pet_you_have: 'crocodile'
|
|
15
|
+
)
|
|
16
|
+
|
|
17
|
+
body.panels_responsive padding: glib_json_padding_body, childViews: ->(res) do
|
|
18
|
+
res.h2 text: 'Job Application'
|
|
19
|
+
res.spacer height: 8
|
|
20
|
+
res.panels_form \
|
|
21
|
+
url: json_ui_garage_url(path: 'forms/generic_post'),
|
|
22
|
+
method: 'post',
|
|
23
|
+
model: model,
|
|
24
|
+
autoValidate: true,
|
|
25
|
+
childViews: ->(form) do
|
|
26
|
+
form.fields_text prop: :name, label: 'name', name: 'user[name]', width: 'matchParent'
|
|
27
|
+
form.spacer height: 4
|
|
28
|
+
|
|
29
|
+
form.fields_text label: 'say hello', name: 'user[say]', width: 'matchParent', validation: { format: { regex: 'hello', message: 'Say hello!' } }, value: 'sup'
|
|
30
|
+
form.spacer height: 4
|
|
31
|
+
|
|
32
|
+
form.fields_number prop: :age, label: 'age', name: 'user[age]', width: 'matchParent'
|
|
33
|
+
form.spacer height: 4
|
|
34
|
+
|
|
35
|
+
form.fields_number \
|
|
36
|
+
name: 'user[height]',
|
|
37
|
+
label: 'height',
|
|
38
|
+
width: 'matchParent',
|
|
39
|
+
validation: { numericality: { greater_than_or_equal_to: 155, less_than_or_equal_to: 190, message: { greater_than_or_equal_to: 'Too short', less_than_or_equal_to: 'Too long' } } },
|
|
40
|
+
value: 150
|
|
41
|
+
form.spacer height: 4
|
|
42
|
+
|
|
43
|
+
form.fields_textarea prop: :words, label: 'words', name: 'user[words]', width: 'matchParent'
|
|
44
|
+
form.spacer height: 4
|
|
45
|
+
|
|
46
|
+
form.fields_textarea label: 'Tell me story', name: 'user[story]', width: 'matchParent', validation: { length: { minimum: 1, message: { too_short: { one: 'Min %{count} word', other: 'Min %{count} words' } } } }
|
|
47
|
+
form.spacer height: 4
|
|
48
|
+
|
|
49
|
+
options = ['programmer', 'devops', 'designer', 'ceo', 'office_boy'].map { |v| { text: v.humanize, value: v } }
|
|
50
|
+
form.fields_select prop: :position, label: 'postion', name: 'user[position]', width: 'matchParent', options: options
|
|
51
|
+
form.spacer height: 4
|
|
52
|
+
|
|
53
|
+
options2 = ['crocodile', 'cat', 'dog', 'bird', 'shark'].map { |v| { text: v.humanize, value: v } }
|
|
54
|
+
form.fields_select prop: :pet_you_have, label: 'Pet you have', name: 'user[pet_you_have]', width: 'matchParent', options: options2
|
|
55
|
+
form.spacer height: 4
|
|
56
|
+
|
|
57
|
+
form.label text: 'Decision'
|
|
58
|
+
options3 = ['choose me', 'dont choose me', 'whatever']
|
|
59
|
+
form.fields_radioGroup value: 'dont choose me', validation: { exclusion: { in: ['dont choose me'], message: 'dont choose me' } }, childViews: ->(radio) do
|
|
60
|
+
options3.each do |option|
|
|
61
|
+
radio.fields_radio label: option, value: option
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
form.spacer height: 4
|
|
65
|
+
|
|
66
|
+
form.fields_check prop: :accept, label: 'accept', name: 'user[accept]', width: 'matchParent', checkValue: '1'
|
|
67
|
+
form.spacer height: 4
|
|
68
|
+
|
|
69
|
+
form.spacer height: 4
|
|
70
|
+
form.fields_submit text: 'submit'
|
|
71
|
+
form.spacer height: 2
|
|
72
|
+
form.fields_submit text: 'submit (if form valid)', disableIfFormInvalid: true
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
res.spacer height: 16
|
|
76
|
+
end
|
|
77
|
+
end
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
|
|
2
|
+
|
|
3
|
+
json.title 'Test Page (Form)'
|
|
4
|
+
|
|
5
|
+
page = json_ui_page json
|
|
6
|
+
|
|
7
|
+
page.body childViews: ->(body) do
|
|
8
|
+
render 'json_ui/garage/test_page/header', view: body
|
|
9
|
+
|
|
10
|
+
body.panels_responsive padding: glib_json_padding_body, childViews: ->(res) do
|
|
11
|
+
res.h2 text: 'Dialog'
|
|
12
|
+
res.spacer height: 8
|
|
13
|
+
res.button text: 'Dialog updateExisting', onClick: ->(action) do
|
|
14
|
+
action.runMultiple childActions: ->(saction) do
|
|
15
|
+
saction.dialogs_show content: ->(dialog) do
|
|
16
|
+
dialog.body padding: glib_json_padding_body, childViews: ->(sbody) do
|
|
17
|
+
sbody.h1 text: 'Hello world'
|
|
18
|
+
sbody.button text: 'change dialog content', onClick: ->(ssaction) do
|
|
19
|
+
ssaction.dialogs_show updateExisting: true, disableCloseButton: true, content: ->(sdialog) do
|
|
20
|
+
sdialog.body padding: glib_json_padding_body, childViews: ->(ssbody) do
|
|
21
|
+
ssbody.h1 text: 'Hello world (updated)'
|
|
22
|
+
ssbody.spacer height: 8
|
|
23
|
+
ssbody.button text: 'close', onClick: ->(xaction) do
|
|
24
|
+
xaction.dialogs_close
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
res.spacer height: 4
|
|
34
|
+
res.button text: 'Dialog open', onClick: ->(action) do
|
|
35
|
+
action.dialogs_open url: json_ui_garage_url(path: 'test_page/dialog_open')
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
page = json_ui_page json
|
|
2
|
+
|
|
3
|
+
page.body padding: glib_json_padding_body, childViews: ->(body) do
|
|
4
|
+
body.panels_responsive width: 'matchParent', childViews: ->(res) do
|
|
5
|
+
res.h2 text: 'Title'
|
|
6
|
+
res.spacer height: 16
|
|
7
|
+
res.button text: 'open', onClick: ->(action) do
|
|
8
|
+
action.dialogs_open url: json_ui_garage_url(path: 'test_page/dialog_open')
|
|
9
|
+
end
|
|
10
|
+
res.button text: 'close', onClick: ->(action) do
|
|
11
|
+
action.dialogs_close
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
json.title 'Test Page (Form)'
|
|
2
|
+
|
|
3
|
+
page = json_ui_page json
|
|
4
|
+
|
|
5
|
+
page.body childViews: ->(body) do
|
|
6
|
+
render 'json_ui/garage/test_page/header', view: body
|
|
7
|
+
|
|
8
|
+
body.panels_responsive padding: glib_json_padding_body, childViews: ->(res) do
|
|
9
|
+
res.h2 text: 'Form'
|
|
10
|
+
res.spacer height: 8
|
|
11
|
+
res.panels_form \
|
|
12
|
+
url: json_ui_garage_url(path: 'forms/generic_post'),
|
|
13
|
+
method: 'post',
|
|
14
|
+
childViews: ->(form) do
|
|
15
|
+
form.panels_flow innerPadding: { bottom: 0 }, width: 'matchParent', childViews: ->(hori) do
|
|
16
|
+
hori.button text: 'components/set', onClick: ->(action) do
|
|
17
|
+
action.runMultiple childActions: ->(saction) do
|
|
18
|
+
saction.components_set targetId: 'textarea', data: { value: 'The quick brown fox jumps over the lazy dog' }
|
|
19
|
+
new_options = [{ text: 'Option99', value: 'option99' }]
|
|
20
|
+
['select', 'chip_group'].each do |id|
|
|
21
|
+
saction.components_set targetId: id, data: { options: new_options, value: ['option99'] }
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
hori.spacer width: 4
|
|
26
|
+
hori.button text: 'logics/set', onClick: ->(action) do
|
|
27
|
+
action.logics_set targetId: 'date', conditionalData: { value: { "+": [{ "var": ['user[date]'] }, 60 * 60 * 24 * 3] } }
|
|
28
|
+
end
|
|
29
|
+
hori.spacer width: 4
|
|
30
|
+
hori.button text: 'components/replace', onClick: ->(action) do
|
|
31
|
+
action.runMultiple childActions: ->(saction) do
|
|
32
|
+
saction.components_replace targetId: 'radio_group', newView: ->(view) do
|
|
33
|
+
view.fields_radioGroup value: '', childViews: ->(sview) do
|
|
34
|
+
sview.fields_radio label: 'Option99', value: 'option99'
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
saction.components_replace targetId: 'check_group', newView: ->(view) do
|
|
39
|
+
view.fields_checkGroup value: '', childViews: ->(sview) do
|
|
40
|
+
sview.fields_check label: 'Option99', value: nil, checkValue: 'option99'
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
hori.spacer width: 4
|
|
46
|
+
hori.button text: 'hide select', onClick: ->(action) do
|
|
47
|
+
action.components_set targetId: 'select', data: { displayed: false }
|
|
48
|
+
end
|
|
49
|
+
hori.spacer height: 4
|
|
50
|
+
hori.button text: 'hide jack', onClick: ->(action) do
|
|
51
|
+
action.runMultiple childActions: ->(saction) do
|
|
52
|
+
saction.components_set targetId: 'ver', data: { displayed: true }
|
|
53
|
+
saction.components_set targetId: 'ver1', data: { displayed: false }
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
hori.spacer height: 4
|
|
57
|
+
hori.button text: 'show jack', onClick: ->(action) do
|
|
58
|
+
action.runMultiple childActions: ->(saction) do
|
|
59
|
+
saction.components_set targetId: 'ver', data: { displayed: false }
|
|
60
|
+
saction.components_set targetId: 'ver1', data: { displayed: true }
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
form.spacer height: 8
|
|
66
|
+
form.hr width: 'matchParent'
|
|
67
|
+
form.spacer height: 8
|
|
68
|
+
|
|
69
|
+
validation = { required: { message: 'Required' } }
|
|
70
|
+
options = ['option1', 'option2', 'option3', 'option4'].map { |option| { 'text'=> option.humanize, 'value' => option } }
|
|
71
|
+
|
|
72
|
+
form.fields_date width: 'matchParent', name: 'user[date]', id: 'date', value: Date.new(2024, 7, 24), validation: validation
|
|
73
|
+
form.hr width: 'matchParent'
|
|
74
|
+
form.fields_select multiple: true, width: 'matchParent', name: 'user[select][]', id: 'select', options: options, value: ['option1', 'option2'], validation: validation
|
|
75
|
+
form.hr width: 'matchParent'
|
|
76
|
+
form.fields_chipGroup width: 'matchParent', name: 'user[chip_group]', id: 'chip_group', options: options, value: ['option2'], validation: validation
|
|
77
|
+
form.hr width: 'matchParent'
|
|
78
|
+
form.fields_radioGroup width: 'matchParent', name: 'user[radio_group]', id: 'radio_group', value: 'option3', validation: validation, childViews: ->(radio) do
|
|
79
|
+
options.each do |option|
|
|
80
|
+
radio.fields_radio label: option['text'], value: option['value']
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
form.hr width: 'matchParent'
|
|
84
|
+
check_group_value = ['option3', 'option1']
|
|
85
|
+
form.fields_checkGroup width: 'matchParent', name: 'user[check_group]', id: 'check_group', value: check_group_value, validation: validation, childViews: ->(radio) do
|
|
86
|
+
options.each do |option|
|
|
87
|
+
radio.fields_check label: option['text'], checkValue: option['value']
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
form.hr width: 'matchParent'
|
|
91
|
+
form.panels_vertical width: 'matchParent', id: 'ver', childViews: ->(ver) do
|
|
92
|
+
form.fields_text width: 'matchParent', name: 'user[text]', id: 'text', value: 'John Doe', validation: validation.merge(format: { regex: /Doe\z/, message: 'Must end with Doe' })
|
|
93
|
+
end
|
|
94
|
+
form.panels_vertical width: 'matchParent', id: 'ver1', displayed: false, childViews: ->(ver) do
|
|
95
|
+
form.fields_text width: 'matchParent', name: 'user[text]', value: 'Jack Doe', validation: validation.merge(format: { regex: /Doe\z/, message: 'Must end with Doe' })
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
form.hr width: 'matchParent'
|
|
99
|
+
|
|
100
|
+
form.fields_textarea width: 'matchParent', name: 'user[textarea]', id: 'textarea', value: 'Lorem ipsum et dumet bla bla bla...'
|
|
101
|
+
|
|
102
|
+
form.hr width: 'matchParent'
|
|
103
|
+
form.fields_submit text: 'submit'
|
|
104
|
+
form.spacer height: 2
|
|
105
|
+
form.fields_submit text: 'submit (if form valid)', disableIfFormInvalid: true
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
res.spacer height: 16
|
|
110
|
+
end
|
|
111
|
+
end
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
json.title 'Test Page (Form)'
|
|
2
|
+
|
|
3
|
+
page = json_ui_page json
|
|
4
|
+
|
|
5
|
+
page.body childViews: ->(body) do
|
|
6
|
+
render 'json_ui/garage/test_page/header', view: body
|
|
7
|
+
|
|
8
|
+
body.panels_responsive padding: glib_json_padding_body, childViews: ->(res) do
|
|
9
|
+
res.h2 text: 'Form'
|
|
10
|
+
res.spacer height: 8
|
|
11
|
+
res.panels_form \
|
|
12
|
+
url: json_ui_garage_url(path: 'forms/generic_post'),
|
|
13
|
+
method: 'post',
|
|
14
|
+
childViews: ->(form) do
|
|
15
|
+
|
|
16
|
+
properties = [
|
|
17
|
+
[
|
|
18
|
+
{ name: 'question', value: 'Punctuality' },
|
|
19
|
+
{ name: 'type', value: 'rating' },
|
|
20
|
+
],
|
|
21
|
+
[
|
|
22
|
+
{ name: 'question', value: 'Quality of work' },
|
|
23
|
+
{ name: 'type', value: 'rating' },
|
|
24
|
+
{ name: 'enabled', value: '1' },
|
|
25
|
+
],
|
|
26
|
+
[
|
|
27
|
+
{ name: 'question', value: 'Satisfied?' },
|
|
28
|
+
{ name: 'type', value: 'yes_no' },
|
|
29
|
+
]
|
|
30
|
+
]
|
|
31
|
+
validation = { required: { message: 'Required' } }
|
|
32
|
+
form.fields_dynamicGroup width: 'matchParent', name: 'user[evaluation]', groupFieldProperties: properties, titlePrefix: 'Entry', content: ->(group) do
|
|
33
|
+
group.template padding: { left: 32 }, childViews: ->(template) do
|
|
34
|
+
template.spacer height: 10
|
|
35
|
+
template.fields_text width: 'matchParent', name: 'question', label: 'Question', placeholder: 'Question', validation: validation
|
|
36
|
+
|
|
37
|
+
options = [ :rating, :yes_no ]
|
|
38
|
+
template.fields_select \
|
|
39
|
+
width: 'matchParent',
|
|
40
|
+
name: 'type',
|
|
41
|
+
label: 'Answer Type',
|
|
42
|
+
placeholder: 'Answer Type',
|
|
43
|
+
options: options.map { |o| { text: o.to_s.humanize, value: o } },
|
|
44
|
+
validation: validation
|
|
45
|
+
|
|
46
|
+
template.fields_check \
|
|
47
|
+
width: 'matchParent',
|
|
48
|
+
name: 'enabled',
|
|
49
|
+
label: 'Enable',
|
|
50
|
+
checkValue: '1',
|
|
51
|
+
showIf: { "==": [{ "var": 'user[evaluation][{{index}}][type]' }, 'rating'] }
|
|
52
|
+
|
|
53
|
+
template.spacer height: 14
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
form.fields_submit text: 'submit'
|
|
57
|
+
form.spacer height: 2
|
|
58
|
+
form.fields_submit text: 'submit (if form valid)', disableIfFormInvalid: true
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
res.spacer height: 16
|
|
62
|
+
end
|
|
63
|
+
end
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
json.title 'Test Page (Form)'
|
|
2
|
+
|
|
3
|
+
page = json_ui_page json
|
|
4
|
+
|
|
5
|
+
page.body childViews: ->(body) do
|
|
6
|
+
render 'json_ui/garage/test_page/header', view: body
|
|
7
|
+
|
|
8
|
+
body.panels_responsive padding: glib_json_padding_body, childViews: ->(res) do
|
|
9
|
+
res.h2 text: 'MultiUpload'
|
|
10
|
+
res.spacer height: 8
|
|
11
|
+
res.panels_form \
|
|
12
|
+
url: json_ui_garage_url(path: 'forms/generic_post'),
|
|
13
|
+
method: 'post',
|
|
14
|
+
childViews: ->(form) do
|
|
15
|
+
|
|
16
|
+
form.spacer height: 16
|
|
17
|
+
form.label text: 'Simple file upload'
|
|
18
|
+
form.spacer height: 8
|
|
19
|
+
form.fields_multiUpload \
|
|
20
|
+
name: 'user[multi][]',
|
|
21
|
+
id: 'upload_1',
|
|
22
|
+
width: 360,
|
|
23
|
+
accepts: { fileType: 'image', maxFileSize: 10 },
|
|
24
|
+
directUploadUrl: glib_direct_uploads_url,
|
|
25
|
+
uploadTitle: 'Files uploaded:',
|
|
26
|
+
storagePrefix: 'glib',
|
|
27
|
+
metadata: {
|
|
28
|
+
foo: 'bar',
|
|
29
|
+
zoo: 'baz'
|
|
30
|
+
},
|
|
31
|
+
# tagging: 'key=value&key1=value1',
|
|
32
|
+
tags: { key: 'value', key1: 'value1' },
|
|
33
|
+
files: [
|
|
34
|
+
{ name: 'File (Example)', signed_id: ActiveStorage::Attachment.first&.signed_id }
|
|
35
|
+
]
|
|
36
|
+
form.button text: 'clear files', onClick: ->(action) do
|
|
37
|
+
action.components_set targetId: 'upload_1', data: { files: [], value: nil }
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
form.spacer height: 16
|
|
41
|
+
form.label text: 'File upload with onFinishUpload'
|
|
42
|
+
form.spacer height: 8
|
|
43
|
+
form.fields_multiUpload \
|
|
44
|
+
name: 'user[multi2][]',
|
|
45
|
+
id: 'upload_2',
|
|
46
|
+
width: 360,
|
|
47
|
+
accepts: { fileType: 'image', maxFileSize: 5000 },
|
|
48
|
+
directUploadUrl: glib_direct_uploads_url,
|
|
49
|
+
uploadTitle: 'Files uploaded:',
|
|
50
|
+
onFinishUpload: ->(action) { action.forms_submit }
|
|
51
|
+
form.button text: 'populate files', onClick: ->(action) do
|
|
52
|
+
action.components_set targetId: 'upload_2', data: {
|
|
53
|
+
files: [
|
|
54
|
+
{ name: 'File (Example)', signed_id: ActiveStorage::Attachment.last&.signed_id }
|
|
55
|
+
],
|
|
56
|
+
value: [1]
|
|
57
|
+
}
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
form.fields_submit text: 'submit'
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
res.spacer height: 16
|
|
64
|
+
end
|
|
65
|
+
end
|
data/lib/glib/mailer_tester.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: glib-web
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 4.
|
|
4
|
+
version: 4.4.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- ''
|
|
@@ -111,6 +111,7 @@ files:
|
|
|
111
111
|
- app/helpers/glib/json_ui/abstract_builder.rb
|
|
112
112
|
- app/helpers/glib/json_ui/action_builder.rb
|
|
113
113
|
- app/helpers/glib/json_ui/action_builder/bottom_banners.rb
|
|
114
|
+
- app/helpers/glib/json_ui/action_builder/browsers.rb
|
|
114
115
|
- app/helpers/glib/json_ui/action_builder/commands.rb
|
|
115
116
|
- app/helpers/glib/json_ui/action_builder/components.rb
|
|
116
117
|
- app/helpers/glib/json_ui/action_builder/dialogs.rb
|
|
@@ -123,6 +124,7 @@ files:
|
|
|
123
124
|
- app/helpers/glib/json_ui/action_builder/popovers.rb
|
|
124
125
|
- app/helpers/glib/json_ui/action_builder/sheets.rb
|
|
125
126
|
- app/helpers/glib/json_ui/action_builder/snackbars.rb
|
|
127
|
+
- app/helpers/glib/json_ui/action_builder/storage_items.rb
|
|
126
128
|
- app/helpers/glib/json_ui/action_builder/tours.rb
|
|
127
129
|
- app/helpers/glib/json_ui/action_builder/windows.rb
|
|
128
130
|
- app/helpers/glib/json_ui/analytics_helper.rb
|
|
@@ -287,7 +289,13 @@ files:
|
|
|
287
289
|
- app/views/json_ui/garage/tables/index.json.jbuilder
|
|
288
290
|
- app/views/json_ui/garage/tables/layout.json.jbuilder
|
|
289
291
|
- app/views/json_ui/garage/tables/panel_content.json.jbuilder
|
|
290
|
-
- app/views/json_ui/garage/test_page/
|
|
292
|
+
- app/views/json_ui/garage/test_page/_header.json.jbuilder
|
|
293
|
+
- app/views/json_ui/garage/test_page/auto_validate.json.jbuilder
|
|
294
|
+
- app/views/json_ui/garage/test_page/dialog.json.jbuilder
|
|
295
|
+
- app/views/json_ui/garage/test_page/dialog_open.json.jbuilder
|
|
296
|
+
- app/views/json_ui/garage/test_page/form.json.jbuilder
|
|
297
|
+
- app/views/json_ui/garage/test_page/form_dynamic.json.jbuilder
|
|
298
|
+
- app/views/json_ui/garage/test_page/multiupload.json.jbuilder
|
|
291
299
|
- app/views/json_ui/garage/views/_chart_data.json.jbuilder
|
|
292
300
|
- app/views/json_ui/garage/views/banners.json.jbuilder
|
|
293
301
|
- app/views/json_ui/garage/views/calendar_data.json.jbuilder
|
|
@@ -1,120 +0,0 @@
|
|
|
1
|
-
json.title 'Test Page'
|
|
2
|
-
|
|
3
|
-
page = json_ui_page json
|
|
4
|
-
|
|
5
|
-
page.body childViews: ->(body) do
|
|
6
|
-
body.panels_responsive padding: glib_json_padding_body, childViews: ->(res) do
|
|
7
|
-
res.panels_column lg: { cols: 6 }, childViews: ->(col) do
|
|
8
|
-
res.h2 text: 'Reactivity & validation'
|
|
9
|
-
res.spacer height: 8
|
|
10
|
-
res.panels_form \
|
|
11
|
-
url: json_ui_garage_url(path: 'forms/generic_post'),
|
|
12
|
-
method: 'post',
|
|
13
|
-
childViews: ->(form) do
|
|
14
|
-
form.panels_flow innerPadding: { bottom: 0 }, width: 'matchParent', childViews: ->(hori) do
|
|
15
|
-
hori.button text: 'components/set', onClick: ->(action) do
|
|
16
|
-
action.runMultiple childActions: ->(saction) do
|
|
17
|
-
saction.components_set targetId: 'text', data: { value: 'Doe John' }
|
|
18
|
-
saction.components_set targetId: 'textarea', data: { value: 'The quick brown fox jumps over the lazy dog' }
|
|
19
|
-
new_options = [{ text: 'Option99', value: 'option99' }]
|
|
20
|
-
['select', 'chip_group'].each do |id|
|
|
21
|
-
saction.components_set targetId: id, data: { options: new_options, value: ['option99'] }
|
|
22
|
-
end
|
|
23
|
-
end
|
|
24
|
-
end
|
|
25
|
-
hori.spacer width: 4
|
|
26
|
-
hori.button text: 'logics/set', onClick: ->(action) do
|
|
27
|
-
action.logics_set targetId: 'date', conditionalData: { value: { "+": [{ "var": ['user[date]'] }, 60 * 60 * 24 * 3] } }
|
|
28
|
-
end
|
|
29
|
-
hori.spacer width: 4
|
|
30
|
-
hori.button text: 'components/replace', onClick: ->(action) do
|
|
31
|
-
action.runMultiple childActions: ->(saction) do
|
|
32
|
-
saction.components_replace targetId: 'radio_group', newView: ->(view) do
|
|
33
|
-
view.fields_radioGroup value: '', childViews: ->(sview) do
|
|
34
|
-
sview.fields_radio label: 'Option99', value: 'option99'
|
|
35
|
-
end
|
|
36
|
-
end
|
|
37
|
-
|
|
38
|
-
saction.components_replace targetId: 'check_group', newView: ->(view) do
|
|
39
|
-
view.fields_checkGroup value: '', childViews: ->(sview) do
|
|
40
|
-
sview.fields_check label: 'Option99', value: nil, checkValue: 'option99'
|
|
41
|
-
end
|
|
42
|
-
end
|
|
43
|
-
end
|
|
44
|
-
end
|
|
45
|
-
hori.spacer width: 4
|
|
46
|
-
hori.button text: 'hide select', onClick: ->(action) do
|
|
47
|
-
action.components_set targetId: 'select', data: { displayed: false }
|
|
48
|
-
end
|
|
49
|
-
end
|
|
50
|
-
|
|
51
|
-
form.spacer height: 8
|
|
52
|
-
form.hr width: 'matchParent'
|
|
53
|
-
form.spacer height: 8
|
|
54
|
-
|
|
55
|
-
validation = { required: { message: 'Required' } }
|
|
56
|
-
options = ['option1', 'option2', 'option3', 'option4'].map { |option| { 'text'=> option.humanize, 'value' => option } }
|
|
57
|
-
|
|
58
|
-
form.fields_date width: 'matchParent', name: 'user[date]', id: 'date', value: Date.new(2024, 7, 24), validation: validation
|
|
59
|
-
form.hr width: 'matchParent'
|
|
60
|
-
form.fields_select multiple: true, width: 'matchParent', name: 'user[select][]', id: 'select', options: options, value: ['option1', 'option2'], validation: validation
|
|
61
|
-
form.hr width: 'matchParent'
|
|
62
|
-
form.fields_chipGroup width: 'matchParent', name: 'user[chip_group]', id: 'chip_group', options: options, value: ['option2'], validation: validation
|
|
63
|
-
form.hr width: 'matchParent'
|
|
64
|
-
form.fields_radioGroup width: 'matchParent', name: 'user[radio_group]', id: 'radio_group', value: 'option3', validation: validation, childViews: ->(radio) do
|
|
65
|
-
options.each do |option|
|
|
66
|
-
radio.fields_radio label: option['text'], value: option['value']
|
|
67
|
-
end
|
|
68
|
-
end
|
|
69
|
-
form.hr width: 'matchParent'
|
|
70
|
-
check_group_value = ['option3', 'option1']
|
|
71
|
-
form.fields_checkGroup width: 'matchParent', name: 'user[check_group]', id: 'check_group', value: check_group_value, validation: validation, childViews: ->(radio) do
|
|
72
|
-
options.each do |option|
|
|
73
|
-
radio.fields_check label: option['text'], checkValue: option['value']
|
|
74
|
-
end
|
|
75
|
-
end
|
|
76
|
-
form.hr width: 'matchParent'
|
|
77
|
-
form.fields_text width: 'matchParent', name: 'user[text]', id: 'text', value: 'John Doe', validation: validation
|
|
78
|
-
|
|
79
|
-
form.hr width: 'matchParent'
|
|
80
|
-
|
|
81
|
-
form.fields_textarea width: 'matchParent', name: 'user[textarea]', id: 'textarea', value: 'Lorem ipsum et dumet bla bla bla...'
|
|
82
|
-
|
|
83
|
-
form.hr width: 'matchParent'
|
|
84
|
-
form.fields_submit text: 'submit'
|
|
85
|
-
form.spacer height: 2
|
|
86
|
-
form.fields_submit text: 'submit (if form valid)', disableIfFormInvalid: true
|
|
87
|
-
end
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
res.spacer height: 16
|
|
91
|
-
|
|
92
|
-
end
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
res.panels_column lg: { cols: 6 }, childViews: ->(col) do
|
|
96
|
-
res.h2 text: 'Dialog'
|
|
97
|
-
res.spacer height: 8
|
|
98
|
-
res.button text: 'Dialog updateExisting', onClick: ->(action) do
|
|
99
|
-
action.runMultiple childActions: ->(saction) do
|
|
100
|
-
saction.dialogs_show updateExisting: true, content: ->(dialog) do
|
|
101
|
-
dialog.body padding: glib_json_padding_body, childViews: ->(sbody) do
|
|
102
|
-
sbody.h1 text: 'Hello world'
|
|
103
|
-
sbody.button text: 'change dialog content', onClick: ->(ssaction) do
|
|
104
|
-
ssaction.dialogs_show updateExisting: true, disableCloseButton: true, content: ->(sdialog) do
|
|
105
|
-
sdialog.body padding: glib_json_padding_body, childViews: ->(ssbody) do
|
|
106
|
-
ssbody.h1 text: 'Hello world (updated)'
|
|
107
|
-
ssbody.spacer height: 8
|
|
108
|
-
ssbody.button text: 'close', onClick: ->(xaction) do
|
|
109
|
-
xaction.dialogs_close
|
|
110
|
-
end
|
|
111
|
-
end
|
|
112
|
-
end
|
|
113
|
-
end
|
|
114
|
-
end
|
|
115
|
-
end
|
|
116
|
-
end
|
|
117
|
-
end
|
|
118
|
-
end
|
|
119
|
-
end
|
|
120
|
-
end
|