elevation_event_calendar 1.0.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.
- data/CHANGELOG.rdoc +27 -0
- data/MIT-LICENSE +20 -0
- data/README.rdoc +247 -0
- data/Rakefile +23 -0
- data/generators/event_calendar/USAGE +20 -0
- data/generators/event_calendar/event_calendar_generator.rb +50 -0
- data/generators/event_calendar/lib/insert_routes.rb +55 -0
- data/generators/event_calendar/templates/controller.rb.erb +12 -0
- data/generators/event_calendar/templates/helper.rb.erb +35 -0
- data/generators/event_calendar/templates/javascript.js +49 -0
- data/generators/event_calendar/templates/jq_javascript.js +35 -0
- data/generators/event_calendar/templates/migration.rb.erb +18 -0
- data/generators/event_calendar/templates/model.rb.erb +4 -0
- data/generators/event_calendar/templates/stylesheet.css +233 -0
- data/generators/event_calendar/templates/view.html.erb +6 -0
- data/lib/event_calendar.rb +172 -0
- data/lib/event_calendar/calendar_helper.rb +360 -0
- data/rails/init.rb +2 -0
- data/rails/install.rb +1 -0
- data/rails/uninstall.rb +1 -0
- data/tasks/event_calendar_tasks.rake +4 -0
- data/test/event_calendar_test.rb +8 -0
- data/test/test_helper.rb +3 -0
- metadata +77 -0
@@ -0,0 +1,12 @@
|
|
1
|
+
class <%= view_name.classify %>Controller < ApplicationController
|
2
|
+
|
3
|
+
def index
|
4
|
+
@month = params[:month].to_i
|
5
|
+
@year = params[:year].to_i
|
6
|
+
|
7
|
+
@shown_month = Date.civil(@year, @month)
|
8
|
+
|
9
|
+
@event_strips = <%= class_name.classify %>.event_strips_for_month(@shown_month)
|
10
|
+
end
|
11
|
+
|
12
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module <%= view_name.classify %>Helper
|
2
|
+
def month_link(month_date)
|
3
|
+
link_to(I18n.localize(month_date, :format => "%B"), {:month => month_date.month, :year => month_date.year})
|
4
|
+
end
|
5
|
+
|
6
|
+
# custom options for this calendar
|
7
|
+
def event_calendar_opts
|
8
|
+
{
|
9
|
+
:year => @year,
|
10
|
+
:month => @month,
|
11
|
+
:event_strips => @event_strips,
|
12
|
+
:month_name_text => I18n.localize(@shown_month, :format => "%B %Y"),
|
13
|
+
:previous_month_text => "<< " + month_link(@shown_month.last_month),
|
14
|
+
:next_month_text => month_link(@shown_month.next_month) + " >>"<%- if options[:use_all_day] -%>,
|
15
|
+
:use_all_day => true
|
16
|
+
<%- end -%>
|
17
|
+
}
|
18
|
+
end
|
19
|
+
|
20
|
+
def event_calendar
|
21
|
+
# args is an argument hash containing :event, :day, and :options
|
22
|
+
calendar event_calendar_opts do |args|
|
23
|
+
<%- if options[:use_all_day] -%>
|
24
|
+
event, day = args[:event], args[:day]
|
25
|
+
html = %(<a href="/events/#{event.id}" title="#{h(event.name)}">)
|
26
|
+
html << display_event_time(event, day)
|
27
|
+
html << %(#{h(event.name)}</a>)
|
28
|
+
html
|
29
|
+
<%- else -%>
|
30
|
+
event = args[:event]
|
31
|
+
%(<a href="/events/#{event.id}" title="#{h(event.name)}">#{h(event.name)}</a>)
|
32
|
+
<%- end -%>
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
/*
|
2
|
+
* Smart event highlighting
|
3
|
+
* Handles for when events span rows, or don't have a background color
|
4
|
+
*/
|
5
|
+
Event.observe(window, "load", function() {
|
6
|
+
var highlight_color = "#2EAC6A";
|
7
|
+
|
8
|
+
// highlight events that have a background color
|
9
|
+
$$(".ec-event-bg").each(function(ele) {
|
10
|
+
ele.observe("mouseover", function(evt) {
|
11
|
+
event_id = ele.readAttribute("data-event-id");
|
12
|
+
$$(".ec-event-"+event_id).each(function(el) {
|
13
|
+
el.setStyle({ backgroundColor: highlight_color });
|
14
|
+
});
|
15
|
+
});
|
16
|
+
ele.observe("mouseout", function(evt) {
|
17
|
+
event_color = ele.readAttribute("data-color");
|
18
|
+
event_id = ele.readAttribute("data-event-id");
|
19
|
+
$$(".ec-event-"+event_id).each(function(el) {
|
20
|
+
el.setStyle({ backgroundColor: event_color });
|
21
|
+
});
|
22
|
+
});
|
23
|
+
});
|
24
|
+
|
25
|
+
// highlight events that don't have a background color
|
26
|
+
$$(".ec-event-no-bg").each(function(ele) {
|
27
|
+
ele.observe("mouseover", function(evt) {
|
28
|
+
ele.setStyle({ color: "white" });
|
29
|
+
ele.select("a").each(function(link) {
|
30
|
+
link.setStyle({ color: "white" });
|
31
|
+
});
|
32
|
+
ele.select(".ec-bullet").each(function(bullet) {
|
33
|
+
bullet.setStyle({ backgroundColor: "white" });
|
34
|
+
});
|
35
|
+
ele.setStyle({ backgroundColor: highlight_color });
|
36
|
+
});
|
37
|
+
ele.observe("mouseout", function(evt) {
|
38
|
+
event_color = ele.readAttribute("data-color");
|
39
|
+
ele.setStyle({ color: event_color });
|
40
|
+
ele.select("a").each(function(link) {
|
41
|
+
link.setStyle({ color: event_color });
|
42
|
+
});
|
43
|
+
ele.select(".ec-bullet").each(function(bullet) {
|
44
|
+
bullet.setStyle({ backgroundColor: event_color });
|
45
|
+
});
|
46
|
+
ele.setStyle({ backgroundColor: "transparent" });
|
47
|
+
});
|
48
|
+
});
|
49
|
+
});
|
@@ -0,0 +1,35 @@
|
|
1
|
+
/*
|
2
|
+
* Smart event highlighting
|
3
|
+
* Handles when events span rows, or don't have a background color
|
4
|
+
*/
|
5
|
+
$(document).ready(function() {
|
6
|
+
var highlight_color = "#2EAC6A";
|
7
|
+
|
8
|
+
// highlight events that have a background color
|
9
|
+
$(".ec-event-bg").live("mouseover", function() {
|
10
|
+
event_id = $(this).attr("data-event-id");
|
11
|
+
$(".ec-event-"+event_id).css("background-color", highlight_color);
|
12
|
+
});
|
13
|
+
$(".ec-event-bg").live("mouseout", function() {
|
14
|
+
event_id = $(this).attr("data-event-id");
|
15
|
+
event_color = $(this).attr("data-color");
|
16
|
+
$(".ec-event-"+event_id).css("background-color", event_color);
|
17
|
+
});
|
18
|
+
|
19
|
+
// highlight events that don't have a background color
|
20
|
+
$(".ec-event-no-bg").live("mouseover", function() {
|
21
|
+
ele = $(this);
|
22
|
+
ele.css("color", "white");
|
23
|
+
ele.find("a").css("color", "white");
|
24
|
+
ele.find(".ec-bullet").css("background-color", "white");
|
25
|
+
ele.css("background-color", highlight_color);
|
26
|
+
});
|
27
|
+
$(".ec-event-no-bg").live("mouseout", function() {
|
28
|
+
ele = $(this);
|
29
|
+
event_color = $(this).attr("data-color");
|
30
|
+
ele.css("color", event_color);
|
31
|
+
ele.find("a").css("color", event_color);
|
32
|
+
ele.find(".ec-bullet").css("background-color", event_color);
|
33
|
+
ele.css("background-color", "transparent");
|
34
|
+
});
|
35
|
+
});
|
@@ -0,0 +1,18 @@
|
|
1
|
+
class Create<%= class_name.classify.pluralize %> < ActiveRecord::Migration
|
2
|
+
def self.up
|
3
|
+
create_table :<%= class_name.pluralize %> do |t|
|
4
|
+
t.string :name
|
5
|
+
t.datetime :start_at
|
6
|
+
t.datetime :end_at
|
7
|
+
<%- if options[:use_all_day] -%>
|
8
|
+
t.boolean :all_day
|
9
|
+
<%- end -%>
|
10
|
+
|
11
|
+
t.timestamps
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.down
|
16
|
+
drop_table :<%= class_name.pluralize %>
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,233 @@
|
|
1
|
+
/*
|
2
|
+
Event Calendar stylesheet
|
3
|
+
|
4
|
+
Colors:
|
5
|
+
#d5d5d5 - border (gray)
|
6
|
+
#303030 - day names bg (gray)
|
7
|
+
#444 - number (gray)
|
8
|
+
#ecede2 - day header bg (light tan)
|
9
|
+
##d7d7ba - today header bg (tan)
|
10
|
+
#ffffdd - today bg light (yellow)
|
11
|
+
#777 - other month number (gray)
|
12
|
+
#efefef - other month day header (gray)
|
13
|
+
#2eac6a - hover (green)
|
14
|
+
*/
|
15
|
+
|
16
|
+
/* Outer most container */
|
17
|
+
.ec-calendar {
|
18
|
+
font-family: verdana, arial, helvetica, sans-serif;
|
19
|
+
font-size: 11px;
|
20
|
+
line-height: 14px;
|
21
|
+
margin: 0;
|
22
|
+
padding: 0;
|
23
|
+
border-bottom: 1px solid #d5d5d5;
|
24
|
+
}
|
25
|
+
|
26
|
+
/* Month name header & links */
|
27
|
+
.ec-calendar-header {
|
28
|
+
padding: 5px 0;
|
29
|
+
width: 100%;
|
30
|
+
table-layout: fixed;
|
31
|
+
}
|
32
|
+
|
33
|
+
.ec-month-name {
|
34
|
+
font-size: 16px;
|
35
|
+
font-weight: bold;
|
36
|
+
}
|
37
|
+
|
38
|
+
.ec-month-nav {
|
39
|
+
|
40
|
+
}
|
41
|
+
|
42
|
+
/* Containers */
|
43
|
+
.ec-body {
|
44
|
+
position: relative;
|
45
|
+
border-right: 1px solid #303030;
|
46
|
+
white-space: nowrap;
|
47
|
+
}
|
48
|
+
|
49
|
+
/* Day names */
|
50
|
+
.ec-day-names {
|
51
|
+
position: absolute;
|
52
|
+
top: 0;
|
53
|
+
left: 0;
|
54
|
+
width: 100%;
|
55
|
+
table-layout: fixed;
|
56
|
+
padding: 2px 0;
|
57
|
+
background: #303030;
|
58
|
+
color: white;
|
59
|
+
}
|
60
|
+
|
61
|
+
.ec-day-name {
|
62
|
+
font-weight: normal;
|
63
|
+
}
|
64
|
+
|
65
|
+
/* Rows container and Row */
|
66
|
+
.ec-rows {
|
67
|
+
position: absolute;
|
68
|
+
left: 0;
|
69
|
+
bottom: 0;
|
70
|
+
width: 100%;
|
71
|
+
background: white;
|
72
|
+
overflow: hidden;
|
73
|
+
border-right: 1px solid #d5d5d5;
|
74
|
+
}
|
75
|
+
|
76
|
+
.ec-row {
|
77
|
+
position: absolute;
|
78
|
+
left: 0;
|
79
|
+
width: 100%;
|
80
|
+
overflow: hidden;
|
81
|
+
}
|
82
|
+
|
83
|
+
/* Background */
|
84
|
+
.ec-row-bg {
|
85
|
+
position: absolute;
|
86
|
+
top: 0;
|
87
|
+
left: 0;
|
88
|
+
height: 100%;
|
89
|
+
width: 100%;
|
90
|
+
table-layout: fixed;
|
91
|
+
}
|
92
|
+
|
93
|
+
.ec-day-bg {
|
94
|
+
border-left: 1px solid #d5d5d5;
|
95
|
+
}
|
96
|
+
|
97
|
+
.ec-today-bg {
|
98
|
+
background-color: #ffffdd;
|
99
|
+
}
|
100
|
+
|
101
|
+
.ec-row-table {
|
102
|
+
position: relative;
|
103
|
+
width: 100%;
|
104
|
+
table-layout: fixed;
|
105
|
+
}
|
106
|
+
|
107
|
+
/* Day header */
|
108
|
+
.ec-day-header {
|
109
|
+
color: #444;
|
110
|
+
text-align: right;
|
111
|
+
padding: 0 5px;
|
112
|
+
line-height: 16px;
|
113
|
+
border-top: 1px solid #d5d5d5;
|
114
|
+
border-left: 1px solid #d5d5d5;
|
115
|
+
border-bottom: 1px dotted #bbbbbb;
|
116
|
+
background-color: #ecede2;
|
117
|
+
overflow: hidden;
|
118
|
+
}
|
119
|
+
|
120
|
+
a.ec-day-link {
|
121
|
+
color: #444;
|
122
|
+
}
|
123
|
+
|
124
|
+
.ec-today-header {
|
125
|
+
background-color: #d7d7ba;
|
126
|
+
}
|
127
|
+
|
128
|
+
.ec-weekend-day-header {
|
129
|
+
|
130
|
+
}
|
131
|
+
|
132
|
+
.ec-other-month-header {
|
133
|
+
background-color: #efefef;
|
134
|
+
color: #777;
|
135
|
+
}
|
136
|
+
|
137
|
+
|
138
|
+
/* Event cell and container */
|
139
|
+
.ec-event-cell {
|
140
|
+
cursor: pointer;
|
141
|
+
vertical-align: top;
|
142
|
+
padding-right: 1px;
|
143
|
+
padding-left: 2px;
|
144
|
+
}
|
145
|
+
|
146
|
+
.ec-event-cell a {
|
147
|
+
text-decoration: none;
|
148
|
+
display: block;
|
149
|
+
width: 100%;
|
150
|
+
height: 100%;
|
151
|
+
}
|
152
|
+
|
153
|
+
.ec-no-event-cell {
|
154
|
+
cursor: default;
|
155
|
+
}
|
156
|
+
|
157
|
+
.ec-event {
|
158
|
+
color: white;
|
159
|
+
padding-right: 1px;
|
160
|
+
padding-left: 11px;
|
161
|
+
-webkit-border-radius: 3px;
|
162
|
+
-khtml-border-radius: 3px;
|
163
|
+
-moz-border-radius: 3px;
|
164
|
+
overflow: hidden;
|
165
|
+
white-space: nowrap;
|
166
|
+
}
|
167
|
+
|
168
|
+
.ec-event :hover {
|
169
|
+
/* doesn't look as good as js highlighting */
|
170
|
+
/* background-color: #2eac6a; */
|
171
|
+
}
|
172
|
+
|
173
|
+
.ec-event-bg a {
|
174
|
+
color: white;
|
175
|
+
}
|
176
|
+
|
177
|
+
/* used to distinguish non-all_day events */
|
178
|
+
.ec-event-no-bg {
|
179
|
+
position: relative;
|
180
|
+
/* padding-left: 5px; */
|
181
|
+
}
|
182
|
+
|
183
|
+
.ec-event-no-bg a {
|
184
|
+
/* isn't implemented in all browsers */
|
185
|
+
color: inherit;
|
186
|
+
}
|
187
|
+
|
188
|
+
.ec-event-time {
|
189
|
+
font-size: 85%;
|
190
|
+
font-weight: bold;
|
191
|
+
padding-right: 3px;
|
192
|
+
}
|
193
|
+
|
194
|
+
|
195
|
+
/* Left and right arrows */
|
196
|
+
/* Doesn't work in IE6, use bg images instead */
|
197
|
+
.ec-left-arrow, .ec-right-arrow {
|
198
|
+
position: relative;
|
199
|
+
top: 3px;
|
200
|
+
width: 0;
|
201
|
+
height: 0;
|
202
|
+
font-size: 0;
|
203
|
+
line-height: 0;
|
204
|
+
margin-bottom: -8px;
|
205
|
+
border-top: 4px solid transparent;
|
206
|
+
border-bottom: 4px solid transparent;
|
207
|
+
}
|
208
|
+
|
209
|
+
.ec-left-arrow {
|
210
|
+
margin-left: -7px;
|
211
|
+
margin-right: auto;
|
212
|
+
border-right: 4px solid white;
|
213
|
+
}
|
214
|
+
|
215
|
+
.ec-right-arrow {
|
216
|
+
margin-left: auto;
|
217
|
+
margin-right: 3px;
|
218
|
+
border-left: 4px solid white;
|
219
|
+
}
|
220
|
+
|
221
|
+
/* remove this to not have a bullet */
|
222
|
+
/* don't look as good in ie */
|
223
|
+
.ec-bullet {
|
224
|
+
position: absolute;
|
225
|
+
top: 7px;
|
226
|
+
width: 4px;
|
227
|
+
height: 4px;
|
228
|
+
margin-left: -7px;
|
229
|
+
margin-right: auto;
|
230
|
+
-webkit-border-radius: 2px;
|
231
|
+
-khtml-border-radius: 2px;
|
232
|
+
-moz-border-radius: 2px;
|
233
|
+
}
|
@@ -0,0 +1,172 @@
|
|
1
|
+
module EventCalendar
|
2
|
+
|
3
|
+
module PluginMethods
|
4
|
+
def has_event_calendar
|
5
|
+
ClassMethods.setup_event_calendar_on self
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
# class Methods
|
10
|
+
module ClassMethods
|
11
|
+
|
12
|
+
def self.setup_event_calendar_on(recipient)
|
13
|
+
recipient.extend ClassMethods
|
14
|
+
recipient.class_eval do
|
15
|
+
include InstanceMethods
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
# For the given month, find the start and end dates
|
20
|
+
# Find all the events within this range, and create event strips for them
|
21
|
+
def event_strips_for_month(shown_date, first_day_of_week=0)
|
22
|
+
strip_start, strip_end = get_start_and_end_dates(shown_date, first_day_of_week)
|
23
|
+
events = events_for_date_range(strip_start, strip_end)
|
24
|
+
event_strips = create_event_strips(strip_start, strip_end, events)
|
25
|
+
event_strips
|
26
|
+
end
|
27
|
+
|
28
|
+
# Expand start and end dates to show the previous month and next month's days,
|
29
|
+
# that overlap with the shown months display
|
30
|
+
def get_start_and_end_dates(shown_date, first_day_of_week=0)
|
31
|
+
# start with the first day of the given month
|
32
|
+
start_of_month = Date.civil(shown_date.year, shown_date.month, 1)
|
33
|
+
# the end of last month
|
34
|
+
strip_start = beginning_of_week(start_of_month, first_day_of_week)
|
35
|
+
# the beginning of next month, unless this month ended evenly on the last day of the week
|
36
|
+
if start_of_month.next_month == beginning_of_week(start_of_month.next_month, first_day_of_week)
|
37
|
+
# last day of the month is also the last day of the week
|
38
|
+
strip_end = start_of_month.next_month
|
39
|
+
else
|
40
|
+
# add the extra days from next month
|
41
|
+
strip_end = beginning_of_week(start_of_month.next_month + 7, first_day_of_week)
|
42
|
+
end
|
43
|
+
[strip_start, strip_end]
|
44
|
+
end
|
45
|
+
|
46
|
+
# Get the events overlapping the given start and end dates
|
47
|
+
def events_for_date_range(start_d, end_d)
|
48
|
+
self.find(
|
49
|
+
:all,
|
50
|
+
:conditions => [ '(? <= end_at) AND (start_at < ?)', start_d.to_time.utc, end_d.to_time.utc ],
|
51
|
+
:order => 'start_at ASC'
|
52
|
+
)
|
53
|
+
end
|
54
|
+
|
55
|
+
# Create the various strips that show evetns
|
56
|
+
def create_event_strips(strip_start, strip_end, events)
|
57
|
+
# create an inital event strip, with a nil entry for every day of the displayed days
|
58
|
+
event_strips = [[nil] * (strip_end - strip_start + 1)]
|
59
|
+
|
60
|
+
events.each do |event|
|
61
|
+
cur_date = event.start_at.to_date
|
62
|
+
end_date = event.end_at.to_date
|
63
|
+
cur_date, end_date = event.clip_range(strip_start, strip_end)
|
64
|
+
start_range = (cur_date - strip_start).to_i
|
65
|
+
end_range = (end_date - strip_start).to_i
|
66
|
+
|
67
|
+
# make sure the event is within our viewing range
|
68
|
+
if (start_range <= end_range) and (end_range >= 0)
|
69
|
+
range = start_range..end_range
|
70
|
+
|
71
|
+
open_strip = space_in_current_strips?(event_strips, range)
|
72
|
+
|
73
|
+
if open_strip.nil?
|
74
|
+
# no strips open, make a new one
|
75
|
+
new_strip = [nil] * (strip_end - strip_start + 1)
|
76
|
+
range.each {|r| new_strip[r] = event}
|
77
|
+
event_strips << new_strip
|
78
|
+
else
|
79
|
+
# found an open strip, add this event to it
|
80
|
+
range.each {|r| open_strip[r] = event}
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
event_strips
|
85
|
+
end
|
86
|
+
|
87
|
+
def space_in_current_strips?(event_strips, range)
|
88
|
+
open_strip = nil
|
89
|
+
for strip in event_strips
|
90
|
+
strip_is_open = true
|
91
|
+
range.each do |r|
|
92
|
+
# overlapping events on this strip
|
93
|
+
if !strip[r].nil?
|
94
|
+
strip_is_open = false
|
95
|
+
break
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
if strip_is_open
|
100
|
+
open_strip = strip
|
101
|
+
break
|
102
|
+
end
|
103
|
+
end
|
104
|
+
open_strip
|
105
|
+
end
|
106
|
+
|
107
|
+
def days_between(first, second)
|
108
|
+
if first > second
|
109
|
+
second + (7 - first)
|
110
|
+
else
|
111
|
+
second - first
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
def beginning_of_week(date, start = 0)
|
116
|
+
days_to_beg = days_between(start, date.wday)
|
117
|
+
date - days_to_beg
|
118
|
+
end
|
119
|
+
|
120
|
+
end
|
121
|
+
|
122
|
+
# Instance Methods
|
123
|
+
# Override in your model as needed
|
124
|
+
module InstanceMethods
|
125
|
+
def year
|
126
|
+
date.year
|
127
|
+
end
|
128
|
+
|
129
|
+
def month
|
130
|
+
date.month
|
131
|
+
end
|
132
|
+
|
133
|
+
def day
|
134
|
+
date.day
|
135
|
+
end
|
136
|
+
|
137
|
+
def all_day
|
138
|
+
self[:all_day]
|
139
|
+
end
|
140
|
+
|
141
|
+
def color
|
142
|
+
self[:color] || '#9aa4ad'
|
143
|
+
end
|
144
|
+
|
145
|
+
def days
|
146
|
+
end_at.to_date - start_at.to_date
|
147
|
+
end
|
148
|
+
|
149
|
+
# start_d - start of the month, or start of the week
|
150
|
+
# end_d - end of the month, or end of the week
|
151
|
+
def clip_range(start_d, end_d)
|
152
|
+
# make sure we are comparing date objects to date objects,
|
153
|
+
# otherwise timezones can cause problems
|
154
|
+
start_at_d = start_at.to_date
|
155
|
+
end_at_d = end_at.to_date
|
156
|
+
# Clip start date, make sure it also ends on or after the start range
|
157
|
+
if (start_at_d < start_d and end_at_d >= start_d)
|
158
|
+
clipped_start = start_d
|
159
|
+
else
|
160
|
+
clipped_start = start_at_d
|
161
|
+
end
|
162
|
+
|
163
|
+
# Clip end date
|
164
|
+
if (end_at_d > end_d)
|
165
|
+
clipped_end = end_d
|
166
|
+
else
|
167
|
+
clipped_end = end_at_d
|
168
|
+
end
|
169
|
+
[clipped_start, clipped_end]
|
170
|
+
end
|
171
|
+
end
|
172
|
+
end
|