File Coverage

blib/lib/RapidApp/Module/DatStor/Column.pm
Criterion Covered Total %
statement 176 276 63.7
branch 110 222 49.5
condition 32 44 72.7
subroutine 46 78 58.9
pod 0 68 0.0
total 364 688 52.9


line stmt bran cond sub pod time code
1             package RapidApp::Module::DatStor::Column;
2              
3             # ** This class used to be RapidApp::Column **
4              
5 6     6   658 use strict;
  6         12  
  6         148  
6 6     6   26 use warnings;
  6         12  
  6         159  
7              
8 6     6   28 use RapidApp::Util qw(:all);
  6         10  
  6         14257  
9              
10             our @gridColParams= qw(
11             name sortable hidden header dataIndex width editor menuDisabled tpl xtype
12             id no_column no_multifilter no_quick_search extra_meta_data css listeners
13             filter field_cnf rel_combo_field_cnf field_cmp_config render_fn renderer
14             allow_add allow_edit allow_view query_id_use_column query_search_use_column
15             trueText falseText menu_select_editor render_column multifilter_type summary_functions
16             no_summary allow_batchedit format align is_nullable documentation
17             );
18             our @attrs= ( @gridColParams, qw(
19             data_type required_fetch_columns read_raw_munger update_munger
20             field_readonly field_readonly_config field_config no_fetch broad_data_type
21             quick_search_exact_only enum_value_hash search_operator_strf
22             ) );
23             our %triggers= (
24             render_fn => '_set_render_fn',
25             renderer => '_set_renderer',
26             menu_select_editor => '_set_menu_select_editor',
27             );
28              
29              
30             eval('sub '.$_.' {'
31             .(exists($triggers{$_})
32             ? 'if (scalar @_ > 1) { my $old= $_[0]->{'.$_.'}; $_[0]->{'.$_.'} = $_[1]; $_[0]->'.$triggers{$_}.'($_[0]->{'.$_.'}, $old); }'
33             : '$_[0]->{'.$_.'} = $_[1] if scalar @_ > 1;'
34             ).'$_[0]->{'.$_.'}
35 10 50   10 0 47 }') for @attrs;
  10 100   1698 0 23  
  1698 50   167 0 4745  
  1698 100   1836 0 3050  
  167 100   996 0 604  
  167 50   781 0 341  
  1836 0   0 0 4902  
  1836 0   0 0 3521  
  996 0   0 0 2733  
  996 0   0 0 1880  
  781 50   781 0 2337  
  781 50   1 0 1381  
  0 0   0 0 0  
  0 0   0 0 0  
  0 0   0 0 0  
  0 0   0 0 0  
  0 0   0 0 0  
  0 0   0 0 0  
  0 0   0 0 0  
  0 0   0 0 0  
  781 50   10 0 2480  
  781 100   768 0 1384  
  1 50   147 0 13  
  1 0   0 0 4  
  0 50   781 0 0  
  0 0   0 0 0  
  0 0   0 0 0  
  0 50   1 0 0  
  0 50   439 0 0  
  0 50   781 0 0  
  0 100   4215 0 0  
  0 50   2 0 0  
  0 50   160 0 0  
  0 50   295 0 0  
  0 50   1 0 0  
  0 50   82 0 0  
  0 50   82 0 0  
  0 0   0 0 0  
  0 100   1238 0 0  
  0 50   63 0 0  
  10 50   82 0 45  
  10 0   0 0 22  
  768 50   781 0 2317  
  768 100   237 0 1514  
  147 0   0 0 504  
  147 50   4 0 337  
  0 50   781 0 0  
  0 50   781 0 0  
  781 0   0 0 2333  
  781 50   1070 0 1355  
  0 50   511 0 0  
  0 50   791 0 0  
  0         0  
  0         0  
  1         5  
  1         3  
  1         3  
  1         6  
  1         3  
  439         1396  
  439         790  
  781         2549  
  781         1433  
  4215         9390  
  4215         21027  
  2         12  
  2         6  
  160         538  
  160         344  
  295         942  
  295         557  
  1         8  
  1         3  
  82         337  
  82         161  
  82         285  
  82         165  
  0         0  
  0         0  
  1238         2919  
  1238         7255  
  63         243  
  63         120  
  82         321  
  82         178  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  781         1908  
  781         1212  
  781         1561  
  781         1985  
  781         1985  
  237         800  
  237         555  
  0         0  
  0         0  
  4         24  
  4         10  
  781         2330  
  781         1430  
  781         2264  
  781         1317  
  0         0  
  0         0  
  1070         2566  
  1070         2925  
  511         1655  
  511         875  
  791         3404  
  791         1485  
