1 #package Reaction::UI::ViewPort::TimeRangeCollection;
3 # Marked commented out because unused and unmaintained. Should probably
4 # be turned into a complex viewport example later instead --mst
7 #use Reaction::Types::DateTime;
8 #use Moose::Util::TypeConstraints ();
9 #use DateTime::Event::Recurrence;
10 #use aliased 'Reaction::UI::ViewPort::Field::String';
11 #use aliased 'Reaction::UI::ViewPort::Field::DateTime';
12 #use aliased 'Reaction::UI::ViewPort::Field::HiddenArray';
13 #use aliased 'Reaction::UI::ViewPort::Field::TimeRange';
15 #class TimeRangeCollection is 'Reaction::UI::ViewPort', which {
17 # #has '+layout' => (default => 'timerangecollection');
19 # has '+column_order' => (
20 # default => sub{[ qw/ time_from time_to pattern repeat_from repeat_to / ]},
24 # isa => 'Reaction::UI::ViewPort::Field::DateTime',
25 # is => 'rw', lazy_build => 1,
29 # isa => 'Reaction::UI::ViewPort::Field::DateTime',
30 # is => 'rw', lazy_build => 1,
33 # has repeat_from => (
34 # isa => 'Reaction::UI::ViewPort::Field::DateTime',
35 # is => 'rw', lazy_build => 1,
39 # isa => 'Reaction::UI::ViewPort::Field::DateTime',
40 # is => 'rw', lazy_build => 1,
44 # isa => 'Reaction::UI::ViewPort::Field::String',
45 # # valid_values => [ qw/none daily weekly monthly/ ],
46 # is => 'rw', lazy_build => 1,
49 # has range_vps => (isa => 'ArrayRef', is => 'rw', lazy_build => 1,);
51 # has max_range_vps => (isa => 'Int', is => 'rw', lazy_build => 1,);
59 # has field_names => (
60 # isa => 'ArrayRef', is => 'rw',
61 # lazy_build => 1, clearer => 'clear_field_names',
65 # isa => 'HashRef', is => 'rw', init_arg => 'fields',
66 # clearer => '_clear_field_map',
67 # predicate => '_has_field_map',
71 # has on_next_callback => (
74 # predicate => 'has_on_next_callback',
77 # implements fields => as { shift->_field_map };
79 # implements _build_range_vps => as { [] };
81 # implements spanset => as {
83 # my $spanset = DateTime::SpanSet->empty_set;
84 # $spanset = $spanset->union($_->value) for @{$self->range_vps};
88 # implements range_strings => as {
90 # return [ map { $_->value_string } @{$self->range_vps} ];
93 # implements remove_range_vp => as {
94 # my ($self, $to_remove) = @_;
95 # $self->range_vps([ grep { $_ != $to_remove } @{$self->range_vps} ]);
96 # $self->_clear_field_map;
97 # $self->clear_field_names;
100 # implements add_range_vp => as {
102 # if ($self->can_add) {
103 # $self->_clear_field_map;
104 # $self->clear_field_names;
106 # $self->time_from->value,
107 # $self->time_to->value,
108 # (map { $_->has_value ? $_->value : '' }
109 # map { $self->$_ } qw/repeat_from repeat_to/),
110 # $self->pattern->value,
112 # my $encoded_spanset = join ',', @span_info;
114 # value_string => $encoded_spanset,
117 # my $count = scalar(@{$self->range_vps});
118 # my $field = $self->_build_simple_field(TimeRange, 'range-'.$count, $args);
119 # my $d = DateTime::Format::Duration->new( pattern => '%s' );
120 # if ($d->format_duration( $self->spanset->intersection($field->value)->duration ) > 0) {
121 # # XXX - Stop using the stash here?
122 # $self->ctx->stash->{warning} = 'Warning: Most recent time range overlaps '.
123 # 'with existing time range in this booking.';
125 # #warn "encoded spanset = $encoded_spanset\n";
126 # #warn "current range = ".join(', ', (@{$self->range_vps}))."\n";
127 # push(@{$self->range_vps}, $field);
131 # implements _build_field_map => as {
134 # foreach my $field (@{$self->range_vps}) {
135 # $map{$field->name} = $field;
137 # foreach my $name (@{$self->column_order}) {
138 # $map{$name} = $self->$name;
143 # implements _build_field_names => as {
146 # (map { $_->name } @{$self->range_vps}),
147 # @{$self->column_order}
151 # implements can_add => as {
154 # if ($self->time_to->has_value && $self->time_from->has_value) {
155 # my $time_to = $self->time_to->value;
156 # my $time_from = $self->time_from->value;
158 # my ($pattern, $repeat_from, $repeat_to) = ('','','');
159 # $pattern = $self->pattern->value if $self->pattern->has_value;
160 # $repeat_from = $self->repeat_from->value if $self->repeat_from->has_value;
161 # $repeat_to = $self->repeat_to->value if $self->repeat_to->has_value;
163 # my $duration = $time_to - $time_from;
164 # if ($time_to < $time_from) {
165 # $error = 'Please make sure that the Time To is after the Time From.';
166 # } elsif ($time_to == $time_from) {
167 # $error = 'Your desired booking slot is too small.';
168 # } elsif ($pattern && $pattern ne 'none') {
169 # my %pattern = (hourly => [ hours => 1 ],
170 # daily => [ days => 1 ],
171 # weekly => [ days => 7 ],
172 # monthly => [ months => 1 ]);
173 # my $pattern_comp = DateTime::Duration->compare(
174 # $duration, DateTime::Duration->new( @{$pattern{$pattern}} )
176 # if (!$repeat_to || !$repeat_from) {
177 # $error = 'Please make sure that you enter a valid range for the '.
178 # 'repetition period.';
179 # } elsif ($time_to == $time_from) {
180 # $error = 'Your desired repetition period is too short.';
181 # } elsif ($repeat_to && ($repeat_to < $repeat_from)) {
182 # $error = 'Please make sure that the Repeat To is after the Repeat From.';
183 # } elsif ( ( ($pattern eq 'hourly') && ($pattern_comp > 0) ) ||
184 # ( ($pattern eq 'daily') && ($pattern_comp > 0) ) ||
185 # ( ($pattern eq 'weekly') && ($pattern_comp > 0) ) ||
186 # ( ($pattern eq 'monthly') && ($pattern_comp > 0) ) ) {
187 # $error = "Your repetition pattern ($pattern) is too short for your ".
188 # "desired booking length.";
192 # $error = 'Please complete both the Time To and Time From fields.';
194 # $self->error($error);
195 # return !defined($error);
198 # implements _build_simple_field => as {
199 # my ($self, $class, $name, $args) = @_;
200 # return $class->new(
202 # location => join('-', $self->location, 'field', $name),
208 # implements _build_time_to => as {
210 # return $self->_build_simple_field(DateTime, 'time_to', {});
213 # implements _build_time_from => as {
215 # return $self->_build_simple_field(DateTime, 'time_from', {});
218 # implements _build_repeat_to => as {
220 # return $self->_build_simple_field(DateTime, 'repeat_to', {});
223 # implements _build_repeat_from => as {
225 # return $self->_build_simple_field(DateTime, 'repeat_from', {});
228 # implements _build_pattern => as {
230 # return $self->_build_simple_field(String, 'pattern', {});
233 # implements next => as {
234 # $_[0]->on_next_callback->(@_);
237 # override accept_events => sub {
239 # ('add_range_vp', ($self->has_on_next_callback ? ('next') : ()), super());
242 # override child_event_sinks => sub {
244 # return ((grep { ref($_) =~ 'Hidden' } values %{$self->_field_map}),
245 # (grep { ref($_) !~ 'Hidden' } values %{$self->_field_map}),
249 # override apply_events => sub {
250 # my ($self, $ctx, $events) = @_;
252 # # auto-inflate range fields based on number from hidden field
254 # my $max = $events->{$self->location.':max_range_vps'};
255 # my @range_vps = map {
257 # name => "range-$_",
258 # location => join('-', $self->location, 'field', 'range', $_),
262 # } ($max ? (0 .. $max - 1) : ());
263 # $self->range_vps(\@range_vps);
264 # $self->_clear_field_map;
265 # $self->clear_field_names;
267 # # call original event handling
271 # # repack range VPs in case of deletion
275 # foreach my $vp (@{$self->range_vps}) {
276 # my $cur_idx = ($vp->name =~ m/range-(\d+)/);
277 # if (($cur_idx - $prev_idx) > 1) {
279 # my $name = "range-${cur_idx}";
281 # $vp->location(join('-', $self->location, 'field', $name));
283 # $prev_idx = $cur_idx;
293 #Reaction::UI::ViewPort::TimeRangeCollection
297 # my $trc = $self->push_viewport(TimeRangeCollection,
298 # layout => 'avail_search_form',
299 # on_apply_callback => $search_callback,
321 #Typically either: none, daily, weekly or monthly
323 #=head2 max_range_vps
347 #Returns: $spanset consisting of all the TimeRange spans combined
349 #=head2 range_strings
351 #Returns: ArrayRef of Str consisting of the value_strings of all TimeRange
354 #=head2 remove_range_vp
356 #Arguments: $to_remove
362 #=head2 _build_simple_field
364 #Arguments: $class, $name, $args
365 #where $class is an object, $name is a scalar and $args is a hashref
369 #=head2 on_next_callback
371 #=head2 clear_field_names
373 #=head2 child_event_sinks
377 #=head2 L<Reaction::UI::ViewPort>
379 #=head2 L<Reaction::UI::ViewPort::Field::TimeRange>
381 #=head2 L<Reaction::UI::ViewPort::Field::DateTime>
383 #=head2 L<DateTime::Event::Recurrence>
387 #See L<Reaction::Class> for authors.
391 #See L<Reaction::Class> for the license.