simple_calendar-timeslot 0.8.0 → 0.90.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f52c61db709b554fc0b83bd23ede3fd67eef7d30a6c2ca56653bedfb07aa36e1
4
- data.tar.gz: 85c84c537e0f6c838bd6cfbb1e9d91524e0ffe391d45380dba3d8dda0aed8b10
3
+ metadata.gz: c69834a6c0289a7d3679c45911fd5feb363201a4ae250efe96ec5b9b3e610bdf
4
+ data.tar.gz: 382ed150f3b8cc79e6e8fabd9e2280c320f4963babbf287a9df7a32526c24262
5
5
  SHA512:
6
- metadata.gz: cd7ea8c241c235e106c838f474d357b066bef07cdb67ec2e5df0a046b4fb0b8586b71e19ee32137ca2e78b5f269ced9d55b75003cd471251498387336f9c720b
7
- data.tar.gz: 503206dbd8a107c38cae4f4957904a27a55db2f342a1a001346095d49b71a90ea1b945b1521da7bf180953d0343df0bb7509476670ec844044accbaceac2f39d
6
+ metadata.gz: 03410faac3f8c01a01505583b0cb7676496181f8eda96b8687774dcaaa32006b60d0b760f45f88ba9d20efd3b67545f8790b71ed28d3e8d3d064d3770cf9b778
7
+ data.tar.gz: b901a9dcd48841e85687a528892d9f8cf79c509e7fbaf7d3f22c59d00f7d489eb0d22b30e5a520b3d73497cfd91b1a63e4160aadda6f375f4f8ac72196215cd4
data/CHANGELOG.md CHANGED
@@ -1,5 +1,21 @@
1
1
  ## [Unreleased]
2
2
 
3
+ ## [0.90.0] - 2021-11-17
4
+ ### Changed
5
+ - **Mayor changes** to complete html layout
6
+ - **Option arguments changed**:
7
+ - `orientation` has been removed for `layout`
8
+ - `split_by_type` has been renamed to `bucket_by`
9
+ - `horizontal_height_px` has been renamed to `day_height_px`
10
+ - `horizontal_scroll_split` is now possible with a separate layout
11
+ - `bucket_title_size` has been removed, the size is determined by the size of the DOM-elements
12
+ ### Added
13
+ - New Layout `horizontal_date_on_top`
14
+ - New option `body_size_px` that limits the calendar body height if set and makes it scrollable.
15
+ - New option `date_format_string`, that applies the format string before displaying the date above each day
16
+ - New option `date_header_format_string`, that applies the format string before displaying the `start_date` url parameter in the heading of the calendar (between previos and next links)
17
+
18
+
3
19
  ## [0.8.0] - 2021-11-15
4
20
  ### Changed
5
21
  - Shuffle html layout around a bit for easier css styling like sticky
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- simple_calendar-timeslot (0.8.0)
4
+ simple_calendar-timeslot (0.90.0)
5
5
  simple_calendar (~> 2.0)
6
6
 
7
7
  GEM
@@ -90,6 +90,8 @@ GEM
90
90
  nokogiri (1.12.5)
91
91
  mini_portile2 (~> 2.6.1)
92
92
  racc (~> 1.4)
93
+ nokogiri (1.12.5-x86_64-darwin)
94
+ racc (~> 1.4)
93
95
  parallel (1.21.0)
94
96
  parser (3.0.2.0)
95
97
  ast (~> 2.4.1)
data/README.md CHANGED
@@ -1,18 +1,96 @@
1
1
  # SimpleCalendar::Timeslot
2
2
 
3
- This is an extension of the rubygem `simple_calendar` by Chris Oliver aka excid3. It allows
3
+ This gem is an extension of the rubygem `simple_calendar` by Chris Oliver aka excid3. It allows
4
4
  for simple calendar creation in a Ruby on Rails app with an timeslot representation of events
5
5
  in a 24h day.
6
6
 
7
7
  This helps to visually grasps the length of events and the time between them. In case of overlapping, the respective events are shown side-by-side. It is also possible to categorise events in buckets according to some function, then they will be shown next to one another in the 24h timeline.
8
8
 