36              
37             our %defaults= (
38             sortable => '\1',
39             hidden => '\0',
40             header => '$self->{name}',
41             dataIndex => '$self->{name}',
42             width => '70',
43             no_column => '\0',
44             no_multifilter => '\0',
45             no_quick_search => '\0',
46             field_readonly => '0',
47             required_fetch_columns => '[]',
48             field_readonly_config => '{}',
49             field_config => '{}',
50             );
51              
52             eval 'sub apply_defaults {
53             my $self= shift;
54 909 50   909 0 1757 '.join(';', map { 'exists $self->{'.$_.'} or $self->{'.$_.'}= '.$defaults{$_} } keys %defaults).'
  909 50       2306  
  909 50       2219  
  909 100       2128  
  909 50       2135  
  909 50       2035  
  909 100       2003  
  909 50       2657  
  909 50       1955  
  909 100       1929  
  909 50       2131  
  909 50       2028  
  909         2541  
55             }';
56              
57              
58              
59              
60             sub _set_render_fn {
61 0     0   0 my ($self,$new,$old) = @_;
62            
63 0         0 die 'render_fn is depricated, please use renderer instead.';
64            
65 0 0       0 return unless ($new);
66            
67             # renderer takes priority over render_fn
68 0 0       0 return if (defined $self->renderer);
69            
70 0         0 $self->xtype('templatecolumn');
71 0         0 $self->tpl('{[' . $new . '(values.' . $self->name . ',values)]}');
72             }
73              
74             sub _set_renderer {
75 781     781   1419 my ($self,$new,$old) = @_;
76 781 50       1845 return unless ($new);
77            
78 781         13349 $self->xtype(undef);
79 781         13274 $self->tpl(undef);
80            
81 781 100 66     6094 return unless (defined $new and not blessed $new);
82 597         1779 $self->{renderer}= jsfunc($new);
83             }
84              
85             sub _set_menu_select_editor {
86 1     1   4 my ($self,$new,$old) = @_;
87 1 50       4 return unless ($new);
88            
89 1         10 my %val_to_disp = ();
90 1         4 my @value_list = ();
91            
92 1         3 foreach my $sel (uniq(@{$new->{selections}})) {
  1         7  
93 2         9 push @value_list, [$sel->{value},$sel->{text},$sel->{iconCls}];
94 2 50 33     14 if(defined $sel->{value} and defined $sel->{text}) {
95 2         7 $val_to_disp{$sel->{value}} = $sel->{text};
96              
97             $val_to_disp{$sel->{value}} = '<div class="with-icon ' . $sel->{iconCls} . '">' . $sel->{text} . '</div>'
98 2 50       10 if($sel->{iconCls});
99            
100             $val_to_disp{$sel->{value}} = '<img src="_ra-rel-mnt_/assets/rapidapp/misc/static/s.gif" class="ra-icon-centered-16x16 ' . $sel->{iconCls} . '">'
101 2 50 33     9 if($sel->{iconCls} and jstrue($new->{render_icon_only}));
102             };
103             }
104            
105 1         3 my $first_val;
106 1 50       3 $first_val = $value_list[0]->[0] if (defined $value_list[0]);
107            
108 1         6 my $mapjs = encode_json(\%val_to_disp);
109            
110 1         88 my $js = 'function(v){' .
111             'var val_map = ' . $mapjs . ';' .
112             'if(typeof val_map[v] !== "undefined") { return val_map[v]; }' .
113             'return v;' .
114             '}';
115            
116 1         4 $self->{renderer} = jsfunc($js,$self->{renderer});
117            
118             # If there is already a 'value' property set in editor save it to preserve it (see below):
119 1 50       24 my $orig_value = ref($self->{editor}) eq 'HASH' ? $self->{editor}->{value} : undef;
120            
121             # Update: removed extra, not-needed check of 'allow_edit' param (fixes Github Issue #35)
122              
123 1   50     5 my $mode = $new->{mode} || 'combo';
124            
125 1 50       21 if($mode eq 'combo') {
    50          
    0          
126             $self->{editor} = {
127 0         0 xtype => 'ra-icon-combo',
128             allowBlank => \0,
129             value_list => \@value_list,
130             };
131             }
132             elsif($mode eq 'menu') {
133            
134             $self->{editor} = {
135 1         8 xtype => 'menu-field',
136             menuOnShow => \1,
137             value_list => \@value_list,
138             value => $first_val,
139             minHeight => 10,
140             minWidth => 10
141             };
142            
143 1   33     26 $self->{editor}->{header} = $new->{header} || $self->header;
144             delete $self->{editor}->{header} unless (
145             defined $self->{editor}->{header} and
146 1 50 33     13 $self->{editor}->{header} ne ''
147             );
148            
149             }
150             elsif($mode eq 'cycle') {
151            
152             $self->{editor} = {
153 0         0 xtype => 'cycle-field',
154             cycleOnShow => \1,
155             value_list => \@value_list,
156             value => $first_val,
157             minHeight => 10,
158             minWidth => 10
159             };
160            
161             }
162             else {
163 0         0 die "menu_select_editor: Invalid mode '$mode' - must be 'combo', 'menu' or 'cycle'"
164             }
165            
166             # restore the original 'value' if it was already defined (see above)
167 1 50       5 $self->{editor}->{value} = $orig_value if (defined $orig_value);
168            
169 1 50       24 $self->{editor}->{width} = $new->{width} if ($new->{width});
170             }
171              
172              
173             our %attrKeySet= map { $_ => 1 } @attrs;
174             our %gridColParamKeySet= map { $_ => 1 } @gridColParams;
175              
176             sub new {
177 909     909 0 11900 my $class= shift;
178 909 100       3043 my $self= bless { (ref($_[0]) eq 'HASH')? %{$_[0]} : @_ }, $class;
  11         46  
179 909 50 33     2472 $self->{renderer} = jsfunc($self->{renderer}) if (defined $self->{renderer} and not blessed $self->{renderer});
180 909         2506 for (keys %$self) {
181 935 50       2119 $attrKeySet{$_} || die("No such attribute: $class\::$_");
182 935         1471 my $t= $triggers{$_};
183 935 50       1991 $t and $self->$t($self->{$_});
184             }
185 909         16608 $self->apply_defaults;
186 909         21581 return $self;
187             }
188              
189             sub apply_attributes {
190 1081     1081 0 1575 my $self = shift;
191 1081 50       5937 my %new = (ref($_[0]) eq 'HASH') ? %{ $_[0] } : @_; # <-- arg as hash or hashref
  0         0  
192            
193             # Ignore attribute names which start with underscore (_) -- backcompat fix for special
194             # flag/keys added in 1.1000 for the "allow_*" refactor
195 1081         3525 delete $new{$_} for (grep { $_ =~ /^\_/ } keys %new);
  9496         14669  
196            
197 1081         2448 foreach my $attr (@attrs) {
198 56212 100       83247 next unless (exists $new{$attr});
199 9496         164816 $self->$attr($new{$attr});
200 9496         15408 delete $new{$attr};
201             }
202            
203             #There should be nothing left over in %new:
204 1081 50       2248 if (scalar(keys %new) > 0) {
205             #die "invalid attributes (" . join(',',keys %new) . ") passed to apply_attributes";
206             #use Data::Dumper;
207 0         0 die "invalid attributes (" . join(',',keys %new) . ") passed to apply_attributes :\n" . Dumper(\%new);
208             }
209            
210             $self->_normalize_allow_add_edit
211 1081         2243 }
212              
213             sub applyIf_attributes {
214 0     0 0 0 my $self = shift;
215 0 0       0 my %new = (ref($_[0]) eq 'HASH') ? %{ $_[0] } : @_; # <-- arg as hash or hashref
  0         0  
216            
217             # Ignore attribute names which start with underscore (_) -- backcompat fix for special
218             # flag/keys added in 1.1000 for the "allow_*" refactor
219 0         0 delete $new{$_} for (grep { $_ =~ /^\_/ } keys %new);
  0         0  
220            
221 0         0 foreach my $attr (@attrs) {
222 0 0       0 next unless (exists $new{$attr});
223 0 0       0 $self->$attr($new{$attr}) unless defined $self->{$attr}; # <-- only set attrs that aren't already set
224 0         0 delete $new{$attr};
225             }
226            
227             #There should be nothing left over in %new:
228 0 0       0 if (scalar(keys %new) > 0) {
229             #die "invalid attributes (" . join(',',keys %new) . ") passed to apply_attributes";
230             #use Data::Dumper;
231 0         0 die "invalid attributes (" . join(',',keys %new) . ") passed to apply_attributes :\n" . Dumper(\%new);
232             }
233            
234             $self->_normalize_allow_add_edit
235 0         0 }
236              
237             ## -----
238             ##
239             ## This just ensures allow_add/allow_edit/allow_view/no_column are always populated, with
240             ## values which are already implied by the existing rules. This just makes it easier to
241             ## check later, avoiding all the defined or not checks, etc
242             ##
243             sub _normalize_allow_add_edit {
244 1081     1081   1551 my $self = shift;
245            
246 1081 100       2535 $self->no_column(${$self->{no_column}}) if (ref $self->{no_column}); # consistent 0/1
  948         16579  
247 1081 100       17160 $self->no_column(0) unless ($self->no_column);
248            
249 1081         2631 $self->_normalize_allow_edit;
250 1081 100       2328 $self->allow_edit(${$self->{allow_edit}}) if (ref $self->{allow_edit});
  654         11630  
251              
252 1081         2423 $self->_normalize_allow_add;
253 1081 100       2183 $self->allow_add(${$self->{allow_add}}) if (ref $self->{allow_add});
  715         12638  
254            
255 1081         2400 $self->_normalize_allow_view;
256 1081 100       3203 $self->allow_view(${$self->{allow_view}}) if (ref $self->{allow_view});
  2         35  
257            
258             }
259              
260             sub _normalize_allow_edit {
261 1081     1081   1515 my $self = shift;
262            
263             # if its already set - and turned off - we're done:
264 1081 100 100     3962 return if (exists $self->{allow_edit} && !jstrue($self->{allow_edit}));
265            
266             # remember if allow_edit was *not* already set, because this effects the default for allow_add
267 258 100       741 $self->{_allow_edit_init_unset} = 1 unless (exists $self->{allow_edit});
268            
269             # if its true (or not yet set, which implies true) test for any
270             # conditions which prevent it from being true
271             my $no_edit = (
272             ! $self->{editor}
273             || ( $self->no_column && $self->{_allow_edit_init_unset} )
274 258   100     2806 );
275            
276 258 100       4548 $self->allow_edit( $no_edit ? 0 : 1 )
277             }
278              
279             sub _normalize_allow_add {
280 1081     1081   1475 my $self = shift;
281            
282             # if its already set - and turned off - we're done:
283 1081 100 100     2920 return if (exists $self->{allow_add} && !jstrue($self->{allow_add}));
284              
285 194 100       659 $self->{_allow_add_init_unset} = 1 unless (exists $self->{allow_add});
286              
287             # Go with allow_edit when it's explicitly false and we weren't set
288             return $self->allow_add(0) if(
289             ! exists $self->{allow_add}
290             && ! $self->allow_edit
291             && ! $self->{_allow_edit_init_unset}
292 194 100 100     2428 );
      100        
293            
294             # if its true (or not yet set, which implies true) test for any
295             # conditions which prevent it from being true
296             my $no_add = (
297             ! $self->{editor}
298             || ( $self->no_column && ! $self->allow_edit && $self->{_allow_add_init_unset} )
299 192   100     1638 );
300            
301 192 100       3329 $self->allow_add( $no_add ? 0 : 1 )
302             }
303              
304             sub _normalize_allow_view {
305 1081     1081   1558 my $self = shift;
306            
307             # if its already set - and turned off - we're done:
308 1081 100 100     2552 return if (exists $self->{allow_view} && !jstrue($self->{allow_view}));
309            
310             # remember if allow_edit was *not* already set, because this effects the default for allow_add
311 983 100       2238 $self->{_allow_view_init_unset} = 1 unless (exists $self->{allow_view});
312            
313             # If allow_edit was expressly set to false:
314             #my $deny_edit = (! $self->allow_edit && ! $self->{_allow_edit_init_unset});
315            
316             # if its true (or not yet set, which implies true) test for any
317             # conditions which prevent it from being true
318             my $no_view = (
319             $self->no_column && $self->{_allow_view_init_unset}
320 983   100     15931 );
321            
322 983 100       16674 $self->allow_view( $no_view ? 0 : 1 )
323             }
324             ##
325             ## -----
326              
327              
328             sub get_grid_config {
329 5199     5199 0 7378 my $self = shift;
330 5199 100       7666 return { map { defined($self->{$_})? ($_ => $self->{$_}) : () } @gridColParams };
  207960         347020  
331             }
332              
333             sub apply_field_readonly_config {
334 0     0 0   my $self= shift;
335 0 0         %{ $self->{field_readonly_config} }= %{ $self->{field_readonly_config} }, (ref($_[0]) eq 'HASH') ? %{ $_[0] } : @_; # <-- arg as hash or hashref
  0            
  0            
  0            
336             }
337              
338             sub get_field_config_readonly_param {
339 0     0 0   my $self= shift;
340 0           return $self->{field_readonly_config}{$_[0]};
341             }
342              
343             sub has_field_config_readonly_param {
344 0     0 0   my $self= shift;
345 0           return exists $self->{field_readonly_config}{$_[0]};
346             }
347              
348             sub has_no_field_readonly_config {
349 0     0 0   my $self= shift;
350 0           return 0 == (keys %{ $self->{field_readonly_config} });
  0            
351             }
352              
353             sub delete_field_readonly_config_param {
354 0     0 0   my $self= shift;
355 0           delete $self->{field_readonly_config}{$_[0]};
356             }
357              
358             sub apply_field_config {
359 0     0 0   my $self= shift;
360 0 0         %{ $self->{field_config} }= %{ $self->{field_config} }, (ref($_[0]) eq 'HASH') ? %{ $_[0] } : @_; # <-- arg as hash or hashref
  0            
  0            
  0            
361             }
362             sub get_field_config_param {
363 0     0 0   my $self= shift;
364 0           return $self->{field_config}{$_[0]};
365             }
366              
367             sub has_field_config_param {
368 0     0 0   my $self= shift;
369 0           return exists $self->{field_config}{$_[0]};
370             }
371             sub has_no_field_config {
372 0     0 0   my $self= shift;
373 0           return 0 == (keys %{ $self->{field_config} });
  0            
374             }
375              
376             sub delete_field_config_param {
377 0     0 0   my $self= shift;
378 0           delete $self->{field_config}{$_[0]};
379             }
380              
381             sub get_field_config {
382 0     0 0   my $self = shift;
383            
384 0           my $config = $self->field_config;
385 0 0         $config = $self->editor if ($self->editor);
386            
387 0           my $cnf = {
388             name => $self->name,
389             %$config
390             };
391            
392 0 0         $cnf = { %$cnf, %{$self->field_readonly_config} } if ($self->field_readonly);
  0            
393            
394 0           $self->field_cmp_config($cnf);
395            
396 0           return $cnf;
397             }
398              
399             1;