brick 1.0.213 → 1.0.214
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/lib/brick/config.rb +0 -13
- data/lib/brick/extensions.rb +37 -50
- data/lib/brick/frameworks/rails/engine.rb +17 -7
- data/lib/brick/frameworks/rails/form_tags.rb +268 -229
- data/lib/brick/reflect_tables.rb +1 -1
- data/lib/brick/version_number.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: afed5350a655b7eca570609ff4d15f998ecfe746345c4771b7eb910274df14ae
|
|
4
|
+
data.tar.gz: 45d5cccb07240fe0995bf812dc4b0cc34d21edd1bb0ab3cf212cd255c8a0f6a4
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: ca420002527953167f6ba1112e43d197bea259bf360c89ff92a01c9753c53da1b7060c15cd021c27e6106c4e77e7d3c30f589c89509ae21c2a2fe69d42e6f079
|
|
7
|
+
data.tar.gz: e6b1fd3745b5c69bfaa9486a4158b7a8efc03c7c43aa884a13f630e9b023e40e0893e1862e6e7fee545049efb46c5b3686cd4f05363d19eb3dfcf0d8f6b1cef3
|
data/lib/brick/config.rb
CHANGED
|
@@ -429,19 +429,6 @@ module Brick
|
|
|
429
429
|
end
|
|
430
430
|
end
|
|
431
431
|
|
|
432
|
-
def acts_as_list_cols
|
|
433
|
-
@mutex.synchronize { @acts_as_list || {} }
|
|
434
|
-
end
|
|
435
|
-
|
|
436
|
-
# Get something like:
|
|
437
|
-
# { 'on_call_list' => { _brick_default: [:last_name, :first_name] } }
|
|
438
|
-
# { 'on_call_list' => { _brick_default: :sequence } }
|
|
439
|
-
def acts_as_list_cols=(position_cols)
|
|
440
|
-
@mutex.synchronize do
|
|
441
|
-
@acts_as_list ||= position_cols
|
|
442
|
-
end
|
|
443
|
-
end
|
|
444
|
-
|
|
445
432
|
def metadata_columns
|
|
446
433
|
@mutex.synchronize { @metadata_columns ||= ['created_at', 'updated_at', 'deleted_at'] }
|
|
447
434
|
end
|
data/lib/brick/extensions.rb
CHANGED
|
@@ -71,15 +71,24 @@ module ActiveRecord
|
|
|
71
71
|
end
|
|
72
72
|
|
|
73
73
|
def real_model(params)
|
|
74
|
-
if params && (
|
|
75
|
-
|
|
74
|
+
if params && ((sub_name = params.fetch(inheritance_column, nil)).present? ||
|
|
75
|
+
(sub_name = params[name.underscore]&.fetch(inheritance_column, nil)))
|
|
76
|
+
sub_name = sub_name.first if sub_name.is_a?(Array) # Support the params style that gets returned from #_brick_querying
|
|
76
77
|
# Make sure the chosen model is really the same or a subclass of this model
|
|
77
|
-
|
|
78
|
+
return self if sub_name.blank?
|
|
79
|
+
|
|
80
|
+
(possible_model = sub_name.constantize) <= self ? possible_model : self
|
|
78
81
|
else
|
|
79
82
|
self
|
|
80
83
|
end
|
|
81
84
|
end
|
|
82
85
|
|
|
86
|
+
# Accommodate STI
|
|
87
|
+
def real_singular(params)
|
|
88
|
+
real_model = real_model(params)
|
|
89
|
+
[real_model, real_model.name.underscore.split('/').last]
|
|
90
|
+
end
|
|
91
|
+
|
|
83
92
|
def json_column?(col)
|
|
84
93
|
col.type == :json || ::Brick.config.json_columns[table_name]&.include?(col.name) ||
|
|
85
94
|
(
|
|
@@ -196,33 +205,6 @@ module ActiveRecord
|
|
|
196
205
|
def _brick_monetized_attributes
|
|
197
206
|
@_brick_monetized_attributes ||= respond_to?(:monetized_attributes) ? monetized_attributes.values : {}
|
|
198
207
|
end
|
|
199
|
-
|
|
200
|
-
# def acts_as_list(aal_cols = nil)
|
|
201
|
-
# if aal_cols
|
|
202
|
-
# aal_cols = [aal_cols] unless aal_cols.is_a?(Array)
|
|
203
|
-
# @acts_as_list_cols = aal_cols.each_with_object([]) do |aal_col, s|
|
|
204
|
-
# if column_names.include?(aal_col = aal_col.to_s) && !s.include?(aal_col)
|
|
205
|
-
# s << aal_col
|
|
206
|
-
# end
|
|
207
|
-
# end
|
|
208
|
-
# else
|
|
209
|
-
# if [:integer, :bigint].include?(columns_hash['position']&.type)
|
|
210
|
-
# @acts_as_list_cols = ['position']
|
|
211
|
-
# else
|
|
212
|
-
# return
|
|
213
|
-
# end
|
|
214
|
-
# end
|
|
215
|
-
# # Override save in order to update neighbours when necessary
|
|
216
|
-
# alias _brick_save save
|
|
217
|
-
# def save
|
|
218
|
-
# # @acts_as_list_cols
|
|
219
|
-
# # -1
|
|
220
|
-
# @acts_as_list_cols.each do |aal_col|
|
|
221
|
-
# binding.pry if (aal_change = changes[aal_col])
|
|
222
|
-
# end
|
|
223
|
-
# _brick_save
|
|
224
|
-
# end
|
|
225
|
-
# end
|
|
226
208
|
end
|
|
227
209
|
|
|
228
210
|
def self.brick_parse_dsl(join_array = nil, prefix = [], translations = {}, is_polymorphic = false, dsl = nil, emit_dsl = false)
|
|
@@ -1765,7 +1747,9 @@ class Object
|
|
|
1765
1747
|
end
|
|
1766
1748
|
# Accommodate singular or camel-cased table names such as "order_detail" or "OrderDetails"
|
|
1767
1749
|
code << " self.table_name = '#{self.table_name = matching}'\n" if (inheritable_name || model_name).underscore.pluralize != matching
|
|
1768
|
-
|
|
1750
|
+
|
|
1751
|
+
if (inh_col = relation.fetch(:sti_col, nil) ||
|
|
1752
|
+
::Brick.config.sti_type_column.find { |_k, v| v.include?(matching) }&.first)
|
|
1769
1753
|
new_model_class.inheritance_column = inh_col
|
|
1770
1754
|
code << " self.inheritance_column = '#{inh_col}'\n"
|
|
1771
1755
|
end
|
|
@@ -1816,11 +1800,6 @@ class Object
|
|
|
1816
1800
|
end
|
|
1817
1801
|
end
|
|
1818
1802
|
|
|
1819
|
-
if (sti_col = relation.fetch(:sti_col, nil))
|
|
1820
|
-
new_model_class.send(:'inheritance_column=', sti_col)
|
|
1821
|
-
code << " self.inheritance_column = #{sti_col.inspect}\n"
|
|
1822
|
-
end
|
|
1823
|
-
|
|
1824
1803
|
unless is_sti
|
|
1825
1804
|
fks = relation[:fks] || {}
|
|
1826
1805
|
# Do the bulk of the has_many / belongs_to processing, and store details about HMT so they can be done at the very last
|
|
@@ -1902,12 +1881,6 @@ class Object
|
|
|
1902
1881
|
end
|
|
1903
1882
|
end
|
|
1904
1883
|
|
|
1905
|
-
# Apply any acts_as_list things
|
|
1906
|
-
if (aal_col = ::Brick.config.acts_as_list_cols.fetch(matching, nil))
|
|
1907
|
-
new_model_class.send(:acts_as_list, aal_col.to_sym)
|
|
1908
|
-
code << " acts_as_list :#{aal_col}\n"
|
|
1909
|
-
end
|
|
1910
|
-
|
|
1911
1884
|
# Auto-support Ransack if it's present
|
|
1912
1885
|
if self.respond_to?(:ransackable_attributes)
|
|
1913
1886
|
def self.ransackable_attributes(auth_object = nil)
|
|
@@ -2480,13 +2453,15 @@ class Object
|
|
|
2480
2453
|
code << " @#{plural_table_name}._brick_querying(params, brick_col_names: true)\n"
|
|
2481
2454
|
code << " end\n"
|
|
2482
2455
|
|
|
2483
|
-
|
|
2456
|
+
# ----------------------------------------------------------------------------------
|
|
2457
|
+
|
|
2484
2458
|
if pk.present?
|
|
2485
2459
|
code << " def show\n"
|
|
2486
2460
|
code << " #{find_by_name = "find_#{singular_table_name}"}\n"
|
|
2487
2461
|
code << " end\n"
|
|
2488
2462
|
self.define_method :show do
|
|
2489
2463
|
_schema, @_is_show_schema_list = ::Brick.set_db_schema(params)
|
|
2464
|
+
_, singular_table_name = model.real_singular(params)
|
|
2490
2465
|
instance_variable_set("@#{singular_table_name}".to_sym, find_obj)
|
|
2491
2466
|
add_csp_hash("'unsafe-inline'")
|
|
2492
2467
|
end
|
|
@@ -2505,7 +2480,8 @@ class Object
|
|
|
2505
2480
|
send(params_name_sym)
|
|
2506
2481
|
rescue
|
|
2507
2482
|
end
|
|
2508
|
-
|
|
2483
|
+
real_model, singular_table_name = model.real_singular(params)
|
|
2484
|
+
new_params ||= real_model.attribute_names.each_with_object({}) do |a, s|
|
|
2509
2485
|
if (val = params["__#{a}"])
|
|
2510
2486
|
# val = case new_obj.class.column_for_attribute(a).type
|
|
2511
2487
|
# when :datetime, :date, :time, :timestamp
|
|
@@ -2516,7 +2492,7 @@ class Object
|
|
|
2516
2492
|
s[a] = val
|
|
2517
2493
|
end
|
|
2518
2494
|
end
|
|
2519
|
-
if (new_obj =
|
|
2495
|
+
if (new_obj = real_model.new(new_params)).respond_to?(:serializable_hash)
|
|
2520
2496
|
# Convert any Filename objects with nil into an empty string so that #encode can be called on them
|
|
2521
2497
|
new_obj.serializable_hash.each do |k, v|
|
|
2522
2498
|
new_obj.send("#{k}=", ::ActiveStorage::Filename.new('')) if v.is_a?(::ActiveStorage::Filename) && !v.instance_variable_get(:@filename)
|
|
@@ -2542,12 +2518,20 @@ class Object
|
|
|
2542
2518
|
end
|
|
2543
2519
|
render json: { result: ::Brick.unexclude_column(table_name, col) }
|
|
2544
2520
|
else
|
|
2545
|
-
|
|
2546
|
-
|
|
2521
|
+
real_model = model.real_model(params)
|
|
2522
|
+
singular_table_name = real_model.name.underscore.split('/').last
|
|
2523
|
+
created_obj = model.send(:new, send(params_name_sym))
|
|
2524
|
+
if created_obj.respond_to?(inh_col = model.inheritance_column) && created_obj.send(inh_col) == ''
|
|
2525
|
+
created_obj.send("#{inh_col}=", model.name)
|
|
2526
|
+
end
|
|
2527
|
+
created_obj.save
|
|
2528
|
+
@_lookup_context.instance_variable_set(:@_brick_model, real_model)
|
|
2547
2529
|
if created_obj.errors.empty?
|
|
2530
|
+
instance_variable_set("@#{singular_table_name}".to_sym, created_obj)
|
|
2548
2531
|
index
|
|
2549
2532
|
render :index
|
|
2550
2533
|
else # Surface errors to the user in a flash message
|
|
2534
|
+
instance_variable_set("@#{singular_table_name}".to_sym, created_obj)
|
|
2551
2535
|
flash.now.alert = (created_obj.errors.errors.map { |err| "<b>#{err.attribute}</b> #{err.message}" }.join(', '))
|
|
2552
2536
|
new
|
|
2553
2537
|
render :new
|
|
@@ -2566,6 +2550,7 @@ class Object
|
|
|
2566
2550
|
code << " end\n"
|
|
2567
2551
|
self.define_method :edit do
|
|
2568
2552
|
_schema, @_is_show_schema_list = ::Brick.set_db_schema(params)
|
|
2553
|
+
_, singular_table_name = model.real_singular(params)
|
|
2569
2554
|
instance_variable_set("@#{singular_table_name}".to_sym, find_obj)
|
|
2570
2555
|
add_csp_hash
|
|
2571
2556
|
end
|
|
@@ -2593,6 +2578,7 @@ class Object
|
|
|
2593
2578
|
# return
|
|
2594
2579
|
end
|
|
2595
2580
|
|
|
2581
|
+
_, singular_table_name = model.real_singular(params)
|
|
2596
2582
|
instance_variable_set("@#{singular_table_name}".to_sym, (obj = find_obj))
|
|
2597
2583
|
upd_params = send(params_name_sym)
|
|
2598
2584
|
json_overrides = ::Brick.config.json_columns&.fetch(table_name, nil)
|
|
@@ -2679,11 +2665,11 @@ class Object
|
|
|
2679
2665
|
if is_need_params
|
|
2680
2666
|
code << " def #{params_name}\n"
|
|
2681
2667
|
permits_txt = model._brick_find_permits(model, permits = model._brick_all_fields(true))
|
|
2682
|
-
code << " params.require(:#{
|
|
2668
|
+
code << " params.require(:#{model.base_class.name.underscore.tr('/', '_')
|
|
2683
2669
|
}).permit(#{permits_txt.map(&:inspect).join(', ')})\n"
|
|
2684
2670
|
code << " end\n"
|
|
2685
2671
|
self.define_method(params_name) do
|
|
2686
|
-
params.require(
|
|
2672
|
+
params.require(model.base_class.name.underscore.tr('/', '_').to_sym).permit(permits)
|
|
2687
2673
|
end
|
|
2688
2674
|
private params_name
|
|
2689
2675
|
# Get column names for params from relations[model.table_name][:cols].keys
|
|
@@ -2978,7 +2964,8 @@ module Brick
|
|
|
2978
2964
|
else
|
|
2979
2965
|
inverse_table = [primary_table] if polymorphic_class
|
|
2980
2966
|
assoc_bt = bts[cnstr_name] = { is_bt: true, fk: fk[2], assoc_name: bt_assoc_name, inverse_table: inverse_table || primary_table }
|
|
2981
|
-
assoc_bt[:optional] = true if is_optional
|
|
2967
|
+
assoc_bt[:optional] = true if is_optional ||
|
|
2968
|
+
(is_optional.nil? && !relations[fk[1]][:cols][fk[2]][3])
|
|
2982
2969
|
assoc_bt[:polymorphic] = [polymorphic_class] if polymorphic_class
|
|
2983
2970
|
end
|
|
2984
2971
|
if is_class
|
|
@@ -809,6 +809,7 @@ h1, h3 {
|
|
|
809
809
|
background-repeat: no-repeat;
|
|
810
810
|
background-size: 100% 100%;
|
|
811
811
|
width: 28px;
|
|
812
|
+
height: 32px;
|
|
812
813
|
cursor: pointer;
|
|
813
814
|
}
|
|
814
815
|
#mermaidErd {
|
|
@@ -942,10 +943,10 @@ table.shadow > tbody > tr {
|
|
|
942
943
|
table tbody tr:nth-of-type(even) {
|
|
943
944
|
background-color: #f3f3f3;
|
|
944
945
|
}
|
|
945
|
-
table tbody tr:nth-of-type(even) .
|
|
946
|
+
table tbody tr:nth-of-type(even) .alternating-gray {
|
|
946
947
|
background-color: #fff;
|
|
947
948
|
}
|
|
948
|
-
table tbody tr:nth-of-type(odd) .
|
|
949
|
+
table tbody tr:nth-of-type(odd) .alternating-gray {
|
|
949
950
|
background-color: #f3f3f3;
|
|
950
951
|
}
|
|
951
952
|
|
|
@@ -991,6 +992,11 @@ a.big-arrow {
|
|
|
991
992
|
background-color: red;
|
|
992
993
|
color: white;
|
|
993
994
|
}
|
|
995
|
+
.brick-note {
|
|
996
|
+
font-size: 0.7em;
|
|
997
|
+
color: #A0FFA0;
|
|
998
|
+
max-width: 0;
|
|
999
|
+
}
|
|
994
1000
|
|
|
995
1001
|
#revertTemplate {
|
|
996
1002
|
display: none;
|
|
@@ -1336,8 +1342,7 @@ end
|
|
|
1336
1342
|
end}
|
|
1337
1343
|
%>
|
|
1338
1344
|
|
|
1339
|
-
#{"<hr><%=
|
|
1340
|
-
obj_name}\", #{new_path_name}, { class: '__brick' }) if respond_to?(:#{new_path_name}) %>" unless @_brick_model.is_view?}
|
|
1345
|
+
#{"<hr><%= link_to_brick(model, new: true, class: '__brick') %>" unless @_brick_model.is_view?}
|
|
1341
1346
|
#{script}
|
|
1342
1347
|
</body>
|
|
1343
1348
|
</html>
|
|
@@ -1437,7 +1442,7 @@ end
|
|
|
1437
1442
|
<head>
|
|
1438
1443
|
#{css}
|
|
1439
1444
|
<title><%=
|
|
1440
|
-
base_model = (model = (obj = @#{obj_name})
|
|
1445
|
+
base_model = (model = (obj = @#{obj_name}).class).base_class
|
|
1441
1446
|
see_all_path = send(\"#\{base_model._brick_index}_path\")
|
|
1442
1447
|
#{(inh_col = @_brick_model.inheritance_column).present? &&
|
|
1443
1448
|
" if obj.respond_to?(:#{inh_col}) && (model_name = @#{obj_name}.#{inh_col}) &&
|
|
@@ -1445,6 +1450,7 @@ end
|
|
|
1445
1450
|
see_all_path << \"?#{inh_col}=#\{model_name}\"
|
|
1446
1451
|
end
|
|
1447
1452
|
model_name = base_model.name if model_name.is_a?(Numeric)"}
|
|
1453
|
+
model_name = nil if model_name == ''
|
|
1448
1454
|
page_title = (\"#\{model_name ||= model.name}: #\{obj&.brick_descrip || controller_name}\")
|
|
1449
1455
|
%></title>
|
|
1450
1456
|
</head>
|
|
@@ -1510,8 +1516,12 @@ end
|
|
|
1510
1516
|
# path_options = [obj.#{pk}]
|
|
1511
1517
|
# path_options << { '_brick_schema': } if
|
|
1512
1518
|
options = {}
|
|
1513
|
-
|
|
1514
|
-
|
|
1519
|
+
options[:url] = if obj.new_record?
|
|
1520
|
+
link_to_brick(obj.class, path_only: true) # Properly supports STI, but only works for :new
|
|
1521
|
+
else
|
|
1522
|
+
path_helper = obj.new_record? ? #{model_name}._brick_index : #{model_name}._brick_index(:singular)
|
|
1523
|
+
options[:url] = send(\"#\{path_helper}_path\".to_sym, obj) if ::Brick.config.path_prefix || (path_helper != obj.class.table_name)
|
|
1524
|
+
end
|
|
1515
1525
|
%>
|
|
1516
1526
|
<br><br>
|
|
1517
1527
|
|
|
@@ -6,70 +6,20 @@ module Brick::Rails::FormTags
|
|
|
6
6
|
# When a relation is not provided, first see if one exists which matches the controller name or
|
|
7
7
|
# something has turned up in the instance variables.
|
|
8
8
|
relation ||= (instance_variable_get("@#{controller_name}".to_sym) || _brick_resource_from_iv)
|
|
9
|
+
klass = relation.klass
|
|
9
10
|
|
|
10
11
|
nfc = Brick.config.sidescroll.fetch(relation.table_name, nil)&.fetch(:num_frozen_columns, nil) ||
|
|
11
12
|
Brick.config.sidescroll.fetch(:num_frozen_columns, nil) ||
|
|
12
13
|
0
|
|
13
14
|
|
|
14
|
-
|
|
15
|
-
out = +"<div id=\"headerTopContainer\"><table id=\"headerTop\"></table>
|
|
16
|
-
"
|
|
17
|
-
klass = relation.klass
|
|
15
|
+
out = +''
|
|
18
16
|
rel = ::Brick.relations&.fetch(relation.table_name, nil)
|
|
19
|
-
|
|
20
|
-
out <<
|
|
21
|
-
<div id=\"headerButtonBox\">
|
|
22
|
-
"
|
|
23
|
-
unless show_row_count == false
|
|
24
|
-
out << " <div id=\"rowCount\"></div>
|
|
25
|
-
"
|
|
26
|
-
end
|
|
27
|
-
unless show_erd_button == false
|
|
28
|
-
out << " <div id=\"imgErd\" title=\"Show ERD\"></div>
|
|
29
|
-
"
|
|
30
|
-
end
|
|
31
|
-
if rel && show_in_app_button != false && (in_app = rel.fetch(:existing, nil)&.fetch(:index, nil))
|
|
32
|
-
begin
|
|
33
|
-
in_app = send("#{in_app}_path") if in_app.is_a?(Symbol)
|
|
34
|
-
out << " <td title=\"Show in app\">#{link_to(::Brick::Rails::IN_APP.html_safe, in_app)}</td>
|
|
35
|
-
"
|
|
36
|
-
rescue ActionController::UrlGenerationError # Avoid snags like "No route matches {:action=>"index", :controller=>"categories/products"}, missing required keys: [:category_id]"
|
|
37
|
-
end
|
|
38
|
-
end
|
|
39
|
-
if show_avo_button != false && Object.const_defined?('Avo') && ::Avo.respond_to?(:railtie_namespace) && klass.name.exclude?('::')
|
|
40
|
-
out << "
|
|
41
|
-
<td>#{link_to_brick(
|
|
42
|
-
::Brick::Rails::AVO_SVG.html_safe,
|
|
43
|
-
{ index_proc: Proc.new do |_avo_model, relation|
|
|
44
|
-
path_helper = "resources_#{relation.fetch(:auto_prefixed_schema, nil)}#{klass.model_name.route_key}_path".to_sym
|
|
45
|
-
::Avo.railtie_routes_url_helpers.send(path_helper) if ::Avo.railtie_routes_url_helpers.respond_to?(path_helper)
|
|
46
|
-
end,
|
|
47
|
-
title: "#{klass.name} in Avo" }
|
|
48
|
-
)}</td>
|
|
49
|
-
"
|
|
50
|
-
end
|
|
51
|
-
|
|
52
|
-
if show_aa_button != false && Object.const_defined?('ActiveAdmin')
|
|
53
|
-
ActiveAdmin.application.namespaces.names.each do |ns|
|
|
54
|
-
out << "
|
|
55
|
-
<td>#{link_to_brick(
|
|
56
|
-
::Brick::Rails::AA_PNG.html_safe,
|
|
57
|
-
{ index_proc: Proc.new do |aa_model, relation|
|
|
58
|
-
path_helper = "#{ns}_#{relation.fetch(:auto_prefixed_schema, nil)}#{aa_model.model_name.route_key}_path".to_sym
|
|
59
|
-
send(path_helper) if respond_to?(path_helper)
|
|
60
|
-
end,
|
|
61
|
-
title: "#{klass.name} in ActiveAdmin" }
|
|
62
|
-
)}</td>
|
|
63
|
-
"
|
|
64
|
-
end
|
|
65
|
-
end
|
|
66
|
-
out << " </div>
|
|
67
|
-
</div>
|
|
68
|
-
"
|
|
17
|
+
if show_header != false
|
|
18
|
+
out << brick_header(rel, klass, show_row_count, show_erd_button, show_in_app_button, show_avo_button, show_aa_button)
|
|
69
19
|
end
|
|
70
20
|
|
|
71
|
-
|
|
72
|
-
<table id=\"#{table_name = relation.table_name.split('.').last}\" class=\"shadow\"#{ " x-num-frozen=\"#{nfc}\"" if nfc.positive? }>
|
|
21
|
+
# HTML for brick_grid
|
|
22
|
+
out << "<table id=\"#{table_name = relation.table_name.split('.').last}\" class=\"shadow\"#{ " x-num-frozen=\"#{nfc}\"" if nfc.positive? }>
|
|
73
23
|
<thead><tr>"
|
|
74
24
|
pk = klass.primary_key || []
|
|
75
25
|
pk = [pk] unless pk.is_a?(Array)
|
|
@@ -145,13 +95,13 @@ module Brick::Rails::FormTags
|
|
|
145
95
|
row_count = 0
|
|
146
96
|
relation.each do |obj|
|
|
147
97
|
out << "<tr>\n"
|
|
148
|
-
out << "<td class=\"col-sticky\">#{link_to('⇛', send("#{klass._brick_index(:singular)}_path".to_sym,
|
|
98
|
+
out << "<td class=\"col-sticky alternating-gray\">#{link_to('⇛', send("#{klass._brick_index(:singular)}_path".to_sym,
|
|
149
99
|
pk.map { |pk_part| obj.send(pk_part.to_sym) }), { class: 'big-arrow' })}</td>\n" if pk.present?
|
|
150
100
|
sequence.each_with_index do |col_name, idx|
|
|
151
101
|
val = obj.attributes[col_name]
|
|
152
102
|
bt = bts[col_name] || composite_bt_names[col_name]
|
|
153
103
|
out << '<td'
|
|
154
|
-
(classes ||= []) << 'col-sticky' if idx < nfc
|
|
104
|
+
(classes ||= []) << 'col-sticky alternating-gray' if idx < nfc
|
|
155
105
|
(classes ||= []) << 'dimmed' unless cols.key?(col_name) || (cust_col = cust_cols[col_name]) ||
|
|
156
106
|
(col_name.is_a?(Symbol) && bts.key?(col_name)) # HOT
|
|
157
107
|
(classes ||= []) << 'right' if val.is_a?(Numeric) && !bt
|
|
@@ -255,161 +205,14 @@ module Brick::Rails::FormTags
|
|
|
255
205
|
out << '</tr>'
|
|
256
206
|
row_count += 1
|
|
257
207
|
end
|
|
258
|
-
if rel && (total_row_count = rel.fetch(:rowcount, nil))
|
|
259
|
-
total_row_count = total_row_count > row_count ? " (out of #{total_row_count})" : nil
|
|
260
|
-
end
|
|
261
208
|
out << " </tbody>
|
|
262
209
|
</table>
|
|
263
|
-
<script>
|
|
264
|
-
var rowCount = document.getElementById(\"rowCount\");
|
|
265
|
-
if (rowCount) rowCount.innerHTML = \"#{pluralize(row_count, "row")}#{total_row_count} \";
|
|
266
|
-
</script>
|
|
267
|
-
"
|
|
268
|
-
|
|
269
|
-
# Javascript for brick_grid
|
|
270
|
-
(@_brick_javascripts ||= {})[:grid_scripts] = "
|
|
271
|
-
var #{table_name}HtColumns;
|
|
272
|
-
|
|
273
|
-
// Snag first TR for sticky header
|
|
274
|
-
var grid = document.getElementById(\"#{table_name}\");
|
|
275
|
-
#{table_name}HtColumns = grid && [grid.getElementsByTagName(\"TR\")[0]];
|
|
276
|
-
var headerTop = document.getElementById(\"headerTop\");
|
|
277
|
-
var headerCols;
|
|
278
|
-
if (grid) {
|
|
279
|
-
// COLUMN HEADER AND TABLE CELL HIGHLIGHTING
|
|
280
|
-
var gridHighHeader = null,
|
|
281
|
-
gridHighCell = null;
|
|
282
|
-
grid.addEventListener(\"mouseenter\", gridMove);
|
|
283
|
-
grid.addEventListener(\"mousemove\", gridMove);
|
|
284
|
-
grid.addEventListener(\"mouseleave\", function (evt) {
|
|
285
|
-
if (gridHighCell) gridHighCell.classList.remove(\"highlight\");
|
|
286
|
-
gridHighCell = null;
|
|
287
|
-
if (gridHighHeader) gridHighHeader.classList.remove(\"highlight\");
|
|
288
|
-
gridHighHeader = null;
|
|
289
|
-
});
|
|
290
|
-
function gridMove(evt) {
|
|
291
|
-
var lastHighCell = gridHighCell;
|
|
292
|
-
gridHighCell = document.elementFromPoint(evt.x, evt.y);
|
|
293
|
-
while (gridHighCell && gridHighCell.tagName !== \"TD\" && gridHighCell.tagName !== \"TH\")
|
|
294
|
-
gridHighCell = gridHighCell.parentElement;
|
|
295
|
-
if (gridHighCell) {
|
|
296
|
-
if (lastHighCell !== gridHighCell) {
|
|
297
|
-
gridHighCell.classList.add(\"highlight\");
|
|
298
|
-
if (lastHighCell) lastHighCell.classList.remove(\"highlight\");
|
|
299
|
-
}
|
|
300
|
-
var lastHighHeader = gridHighHeader;
|
|
301
|
-
if ((gridHighHeader = headerCols[gridHighCell.cellIndex]) && lastHighHeader !== gridHighHeader) {
|
|
302
|
-
if (gridHighHeader) gridHighHeader.classList.add(\"highlight\");
|
|
303
|
-
if (lastHighHeader) lastHighHeader.classList.remove(\"highlight\");
|
|
304
|
-
}
|
|
305
|
-
}
|
|
306
|
-
}
|
|
307
|
-
// // LESS TOUCHY NAVIGATION BACK OR FORWARD IN HISTORY WHEN USING MOUSE WHEEL
|
|
308
|
-
// grid.addEventListener(\"wheel\", function (evt) {
|
|
309
|
-
// grid.scrollLeft += evt.deltaX;
|
|
310
|
-
// document.body.scrollTop += (evt.deltaY * 0.6);
|
|
311
|
-
// evt.preventDefault();
|
|
312
|
-
// return false;
|
|
313
|
-
// });
|
|
314
|
-
}
|
|
315
|
-
function setHeaderSizes() {
|
|
316
|
-
if (grid.clientWidth > window.outerWidth)
|
|
317
|
-
document.getElementById(\"titleBox\").style.width = grid.clientWidth;
|
|
318
|
-
// console.log(\"start\");
|
|
319
|
-
// See if the headerTop is already populated
|
|
320
|
-
// %%% Grab the TRs from headerTop, clear it out, do this stuff, add them back
|
|
321
|
-
headerTop.innerHTML = \"\"; // %%% Would love to not have to clear it out like this every time! (Currently doing this to support resize events.)
|
|
322
|
-
var isEmpty = headerTop.childElementCount === 0;
|
|
323
|
-
var numFixed = parseInt(grid.getAttribute(\"x-num-frozen\")) || 0;
|
|
324
|
-
var fixedColLefts = [0];
|
|
325
|
-
|
|
326
|
-
// Set up proper sizings of sticky column header
|
|
327
|
-
var node;
|
|
328
|
-
for (var j = 0; j < #{table_name}HtColumns.length; ++j) {
|
|
329
|
-
var row = #{table_name}HtColumns[j];
|
|
330
|
-
var tr = isEmpty ? document.createElement(\"TR\") : headerTop.childNodes[j];
|
|
331
|
-
tr.innerHTML = row.innerHTML.trim();
|
|
332
|
-
var curLeft = 0.0;
|
|
333
|
-
// Match up widths from the original column headers
|
|
334
|
-
for (var i = 0; i < row.childNodes.length; ++i) {
|
|
335
|
-
node = row.childNodes[i];
|
|
336
|
-
if (node.nodeType === 1) {
|
|
337
|
-
var th = tr.childNodes[i];
|
|
338
|
-
th.style.minWidth = th.style.maxWidth = getComputedStyle(node).width;
|
|
339
|
-
// Add \"left: __px\" style to the fixed-width column THs
|
|
340
|
-
if (i <= numFixed) {
|
|
341
|
-
th.style.position = \"sticky\";
|
|
342
|
-
th.style.backgroundColor = \"#008061\";
|
|
343
|
-
th.style.zIndex = \"1\";
|
|
344
|
-
th.style.left = curLeft + \"px\";
|
|
345
|
-
fixedColLefts.push(curLeft += node.clientWidth);
|
|
346
|
-
}
|
|
347
|
-
if (#{pk&.present? ? 'i > 0' : 'true'}) {
|
|
348
|
-
// Add <span> at the end
|
|
349
|
-
var span = document.createElement(\"SPAN\");
|
|
350
|
-
span.className = \"exclude\";
|
|
351
|
-
span.innerHTML = \"X\";
|
|
352
|
-
span.addEventListener(\"click\", function (e) {
|
|
353
|
-
e.stopPropagation();
|
|
354
|
-
doFetch(\"POST\", {_brick_exclude: this.parentElement.getAttribute(\"x-order\")});
|
|
355
|
-
});
|
|
356
|
-
th.appendChild(span);
|
|
357
|
-
}
|
|
358
|
-
}
|
|
359
|
-
}
|
|
360
|
-
headerCols = tr.childNodes;
|
|
361
|
-
if (isEmpty) headerTop.appendChild(tr);
|
|
362
|
-
}
|
|
363
|
-
// Add \"left: __px\" style to all fixed-width column TDs
|
|
364
|
-
[...grid.children[1].children].forEach(function (row) {
|
|
365
|
-
for (var j = 1; j <= numFixed; ++j) {
|
|
366
|
-
row.children[j].style.left = fixedColLefts[j] + 'px';
|
|
367
|
-
}
|
|
368
|
-
});
|
|
369
|
-
grid.style.marginTop = \"-\" + getComputedStyle(headerTop).height;
|
|
370
|
-
// console.log(\"end\");
|
|
371
|
-
}
|
|
372
|
-
|
|
373
|
-
if (headerTop) {
|
|
374
|
-
onImagesLoaded(function() {
|
|
375
|
-
setHeaderSizes();
|
|
376
|
-
});
|
|
377
|
-
window.addEventListener(\"resize\", function(event) {
|
|
378
|
-
setHeaderSizes();
|
|
379
|
-
}, true);#{
|
|
380
|
-
if !klass.is_view? && respond_to?(new_path_name = "new_#{klass._brick_index(:singular)}_path")
|
|
381
|
-
"
|
|
382
|
-
var headerButtonBox = document.getElementById(\"headerButtonBox\");
|
|
383
|
-
if (headerButtonBox) {
|
|
384
|
-
var addNew = document.createElement(\"A\");
|
|
385
|
-
addNew.id = \"addNew\";
|
|
386
|
-
addNew.href = \"#{send(new_path_name)}\";
|
|
387
|
-
addNew.title = \"New #{table_name.singularize}\";
|
|
388
|
-
addNew.innerHTML = '<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\"><path fill=\"#fff\" d=\"M24 10h-10v-10h-4v10h-10v4h10v10h4v-10h10z\"/></svg>';
|
|
389
|
-
headerButtonBox.append(addNew);
|
|
390
|
-
}
|
|
391
|
-
"
|
|
392
|
-
end}
|
|
393
|
-
}
|
|
394
|
-
|
|
395
|
-
function onImagesLoaded(event) {
|
|
396
|
-
var images = document.getElementsByTagName(\"IMG\");
|
|
397
|
-
var numLoaded = images.length;
|
|
398
|
-
for (var i = 0; i < images.length; ++i) {
|
|
399
|
-
if (images[i].complete)
|
|
400
|
-
--numLoaded;
|
|
401
|
-
else {
|
|
402
|
-
images[i].addEventListener(\"load\", function() {
|
|
403
|
-
if (--numLoaded <= 0)
|
|
404
|
-
event();
|
|
405
|
-
});
|
|
406
|
-
}
|
|
407
|
-
}
|
|
408
|
-
if (numLoaded <= 0)
|
|
409
|
-
event();
|
|
410
|
-
}
|
|
411
210
|
"
|
|
211
|
+
if rel && (total_row_count = rel.fetch(:rowcount, nil))
|
|
212
|
+
total_row_count = total_row_count > row_count ? " (out of #{total_row_count})" : nil
|
|
213
|
+
end
|
|
412
214
|
|
|
215
|
+
set_grid_javascript(klass, pk, show_new_button, row_count, total_row_count)
|
|
413
216
|
out.html_safe
|
|
414
217
|
end # brick_grid
|
|
415
218
|
|
|
@@ -418,7 +221,7 @@ function onImagesLoaded(event) {
|
|
|
418
221
|
def brick_form_for(obj, options = {}, model = obj.class, bts = {}, pk = (obj.class.primary_key || []))
|
|
419
222
|
pk = [pk] unless pk.is_a?(Array)
|
|
420
223
|
pk.map!(&:to_s)
|
|
421
|
-
form_for(obj.becomes(model), options) do |f|
|
|
224
|
+
form_for(obj.becomes(model.base_class), options) do |f|
|
|
422
225
|
out = +'<table class="shadow">'
|
|
423
226
|
has_fields = false
|
|
424
227
|
# If it's a new record, set any default polymorphic types
|
|
@@ -525,28 +328,37 @@ function onImagesLoaded(event) {
|
|
|
525
328
|
|
|
526
329
|
# ------------------------------------------
|
|
527
330
|
# Our cool N:M checkbox constellation editor
|
|
528
|
-
def brick_constellation(relation = nil, options = {}, x_axis: nil, y_axis: nil, bt_descrip: nil, bts: {}
|
|
331
|
+
def brick_constellation(relation = nil, options = {}, x_axis: nil, y_axis: nil, bt_descrip: nil, bts: {},
|
|
332
|
+
show_header: nil, show_erd_button: nil, show_in_app_button: nil, show_new_button: nil, show_avo_button: nil, show_aa_button: nil)
|
|
333
|
+
relation ||= (instance_variable_get("@#{controller_name}".to_sym) || _brick_resource_from_iv)
|
|
334
|
+
klass = relation.klass
|
|
529
335
|
x_axis, x_list, y_axis, y_list, existing = _n_m_prep(relation, x_axis, y_axis)
|
|
530
336
|
|
|
337
|
+
out = +''
|
|
338
|
+
rel = ::Brick.relations&.fetch(relation.table_name, nil)
|
|
339
|
+
if show_header != false
|
|
340
|
+
out << brick_header(rel, klass, false, show_erd_button, show_in_app_button, show_avo_button, show_aa_button)
|
|
341
|
+
end
|
|
342
|
+
|
|
531
343
|
# HTML for constellation
|
|
532
344
|
prefix = options[:prefix]
|
|
533
|
-
out
|
|
345
|
+
out << "<form action=\"#{"#{prefix}/" if prefix}brick_constellation\">
|
|
534
346
|
<table id=\"#{table_name = relation.table_name.split('.').last}\" class=\"shadow\">
|
|
535
|
-
<thead><tr><td
|
|
536
|
-
"
|
|
347
|
+
<thead><tr><td class=\"brick-note\">Checkbox changes are saved immediately</td>"
|
|
537
348
|
# Header row with X axis values
|
|
349
|
+
# (In order for grid highlighting to function, these TH elements must have no whitespace between them.
|
|
350
|
+
# In this way the Javascript headerCols array will be set properly.
|
|
538
351
|
x_list.each do |x_item|
|
|
539
|
-
out << "
|
|
540
|
-
"
|
|
352
|
+
out << "<th>#{x_item.first}</th>"
|
|
541
353
|
end
|
|
542
|
-
out << "
|
|
354
|
+
out << "</tr></thead>
|
|
543
355
|
<tbody>
|
|
544
356
|
"
|
|
545
|
-
obj_path = "#{
|
|
357
|
+
obj_path = "#{klass._brick_index(:singular)}_path".to_sym
|
|
546
358
|
link_arrow = link_to('⇛', send(obj_path, '____'), { class: 'big-arrow' })
|
|
547
|
-
pk_as_array =
|
|
359
|
+
pk_as_array = klass._pk_as_array
|
|
548
360
|
y_list.each do |y_item|
|
|
549
|
-
out << " <tr><th>#{y_item.first}</th>
|
|
361
|
+
out << " <tr><th class=\"col-sticky\">#{y_item.first}</th>
|
|
550
362
|
"
|
|
551
363
|
x_list.each do |x_item|
|
|
552
364
|
checked = existing.find { |e| e[1] == x_item.last && e[2] == y_item.last }
|
|
@@ -570,7 +382,7 @@ function onImagesLoaded(event) {
|
|
|
570
382
|
_this = this;
|
|
571
383
|
if (this.checked) {
|
|
572
384
|
var ids = this.value.split(\"_\");
|
|
573
|
-
doFetch(\"POST\", {modelName: \"#{
|
|
385
|
+
doFetch(\"POST\", {modelName: \"#{klass.name}\",
|
|
574
386
|
args: [#{x_axis[1].inspect}, ids[0], #{y_axis[1].inspect}, ids[1]],
|
|
575
387
|
_brick_action: \"/#{prefix}brick_associate\"},
|
|
576
388
|
function (p) { // If it returns successfully, create an <a> element
|
|
@@ -586,7 +398,7 @@ function onImagesLoaded(event) {
|
|
|
586
398
|
}
|
|
587
399
|
);
|
|
588
400
|
} else if (nextSib = this.nextElementSibling) {
|
|
589
|
-
doFetch(\"DELETE\", {modelName: \"#{
|
|
401
|
+
doFetch(\"DELETE\", {modelName: \"#{klass.name}\",
|
|
590
402
|
id: this.getAttribute(\"x-id\"),
|
|
591
403
|
_brick_action: \"/#{prefix}brick_associate\"},
|
|
592
404
|
function (p) { // If it returns successfully, remove the an <a> element
|
|
@@ -599,6 +411,7 @@ function onImagesLoaded(event) {
|
|
|
599
411
|
</script>
|
|
600
412
|
</form>
|
|
601
413
|
"
|
|
414
|
+
set_grid_javascript(klass, pk_as_array, false)
|
|
602
415
|
out.html_safe
|
|
603
416
|
end # brick_constellation
|
|
604
417
|
|
|
@@ -606,7 +419,9 @@ function onImagesLoaded(event) {
|
|
|
606
419
|
# Our cool N:M bezier visualisation
|
|
607
420
|
# (...... work in progress .......)
|
|
608
421
|
def brick_bezier(relation = nil, options = {}, x_axis: nil, y_axis: nil, bt_descrip: nil, bts: {})
|
|
422
|
+
relation ||= (instance_variable_get("@#{controller_name}".to_sym) || _brick_resource_from_iv)
|
|
609
423
|
x_axis, x_list, y_axis, y_list, existing = _n_m_prep(relation, x_axis, y_axis)
|
|
424
|
+
rel = ::Brick.relations&.fetch(relation.table_name, nil)
|
|
610
425
|
# HTML for constellation
|
|
611
426
|
# X axis (List on left side)
|
|
612
427
|
out = +"<table id=\"#{x_axis.first}\" class=\"shadow\">
|
|
@@ -629,13 +444,222 @@ function onImagesLoaded(event) {
|
|
|
629
444
|
out.html_safe
|
|
630
445
|
end # brick_bezier
|
|
631
446
|
|
|
447
|
+
# ---------------------------------------------------------------------------------------------------------
|
|
448
|
+
def brick_header(rel, klass, show_row_count, show_erd_button, show_in_app_button, show_avo_button, show_aa_button)
|
|
449
|
+
out = +"<div id=\"headerTopContainer\"><table id=\"headerTop\"></table>
|
|
450
|
+
<div id=\"headerTopAddNew\">
|
|
451
|
+
<div id=\"headerButtonBox\">
|
|
452
|
+
"
|
|
453
|
+
unless show_row_count == false
|
|
454
|
+
out << " <div id=\"rowCount\"></div>
|
|
455
|
+
"
|
|
456
|
+
end
|
|
457
|
+
unless show_erd_button == false
|
|
458
|
+
out << " <div id=\"imgErd\" title=\"Show ERD\"></div>
|
|
459
|
+
"
|
|
460
|
+
end
|
|
461
|
+
if rel && show_in_app_button != false && (in_app = rel.fetch(:existing, nil)&.fetch(:index, nil))
|
|
462
|
+
begin
|
|
463
|
+
in_app = send("#{in_app}_path") if in_app.is_a?(Symbol)
|
|
464
|
+
out << " <td title=\"Show in app\">#{link_to(::Brick::Rails::IN_APP.html_safe, in_app)}</td>
|
|
465
|
+
"
|
|
466
|
+
rescue ActionController::UrlGenerationError # Avoid snags like "No route matches {:action=>"index", :controller=>"categories/products"}, missing required keys: [:category_id]"
|
|
467
|
+
end
|
|
468
|
+
end
|
|
469
|
+
if show_avo_button != false && Object.const_defined?('Avo') && ::Avo.respond_to?(:railtie_namespace) && klass.name.exclude?('::')
|
|
470
|
+
out << "
|
|
471
|
+
<td>#{link_to_brick(
|
|
472
|
+
::Brick::Rails::AVO_SVG.html_safe,
|
|
473
|
+
{ index_proc: Proc.new do |_avo_model, relation|
|
|
474
|
+
path_helper = "resources_#{relation.fetch(:auto_prefixed_schema, nil)}#{klass.model_name.route_key}_path".to_sym
|
|
475
|
+
::Avo.railtie_routes_url_helpers.send(path_helper) if ::Avo.railtie_routes_url_helpers.respond_to?(path_helper)
|
|
476
|
+
end,
|
|
477
|
+
title: "#{klass.name} in Avo" }
|
|
478
|
+
)}</td>
|
|
479
|
+
"
|
|
480
|
+
end
|
|
481
|
+
|
|
482
|
+
if show_aa_button != false && Object.const_defined?('ActiveAdmin')
|
|
483
|
+
ActiveAdmin.application.namespaces.names.each do |ns|
|
|
484
|
+
out << "
|
|
485
|
+
<td>#{link_to_brick(
|
|
486
|
+
::Brick::Rails::AA_PNG.html_safe,
|
|
487
|
+
{ index_proc: Proc.new do |aa_model, relation|
|
|
488
|
+
path_helper = "#{ns}_#{relation.fetch(:auto_prefixed_schema, nil)}#{aa_model.model_name.route_key}_path".to_sym
|
|
489
|
+
send(path_helper) if respond_to?(path_helper)
|
|
490
|
+
end,
|
|
491
|
+
title: "#{rel[:class_name]} in ActiveAdmin" }
|
|
492
|
+
)}</td>
|
|
493
|
+
"
|
|
494
|
+
end
|
|
495
|
+
end
|
|
496
|
+
out << " </div>
|
|
497
|
+
</div>
|
|
498
|
+
</div>
|
|
499
|
+
"
|
|
500
|
+
out
|
|
501
|
+
end # brick_header
|
|
502
|
+
|
|
503
|
+
# -----------------------------------------------------------------------------------------------
|
|
504
|
+
def set_grid_javascript(klass, pk, show_new_button = nil, row_count = nil, total_row_count = nil)
|
|
505
|
+
table_name = klass.table_name.split('.').last
|
|
506
|
+
|
|
507
|
+
# Javascript for brick_grid and brick_constellation
|
|
508
|
+
grid_scripts = (@_brick_javascripts ||= {})[:grid_scripts] = +''
|
|
509
|
+
|
|
510
|
+
grid_scripts << "
|
|
511
|
+
// Plunk the row count in now that we know it
|
|
512
|
+
var rowCount = document.getElementById(\"rowCount\");
|
|
513
|
+
if (rowCount) rowCount.innerHTML = \"#{pluralize(row_count, "row")}#{total_row_count} \";
|
|
514
|
+
var #{table_name}HtColumns;
|
|
515
|
+
" unless row_count.nil?
|
|
516
|
+
|
|
517
|
+
grid_scripts << "
|
|
518
|
+
// Snag first TR for sticky header
|
|
519
|
+
var grid = document.getElementById(\"#{table_name}\");
|
|
520
|
+
#{table_name}HtColumns = grid && [grid.getElementsByTagName(\"TR\")[0]];
|
|
521
|
+
var headerTop = document.getElementById(\"headerTop\");
|
|
522
|
+
var headerCols;
|
|
523
|
+
if (grid) {
|
|
524
|
+
// COLUMN HEADER AND TABLE CELL HIGHLIGHTING
|
|
525
|
+
var gridHighHeader = null,
|
|
526
|
+
gridHighCell = null;
|
|
527
|
+
grid.addEventListener(\"mouseenter\", gridMove);
|
|
528
|
+
grid.addEventListener(\"mousemove\", gridMove);
|
|
529
|
+
grid.addEventListener(\"mouseleave\", function (evt) {
|
|
530
|
+
if (gridHighCell) gridHighCell.classList.remove(\"highlight\");
|
|
531
|
+
gridHighCell = null;
|
|
532
|
+
if (gridHighHeader) gridHighHeader.classList.remove(\"highlight\");
|
|
533
|
+
gridHighHeader = null;
|
|
534
|
+
});
|
|
535
|
+
function gridMove(evt) {
|
|
536
|
+
var lastHighCell = gridHighCell;
|
|
537
|
+
gridHighCell = document.elementFromPoint(evt.x, evt.y);
|
|
538
|
+
while (gridHighCell && gridHighCell.tagName !== \"TD\" && gridHighCell.tagName !== \"TH\")
|
|
539
|
+
gridHighCell = gridHighCell.parentElement;
|
|
540
|
+
if (gridHighCell) {
|
|
541
|
+
if (lastHighCell !== gridHighCell) {
|
|
542
|
+
gridHighCell.classList.add(\"highlight\");
|
|
543
|
+
if (lastHighCell) lastHighCell.classList.remove(\"highlight\");
|
|
544
|
+
}
|
|
545
|
+
var lastHighHeader = gridHighHeader;
|
|
546
|
+
if ((gridHighHeader = headerCols[gridHighCell.cellIndex]) && lastHighHeader !== gridHighHeader) {
|
|
547
|
+
if (gridHighHeader) gridHighHeader.classList.add(\"highlight\");
|
|
548
|
+
if (lastHighHeader) lastHighHeader.classList.remove(\"highlight\");
|
|
549
|
+
}
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
// // Less touchy navigation back or forward in history when using mouse wheel
|
|
553
|
+
// grid.addEventListener(\"wheel\", function (evt) {
|
|
554
|
+
// grid.scrollLeft += evt.deltaX;
|
|
555
|
+
// document.body.scrollTop += (evt.deltaY * 0.6);
|
|
556
|
+
// evt.preventDefault();
|
|
557
|
+
// return false;
|
|
558
|
+
// });
|
|
559
|
+
}
|
|
560
|
+
function setHeaderSizes() {
|
|
561
|
+
if (grid.clientWidth > window.outerWidth)
|
|
562
|
+
document.getElementById(\"titleBox\").style.width = grid.clientWidth;
|
|
563
|
+
// console.log(\"start\");
|
|
564
|
+
// See if the headerTop is already populated
|
|
565
|
+
// %%% Grab the TRs from headerTop, clear it out, do this stuff, add them back
|
|
566
|
+
headerTop.innerHTML = \"\"; // %%% Would love to not have to clear it out like this every time! (Currently doing this to support resize events.)
|
|
567
|
+
var isEmpty = headerTop.childElementCount === 0;
|
|
568
|
+
var numFixed = parseInt(grid.getAttribute(\"x-num-frozen\")) || 0;
|
|
569
|
+
var fixedColLefts = [0];
|
|
570
|
+
|
|
571
|
+
// Set up proper sizings of sticky column header
|
|
572
|
+
var node;
|
|
573
|
+
for (var j = 0; j < #{table_name}HtColumns.length; ++j) {
|
|
574
|
+
var row = #{table_name}HtColumns[j];
|
|
575
|
+
var tr = isEmpty ? document.createElement(\"TR\") : headerTop.childNodes[j];
|
|
576
|
+
tr.innerHTML = row.innerHTML.trim();
|
|
577
|
+
var curLeft = 0.0;
|
|
578
|
+
// Match up widths from the original column headers
|
|
579
|
+
for (var i = 0; i < row.childNodes.length; ++i) {
|
|
580
|
+
node = row.childNodes[i];
|
|
581
|
+
if (node.nodeType === 1) {
|
|
582
|
+
var th = tr.childNodes[i];
|
|
583
|
+
th.style.minWidth = th.style.maxWidth = getComputedStyle(node).width;
|
|
584
|
+
// Add \"left: __px\" style to the fixed-width column THs
|
|
585
|
+
if (i <= numFixed) {
|
|
586
|
+
th.style.position = \"sticky\";
|
|
587
|
+
th.style.backgroundColor = \"#008061\";
|
|
588
|
+
th.style.zIndex = \"1\";
|
|
589
|
+
th.style.left = curLeft + \"px\";
|
|
590
|
+
fixedColLefts.push(curLeft += node.clientWidth);
|
|
591
|
+
}
|
|
592
|
+
if (#{pk&.present? ? 'i > 0' : 'true'}) {
|
|
593
|
+
// Add <span> at the end
|
|
594
|
+
var span = document.createElement(\"SPAN\");
|
|
595
|
+
span.className = \"exclude\";
|
|
596
|
+
span.innerHTML = \"X\";
|
|
597
|
+
span.addEventListener(\"click\", function (e) {
|
|
598
|
+
e.stopPropagation();
|
|
599
|
+
doFetch(\"POST\", {_brick_exclude: this.parentElement.getAttribute(\"x-order\")});
|
|
600
|
+
});
|
|
601
|
+
th.appendChild(span);
|
|
602
|
+
}
|
|
603
|
+
}
|
|
604
|
+
}
|
|
605
|
+
headerCols = tr.childNodes;
|
|
606
|
+
if (isEmpty) headerTop.appendChild(tr);
|
|
607
|
+
}
|
|
608
|
+
// Add \"left: __px\" style to all fixed-width column TDs
|
|
609
|
+
[...grid.children[1].children].forEach(function (row) {
|
|
610
|
+
for (var j = 1; j <= numFixed; ++j) {
|
|
611
|
+
row.children[j].style.left = fixedColLefts[j] + 'px';
|
|
612
|
+
}
|
|
613
|
+
});
|
|
614
|
+
grid.style.marginTop = \"-\" + getComputedStyle(headerTop).height;
|
|
615
|
+
// console.log(\"end\");
|
|
616
|
+
}
|
|
617
|
+
|
|
618
|
+
if (headerTop) {
|
|
619
|
+
onImagesLoaded(function() {
|
|
620
|
+
setHeaderSizes();
|
|
621
|
+
});
|
|
622
|
+
window.addEventListener(\"resize\", function(event) {
|
|
623
|
+
setHeaderSizes();
|
|
624
|
+
}, true);#{
|
|
625
|
+
"
|
|
626
|
+
var headerButtonBox = document.getElementById(\"headerButtonBox\");
|
|
627
|
+
if (headerButtonBox) {
|
|
628
|
+
var addNew = document.createElement(\"A\");
|
|
629
|
+
addNew.id = \"addNew\";
|
|
630
|
+
addNew.href = \"#{link_to_brick(klass, new: true, path_only: true)}\";
|
|
631
|
+
addNew.title = \"New #{table_name.singularize}\";
|
|
632
|
+
addNew.innerHTML = '<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\"><path fill=\"#fff\" d=\"M24 10h-10v-10h-4v10h-10v4h10v10h4v-10h10z\"/></svg>';
|
|
633
|
+
headerButtonBox.append(addNew);
|
|
634
|
+
}
|
|
635
|
+
" unless klass.is_view? || show_new_button == false
|
|
636
|
+
}
|
|
637
|
+
}
|
|
638
|
+
|
|
639
|
+
function onImagesLoaded(event) {
|
|
640
|
+
var images = document.getElementsByTagName(\"IMG\");
|
|
641
|
+
var numLoaded = images.length;
|
|
642
|
+
for (var i = 0; i < images.length; ++i) {
|
|
643
|
+
if (images[i].complete)
|
|
644
|
+
--numLoaded;
|
|
645
|
+
else {
|
|
646
|
+
images[i].addEventListener(\"load\", function() {
|
|
647
|
+
if (--numLoaded <= 0)
|
|
648
|
+
event();
|
|
649
|
+
});
|
|
650
|
+
}
|
|
651
|
+
}
|
|
652
|
+
if (numLoaded <= 0)
|
|
653
|
+
event();
|
|
654
|
+
}
|
|
655
|
+
"
|
|
656
|
+
end
|
|
657
|
+
|
|
658
|
+
# -------------------------------------
|
|
632
659
|
def _n_m_prep(relation, x_axis, y_axis)
|
|
633
|
-
relation ||= (instance_variable_get("@#{controller_name}".to_sym) || _brick_resource_from_iv)
|
|
634
660
|
# Just find the first two BT things at this point
|
|
635
661
|
|
|
636
662
|
klass = relation.klass
|
|
637
|
-
rel = ::Brick.relations&.fetch(relation.table_name, nil)
|
|
638
|
-
# fk_assocs = rel[:fks].map { |k, fk| [fk[:assoc_name], fk[:fk]] }
|
|
639
663
|
fk_assocs = klass.reflect_on_all_associations.each_with_object([]) do |assoc, s|
|
|
640
664
|
s << [assoc.name.to_s, assoc.foreign_key, assoc.klass] if assoc.belongs_to?
|
|
641
665
|
end
|
|
@@ -690,8 +714,10 @@ function onImagesLoaded(event) {
|
|
|
690
714
|
kwargs[:visited] = {}
|
|
691
715
|
end
|
|
692
716
|
|
|
693
|
-
|
|
694
|
-
|
|
717
|
+
unless (is_path_only = kwargs.delete(:path_only))
|
|
718
|
+
text = ((args.first.is_a?(String) || args.first.is_a?(Proc)) && args.shift) || args[1]
|
|
719
|
+
text = text.call if text.is_a?(Proc)
|
|
720
|
+
end
|
|
695
721
|
klass_or_obj = ((args.first.is_a?(ActiveRecord::Relation) ||
|
|
696
722
|
args.first.is_a?(ActiveRecord::Base) ||
|
|
697
723
|
args.first.is_a?(Class)) &&
|
|
@@ -739,6 +765,8 @@ function onImagesLoaded(event) {
|
|
|
739
765
|
filter_parts << "#{whr.first}=#{whr.last}" if whr.last && !whr.last.is_a?(Array)
|
|
740
766
|
end
|
|
741
767
|
klass_or_obj = klass_or_obj.klass
|
|
768
|
+
end
|
|
769
|
+
if klass_or_obj.is_a?(Class) && klass_or_obj <= ActiveRecord::Base
|
|
742
770
|
type_col = klass_or_obj.inheritance_column
|
|
743
771
|
if klass_or_obj.column_names.include?(type_col) && klass_or_obj.name != klass_or_obj.base_class.name
|
|
744
772
|
filter_parts << "#{type_col}=#{klass_or_obj.name}"
|
|
@@ -750,11 +778,22 @@ function onImagesLoaded(event) {
|
|
|
750
778
|
relation = ::Brick.relations.fetch(rel_name || klass.table_name, nil)
|
|
751
779
|
if (klass_or_obj&.is_a?(Class) && klass_or_obj < ActiveRecord::Base) ||
|
|
752
780
|
(klass_or_obj&.is_a?(ActiveRecord::Base) && klass_or_obj.new_record? && (klass_or_obj = klass_or_obj.class))
|
|
753
|
-
|
|
754
|
-
|
|
781
|
+
if kwargs.delete(:new)
|
|
782
|
+
path = (proc = kwargs[:new_proc]) ? proc.call(klass_or_obj, relation) : "#{app_routes.path_for(controller: klass_or_obj.base_class._brick_index(:singular, '/', relation, true), action: :new)}#{filter}"
|
|
783
|
+
return path if is_path_only
|
|
784
|
+
|
|
785
|
+
lt_args = [text || "New #{klass_or_obj.name}", path]
|
|
786
|
+
else
|
|
787
|
+
path = (proc = kwargs[:index_proc]) ? proc.call(klass_or_obj, relation) : "#{app_routes.path_for(controller: klass_or_obj.base_class._brick_index(nil, '/', relation, true), action: :index)}#{filter}"
|
|
788
|
+
return path if is_path_only
|
|
789
|
+
|
|
790
|
+
lt_args = [text || "Index for #{klass_or_obj.name.pluralize}", path]
|
|
791
|
+
end
|
|
755
792
|
else
|
|
756
793
|
# If there are multiple incoming parameters then last one is probably the actual ID, and first few might be some nested tree of stuff leading up to it
|
|
757
794
|
path = (proc = kwargs[:show_proc]) ? proc.call(klass_or_obj, relation) : "#{app_routes.path_for(controller: klass_or_obj.class.base_class._brick_index(nil, '/', relation, true), action: :show, id: klass_or_obj)}#{filter}"
|
|
795
|
+
return path if is_path_only
|
|
796
|
+
|
|
758
797
|
lt_args = [text || "Show this #{klass_or_obj.class.name}", path]
|
|
759
798
|
end
|
|
760
799
|
kwargs.delete(:visited)
|
data/lib/brick/reflect_tables.rb
CHANGED
|
@@ -341,7 +341,7 @@ ORDER BY 1, 2, c.internal_column_id, acc.position"
|
|
|
341
341
|
fk[4].downcase! if fk[4] =~ /^[A-Z0-9_]+$/
|
|
342
342
|
fk[2] = connection.send(:oracle_downcase, fk[2])
|
|
343
343
|
end
|
|
344
|
-
::Brick._add_bt_and_hm(fk, relations)
|
|
344
|
+
::Brick._add_bt_and_hm(fk, relations, nil, nil)
|
|
345
345
|
end
|
|
346
346
|
kcus = nil # Allow this large item to be garbage collected
|
|
347
347
|
end
|
data/lib/brick/version_number.rb
CHANGED
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: brick
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.0.
|
|
4
|
+
version: 1.0.214
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Lorin Thwaits
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2024-04-
|
|
11
|
+
date: 2024-04-06 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: activerecord
|