9
- Horizontal and vertical layout is selectable via options, just like many other ones.
9
+ Different layouts are selectable via options, just like many other ones.
10
+
11
+ All layouts support the following options:
12
+ - event rendering can be completely controlled, the calendar provides a wrapping div around with the correct dimensions at the right place
13
+ - responsive design which can (and should) be styled to your liking
14
+ - turn hour grid on/off
15
+ - set the width of the grid in `px` or `%`
16
+ - adjust the pixel-size corresponding to one minute
17
+ - limit the overall size of day, making part of it scroll
18
+ - for horizontal layouts: determine the breadth of one day
19
+ - "bucketing" of events by same value, any event function can be provided (see colums "Me" and "Mom" in image below and symbol `:event_type_name` in code)
20
+ - displaying of bucket label by provided function on event
21
+ - formating of date above day
22
+ - formating of date in heading
23
+ - turn current time indicator on/off, this is an invisible css-stylable div with class `tscal-current-time-indicator` (can be seen in examples below)
24
+ - by default, the 24h-grid hides any overflow which is recommended not to overwrite, otherwise there might be 2-directional scrolling
25
+
26
+ **Note:** events are styled in the examples with the following minimalistic styles to show their outline. This is not the case when the gem is used out of the box, because it would make the style hard to overwrite because of css-predence rules.
27
+ ```css
28
+ .event-wrapper {
29
+ border: solid 1px black;
30
+ }
31
+ ```
32
+
33
+ ### Vertical layout
34
+ This layout grows vertically, and can be limited in height by option `body_size_px` and will then scroll.
35
+ The horizontal direction is responsive.
36
+ ![Vertical Layout](https://raw.githubusercontent.com/1klap/simple_calendar-timeslot/90a0c2b72b172a113105412ef34dd00f728e50e4/img/simple_calendar-timeslot_vertical-v2.png)
37
+
38
+ Code
39
+ ```erb
40
+ <%= timeslot_calendar(events: @events,
41
+ layout: :vertical,
42
+ number_of_days: 2,
43
+ px_per_minute: 1.3,
44
+ #display_grid: true,
45
+ grid_width: "30px",
46
+ body_size_px: 600,
47
+ bucket_by: :event_type,
48
+ date_format_string: "%d.%m.%Y",
49
+ #date_heading_format_string: "%d.%m.%Y",
50
+ display_bucket_title: :event_type_name,
51
+ display_current_time_indicator: true
52
+ ) do |event| %>
53
+ <div class="timeslot-event">
54
+ <%= event.title %>
55
+ </div>
56
+ <% end %>
57
+ ```
58
+
59
+ ### Horizontal layout
60
+ This layout is basicall the vertical one toppled over. The days grows horizontally, if it has not enough space (which is likely this direction) the day will scroll with the day and bucket headings staying fixed. Multiple days scroll together. The height per day can be adjusted as option, the events scale responsively.
61
+
62
+ One advantage over vertical layout is that the horizontal scrolling works better for mobile devices, combined with vertical scroll to scroll further down.
63
+ ![Horizontal Layout](https://raw.githubusercontent.com/1klap/simple_calendar-timeslot/90a0c2b72b172a113105412ef34dd00f728e50e4/img/simple_calendar-timeslot_horizontal-v2.png)
64
+
65
+ Code:
66
+ ```erb
67
+ <%= timeslot_calendar(events: @events,
68
+ layout: :horizontal,
69
+ day_height_px: 100,
70
+ #...
71
+ ) do |event| %>
72
+ <div class="timeslot-event">
73
+ <%= event.title %>
74
+ </div>
75
+ <% end %>
76
+ ```
77
+
78
+ ### Horizontal - Date on top
79
+ My personal favorite: like horizontal layout, but the date is moved above the scrolling day, freeing up space. Forcibly, the scroll between days is separated (this could be restored with a javascript scroll-lock).
80
+ ![Horizontal Layout](https://raw.githubusercontent.com/1klap/simple_calendar-timeslot/90a0c2b72b172a113105412ef34dd00f728e50e4/img/simple_calendar-timeslot_horizontal2-v2.png)
10
81
 
11
- Horizontal example
12
- ![Horizontal Calendar](https://github.com/1klap/simple_calendar-timeslot/blob/96475bf7c354b7e0318a9421e155588d96517fc3/img/simple_calendar-timeslot_horizontal.png?raw=true)
82
+ Code:
83
+ ```erb
84
+ <%= timeslot_calendar(events: @events,
85
+ layout: :horizontal_date_on_top,
86
+ #...
87
+ ) do |event| %>
88
+ <div class="timeslot-event">
89
+ <%= event.title %>
90
+ </div>
91
+ <% end %>
92
+ ```
13
93
 
14
- Vertical example
15
- ![Vertical Calendar](https://github.com/1klap/simple_calendar-timeslot/blob/96475bf7c354b7e0318a9421e155588d96517fc3/img/simple_calendar-timeslot_vertical.png?raw=true)
16
94
 
17
95
 
18
96
  ## Installation
@@ -34,7 +112,7 @@ Or install it yourself as:
34
112
 
35
113
  **Important** Then include the stylesheet in your rails app.
36
114
 
37
- If you have an `application.css` file, include the following:
115
+ If you have an `application.css` file, include the following (before `*= require_tree .` and `*= require_self` if you want to overwrite styles with equal specificity):
38
116
  ```ruby
39
117
  *= require simple_calendar-timeslot
40
118
  ```
@@ -45,43 +123,49 @@ If you use an SCSS file (`application.scss`), add the following line instead:
45
123
 
46
124
  ## Usage
47
125
 
48
- TODO: Write usage instructions here
126
+ Include a code snipped like the one below anywhere in your `.html.erb` file, set `@events` in your calling controller to be a collection of your model object to be displayed. You can refer to the documentation on [simple_calendar/Rendering_Events](https://github.com/excid3/simple_calendar#rendering-events) (thats from the gem on which this one is built on top of), the complete paragraph applies to this gem as well.
49
127
 
50
- Your model must implement a `start_time` and `end_time` function,
51
- or you can specify alternatives as options to the call below
52
- as `attribute: :my_start_time` and `end_attribute: :my_end_time`.
128
+ All options are optional, below you see all possible values commented out with their default value behind the colon and a short description afterwards.
129
+
130
+ Your model must implement a `start_time` and `end_time` function that returns a datetime, or you can specify alternatives as options to the call below
131
+ as `attribute: :my_start_time` and `end_attribute: :my_end_time` (without the `#` of course).
53
132
 
54
133
  ```erb
55
134
  <%= timeslot_calendar(events: @events,
56
- number_of_days: 2,
57
- px_per_minute: 1.5,
58
- orientation: :horizontal,
59
- horizontal_height_px: 250,
60
- # attribute: :my_start_time,
61
- # display_grid: false,
62
- # display_bucket_title: :event_type,
63
- # bucket_title_size: 30,
64
- # grid_width: "20px",
65
- # split_by_type: :event_type
135
+ # number_of_days: 4,
136
+ # layout: :vertical, # possible values: :vertical, :horizontal, :horizontal_date_on_top
137
+ # px_per_minute: 0.65, # define size of one minute
138
+ # display_grid: true,
139
+ # grid_width: "20px", # can be any valid css size px, %, em
140
+ # display_current_time_indicator: false, # draw a line to show the current time, stylable class: tscal-current-time-indicator
141
+ # body_size_px: false, # only vertical layout: set integer if your want to limit the height
142
+ # day_height_px: 200, # only horizontal and horizontal_date_on_top layout: set height for a day
143
+ # bucket_by: false, # give model function as symbol if you want to bucket events by this function (f.ex. :event_type)
144
+ # display_bucket_title: false,
145
+ # date_format_string: false,
146
+ # date_heading_format_string: "%B %Y",
147
+ # attribute: :my_start_time, # provide alternative to :start_time model function
148
+ # end_attribute: :my_end_time, # provide alternative to :end_time model function
66
149
  ) do |event| %>
67
150
  <div class="timeslot-event">
68
151
  <%= event.title %>
69
152
  </div>
70
153
  <% end %>
71
-
72
154
  ```
73
155
 
74
- Shortversion in the meantime:
75
- - `orientation` (`:vertical`, `:horizontal`, default: :vertical)
76
- - `px_per_minute` (defines size of calendar, default: 0.65)
77
- - `horizontal_height_px` default: 300
78
- - `horizontal_scroll_split` (scroll days separately or together, default: false)
79
- - `split_by_type` (model function to call in case of bucketing f.ex.`:event_type`, default: false)
80
- - `display_bucket_title` (model function to call in case of bucketing f.ex.`:event_type_name`, default: false)
81
- - `bucket_title_size` default: 20
82
- - `grid_width` default: 20px
83
- - `display_grid` default: true
84
- - `display_current_time_indicator` (display a stylable div across the timeline that display the current time, css-class: `current_time_indicator`, default: false)
156
+ ## Customization
157
+
158
+ Style away as much as you want. This gem is mainly concerned to move the right pieces to the right place, how they look is up to you. Have a look
159
+ at the generated HTML or start with these classes
160
+ - `.tscal-event-wrapper`
161
+ - `.tscal-current-time-indicator`
162
+ - `.tscal-hour-cell`
163
+
164
+ Some words of caution: overflow is hidden for the scrolling part of the calendar, that is a div with class `.buckets-wrapper`. If you see your box-shadows clipped, that is probably causing it. You can of course overwrite clipping (with `.timeslot-calendar .buckets-wrapper { overflow: visible; }`), but then I recommend setting `overflow: hidden;` on `.tscal-event-wrapper`, otherwise you risk to see scrolling where you don't want to, when to content of the event is overflowing.
165
+
166
+ Here is an example with some basic styling
167
+
168
+ ![Styled calendar](https://raw.githubusercontent.com/1klap/simple_calendar-timeslot/c844c11f99c51f1b44bab825943615c295acde29/img/simple_calendar-timeslot_styled.png)
85
169
 
86
170
  ## Development
87
171
 
@@ -91,4 +175,5 @@ To install this gem onto your local machine, run `bundle exec rake install`. To
91
175
 
92
176
  ## Contributing
93
177
 
178
+ I could use some help with the test suite.
94
179
  Bug reports and pull requests are welcome on GitHub at https://github.com/1klap/simple_calendar-timeslot.
@@ -1,123 +1,130 @@
1
+ /******* Default styling, overwrite me! *******/
2
+ .tscal-event-wrapper {
3
+ border: solid 1px black;
4
+ /*
5
+ overflow: hidden;
6
+ background-color: #fff;
7
+ z-index: 5;
8
+ */
9
+ }
10
+ .tscal-current-time-indicator {
11
+ border: solid 1px rgba(219, 187, 187, 0.5);;
12
+ }
13
+ .tscal-hour-cell {
14
+ border-style: solid;
15
+ border-color: rgba(229, 231, 235, 0.5);
16
+ }
17
+ .tscal-vertical {
18
+ border-width: 2px 0 0;
19
+ }
20
+ .tscal-horizontal {
21
+ border-width: 0 0 0 2px;
22
+ }
23
+ /******* Layout: Base (==Vertical) *******/
1
24
  .timeslot-calendar div {
2
25
  box-sizing: border-box;
3
26
  }
4
- .timeslot-calendar .days-wrapper-vertical .days-body {
27
+ .timeslot-calendar .titles-heading {
5
28
  display: flex;
6
29
  flex-direction: row;
7
30
  }
8
- .timeslot-calendar .days-wrapper-vertical .days-heading {
9
- width: 100%;
31
+ .timeslot-calendar .title-heading {
32
+ flex: 1;
33
+ }
34
+ .timeslot-calendar .buckets-heading {
10
35
  display: flex;
11
36
  flex-direction: row;
12
- top: 0;
13
- /*position: sticky;*/
14
37
  }
15
- .timeslot-calendar .days-wrapper-vertical .days-heading .day-title-row{
38
+ .timeslot-calendar .bucket-heading {
16
39
  flex: 1;
17
40
  }
18
-
19
- .timeslot-calendar .days-wrapper-horizontal {
41
+ .timeslot-calendar .calendar-body {
20
42
  display: flex;
21
- flex-direction: column;
22
- }
23
- .timeslot-calendar .days-wrapper-horizontal .day-title-row {
24
- display: inline-block;
25
- left: 0;
26
- /*position: sticky;*/
27
- }
28
- .timeslot-calendar .days-wrapper-horizontal.scroll-link {
29
- overflow-x: auto;
30
- overflow-y: hidden;
43
+ flex-direction: row;
44
+ overflow-y: scroll;
31
45
  }
32
46
  .timeslot-calendar .day-wrapper {
33
- flex: 1 1 0;
47
+ flex: 1;
34
48
  }
35
- .timeslot-calendar .day-content-vertical {
36
- display: flex;
37
- flex-direction: column;
49
+ .timeslot-calendar .day-body {
38
50
  position: relative;
39
51
  }
40
- .timeslot-calendar .day-content-horizontal {
52
+ .timeslot-calendar .hour-indicator-wrapper {
41
53
  display: flex;
42
54
  flex-direction: column;
55
+ height: 100%;
43
56
  position: relative;
44
57
  }
45
- .timeslot-calendar .day-content-horizontal.scroll-split {
46
- overflow-x: auto;
47
- overflow-y: hidden;
48
- }
49
- .timeslot-calendar .day-content-horizontal-inner {
50
- position: relative;
58
+ .timeslot-calendar .hour-indicator-cell {
59
+ min-height: 0;
60
+ flex: 1;
51
61
  }
52
- .timeslot-calendar .hour-indicator-col-vertical {
53
- display: flex;
54
- flex: 1 1 0;
55
- flex-direction: column;
56
- z-index: 0;
62
+ .timeslot-calendar .tscal-current-time-indicator {
63
+ position: absolute;
57
64
  }
58
- .timeslot-calendar .hour-indicator-col-horizontal {
65
+ .timeslot-calendar .buckets-wrapper {
66
+ position: absolute;
59
67
  display: flex;
60
- flex: 1 1 0;
61
68
  flex-direction: row;
62
- height: 100%;
63
- z-index: 0;
69
+ overflow: hidden;
64
70
  }
65
- .timeslot-calendar .hour-indicator-vertical {
66
- border-style: solid;
67
- flex: 1 1 0;
68
- border-width: 2px 0 0;
69
- border-color: rgba(229, 231, 235, 0.5);
70
- box-sizing: border-box;
71
- }
72
- .timeslot-calendar .hour-indicator-horizontal {
73
- border-style: solid;
74
- flex: 1 1 0;
75
- border-width: 0 0 0 2px;
76
- border-color: rgba(229, 231, 235, 0.5);
77
- box-sizing: border-box;
71
+ .timeslot-calendar .bucket {
72
+ flex: 1;
73
+ position: relative;
78
74
  }
79
- .timeslot-calendar .buckets-wrapper {
75
+ .timeslot-calendar .event-wrapper {
80
76
  position: absolute;
81
-
82
77
  }
83
- .timeslot-calendar .buckets-vertical {
78
+ /******* Layout: Vertical specific *******/
79
+ .timeslot-calendar .orientation-wrapper.vertical .hour-indicator {
80
+ text-align: center;
81
+ }
82
+ /******* Layout: Horizontal *******/
83
+ .timeslot-calendar .orientation-wrapper.horizontal {
84
84
  display: flex;
85
85
  flex-direction: row;
86
86
  }
87
- .timeslot-calendar .buckets-horizontal {
88
- position: absolute;
87
+ .timeslot-calendar .orientation-wrapper.horizontal .titles-heading {
88
+ flex-direction: column;
89
+ }
90
+ .timeslot-calendar .orientation-wrapper.horizontal .title-heading {
91
+ flex: none;
89
92
  display: flex;
93
+ flex-direction: row;
94
+ }
95
+ .timeslot-calendar .orientation-wrapper.horizontal .day-heading {
96
+ flex: 1;
97
+ }
98
+ .timeslot-calendar .orientation-wrapper.horizontal .buckets-heading {
90
99
  flex-direction: column;
91
100
  }
92
- .timeslot-calendar .bucket-wrapper {
93
- flex: 1 1 0;
101
+ .timeslot-calendar .orientation-wrapper.horizontal .calendar-body {
102
+ flex: 1;
103
+ flex-direction: column;
104
+ overflow-x: scroll;
94
105
  }
95
- .timeslot-calendar .bucket-horizontal {
96
- flex: 1 1 0;
97
- display: flex;
106
+ .timeslot-calendar .orientation-wrapper.horizontal .buckets-wrapper {
107
+ flex-direction: column;
108
+ }
109
+ .timeslot-calendar .orientation-wrapper.horizontal .hour-indicator-wrapper {
98
110
  flex-direction: row;
99
111
  }
100
- .timeslot-calendar .bucket-inner-horizontal {
101
- position: relative;
112
+ /******* Layout: Horizontal - Date On Top *******/
113
+ .timeslot-calendar .orientation-wrapper.horizontal_date_on_top .body-wrapper {
114
+ display: flex;
115
+ flex-direction: row;
102
116
  }
103
- .timeslot-calendar .events-wrapper {
104
- position: relative;
117
+ .timeslot-calendar .orientation-wrapper.horizontal_date_on_top .buckets-heading {
118
+ flex-direction: column;
105
119
  }
106
- .timeslot-calendar .event-wrapper {
107
- position: absolute;
108
- z-index: 1;
109
- box-sizing: border-box;
120
+ .timeslot-calendar .orientation-wrapper.horizontal_date_on_top .calendar-body {
121
+ flex: 1;
122
+ flex-direction: column;
123
+ overflow-x: scroll;
110
124
  }
111
- .timeslot-calendar .current_time_indicator {
112
- position: absolute;
125
+ .timeslot-calendar .orientation-wrapper.horizontal_date_on_top .buckets-wrapper {
126
+ flex-direction: column;
113
127
  }
114
- /*--- Event example style ----*/
115
- .timeslot-event {
116
- width: 100%;
117
- height: 100%;
118
- border-width: 2px;
119
- border-style: solid;
120
- border-color: rgba(0, 0, 0, 0.5);
121
- border-radius: 0.25rem;
122
- background-color: white;
128
+ .timeslot-calendar .orientation-wrapper.horizontal_date_on_top .hour-indicator-wrapper {
129
+ flex-direction: row;
123
130
  }
@@ -1,151 +1,178 @@
1
1
  <div class="timeslot-calendar">
2
2
  <div class="calendar-heading">
3
3
  <%= link_to t('simple_calendar.previous', default: 'Previous'), calendar.url_for_previous_view %>
4
- <span class="calendar-title"><%= t('date.month_names')[start_date.month] %> <%= start_date.year %></span>
4
+ <span class="calendar-title">
5
+ <%= start_date.strftime(calendar.date_heading_format_string) %>
6
+ </span>
5
7
  <%= link_to t('simple_calendar.next', default: 'Next'), calendar.url_for_next_view %>
6
8
  </div>
7
-
8
- <% if calendar.orientation == :vertical %>
9
- <div class="days-wrapper-vertical">
10
- <div class="days-heading">
11
- <% date_range.slice(0, 7).each do |day| %>
12
- <div class="day-title-row">
9
+ <% if calendar.layout == :vertical || calendar.layout == :horizontal %>
10
+ <div class="orientation-wrapper <%=calendar.layout%>">
11
+ <div class="titles-heading">
12
+ <% event_map = date_range.map { |day| calendar.split_into_buckets(sorted_events.fetch(day, [])) } %>
13
+ <% date_range.each_with_index do |day, index| %>
14
+ <div class="title-heading <%=calendar.td_classes_for(day).join(' ')%>" style="<%=calendar.day_height_style%>">
15
+ <div class="day-heading">
16
+ <div class="day-heading-inner">
13
17
  <span class="day-weekday">
14
18
  <%= t('date.abbr_day_names')[day.wday] %>
15
19
  </span>
16
20
  <span class="day-date">
17
- <%= day %>
21
+ <%= calendar.date_format_string ? day.strftime(calendar.date_format_string) : day %>
18
22
  </span>
19
23
  </div>
24
+ </div>
25
+ <% if calendar.display_bucket_title %>
26
+ <div class="buckets-heading">
27
+ <% if calendar.layout == :vertical %>
28
+ <div style="width:<%=calendar.grid_width%>"></div>
29
+ <% else %>
30
+ <div style="height:<%=calendar.grid_width%>"></div>
31
+ <% end %>
32
+ <% event_map[index].each do |bucket| %>
33
+ <div class="bucket-heading">
34
+ <%= bucket&.first&.send calendar.display_bucket_title %>
35
+ </div>
36
+ <% end %>
37
+ </div>
20
38
  <% end %>
21
39
  </div>
22
- <div class="days-body">
23
- <% date_range.slice(0, 7).each do |day| %>
24
- <div class="day-wrapper">
25
- <%= content_tag :div, class: calendar.td_classes_for(day) do %>
26
- <div class="day-content-vertical" style="height:<%=calendar.height%>px;">
27
- <% if calendar.display_grid %>
28
- <div class="hour-indicator-col-vertical">
29
- <% if calendar.display_bucket_title %>
30
- <div class="bucket-title" style="height:<%=calendar.bucket_title_size%>px"></div>
31
- <% end %>
32
- <% (0..23).each do |hour| %>
33
- <div class="hour-indicator-vertical" id="hour-<%=hour %>">
34
- <%=hour%>
35
- </div>
36
- <% end %>
37
- </div>
38
- <% end %>
39
- <% if calendar.display_current_time_indicator %>
40
- <div class="current_time_indicator" style="top:<%=calendar.current_time_offset %>px;left:0;right:0;height:0;"></div>
41
- <% end %>
42
- <% events = sorted_events.fetch(day, []) %>
43
- <% buckets = calendar.split_into_buckets(events) %>
44
- <div class="buckets-wrapper" style="left:<%=calendar.grid_width%>;right:0">
45
- <div class="buckets-vertical">
46
- <% buckets.each do |bucket| %>
47
- <div class="bucket-wrapper">
48
- <div class="bucket-vertical">
49
- <% if calendar.display_bucket_title %>
50
- <div class="bucket-title" style="height:<%=calendar.bucket_title_size%>px">
51
- <%= bucket&.first&.send calendar.display_bucket_title %>
52
- </div>
53
- <% end %>
54
- <div class="events-wrapper">
55
- <% events_size = calendar.slot_events(bucket, day) %>
56
- <% bucket.each do |event| %>
57
- <div class="event-wrapper" style="width:<%=events_size[event][0]%>%;top:<%=events_size[event][3]%>px;left:<%=events_size[event][1]%>%;height:<%=events_size[event][2]%>px">
58
- <% if defined?(Haml) && respond_to?(:block_is_haml?) && block_is_haml?(passed_block) %>
59
- <% capture_haml(event, &passed_block) %>
60
- <% else %>
61
- <% passed_block.call event %>
62
- <% end %>
63
- </div>
64
- <% end %>
65
- </div>
66
- </div>
67
- </div>
68
- <% end %>
69
- </div>
70
- </div>
40
+ <% end %>
41
+ </div>
42
+ <div class="calendar-body" style="<%=calendar.body_style%>" >
43
+ <% event_map.each_with_index do |buckets, index| %>
44
+ <div class="day-wrapper">
45
+ <% if calendar.layout == :vertical %>
46
+ <div class="day-body <%=calendar.td_classes_for(date_range[index]).join(' ')%>" style="height:<%=calendar.day_size%>px">
47
+ <% else %>
48
+ <div class="day-body <%=calendar.td_classes_for(date_range[index]).join(' ')%>" style="width:<%=calendar.day_size%>px;height:<%=calendar.day_height_px%>px">
49
+ <% end %>
50
+ <% if calendar.display_grid %>
51
+ <div class="hour-indicator-wrapper">
52
+ <% (0..23).each do |hour| %>
53
+ <% if calendar.layout == :vertical %>
54
+ <div class="hour-indicator-cell tscal-vertical tscal-hour-cell" id="hour-<%=hour %>">
55
+ <div class="hour-indicator" style="width:<%=calendar.grid_width%>">
56
+ <% else %>
57
+ <div class="hour-indicator-cell tscal-horizontal tscal-hour-cell" id="hour-<%=hour %>">
58
+ <div class="hour-indicator" style="height:<%=calendar.grid_width%>">
59
+ <% end %>
60
+ <%=hour%>
71
61
  </div>
62
+ </div>
63
+ <% end %>
64
+ </div>
65
+ <% end %>
66
+ <% if calendar.display_current_time_indicator %>
67
+ <% if calendar.layout == :vertical %>
68
+ <div class="tscal-current-time-indicator" style="top:<%=calendar.current_time_offset %>px;left:0;right:0;height:0;"></div>
69
+ <% else %>
70
+ <div class="tscal-current-time-indicator" style="left:<%=calendar.current_time_offset %>px;top:0;bottom:0;width:0;"></div>
72
71
  <% end %>
72
+ <% end %>
73
+ <% if calendar.layout == :vertical %>
74
+ <div class="buckets-wrapper" style="left:<%=calendar.grid_width%>;right:0;top:0;bottom:0;">
75
+ <% else %>
76
+ <div class="buckets-wrapper" style="top:<%=calendar.grid_width%>;right:0;left:0;bottom:0;">
77
+ <% end %>
78
+ <% buckets.each do |bucket| %>
79
+ <div class="bucket">
80
+ <% events_size = calendar.slot_events(bucket, date_range[index]) %>
81
+ <% bucket.each do |event| %>
82
+ <% if calendar.layout == :vertical %>
83
+ <div class="event-wrapper tscal-event-wrapper" style="width:<%=events_size[event][0]%>%;top:<%=events_size[event][3]%>px;left:<%=events_size[event][1]%>%;height:<%=events_size[event][2]%>px">
84
+ <% else %>
85
+ <div class="event-wrapper tscal-event-wrapper" style="height:<%=events_size[event][0]%>%;left:<%=events_size[event][3]%>px;top:<%=events_size[event][1]%>%;width:<%=events_size[event][2]%>px">
86
+ <% end %>
87
+ <% if defined?(Haml) && respond_to?(:block_is_haml?) && block_is_haml?(passed_block) %>
88
+ <% capture_haml(event, &passed_block) %>
89
+ <% else %>
90
+ <% passed_block.call event %>
91
+ <% end %>
92
+ </div>
93
+ <% end %>
94
+ </div>
95
+ <% end %>
73
96
  </div>
74
- <% end %>
97
+ </div>
75
98
  </div>
99
+ <% end %>
76
100
  </div>
77
- <% elsif calendar.orientation == :horizontal %>
78
- <div class="days-wrapper-horizontal <%= calendar.horizontal_scroll_split ? "" : "scroll-link" %>">
79
- <% date_range.slice(0, 7).each do |day| %>
80
- <div class="day-wrapper">
81
- <div class="day-title-row">
82
- <span class="day-weekday">
83
- <%= t('date.abbr_day_names')[day.wday] %>
84
- </span>
85
- <span class="day-date">
86
- <%= day %>
87
- </span>
101
+ </div>
102
+ <% elsif calendar.layout == :horizontal_date_on_top %>
103
+ <div class="orientation-wrapper <%=calendar.layout%>">
104
+ <% event_map = date_range.map { |day| calendar.split_into_buckets(sorted_events.fetch(day, [])) } %>
105
+ <% date_range.each_with_index do |day, index| %>
106
+ <div class="outer-day-wrapper <%=calendar.td_classes_for(day).join(' ')%>">
107
+ <div class="day-heading">
108
+ <div class="day-heading-inner">
109
+ <span class="day-weekday">
110
+ <%= t('date.abbr_day_names')[day.wday] %>
111
+ </span>
112
+ <span class="day-date">
113
+ <%= calendar.date_format_string ? day.strftime(calendar.date_format_string) : day %>
114
+ </span>
115
+ </div>
116
+ </div>
117
+ <div class="body-wrapper">
118
+ <% if calendar.display_bucket_title %>
119
+ <div class="buckets-heading">
120
+ <% if calendar.layout == :vertical %>
121
+ <div style="width:<%=calendar.grid_width%>"></div>
122
+ <% else %>
123
+ <div style="height:<%=calendar.grid_width%>"></div>
124
+ <% end %>
125
+ <% event_map[index].each do |bucket| %>
126
+ <div class="bucket-heading">
127
+ <%= bucket&.first&.send calendar.display_bucket_title %>
88
128
  </div>
89
- <%= content_tag :div, class: calendar.td_classes_for(day) do %>
90
- <div class="day-content-horizontal <%= calendar.horizontal_scroll_split ? "scroll-split" : "" %>">
91
- <div class="day-content-horizontal-inner" style="width:<%=calendar.height%>px;height:<%=calendar.horizontal_height_px%>px">
92
- <% if calendar.display_grid %>
93
- <div class="hour-indicator-col-horizontal" style="z-index:-10;">
94
- <% if calendar.display_bucket_title %>
95
- <div class="bucket-title" style="width:<%=calendar.bucket_title_size%>px;"></div>
96
- <% end %>
97
- <% (0..23).each do |hour| %>
98
- <div class="hour-indicator-horizontal" id="hour-<%=hour %>">
99
- <div style="height:20px">
100
- <%=hour%>
101
- </div>
102
- </div>
103
- <% end %>
129
+ <% end %>
130
+ </div>
131
+ <% end %>
132
+
133
+ <div class="calendar-body" style="<%=calendar.body_style%>" >
134
+ <% buckets = event_map[index] %>
135
+ <div class="day-wrapper">
136
+ <div class="day-body <%=calendar.td_classes_for(date_range[index]).join(' ')%>" style="width:<%=calendar.day_size%>px;height:<%=calendar.day_height_px%>px">
137
+ <% if calendar.display_grid %>
138
+ <div class="hour-indicator-wrapper">
139
+ <% (0..23).each do |hour| %>
140
+ <div class="hour-indicator-cell tscal-horizontal tscal-hour-cell" id="hour-<%=hour %>">
141
+ <div class="hour-indicator" style="height:<%=calendar.grid_width%>">
142
+ <%=hour%>
104
143
  </div>
105
- <% end %>
106
- <% if calendar.display_current_time_indicator && !calendar.horizontal_scroll_split %>
107
- <div class="current_time_indicator" style="left:<%=calendar.current_time_offset %>px;top:0;bottom:0;width:0;"></div>
108
- <% end %>
109
- <% events = sorted_events.fetch(day, []) %>
110
- <% buckets = calendar.split_into_buckets(events) %>
111
- <div class="buckets-wrapper" style="top:<%=calendar.grid_width%>;bottom:0">
112
- <div class="buckets" >
113
- <% buckets.each do |bucket| %>
114
- <div class="bucket-horizontal">
115
- <% if calendar.display_bucket_title %>
116
- <div class="bucket-title-size-wrap" style="width:<%=calendar.bucket_title_size%>px;">
117
- <div class="bucket-title-text-wrapper">
118
- <div class="bucket-title-text">
119
- <%= bucket&.first&.send calendar.display_bucket_title %>
120
- </div>
121
- </div>
122
- </div>
123
- <% end %>
124
- <div class="events-wrapper" style="height:<%=(calendar.horizontal_height_px-(calendar.display_grid ? 20 : 0)) / buckets.size%>px;">
125
- <div class="events-inner-horizontal">
126
- <% events_size = calendar.slot_events(bucket, day) %>
127
- <% bucket.each do |event| %>
128
- <div class="event-wrapper" style="height:<%=events_size[event][0]%>%;left:<%=events_size[event][3]%>px;top:<%=events_size[event][1]%>%;width:<%=events_size[event][2]%>px">
129
- <% if defined?(Haml) && respond_to?(:block_is_haml?) && block_is_haml?(passed_block) %>
130
- <% capture_haml(event, &passed_block) %>
131
- <% else %>
132
- <% passed_block.call event %>
133
- <% end %>
134
- </div>
135
- <% end %>
136
- </div>
137
- </div>
138
- </div>
144
+ </div>
145
+ <% end %>
146
+ </div>
147
+ <% end %>
148
+ <% if calendar.display_current_time_indicator %>
149
+ <div class="tscal-current-time-indicator" style="left:<%=calendar.current_time_offset %>px;top:0;bottom:0;width:0;"></div>
150
+ <% end %>
151
+ <div class="buckets-wrapper" style="top:<%=calendar.grid_width%>;right:0;left:0;bottom:0;">
152
+ <% buckets.each do |bucket| %>
153
+ <div class="bucket">
154
+ <% events_size = calendar.slot_events(bucket, date_range[index]) %>
155
+ <% bucket.each do |event| %>
156
+ <div class="event-wrapper tscal-event-wrapper" style="height:<%=events_size[event][0]%>%;left:<%=events_size[event][3]%>px;top:<%=events_size[event][1]%>%;width:<%=events_size[event][2]%>px">
157
+ <% if defined?(Haml) && respond_to?(:block_is_haml?) && block_is_haml?(passed_block) %>
158
+ <% capture_haml(event, &passed_block) %>
159
+ <% else %>
160
+ <% passed_block.call event %>
139
161
  <% end %>
140
162
  </div>
163
+ <% end %>
141
164
  </div>
165
+ <% end %>
142
166
  </div>
143
167
  </div>
144
- <% end %>
168
+ </div>
145
169
  </div>
146
- <% end %>
170
+ </div>
147
171
  </div>
172
+
173
+ <% end %>
174
+ </div>
148
175
  <% else %>
149
- <div>Unsupported orientation: <%= calendar.orientation %></div>
176
+ <div>Unsupported layout for timeslot_calendar, please contact your webdeveloper</div>
150
177
  <% end %>
151
- </div>
178
+ </div>
@@ -3,27 +3,29 @@ require "simple_calendar"
3
3
  module SimpleCalendar
4
4
  module Timeslot
5
5
  class TimeslotCalendar < SimpleCalendar::Calendar
6
- MINUTE_HEIGHT_PX = 0.65
7
- FIRST_HOUR_SLOT = 0
8
6
 
9
- def orientation
10
- @options.fetch(:orientation, :vertical)
7
+ def layout
8
+ @options.fetch(:layout, :vertical)
11
9
  end
12
10
 
13
- def horizontal_height_px
14
- @options.fetch(:horizontal_height_px, 300)
11
+ def px_per_minute
12
+ @options.fetch(:px_per_minute, 0.65)
15
13
  end
16
14
 
17
- def split_by_type
18
- @options.fetch(:split_by_type, false)
15
+ def display_grid
16
+ @options.fetch(:display_grid, true)
19
17
  end
20
-
21
- def px_per_minute
22
- @options.fetch(:px_per_minute, TimeslotCalendar::MINUTE_HEIGHT_PX)
18
+
19
+ def grid_width
20
+ if display_grid
21
+ @options.fetch(:grid_width, "20px")
22
+ else
23
+ 0
24
+ end
23
25
  end
24
26
 
25
- def display_bucket_title
26
- @options.fetch(:display_bucket_title, false)
27
+ def display_current_time_indicator
28
+ @options.fetch(:display_current_time_indicator, false)
27
29
  end
28
30
 
29
31
  def bucket_title_size
@@ -34,35 +36,46 @@ module SimpleCalendar
34
36
  end
35
37
  end
36
38
 
37
- def grid_top_offset(hour)
38
- 4.16666667 * hour
39
+ def body_size_px
40
+ @options.fetch(:body_size_px, false)
39
41
  end
40
42
 
41
- def grid_width
42
- if display_grid
43
- @options.fetch(:grid_width, "20px")
44
- else
45
- 0
46
- end
43
+ def day_height_px
44
+ @options.fetch(:day_height_px, 200)
47
45
  end
48
46
 
49
- def display_grid
50
- @options.fetch(:display_grid, true)
47
+ def bucket_by
48
+ @options.fetch(:bucket_by, false)
51
49
  end
52
50
 
53
- def horizontal_scroll_split
54
- @options.fetch(:horizontal_scroll_split, false)
51
+ def display_bucket_title
52
+ @options.fetch(:display_bucket_title, false)
55
53
  end
56
54
 
57
- def display_current_time_indicator
58
- @options.fetch(:display_current_time_indicator, false)
55
+ def date_format_string
56
+ @options.fetch(:date_format_string, false)
57
+ end
58
+
59
+ def date_heading_format_string
60
+ @options.fetch(:date_heading_format_string, "%B %Y")
61
+ end
62
+
63
+ def body_style
64
+ if layout == :vertical
65
+ body_size_px ? "height:#{body_size_px}px" : ''
66
+ elsif layout == :horizontal
67
+ 'height:100%'
68
+ else
69
+ ''
70
+ end
71
+ end
72
+
73
+ def day_height_style
74
+ layout == :horizontal ? "height:#{day_height_px}px;" : ""
59
75
  end
60
76
 
61
- def height
62
- #h = (24 - TimeslotCalendar::FIRST_HOUR_SLOT) * 60 * px_per_minute
63
- h = 24 * 60 * px_per_minute
64
- h = h+bucket_title_size if display_bucket_title
65
- h
77
+ def day_size
78
+ 24 * 60 * px_per_minute
66
79
  end
67
80
 
68
81
  def event_height(event, day)
@@ -83,8 +96,9 @@ module SimpleCalendar
83
96
  end
84
97
 
85
98
  def split_into_buckets(events)
86
- if split_by_type
87
- events.group_by{|e| e.send split_by_type}.values
99
+ if bucket_by
100
+ return [[]] if events.size == 0
101
+ events.group_by{|e| e.send bucket_by}.values
88
102
  else
89
103
  [events]
90
104
  end
@@ -130,7 +144,6 @@ module SimpleCalendar
130
144
  def current_time_offset
131
145
  now = Time.zone.now
132
146
  offset = (now.hour * 60 + now.min) * px_per_minute
133
- offset = offset + bucket_title_size if display_bucket_title
134
147
  offset
135
148
  end
136
149
 
@@ -2,6 +2,6 @@
2
2
 
3
3
  module SimpleCalendar
4
4
  module Timeslot
5
- VERSION = "0.8.0"
5
+ VERSION = "0.90.0"
6
6
  end
7
7
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: simple_calendar-timeslot
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.8.0
4
+ version: 0.90.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kim Laplume
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-11-15 00:00:00.000000000 Z
11
+ date: 2021-11-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: simple_calendar